33.纹理-渐变纹理-综合实现
33.1 知识点
复用凹凸纹理切线空间下的法线纹理贴图Shader代码
- 拷贝凹凸纹理切线空间下实现的代码,再进行修改
Properties
{
_MainColor("MainColor", Color) = (1,1,1,1)// 漫反射颜色
_MainTex("MainTex", 2D) = ""{}// 单张纹理
_BumpMap("BumpMap", 2D) = ""{}// 法线纹理
_BumpScale("BumpScale", Range(0,1)) = 1// 凹凸程度
_SpecularColor("SpecularColor", Color) = (1,1,1,1)// 高光反射颜色
_SpecularNum("SpecularNum", Range(0,20)) = 18// 光泽度
}
SubShader
{
Pass
{
Tags
{
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
float4 _MainColor; //漫反射颜色
sampler2D _MainTex; //颜色纹理
float4 _MainTex_ST; //颜色纹理的缩放和平移
sampler2D _BumpMap; //法线纹理
float4 _BumpMap_ST; //法线纹理的缩放和平移
float _BumpScale; //凹凸程度
float4 _SpecularColor; //高光颜色
fixed _SpecularNum; //光泽度
struct v2f
{
//裁剪空间下坐标
float4 pos:SV_POSITION;
//纹理uv
//我们可以单独的声明两个float2的成员用于记录 颜色和法线纹理的uv坐标
//float2 uvTex:TEXCOORD0;//颜色纹理
//float2 uvBump:TEXCOORD1;//法线纹理
//也可以直接声明一个float4的成员 xy用于记录颜色纹理的uv,zw用于记录法线纹理的uv
float4 uv:TEXCOORD0; //纹理变量
//光的方向 相对于切线空间下的
float3 lightDir:TEXCOORD1;
//视角的方向 相对于切线空间下的
float3 viewDir:TEXCOORD2;
};
// 顶点着色器中传入:
// 可以使用 UnityCG.cginc 中的 appdata_full
// 其中包含了我们需要的顶点、法线、切线、纹理坐标相关数据
v2f vert(appdata_full appdata_full)
{
v2f v2f;
//把模型空间下的顶点转到裁剪空间下
v2f.pos = UnityObjectToClipPos(appdata_full.vertex);
//单张纹理和法线纹理 UV坐标缩放偏移计算
v2f.uv.xy = appdata_full.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
v2f.uv.zw = appdata_full.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
//在顶点着色器当中 得到 模型空间到切线空间的 转换矩阵
//切线、副切线、法线
//计算副切线 计算叉乘结果后 垂直与切线和法线的向量有两条 通过乘以 切线当中的w,就可以确定是哪一条(确定副切线方向)
//cross是叉乘 appdata_full.tangent是切线 appdata_full.normal是法线 appdata_full.tangent.w代表叉乘结果方向
float3 binormal = cross(normalize(appdata_full.tangent), normalize(appdata_full.normal)) * appdata_full.
tangent.w;
//构建模型空间到切线空间的变换矩阵
float3x3 rotation = float3x3(appdata_full.tangent.xyz,
binormal,
appdata_full.normal);
//模型空间下的光的方向
//v2f.lightDir = ObjSpaceLightDir(appdata_full.vertex);
//乘以模型空间到切线空间的转换矩阵 就可以得到切线空间下的 光的方向了
v2f.lightDir = mul(rotation, ObjSpaceLightDir(appdata_full.vertex));
//模型空间下的视角的方向
//v2f.viewDir = ObjSpaceViewDir(appdata_full.vertex);
//乘以模型空间到切线空间的转换矩阵 就可以得到切线空间下的 视角的方向了
v2f.viewDir = mul(rotation, ObjSpaceViewDir(appdata_full.vertex));
return v2f;
}
// 片元着色器中传入:
// 自定义一个结构体
// 其中包含 裁剪空间下坐标、uv坐标、光的方向、视角的方向
fixed4 frag(v2f v2f) : SV_Target
{
//纹理采样函数tex2D
//通过纹理采样函数 取出法线纹理贴图当中的数据
float4 packedNormal = tex2D(_BumpMap, v2f.uv.zw);
//利用内置的UnpackNormal函数对法线信息进行逆运算以及可能的解压
//将我们取出来的法线数据 进行逆运算并且可能会进行解压缩的运算,最终得到切线空间下的法线数据
float3 tangentNormal = UnpackNormal(packedNormal);
//用得到的切线空间的法线数据 乘以 BumpScale 来控制凹凸程度
//注意 tangentNormal不要进行单位化 直接用即可 因为乘了BumpScale就不是单位向量了
tangentNormal *= _BumpScale;
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
//接下来就来处理 带颜色纹理的 布林方光照模型计算
//颜色纹理和漫反射颜色的 叠加
fixed3 albedo = tex2D(_MainTex, v2f.uv.xy) * _MainColor.rgb;
//兰伯特漫反射颜色 = 光的颜色 * 漫反射材质的颜色 * max(0, dot(切线坐标系下的法线, 光的方向))
fixed3 lambertColor = _LightColor0.rgb * albedo.rgb * max(0, dot(tangentNormal, normalize(v2f.lightDir)));
//半角向量 = 视角方向 + 光的方向
float3 halfA = normalize(normalize(v2f.viewDir) + normalize(v2f.lightDir));
//高光反射的颜色 = 光的颜色 * 高光反射材质的颜色 * pow(max(0, dot(切线坐标系下的法线, 半角向量)), 光泽度)
fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(tangentNormal, halfA)), _SpecularNum);
//布林方光照颜色 = 环境光颜色 + 兰伯特漫反射颜色 + 高光反射的颜色
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + lambertColor + specularColor;
return fixed4(color.rgb, 1);
}
ENDCG
}
}
将渐变纹理贴图融合其中
关键步骤
- 将原本兰伯特光照模型,修改为渐变纹理的计算方式
Properties 添加渐变纹理支持
RampTex作为渐变纹理
Properties
{
_MainColor("MainColor", Color) = (1,1,1,1)
_MainTex("MainTex", 2D) = ""{}
_BumpMap("BumpMap", 2D) = ""{}
_BumpScale("BumpScale", Range(0,1)) = 1
_RampTex("RampTex", 2D) = ""{}
_SpecularColor("SpecularColor", Color) = (1,1,1,1)
_SpecularNum("SpecularNum", Range(8,256)) = 18
}
float4 _MainColor; //漫反射颜色
sampler2D _MainTex; //颜色纹理
float4 _MainTex_ST; //颜色纹理的缩放和平移
sampler2D _BumpMap; //法线纹理
float4 _BumpMap_ST; //法线纹理的缩放和平移
float _BumpScale; //凹凸程度
sampler2D _RampTex; //渐变纹理
float4 _RampTex_ST; //渐变纹理的缩放和平移(基本不会用)
float4 _SpecularColor; //高光颜色
fixed _SpecularNum; //光泽度
修改片元着色器函数以支持渐变纹理
修改片元函数,把兰伯特修改成从渐变纹理中得到颜色并参与运算
fixed4 frag(v2f v2f) : SV_Target
{
//通过纹理采样函数 取出法线纹理贴图当中的数据
float4 packedNormal = tex2D(_BumpMap, v2f.uv.zw);
//将我们取出来的法线数据 进行逆运算并且可能会进行解压缩的运算,最终得到切线空间下的法线数据
float3 tangentNormal = UnpackNormal(packedNormal);
//乘以凹凸程度的系数
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
//接下来就来处理 带颜色纹理的 布林方光照模型计算
//颜色纹理和漫反射颜色的 叠加
fixed3 albedo = tex2D(_MainTex, v2f.uv.xy) * _MainColor.rgb;
//修改为 渐变纹理相关的计算方式
fixed halfLambertNum = dot(normalize(tangentNormal), normalize(v2f.lightDir)) * 0.5 + 0.5;
//渐变纹理 漫反射计算方式
fixed3 diffuseColor = _LightColor0.rgb * albedo.rgb *
tex2D( _RampTex, fixed2(halfLambertNum, halfLambertNum)).rgb;
//半角向量
float3 halfA = normalize(normalize(v2f.viewDir) + normalize(v2f.lightDir));
//高光反射
fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(
max(0, dot(tangentNormal, halfA)), _SpecularNum);
//布林方
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + diffuseColor + specularColor;
return fixed4(color.rgb, 1);
}
创建材质,查看使用渐变纹理前后时的效果区别。可以看到使用后下方有分割线,明暗过渡更加明显
复制一个切线空间凹凸纹理,赋值机器人的颜色为例和贴图。放到场景上和渐变纹理机器人对比。可以看到渐变纹理机器人分割线更明显,更有卡通感。而凹凸纹理偏写实
33.2 知识点代码
Lesson33_纹理_渐变纹理_综合实现
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson33_纹理_渐变纹理_综合实现 : MonoBehaviour
{
void Start()
{
#region 知识点一 复用法线纹理贴图Shader代码(切线空间下计算)
#endregion
#region 知识点二 将渐变纹理贴图融合其中
//关键点
//将原本兰伯特光照模型
//修改为渐变纹理的计算方式
#endregion
}
}
Lesson33_Gradient_Texture_Comprehensive.shader
Shader "Unlit/Lesson33_Gradient_Texture_Comprehensive"
{
Properties
{
_MainColor("MainColor", Color) = (1,1,1,1)
_MainTex("MainTex", 2D) = ""{}
_BumpMap("BumpMap", 2D) = ""{}
_BumpScale("BumpScale", Range(0,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"
float4 _MainColor; //漫反射颜色
sampler2D _MainTex; //颜色纹理
float4 _MainTex_ST; //颜色纹理的缩放和平移
sampler2D _BumpMap; //法线纹理
float4 _BumpMap_ST; //法线纹理的缩放和平移
float _BumpScale; //凹凸程度
sampler2D _RampTex; //渐变纹理
float4 _RampTex_ST; //渐变纹理的缩放和平移(基本不会用)
float4 _SpecularColor; //高光颜色
fixed _SpecularNum; //光泽度
struct v2f
{
float4 pos:SV_POSITION;
//float2 uvTex:TEXCOORD0;
//float2 uvBump:TEXCOORD1;
//我们可以单独的声明两个float2的成员用于记录 颜色和法线纹理的uv坐标
//也可以直接声明一个float4的成员 xy用于记录颜色纹理的uv,zw用于记录法线纹理的uv
float4 uv:TEXCOORD0;
//光的方向 相对于切线空间下的
float3 lightDir:TEXCOORD1;
//视角的方向 相对于切线空间下的
float3 viewDir:TEXCOORD2;
};
v2f vert(appdata_full appdata_full)
{
v2f v2f;
//把模型空间下的顶点转到裁剪空间下
v2f.pos = UnityObjectToClipPos(appdata_full.vertex);
//计算纹理的缩放偏移
v2f.uv.xy = appdata_full.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
v2f.uv.zw = appdata_full.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
//在顶点着色器当中 得到 模型空间到切线空间的 转换矩阵
//切线、副切线、法线
//计算副切线 计算叉乘结果后 垂直与切线和法线的向量有两条 通过乘以 切线当中的w,就可以确定是哪一条
float3 binormal = cross(normalize(appdata_full.tangent), normalize(appdata_full.normal)) * appdata_full.
tangent.w;
//转换矩阵
float3x3 rotation = float3x3(appdata_full.tangent.xyz,
binormal,
appdata_full.normal);
//模型空间下的光的方向
//data.lightDir = ObjSpaceLightDir(v.vertex);
//乘以模型空间到切线空间的转换矩阵 就可以得到切线空间下的 光的方向了
v2f.lightDir = mul(rotation, ObjSpaceLightDir(appdata_full.vertex));
//模型空间下的视角的方向
//data.viewDir = ObjSpaceViewDir(v.vertex);
v2f.viewDir = mul(rotation, ObjSpaceViewDir(appdata_full.vertex));
return v2f;
}
fixed4 frag(v2f v2f) : SV_Target
{
//通过纹理采样函数 取出法线纹理贴图当中的数据
float4 packedNormal = tex2D(_BumpMap, v2f.uv.zw);
//将我们取出来的法线数据 进行逆运算并且可能会进行解压缩的运算,最终得到切线空间下的法线数据
float3 tangentNormal = UnpackNormal(packedNormal);
//乘以凹凸程度的系数
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
//接下来就来处理 带颜色纹理的 布林方光照模型计算
//颜色纹理和漫反射颜色的 叠加
fixed3 albedo = tex2D(_MainTex, v2f.uv.xy) * _MainColor.rgb;
//修改为 渐变纹理相关的计算方式
fixed halfLambertNum = dot(normalize(tangentNormal), normalize(v2f.lightDir)) * 0.5 + 0.5;
//渐变纹理 漫反射计算方式
fixed3 diffuseColor = _LightColor0.rgb * albedo.rgb *
tex2D( _RampTex, fixed2(halfLambertNum, halfLambertNum)).rgb;
//半角向量
float3 halfA = normalize(normalize(v2f.viewDir) + normalize(v2f.lightDir));
//高光反射
fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(
max(0, dot(tangentNormal, halfA)), _SpecularNum);
//布林方
fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo + diffuseColor + specularColor;
return fixed4(color.rgb, 1);
}
ENDCG
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com