Koo叔说Shader-调试Shader

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/java3182/article/details/81195703

前言

当写的Shader出现了一些不是预期的效果时,可能需要对Shader进行调试。但Shader不像其它语言能加断点debug,也不能打印输出。输出的只能是颜色值,所以可以将想要看的变量变换成颜色值,可视化的来查看问题,当然这需要一些小小的转换。

顶点数据从哪里来

一般对Shader调试,主要是调试顶点数据及变换,那么顶点数据是如何设置到Shader中的呢?在Unity中,是由Mesh Renderer component对象每帧将mesh data发送到GPU中的(这个过程通常就叫做draw call)。每次draw call都会对性能有一定的开销,因此应当尽可能的在每次Draw call中传输大量Mesh.Mesh数据是由一组三角形(Triangle)列表数据组成,每个三角形有三个顶点(vertex),每个顶点存储着多个属性(attributes),如POSITION,NORMAL,TEXCOORD0,TEXCOORD1,TANGENT,COLOR等

内置顶点属性

通常将顶点属性组织到一个struct中。例如:

struct vertexInput{
    flaot4 vertex:POSITION;
    float4 tangent:TANGENT;
    float3 normal:NORMAL;
    float4 texcoord:TEXCOORD0;
    float4 texcoord1:TEXCOORD1;
    float4 texcoord2:TEXCOORD2;
    float4 texcoord3:TEXCOORD3;
    float4 color:COLOR;
}

这个结构在Shader中的用法如下:

Shader "Cg shader with all built-in vertex input parameters"{
    SubShader{
        Pass{
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            struct vertexInput{
                flaot4 vertex:POSITION;
                float4 tangent:TANGENT;
                float3 normal:NORMAL;
                float4 texcoord:TEXCOORD0;
                float4 texcoord1:TEXCOORD1;
                float4 texcoord2:TEXCOORD2;
                float4 texcoord3:TEXCOORD3;
                float4 color:COLOR;
            };
            struct vertexOutput{
                float4 pos:SV_POSITION;
                float4 col:TEXCOORD0;
            };
            vertexOutput vert(vertexInput input){
                vertexOutput output;
                output.pos = UnityObjectToClipPos(input.vertex);
                // other possibilities to play with:
                // output.col = input.vertex;
                // output.col = input.tangent;
                // output.col = float4(input.normal, 1.0);
                // output.col = input.texcoord;
                // output.col = input.texcoord1;
                // output.col = input.texcoord2;
                // output.col = input.texcoord3;
                // output.col = input.color;
                return output;
            }
            float4 frag(vertexOutput input):COLOR{
                return input.col;
            }
            ENDCG
        }
    }
}

Unity中预定义的结构体

Unity提供了几种预定义结构分别是appdata_base,
appdata_tan,appdata_full和appdata_img,都在UnityCG.cginc中定义,具体结构如下:

struct appdata_base{
    float4 vertex:POSITION;
    float3 normal:NORMAL;
    float4 texcoord:TEXCOORD0;
};
struct appdata_tan{
    float4 vertex:POSITION;
    float4 tangent:TANGENT;
    float3 normal:NORMAL;
    float4 texcoord:TEXCOORD0;
};
struct appdata_full{
    float4 vertex:POSITION;
    float4 tangent:TANGENT;
    float3 normal:NORMAL;
    float4 texcoord:TEXCOORD0;
    float4 texcoord1:TEXCOORD1;
    float4 texcoord2:TEXCOORD2;
    float4 texcoord3:TEXCOORD3;
    fixed4 color:COLOR;
};
struct appdata_img{
    float4 vertex:POSITION;
    half2 texcoord:TEXCOORD0;
};

所以上面的shader可以重写成这样:

Shader "Cg shader with all built-in vertex input parameters" { 
   SubShader { 
      Pass { 
         CGPROGRAM 

         #pragma vertex vert  
         #pragma fragment frag 
         #include "UnityCG.cginc"

         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 col : TEXCOORD0;
         };

         vertexOutput vert(appdata_full input) 
         {
            vertexOutput output;

            output.pos =  mul(UNITY_MATRIX_MVP, input.vertex);
            output.col = input.texcoord;

            return output;
         }

         float4 frag(vertexOutput input) : COLOR 
         {
            return input.col; 
         }

         ENDCG  
      }
   }
}

颜色对应属性的解析

当尝试理解false-color图像中的信息时,最重要的是一次只关注一个颜色分量。例如:输入顶点属性texcoord,然后使用red分量表示texcoord的x坐标

output.col = float4(input.texcoord.x,0.0,0.0,1.0);

使用green分量表示texcoord的y坐标

output.col = float4(0.0,input.texcoord.y,0.0,1.0)

x,y坐标取值范围是(0,1)
颜色分量也是(0,1)正好一一对应。
当可视化法线时,由于法线取值范围是(-1,1),所以需要一个小小的转化,变到(0,1),才能用颜色分量表示

output.col = float4(input.normal+float3(1.0,1.0,1.0))/2.0,1.0);

调试练习

为了练习,下面有几个小例子,将会产生黑色的结果,你的任务是考虑每一行,为什么结果是黑色的。到最后,你应该可以可视化任何你不能完全确定的值

output.col = input.texcoord - float4(1.5,2.3,1.1,0.0);
output.col = input.texcoord.zzzz;
output.col = input.texcoord/tan(0.0);

下面的需要一些点乘和叉乘的知识

output.col = dot(input.normal,input.tangent.xyz)*input.texcoord;
output.col = dot(cross(input.normal,input.tangent.xyz),input.normal)*input.texcoord;
output.col = float4(cross(input.normal,input.normal),1.0);
output.col = float4(cross(input.normal,input.vertex.xyz),1.0);

总结

  • 学习了Unity中内置的输入属性
  • 如何通过设置fragment 的color,可视化这些属性.

猜你喜欢

转载自blog.csdn.net/java3182/article/details/81195703