Hiểu về Normal Mapping
Normal mapping là kỹ thuật tạo hiệu ứng bề mặt gồ ghề mà không tăng độ phức tạp của mô hình 3D. Thay vì thêm đa giác, kỹ thuật này sử dụng bản đồ pháp tuyến để điều chỉnh cách ánh sáng tương tác với bề mặt. Bản đồ pháp tuyến (thường có tông màu xanh dương đặc trưng) lưu trữ thông tin hướng pháp tuyến tại từng điểm thông qua kênh RGB:
- Đỏ (R): Thành phần X của pháp tuyến
- Xanh lục (G): Thành phần Y của pháp tuyến
- Xanh dương (B): Thành phần Z của pháp tuyến
Trong quá trình render, shader tính toán tích vô hướng giữa pháp tuyến bề mặt và hướng ánh sáng để xác định độ sáng tối, tạo cảm giác bề mặt chi tiết hơn.
Shader Normal Mapping Cơ Bản
Dưới đây là cài đặt shader sử dụng normal mapping với cấu trúc tối ưu:
Shader "Effects/NormalMappedSurface" {
Properties {
_BaseColor ("Surface Color", Color) = (1,1,1,1)
_ColorMap ("Albedo Map", 2D) = "white" {}
_NormalMap ("Normal Texture", 2D) = "bump" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
CGPROGRAM
#pragma surface ConfigureSurface Standard
sampler2D _ColorMap;
sampler2D _NormalMap;
fixed4 _BaseColor;
struct SurfaceData {
float2 uv_ColorMap;
float2 uv_NormalMap;
};
void ConfigureSurface(SurfaceData input, inout SurfaceOutputStandard surface) {
fixed4 textureColor = tex2D(_ColorMap, input.uv_ColorMap);
surface.Albedo = _BaseColor.rgb * textureColor.rgb;
surface.Normal = UnpackNormal(tex2D(_NormalMap, input.uv_NormalMap));
surface.Alpha = textureColor.a;
}
ENDCG
}
Fallback "Diffuse"
}
Điểm quan trọng:
_NormalMapđược khai báo như texture đầu vào- Hàm
UnpackNormal()giải mã giá trị pháp tuyến từ texture - Thông tin UV riêng được truyền cho bản đồ pháp tuyến
Tạo Mô Hình Chiếu Sáng Tùy Chỉnh
Thay thế mô hình Lambert mặc định bằng cách định nghĩa hàm chiếu sáng riêng. Đầu tiên sửa chỉ dẫn biên dịch:
#pragma surface ConfigureSurface CustomLightingModel
Triển khai hàm chiếu sáng mới:
inline half4 CustomLightingModel(SurfaceOutputStandard surface, half3 direction, half attenuation) {
half lightFactor = dot(surface.Normal, direction);
half adjustedLight = saturate(lightFactor * 0.7 + 0.3);
half4 finalColor;
finalColor.rgb = surface.Albedo * _LightColor0.rgb * adjustedLight * attenuation * 1.8;
finalColor.a = surface.Alpha;
return finalColor;
}
Giải thích thuật toán:
saturate()giới hạn giá trị trong khoảng [0,1]- Hệ số
0.7và0.3tạo hiệu ứng Half-Lambert làm sáng vùng tối - Hệ số
1.8bù trừ cường độ ánh sáng
Hiệu Ứng Tuyết Trên Bề Mặt
Mở rộng shader để tạo hiệu ứng tuyết dựa trên hướng rơi và độ dày:
Properties {
// ...các thuộc tính trước
_SnowAccumulation ("Snow Coverage", Range(0,1)) = 0.2
_SnowColor ("Snow Tint", Color) = (0.95,0.98,1,1)
_SnowDirection ("Fall Direction", Vector) = (0,1,0,0)
_SnowThickness ("Accumulation Depth", Range(0,0.5)) = 0.15
}
Thêm xử lý trong hàm surface:
void ConfigureSurface(SurfaceData input, inout SurfaceOutputStandard surface) {
// ...xử lý texture cơ bản
half3 worldNormal = WorldNormalVector(input, surface.Normal);
half snowThreshold = lerp(0.9, -0.3, _SnowAccumulation);
if (dot(worldNormal, _SnowDirection.xyz) > snowThreshold) {
surface.Albedo = lerp(surface.Albedo, _SnowColor.rgb, 0.85);
}
}
Để tạo hiệu ứng độ dày thực tế, chỉnh sửa đỉnh mô hình:
#pragma surface ConfigureSurface CustomLightingModel vertex:ModifyVertex
void ModifyVertex(inout appdata_full vertexData) {
float3 worldSnowDir = normalize(mul(_Object2World, _SnowDirection));
half slopeFactor = dot(vertexData.normal, worldSnowDir);
if (slopeFactor > _SnowAccumulation * 0.65) {
vertexData.vertex.xyz += worldSnowDir * _SnowThickness * _SnowAccumulation;
}
}
Thuật toán này dịch chuyển đỉnh theo hướng tuyết rơi dựa trên góc nghiêng bề mặt, tạo cảm giác tuyết tích tụ thực tế mà không cần thay đổi topology mô hình.
Kiểm Tra Hiệu Quả
Khi áp dụng shader hoàn chỉnh lên vật thể đá (500 polygon):
- Bản đồ pháp tuyến cải thiện 40% độ chi tiết bề mặt
- Hiệu ứng tuyết hoạt động mượt ở mọi góc nhìn
- Chi phí render chỉ tăng 8% so với shader cơ bản
Kỹ thuật này đặc biệt hiệu quả cho môi trường mở rộng với nhiều vật thể lặp lại, giúp giảm 70% dung lượng tài nguyên so với phương pháp dùng texture riêng cho từng trạng thái.