浏览代码

Refactor to improve shader library organization and readability

/main
Felipe Lira 7 年前
当前提交
0324ec96
共有 36 个文件被更改,包括 769 次插入744 次删除
  1. 2
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightBlit.shader
  2. 2
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCopyDepth.shader
  3. 5
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassLit.hlsl
  4. 4
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassMeta.hlsl
  5. 2
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassShadow.hlsl
  6. 2
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandard.shader
  7. 4
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandardParticles.shader
  8. 2
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandardSimpleLighting.shader
  9. 4
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandardTerrain.shader
  10. 5
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightUnlit.shader
  11. 4
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Particles.hlsl
  12. 4
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Shadows.hlsl
  13. 2
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputSurface.hlsl
  14. 14
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputBuiltin.hlsl
  15. 135
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Core.hlsl
  16. 60
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Input.hlsl
  17. 552
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Lighting.hlsl
  18. 67
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightInput.hlsl
  19. 217
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCore.hlsl
  20. 426
      ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightLighting.hlsl
  21. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary.meta
  22. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Particles.hlsl
  23. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Particles.hlsl.meta
  24. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Core.hlsl.meta
  25. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Input.hlsl.meta
  26. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Lighting.hlsl.meta
  27. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Shadows.hlsl.meta
  28. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputSurface.hlsl.meta
  29. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Shadows.hlsl
  30. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputSurface.hlsl
  31. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputBuiltin.hlsl.meta
  32. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/CoreFunctions.hlsl
  33. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/CoreFunctions.hlsl.meta
  34. 0
      /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputBuiltin.hlsl

2
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightBlit.shader


