Unity3D Shader之光照模型——理论与实践:用两种方式来实现漫反射Diffuse Reflection
2016-11-03 16:07
791 查看
漫反射原理解析
众所周知,漫反射即光线射到粗糙的物体表面时发生的反射现象,入射光线为平行光线,而出射光线为各个方向。光在空气中以直线传播,光线的反射也遵守物理规则。如下图所示:图片来源于网络。
上图左侧入射方向的是平行光,反射光也是平行光,这种现象称为镜面反射。而左侧反射光不平行无规则的则为漫反射。
图片来源于网络。
上图左侧表示,入射光线与出射光线形成的夹角,被垂直于反射面的光线均分。上图右侧表示在圆弧或不规则表面时,反射平面为反射点的切线,此时反射点的法线为经过此点垂直于其切线的直线。
然而在图形处理中,实际情况是模型远远没有现实这么复杂,有的时候甚至想用简单的模型(甚至是完全平面的模型)来表现出复杂或是特殊材质的物体。对于漫反射而言,不可能真的去做出具有无数个顶点,表面具有极其细微的凹凸不平之处的模型,如果真这样做,无论是人力还是计算机的处理能力都是非常有限的。因此就要使用一定的算法来模拟漫反射。
根据反射的规则和实际生活情况可知,入射光线与反射光线的夹角越小,则反射强度越大。并且物体表面越粗糙,那么反射后的亮度越弱,这是因为粗糙的表面将光线反射到了各个地方去。因此,我们要模拟的就是:
反射规则:入射光线与反射光线的关系
光线逸散:反射后由物体表面粗糙的原因导致光线光线逸散,反射后光线亮度变低
结合上两点,在实际生活中观察到的漫反射现象是: 入射光线与法线的夹角越小,则反射后的光线亮度越大。于是便采用 入射光线与法线的点积来 来计算反射系数,因为点积的几何意义是:点积的值越大,则两个向量的方向越相近。
结合我前面的文章《Unity3D内建参数文档翻译与解析——Built-in shader variables》来使用两种不同的Shader形式实现漫反射。
可编程Shader实现方式
代码
Shader "Custom/DiffuseReflection" { Properties { _Color("Color", Color) = (1,1,1,1) _MainTex("Texture", 2D) = "white" {} } SubShader { // 设定LightMode为ForwardBase,相关细节可以查看我之前的文章《Unity3D光照前置知识——Rendering Paths(渲染路径)及LightMode(光照模式)译解》 Tags{ "LightMode" = "ForwardBase" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" // 使用Unity3D的头文件"Lighting.cginc",包含有我们需要的光照参数 #include "Lighting.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; half3 normal : NORMAL; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float4 diff : TEXCOORD1; float4 diffColor : TEXCOORD2; }; v2f vert(appdata v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.uv; // 本例中将光照计算过程写在vert函数内,因为这样相比写在frag函数内更节约性能。不过当然效果肯定没有在frag内好。 // 计算物体法线(用来代表在物体上入射点处的法线)与光照方向的点积,得到漫反射系数diff,用来表示漫反射的光照衰减,并且保证其值大于0。 float diff = max(0, dot(v.normal, _WorldSpaceLightPos0.xyz)); // 利用系数计算光线衰减后的色值 o.diffColor = _LightColor0 * 2 * diff; return o; } sampler2D _MainTex; fixed4 _Color; fixed4 frag(v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv) * _Color; // 得到最终颜色 col.rgb = i.diffColor * col.rgb; return col; } ENDCG } } }
结果
Surface Shader实现方式
代码
surface shader是Unity3D特有的一种Shader编写形式,封装了许多光照相关的功能。以后会开坑细讲。Shader "Custom/DiffuseReflection" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM // 声明自定义光照函数名 #pragma surface surf DiffuseReflection #pragma target 3.0 sampler2D _MainTex; struct Input { float2 uv_MainTex; }; fixed4 _Color; // 自定义光照函数 half4 LightingDiffuseReflection(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) { half diff = max(0, dot(s.Normal, lightDir)); half3 c = s.Albedo * diff * _LightColor0.rgb * 2; return fixed4(c, s.Alpha); } void surf (Input IN, inout SurfaceOutput o) { fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
结果
相关文章推荐
- Unity3D - Shader - 实现漫反射光照模型
- Unity3D ShaderLab 自定义光照模型
- Shader自学笔记 2.1.1 逐顶点漫反射光照模型实现
- Unity3d-Shader-光照模型
- UnityShader初级篇——实现逐顶点高光反射光照模型
- 13、生产者消费者模型_两种实现方式2
- <unity shader入门精要> - unity shader 中实现漫反射光照模型
- Shader自学笔记 2.1.3 半兰伯特光照模型实现
- Unity实现标准光照模型的Shader代码
- 三种光照模型的shader实现
- Unity3D for VR 学习(9): Unity Shader 光照模型 (illumination model)
- Unity3D for VR 学习(9): Unity Shader 光照模型 (illumination model)
- unity shader 入门之路(五)标准光照模型理论
- Unity3D Shader 半兰伯特光照模型
- Unity3D ShaderLab Half Lambert光照模型
- Shader自学笔记 2.1.2 逐像素漫反射光照模型实现
- 13、生产者消费者模型_两种实现方式
- 计算机图形学——MFC和OpenGL两种方法实现光照模型
- Unity3D - Shader - 高光反射光照模型
- 用Shader实现标准光照模型