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
        }
    }
}
相关推荐
鹿野素材屋21 小时前
Unity超轻量级中文语音播报,仅5兆大小,无需联网即可使用,适用于弹幕、提示等动态语音播出
unity·游戏引擎
电子云与长程纠缠2 天前
UE5 Lyra PocketWorld进行3D内容UI预览 - 上
开发语言·学习·3d·ue5·游戏引擎
玖玥拾2 天前
Unity3D RPG 入门项目(八)游戏设置面板、帧率控制、快捷技能药品栏、技能解锁系统
游戏·3d·unity·游戏引擎
ellis19702 天前
u3d插件xLua[十] lua侧判空问题
unity
牛哇网络工作室2 天前
UnityHDRP写实数字人全流程基础5—语音输入和语音识别
android·unity·c#·游戏引擎·aigc·语音识别·xcode
ellis19703 天前
u3d插件xLua[九]例8 Hotfix
unity
淡海水3 天前
01-07-运行时-GC深度剖析-内存分配回收与结构选择
jvm·windows·unity·gc
优梦创客3 天前
游戏开发架构选型:第1篇|什么是架构?从进球事件看 MVC 的局限
unity·架构·游戏引擎·游戏开发
zhangphil4 天前
Unity3D(Unity)跨平台游戏引擎简介
unity
Madokaly4 天前
DOTween动画:TweenManager深度解析
unity