找回密码
 立即注册
查看: 369|回复: 0

Unity Shader应用

[复制链接]
发表于 2022-1-5 10:17 | 显示全部楼层 |阅读模式
实验性工具 Shader Forge

    这里的连连看插件用的是Shader Forge,但是现在已经不更新了,最后更新是在2018的版本中,但是也可以用。 Shader Forge最后生成的Shader代码没有Shader Graph那么多,稍微方便一点,所以先用这个。
漫反射模型(兰伯特光照)
兰伯特光照是最基础的漫反射模型,其效果如下


Lambert光照模型

在兰伯特光照中,很明显,朝向光的点最亮(灰度为1),背向光的点最暗(灰度为0),中间则介于0~1之间。
通过光的反方向lDir某个点的朝向(该点法向量)nDir的接近程度,就可以得知该点是否面朝光
刚好,数学上的点乘Dot刚好可以用于表示两个向量方向的接近程度,数值越大,两者方向越接近。(两个向量前提都经过了归一化处理)
点乘的定义是:a·b = |a||b|cosθ
当某点面朝光时,θ = 0,那么cosθ = 1。最后点乘结果也是等于1。
模型上的每个点都进行一次 灰度值 = a·b 的运算,就可以得到整个模型经过漫反射之后的外观。


  • 用到的函数:
    UnityObjectToClipPos(点的局部坐标)
    UnityObjectToWorldNormal( 点的局部法向量 )
    dot(向量,向量)
代码