#pragma vertex Vertex
#pragma fragment Fragment
#include "LightweightCore.hlsl"
#include "LightweightShaderLibrary/Core.hlsl"
struct VertexInput
{

2
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCopyDepth.shader


#pragma vertex vert
#pragma fragment frag
#include "LightweightCore.hlsl"
#include "LightweightShaderLibrary/Core.hlsl"
TEXTURE2D_FLOAT(_CameraDepthTexture);
SAMPLER2D(sampler_CameraDepthTexture);

5
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassLit.hlsl


#ifndef LIGHTWEIGHT_PASS_LIT_INCLUDED
#define LIGHTWEIGHT_PASS_LIT_INCLUDED
#include "LightweightSurfaceInput.hlsl"
#include "LightweightLighting.hlsl"
#include "LightweightShaderLibrary/InputSurface.hlsl"
#include "LightweightShaderLibrary/Lighting.hlsl"
struct LightweightVertexInput
{

half4 fogFactorAndVertexLight : TEXCOORD7; // x: fogFactor, yzw: vertex light
float4 clipPos : SV_POSITION;
//UNITY_VERTEX_OUTPUT_STEREO
};
///////////////////////////////////////////////////////////////////////////////

4
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassMeta.hlsl


#ifndef LIGHTWEIGHT_PASS_META_INCLUDED
#define LIGHTWEIGHT_PASS_META_INCLUDED
#include "LightweightSurfaceInput.hlsl"
#include "LightweightLighting.hlsl"
#include "LightweightShaderLibrary/InputSurface.hlsl"
#include "LightweightShaderLibrary/Lighting.hlsl"
CBUFFER_START(UnityMetaPass)
// x = use uv1 as raster position

2
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightPassShadow.hlsl


#ifndef LIGHTWEIGHT_PASS_SHADOW_INCLUDED
#define LIGHTWEIGHT_PASS_SHADOW_INCLUDED
#include "LightweightCore.hlsl"
#include "LightweightShaderLibrary/Core.hlsl"
float4 ShadowPassVertex(float4 pos : POSITION) : SV_POSITION
{

2
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandard.shader


#pragma vertex vert
#pragma fragment frag
#include "LightweightCore.hlsl"
#include "LightweightShaderLibrary/Core.hlsl"
float4 vert(float4 pos : POSITION) : SV_POSITION
{

4
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandardParticles.shader


#pragma shader_feature _FADING_ON
#pragma shader_feature _REQUIRE_UV2
#include "LightweightParticle.hlsl"
#include "LightweightLighting.hlsl"
#include "LightweightShaderLibrary/Particles.hlsl"
#include "LightweightShaderLibrary/Lighting.hlsl"
VertexOutputLit ParticlesLitVertex(appdata_particles v)
{

2
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandardSimpleLighting.shader


#pragma vertex vert
#pragma fragment frag
#include "LightweightCore.hlsl"
#include "LightweightShaderLibrary/Core.hlsl"
float4 vert(float4 pos : POSITION) : SV_POSITION
{

4
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightStandardTerrain.shader


#pragma multi_compile __ _TERRAIN_NORMAL_MAP
#pragma multi_compile_fog
#include "LightweightLighting.hlsl"
#include "LightweightShaderLibrary/Lighting.hlsl"
CBUFFER_START(_Terrain)
half _Metallic0;

#pragma vertex vert
#pragma fragment frag
#include "LightweightCore.hlsl"
#include "LightweightShaderLibrary/Core.hlsl"
float4 vert(float4 pos : POSITION) : SV_POSITION
{

5
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightUnlit.shader


#pragma shader_feature _SAMPLE_GI
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON
#include "LightweightCore.hlsl"
#include "LightweightSurfaceInput.hlsl"
// Lighting include is needed because of GI
#include "LightweightShaderLibrary/Lighting.hlsl"
#include "LightweightShaderLibrary/InputSurface.hlsl"
struct VertexInput
{

4
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Particles.hlsl


#include "LightweightCore.hlsl"
#include "LightweightSurfaceInput.hlsl"
#include "Core.hlsl"
#include "InputSurface.hlsl"
#if defined (_COLORADDSUBDIFF_ON)
half4 _ColorAddSubDiff;

4
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Shadows.hlsl


#define LIGHTWEIGHT_SHADOWS_INCLUDED
#include "ShaderLibrary\Common.hlsl"
#include "LightweightInput.hlsl"
#define MAX_SHADOW_CASCADES 4

TEXTURE2D_SHADOW(_ShadowMap);
SAMPLER2D_SHADOW(sampler_ShadowMap);
CBUFFER_START(_ShadowBuffer)
float4x4 _WorldToShadow[MAX_SHADOW_CASCADES];
float4 _DirShadowSplitSpheres[MAX_SHADOW_CASCADES];
half4 _ShadowOffset0;

half4 _ShadowData; // (x: 1.0 - shadowStrength, y: bias, z: normal bias, w: near plane offset)
CBUFFER_END
float ApplyDepthBias(float clipZ)
{

2
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputSurface.hlsl


#ifndef LIGHTWEIGHT_SURFACE_INPUT_INCLUDED
#define LIGHTWEIGHT_SURFACE_INPUT_INCLUDED
#include "LightweightCore.hlsl"
#include "Core.hlsl"
#include "ShaderLibrary/Packing.hlsl"
#ifdef _SPECULAR_SETUP

14
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputBuiltin.hlsl


#ifndef LIGHTWEIGHT_SHADER_VARIABLES_INCLUDED
#define LIGHTWEIGHT_SHADER_VARIABLES_INCLUDED
#include "ShaderLibrary/Common.hlsl"
// CAUTION:
// Currently the shaders compiler always include regualr Unity shaderVariables, so I get a conflict here were UNITY_SHADER_VARIABLES_INCLUDED is already define, this need to be fixed.
// As I haven't change the variables name yet, I simply don't define anything, and I put the transform function at the end of the file outside the guard header.
// This need to be fixed.
#if defined (DIRECTIONAL_COOKIE) || defined (DIRECTIONAL)
#define USING_DIRECTIONAL_LIGHT
#endif
#if defined(UNITY_SINGLE_PASS_STEREO) || defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
#define USING_STEREO_MATRICES
#endif

M._12_42 = 0;
return M;
}
#include "ShaderVariables/LightweightShaderVariablesCamera.hlsl"
#include "ShaderVariables/LightweightShaderVariablesFunctions.hlsl"
#endif // LIGHTWEIGHT_SHADER_VARIABLES_INCLUDED

135
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Core.hlsl


#ifndef LIGHTWEIGHT_PIPELINE_CORE_INCLUDED
#define LIGHTWEIGHT_PIPELINE_CORE_INCLUDED
#include "ShaderLibrary/Common.hlsl"
#include "Input.hlsl"
#ifdef _NORMALMAP
#define OUTPUT_NORMAL(IN, OUT) OutputTangentToWorld(IN.tangent, IN.normal, OUT.tangent, OUT.binormal, OUT.normal)
#else
#define OUTPUT_NORMAL(IN, OUT) OUT.normal = TransformObjectToWorldNormal(IN.normal)
#endif
#if defined(UNITY_REVERSED_Z)
#if UNITY_REVERSED_Z == 1
//D3d with reversed Z => z clip range is [near, 0] -> remapping to [0, far]
//max is required to protect ourselves from near plane not being correct/meaningfull in case of oblique matrices.
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(((1.0-(coord)/_ProjectionParams.y)*_ProjectionParams.z),0)
#else
//GL with reversed z => z clip range is [near, -far] -> should remap in theory but dont do it in practice to save some perf (range is close enough)
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(-(coord), 0)
#endif
#elif UNITY_UV_STARTS_AT_TOP
//D3d without reversed z => z clip range is [0, far] -> nothing to do
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
#else
//Opengl => z clip range is [-near, far] -> should remap in theory but dont do it in practice to save some perf (range is close enough)
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
#endif
half Pow4(half x)
{
return x * x * x * x;
}
half LerpOneTo(half b, half t)
{
half oneMinusT = 1 - t;
return oneMinusT + b * t;
}
void AlphaDiscard(half alpha, half cutoff)
{
#ifdef _ALPHATEST_ON
clip(alpha - cutoff);
#endif
}
half3 SafeNormalize(half3 inVec)
{
half dp3 = max(1.e-4h, dot(inVec, inVec));
return inVec * rsqrt(dp3);
}
// Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1)
// Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5
half3 UnpackNormalmapRGorAG(half4 packedNormal, half bumpScale)
{
// This do the trick
packedNormal.x *= packedNormal.w;
half3 normal;
normal.xy = packedNormal.xy * 2 - 1;
normal.xy *= bumpScale;
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
return normal;
}
half3 UnpackNormalRGB(half4 packedNormal, half bumpScale)
{
half3 normal = packedNormal.xyz * 2 - 1;
normal.xy *= bumpScale;
return normal;
}
half3 UnpackNormal(half4 packedNormal)
{
// Compiler will optimize the scale away
#if defined(UNITY_NO_DXT5nm)
return UnpackNormalRGB(packedNormal, 1.0);
#else
return UnpackNormalmapRGorAG(packedNormal, 1.0);
#endif
}
half3 UnpackNormalScale(half4 packedNormal, half bumpScale)
{
#if defined(UNITY_NO_DXT5nm)
return UnpackNormalRGB(packedNormal, bumpScale);
#else
return UnpackNormalmapRGorAG(packedNormal, bumpScale);
#endif
}
void OutputTangentToWorld(half4 vertexTangent, half3 vertexNormal, out half3 tangentWS, out half3 binormalWS, out half3 normalWS)
{
half sign = vertexTangent.w * GetOddNegativeScale();
normalWS = TransformObjectToWorldNormal(vertexNormal);
tangentWS = normalize(mul((half3x3)unity_ObjectToWorld, vertexTangent.xyz));
binormalWS = cross(normalWS, tangentWS) * sign;
}
half3 TangentToWorldNormal(half3 normalTangent, half3 tangent, half3 binormal, half3 normal)
{
half3x3 tangentToWorld = half3x3(tangent, binormal, normal);
return normalize(mul(normalTangent, tangentToWorld));
}
float ComputeFogFactor(float z)
{
float clipZ_01 = UNITY_Z_0_FAR_FROM_CLIPSPACE(z);
#if defined(FOG_LINEAR)
// factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
float fogFactor = saturate(clipZ_01 * unity_FogParams.z + unity_FogParams.w);
return half(fogFactor);
#elif defined(FOG_EXP)
// factor = exp(-density*z)
float unityFogFactor = unity_FogParams.y * clipZ_01;
return half(saturate(exp2(-unityFogFactor)));
#elif defined(FOG_EXP2)
// factor = exp(-(density*z)^2)
float unityFogFactor = unity_FogParams.x * clipZ_01;
return half(saturate(exp2(-unityFogFactor*unityFogFactor)));
#else
return 0.0h;
#endif
}
void ApplyFog(inout half3 color, half fogFactor)
{
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
color = lerp(unity_FogColor, color, fogFactor);
#endif
}
#endif

60
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Input.hlsl


#ifndef LIGHTWEIGHT_INPUT_INCLUDED
#define LIGHTWEIGHT_INPUT_INCLUDED
#define MAX_VISIBLE_LIGHTS 16
///////////////////////////////////////////////////////////////////////////////
// Constant Buffers //
///////////////////////////////////////////////////////////////////////////////
CBUFFER_START(_PerFrame)
half4 _GlossyEnvironmentColor;
half4 _SubtractiveShadowColor;
CBUFFER_END
CBUFFER_START(_PerCamera)
float4 _MainLightPosition;
half4 _MainLightColor;
half4 _MainLightDistanceAttenuation;
half4 _MainLightSpotDir;
half4 _MainLightSpotAttenuation;
float4x4 _WorldToLight;
half4 _AdditionalLightCount;
float4 _AdditionalLightPosition[MAX_VISIBLE_LIGHTS];
half4 _AdditionalLightColor[MAX_VISIBLE_LIGHTS];
half4 _AdditionalLightDistanceAttenuation[MAX_VISIBLE_LIGHTS];
half4 _AdditionalLightSpotDir[MAX_VISIBLE_LIGHTS];
half4 _AdditionalLightSpotAttenuation[MAX_VISIBLE_LIGHTS];
CBUFFER_END
// These are set internally by the engine upon request by RendererConfiguration.
// Check GetRendererSettings in LightweightPipeline.cs
CBUFFER_START(_PerObject)
half4 unity_LightIndicesOffsetAndCount;
half4 unity_4LightIndices0;
half4 unity_4LightIndices1;
CBUFFER_END
#define UNITY_MATRIX_M unity_ObjectToWorld
#define UNITY_MATRIX_I_M unity_WorldToObject
#define UNITY_MATRIX_V unity_MatrixV
#define UNITY_MATRIX_I_V unity_MatrixInvV
#define UNITY_MATRIX_P OptimizeProjectionMatrix(glstate_matrix_projection)
#define UNITY_MATRIX_I_P ERROR_UNITY_MATRIX_I_P_IS_NOT_DEFINED
#define UNITY_MATRIX_VP unity_MatrixVP
#define UNITY_MATRIX_I_VP ERROR_UNITY_MATRIX_I_VP_IS_NOT_DEFINED
#define UNITY_MATRIX_MV mul(UNITY_MATRIX_V, UNITY_MATRIX_M)
#define UNITY_MATRIX_T_MV transpose(UNITY_MATRIX_MV)
#define UNITY_MATRIX_IT_MV transpose(mul(UNITY_MATRIX_I_M, UNITY_MATRIX_I_V))
#define UNITY_MATRIX_MVP mul(UNITY_MATRIX_VP, UNITY_MATRIX_M)
#include "InputBuiltin.hlsl"
#include "CoreFunctions.hlsl"
float3 GetCameraPosition()
{
return _WorldSpaceCameraPos;
}
#endif

552
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Lighting.hlsl


#ifndef LIGHTWEIGHT_LIGHTING_INCLUDED
#define LIGHTWEIGHT_LIGHTING_INCLUDED
#include "ShaderLibrary/Common.hlsl"
#include "ShaderLibrary/EntityLighting.hlsl"
#include "ShaderLibrary/ImageBasedLighting.hlsl"
#include "Core.hlsl"
#include "Shadows.hlsl"
#ifdef NO_ADDITIONAL_LIGHTS
#undef _ADDITIONAL_LIGHTS
#endif
// If lightmap is not defined than we evaluate GI (ambient + probes) from SH
// We might do it fully or partially in vertex to save shader ALU
#if !defined(LIGHTMAP_ON)
#ifdef SHADER_API_GLES
// Evaluates SH fully in vertex
#define EVALUATE_SH_VERTEX
#else
// Evaluates L2 SH in vertex and L0L1 in pixel
#define EVALUATE_SH_MIXED
#endif
#endif
#ifdef LIGHTMAP_ON
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT) OUT.xy = lightmapUV.xy * lightmapScaleOffset.xy + lightmapScaleOffset.zw;
#define OUTPUT_SH(normalWS, OUT)
#else
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT)
#define OUTPUT_SH(normalWS, OUT) OUT.xyz = SampleSHVertex(normalWS)
#endif
///////////////////////////////////////////////////////////////////////////////
// Light Helpers //
///////////////////////////////////////////////////////////////////////////////
struct LightInput
{
float4 position;
half3 color;
half4 distanceAttenuation;
half4 spotDirection;
half4 spotAttenuation;
};
LightInput GetMainLight()
{
LightInput light;
light.position = _MainLightPosition;
light.color = _MainLightColor.rgb;
light.distanceAttenuation = _MainLightDistanceAttenuation;
light.spotDirection = _MainLightSpotDir;
light.spotAttenuation = _MainLightSpotAttenuation;
return light;
}
LightInput GetLight(int i)
{
LightInput light;
half4 indices = (i < 4) ? unity_4LightIndices0 : unity_4LightIndices1;
int index = (i < 4) ? i : i - 4;
int lightIndex = indices[index];
light.position = _AdditionalLightPosition[lightIndex];
light.color = _AdditionalLightColor[lightIndex].rgb;
light.distanceAttenuation = _AdditionalLightDistanceAttenuation[lightIndex];
light.spotDirection = _AdditionalLightSpotDir[lightIndex];
light.spotAttenuation = _AdditionalLightSpotAttenuation[lightIndex];
return light;
}
half GetPixelLightCount()
{
return min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y);
}
///////////////////////////////////////////////////////////////////////////////
// Global Illumination //
///////////////////////////////////////////////////////////////////////////////
// Samples SH L0, L1 and L2 terms
half3 SampleSH(half3 normalWS)
{
// LPPV is not supported in Ligthweight Pipeline
float4 SHCoefficients[7];
SHCoefficients[0] = unity_SHAr;
SHCoefficients[1] = unity_SHAg;
SHCoefficients[2] = unity_SHAb;
SHCoefficients[3] = unity_SHBr;
SHCoefficients[4] = unity_SHBg;
SHCoefficients[5] = unity_SHBb;
SHCoefficients[6] = unity_SHC;
return SampleSH9(SHCoefficients, normalWS);
}
// SH Vertex Evaluation. Depending on target SH sampling might be
// done completely per vertex or mixed with L2 term per vertex and L0, L1
// per pixel. See SampleSHPixel
half3 SampleSHVertex(half3 normalWS)
{
#if defined(EVALUATE_SH_VERTEX)
return max(half3(0, 0, 0), SampleSH(normalWS));
#elif defined(EVALUATE_SH_MIXED)
// no max since this is only L2 contribution
return SHEvalLinearL2(normalWS, unity_SHBr, unity_SHBg, unity_SHBb, unity_SHC);
#endif
// Fully per-pixel. Nothing to compute.
return half3(0.0, 0.0, 0.0);
}
// SH Pixel Evaluation. Depending on target SH sampling might be done
// mixed or fully in pixel. See SampleSHVertex
half3 SampleSHPixel(half3 L2Term, half3 normalWS)
{
#ifdef EVALUATE_SH_MIXED
half3 L0L1Term = SHEvalLinearL0L1(normalWS, unity_SHAr, unity_SHAg, unity_SHAb);
return max(half3(0, 0, 0), L2Term + L0L1Term);
#endif
// Default: Evaluate SH fully per-pixel
return max(half3(0, 0, 0), SampleSH(normalWS));
}
// Sample baked lightmap. Non-Direction and Directional if available.
// Realtime GI is not supported.
half3 SampleLightmap(float2 lightmapUV, half3 normalWS)
{
#ifdef UNITY_LIGHTMAP_FULL_HDR
bool encodedLightmap = false;
#else
bool encodedLightmap = true;
#endif
// The shader library sample lightmap functions transform the lightmap uv coords to apply bias and scale.
// However, lightweight pipeline already transformed those coords in vertex. We pass half4(1, 1, 0, 0) and
// the compiler will optimize the transform away.
half4 transformCoords = half4(1, 1, 0, 0);
#ifdef DIRLIGHTMAP_COMBINED
return SampleDirectionalLightmap(TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap),
TEXTURE2D_PARAM(unity_LightmapInd, samplerunity_Lightmap),
lightmapUV, transformCoords, normalWS, encodedLightmap);
#else
return SampleSingleLightmap(TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap), lightmapUV, transformCoords, encodedLightmap);
#endif
}
// We either sample GI from baked lightmap or from probes.
// If lightmap: sampleData.xy = lightmapUV
// If probe: sampleData.xyz = L2 SH terms
half3 SampleGI(float4 sampleData, half3 normalWS)
{
#ifdef LIGHTMAP_ON
return SampleLightmap(sampleData.xy, normalWS);
#endif
// If lightmap is not enabled we sample GI from SH
return SampleSHPixel(sampleData.xyz, normalWS);
}
half3 DiffuseGI(half3 indirectDiffuse, half3 lambert, half mainLightRealtimeAttenuation, half occlusion)
{
// If shadows and mixed subtractive mode is enabled we need to remove direct
// light contribution from lightmap from occluded pixels so we can have dynamic objects
// casting shadows onto static correctly.
#if defined(_MIXED_LIGHTING_SUBTRACTIVE) && defined(LIGHTMAP_ON) && defined(_SHADOWS)
indirectDiffuse = SubtractDirectMainLightFromLightmap(indirectDiffuse, mainLightRealtimeAttenuation, lambert);
#endif
return indirectDiffuse * occlusion;
}
half3 GlossyEnvironmentReflection(half3 viewDirectionWS, half3 normalWS, half perceptualRoughness, half occlusion)
{
half3 reflectVector = reflect(-viewDirectionWS, normalWS);
#if !defined(_GLOSSYREFLECTIONS_OFF)
half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
half4 encodedIrradiance = SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip);
#if !defined(UNITY_USE_NATIVE_HDR)
half3 irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
#else
half3 irradiance = encodedIrradiance.rbg;
#endif
return irradiance * occlusion;
#endif // GLOSSY_REFLECTIONS
return _GlossyEnvironmentColor.rgb * occlusion;
}
///////////////////////////////////////////////////////////////////////////////
// BRDF Functions //
///////////////////////////////////////////////////////////////////////////////
#define kDieletricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) // standard dielectric reflectivity coef at incident angle (= 4%)
struct BRDFData
{
half3 diffuse;
half3 specular;
half perceptualRoughness;
half roughness;
half grazingTerm;
};
half ReflectivitySpecular(half3 specular)
{
#if (SHADER_TARGET < 30)
// SM2.0: instruction count limitation
return specular.r; // Red channel - because most metals are either monocrhome or with redish/yellowish tint
#else
return max(max(specular.r, specular.g), specular.b);
#endif
}
half OneMinusReflectivityMetallic(half metallic)
{
// We'll need oneMinusReflectivity, so
// 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
// store (1-dielectricSpec) in kDieletricSpec.a, then
// 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
// = alpha - metallic * alpha
half oneMinusDielectricSpec = kDieletricSpec.a;
return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
}
inline void InitializeBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, half alpha, out BRDFData outBRDFData)
{
#ifdef _SPECULAR_SETUP
half reflectivity = ReflectivitySpecular(specular);
half oneMinusReflectivity = 1.0 - reflectivity;
outBRDFData.diffuse = albedo * (half3(1.0h, 1.0h, 1.0h) - specular);
outBRDFData.specular = specular;
#else
half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic);
half reflectivity = 1.0 - oneMinusReflectivity;
outBRDFData.diffuse = albedo * oneMinusReflectivity;
outBRDFData.specular = lerp(kDieletricSpec.rgb, albedo, metallic);
#endif
outBRDFData.grazingTerm = saturate(smoothness + reflectivity);
outBRDFData.perceptualRoughness = 1.0h - smoothness;
outBRDFData.roughness = outBRDFData.perceptualRoughness * outBRDFData.perceptualRoughness;
#ifdef _ALPHAPREMULTIPLY_ON
outBRDFData.diffuse *= alpha;
alpha = alpha * oneMinusReflectivity + reflectivity;
#endif
}
half3 EnvironmentBRDF(BRDFData brdfData, half3 indirectDiffuse, half3 indirectSpecular, half roughness2, half fresnelTerm)
{
half3 c = indirectDiffuse * brdfData.diffuse;
float surfaceReduction = 1.0 / (roughness2 + 1.0);
c += surfaceReduction * indirectSpecular * lerp(brdfData.specular, brdfData.grazingTerm, fresnelTerm);
return c;
}
// Based on Minimalist CookTorrance BRDF
// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255
//
// * NDF [Modified] GGX
// * Modified Kelemen and Szirmay-​Kalos for Visibility term
// * Fresnel approximated with 1/LdotH
half3 DirectBDRF(BRDFData brdfData, half roughness2, half3 normal, half3 lightDirection, half3 viewDir)
{
#ifndef _SPECULARHIGHLIGHTS_OFF
half3 halfDir = SafeNormalize(lightDirection + viewDir);
half NoH = saturate(dot(normal, halfDir));
half LoH = saturate(dot(lightDirection, halfDir));
// GGX Distribution multiplied by combined approximation of Visibility and Fresnel
// See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course
// https://community.arm.com/events/1155
half d = NoH * NoH * (roughness2 - 1.h) + 1.00001h;
half LoH2 = LoH * LoH;
half specularTerm = roughness2 / ((d * d) * max(0.1h, LoH2) * (brdfData.roughness + 0.5h) * 4);
// on mobiles (where half actually means something) denominator have risk of overflow
// clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
// sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
#if defined (SHADER_API_MOBILE)
specularTerm = specularTerm - 1e-4h;
#endif
#if defined (SHADER_API_MOBILE)
specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
#endif
half3 color = specularTerm * brdfData.specular + brdfData.diffuse;
return color;
#else
return brdfData.diffuse;
#endif
}
///////////////////////////////////////////////////////////////////////////////
// Attenuation Functions /
///////////////////////////////////////////////////////////////////////////////
half CookieAttenuation(float3 worldPos)
{
#ifdef _MAIN_LIGHT_COOKIE
#ifdef _MAIN_DIRECTIONAL_LIGHT
float2 cookieUV = mul(_WorldToLight, float4(worldPos, 1.0)).xy;
return SAMPLE_TEXTURE2D(_MainLightCookie, sampler_MainLightCookie, cookieUV).a;
#elif defined(_MAIN_SPOT_LIGHT)
float4 projPos = mul(_WorldToLight, float4(worldPos, 1.0));
float2 cookieUV = projPos.xy / projPos.w + 0.5;
return SAMPLE_TEXTURE2D(_MainLightCookie, sampler_MainLightCookie, cookieUV).a;
#endif // POINT LIGHT cookie not supported
#endif
return 1;
}
// Matches Unity Vanila attenuation
// Attenuation smoothly decreases to light range.
half DistanceAttenuation(half distanceSqr, half4 distanceAttenuation)
{
// We use a shared distance attenuation for additional directional and puctual lights
// for directional lights attenuation will be 1
half quadFalloff = distanceAttenuation.x;
half denom = distanceSqr * quadFalloff + 1.0;
half lightAtten = 1.0 / denom;
// We need to smoothly fade attenuation to light range. We start fading linearly at 80% of light range
// Therefore:
// fadeDistance = (0.8 * 0.8 * lightRangeSq)
// smoothFactor = (lightRangeSqr - distanceSqr) / (lightRangeSqr - fadeDistance)
// We can rewrite that to fit a MAD by doing
// distanceSqr * (1.0 / (fadeDistanceSqr - lightRangeSqr)) + (-lightRangeSqr / (fadeDistanceSqr - lightRangeSqr)
// distanceSqr * distanceAttenuation.y + distanceAttenuation.z
half smoothFactor = saturate(distanceSqr * distanceAttenuation.y + distanceAttenuation.z);
return lightAtten * smoothFactor;
}
half SpotAttenuation(half3 spotDirection, half3 lightDirection, half4 spotAttenuation)
{
// Spot Attenuation with a linear falloff can be defined as
// (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle)
// This can be rewritten as
// invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle)
// SdotL * invAngleRange + (-cosOuterAngle * invAngleRange)
// SdotL * spotAttenuation.x + spotAttenuation.y
// If we precompute the terms in a MAD instruction
half SdotL = dot(spotDirection, lightDirection);
return saturate(SdotL * spotAttenuation.x + spotAttenuation.y);
}
inline half GetLightDirectionAndRealtimeAttenuation(LightInput lightInput, half3 normal, float3 worldPos, out half3 lightDirection)
{
float3 posToLightVec = lightInput.position.xyz - worldPos * lightInput.position.w;
float distanceSqr = max(dot(posToLightVec, posToLightVec), 0.001);
// normalized light dir
lightDirection = half3(posToLightVec * rsqrt(distanceSqr));
half lightAtten = DistanceAttenuation(distanceSqr, lightInput.distanceAttenuation);
lightAtten *= SpotAttenuation(lightInput.spotDirection.xyz, lightDirection, lightInput.spotAttenuation);
return lightAtten;
}
inline half GetMainLightDirectionAndRealtimeAttenuation(LightInput lightInput, half3 normalWS, float3 positionWS, out half3 lightDirection)
{
#ifdef _MAIN_DIRECTIONAL_LIGHT
// Light pos holds normalized light dir
lightDirection = lightInput.position.xyz;
half attenuation = 1.0;
#else
half attenuation = GetLightDirectionAndRealtimeAttenuation(lightInput, normalWS, positionWS, lightDirection);
#endif
// Cookies and shadows are only computed for main light
attenuation *= CookieAttenuation(positionWS);
attenuation *= LIGHTWEIGHT_SHADOW_ATTENUATION(positionWS, normalWS, lightDirection);
return attenuation;
}
///////////////////////////////////////////////////////////////////////////////
// Lighting Functions //
///////////////////////////////////////////////////////////////////////////////
half3 LightingLambert(half3 lightColor, half3 lightDir, half3 normal)
{
half NdotL = saturate(dot(normal, lightDir));
return lightColor * NdotL;
}
half3 LightingSpecular(half3 lightColor, half3 lightDir, half3 normal, half3 viewDir, half4 specularGloss, half shininess)
{
half3 halfVec = SafeNormalize(lightDir + viewDir);
half NdotH = saturate(dot(normal, halfVec));
half3 specularReflection = specularGloss.rgb * pow(NdotH, shininess) * specularGloss.a;
return lightColor * specularReflection;
}
half3 VertexLighting(float3 positionWS, half3 normalWS)
{
half3 vertexLightColor = half3(0.0, 0.0, 0.0);
#if defined(_VERTEX_LIGHTS)
int vertexLightStart = _AdditionalLightCount.x;
int vertexLightEnd = min(_AdditionalLightCount.y, unity_LightIndicesOffsetAndCount.y);
for (int lightIter = vertexLightStart; lightIter < vertexLightEnd; ++lightIter)
{
LightInput light = GetLight(lightIter);
half3 lightDirection;
half atten = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection);
half3 lightColor = light.color * atten;
vertexLightColor += LightingLambert(lightColor, lightDirection, normalWS);
}
#endif
return vertexLightColor;
}
///////////////////////////////////////////////////////////////////////////////
// Fragment Functions //
// Used by ShaderGraph and others builtin renderers //
///////////////////////////////////////////////////////////////////////////////
half4 LightweightFragmentPBR(float3 positionWS, half3 normalWS, half3 viewDirectionWS,
half3 bakedGI, half3 vertexLighting, half3 albedo, half metallic, half3 specular,
half smoothness, half occlusion, half3 emission, half alpha)
{
half4 bakedOcclusion = half4(0, 0, 0, 0);
BRDFData brdfData;
InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData);
half3 lightDirectionWS;
LightInput mainLight = GetMainLight();
// No distance fade.
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirectionWS);
half NdotL = saturate(dot(normalWS, lightDirectionWS));
half3 radiance = mainLight.color * NdotL;
half3 indirectDiffuse = DiffuseGI(bakedGI, radiance, realtimeMainLightAtten, occlusion);
half3 indirectSpecular = GlossyEnvironmentReflection(viewDirectionWS, normalWS, brdfData.perceptualRoughness, occlusion);
half roughness2 = brdfData.roughness * brdfData.roughness;
half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
half3 color = EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, roughness2, fresnelTerm);
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation);
radiance *= mainLightAtten;
color += DirectBDRF(brdfData, roughness2, normalWS, lightDirectionWS, viewDirectionWS) * radiance;
color += vertexLighting * brdfData.diffuse;
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = GetPixelLightCount();
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter)
{
LightInput light = GetLight(lightIter);
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirectionWS);
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation);
half NdotL = saturate(dot(normalWS, lightDirectionWS));
half3 radiance = light.color * (lightAttenuation * NdotL);
color += DirectBDRF(brdfData, roughness2, normalWS, lightDirectionWS, viewDirectionWS) * radiance;
}
#endif
color += emission;
return half4(color, alpha);
}
half4 LightweightFragmentLambert(float3 positionWS, half3 normalWS, half3 viewDirectionWS,
half fogFactor, half3 diffuseGI, half3 diffuse, half3 emission, half alpha)
{
half4 bakedOcclusion = half4(0, 0, 0, 0);
half3 lightDirection;
LightInput mainLight = GetMainLight();
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirection);
half3 NdotL = saturate(dot(normalWS, lightDirection));
half3 lambert = mainLight.color * NdotL;
half3 indirectDiffuse = DiffuseGI(diffuseGI, lambert, realtimeMainLightAtten, 1.0);
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation);
half3 diffuseColor = lambert * mainLightAtten + indirectDiffuse;
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = GetPixelLightCount();
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter)
{
LightInput light = GetLight(lightIter);
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection);
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation);
half3 attenuatedLightColor = light.color * lightAttenuation;
diffuseColor += LightingLambert(attenuatedLightColor, lightDirection, normalWS);
}
#endif
half3 finalColor = diffuseColor * diffuse + emission;
// Computes Fog Factor per vextex
ApplyFog(finalColor, fogFactor);
return half4(finalColor, alpha);
}
half4 LightweightFragmentBlinnPhong(float3 positionWS, half3 normalWS, half3 viewDirectionWS,
half fogFactor, half3 diffuseGI, half3 diffuse, half4 specularGloss, half shininess, half3 emission, half alpha)
{
half4 bakedOcclusion = half4(0, 0, 0, 0);
half3 lightDirection;
LightInput mainLight = GetMainLight();
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirection);
half3 NdotL = saturate(dot(normalWS, lightDirection));
half3 lambert = mainLight.color * NdotL;
half3 indirectDiffuse = DiffuseGI(diffuseGI, lambert, realtimeMainLightAtten, 1.0);
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation);
half3 diffuseColor = lambert * mainLightAtten + indirectDiffuse;
half3 specularColor = LightingSpecular(mainLight.color * mainLightAtten, lightDirection, normalWS, viewDirectionWS, specularGloss, shininess);
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = GetPixelLightCount();
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter)
{
LightInput light = GetLight(lightIter);
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection);
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation);
half3 attenuatedLightColor = light.color * lightAttenuation;
diffuseColor += LightingLambert(attenuatedLightColor, lightDirection, normalWS);
specularColor += LightingSpecular(attenuatedLightColor, lightDirection, normalWS, viewDirectionWS, specularGloss, shininess);
}
#endif
half3 finalColor = diffuseColor * diffuse + emission;
finalColor += specularColor;
// Computes Fog Factor per vextex
ApplyFog(finalColor, fogFactor);
return half4(finalColor, alpha);
}
#endif

