unity shader 入门精要(冯乐乐著) 读书笔记(三)

unity的shader初体验

第一个实例代码

Shader "Unlit/Chapter5/SimpleShader"
{
    Properties
    {
        //_MainTex ("Texture", 2D) = "white" {}
        //声明一个color类型的属性
        _Color("Color Tint",Color) = (1.0, 1.0, 1.0, 1.0)
    }
        SubShader
    { 
    	Pass
    	{
        	CGPROGRAM
        	#pragma vertex vert//vert即为函数名
        	#pragma fragment frag//frag也为函数名
            //告诉unity哪个函数中包含了定点着色器的代码,哪个函数包含片元着色器代码
            // make fog work

            //在Cg代码中,我们需要定义一个与属性名称和类型都匹配的变量
            fixed4 _Color;

            //使用一个结构体来定义顶点着色器的输入
            struct a2v {
            //POSITION语义告诉unity用模型空间的定点坐标填充vertex变量
            float4 vertex : POSITION;
            //NORMAL语义告诉unity用模型空间的法线方向填充normal变量
            float3 normal : NORMAL;
            //TEXCOORD0语义告诉unity,用模型的第一套纹理坐标填充texcoord变量
            float4 texcoord : TEXCOORD0;

            };

            //使用一个结构体来定义顶点着色器的输出
            struct v2f {
            //SV_POSITION语义告诉unity,pos里包含了顶点裁剪空间中的位置信息
            float4 pos : SV_POSITION;
            //COLOR0语义可以用于存储颜色信息
            fixed3 color : COLOR0;
            };

            //unity支持的语义有:POSITION TANGENT NORMAL TEXCOORD0~3 COLOR等
            v2f vert(a2v v) {
            //声明输出结构
            v2f o;
            o.pos = UnityObjectToClipPos(v.vertex);
            //v.normal包含了顶点的法线方向,其分量范围在[-1.0, 1.0]
            //下面的代码吧分量范围映射到了[0.0 , 1.0]
            //存储到o.color中传递给片元着色器
            o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
            return o;
            }

            fixed4 frag(v2f i) : SV_Target{
            //将插值后的i.color显示到屏幕上
            fixed3 c = i.color;
            //使用_Color属性来控制输出颜色
            c *= _Color.rgb;
            return fixed4(c, 1.0);
            }
            ENDCG
    	}
    }
}

在书的 p106 中有ShaderLab属性类型Cg变量类型的匹配关系

在书的p108中包含了CGInclude中主要的包含文件以及主要用处、UnityCG.cginc中的一些常用的结构体、一些常用的帮助函数

Unity提供的Cg/HLSL语义

输入结构体:a2v

输出结构体:v2f

对于一些语义在 a2v 和 v2f 中出现时的作用并不一样,例如:

TEXCOORD0在输入结构体中的作用为:把模型的第一组纹理坐标存储在该变量中

而在输出结构体中的作用为:修饰的变量含义可以由我们来决定

系统数值语义

这类语义一般以SV开头(system-value),在上述代码中我们使用了SV_POSITION语义去修饰顶点着色器的输出变量pos,这些语义描述的变量是不可以随便赋值的,渲染引擎会把用SV_POSITION修饰的变量经过光栅化后显示在屏幕上

注:为了让shader更具有跨平台性,最好对有特殊意义的变量我们最好使用以SV开头的语义进行修饰

p110页具有Unity在渲染阶段支持的常用语义

