1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
| Shader "Custom/URP/TriplanarMapping" { Properties { _MainTex ("Albedo Texture", 2D) = "white" {} _NormalMap ("Normal Map", 2D) = "bump" {} _NormalStrength ("Normal Strength", Range(0, 2)) = 1.0 _Tiling ("World Space Tiling", Float) = 1.0 _Blend ("Blend Sharpness", Range(1, 8)) = 4.0 _Smoothness ("Smoothness", Range(0, 1)) = 0.3 _Metallic ("Metallic", Range(0, 1)) = 0.0 } SubShader { Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "Queue" = "Geometry" }
Pass { Tags { "LightMode" = "UniversalForward" } HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile _ _MAIN_LIGHT_SHADOWS #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE #pragma multi_compile _ _SHADOWS_SOFT
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; };
struct Varyings { float4 positionHCS : SV_POSITION; float3 positionWS : TEXCOORD0; // 世界空间位置(用于 triplanar 投影) float3 normalWS : TEXCOORD1; float3 tangentWS : TEXCOORD2; float3 bitangentWS : TEXCOORD3; };
TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap);
CBUFFER_START(UnityPerMaterial) float4 _MainTex_ST; float _Tiling; float _Blend; float _NormalStrength; float _Smoothness; float _Metallic; CBUFFER_END
Varyings vert(Attributes IN) { Varyings OUT; VertexPositionInputs posInputs = GetVertexPositionInputs(IN.positionOS.xyz); VertexNormalInputs norInputs = GetVertexNormalInputs(IN.normalOS, IN.tangentOS);
OUT.positionHCS = posInputs.positionCS; OUT.positionWS = posInputs.positionWS; OUT.normalWS = norInputs.normalWS; OUT.tangentWS = norInputs.tangentWS; OUT.bitangentWS = norInputs.bitangentWS; return OUT; }
// ===== Triplanar 采样核心函数 ===== // 返回三个轴方向的混合权重(已归一化) float3 TriplanarWeights(float3 worldNormal, float blend) { float3 w = pow(abs(worldNormal), blend); // 归一化,防止混合权重之和不为 1 return w / (w.x + w.y + w.z + 1e-6); }
// 三面投影采样颜色纹理 half4 SampleTriplanar(TEXTURE2D_PARAM(tex, smp), float3 worldPos, float3 weights, float tiling) { // 三个轴的 UV(世界坐标直接用作纹理坐标) half4 xProj = SAMPLE_TEXTURE2D(tex, smp, worldPos.zy * tiling); // YZ 面 half4 yProj = SAMPLE_TEXTURE2D(tex, smp, worldPos.xz * tiling); // XZ 面(地面) half4 zProj = SAMPLE_TEXTURE2D(tex, smp, worldPos.xy * tiling); // XY 面
return xProj * weights.x + yProj * weights.y + zProj * weights.z; }
// 三面投影采样法线贴图(需要在各轴的切线空间中重建法线) float3 SampleTriplanarNormal(TEXTURE2D_PARAM(tex, smp), float3 worldPos, float3 worldNormal, float3 weights, float tiling, float strength) { // 分别采样三个面的法线 half4 xN = SAMPLE_TEXTURE2D(tex, smp, worldPos.zy * tiling); half4 yN = SAMPLE_TEXTURE2D(tex, smp, worldPos.xz * tiling); half4 zN = SAMPLE_TEXTURE2D(tex, smp, worldPos.xy * tiling);
// 解包法线(DXT5nm 格式:.ag 通道,或标准 .rgb 格式) float3 nX = UnpackNormal(xN); float3 nY = UnpackNormal(yN); float3 nZ = UnpackNormal(zN);
// 法线强度控制 nX.xy *= strength; nY.xy *= strength; nZ.xy *= strength;
// 各轴的法线变换到世界空间 // X 面:tangent=Z, bitangent=Y // Y 面:tangent=X, bitangent=Z // Z 面:tangent=X, bitangent=Y float3 nXWS = float3(nX.z * sign(worldNormal.x), nX.y, nX.x * sign(worldNormal.x)); float3 nYWS = float3(nY.x, nY.z * sign(worldNormal.y), nY.y * sign(worldNormal.y)); float3 nZWS = float3(nZ.x, nZ.y, nZ.z * sign(worldNormal.z));
return normalize(nXWS * weights.x + nYWS * weights.y + nZWS * weights.z + worldNormal); }
half4 frag(Varyings IN) : SV_Target { float3 worldNormal = normalize(IN.normalWS); float3 weights = TriplanarWeights(worldNormal, _Blend);
// 三面投影采样颜色和法线 half4 albedo = SampleTriplanar(TEXTURE2D_ARGS(_MainTex, sampler_MainTex), IN.positionWS, weights, _Tiling); float3 normal = SampleTriplanarNormal(TEXTURE2D_ARGS(_NormalMap, sampler_NormalMap), IN.positionWS, worldNormal, weights, _Tiling, _NormalStrength);
// URP 标准光照 InputData inputData = (InputData)0; inputData.positionWS = IN.positionWS; inputData.normalWS = normal; inputData.viewDirectionWS = GetWorldSpaceNormalizeViewDir(IN.positionWS); inputData.shadowCoord = TransformWorldToShadowCoord(IN.positionWS);
SurfaceData surfaceData = (SurfaceData)0; surfaceData.albedo = albedo.rgb; surfaceData.alpha = 1.0; surfaceData.smoothness = _Smoothness; surfaceData.metallic = _Metallic; surfaceData.normalTS = float3(0, 0, 1); // 法线已在世界空间处理
return UniversalFragmentPBR(inputData, surfaceData); } ENDHLSL }
// 阴影投射 Pass(必须包含,否则物体不产生阴影) UsePass "Universal Render Pipeline/Lit/ShadowCaster" } }
|