Normal Map HLSL实现

本文介绍了一种在DirectX平台上实现Tangent Space Normal Mapping的技术细节。通过顶点着色器与像素着色器的配合,实现了光照效果的真实感增强。文章详细展示了着色器代码,包括如何构建切线空间矩阵、读取法线贴图以及计算光照强度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Normal Map 分为Object Space 和Tangent Space。下面是Tagent Space的实现。

贴上Normal Map在DX 上的实现。

sampler NormalMap =
sampler_state
{
    Texture = <g_Texture1>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};

struct VS_INPUT_Mesh_N
{
    float4 Position     : POSITION;
    float3 Normal       : NORMAL;
    float2 Tex0   : TEXCOORD0;
    float3 Tangent      : TANGENT;
    float3 Binormal     : BINORMAL;
   
};

struct VS_OUTPUT_Mesh_N
{
    float4 Position   : POSITION;
    float2 Tex0    : TEXCOORD0;
    float3 Normal     : TEXCOORD1;
    float3 Tangent    : TEXCOORD2;
    float3 Binormal   : TEXCOORD3;
    float3 VertexPos   : TEXCOORD4;
};

VS_OUTPUT_Mesh_N VShaderMeshNormalMap( VS_INPUT_Mesh_N In )
{
    VS_OUTPUT_Mesh_N Out;
    Out.Position = 0;
    Out.Normal = 0;
    Out.Tangent = 0;
    Out.Binormal = 0;
    Out.VertexPos = In.Position.xyz;
   
    float4 position =  mul(In.Position, g_mWorld);
    Out.Position = mul(float4(position.xyz, 1.0f), g_mViewProj);
   
    Out.Normal = normalize(mul(In.Normal, (float3x3)g_mWorld));   // normal (world space)
    Out.Tangent = normalize(mul(-In.Tangent, (float3x3)g_mWorld));  //maya exporter perhaps "-"
    Out.Binormal = normalize(mul(-In.Binormal, (float3x3)g_mWorld));
   
    //Out.Binormal = cross( Out.Normal, Out.Tangent );
   
    // Pass the texture coordinate
    Out.Tex0 = In.Tex0;
       
    return Out;
}

PS_OUTPUT PShaderMeshNormalMap( VS_OUTPUT_Mesh_N In)
{
 PS_OUTPUT Out; 
 
 float4 diffuse_color = tex2D(DiffuseMap, In.Tex0);
 float3 normal_map = tex2D( NormalMap, In.Tex0 ).xyz;
    
    float3 L = normalize(g_LightDir[0].xyz);
    float3 V = normalize ( g_vCameraPosition - In.VertexPos ) ;
    float3 H = normalize ( V + L ) ;
   
    float3 N = normalize(normal_map . xyz/* * 2.0f - 0.5f*/) ;
    float3x3 TBNMatrix = float3x3(In.Tangent, In.Binormal, In.Normal);
    N = normalize(mul(N, TBNMatrix));
   
 float intensity = saturate( dot(N, L) );
 float3 ambient = g_LightAmbient;
 float3 diffuse = intensity * g_LightDiffuse[0];
 float3 light = lerp( ambient + diffuse, float3(1,1,1), emissive ) ;
 float3 specular_light = pow(max(dot(H , N) , 0.001f) , g_MaterialShininess) * g_LightDiffuse[0] ;
 
 Out.RGBColor.xyz = diffuse_color.xyz * light + specular_light;
    Out.RGBColor.w = diffuse_color.w;
   
 return Out;
}

technique MeshNormalMap
{
    pass P0
    { 
        VertexShader = compile vs_2_0 VShaderMeshNormalMap();
        PixelShader  = compile ps_2_0 PShaderMeshNormalMap();
    }
}