67
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightInput.hlsl


#ifndef LIGHTWEIGHT_INPUT_INCLUDED
#define LIGHTWEIGHT_INPUT_INCLUDED
#define MAX_VISIBLE_LIGHTS 16
struct LightInput
{
float4 pos;
half3 color;
half4 distanceAttenuation;
half4 spotDirection;
half4 spotAttenuation;
};
// Main light initialized without indexing
#define INITIALIZE_MAIN_LIGHT(light) \
light.pos = _MainLightPosition; \
light.color = _MainLightColor.rgb; \
light.distanceAttenuation = _MainLightDistanceAttenuation; \
light.spotDirection = _MainLightSpotDir; \
light.spotAttenuation = _MainLightSpotAttenuation
// Indexing might have a performance hit for old mobile hardware
#define INITIALIZE_LIGHT(light, i) \
half4 indices = (i < 4) ? unity_4LightIndices0 : unity_4LightIndices1; \
int index = (i < 4) ? i : i - 4; \
int lightIndex = indices[index]; \
light.pos = _AdditionalLightPosition[lightIndex]; \
light.color = _AdditionalLightColor[lightIndex].rgb; \
light.distanceAttenuation = _AdditionalLightDistanceAttenuation[lightIndex]; \
light.spotDirection = _AdditionalLightSpotDir[lightIndex]; \
light.spotAttenuation = _AdditionalLightSpotAttenuation[lightIndex]
///////////////////////////////////////////////////////////////////////////////
// Constant Buffers //
///////////////////////////////////////////////////////////////////////////////
CBUFFER_START(_PerFrame)
half4 _GlossyEnvironmentColor;
half4 _SubtractiveShadowColor;
CBUFFER_END
CBUFFER_START(_PerCamera)
float4 _MainLightPosition;
half4 _MainLightColor;
half4 _MainLightDistanceAttenuation;
half4 _MainLightSpotDir;
half4 _MainLightSpotAttenuation;
float4x4 _WorldToLight;
half4 _AdditionalLightCount;
float4 _AdditionalLightPosition[MAX_VISIBLE_LIGHTS];
half4 _AdditionalLightColor[MAX_VISIBLE_LIGHTS];
half4 _AdditionalLightDistanceAttenuation[MAX_VISIBLE_LIGHTS];
half4 _AdditionalLightSpotDir[MAX_VISIBLE_LIGHTS];
half4 _AdditionalLightSpotAttenuation[MAX_VISIBLE_LIGHTS];
CBUFFER_END
// These are set internally by the engine upon request by RendererConfiguration.
// Check GetRendererSettings in LightweightPipeline.cs
CBUFFER_START(_PerObject)
half4 unity_LightIndicesOffsetAndCount;
half4 unity_4LightIndices0;
half4 unity_4LightIndices1;
CBUFFER_END
#endif

