当前位置:网站首页>Unity Shader :实现漫反射与高光反射
Unity Shader :实现漫反射与高光反射
2022-07-24 05:21:00 【一只小EZ】
最近在研究Unity 的Shader编写,冯乐乐《UnityShader 入门精要》发现还是挺有意思的。
这里就来实现一下基础的Shader。笔者使用的Unity版本是2019.4.19f1。相比于《UnityShader 入门精要》中的某些写法和函数进行了更新。
标准光照模型
在游戏引擎中光照模型有很多种,但在早期的游戏引擎中往往只使用一个光照模型,这个模型被称为标准光照模型。
它的基本方法是,把进入到摄像机内的光线分为4个部分,每个部分使用一种方法来计算它的贡献度。这4个部分如下
- 自发光
- 环境光
- 满反射
- 高光反射
环境光照
在标准光照模型中,我们使用了一种被称为环境光的部分来近似模拟间接光照(可以理解为整体环境的光照)。环境光的计算非常简单,它通常是一个全局变量,即场景中的所有物体都使用这个环境光。
在Unity 中 环境光使用如下代码求得:
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
漫反射
漫反射的介绍见 漫反射_百度百科。
在漫反射中,视角的位置是不重要的,因为反射是完全随机的,因此可以认为在任何反射方向上的分布都是一样的。但是,入射光线的角度很重要。
漫反射公式如下:
C diffuse 为 漫反射颜色
C light 为 光源颜色
M diffuse 为 材质漫反射系数
向量 n 为法线方向
向量 l 为光源方向
为了防止法线和光源方向点积结果为负值,所以使用取最大值的函数来将其截取到0。
这里的公式没看懂也没关系。熟能生巧。随着研究的深入,就会慢慢理解了。
上代码
Shader "Custom/DiffuseShader"
{
Properties
{
_Diffuse("Diffuse", Color) = (1, 1, 1, 1)
}
SubShader
{
Pass
{
Tags {
"LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _Diffuse;
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 worldNormal : TEXCOORD0;
};
v2f vert(appdata v)
{
v2f o;
//从模型空间变换到裁剪空间
o.vertex = UnityObjectToClipPos(v.vertex);
//从模型空间变换到世界空间
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(i.worldNormal, worldLight));
fixed3 color = ambient + diffuse;
return fixed4(color, 1);
}
ENDCG
}
}
// 上述SubShader都失败后用于回调的Unity Shader
FallBack "Diffuse"
}
新建一个 Image Effect Shader,打开将此代码覆盖。新建一个材质 选择 Custom/DiffuseShader ,将材质拖到物体上即可。
代码解析:
Shader “Custom/DiffuseShader” 指定了Shader的路径。
在Properties 中规定了可以在Inspector中编辑的属性。这里我们指定了材质的默认漫反射系数(公式中的M diffuse)。
在SubShader的Pass中,我们指定了Pass中LightMode为ForwardBase。该Pass会计算环境光、主要的平行光、顶点/SH光源和Lightmaps光照贴图。
同时在Pass中规定了顶点和片段着色器的输入。
在顶点着色器中,获取了模型空间下的顶点坐标和顶点法线。之后将顶点坐标变换到裁剪空间中。将法线变换到世界坐标下。法线即为公式中的向量 n 。
在片段着色器中 ambient 为 环境光
worldLight 为公式中的向量 l
_LightColor0.rgb 为公式中的 C light
最终得到了该片段颜色的结果。
最终指定了 Fallback),如果所有SubShader都无法在该硬件上运行,会使用默认的Diffuse。
得到的结果为
高光反射
高光反射用于计算那些沿着完全镜面反射方向被反射的光线,这可以让物体看起来是有光泽的,例如金属材质。
但是这里的高光反射是一种经验模型,也就是说,它并不完全符合真实世界中的高光反射现象。
公式为
C specular为 高光反射颜色
C light 为 光源颜色
M specular为 材质高光反射系数
向量 v 为视角方向
向量 l 为反射方向
上代码
Shader "Custom/SpecularShader"
{
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 "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};
v2f vert(a2v v)
{
v2f o;
//从模型空间变换到裁剪空间
o.vertex = UnityObjectToClipPos(v.vertex);
//法线从模型空间变换到世界空间
o.worldNormal = UnityObjectToWorldNormal(v.normal);
//顶点从模型空间变换到世界空间
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
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 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
//得到视角方向
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
//计算高光反射
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);
return fixed4(ambient + diffuse + specular, 1.0);
}
ENDCG
}
}
FallBack "Specular"
}
在Pass的顶点着色器中计算得到了世界空间下的顶点坐标,在片段着色器中新增了对于高光反射的计算,最终将环境光 漫反射 以及高光反射的结果相加,得到最终结果。
同时指定了FallBack为默认的Specular
新建一个 Image Effect Shader,打开将此代码覆盖。新建一个材质 选择 Custom/SpecularShader ,将材质拖到物体上即可。
得到的结果为。
可以看到高光反射的Shader更带一些金属性,同时在材质的Inspector面板调整Gloss的值,Gloss值越大,高光反射的光点越小。
边栏推荐
- day6-jvm
- 【数据库系统原理】第四章 高级数据库模型:统一建模语言UML、对象定义语言ODL
- Could not load library cudnn_ cnn_ infer64_ 8.dll. Error code 126Please make sure cudnn_ cnn_ infer64_ eight
- [activiti] personal task
- Foundation of JUC concurrent programming (8) -- read write lock
- Jupyter notebook select CONDA environment
- The kernel apps to have died. it will restart automatically
- JDBC进阶—— 师承尚硅谷(DAO)
- Accurate calculation of time delay detailed explanation of VxWorks timestamp
- Machine learning (zhouzhihua) Chapter 2 model selection and evaluation notes learning experience
猜你喜欢

How to solve the problem of large distribution gap between training set and test set

Raspberry pie is of great use. Use the campus network to build a campus local website
![[activiti] group task](/img/f1/b99cae9e840d3a91d0d823655748fe.png)
[activiti] group task

使用Qt连接MySql并创建表号、写入数据、删除数据

JUC并发编程基础(6)--Lock锁

On the concepts of "input channel" and "output channel" in convolutional neural networks

JUC并发编程基础(9)--线程池

es6常用特性

JDBC初级学习 ------(师承尚硅谷)

"Statistical learning methods (2nd Edition)" Li Hang Chapter 17 latent semantic analysis LSA LSI mind mapping notes and after-school exercise answers (detailed steps) Chapter 17
随机推荐
【深度学习】手写神经网络模型保存
用指针访问二维数组
In GCC__ attribute__ ((constructor) and__ attribute__ ((destructor)).
JUC并发编程基础(4)--线程组和线程优先级
YOLOv5学习总结(持续更新)
[deep learning] teach you to write "handwritten digit recognition neural network" hand in hand, without using any framework, pure numpy
绘制轮廓 cv2.findContours函数及参数解释
Typora 安装包2021年11月最后一次免费版本的安装包下载V13.6.1
Common features of ES6
bat批处理脚本、同时运行多个文件、按照顺序执行的批处理命令及xshell脚本。
vscode 多行注释总是会自动展开的问题
Foundation of JUC concurrent programming (4) -- thread group and thread priority
Openwrt quick configuration Samba
JVM系统学习
day6-jvm
[principles of database system] Chapter 5 algebra and logic query language: package, extension operator, relational logic, relational algebra and datalog
JSON. Dumps() function parsing
KMP代码分布详解
JS star scoring effect
Yolov5 learning summary (continuously updated)