using ch.sycoforge.Types; using UnityEngine; using UnityEngine.Profiling; using static UnityEditor.ShaderData; Shader "Custom/WaterShaderWithDepth" { Properties { _Color ("Shallow Water Color", Color) = (0.2, 0.6, 1, 0.8) _DepthColor ("Deep Water Color", Color) = (0.1, 0.3, 0.5, 1) _WaveSpeed ("Wave Speed", Range(0, 5)) = 1.0 _WaveHeight ("Wave Height", Range(0, 1)) = 0.2 _WaveFrequency ("Wave Frequency", Range(0, 10)) = 2.0 _NormalMap ("Normal Map", 2D) = "bump" {} _NormalScale("Normal Scale", Range(0, 2)) = 0.5 _ReflectionCube("Reflection Cubemap", Cube) = "" { } _ReflectionIntensity("Reflection Intensity", Range(0, 1)) = 0.7 _Glossiness("Smoothness", Range(0, 1)) = 0.9 _DepthMaxDistance("Depth Max Distance", Float) = 10.0 _DepthFactor("Depth Factor", Range(0, 5)) = 1.0 _FoamColor("Foam Color", Color) = (1, 1, 1, 1) _FoamThreshold("Foam Threshold", Range(0, 1)) = 0.3 _FoamIntensity("Foam Intensity", Range(0, 1)) = 0.5 } SubShader { Tags { "RenderType"="Transparent" "Queue"="Transparent" } LOD 300 Blend SrcAlpha OneMinusSrcAlpha ZWrite Off CGPROGRAM #pragma surface surf Standard alpha:fade #pragma target 3.0 # include "UnityCG.cginc" struct Input { float2 uv_NormalMap; float3 worldPos; float3 worldRefl; float4 screenPos; INTERNAL_DATA }; fixed4 _Color; fixed4 _DepthColor; float _WaveSpeed; float _WaveHeight; float _WaveFrequency; sampler2D _NormalMap; float _NormalScale; samplerCUBE _ReflectionCube; float _ReflectionIntensity; float _Glossiness; float _DepthMaxDistance; float _DepthFactor; fixed4 _FoamColor; float _FoamThreshold; float _FoamIntensity; sampler2D _CameraDepthTexture; // 深度纹理 void surf(Input IN, inout SurfaceOutputStandard o) { // 波浪动画 float wave1 = sin(_Time.y * _WaveSpeed + IN.worldPos.x * _WaveFrequency) * _WaveHeight; float wave2 = sin(_Time.y * _WaveSpeed * 0.7 + IN.worldPos.z * _WaveFrequency * 1.3) * _WaveHeight * 0.7; float wave = wave1 + wave2; // 法线贴图 float2 normalUV = IN.uv_NormalMap; normalUV.x += _Time.x * 0.1; normalUV.y += _Time.x * 0.05; fixed3 normal1 = UnpackScaleNormal(tex2D(_NormalMap, normalUV), _NormalScale); fixed3 normal2 = UnpackScaleNormal(tex2D(_NormalMap, normalUV * 1.7 + float2(0.2, -0.3)), _NormalScale * 0.7); o.Normal = normalize(normal1 + normal2); // 菲涅尔效应 float3 viewDir = normalize(IN.worldPos - _WorldSpaceCameraPos); float fresnel = pow(1.0 - saturate(dot(o.Normal, viewDir)), 4); // 反射计算 float3 worldRefl = WorldReflectionVector(IN, o.Normal); fixed4 reflection = texCUBE(_ReflectionCube, worldRefl); // ================== 深度计算 ================== // 获取屏幕坐标和深度值 float2 screenUV = IN.screenPos.xy / IN.screenPos.w; #if UNITY_UV_STARTS_AT_TOP screenUV.y = 1 - screenUV.y; #endif // 采样场景深度 float sceneDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, screenUV)); // 计算水面深度 float waterSurfaceDepth = IN.screenPos.w; // 计算实际水深 float waterDepth = sceneDepth - waterSurfaceDepth; // 标准化水深 (0-1范围) float depthNormalized = saturate(waterDepth / _DepthMaxDistance); // 应用深度因子调整 float depthFactor = saturate(depthNormalized * _DepthFactor); // ================== 颜色混合 ================== // 基于水深混合浅水和深水颜色 fixed4 baseColor = lerp(_Color, _DepthColor, depthFactor); // 添加泡沫效果(岸边浅水区) float foam = 1 - saturate(depthFactor / _FoamThreshold); fixed4 foamColor = _FoamColor * foam * _FoamIntensity; baseColor.rgb += foamColor.rgb; // 混合反射 fixed4 waterColor = lerp(baseColor, reflection, fresnel * _ReflectionIntensity); // 应用波浪高度影响颜色 waterColor.rgb *= 1.0 - (abs(wave) * 0.2); o.Albedo = waterColor.rgb; o.Metallic = 0.0; o.Smoothness = _Glossiness; // 透明度基于水深调整(深水区更透明) o.Alpha = lerp(_Color.a, _DepthColor.a, depthFactor * 0.5); } ENDCG } FallBack "Transparent/Diffuse" }
最新发布
07-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值