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
        }
    }
}
相关推荐
一锅炖出任易仙1 小时前
创梦汤锅学习日记day34
学习·游戏引擎
Y学院2 小时前
C#游戏脚本开发全流程(Unity通用完整版)
游戏·unity·c#
ellis19703 小时前
Lua的module和require
unity·lua
淡海水4 小时前
38-Hybrid生态-LeanCLR总览
unity·架构·c#·热更新·clr·hybrid·leanclr
郝学胜-神的一滴5 小时前
[简化版 GAMES 101] 计算机图形学 13:从光栅化到着色——赋予三维像素光影灵魂
c++·计算机视觉·unity·godot·图形渲染·opengl·unreal
晓13135 小时前
【Cocos Creator 3.x】篇——第五章 项目实战优化技术
前端·javascript·游戏引擎
fqkw65 小时前
unity 安装MCP +uvx
unity·游戏引擎
魔士于安1 天前
unity 音乐会场景 unity2022
游戏·unity·游戏引擎·贴图·模型
一线灵1 天前
Axmol 3.x 输入系统重构:从 Touch/Mouse 到统一 Pointer,再到现代 InputField
重构·游戏引擎
Zwarwolf1 天前
Godot零散知识点项目汇总
游戏引擎·godot