5.光照模型-漫反射光照模型-兰伯特光照模型-逐片元光照
5.1 知识点
利用兰伯特光照模型实现光照效果(逐片元光照)
创建顶点片元着色器
我们首先创建一个基本的顶点片元着色器,删除默认代码,保留最基础的顶点片元函数的骨架:
Shader "Unlit/Lesson05_Lambert_Pixel"
{
Properties {}
SubShader
{
Tags {}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
v2f vert(appdata appdata)
{
}
fixed4 frag(v2f v2f) : SV_Target
{
}
ENDCG
}
}
}
属性、Tag和内置文件引用
接下来,我们设置一些属性、Tag和内置文件引用,这与逐顶点光照基本一致:
Shader "Unlit/Lesson05_Lambert_Pixel"
{
Properties
{
// 材质的漫反射光照颜色
_MainColor("MainColor", Color) = (1,1,1,1)
}
SubShader
{
// 设置光照模式为 ForwardBase,主要用于处理不透明物体的光照渲染
Tags
{
"LightMode"="ForwardBase"
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// 引用内置文件,主要用于内置结构体和变量的使用
#include "UnityCG.cginc"
#include "Lighting.cginc"
// 材质漫反射颜色
fixed4 _MainColor;
v2f vert(appdata_base appdata_base)
{
}
fixed4 frag(v2f v2f) : SV_Target
{
}
ENDCG
}
}
}
声明结构体,在顶点着色器中计算裁剪空间顶点和世界空间法线
在顶点着色器中,我们需要计算顶点和法线。声明结构体 v2f
,包括裁剪空间下的顶点位置和世界空间下的法线位置:
//顶点着色器返回出去的内容
struct v2f
{
//裁剪空间下的顶点位置
float4 pos:SV_POSITION;
//世界空间下的法线位置
float3 normal:NORMAL;
};
//一定注意 顶点着色器回调函数 主要就是用于处理顶点、法线、切线等数据的坐标转换
v2f vert(appdata_base appdata_base)
{
//声明v2f 要传递给片元函数的
v2f v2f;
//UnityObjectToClipPos 把模型空间下的顶点转换到裁剪空间下
v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
//appdata_base.normal 获取到在模型空间下的法线
//UnityObjectToWorldNormal 将法线从模型空间转换成世界空间 获取到相对于世界坐标系下的法线信息
v2f.normal = UnityObjectToWorldNormal(appdata_base.normal);
return v2f;
}
片元着色器中计算兰伯特光照
在片元着色器中,我们将使用兰伯特光照模型进行光照计算:
fixed4 frag(v2f v2f) : SV_Target
{
//_WorldSpaceLightPos0.xyz 世界坐标系下光源方向 _WorldSpaceLightPos0是四维向量 只需要xyz即可
//normalize 把向量归一化
//lightDir 得到光源单位向量
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//_LightColor0光 照颜色
//.rgb 代表只使用颜色进行计算 透明度不考虑
//color 计算出了兰伯特光照的漫反射颜色
fixed3 color = _LightColor0.rgb * _MainColor.rgb * max(0, dot(v2f.normal, lightDir));
//UNITY_LIGHTMODEL_AMBIENT.rgb 兰伯特光照模型环境光变量
//为了让背光的地方不至于是黑色 所以加上自带的漫反射颜色 看起来更加真实
color = UNITY_LIGHTMODEL_AMBIENT.rgb + color;
//返回color中的颜色 透明度传1
return fixed4(color.rgb, 1);
}
赋值到材质并进行对比
将完成的着色器赋值到材质,再应用到场景中的球体对象上。与逐顶点光照相比,可以看到逐片元光照过渡更加平滑细致,带来了更好的视觉效果。
5.2 知识点代码
Lesson05_光照模型_漫反射光照模型_兰伯特光照模型_逐片元光照
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson05_光照模型_漫反射光照模型_兰伯特光照模型_逐片元光照 : MonoBehaviour
{
void Start()
{
#region 知识点 利用兰伯特光照模型实现光照效果(逐片元光照)
//关键步骤
//基本和逐顶点一致
//区别:
//1.在顶点着色器中计算顶点和法线
//2.在片元着色器中计算兰伯特光照
#endregion
}
}
Lesson05_Lambert_Pixel.shader
Shader "Unlit/Lesson05_Lambert_Pixel"
{
Properties
{
//材质的漫反射光照颜色
_MainColor("MainColor", Color) = (1,1,1,1)
}
SubShader
{
//设置我们的光照模式 ForwardBase这种向前渲染模式 主要是用来处理 不透明物体的 光照渲染的
Tags
{
"LightMode"="ForwardBase"
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//引用对应的内置文件
//主要是为了之后 的 比如内置结构体使用,内置变量使用
#include "UnityCG.cginc"
#include "Lighting.cginc"
//材质漫反射颜色
fixed4 _MainColor;
//顶点着色器返回出去的内容
struct v2f
{
//裁剪空间下的顶点位置
float4 pos:SV_POSITION;
//世界空间下的法线位置
float3 normal:NORMAL;
};
//一定注意 顶点着色器回调函数 主要就是用于处理顶点、法线、切线等数据的坐标转换
v2f vert(appdata_base appdata_base)
{
//声明v2f 要传递给片元函数的
v2f v2f;
//UnityObjectToClipPos 把模型空间下的顶点转换到裁剪空间下
v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
//appdata_base.normal 获取到在模型空间下的法线
//UnityObjectToWorldNormal 将法线从模型空间转换成世界空间 获取到相对于世界坐标系下的法线信息
v2f.normal = UnityObjectToWorldNormal(appdata_base.normal);
return v2f;
}
fixed4 frag(v2f v2f) : SV_Target
{
//_WorldSpaceLightPos0.xyz 世界坐标系下光源方向 _WorldSpaceLightPos0是四维向量 只需要xyz即可
//normalize 把向量归一化
//lightDir 得到光源单位向量
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//_LightColor0光 照颜色
//.rgb 代表只使用颜色进行计算 透明度不考虑
//color 计算出了兰伯特光照的漫反射颜色
fixed3 color = _LightColor0.rgb * _MainColor.rgb * max(0, dot(v2f.normal, lightDir));
//UNITY_LIGHTMODEL_AMBIENT.rgb 兰伯特光照模型环境光变量
//为了让背光的地方不至于是黑色 所以加上自带的漫反射颜色 看起来更加真实
color = UNITY_LIGHTMODEL_AMBIENT.rgb + color;
//返回color中的颜色 透明度传1
return fixed4(color.rgb, 1);
}
ENDCG
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com