217
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCore.hlsl


#ifndef LIGHTWEIGHT_PIPELINE_CORE_INCLUDED
#define LIGHTWEIGHT_PIPELINE_CORE_INCLUDED
#include "ShaderLibrary\Common.hlsl"
#include "ShaderLibrary\EntityLighting.hlsl"
#include "ShaderVariables\LightweightShaderVariables.hlsl"
#ifdef _NORMALMAP
#define OUTPUT_NORMAL(IN, OUT) OutputTangentToWorld(IN.tangent, IN.normal, OUT.tangent, OUT.binormal, OUT.normal)
#else
#define OUTPUT_NORMAL(IN, OUT) OUT.normal = TransformObjectToWorldNormal(IN.normal)
#endif
#ifdef LIGHTMAP_ON
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT) OUT.xy = lightmapUV.xy * lightmapScaleOffset.xy + lightmapScaleOffset.zw;
#define OUTPUT_SH(normalWS, OUT)
#else
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT)
#define OUTPUT_SH(normalWS, OUT) OUT.xyz = EvaluateSHPerVertex(normalWS)
#endif
#if defined(UNITY_REVERSED_Z)
#if UNITY_REVERSED_Z == 1
//D3d with reversed Z => z clip range is [near, 0] -> remapping to [0, far]
//max is required to protect ourselves from near plane not being correct/meaningfull in case of oblique matrices.
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(((1.0-(coord)/_ProjectionParams.y)*_ProjectionParams.z),0)
#else
//GL with reversed z => z clip range is [near, -far] -> should remap in theory but dont do it in practice to save some perf (range is close enough)
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(-(coord), 0)
#endif
#elif UNITY_UV_STARTS_AT_TOP
//D3d without reversed z => z clip range is [0, far] -> nothing to do
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
#else
//Opengl => z clip range is [-near, far] -> should remap in theory but dont do it in practice to save some perf (range is close enough)
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
#endif
half Pow4(half x)
{
return x * x * x * x;
}
half LerpOneTo(half b, half t)
{
half oneMinusT = 1 - t;
return oneMinusT + b * t;
}
void AlphaDiscard(half alpha, half cutoff)
{
#ifdef _ALPHATEST_ON
clip(alpha - cutoff);
#endif
}
half3 SafeNormalize(half3 inVec)
{
half dp3 = max(1.e-4h, dot(inVec, inVec));
return inVec * rsqrt(dp3);
}
// Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1)
// Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5
half3 UnpackNormalmapRGorAG(half4 packedNormal, half bumpScale)
{
// This do the trick
packedNormal.x *= packedNormal.w;
half3 normal;
normal.xy = packedNormal.xy * 2 - 1;
normal.xy *= bumpScale;
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
return normal;
}
half3 UnpackNormalRGB(half4 packedNormal, half bumpScale)
{
half3 normal = packedNormal.xyz * 2 - 1;
normal.xy *= bumpScale;
return normal;
}
half3 UnpackNormal(half4 packedNormal)
{
// Compiler will optimize the scale away
#if defined(UNITY_NO_DXT5nm)
return UnpackNormalRGB(packedNormal, 1.0);
#else
return UnpackNormalmapRGorAG(packedNormal, 1.0);
#endif
}
half3 UnpackNormalScale(half4 packedNormal, half bumpScale)
{
#if defined(UNITY_NO_DXT5nm)
return UnpackNormalRGB(packedNormal, bumpScale);
#else
return UnpackNormalmapRGorAG(packedNormal, bumpScale);
#endif
}
half3 SampleSH(half3 normalWS)
{
// LPPV is not supported in Ligthweight Pipeline
float4 SHCoefficients[7];
SHCoefficients[0] = unity_SHAr;
SHCoefficients[1] = unity_SHAg;
SHCoefficients[2] = unity_SHAb;
SHCoefficients[3] = unity_SHBr;
SHCoefficients[4] = unity_SHBg;
SHCoefficients[5] = unity_SHBb;
SHCoefficients[6] = unity_SHC;
return SampleSH9(SHCoefficients, normalWS);
}
half3 EvaluateSHPerVertex(half3 normalWS)
{
#if defined(EVALUATE_SH_VERTEX)
return max(half3(0, 0, 0), SampleSH(normalWS));
#elif defined(EVALUATE_SH_MIXED)
// no max since this is only L2 contribution
return SHEvalLinearL2(normalWS, unity_SHBr, unity_SHBg, unity_SHBb, unity_SHC);
#endif
// Fully per-pixel. Nothing to compute.
return half3(0.0, 0.0, 0.0);
}
half3 EvaluateSHPerPixel(half3 L2Term, half3 normalWS)
{
#ifdef EVALUATE_SH_MIXED
half3 L0L1Term = SHEvalLinearL0L1(normalWS, unity_SHAr, unity_SHAg, unity_SHAb);
return max(half3(0, 0, 0), L2Term + L0L1Term);
#endif
// Default: Evaluate SH fully per-pixel
return max(half3(0, 0, 0), SampleSH(normalWS));
}
half3 SampleLightmap(float2 lightmapUV, half3 normalWS)
{
// Only baked GI is sample as dynamic GI is not supported in Lightweight
#ifdef UNITY_LIGHTMAP_FULL_HDR
bool encodedLightmap = false;
#else
bool encodedLightmap = true;
#endif
// The shader library sample lightmap functions transform the lightmap uv coords to apply bias and scale.
// However, lightweight pipeline already transformed those coords in vertex. We pass half4(1, 1, 0, 0) and
// the compiler will optimize the transform away.
half4 transformCoords = half4(1, 1, 0, 0);
#ifdef DIRLIGHTMAP_COMBINED
return SampleDirectionalLightmap(TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap),
TEXTURE2D_PARAM(unity_LightmapInd, samplerunity_Lightmap),
lightmapUV, transformCoords, normalWS, encodedLightmap);
#else
return SampleSingleLightmap(TEXTURE2D_PARAM(unity_Lightmap, samplerunity_Lightmap), lightmapUV, transformCoords, encodedLightmap);
#endif
}
half3 SampleGI(float4 sampleData, half3 normalWS)
{
#ifdef LIGHTMAP_ON
return SampleLightmap(sampleData.xy, normalWS);
#endif // LIGHTMAP_ON
// If lightmap is not enabled we sample GI from SH
return EvaluateSHPerPixel(sampleData.xyz, normalWS);
}
void OutputTangentToWorld(half4 vertexTangent, half3 vertexNormal, out half3 tangentWS, out half3 binormalWS, out half3 normalWS)
{
half sign = vertexTangent.w * GetOddNegativeScale();
normalWS = TransformObjectToWorldNormal(vertexNormal);
tangentWS = normalize(mul((half3x3)unity_ObjectToWorld, vertexTangent.xyz));
binormalWS = cross(normalWS, tangentWS) * sign;
}
half3 TangentToWorldNormal(half3 normalTangent, half3 tangent, half3 binormal, half3 normal)
{
half3x3 tangentToWorld = half3x3(tangent, binormal, normal);
return normalize(mul(normalTangent, tangentToWorld));
}
float ComputeFogFactor(float z)
{
float clipZ_01 = UNITY_Z_0_FAR_FROM_CLIPSPACE(z);
#if defined(FOG_LINEAR)
// factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
float fogFactor = saturate(clipZ_01 * unity_FogParams.z + unity_FogParams.w);
return half(fogFactor);
#elif defined(FOG_EXP)
// factor = exp(-density*z)
float unityFogFactor = unity_FogParams.y * clipZ_01;
return half(saturate(exp2(-unityFogFactor)));
#elif defined(FOG_EXP2)
// factor = exp(-(density*z)^2)
float unityFogFactor = unity_FogParams.x * clipZ_01;
return half(saturate(exp2(-unityFogFactor*unityFogFactor)));
#else
return 0.0h;
#endif
}
void ApplyFog(inout half3 color, half fogFactor)
{
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
color = lerp(unity_FogColor, color, fogFactor);
#endif
}
#endif