Shader "Shader Forge/02" {     Properties {     }     SubShader {         Tags {             "RenderType"="Opaque"         }         Pass {             Name "FORWARD"             Tags {                 "LightMode"="ForwardBase"             }                          CGPROGRAM             #pragma vertex vert             #pragma fragment frag             #include "UnityCG.cginc"              struct VertexInput {                 float4 vertex : POSITION;                 float3 normal : NORMAL;             };             struct VertexOutput {                 float4 pos : SV_POSITION;                 float3 normalWS : TEXCOORD;             };              VertexOutput vert (VertexInput v) {                 VertexOutput o = (VertexOutput)0;                 o.pos = UnityObjectToClipPos( v.vertex );                 o.normalWS = UnityObjectToWorldNormal( v.normal );                 return o;             }             float4 frag(VertexOutput i) : COLOR {                 float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);                 float c = dot(i.normalWS,lightDir);                 c = max(0,c);                 return float4(c,c,c,1);             }             ENDCG         }     }     FallBack "Diffuse" }  镜面反射模型(高光反射)

Phong 模型
思想:亮度 = Dot(光折射方向, 视方向)
    用到的函数:reflect(入射光,法线) 、mul( 矩阵,矩阵(或向量) ) 用到的矩阵:unity_ObjectToWorld 用到的全局变量:_WorldSpaceCameraPos、_WorldSpaceLightPos0

image.png

代码

Shader "Shader Forge/02" {     Properties {         _Color("颜色",Color) = (1.0,1.0,0.0,1.0)         _SpecPow("高光次幂",Range(1,50)) = 30     }     SubShader {         Tags {             "RenderType"="Opaque"         }         Pass {             Name "FORWARD"             Tags {                 "LightMode"="ForwardBase"             }                          CGPROGRAM             #pragma vertex vert             #pragma fragment frag             #include "UnityCG.cginc"                          uniform float4 _Color;             uniform float _SpecPow;              struct VertexInput {                 float4 vertex : POSITION;                 float3 normal : NORMAL;             };             struct VertexOutput {                 float4 posCS : SV_POSITION;                 float4 posWS : TEXCOORD0;                 float3 normalWS : TEXCOORD1;             };              VertexOutput vert (VertexInput v) {                 VertexOutput o = (VertexOutput)0;                 o.posCS = UnityObjectToClipPos( v.vertex );                 o.posWS = mul(unity_ObjectToWorld, v.vertex);                 o.normalWS = UnityObjectToWorldNormal( v.normal );                 return o;             }             float4 frag(VertexOutput i) : COLOR {                 //准备向量                 float3 nDir = i.normalWS;                 float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWS);                 float3 lDir = normalize(_WorldSpaceLightPos0.xyz);                 float3 rDir = reflect(-lDir,nDir);                 //准备点积结果                 float nDotl = dot(nDir,lDir);                 float vDotr = dot(vDir,rDir);                 //光照模型                 float lambert = max(0,nDotl);                 //float phong = pow(max(0,vDotr),_SpecPow);  直接截断负值的方式                 float phong = pow((vDotr+1)/2,_SpecPow);  // 将[-1,1]的区间映射到[0,1]的方式                 //输出结果                 float3 finalRGB = _Color * lambert + phong;                 return float4(finalRGB,1.0);             }             ENDCG         }     }     FallBack "Diffuse" }  Blinn-Phong 模型
思想:亮度 = Dot(半角方向, 法线方向)

代码(除了frag其他和Phone一样)

            float4 frag(VertexOutput i) : COLOR {                 float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWS);                 float3 lDir = normalize(_WorldSpaceLightPos0.xyz);                 float3 hDir = normalize(vDir+lDir);                 float3 nDir = i.normalWS;                  float nDotl = dot(nDir,lDir);                 float nDoth = dot(nDir,hDir);                  float lambert = max(0,nDotl);                 float B_Phong = pow(max(0,nDoth),_SpecPow);                  float3 finalRGB = _Color * lambert + B_Phong;                 return float4(finalRGB,1.0);             } 将法线映射为颜色


float4 frag(VertexOutput i) : COLOR {      return float4(i.normalWS,1.0); } 三色环境光
思路:
    不同侧面的环境光:利用法线方向来确定朝向。 模型对环境光的遮挡导致的亮暗区别(例如耳朵朝内凹,因此内部容易被遮挡,会较暗):利用一张AO图(需要烘焙),来指明被遮挡的区域。


AO纹理

代码 (最后随意地结合了一下Lambert和Phong)

Shader "Shader Forge/03" {     Properties {         _Color("颜色",Color) = (1.0,1.0,0.0,1.0)         _SpecPow("高光次幂",Range(1,90)) = 30         _EnvUpCol("上部环境光色",Color) = (1,1,1,1)         _EnvDownCol("下部环境光色",Color) = (0.2,0.2,0.2,1)         _EnvSideCol("侧边环境光色",Color) = (0.1,0.8,0.1,1)         _Occlusion("环境遮罩图AO",2d) = "white"{}         _EnvIntensity("环境光强度",Range(0,1)) = 0.3     }     SubShader {         Tags {             "RenderType"="Opaque"         }         Pass {             Name "FORWARD"             Tags {                 "LightMode"="ForwardBase"             }                          CGPROGRAM             #pragma vertex vert             #pragma fragment frag             #include "UnityCG.cginc"                          uniform float4 _Color;             uniform float _SpecPow;              uniform float4 _EnvUpCol;             uniform float4 _EnvDownCol;             uniform float4 _EnvSideCol;             uniform float _EnvIntensity;             uniform sampler2D _Occlusion;             struct VertexInput {                 float4 vertex : POSITION;                 float3 normal : NORMAL;                 float2 uv : TEXCOORD0;             };             struct VertexOutput {                 float4 posCS : SV_POSITION;                 float4 posWS : TEXCOORD0;                 float3 normalWS : TEXCOORD1;                 float2 uv : TEXCOORD2;             };              VertexOutput vert (VertexInput v) {                 VertexOutput o = (VertexOutput)0;                 o.posCS = UnityObjectToClipPos( v.vertex );                 o.posWS = mul(unity_ObjectToWorld, v.vertex);                 o.normalWS = UnityObjectToWorldNormal( v.normal );                 o.uv = v.uv;                 return o;             }             float4 frag(VertexOutput i) : COLOR {                 //准备向量                 float3 nDir = i.normalWS;                 float3 vDir = normalize(_WorldSpaceCameraPos.xyz - i.posWS);                 float3 lDir = normalize(_WorldSpaceLightPos0.xyz);                 float3 rDir = reflect(-lDir,nDir);                 //准备点积结果                 float nDotl = dot(nDir,lDir);                 float vDotr = dot(vDir,rDir);                 //光照模型                     //漫反射 + 镜面反射                 float lambert = max(0,nDotl);                 float phong = pow((vDotr+1)/2,_SpecPow);                      //环境光                 float upMask = max(0,i.normalWS.y);                 float downMask = max(0,-i.normalWS.y);                 float sideMask = 1 - upMask - downMask;                 float occlusion = tex2D(_Occlusion,i.uv);                 float3 envCol = _EnvUpCol*upMask + _EnvSideCol*sideMask + _EnvDownCol*downMask;                  //输出结果                 float3 finalRGB = (_Color * lambert *(1-_EnvIntensity) + envCol * _EnvIntensity * occlusion + phong );  //这个暂时先用加法简单相加了,实际不知道是什么样的                                  return float4(finalRGB,1.0);             }             ENDCG         }     }     FallBack "Diffuse" }

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-9-23 00:27 , Processed in 0.091335 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表