前言
在Unity URP(Universal Render Pipeline)中实现法线贴图效果,可以通过以下步骤完成。法线贴图通过修改表面法线方向模拟凹凸细节,无需增加几何复杂度。
对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀!
完整实现步骤:
1. 准备法线贴图
- 使用图像软件(如Photoshop或Substance)创建法线贴图,或从资源商店获取
- 导入设置:
- 纹理类型:
Default
- 纹理形状:
Texture2D
- 勾选
Bump Map
(自动切换为法线贴图模式) - 压缩格式:推荐
BC5
(DXT5nm)或BC7
- 纹理类型:
2. 创建URP材质
- 在Project窗口右键:
Create > Material
- 使用URP内置着色器:
- 选择Shader:
Universal Render Pipeline > Lit
- 或
Universal Render Pipeline > Simple Lit
(简化版)
- 选择Shader:
3. 配置材质参数
- 在Material Inspector中:
Surface Type
:根据需求选 Opaque/Transparent- 将法线贴图拖拽到
Normal Map
插槽 - 调整
Normal Scale
(通常0.5-1.5)控制凹凸强度 - 设置基础贴图(Albedo)和其他参数
4. 应用到模型
- 将材质拖拽到场景中的模型上
- 确保模型有UV坐标(可在导入设置中检查)
5. 自定义Shader(可选进阶)
如果需要特殊效果,可编写自定义Shader:
Shader "Custom/NormalMapShader" {
Properties {
_MainTex("Albedo", 2D) = "white" {}
_NormalMap("Normal Map", 2D) = "bump" {}
_NormalScale("Normal Scale", Range(0,2)) = 1
}
SubShader {
Tags { "RenderPipeline"="UniversalPipeline" }
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
ENDHLSL
Pass {
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
struct Attributes {
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
float3 normalOS : NORMAL;
float4 tangentOS : TANGENT;
};
struct Varyings {
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float3 normalWS : TEXCOORD1;
float4 tangentWS : TEXCOORD2;
};
sampler2D _MainTex;
sampler2D _NormalMap;
float _NormalScale;
Varyings vert(Attributes IN) {
Varyings OUT;
// 顶点变换
VertexPositionInputs posInput = GetVertexPositionInputs(IN.positionOS.xyz);
OUT.positionCS = posInput.positionCS;
OUT.uv = IN.uv;
// 法线和切线计算
VertexNormalInputs normInput = GetVertexNormalInputs(IN.normalOS, IN.tangentOS);
OUT.normalWS = normInput.normalWS;
OUT.tangentWS = float4(normInput.tangentWS, IN.tangentOS.w);
return OUT;
}
half4 frag(Varyings IN) : SV_Target {
// 采样法线贴图
float4 normalSample = tex2D(_NormalMap, IN.uv);
float3 tangentNormal = UnpackNormalScale(normalSample, _NormalScale);
// 构建TBN矩阵
float3 normalWS = IN.normalWS;
float3 tangentWS = IN.tangentWS.xyz;
float3 bitangentWS = cross(normalWS, tangentWS) * IN.tangentWS.w;
float3x3 TBN = float3x3(tangentWS, bitangentWS, normalWS);
// 转换到世界空间
float3 finalNormal = mul(tangentNormal, TBN);
// 光照计算(简单漫反射)
Light mainLight = GetMainLight();
float NdotL = saturate(dot(finalNormal, mainLight.direction));
half3 albedo = tex2D(_MainTex, IN.uv).rgb;
half3 diffuse = albedo * NdotL * mainLight.color;
return half4(diffuse, 1);
}
ENDHLSL
}
}
}
关键注意事项:
- 切线空间要求:
- 模型必须包含切线(Tangent)数据
- 检查导入设置:
Model > Normals & Tangents
设为Calculate
- 性能优化:
- 移动平台使用
Normal Quality
设置为Low
(16位精度) - 复杂场景启用
Batching
减少Draw Calls
- 常见问题排查:
- 法线反向:尝试调整
Normal Scale
为负值 - 接缝问题:确保UV展开无重叠,检查模型拓扑
- 光照无反应:确认场景中有URP灯光(Directional Light)
增强效果技巧:
- 视差贴图:在法线基础上添加高度偏移
float2 parallaxUV = IN.uv + (tangentNormal.xy * _HeightScale); - 光滑度控制:将法线信息与粗糙度贴图结合
- 双面渲染:添加
Cull Off
指令支持双面法线
通过以上步骤,可在URP中高效实现法线贴图效果,显著提升模型表面细节表现力。
更多教学视