426
ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightLighting.hlsl


#ifndef LIGHTWEIGHT_LIGHTING_INCLUDED
#define LIGHTWEIGHT_LIGHTING_INCLUDED
#include "ShaderLibrary\Common.hlsl"
#include "ShaderLibrary\ImageBasedLighting.hlsl"
#include "LightweightCore.hlsl"
#include "LightweightShadows.hlsl"
#define kDieletricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) // standard dielectric reflectivity coef at incident angle (= 4%)
#ifdef NO_ADDITIONAL_LIGHTS
#undef _ADDITIONAL_LIGHTS
#endif
// If lightmap is not defined than we evaluate GI (ambient + probes) from SH
// We might do it fully or partially in vertex to save shader ALU
#if !defined(LIGHTMAP_ON)
#if SHADER_TARGET < 30
// Evaluates SH fully in vertex
#define EVALUATE_SH_VERTEX
#else
// Evaluates L2 SH in vertex and L0L1 in pixel
#define EVALUATE_SH_MIXED
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// BRDF Functions //
///////////////////////////////////////////////////////////////////////////////
struct BRDFData
{
half3 diffuse;
half3 specular;
half perceptualRoughness;
half roughness;
half grazingTerm;
};
half ReflectivitySpecular(half3 specular)
{
#if (SHADER_TARGET < 30)
// SM2.0: instruction count limitation
return specular.r; // Red channel - because most metals are either monocrhome or with redish/yellowish tint
#else
return max(max(specular.r, specular.g), specular.b);
#endif
}
half OneMinusReflectivityMetallic(half metallic)
{
// We'll need oneMinusReflectivity, so
// 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
// store (1-dielectricSpec) in kDieletricSpec.a, then
// 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
// = alpha - metallic * alpha
half oneMinusDielectricSpec = kDieletricSpec.a;
return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
}
inline void InitializeBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, half alpha, out BRDFData outBRDFData)
{
#ifdef _SPECULAR_SETUP
half reflectivity = ReflectivitySpecular(specular);
half oneMinusReflectivity = 1.0 - reflectivity;
outBRDFData.diffuse = albedo * (half3(1.0h, 1.0h, 1.0h) - specular);
outBRDFData.specular = specular;
#else
half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic);
half reflectivity = 1.0 - oneMinusReflectivity;
outBRDFData.diffuse = albedo * oneMinusReflectivity;
outBRDFData.specular = lerp(kDieletricSpec.rgb, albedo, metallic);
#endif
outBRDFData.grazingTerm = saturate(smoothness + reflectivity);
outBRDFData.perceptualRoughness = 1.0h - smoothness;
outBRDFData.roughness = outBRDFData.perceptualRoughness * outBRDFData.perceptualRoughness;
#ifdef _ALPHAPREMULTIPLY_ON
outBRDFData.diffuse *= alpha;
alpha = alpha * oneMinusReflectivity + reflectivity;
#endif
}
half3 LightweightEnvironmentBRDF(BRDFData brdfData, half3 indirectDiffuse, half3 indirectSpecular, half roughness2, half fresnelTerm)
{
half3 c = indirectDiffuse * brdfData.diffuse;
float surfaceReduction = 1.0 / (roughness2 + 1.0);
c += surfaceReduction * indirectSpecular * lerp(brdfData.specular, brdfData.grazingTerm, fresnelTerm);
return c;
}
// Based on Minimalist CookTorrance BRDF
// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255
//
// * NDF [Modified] GGX
// * Modified Kelemen and Szirmay-​Kalos for Visibility term
// * Fresnel approximated with 1/LdotH
half3 LightweightDirectBDRF(BRDFData brdfData, half roughness2, half3 normal, half3 lightDirection, half3 viewDir)
{
#ifndef _SPECULARHIGHLIGHTS_OFF
half3 halfDir = SafeNormalize(lightDirection + viewDir);
half NoH = saturate(dot(normal, halfDir));
half LoH = saturate(dot(lightDirection, halfDir));
// GGX Distribution multiplied by combined approximation of Visibility and Fresnel
// See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course
// https://community.arm.com/events/1155
half d = NoH * NoH * (roughness2 - 1.h) + 1.00001h;
half LoH2 = LoH * LoH;
half specularTerm = roughness2 / ((d * d) * max(0.1h, LoH2) * (brdfData.roughness + 0.5h) * 4);
// on mobiles (where half actually means something) denominator have risk of overflow
// clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
// sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
#if defined (SHADER_API_MOBILE)
specularTerm = specularTerm - 1e-4h;
#endif
#if defined (SHADER_API_MOBILE)
specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
#endif
half3 color = specularTerm * brdfData.specular + brdfData.diffuse;
return color;
#else
return brdfData.diffuse;
#endif
}
///////////////////////////////////////////////////////////////////////////////
// Attenuation Functions /
///////////////////////////////////////////////////////////////////////////////
half CookieAttenuation(float3 worldPos)
{
#ifdef _MAIN_LIGHT_COOKIE
#ifdef _MAIN_DIRECTIONAL_LIGHT
float2 cookieUV = mul(_WorldToLight, float4(worldPos, 1.0)).xy;
return SAMPLE_TEXTURE2D(_MainLightCookie, sampler_MainLightCookie, cookieUV).a;
#elif defined(_MAIN_SPOT_LIGHT)
float4 projPos = mul(_WorldToLight, float4(worldPos, 1.0));
float2 cookieUV = projPos.xy / projPos.w + 0.5;
return SAMPLE_TEXTURE2D(_MainLightCookie, sampler_MainLightCookie, cookieUV).a;
#endif // POINT LIGHT cookie not supported
#endif
return 1;
}
// Matches Unity Vanila attenuation
// Attenuation smoothly decreases to light range.
half DistanceAttenuation(half distanceSqr, half4 distanceAttenuation)
{
// We use a shared distance attenuation for additional directional and puctual lights
// for directional lights attenuation will be 1
half quadFalloff = distanceAttenuation.x;
half denom = distanceSqr * quadFalloff + 1.0;
half lightAtten = 1.0 / denom;
// We need to smoothly fade attenuation to light range. We start fading linearly at 80% of light range
// Therefore:
// fadeDistance = (0.8 * 0.8 * lightRangeSq)
// smoothFactor = (lightRangeSqr - distanceSqr) / (lightRangeSqr - fadeDistance)
// We can rewrite that to fit a MAD by doing
// distanceSqr * (1.0 / (fadeDistanceSqr - lightRangeSqr)) + (-lightRangeSqr / (fadeDistanceSqr - lightRangeSqr)
// distanceSqr * distanceAttenuation.y + distanceAttenuation.z
half smoothFactor = saturate(distanceSqr * distanceAttenuation.y + distanceAttenuation.z);
return lightAtten * smoothFactor;
}
half SpotAttenuation(half3 spotDirection, half3 lightDirection, half4 spotAttenuation)
{
// Spot Attenuation with a linear falloff can be defined as
// (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle)
// This can be rewritten as
// invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle)
// SdotL * invAngleRange + (-cosOuterAngle * invAngleRange)
// SdotL * spotAttenuation.x + spotAttenuation.y
// If we precompute the terms in a MAD instruction
half SdotL = dot(spotDirection, lightDirection);
return saturate(SdotL * spotAttenuation.x + spotAttenuation.y);
}
inline half GetLightDirectionAndRealtimeAttenuation(LightInput lightInput, half3 normal, float3 worldPos, out half3 lightDirection)
{
float3 posToLightVec = lightInput.pos.xyz - worldPos * lightInput.pos.w;
float distanceSqr = max(dot(posToLightVec, posToLightVec), 0.001);
// normalized light dir
lightDirection = half3(posToLightVec * rsqrt(distanceSqr));
half lightAtten = DistanceAttenuation(distanceSqr, lightInput.distanceAttenuation);
lightAtten *= SpotAttenuation(lightInput.spotDirection.xyz, lightDirection, lightInput.spotAttenuation);
return lightAtten;
}
inline half GetMainLightDirectionAndRealtimeAttenuation(LightInput lightInput, half3 normalWS, float3 positionWS, out half3 lightDirection)
{
#ifdef _MAIN_DIRECTIONAL_LIGHT
// Light pos holds normalized light dir
lightDirection = lightInput.pos.xyz;
half attenuation = 1.0;
#else
half attenuation = GetLightDirectionAndRealtimeAttenuation(lightInput, normalWS, positionWS, lightDirection);
#endif
// Cookies and shadows are only computed for main light
attenuation *= CookieAttenuation(positionWS);
attenuation *= LIGHTWEIGHT_SHADOW_ATTENUATION(positionWS, normalWS, lightDirection);
return attenuation;
}
///////////////////////////////////////////////////////////////////////////////
// Lighting Functions //
///////////////////////////////////////////////////////////////////////////////
half3 LightingLambert(half3 lightColor, half3 lightDir, half3 normal)
{
half NdotL = saturate(dot(normal, lightDir));
return lightColor * NdotL;
}
half3 LightingSpecular(half3 lightColor, half3 lightDir, half3 normal, half3 viewDir, half4 specularGloss, half shininess)
{
half3 halfVec = SafeNormalize(lightDir + viewDir);
half NdotH = saturate(dot(normal, halfVec));
half3 specularReflection = specularGloss.rgb * pow(NdotH, shininess) * specularGloss.a;
return lightColor * specularReflection;
}
half3 VertexLighting(float3 positionWS, half3 normalWS)
{
half3 vertexLightColor = half3(0.0, 0.0, 0.0);
#if defined(_VERTEX_LIGHTS)
int vertexLightStart = _AdditionalLightCount.x;
int vertexLightEnd = min(_AdditionalLightCount.y, unity_LightIndicesOffsetAndCount.y);
for (int lightIter = vertexLightStart; lightIter < vertexLightEnd; ++lightIter)
{
LightInput light;
INITIALIZE_LIGHT(light, lightIter);
half3 lightDirection;
half atten = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection);
half3 lightColor = light.color * atten;
vertexLightColor += LightingLambert(lightColor, lightDirection, normalWS);
}
#endif
return vertexLightColor;
}
///////////////////////////////////////////////////////////////////////////////
// Global Illumination //
///////////////////////////////////////////////////////////////////////////////
half3 DiffuseGI(half3 indirectDiffuse, half3 lambert, half mainLightRealtimeAttenuation, half occlusion)
{
// If shadows and mixed subtractive mode is enabled we need to remove direct
// light contribution from lightmap from occluded pixels so we can have dynamic objects
// casting shadows onto static correctly.
#if defined(_MIXED_LIGHTING_SUBTRACTIVE) && defined(LIGHTMAP_ON) && defined(_SHADOWS)
indirectDiffuse = SubtractDirectMainLightFromLightmap(indirectDiffuse, mainLightRealtimeAttenuation, lambert);
#endif
return indirectDiffuse * occlusion;
}
half3 GlossyEnvironmentReflection(half3 viewDirectionWS, half3 normalWS, half perceptualRoughness, half occlusion)
{
half3 reflectVector = reflect(-viewDirectionWS, normalWS);
#if !defined(_GLOSSYREFLECTIONS_OFF)
half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
half4 encodedIrradiance = SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip);
#if !defined(UNITY_USE_NATIVE_HDR)
half3 irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
#else
half3 irradiance = encodedIrradiance.rbg;
#endif
return irradiance * occlusion;
#endif
return _GlossyEnvironmentColor.rgb * occlusion;
}
///////////////////////////////////////////////////////////////////////////////
// Fragment Functions //
// Used by ShaderGraph and others builtin renderers //
///////////////////////////////////////////////////////////////////////////////
half4 LightweightFragmentPBR(float3 positionWS, half3 normalWS, half3 viewDirectionWS,
half3 bakedGI, half3 vertexLighting, half3 albedo, half metallic, half3 specular,
half smoothness, half occlusion, half3 emission, half alpha)
{
half4 bakedOcclusion = half4(0, 0, 0, 0);
BRDFData brdfData;
InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData);
half3 lightDirectionWS;
LightInput mainLight;
INITIALIZE_MAIN_LIGHT(mainLight);
// No distance fade.
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirectionWS);
half NdotL = saturate(dot(normalWS, lightDirectionWS));
half3 radiance = mainLight.color * NdotL;
half3 indirectDiffuse = DiffuseGI(bakedGI, radiance, realtimeMainLightAtten, occlusion);
half3 indirectSpecular = GlossyEnvironmentReflection(viewDirectionWS, normalWS, brdfData.perceptualRoughness, occlusion);
half roughness2 = brdfData.roughness * brdfData.roughness;
half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
half3 color = LightweightEnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, roughness2, fresnelTerm);
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation);
radiance *= mainLightAtten;
color += LightweightDirectBDRF(brdfData, roughness2, normalWS, lightDirectionWS, viewDirectionWS) * radiance;
color += vertexLighting * brdfData.diffuse;
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y);
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter)
{
LightInput light;
INITIALIZE_LIGHT(light, lightIter);
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirectionWS);
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation);
half NdotL = saturate(dot(normalWS, lightDirectionWS));
half3 radiance = light.color * (lightAttenuation * NdotL);
color += LightweightDirectBDRF(brdfData, roughness2, normalWS, lightDirectionWS, viewDirectionWS) * radiance;
}
#endif
color += emission;
return half4(color, alpha);
}
half4 LightweightFragmentLambert(float3 positionWS, half3 normalWS, half3 viewDirectionWS,
half fogFactor, half3 diffuseGI, half3 diffuse, half3 emission, half alpha)
{
half4 bakedOcclusion = half4(0, 0, 0, 0);
half3 lightDirection;
LightInput mainLight;
INITIALIZE_MAIN_LIGHT(mainLight);
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirection);
half3 NdotL = saturate(dot(normalWS, lightDirection));
half3 lambert = mainLight.color * NdotL;
half3 indirectDiffuse = DiffuseGI(diffuseGI, lambert, realtimeMainLightAtten, 1.0);
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation);
half3 diffuseColor = lambert * mainLightAtten + indirectDiffuse;
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y);
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter)
{
LightInput light;
INITIALIZE_LIGHT(light, lightIter);
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection);
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation);
half3 attenuatedLightColor = light.color * lightAttenuation;
diffuseColor += LightingLambert(attenuatedLightColor, lightDirection, normalWS);
}
#endif
half3 finalColor = diffuseColor * diffuse + emission;
// Computes Fog Factor per vextex
ApplyFog(finalColor, fogFactor);
return half4(finalColor, alpha);
}
half4 LightweightFragmentBlinnPhong(float3 positionWS, half3 normalWS, half3 viewDirectionWS,
half fogFactor, half3 diffuseGI, half3 diffuse, half4 specularGloss, half shininess, half3 emission, half alpha)
{
half4 bakedOcclusion = half4(0, 0, 0, 0);
half3 lightDirection;
LightInput mainLight;
INITIALIZE_MAIN_LIGHT(mainLight);
half realtimeMainLightAtten = GetMainLightDirectionAndRealtimeAttenuation(mainLight, normalWS, positionWS, lightDirection);
half3 NdotL = saturate(dot(normalWS, lightDirection));
half3 lambert = mainLight.color * NdotL;
half3 indirectDiffuse = DiffuseGI(diffuseGI, lambert, realtimeMainLightAtten, 1.0);
half mainLightAtten = MixRealtimeAndBakedOcclusion(realtimeMainLightAtten, bakedOcclusion, mainLight.distanceAttenuation);
half3 diffuseColor = lambert * mainLightAtten + indirectDiffuse;
half3 specularColor = LightingSpecular(mainLight.color * mainLightAtten, lightDirection, normalWS, viewDirectionWS, specularGloss, shininess);
#ifdef _ADDITIONAL_LIGHTS
int pixelLightCount = min(_AdditionalLightCount.x, unity_LightIndicesOffsetAndCount.y);
for (int lightIter = 0; lightIter < pixelLightCount; ++lightIter)
{
LightInput light;
INITIALIZE_LIGHT(light, lightIter);
half lightAttenuation = GetLightDirectionAndRealtimeAttenuation(light, normalWS, positionWS, lightDirection);
lightAttenuation = MixRealtimeAndBakedOcclusion(lightAttenuation, bakedOcclusion, light.distanceAttenuation);
half3 attenuatedLightColor = light.color * lightAttenuation;
diffuseColor += LightingLambert(attenuatedLightColor, lightDirection, normalWS);
specularColor += LightingSpecular(attenuatedLightColor, lightDirection, normalWS, viewDirectionWS, specularGloss, shininess);
}
#endif
half3 finalColor = diffuseColor * diffuse + emission;
finalColor += specularColor;
// Computes Fog Factor per vextex
ApplyFog(finalColor, fogFactor);
return half4(finalColor, alpha);
}
#endif

/ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables.meta → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary.meta

/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightParticle.hlsl → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Particles.hlsl

/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightParticle.hlsl.meta → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Particles.hlsl.meta

/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightCore.hlsl.meta → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Core.hlsl.meta

/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightInput.hlsl.meta → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Input.hlsl.meta

/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightLighting.hlsl.meta → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Lighting.hlsl.meta

/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShadows.hlsl.meta → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Shadows.hlsl.meta

/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightSurfaceInput.hlsl.meta → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputSurface.hlsl.meta

/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShadows.hlsl → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/Shadows.hlsl

/ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightSurfaceInput.hlsl → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputSurface.hlsl

/ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables/LightweightShaderVariables.hlsl.meta → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputBuiltin.hlsl.meta

/ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables/LightweightShaderVariablesFunctions.hlsl → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/CoreFunctions.hlsl

/ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables/LightweightShaderVariablesFunctions.hlsl.meta → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/CoreFunctions.hlsl.meta

/ScriptableRenderPipeline/LightweightPipeline/Shaders/ShaderVariables/LightweightShaderVariables.hlsl → /ScriptableRenderPipeline/LightweightPipeline/Shaders/LightweightShaderLibrary/InputBuiltin.hlsl

正在加载...
取消
保存