Code Snippets

            
            永远不该为取悦别人,
            而使自己失敬于人。
             
            Man is born free, 
            And everywhere he is in chains.
             
            这里是我的平日工作和 side projects 代码片段记录.
            其实就只是单纯想在 comments 里吐槽罢了 (bushi
             
            2024.09.05
            
        
// Code is full of bugs, and so is life.
//       /\_/\
//      ( o.o )
// 妈的,我是一只可爱的小猫该多好啊,人人都会喜欢我
// 王小兵写此段代码于上海 2024.09.01

#include <stdio.h>

int main(int argc, char **argv)
{
    printf("hello my friend, welcome.\n");
    return 0;
}
            
            人生,
            处处是苦涩的试炼,
            短暂的欢愉。
             
            Life is full of bitter trials and short pleasures. 
             
            希望我也能从 infj 变成 intj
            不想内耗了
             
            2024.09.08
            
        
// fwidth 函数是一个 GLSL 内置函数
// 用于计算函数在屏幕空间(或者其他坐标系)中 x 和 y 方向的变化率
// 也就是函数沿着 x 和 y 方向的梯度

// 对于输入坐标 p,fwidth(p)的计算公式如下
// fwidth(p) = abs(dFdx(p)) + abs(dFdy(p))
// abs函数表示取绝对值
// dFdx(p) 表示函数在 x 轴上的偏导数
// dFdy(p) 表示函数在 y 轴上的偏导数

// 下面是一个示例片元着色器
// 使用fwidth函数计算表面法线的偏导数,结果用于计算环境光的强度
// 来自 GLSL ES Shader 参考文档 http://www.bimant.com/docs/glsl-es/fwidth/

// 老夫我啊,一独立项目会用 fwdith 函数来实现 sdf 来做边缘检测和抗锯齿

uniform vec3 ambientColor;
uniform vec3 lightColor;
uniform vec3 lightDir;
varying vec3 vNormal;

void main() 
{
    vec3 n = normalize(vNormal);
    vec3 l = normalize(lightDir);
    float NdotL = dot(n, l);
    float intensity = max(0.0, NdotL);

    // 计算法线的偏导数
    vec2 derivative = fwidth(gl_FragCoord.xy);

    // 加权环境光颜色
    vec3 ambient = ambientColor * (1.0 - intensity * intensity);
    vec3 color = ambient + intensity * lightColor;

    // 应用边缘柔化
    color *= exp(-(derivative.x + derivative.y));
    gl_FragColor = vec4(color, 1.0);
}

临江仙 - 绝影

加班调试无空调,

八戈解完心难解。

函数堆栈似深海。

错报如血若残阳,

回溯难寻源,

算法乱成线,

无尽循环乱引用,

编程人难眠。

// URP 自定义着色器的 Shadow Receieve
// 自定义 shaderlab 添加 GPU instancing 支持需要在 pass 里添加
// #pragma multi_compile_instancing
// 如果大量绘制的网格都一致,那么建议用 instancing
// 如果用上 instancing,那么你的其他 pass 最好都同步添加上 instancing 的支持
// 如果网格不一致,但是相同 shader,且 shader 变体一致,那么建议用 SRP Batcher
// 支持 SRP Batcher 主要是将 uniform 变量都划分到对应的 CBuffer
// 这篇文章讲的不错 https://blog.csdn.net/linjf520/article/details/120757669

// 有些时候,老夫我真的尽力了

Shader "Custom/ShadowReceieve"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1, 1, 1, 1)
        [Toggle] _ALPHATEST ("Alpha Test On", Float) = 0
    }

    SubShader {
    Tags { "RenderType"="Opaque" }
    LOD 100

    HLSLINCLUDE
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        CBUFFER_START(UnityPerMaterial)
            half4 _Color;
            float4 _MainTex_ST;
        CBUFFER_END
    ENDHLSL

    Pass
    {
        HLSLPROGRAM
        #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
        #pragma multi_compile _ _SHADOWS_SOFT
        #pragma multi_compile_instancing
        #pragma shader_feature _ALPHATEST_ON

        #pragma vertex vert
        #pragma fragment frag
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"

        struct appdata
        {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
        };

        struct v2f
        {
            float4 vertex : SV_POSITION;
            float2 uv : TEXCOORD0;
            float4 shadowCoord : TEXCOORD1;
            float3 positionWS : TEXCOORD2;
        };

        sampler2D _MainTex;

        v2f vert (appdata v)
        {
            v2f o;
            o.positionWS = TransformObjectToWorld(v.vertex.xyz);
            o.vertex = TransformWorldToHClip(o.positionWS);
            o.uv = TRANSFORM_TEX(v.uv, _MainTex);
            o.shadowCoord = TransformWorldToShadowCoord(o.positionWS);
            return o;
        }
        
        half4 frag(v2f i) : SV_Target
        {
            half3 ambient = half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);
            half shadow = MainLightRealtimeShadow(i.shadowCoord);
            half4 col = tex2D(_MainTex, i.uv);
            half4 finalCol = col * _Color;    
            finalCol.rgb = lerp(finalCol.rgb * ambient.rgb, finalCol.rgb, shadow);
            return finalCol;
        }
        ENDHLSL
        }
    }
}
            
            人一旦丧失专注的能力,
            稍微动一动,就觉得快累死了。
            所以,千万别堕落。
             
            So, don't fall into depravity.
            2024.09.05
            
        
