32.纹理-渐变纹理-基础实现
32.1 知识点
导入测试资源
在进行渐变纹理基础Shader开发之前,首先需要准备一些测试资源,例如机器人模型和渐变纹理。我们将使用这些资源进行渲染效果的测试。
渐变纹理基础Shader实现
关键步骤
在实现Shader时,我们需要关注以下几个关键步骤:
属性相关
- 漫反射颜色
- 渐变纹理
- 高光反射颜色
- 光泽度
结构体相关
- 顶点着色器中传入:
- 可以使用
UnityCG.cginc
中的appdata_base
,其中包含了我们需要的顶点、法线相关数据。
- 可以使用
- 片元着色器中传入:
- 自定义一个结构体,其中包含裁剪空间下的坐标、世界空间下的顶点坐标、世界空间下的法线方向。
- 顶点着色器中传入:
顶点着色器回调函数中
- 顶点坐标从模型空间转裁剪空间。
- 顶点坐标从模型空间转世界空间。
- 法线从模型空间转世界空间。
片元着色器回调函数中
- 计算光的方向。
- 计算半兰伯特光照后半部分公式值:
diffuseColor = 光源的颜色 * 材质的漫反射颜色 * ((标准化后物体表面法线向量· 标准化后光源方向向量) * 0.5 + 0.5)
- 利用该值从渐变纹理中取出对应颜色,参与漫反射光照计算,得到漫反射颜色:
diffuseColor = 光源的颜色 * 材质的漫反射颜色 * 渐变纹理中取出的颜色
- 计算Blinn-Phong光照模型,其中的漫反射光照颜色使用上一步计算出来的颜色。
写出Shader骨架
Shader "Unlit/Lesson32_Gradient_Texture_Base"
{
Properties
{
}
SubShader
{
Pass
{
Tags
{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
v2f vert(appdata_base appdata_base)
{
}
fixed4 frag(v2f v2f) : SV_Target
{
}
ENDCG
}
}
}
声明属性相关和属性映射
定义Shader中的属性,包括漫反射颜色、渐变纹理、高光反射颜色和光泽度:
Properties
{
_MainColor("MainColor", Color) = (1,1,1,1) // 漫反射颜色
_RampTex("RampTex", 2D) = ""{} // 渐变纹理
_SpecularColor("SpecularColor", Color) = (1,1,1,1) // 高光反射颜色
_SpecularNum("SpecularNum", Range(8, 256)) = 18 // 光泽度
}
fixed4 _MainColor; // 漫反射颜色
sampler2D _RampTex; // 渐变纹理
float4 _RampTex_ST; // 渐变纹理的缩放和偏移
fixed4 _SpecularColor; // 高光反射颜色
float _SpecularNum; // 光泽度
声明结构体
我们需要定义一个结构体,用于存储裁剪空间下的顶点坐标、世界空间下的顶点坐标以及法线方向:
struct v2f
{
//裁剪空间下顶点坐标
float4 pos:SV_POSITION;
//世界空间下顶点坐标
float3 worldPos:TEXCOORD0;
//世界空间下法线
float3 worldNormal:TEXCOORD1;
};
顶点着色器
在顶点着色器中,将顶点坐标从模型空间转换为裁剪空间,并将法线从模型空间转换为世界空间:
v2f vert(appdata_base appdata_base)
{
v2f v2f;
v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
v2f.worldPos = mul(unity_ObjectToWorld, appdata_base.vertex);
v2f.worldNormal = UnityObjectToWorldNormal(appdata_base.normal);
return v2f;
}
片元着色器
在片元着色器中,计算半兰伯特光照后半部分的值,利用该值从渐变纹理中取出颜色,计算漫反射光照,并加入高光反射计算:
fixed4 frag(v2f v2f) : SV_Target
{
//光的方向
float3 lightDir = normalize(_WorldSpaceLightPos0);
//diffuseColor = 光源的颜色 * 材质的漫反射颜色 *((标准化后物体表面法线向量· 标准化后光源方向向量)* 0.5 + 0.5)
//计算半兰伯特光照后半部分公式值 ((标准化后物体表面法线向量· 标准化后光源方向向量)* 0.5 + 0.5)
fixed halfLambertNum = dot(normalize(v2f.worldNormal), lightDir) * 0.5 + 0.5;
//diffuseColor = 漫反射颜色 = 光的颜色 * 漫反射颜色 * 渐变纹理中取出的颜色
fixed3 diffuseColor = _LightColor0.rgb * _MainColor.rgb *
tex2D(_RampTex, fixed2(halfLambertNum, halfLambertNum));
//高光反射颜色
//视角方向
float3 viewDir = normalize(UnityWorldSpaceViewDir(v2f.worldPos));
//半角向量
float3 halfDir = normalize(lightDir + viewDir);
//color = 光源颜色 * 材质高光反射颜色 * pow( max(0, dot(视角单位向量, 光的反射单位向量)), 光泽度 )
fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(v2f.worldNormal, halfDir)), _SpecularNum);
//布林方 公式
//物体表面光照颜色 = 环境光颜色 + 兰伯特光照模型所得颜色 + Phong式高光反射光照模型所得颜色
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb + diffuseColor + specularColor;
return fixed4(color.rgb, 1);
}
创建材质并赋值给模型
将上面的Shader编译后,创建一个新的材质,将材质赋值给模型,进行效果测试。你将能够看到基于渐变纹理的半兰伯特光照和高光反射效果。
修改渐变纹理设置避免黑点出现
为了避免渐变纹理在接缝处出现黑点,我们需要将 Wrap Mode
(循环模式)切换为 Clamp
(拉伸模式):
- 原因:浮点数计算可能存在误差,会出现超过1的值(例如1.00001)。如果使用
Repeat
(重复模式),会舍弃整数部分,保留小数部分0.00001,这时对应的颜色会是渐变纹理最左边的值,因此会出现黑色。
32.2 知识点代码
Lesson32_纹理_渐变纹理_基础实现
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson32_纹理_渐变纹理_基础实现 : MonoBehaviour
{
void Start()
{
#region 知识点一 导入测试资源
#endregion
#region 知识点二 渐变纹理基础Shader实现
//关键点:
//1.属性相关
// 漫反射颜色
// 渐变纹理
// 高光反射颜色
// 光泽度
//2.结构体相关
// 顶点着色器中传入:
// 可以使用 UnityCG.cginc 中的 appdata_base
// 其中包含了我们需要的顶点、法线相关数据
//
// 片元着色器中传入:
// 自定义一个结构体
// 其中包含 裁剪空间下坐标、世界空间下顶点坐标、世界空间下法线方向
//3.顶点着色器回调函数中
// 3-1 顶点坐标模型转裁剪
// 3-2 顶点坐标模型转世界
// 3-3 法线从模型转世界
//4.片元着色器回调函数中
// 4-1 计算光的方向
// 4-2 计算半兰伯特光照后半部分公式值
// diffuseColor = 光源的颜色 * 材质的漫反射颜色 *((标准化后物体表面法线向量· 标准化后光源方向向量)* 0.5 + 0.5)
// 4-3 利用该值从渐变纹理中取出对应颜色,参与漫反射光照计算 得出漫反射颜色
// diffuseColor = 光源的颜色 * 材质的漫反射颜色 * 渐变纹理中取出的颜色
// 4-4 计算Blinn Phong光照模型,其中的漫反射光照颜色使用上一步计算出来的颜色
#endregion
#region 知识点三 修改渐变纹理设置 避免黑点出现
//避免渐变纹理接缝处有黑点
//我们需要将 Wrap Mode(循环模式)切换为 Clamp(拉伸模式)
//出现黑点的原因是:
//浮点数计算可能存在误差,会出现超过1的值(1.00001)
//如果使用Repeat(重复模式),会舍弃整数部分,保留小数0.00001
//这时对应的颜色会是最左边的值,因此会出现黑色
#endregion
}
}
Lesson32_Gradient_Texture_Base.shader
Shader "Unlit/Lesson32_Gradient_Texture_Base"
{
Properties
{
_MainColor("MainColor", Color) = (1,1,1,1) // 漫反射颜色
_RampTex("RampTex", 2D) = ""{}// 渐变纹理
_SpecularColor("SpecularColor", Color) = (1,1,1,1)// 高光反射颜色
_SpecularNum("SpecularNum", Range(8, 256)) = 18 // 光泽度
}
SubShader
{
Pass
{
Tags
{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _MainColor; // 漫反射颜色
sampler2D _RampTex; // 渐变纹理
float4 _RampTex_ST; // 渐变纹理的缩放和偏移
fixed4 _SpecularColor; // 高光反射颜色
float _SpecularNum; // 光泽度
struct v2f
{
//裁剪空间下顶点坐标
float4 pos:SV_POSITION;
//世界空间下顶点坐标
float3 worldPos:TEXCOORD0;
//世界空间下法线
float3 worldNormal:TEXCOORD1;
};
v2f vert(appdata_base appdata_base)
{
v2f v2f;
v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
v2f.worldPos = mul(unity_ObjectToWorld, appdata_base.vertex);
v2f.worldNormal = UnityObjectToWorldNormal(appdata_base.normal);
return v2f;
}
fixed4 frag(v2f v2f) : SV_Target
{
//光的方向
float3 lightDir = normalize(_WorldSpaceLightPos0);
//diffuseColor = 光源的颜色 * 材质的漫反射颜色 *((标准化后物体表面法线向量· 标准化后光源方向向量)* 0.5 + 0.5)
//计算半兰伯特光照后半部分公式值 ((标准化后物体表面法线向量· 标准化后光源方向向量)* 0.5 + 0.5)
fixed halfLambertNum = dot(normalize(v2f.worldNormal), lightDir) * 0.5 + 0.5;
//diffuseColor = 漫反射颜色 = 光的颜色 * 漫反射颜色 * 渐变纹理中取出的颜色
fixed3 diffuseColor = _LightColor0.rgb * _MainColor.rgb *
tex2D(_RampTex, fixed2(halfLambertNum, halfLambertNum));
//高光反射颜色
//视角方向
float3 viewDir = normalize(UnityWorldSpaceViewDir(v2f.worldPos));
//半角向量
float3 halfDir = normalize(lightDir + viewDir);
//color = 光源颜色 * 材质高光反射颜色 * pow( max(0, dot(视角单位向量, 光的反射单位向量)), 光泽度 )
fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(v2f.worldNormal, halfDir)), _SpecularNum);
//布林方 公式
//物体表面光照颜色 = 环境光颜色 + 兰伯特光照模型所得颜色 + Phong式高光反射光照模型所得颜色
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb + diffuseColor + specularColor;
return fixed4(color.rgb, 1);
}
ENDCG
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com