发布时间:2023-12-01 10:30
shader结构体 颜色叠加
2022.5.27
Shader \"Unlit/003\"
{
//属性块
Properties
{
_MainTex (\"Texture\", 2D) = \"white\" {}
_Color(\"Color\",Color) = (1,1,1,1)
}
SubShader
{
Tags { \"RenderType\" = \"Opaque\" }
LOD 100
Pass
{
CGPROGRAM
//定义了顶点着色器和片元着色器的函数名 在下面调用的时候 名字必须相同 否则会编译出错
#pragma vertex vert //顶点vert
#pragma fragment frag //片元frag
// make fog work
#pragma multi_compile_fog
//只有在CGPROGRAM内再次定义一个与属性块内名字与类型相同的变量
//属性块里面对应的变量才会起作用,才能被代码调用
fixed4 _Color;
//结构体
struct a2v //a代表 application(应用) 2(谐音to) vert
{ //即应用到顶点着色器
//用模型顶点填充v变量
float4 vertex:POSITION;
//用模型的法线方向填写n变量
float3 normal:NORMAL; //NORMAL语义就是法线 法线是代表方向 没有位移相关的概念 法线就是永远垂直于平面的向量(初中数学,不要忘记了)
//用模型的第一套UV纹理填充texcoord
float4 texcoord:TEXCOORD0; //TEXCOORD0语义是公认的第一套UV
};
struct v2f //v(vert) to f(frag) 从顶点着色器到片元着色器
{
//SV_POSITION语义告诉unity :pos为剪裁空间中的位置信息
float4 pos:SV_POSITION;
//COLOR0 语义可以储存颜色信息
fixed3 color : COLOR0;
};
//unity会自动引入库文件
#include \"UnityCG.cginc\"
//正常我们编写OpenGL和DX里面,我们要从代码层面上把顶点信息或者其它什么信息全部计算好然后送过来
//在Unity里面,这些都已经做好了。我们只需要去定义输入,并且保证渲染的模型有这个输入 就可以了
//在这里我们的输入变成了结构体,然后通过获取结构体里面的变量 达到同样的效果
v2f vert(a2v v)
{
v2f o;
o.pos= UnityObjectToClipPos(v.vertex);
o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
//(将-1到1这个区间 变换为0到1) 就是除以2然后加上0.5
//-1到1这个区间的-0.6变为 0到1区间的就是-0.6/2=>-0.3+0.5=>0.2 变换成功
return o;
}
fixed4 frag(v2f i) : SV_TARGET
{
fixed3 c = i.color;
//通过 . 来访问我们的属性,也就是i.xywz i.rgba i.x i.xw 只需要用相应的fixed来存放
c *= _Color.rgb; //颜色叠加 三维乘以三维
return fixed4(c,1);
}
ENDCG
}
}
}
首先,我们可以在shader代码开始的时候去使用参数块去定义参数,在外部进行配置
那么我们在代码中可以直接拿来使用吗?
不,我们需要在我们的Pass语句块里面CGPROGRAM内重新定义,才能引用
//只有在CGPROGRAM内再次定义一个与属性块内名字与类型相同的变量
//属性块里面对应的变量才会起作用,才能被代码调用
fixed4 _Color;
由于Shader里面没有类的概念,所以我们想要使用数据的集合,或者多种参数传递的时候,就需要我们来定义我们的结构体
a代表 application(应用) 2(谐音to) vert
我们在结构体里面可以使用语义,比如 float4 vertex:POSITION;
在结构体初始化的时候,vertex就会被自动赋值
//结构体
struct a2v //a代表 application(应用) 2(谐音to) vert
{ //即应用到顶点着色器
//用模型顶点填充v变量
float4 vertex:POSITION;
//用模型的法线方向填写n变量
float3 normal:NORMAL;
//NORMAL语义就是法线 法线是代表方向 没有位移相关的概念 法线就是永远垂直于平面的向量(初中数学,不要忘记了)
//用模型的第一套UV纹理填充texcoord
float4 texcoord:TEXCOORD0; //TEXCOORD0语义是公认的第一套UV
};
v(vert) to f(frag) 从顶点着色器到片元着色器
我们在结构体里面可以使用语义,比如 float4 pos:SV_POSITION;
在为结构体这个pos成员赋值的时候的时候,SV_POSITION就会被自动赋值
struct v2f //v(vert) to f(frag) 从顶点着色器到片元着色器
{
//SV_POSITION语义告诉unity :pos为剪裁空间中的位置信息
float4 pos:SV_POSITION;
//COLOR0 语义可以储存颜色信息
fixed3 color : COLOR0;
};
unity会自动引入库文件 #include \"UnityCG.cginc\"
正常我们编写OpenGL和DX里面,我们要从代码层面上把顶点信息或者其它什么信息全部计算好然后送过来
在Unity里面,这些都已经做好了。我们只需要去定义输入,并且保证渲染的模型有这个输入 就可以了
在这里我们的输入变成了结构体,然后通过获取结构体里面的变量 达到同样的效果
在这里我们将结构体传入
a2v v 在初始化的时候,语义就已经为里面的成员进行赋值了
然后我们进行坐标转换,将模型空间下的顶点转换到齐次裁剪空间
然后我们将结构体的color成员,赋值为0-1的一个区间,这个区间的值是和法线相关的
比如说,一个正方体,一个面的法线是相同的,所以一个面的颜色是相同的,这个很好理解
v2f vert(a2v v)
{
v2f o;
o.pos= UnityObjectToClipPos(v.vertex);//将模型空间下的顶点转换到齐次裁剪空间
o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
//(将-1到1这个区间 变换为0到1) 就是除以2然后加上0.5
//-1到1这个区间的-0.6变为 0到1区间的就是-0.6/2=>-0.3+0.5=>0.2 变换成功
return o;
}
在这里我们将顶点着色器的结果结构体作为参数传入
我们定义一个颜色变量fixed3拿到颜色值
然后我们对这个颜色乘以我们的参数_Color,这个可以在参数面板动态设置的
然后我们返回一个fixed4的值作为最终的像素颜色值
fixed4 frag(v2f i) : SV_TARGET
{
fixed3 c = i.color;
//通过 . 来访问我们的属性,也就是i.xywz i.rgba i.x i.xw 只需要用相应的fixed来存放
c *= _Color.rgb; //颜色叠加 三维乘以三维
return fixed4(c,1);
}