【Unity Shader】Unity提供的CG/HLSL语义

主要参考《Unity Shader入门精要》一书,外加自己的一些总结


什么是语义


语义实际就是一个赋给Shader输入和输出的字符串,这个字符串表达了这个参数的含义。这些语义可以让Shader知道从哪里读取数据,并把数据输到哪里。
在DirectX10以后,有了一种新的语义类型,即系统数值语义(system-value semantics)。这类语义是以SV开头的,SV代表的就是系统数值。这些语义在渲染流水线中有特殊的含义,比如上一篇中,我们使用SV_POSITION 语义修饰顶点着色器的输出变量pos,那么就表示pos包含了可用于光栅化的变换后的顶点坐标,即齐次剪裁空间中的坐标。

Unity支持的语义

从应用阶段传递模型数据给顶点着色器时Unity支持的常用语义,表如下:



从顶点着色器传递给片元着色器时Unity支持的常用语义,表如下:


片元着色器输出时Unity支持的常用语义,表如下:




Unity中对Unity Shader 的调试方法:
1,使用假彩色图像
假彩色图像(false_color image)指的是用假彩色技术生成的一种图像。一张假彩色图像可以用于可视化一些数据,那么如何用它来对Shader 进行调试呢?
主要思想是,我们可以把需要调试的变量映射到[0,1]之间,把它们作为颜色输出到屏幕上,然后通过屏幕上显示的像素颜色来判断这个值是否正确。
作为实例,下面我们会使用假彩色图像的方式来可视化一些模型数据,如法线、切线、纹理坐标、顶点颜色,以及它们之间的运算结果等,代码如下:
Shader "Unity Shader Book/Chapter 5/False Color"{
	SubShader{
		Pass{
			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

			struct v2f {
				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 * 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
		}
	}
}

上面的代码中,我们使用了Uniyt内置的一个结构体——appdata_full。可以在UnityCG.cginc 里找到它的定义:
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;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

可以看出,appdata_full 几乎包含了所有的模型数据。
我们把计算得到的假彩色存储到了顶点着色器的输出结构体——v2f中的color 变量里,并且在片元着色器中输出了这个颜色。我们可以对其中的代码进行不同的注释,来观察不同运算和数据得到的效果。


Shader 整治之道

1,float、half、fixed
在CG/HLSL中,有三种精度的数值类型:float、half、fixed。这些精度将决定计算结果的数值范围,精度范围如下表:
上面的精度范围并不是绝对正确的,在不同的平台和GPU上,可能会有所不同。
尽可能使用精度较低的类型,因为这可以优化Shader的性能,这一点在移动平台上尤其重要。从它们大体的值域范围来看,我们可以使用fixed类型来存储颜色和单位矢量,如果要存储更大范围的数据可以选择half 类型,最差情况下再选择使用float。

2,避免不必要的计算
如果我们在Shader 中,尤其是片元着色器中,进行了大量的计算,那么很可能就会收到Unity的错误提示。不同的Shader Target、不同的着色器阶段,我们可以使用的临时寄存器和指令数目都是不同的。如下表:

3,慎用分支和循环语句
如果我们在Shader中使用了大量的流程控制语句,那么这个Shader的性能可能会成倍下降。解决方法就是,我们尽量把计算向流水线上端移动,比如,把放在片元着色器中的计算放到顶点着色器中,或者直接在CPU中进行预计算,再把结果传递给Shader。
4,不要除以0
不然结果不可预测。
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Unity Shader语义是一种用于定义着色器代码中变量的标识符。它们可以提供有关变量的更多信息,例如变量的作用、数据类型和使用方式。使用着色器语义可以使着色器代码更加简洁、易于阅读,并增加可维护性和可扩展性。 在Unity中,着色器语义通常用于顶点着色器和片段着色器中。在顶点着色器中,通过使用语义变量,可以将模型空间下的顶点位置转换为裁剪空间下的位置,并对其他语义变量进行计算和赋值。 在代码中,UnityObjectToClipPos函数被用来进行模型空间到裁剪空间的转换。这个函数是Unity内置的函数,它将模型空间下的坐标转换为裁剪空间下的坐标。具体实现方式可能会因Unity版本和平台而有所不同,但使用方法是一致的。 除了顶点着色器,语义还可以在片段着色器中使用。比如,在一个完整的代码案例中,我们可以使用纹理坐标和法线语义来对表面进行着色。在表面着色器函数中,我们可以将纹理坐标和主纹理的颜色值赋值给表面输出结构体,还可以将法线向量从世界空间变换到切线空间,并对其他表面输出结构体的变量进行计算和赋值。 总之,Unity Shader语义为我们提供了一种方式来定义和使用着色器代码中的变量,使其更具可读性和可维护性,并且能够方便地与其他着色器和渲染管线进行交互,同时也可以更方便地与外部程序进行交互。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值