unity粗糙、高光、光泽度调节shader记录

记录一个URP中的带粗糙、高光、光泽度调节的shader,方便之后作为扩展的基础使用。

csharp 复制代码
// OrenNayarURP.shader
Shader "Custom/OrenNayarURP"
{
    Properties
    {
        [MainTexture] _BaseMap("Texture", 2D) = "white" {}
        [MainColor] _BaseColor("Color", Color) = (1,1,1,1)
        //粗糙
        _Roughness("Roughness", Range(0, 1)) = 0.5
        //高光
        _Specular("Specular", Range(0, 1)) = 0.0
        //光泽
        _Gloss("Gloss", Range(0, 1)) = 0.5
    }
    
    SubShader
    {
        Tags 
        { 
            "RenderType" = "Opaque"
            "RenderPipeline" = "UniversalPipeline"
            "IgnoreProjector" = "True"
        }
        
        Pass
        {
            Name "ForwardLit"
            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;
                float2 uv           : TEXCOORD0;
            };
            
            struct Varyings
            {
                float4 positionHCS  : SV_POSITION;
                float2 uv           : TEXCOORD0;
                float3 normalWS     : TEXCOORD1;
                float3 positionWS   : TEXCOORD2;
                float3 viewDirWS    : TEXCOORD3;
            };
            
            TEXTURE2D(_BaseMap);
            SAMPLER(sampler_BaseMap);
            float4 _BaseMap_ST;
            
            CBUFFER_START(UnityPerMaterial)
                float4 _BaseColor;
                float _Roughness;
                float _Specular;
                float _Gloss;
            CBUFFER_END
            
            // Oren-Nayar BRDF 函数
            float OrenNayarDiffuse(
                float3 lightDir,
                float3 viewDir,
                float3 normal,
                float roughness)
            {
                float NdotL = saturate(dot(normal, lightDir));
                float NdotV = saturate(dot(normal, viewDir));
                
                if (NdotL <= 0 || NdotV <= 0)
                    return 0.0;
                
                float sigma = roughness * 1.570796; // π/2
                float sigma2 = sigma * sigma;
                
                float A = 1.0 - 0.5 * (sigma2 / (sigma2 + 0.33));
                float B = 0.45 * (sigma2 / (sigma2 + 0.09));
                
                float3 lightProj = normalize(lightDir - normal * NdotL);
                float3 viewProj = normalize(viewDir - normal * NdotV);
                
                float cosPhi = dot(lightProj, viewProj);
                cosPhi = saturate(cosPhi);
                
                float thetaL = acos(NdotL);
                float thetaV = acos(NdotV);
                float alpha = max(thetaL, thetaV);
                float beta = min(thetaL, thetaV);
                
                float L1 = A;
                float L2 = B * cosPhi * sin(alpha) * tan(beta);
                
                return NdotL * (L1 + L2);
            }
            
            Varyings vert(Attributes IN)
            {
                Varyings OUT;
                
                VertexPositionInputs positionInputs = GetVertexPositionInputs(IN.positionOS.xyz);
                OUT.positionHCS = positionInputs.positionCS;
                OUT.positionWS = positionInputs.positionWS;
                
                VertexNormalInputs normalInputs = GetVertexNormalInputs(IN.normalOS);
                OUT.normalWS = normalInputs.normalWS;
                
                OUT.viewDirWS = GetWorldSpaceNormalizeViewDir(OUT.positionWS);
                OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap);
                
                return OUT;
            }
            
            half4 frag(Varyings IN) : SV_Target
            {
                // 准备数据
                float3 normalWS = normalize(IN.normalWS);
                float3 viewDirWS = normalize(IN.viewDirWS);
                
                // 获取主光源
                Light mainLight = GetMainLight();
                float3 lightDirWS = normalize(mainLight.direction);
                
                // Oren-Nayar 漫反射
                float diffuse = OrenNayarDiffuse(lightDirWS, viewDirWS, normalWS, _Roughness);
                float3 diffuseColor = diffuse * mainLight.color * _BaseColor.rgb;
                
                // 简单高光
                float3 halfVec = normalize(lightDirWS + viewDirWS);
                float specular = pow(saturate(dot(normalWS, halfVec)), _Gloss * 128) * _Specular;
                float3 specularColor = specular * mainLight.color;
                
                // 纹理采样
                float4 texColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);
                
                // 组合颜色
                float3 finalColor = (diffuseColor + specularColor) * texColor.rgb;
                
                return half4(finalColor, 1.0);
            }
            ENDHLSL
        }
    }
}
相关推荐
DaLiangChen9 小时前
Unity 精准 Mesh 点击检测:穿透遮挡 + 单击双击识别
unity·游戏引擎
迪普阳光开朗很健康12 小时前
Unity中new() 和实例化有什么区别?
unity·游戏引擎
mxwin12 小时前
Unity Shader 极坐标特效 从数学原理到实战案例
unity·游戏引擎·shader·uv
魔士于安1 天前
unity 圆盘式 太空飞船
游戏·unity·游戏引擎·贴图·模型
陈言必行1 天前
Unity 之 Addressables 加载失败:路径变量未替换导致的 404 错误分析与解决
unity·游戏引擎
qq_170264752 天前
unity出安卓年龄分级的arr包问题
android·unity·游戏引擎
WMX10122 天前
Holoens2开发报错记录02_unity项目常见错误
unity
魔士于安2 天前
宇宙版地球模拟器
游戏·unity·游戏引擎·贴图·模型
魔士于安2 天前
氛围感游戏场景,天空盒,带地形,附赠一个空要塞
游戏·unity·游戏引擎·贴图
ellis19702 天前
Unity程序集(assembly)笔记
unity