【Aladdin Unity3D Shader编程】之三 光照模型(二)

 2023-09-15 阅读 22 评论 0

摘要:高光反射模型 Specular=直射光*pow(cos,高光的参数) :是反射光和视野方向的夹角 编写高光反射Shader Shader "AladdinShader/07 Specular Vertex Shader" {Properties{_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色}SubShader {Pass {Tags{

高光反射模型

Specular=直射光*pow(cosθ,高光的参数) θ:是反射光和视野方向的夹角

编写高光反射Shader

Shader "AladdinShader/07 Specular Vertex Shader"
{Properties{_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色}SubShader {Pass {Tags{"LightMode"="ForwardBase"}CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息  
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0 #pragma vertex vert
#pragma fragment frag fixed4 _Diffuse;struct a2v {float4 vertex:POSITION;float3 normal:NORMAL; //模型空间下法线};struct v2f{float4 position:SV_POSITION;fixed3 color:COLOR;};v2f vert(a2v v){v2f f;f.position = mul(UNITY_MATRIX_MVP, v.vertex);fixed3 adbient = UNITY_LIGHTMODEL_AMBIENT.rgb;fixed3 normalDir = normalize(mul(v.normal,(float3x3)unity_WorldToObject));fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 因为是平行光fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir), 0) * _Diffuse.rgb;//取得漫反射的颜色//反射光方向fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));//视野方向//相机是在世界空间下              fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(v.vertex,unity_WorldToObject).xyz);//高光反射fixed3 specular = _LightColor0.rgb * pow(max(dot(reflectDir,viewDir),0),10);f.color = diffuse + adbient + specular;return f;}fixed4 frag(v2f f):SV_Target{return fixed4(f.color, 1);}ENDCG}}FallBack  "VertexLit"
}

效果图:

添加_Gloss和SpecularColor控制高光大小和高光颜色

unity2d光照?添加一个Range属性,将X次幂的值改成Range属性,做如下修改:

_Gloss("Gloss",Range(8,200)) = 10
//高光反射
fixed3 specular = _LightColor0.rgb * pow(max(dot(reflectDir,viewDir),0),_Gloss);

就会看到高光光圈随着_Gloss改变而改变

想要改变高光部分的颜色控制,我们添加一个颜色变量然后将高光颜色与我们设置的颜色属性进行融合计算就会得到新的高光部分的颜色

Shader "AladdinShader/07 Specular Vertex Shader"
{Properties{_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色_Specular("Specular",Color)=(1,1,1,1)_Gloss("Gloss",Range(8,200)) = 10}SubShader {Pass {Tags{"LightMode"="ForwardBase"}CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息  
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0 #pragma vertex vert
#pragma fragment frag fixed4 _Diffuse;fixed4 _Specular;half _Gloss;struct a2v {float4 vertex:POSITION;float3 normal:NORMAL; //模型空间下法线};struct v2f{float4 position:SV_POSITION;fixed3 color:COLOR;};v2f vert(a2v v){v2f f;f.position = mul(UNITY_MATRIX_MVP, v.vertex);fixed3 adbient = UNITY_LIGHTMODEL_AMBIENT.rgb;fixed3 normalDir = normalize(mul(v.normal,(float3x3)unity_WorldToObject));fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 因为是平行光fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir), 0) * _Diffuse.rgb;//取得漫反射的颜色//反射光方向fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));//视野方向//相机是在世界空间下              fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(v.vertex,unity_WorldToObject).xyz);//高光反射fixed3 specular = _LightColor0.rgb * pow(max(dot(reflectDir,viewDir),0),_Gloss) * _Specular.rgb;f.color = diffuse + adbient + specular;return f;}fixed4 frag(v2f f):SV_Target{return fixed4(f.color, 1);}ENDCG}}FallBack  "VertexLit"
}

unity3d怎么制作shader。效果图:

实现逐像素的高光反射

Shader "AladdinShader/08 Specular Fragment Shader"
{Properties{_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色_Specular("Specular",Color)=(1,1,1,1)_Gloss("Gloss",Range(8,200)) = 10}SubShader {Pass {Tags{"LightMode"="ForwardBase"}CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息  
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0 #pragma vertex vert
#pragma fragment frag fixed4 _Diffuse;fixed4 _Specular;half _Gloss;struct a2v {float4 vertex:POSITION;float3 normal:NORMAL; //模型空间下法线};struct v2f{float4 position:SV_POSITION;float3 worldNormal:TEXCOORD0;//世界空间下的法线方向 float3 worldVertext:TEXCOORD1;//时间空间下的顶点坐标};v2f vert(a2v v){v2f f;f.position = mul(UNITY_MATRIX_MVP, v.vertex);f.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);f.worldVertext = mul(v.vertex , unity_WorldToObject).xyz;return f;}fixed4 frag(v2f f):SV_Target{fixed3 adbient = UNITY_LIGHTMODEL_AMBIENT.rgb;fixed3 normalDir = normalize(f.worldNormal);fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 因为是平行光fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir), 0) * _Diffuse.rgb;//取得漫反射的颜色//反射光方向fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));//视野方向//相机是在世界空间下              fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertext);//高光反射fixed3 specular = _LightColor0.rgb * pow(max(dot(reflectDir,viewDir),0),_Gloss) * _Specular.rgb;fixed3 tempColor = diffuse + adbient + specular;return fixed4(tempColor, 1);}ENDCG}}FallBack  "VertexLit"
}

效果图:

会比逐顶点高光效果更好一些,背光面可以考虑之前说的半兰伯特来处理,这样就不会显示全黑效果不好的情况。

使用Blinn-Phong光照模型

Specular=直射光颜色*pow(max(cosθ,0),10) θ:是发现和x的夹角 x是平行光和视野方向的平分线

Shader "AladdinShader/09 Specular Fragment Blinn Phong Shader"
{Properties{_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色_Specular("Specular",Color)=(1,1,1,1)_Gloss("Gloss",Range(8,200)) = 10}SubShader {Pass {Tags{"LightMode"="ForwardBase"}CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息  
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0 #pragma vertex vert
#pragma fragment frag fixed4 _Diffuse;fixed4 _Specular;half _Gloss;struct a2v {float4 vertex:POSITION;float3 normal:NORMAL; //模型空间下法线};struct v2f{float4 position:SV_POSITION;float3 worldNormal:TEXCOORD0;//世界空间下的法线方向 float3 worldVertext:TEXCOORD1;//时间空间下的顶点坐标};v2f vert(a2v v){v2f f;f.position = mul(UNITY_MATRIX_MVP, v.vertex);f.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);f.worldVertext = mul(v.vertex , unity_WorldToObject).xyz;return f;}fixed4 frag(v2f f):SV_Target{fixed3 adbient = UNITY_LIGHTMODEL_AMBIENT.rgb;fixed3 normalDir = normalize(f.worldNormal);fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 因为是平行光fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir), 0) * _Diffuse.rgb;//取得漫反射的颜色//反射光方向//fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));//视野方向//相机是在世界空间下              fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertext);//平分线fixed3 halfDir = normalize(viewDir + lightDir);  //视野方向和光照方向的平分线//高光反射fixed3 specular = _LightColor0.rgb * pow(max(dot(normalDir,halfDir),0),_Gloss) * _Specular.rgb;fixed3 tempColor = diffuse + adbient + specular;return fixed4(tempColor, 1);}ENDCG}}FallBack  "VertexLit"
}

unity light probe?
会发现高光部分会显得更大了,这也是平时用的比较多的高光反射模型。

如何使用Unity的内置函数

UnityCG.cginc中一些常用的函数

//摄像机方向(视野方向)
* float3 WorldSpaceViewDir(float4 v) 根据模型空间中的顶点坐标得到(世界空间)从这个点到摄像机的观察方向
* float3 UnityWorldSpaceViewDir(float4 v) 世界空间中的顶点坐标=>世界空间从这个点到摄像机的观察方向
* float3 ObjSpaceViewDir(float4 v) 模型空间中的顶点坐标=>模型空间从这个点到摄像机的观察方向

3d独胆三天计划论,//光源方向
* float3 WorldSpaceLightDir(float4 v) 模型空间中的顶点坐标=>世界空间中从这个点到光源的方向
* float3 UnityWorldSpaceLightDir(float4 v) 世界空间中的顶点坐标=>世界空间中从这个点到光源的方向
* float3 ObjSpaceLightDir(float4 v) 模型空间中的顶点坐标=>模型空间中从这个点到光源的方向

//方向转换
float3 UnityObjectToWorldNormal(float3 norm) 把法线方向 模型空间=>世界空间
float3 UnityObjectToWorldDir(float3 dir) 把方向 模型空间=>世界空间
float3 UnityWorldToObjectDir(float3 dir) 把方向 世界空间=>模型空间

上面BP模型修改:

Shader "AladdinShader/09 Specular Fragment Blinn Phong Shader"
{Properties{_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色_Specular("Specular",Color)=(1,1,1,1)_Gloss("Gloss",Range(8,200)) = 10}SubShader {Pass {Tags{"LightMode"="ForwardBase"}CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息  
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0 #pragma vertex vert
#pragma fragment frag fixed4 _Diffuse;fixed4 _Specular;half _Gloss;struct a2v {float4 vertex:POSITION;float3 normal:NORMAL; //模型空间下法线};struct v2f{float4 position:SV_POSITION;float3 worldNormal:TEXCOORD0;//世界空间下的法线方向 float4 worldVertext:TEXCOORD1;//时间空间下的顶点坐标};v2f vert(a2v v){v2f f;f.position = mul(UNITY_MATRIX_MVP, v.vertex);//法线从模型空间转成世界空间下// f.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);f.worldNormal = UnityObjectToWorldNormal(v.normal); //使用内置方法转换f.worldVertext = mul(v.vertex , unity_WorldToObject);return f;}fixed4 frag(v2f f):SV_Target{fixed3 adbient = UNITY_LIGHTMODEL_AMBIENT.rgb;fixed3 normalDir = normalize(f.worldNormal);//光源方向// fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 因为是平行光fixed3 lightDir = normalize(WorldSpaceLightDir(f.worldVertext).xyz); //模型空间中的顶点坐标=>世界空间中从这个点到光源的方向fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir), 0) * _Diffuse.rgb;//取得漫反射的颜色//反射光方向//fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));//视野方向//相机是在世界空间下              // fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertext);fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldVertext));//平分线fixed3 halfDir = normalize(viewDir + lightDir);  //视野方向和光照方向的平分线//高光反射fixed3 specular = _LightColor0.rgb * pow(max(dot(normalDir,halfDir),0),_Gloss) * _Specular.rgb;fixed3 tempColor = diffuse + adbient + specular;return fixed4(tempColor, 1);}ENDCG}}FallBack  "VertexLit"
}

unity灯光,
运行效果还是跟上面效果一样,BP模型是常用的模型,会发现背光面并没有一些奇怪的光斑,更符合生活常理。

漫反射和高光反射统一实现

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'Shader "AladdinShader/10 Diffuse Specular Shader"
{Properties{_Diffuse("Diffuse Color", Color)=(1,1,1,1)_Specular("Specular Color", Color)=(1,1,1,1)_Gloss("Gloss",Range(10,200))=20}SubShader {Pass{//只有正确定义Tags 才能获取跟光相关的属性Tags { "LightMode"="ForwardBase" }CGPROGRAM
#include "Lighting.cginc" 
#pragma vertex vert 
#pragma fragment frag fixed4 _Diffuse;fixed4 _Specular;half _Gloss;//顶点函数参数struct a2v{float4 vertex:POSITION; //顶点位置float3 normal:NORMAL; //模型空间下的法线};struct v2f{float4 svPos:SV_POSITION;fixed3 worldNormal:TEXCOORD0;//世界空间下的法线float4 worldVertex:TEXCOORD1;};v2f vert(a2v v){v2f f;f.svPos = mul(UNITY_MATRIX_MVP,v.vertex); //模型空间位置到剪裁空间的顶点位置的转换f.worldNormal = UnityObjectToWorldNormal(v.normal); //模型空间的法线转成时间空间下的法线f.worldVertex = mul(v.vertex,unity_WorldToObject);return f;} //片元函数返回颜色fixed4 frag(v2f f):SV_Target{//漫反射//漫反射颜色 先不管透明度//_LightColor0 平行光的颜色 cos夹角 光的方向和视野的夹角fixed3 normalDir = normalize(f.worldNormal);//光的方向fixed3 lightDir = normalize(WorldSpaceLightDir(f.worldVertex));//漫反射的颜色fixed3 diffuse = _LightColor0.rgb *_Diffuse.rgb * max(dot(normalDir, lightDir),0);//相机方向fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldVertex));//光和相机方向的平分线fixed3 halfDir = normalize(lightDir + viewDir);//高光反射fixed3  specular = _LightColor0.rgb * _Specular.rgb * pow(max(dot(normalDir,halfDir),0),_Gloss);//环境光fixed3 tempColor = diffuse + specular + UNITY_LIGHTMODEL_AMBIENT.rgb;return fixed4(tempColor,1);}ENDCG}}FallBack  "Specular"
}

以上这一段一定要熟练敲熟并且弄懂。效果图也跟上面效果是差不多的。

Shader学习交流群:
316977780

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/1/64036.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息