// 自定义着色器要想 SRP Batcher compatible
// 材质自定义的属性要放在 UnityPerMaterial 的 CBuffer 中
// 逐材质的属性,需要定义在 cbuffer 中,才能在材质切换时直接绑定显存中的 cbuffer

// 老夫是这屎山项目唯一的光,还会去考虑性能问题

CBUFFER_START(UnityPerMaterial)
    float4 _BaseMap_ST;
    half4 _BaseColor;
    half4 _SpecColor;
    half4 _EmissionColor;
    half _Cutoff;
    half _Surface;
CBUFFER_END
// 公司的这脑洞突破天灵盖的项目
// 什么样的奇葩需求都能遇得到,比如这 Cesium 卫星图的 textures 导出
// 内存里创建的贴图无法修改 import settings isReadable
// 要想读取 unreadable texture2d 可以先 blit 到一张 rt 里

// 草,是一种植物,狗是真的狗

private Texture2D ReadUnreadableTexture(Texture2D texture)
{
    RenderTexture tmp = RenderTexture.GetTemporary(
        texture.width,
        texture.height,
        0,
        RenderTextureFormat.Default,
        RenderTextureReadWrite.Linear);


    Graphics.Blit(texture, tmp);

    RenderTexture previous = RenderTexture.active;
    RenderTexture.active = tmp;
    
    Texture2D retTexture2D = new Texture2D(texture.width, texture.height);
    
    retTexture2D.ReadPixels(new Rect(0, 0, tmp.width, tmp.height), 0, 0);
    retTexture2D.Apply();
    
    RenderTexture.active = previous;
    RenderTexture.ReleaseTemporary(tmp);

    return retTexture2D;
}
// 使用重心坐标在三角形内随机点
// 点的稀疏程度和三角形面积成正比
// 这段代码是为了在草地上随机种树
// 输入是草地 mesh 的 triangles 对应的顶点序列

// 妈的,没错,反正都是些 2b 需求

List<Vector3> RandomPointsInTriangle(Vector3 v1, Vector3 v2, Vector3 v3, float density)
{
    var points = new List<Vector3>();
    var area = Vector3.Cross(v2 - v1, v3 - v1).magnitude * 0.5f;
    var pointCount = Mathf.CeilToInt(area * density);
    
    for (var i = 0; i < pointCount; ++i)
    {
        var randomPoint = GenerateRandomPointInTriangle(v1, v2, v3);
        points.Add(randomPoint);
    }
    return points;
}

Vector3 GenerateRandomPointInTriangle(Vector3 v1, Vector3 v2, Vector3 v3)
{
    var r1 = Random.value;
    var r2 = Random.value;
    if (r1 + r2 > 1f)
    {
        r1 = 1f - r1;
        r2 = 1f - r2;
    }
    return v1 + r1 * (v2 - v1) + r2 * (v3 - v1);
}
            
            术之尽头,炁体源流
             
            人能得志者,元炁充而有微,肌膚潤而光澤。
            雲行雨施,萬物滋也;炁充百脉,萬神靈也。
            僊經曰:無一毛不通於炁,無一節不住於神。