(appdata_full最多使用了6个坐标纹理组 基本上包含了所有的模型数据

如何调试?

假彩色图像

用假彩色生成一种图像

因为颜色分量范围在[0,1]之间,我们要小心处理需要调试的变量的范围,可以将需要测试的变量范围*映射到[0,1]*之间,把它们作为颜色输出到屏幕上

例子:

Shader "Unity Shaders Book/Chapter 5/False Color"
{
    Properties
    {
        //_MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        //Tags { "RenderType"="Opaque" }
        //LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work

            #include "UnityCG.cginc"


            struct v2f
            {
                //float2 uv : TEXCOORD0;
                //UNITY_FOG_COORDS(1)
                //float4 vertex : SV_POSITION;
                float4 pos : SV_POSITION;
                fixed4 color : COLOR0;
            };



            v2f vert (appdata_full v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);

                //可视化法线方向
                o.color = fixed4(v.normal * 0.5 + fixed3(0.5, 0.5, 0.5),1.0);

                //可视化切线方向
                o.color = fixed4(v.tangent.xyz * 0.5 + fixed3(0.5, 0.5, 0.5),1.0);

                //可视化副切线方向
                fixed3 binormal = cross(v.normal, v.tangent.xyz) * v.tangent.w;
                o.color = fixed4(binormal * 0.5 + fixed3(0.5, 0.5, 0.5), 1.0);

                //可视化第一组纹理坐标
                o.color = fixed4(v.texcoord.xy, 0.0, 1.0);

                //可视化第二组纹理坐标
                o.color = fixed4(v.texcoord1.xy, 0.0, 1.0);

                //可视化第一组纹理坐标的小数部分
                o.color = frac(v.texcoord);
                if (any(saturate(v.texcoord) - v.texcoord))
                {
                    o.color.b = 0.5;
                }
                o.color.a = 1.0;

                //可视化第二组纹理坐标的小数部分
                o.color = frac(v.texcoord1);
                if (any(saturate(v.texcoord1) - v.texcoord1)) {
                    o.color.b = 0.5;
                }
                o.color.a = 1.0;

                //可视化顶点颜色
                //o.color = v.color;

                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return i.color;
            }
            ENDCG
        }
    }
}
 

帧调试器

通过 window->analyze->Frame Debugger 即可启用帧调试器

可以用于查看渲染该帧时进行的各种渲染事件

  1. 最上方的滑动条:重放渲染事件
  2. 左侧区域显示所有事件的树状图,可以从每个事件了解渲染的整个过程
  3. 右侧窗口体现事件的细节

内在功能其实是停止渲染查看各个渲染事件的结果,即运行到哪一步,就在哪一步停下来,供我们查看。

渲染平台差异

坐标差异

引起的一大原因是OpenGL与DirectX的屏幕空间出现不同,竖直方向的相反。

不过在平常情况下unity会为我们处理这种不同,只有在当我们打开了抗锯齿且进行了渲染到纹理的操作后,此时得到的图像不会被unity翻转,因此在采样这一环节就应该符合DirectX平台的规定。

UNITY_UV_STARTS_AT_TOP用于判断当前平台类型是否为DirectX类型

_MainTex_TexelSize.y是否小于0用来检验是否开了抗锯齿

语法差异

DirectX对Shader的语义会更加严格

语义差异

不同平台上有一些语义是不等价的

例如:SV_POSITION 和POSITION在一些平台上并不是等价的

书写Shader时保证简洁的一些建议

精度问题

float、half、fixed的精度在不同平台上的表现是不一样的,尽可能采用低精度,确保性能

在移动平台上要尽可能注意到精度的问题,因为移动平台的优化技术是非常重要的

语法规范

注意初始化问题(对DirectX平台的适配问题

避免不必要的计算

要小心需要的临时寄存器数目或指令数目超过当前可支持的数目,不同的Shader Target、不同的着色器阶段可使用的临时寄存器和指令数目是不同的,可以通过指定更高级别的ShaderTarget来消除这些错误。

p118有各个Shader Target支持的指令数目

慎用分支和循环语句

它们会降低GPU的并行处理操作!!!

如果必须要用那么:

  1. 分支判断语句中使用的条件变量最好是常数,即在Shader运行过程中不会发生变化;
  2. 每个分支中包含的操作指令数尽可能少;
  3. 分支点嵌套层数尽可能少。

不要除以0

这会导致一些不可预测的后果,平台不同时就会导致微妙的变化

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值