G-buffer投影

操作原理和步骤:

    1 转到裁剪空间坐标系

    2 计算顶点在相机远裁剪面的位置(通过等比三角形)

    3 计算要显示贴画的顶顶点

   4 转到局部坐标系

  5   

          -0.5scale <= x<=0.5*scale

         -0.5scale <= y<=0.5*scale

  6  计算 uv 坐标

            x+= 0.5*scale

            y += 0.5*scale

    7 对纹理和遮罩图片进行采样

   8 颜色输出

 

unity 官方 commandbuffer 例子里的,C#脚本这边很简略,只是在 LightingPass 前 new 了一个commandbuffer, 核心实现则在 Shader 中,vertex 和 fragment shader 代码如下:

           struct v2f
            {
                float4 pos : SV_POSITION;
                half2 uv : TEXCOORD0;
                float4 screenUV : TEXCOORD1;
                float3 ray : TEXCOORD2;
                half3 orientation : TEXCOORD3;
            };

            v2f vert (float3 v : POSITION)
            {
                v2f o;
                o.pos = mul (UNITY_MATRIX_MVP, float4(v,1));
                o.uv = v.xz+0.5;
                o.screenUV = ComputeScreenPos (o.pos);
                o.ray = mul (UNITY_MATRIX_MV, float4(v,1)).xyz * float3(-1,-1,1);
                o.orientation = mul ((float3x3)unity_ObjectToWorld, float3(0,1,0));
                return o;
            }

            CBUFFER_START(UnityPerCamera2)
            // float4x4 _CameraToWorld;
            CBUFFER_END

            sampler2D _MainTex;
            sampler2D_float _CameraDepthTexture;
            sampler2D _NormalsCopy;

            fixed4 frag(v2f i) : SV_Target
            {
                i.ray = i.ray * (_ProjectionParams.z / i.ray.z);
                float2 uv = i.screenUV.xy / i.screenUV.w;
                // read depth and reconstruct world position
                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
                depth = Linear01Depth (depth);
                float4 vpos = float4(i.ray * depth,1);
                float3 wpos = mul (unity_CameraToWorld, vpos).xyz;
                float3 opos = mul (unity_WorldToObject, float4(wpos,1)).xyz;

                clip (float3(0.5,0.5,0.5) - abs(opos.xyz));


                i.uv = opos.xz+0.5;

                half3 normal = tex2D(_NormalsCopy, uv).rgb;
                fixed3 wnormal = normal.rgb * 2.0 - 1.0;
                clip (dot(wnormal, i.orientation) - 0.3);

                fixed4 col = tex2D (_MainTex, i.uv);
                if (col.a < 0.8)
                    col.a = 0;
                return col;
            }

其中 ray 是相机相机指向每个顶点的向量 (乘以 float3(-1,-1,1) 是因为经过MV变换后 z 通常是负数)

i.ray = i.ray * (_ProjectionParams.z / i.ray.z);

则是将向量的终点由顶点(光栅化后应该是像素,但放这里好像又不太好表达)位置投影到了相机远截面,如图所示: 
è¿éåå¾çæè¿°

 

然后通过深度图得到像素投影在其他物体上的坐标,并重新转换至模型坐标

                                clip (float3(0.5,0.5,0.5) - abs(opos.xyz));

因为 Demo 中使用的是单位大小的 Cube, 因此投影后在 Cube 外的像素直接 clip 掉

                                clip (dot(wnormal, i.orientation) - 0.3);

则是将投影点的法线与设施好的 Decal 朝向做比较,裁剪掉角度太大的避免贴图拉伸造成的Artificial, 如图所示: 

è¿éåå¾çæè¿°

你可能感兴趣的:(shader)