漫反射
漫反射计算公式 : C diffuse = (C light · M diffuse ) max(0 , n · l )
C light :入射光线的强度和颜色
M diffuse : 材质的漫反射系数 物体本色
n : 法线单位向量
l : 光源单位向量
逐顶点漫反射代码 :
效果图:
Shader "DiffuseVertex" { Properties { _Diffuse ("Diffuse",Color)=(1,1,1,1) } SubShader { Pass{ Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Diffuse;//获取反漫射颜色(既上面设置的物体自身颜色) struct a2v{ float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f{ float4 pos : SV_POSITION; fixed3 color : COLOR; }; //逐顶点漫反射 v2f vert(a2v v){ v2f o; o.pos = UnityObjectToClipPos(v.vertex); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光 //由于下方法线光线两个向量点乘必须处于 同一坐标系下 所以此处将此处的顶点转换到 //通过矩阵坐标空间转换 以及 单位转换 算出单位法线向量 //unity_WorldToObject 既 _World2Object 变换矩阵 可将模型空间转换到世界空间 //通过调换顺序已达到此矩阵的转置矩阵 注意 mul 乘法公式从左到右 //由于法线向量是个三维矢量 将变换矩阵通过 float3x3 转成3x3矩阵 fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); // 取得光线的单位向量 fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz); // normalize 单位化 归一化 //通过点乘 获得 法线与光线的夹角 saturate 只截取[0,1]范围内 防止为负数 s //光线的颜色*漫反射的颜色(物体本色)*光线与法线的夹角 光线照射的角度 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight)); //环境光与漫反射相加 得到最终的颜色 o.color = ambient + diffuse; return o; } //片元着色器直接输出 fixed4 frag(v2f i) : SV_Target{ return fixed4(i.color,1.0); } ENDCG } } FallBack "Diffuse" }
逐片元(像素)漫反射代码 :
效果图:
Shader "DiffusePixel" { Properties { _Diffuse ("Diffuse",Color)=(1,1,1,1) } SubShader { Pass{ Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Diffuse;//获取反漫射颜色(既上面设置的物体自身颜色) struct a2v{ float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f{ float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; }; v2f vert(a2v v){ v2f o; //投影矩阵 将模型空间转换为裁切空间 o.pos = UnityObjectToClipPos(v.vertex); //空间转换 o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject); //将世界空间下的法线传递给片元着色器 return o; } fixed4 frag(v2f i) : SV_Target{ fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光 //同逐顶点 fixed3 worldNormal = normalize(i.worldNormal); //光线单位向量 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); //漫反射计算主体 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir)); //颜色叠加计算出最后的颜色 fixed3 color = ambient + diffuse; //返回 return fixed4(color,1.0); } ENDCG } } FallBack "Diffuse" }
半兰伯特公式 像素漫反射:
效果图:
Shader "HalfLambert" { Properties { _Diffuse ("Diffuse",Color)=(1,1,1,1) } SubShader { Pass{ Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Diffuse;//获取反漫射颜色(既上面设置的物体自身颜色) struct a2v{ float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f{ float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; }; v2f vert(a2v v){ v2f o; //投影矩阵 将模型空间转换为裁切空间 o.pos = UnityObjectToClipPos(v.vertex); //空间转换 o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject); //将世界空间下的法线传递给片元着色器 return o; } fixed4 frag(v2f i) : SV_Target{ fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光 //同逐顶点 fixed3 worldNormal = normalize(i.worldNormal); //光线单位向量 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); //漫反射计算主体 //fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir)); //利用半兰伯特公示计算 原理是将原来的max控制最低值的方法给取消 //取代为将值变为原来的一半 原[-1,1] 乘上0.5得 [-0.5,0.5] 最后加上0.5 得 [0,1] 因此称为半兰伯特 //通过这种方法 能够使背光面也会有光线明暗过渡 而不是如同一张纸一样呈现出一个颜色 fixed halfLambert = dot(worldNormal,worldLightDir) * 0.5 + 0.5; fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert; //颜色叠加计算出最后的颜色 fixed3 color = ambient + diffuse; //返回 return fixed4(color,1.0); } ENDCG } } FallBack "Diffuse" }
三种类型的漫反射反射:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了