赞
踩
Shader "MyShader" { // 名字 Properties { //所需的各种属性 } SubShader { // 显卡A用的子着色器 [Tags] //可选的,告诉Unity的渲染引擎:希望怎样以及何时渲染这个对象 [RenderSetup] //可选的,状态设置 Pass { // 每个 Pass定义了一次完整的渲染流程 [Name] [Tags] [RenderSetup] // other code } } SubShader { // 显卡B用的子着色器 //和上一个SubShader类似 } FallBack "Diffuse" // 如果上面的SubShader都不能在这块显卡上运行,就使用这个最低级的Shader }
【Name】
通过在字符串中添加斜杠("/") 可以控制 nity Shader 在材质面板中出现的位置
【Properties】
这些属性将会出现在材质面板中
【SubShader】
SubShader { // 显卡A用的子着色器
[Tags] // /可选的,告诉Unity的渲染引擎:希望怎样以及何时渲染这个对象
[RenderSetup] //可选的,状态设置
Pass { // 每个 Pass定义了一次完整的渲染流程
}
}
1 SubShader标签Tags:
2 状态设置:设置显卡的各种状态
3 Pass语义块
Pass { // 每个 Pass定义了一次完整的渲染流程
[Name]
[Tags]
[RenderSetup]
// other code
}
Pass 中定义该 Pass 名称,通过这个名称,我们可以使用 ShaderLab UsePass 令来直接使用其他 Unity Shader 中的Pass,注意在使用 sePass 命令时必须使用大写形式的名字。
Pass 同样可以设置标签,是用千告诉渲染引擎我们希望怎样来渲染该物体
4、Fallback
自动返回一个通用的最低级的Pass
定义在Pass 语义块内的 CGPROGRAM ENDCG 之间
需要自已定义每个 Pass 需要使用的 Shader 代码,更复杂但灵活性高
是 Unity 对顶点/片元着色器的更高一层的抽象,Unity 为我们处理了很多光照细节, 在背后仍旧把它转换成对应的顶点/片元着色器
表面着色器被定义在 SubShader 语义块内的 CGPROGRAM ENDCG 之间,不需要开发者关心使用多少个 Pass 、每个Pass 如何渲染等问题,
用在一些旧的设备上 其 GPU 仅支持 DirectX 7.0 OpenGL 1.5 OpenGL ES 1. 1), 它们不支持可编程管线着色器,这些着色器往往只可以完 一些非常简单效果
总结
【固定函数着色器】需要在非常旧的设备上运行
【表面着色器】 有各种光源打,但需要小心在移动平台上的性能表现。
【顶点/片元着色器】需要使用的光照数目非常少(例如只有个平行光);或者需要很多自定义的渲染效果
在VS计算颜色,然后直接传到FS输出即可
Shader "Custom/VertexLevel" { Properties { _Diffuse("Diffuse", Color) = (1,1,1,1) // 得到并且控制材质的漫反射颜色 // _Diffuse("Diffuse", Color) = (0, 0, 0, 0) // 得到并且控制材质的漫反射颜色 _Specular("Specular", Color) = (1, 1, 1, 1) // 材质的高光颜色 _Gloss("Gloss", Range(8.0, 256)) = 20 // 高光范围 } SubShader{ Pass { Tags { "LightMode" = "ForwardBase" } // 该Pass的光照模式,只有定义了正确的 LightMode,才能得到一些 Unity 的内置光照变蜇 CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" // 使用 Unity 内置变量 fixed4 _Diffuse; // 要加Properties 语义块中声明的属性 fixed4 _Specular; // 颜色属性的范围在0~1,用fixed float _Gloss; // 范围很大,用float struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; fixed3 color : COLOR; // 为了VS中计算得到的光照颜色传递给FS }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); // 顶点位置转到clip fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject)); // unity_WorldToObject为模型到世界的逆矩阵,调换Mul中位置得到转置,法线是3维的,取前三行前三列 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); // 光源方向由_WorldSpaceLightPos0得到 fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal)); // 注意是入射方向 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz); // 世界空间中的摄像机位置 - 世界空间中的顶点位置 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; // 内置变量得到环境光 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); // saturate限制在 [0,1];点积时向量要出在同一坐标系下,这里选择世界坐标系,记得归一化 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss); o.color = ambient + diffuse + specular; return o; } fixed4 frag(v2f i) : SV_Target{ return fixed4(i.color, 1.0); } ENDCG } } FallBack "Diffuse" }
【理论】
漫反射:
参数:入射光线的颜色和强度+材质的漫反射系数+表面法线+光源方向
HalfLambert 半兰伯特漫反射:max(0, nl)改成了 nl*0.5 + 0.5, 背面也有明暗变化
高光反射:
参数:入射光线的颜色和强度+材质高光反射颜色+观察方向+反射方向+材质反光度(反光区域大小)
【源代码】各项同性,逐像素
Shader "Custom/Phong" { Properties { _Diffuse("Diffuse", Color) = (1,1,1,1) _Specular("Specular", Color) = (1, 1, 1, 1) _Gloss("Gloss", Range(8.0, 256)) = 20 } SubShader{ Pass { Tags { "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Diffuse; fixed4 _Specular; float _Gloss; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o; } fixed4 frag(v2f i) : SV_Target{ fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal)); fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss); return fixed4(ambient + diffuse + specular, 1.0); } ENDCG } } FallBack "Diffuse" }
【具体解释】
Shader "Custom/C6_PixelLevel" { Properties { // 得到并且控制材质的漫反射颜色 _Diffuse("Diffuse", Color) = (1,1,1,1) // 材质的高光颜色 _Specular("Specular", Color) = (1, 1, 1, 1) // 高光范围 _Gloss("Gloss", Range(8.0, 256)) = 20 } SubShader{ Pass { // 有定义了正确的 LightMode,我们才能得到 Unity 的内置光照变量 Tags { "LightMode" = "ForwardBase" } CGPROGRAM // 表明该函数包含了顶点着色器的代码,一般用vert #pragma vertex vert // 该函数包含了片元着色器的代码, 一般用frag #pragma fragment frag // 使用 Unity 内置的一些变量 #include "Lighting.cginc" //在CG代码中, 定义一个与属性名称和类型都匹配的变量,也就是说Properties有啥这里也要有啥 fixed4 _Diffuse; // 颜色属性的范围在0~1,用fixed fixed4 _Specular; // 范围很大,用float float _Gloss; //使用一个结构体来定义项点着色器的输入 struct a2v { // POSITION 语义告诉Unity,用模型空间的顶点坐标填充vertex变量 float4 vertex : POSITION; // NORMAL语义告诉Unity,用模型空间的法线方向填充normal变量 float3 normal : NORMAL; }; //使用一个结构体来定义项点着色器的输出 struct v2f { // SV_POSITION语义告诉Unity, pos里包含了顶点在裁剪空间中的位置信息 float4 pos : SV_POSITION; // TEXCOORDO语义告诉Unity,用模型的第一套纹理坐标填充texcoord变量 float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; }; v2f vert(a2v v) { // 声明输出结构 v2f o; // 顶点位置从模型空间变换到裁剪空间 o.pos = UnityObjectToClipPos(v.vertex); // 将表面法线从模型空间变换到世界空间 // 用顶点变换矩阵的逆转置矩阵:WorldToObject逆,放在mul右侧代表转置,因为法线是三维矢量,截取前三行前三列 o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject); // 顶点位置从模型空间变换到世界空间,用于FS计算光照 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o; } fixed4 frag(v2f i) : SV_Target{ // SV_Target 也是 HLSL 中的一个系统语义,它等同于告诉渲染器,把用户的输出颜色存储到一个渲染目标(render target) 中,这里将输出到默认的帧缓存中 // 法线方向,世界坐标下 fixed3 worldNormal = normalize(i.worldNormal); // 光源方向,世界坐标下 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); // 反射方向,世界坐标下:reflect(i,n),注意入射方向 fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal)); // 观察方向:= 世界坐标下的相机位置-世界坐标下的物体位置 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz); // 环境光:利用内置变量得到 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; // 漫反射:saturate(x):把x截取在[0,1]范围内 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); // 高光 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss); return fixed4(ambient + diffuse + specular, 1.0); } ENDCG } } FallBack "Diffuse" }
【理论】
这两种光照模型都是经验模型
【代码】
Shader "Custom/C6_Blinn-Phong" { Properties { _Diffuse("Diffuse", Color) = (1,1,1,1) _Specular("Specular", Color) = (1, 1, 1, 1) _Gloss("Gloss", Range(8.0, 256)) = 20 } SubShader{ Pass { Tags { "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Diffuse; fixed4 _Specular; // 颜色属性的范围在0~1,用fixed float _Gloss; // 范围很大,用float struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o; } fixed4 frag(v2f i) : SV_Target{ fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); // fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal)); fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz); // 在世界坐标下计算 fixed3 halfDir = normalize(worldLightDir + viewDir); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); // fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (dot(worldNormal, worldLightDir)*0.5 + 0.5); // HalfLambert 半兰伯特漫反射,背面也有明暗变化 // fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss); return fixed4(ambient + diffuse + specular, 1.0); } ENDCG } } FallBack "Diffuse" }
Phong和Blinn-Phong 对比:
半兰伯特漫反射和Blinn-Phong对比:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。