一个仅仅是表现rgb的shader
一个简单的rgb颜色的渲染
Shader "Custom/RgbShader"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
float4 vert(float4 pos:POSITION):POSITION
{
return UnityObjectToClipPos(pos);
}
#pragma fragment frag
fixed4 frag():COLOR
{
return fixed4(1,0,0,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
逐行翻译一下,
首先Shader”Custom/RgbShader”这个是此shader的名称及再unity 的内部路径,名字叫“RgbShader”存储在Custom下
其次Properties是该shader能在unity右边功能栏能显示的属性,以下划线“_”开头”_Name”能够在此shader中直接定义然后调用,”(…)”中是他的面板名称与属性,比如_Color(“Color Tint”,Color)就可以翻译成_Color这个属性在unity的功能面板中的名字为”Color Tint”,该属性的属性是“Color”这个Color是内置的一个属性代表颜色,一般是fixed4,储存了R、G、B、A这四种属性。但在用的时候可能就用R,G,B这三个。”=”赋值后面的是默认值。
所以shader代码的开头一般为这样
Shader"Custom/ShaderName"
Properties{
_Color{"Color",Color}=(1,1,1,1)
...
}
然后就是我们的Subshader。在unity调用一个shader的时候会扫描该shader下的所有subshader然后选择一个能够在该平台下运行的subshader,如果没有的话会调用Fallback之后语义定义的一个内置的shader来达到降级运行的效果。如果不想调用的话,直接添加Off关闭就行了(Fallback Off)。本shader的降级选项是”Diffuse”这个内置shader。所以一个shader必包含至少一个subshader。而subshader中一定包含起码一个Pass(注意这个Pass必须第一个字母大写),因为Pass语句定义了一次完整的渲染过程。在subshader中可以有多个Pass。而有些shader中无Pass,就比如新建的默认standard surface shader,他其中就没有Pass这个语句,因为他在下面的#pragma surface surf Standard fullfowardshadows,进行了一次内置的渲染过程,这个是shaderlab中的默认语句,在编写hlsl时仍需要完整的写出来。所以,添加了这些之后的shader应该是这样的
Shader"Custom/ShaderName"
Properties{
_Color("Color",Color)=(1,1,1,1)
}
Subshader{
Pass{
}
}
Fallback "Diffuse"
这样,我们一个基本的shader大框架就搭建完毕了。
然后是CGPROGRAM,这个语句是一个组合,有CGPROGRAM一定有一个ENDCG。这个语句表示这一区域的代码适用于CG语言。当然unity支持opengl与hlsl这两种GPU语言,所以亦可以是HLSLPROGRAM 与 ENDHLSL来组合,这样就告诉编译器,这篇代码是用hlsl来编写的。添加上这部分的代码我们的框架又充实了一点。如下呈现
Shader"Custom/ShaderName"
Properties{
_Color("Color",Color)=(1,1,1,1)
...
}
Subshader{
Pass{
CGPROGRAM
...
ENDCG
}
}
Fallback "Diffuse"
如此我们就可以正式的用CG语言编写我们的shader代码了。
#pragma vertex vert
这行代码#pragma是编译指令,告诉编译器我要编译什么函数,在shader中可以编译的一般只有两种着色器,顶点与片元。所以#pragma vertex vert就是告诉编译器我要将vert函数编译成顶点着色器。同理编译片元着色器就是#pragma fragment frag。这样就可以继续丰富我们的代码了。
Shader"Custom/ShaderName"
Properties{
_Color("Color",Color)=(1,1,1,1)
...
}
Subshader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
...
ENDCG
}
}
Fallback "Diffuse"
然后我们来编写我们的顶点着色器
float4 vert(float4 pos:POSITION):SV_PSOITION{
}
这其中float4其实是一个数组定义,定义了vert这个函数的返回值是一个1X4的数组,每个数的类型是float,()中的float4 pos:POSITION是获取目标的顶点位置作为输入,其中POSITION是一个语义绑定的概念,这个概念相当于告诉unity讲模型的顶点坐标填充到pos这个参数pos中,而SV_POSITION则告诉unity,输出是裁剪空间的顶点坐标,类型就是我们在函数一开始定义的float4。如果没有这些语义的话,unity不知道用户的输入与输出。由于这个着色器是一个很简单的着色器,所以就包含了一行代码。
return UnityObjectToClipPos(pos);
UnityObjectToClipPos()是新版unityshader的内置函数,作用就是相当于原来之前的mul(UNITY_MATRIX_MVP,pos);矩阵变换 。该矩阵变换是将当前的模型的顶点/方向矢量从模型空间变换到裁剪空间。所以完整的顶点着色器的代码如下。(mul是multiple的缩写,在这指乘法)
float4 vert(pos:POSITION):SV_POSITION{
return UnityObjectToClipPos(pos);
}
同理我们也可以定义片元着色器的函数
fixed4 frag():SV_Target{
return fixed4 color=(1.0,0.0,0.0,1.0);
}
在这个案例中由于frag函数没有任何输入,输出是一个fixed4的变量,这里就直接输出一个颜色。其中SV_Target也是一个语义绑定。这个属于HLSL中的一个系统语义,相当于告诉渲染器,把用户的输出颜色储存到一个渲染目标(render target)中,这里将默认储存到帧缓存中。
Shader"Custom/RGBShader"
{
Properties{
_Color("Color Tint",Color)=(1.0,1.0,1.0,1.0)
}
Subshader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 pos:POSITION):SV_POSITION{
return UnityObjectToClipPos(pos);
}
fixed4 frag():SV_Target{
return fixed4 (1.0,0.0,0.0,1.0);
}
ENDCG
}
}
Fallback "Diffuse"
}
我们如何在shader graph中实现这个代码效果呢,其实很简单
创建一个”Color”标签,然后将他连接到Albedo就可以得到预期的效果。
连接一个color 节点就行了。
可我们在UE4的shader节点编辑器里面,也一样,但UE4中暂时没找到像shader graph那样的直接的颜色标签,他以另一种形式呈现,”Constant”是一个常量标签,有4种形式,constant 1是一个一维常量值,在颜色部分仅表示黑白,但他又是浮点数的形式,所以还可以表达灰色这种中间色。constant 2是一个二维的向量表达,但在颜色这里仅有R、G属性,constant 3就是我们这里用的R、G、B颜色表达。所以本例中要表现红色的表面,我们可以直接进行一个“1.0,0.0,0.0”的颜色输出。constant4,就是我们上面shader所写的RGBA的一个表达。
而在substance design(以后简称SD),中他的表达方式更加直接,可以直接添加Uniform Color标签然后添加到Base Color的输出。
到此,我们第一个基础的颜色表达已经完成。