566 lines
22 KiB
HLSL
566 lines
22 KiB
HLSL
#ifndef BADDOG_AREA_LIGHTING_INCLUDED
|
|
#define BADDOG_AREA_LIGHTING_INCLUDED
|
|
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/AreaLighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonLighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GlobalSamplers.hlsl"
|
|
#include "Packages/com.baddog.rendering.arealight/Shaders/Include/PreIntegratedFGD.hlsl"
|
|
#include "Packages/com.baddog.rendering.arealight/Shaders/Include/LTCAreaLight.hlsl"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Constants
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#define GPULIGHTTYPE_RECTANGLE (6)
|
|
#define GPULIGHTTYPE_TUBE (5)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// PreLightData Structure (Area Light Related)
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Precomputed lighting data for area light evaluation
|
|
// Reference: Based on HDRP's PreLightData structure, simplified for area lights only
|
|
struct BGPreLightData
|
|
{
|
|
float NdotV; // Dot product between normal and view direction (could be negative due to normal mapping)
|
|
|
|
// Pre-integrated FGD (Fresnel, Geometric, Diffuse) terms
|
|
float3 specularFGD; // Pre-integrated specular FGD term
|
|
float diffuseFGD; // Pre-integrated diffuse FGD term
|
|
float reflectivity; // Pre-integrated reflectivity term (for multiscattering)
|
|
float energyCompensation; // Energy compensation for multiscattering (1.0 / specularReflectivity - 1.0)
|
|
|
|
// Area light LTC (Linearly Transformed Cosines) transforms
|
|
float3x3 orthoBasisViewNormal; // Right-handed view-dependent orthogonal basis around the normal
|
|
// Warning: These matrices are transposed! They are designed to transform row vectors via mul(V, M)
|
|
float3x3 ltcTransformDiffuse; // Inverse LTC transformation matrix for diffuse BRDF (Lambertian or Disney Diffuse)
|
|
float3x3 ltcTransformSpecular; // Inverse LTC transformation matrix for specular BRDF (GGX)
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Area Light Data Structure
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Area light data structure for URP
|
|
// This structure contains the necessary information for evaluating area lights (rectangular and line/tube lights)
|
|
// IMPORTANT: Must match C# BGAreaLightRenderingData layout exactly
|
|
// Uses float4 instead of float3+padding to match C# Vector4 layout (avoids alignment issues)
|
|
struct BGAreaLightData
|
|
{
|
|
float4 positionWS; // float4: xyz = position, w = 1 when this entry is an area light (matches C# Vector4 flag)
|
|
float4 right; // float4: xyz = right vector, w = unused
|
|
float4 up; // float4: xyz = up vector, w = unused
|
|
float4 forward; // float4: xyz = forward vector, w = unused
|
|
float4 size; // float4: xy = size (length, height), zw = unused
|
|
float4 colorIntensity; // float4: rgb = color, w = intensity
|
|
float4 rangeParams; // float4: x = range, y = rangeAttenuationScale, z = rangeAttenuationBias, w = isRectLight
|
|
float4 renderingLayerMask; // float4: x = uint mask bits (reinterpreted from C#), yzw = unused
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Area Light Data Buffer
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Structured buffer containing area light data for additional lights (per-object order)
|
|
// Entries without BGAreaLight component will have intensity = 0
|
|
StructuredBuffer<BGAreaLightData> _AreaLightDataBuffer;
|
|
|
|
// Count of entries in the area light data buffer (matches additionalLightsCount)
|
|
int _AreaLightDataBufferCount;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Area Light Shadow Data
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "Packages/com.baddog.rendering.arealight/Shaders/Include/BGAreaLightShadows.hlsl"
|
|
|
|
#if UNITY_VERSION < 60000000
|
|
// This function assumes that inputs are well-behaved, e.i.
|
|
// that the line does not pass through the origin and
|
|
// that the light is (at least partially) above the surface.
|
|
float I_diffuse_line(float3 C, float3 A, float hl)
|
|
{
|
|
// Solve C.z + h * A.z = 0.
|
|
float h = -C.z * rcp(A.z); // May be Inf, but never NaN
|
|
|
|
// Clip the line segment against the z-plane if necessary.
|
|
float h2 = (A.z >= 0) ? max( hl, h)
|
|
: min( hl, h); // P2 = C + h2 * A
|
|
float h1 = (A.z >= 0) ? max(-hl, h)
|
|
: min(-hl, h); // P1 = C + h1 * A
|
|
|
|
// Normalize the tangent.
|
|
float as = dot(A, A); // |A|^2
|
|
float ar = rsqrt(as); // 1/|A|
|
|
float a = as * ar; // |A|
|
|
float3 T = A * ar; // A/|A|
|
|
|
|
// Orthogonal 2D coordinates:
|
|
// P(n, t) = n * N + t * T.
|
|
float tc = dot(T, C); // C = n * N + tc * T
|
|
float3 P0 = C - tc * T; // P(n, 0) = n * N
|
|
float ns = dot(P0, P0); // |P0|^2
|
|
|
|
float nr = rsqrt(ns); // 1/|P0|
|
|
float n = ns * nr; // |P0|
|
|
float Nz = P0.z * nr; // N.z = P0.z/|P0|
|
|
|
|
// P(n, t) - C = P0 + t * T - P0 - tc * T
|
|
// = (t - tc) * T = h * A = (h * a) * T.
|
|
float t2 = tc + h2 * a; // P2.t
|
|
float t1 = tc + h1 * a; // P1.t
|
|
float s2 = ns + t2 * t2; // |P2|^2
|
|
float s1 = ns + t1 * t1; // |P1|^2
|
|
float mr = rsqrt(s1 * s2); // 1/(|P1|*|P2|)
|
|
float r2 = s1 * (mr * mr); // 1/|P2|^2
|
|
float r1 = s2 * (mr * mr); // 1/|P1|^2
|
|
|
|
// I = (i1 + i2 + i3) / Pi.
|
|
// i1 = N.z * (P2.t / |P2|^2 - P1.t / |P1|^2).
|
|
// i2 = -T.z * (P2.n / |P2|^2 - P1.n / |P1|^2).
|
|
// i3 = N.z * ArcCos[Dot[P1, P2] / (|P1| * |P2|)] / |P0|.
|
|
float i12 = (Nz * t2 - (T.z * n)) * r2
|
|
- (Nz * t1 - (T.z * n)) * r1;
|
|
// Guard against numerical errors.
|
|
float dt = min(1, (ns + t1 * t2) * mr);
|
|
float i3 = acos(dt) * (Nz * nr); // angle * cos(θ) / r^2
|
|
|
|
// Guard against numerical errors.
|
|
return INV_PI * max(0, i12 + i3);
|
|
}
|
|
|
|
// A hack to smoothly limit the influence of the light to the interior of a pillow.
|
|
// A "pillow" (for the lack of a better name) is formed by sweeping a ball across a rectangle.
|
|
// This function behaves like CapsuleAttenuation() for a narrow rectangle.
|
|
// This function behaves like SmoothWindowedDistanceAttenuation() for a small rectangle.
|
|
// Convention: the surface point is located at the origin of the coordinate system.
|
|
real PillowWindowing(real3 center, real3 xAxis, real3 yAxis, real halfLength, real halfHeight,
|
|
real rangeAttenuationScale, real rangeAttenuationBias)
|
|
{
|
|
// Conceptually, the idea is very simple: after taking the symmetry
|
|
// of the pillow into account, it is clear that the problem can be
|
|
// reduced to finding the closest sphere inside the pillow.
|
|
// We begin our search at the center of the pillow, and then translate
|
|
// this point along and across the plane of symmetry until we either
|
|
// a) find the closest point on the plane, or b) hit an edge of the rectangle.
|
|
// The problem is simplified by working in the coordinate system of the pillow.
|
|
real x = dot(center, xAxis); // -x, strictly speaking
|
|
real dx = max(0, abs(x) - halfLength);
|
|
real y = dot(center, yAxis); // -y, strictly speaking
|
|
real dy = max(0, abs(y) - halfHeight);
|
|
real r2 = dot(center, center); // r^2
|
|
real z2 = max(0, r2 - x * x - y * y); // z^2
|
|
real d2 = z2 + dx * dx + dy * dy; // Squared distance to the center of the closest sphere
|
|
|
|
return SmoothDistanceWindowing(d2, rangeAttenuationScale, rangeAttenuationBias);
|
|
}
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Area Light Shadow Sampling (moved to BGAreaLightShadows.hlsl)
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Get area light data for a specific additional light index (per-object order)
|
|
BGAreaLightData GetAreaLightData(uint lightIndex)
|
|
{
|
|
return _AreaLightDataBuffer[lightIndex];
|
|
}
|
|
|
|
// Legacy helper for visible light indexing (kept for compatibility)
|
|
BGAreaLightData GetAreaLightDataFromRealIndex(uint realLightIndex)
|
|
{
|
|
return _AreaLightDataBuffer[realLightIndex];
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Area Light Evaluation
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Evaluates area light using LTC approximation
|
|
// isRectLight: true for rectangular light, false for line/tube light
|
|
// center: Light center position in local coordinate system (shaded point at origin)
|
|
// right: Right vector of the light in local coordinate system
|
|
// up: Up vector of the light in local coordinate system
|
|
// halfLength: Half-length of the light along the right axis
|
|
// halfHeight: Half-height of the light along the up axis (0 for line lights)
|
|
// invM: Inverse LTC transformation matrix (transposed)
|
|
// perceptualRoughness: Material perceptual roughness [0, 1]
|
|
// Returns: float4 where rgb = color (1,1,1), a = irradiance
|
|
float4 EvaluateLTC_Area(bool isRectLight, float3 center, float3 right, float3 up,
|
|
float halfLength, float halfHeight,
|
|
float3x3 invM, float perceptualRoughness)
|
|
{
|
|
float3 ortho = cross(center, right);
|
|
float orthoSq = dot(ortho, ortho);
|
|
|
|
// Check whether the light is in a vertical orientation
|
|
bool quit = (orthoSq == 0);
|
|
|
|
// Check whether the light is entirely below the surface
|
|
// We must test twice, since a linear transformation
|
|
// may bring the light above the surface (a side-effect)
|
|
quit = quit || (center.z + halfLength * abs(right.z) + halfHeight * abs(up.z) <= 0);
|
|
|
|
float4 ltcValue = float4(1, 1, 1, 0);
|
|
|
|
if (!quit)
|
|
{
|
|
// Perform sparse matrix multiplication
|
|
float3 C = mul(invM, center);
|
|
float3 A = mul(invM, right);
|
|
float3 B = mul(invM, up);
|
|
|
|
// Check whether the light is entirely below the surface after transformation
|
|
if (C.z + halfLength * abs(A.z) + halfHeight * abs(B.z) > 0)
|
|
{
|
|
if (isRectLight)
|
|
{
|
|
// Transform the rectangular light vertices
|
|
float4x3 lightVerts;
|
|
lightVerts[0] = C - halfLength * A - halfHeight * B; // LL
|
|
lightVerts[1] = lightVerts[0] + (2.0 * halfHeight) * B; // UL
|
|
lightVerts[2] = lightVerts[1] + (2.0 * halfLength) * A; // UR
|
|
lightVerts[3] = lightVerts[2] - (2.0 * halfHeight) * B; // LR
|
|
|
|
// Compute polygon irradiance in the transformed configuration
|
|
#if UNITY_VERSION >= 60000000
|
|
float3 formFactor;
|
|
ltcValue.a = PolygonIrradiance(lightVerts, formFactor);
|
|
#else
|
|
ltcValue.a = PolygonIrradiance(lightVerts);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Line light evaluation
|
|
#if UNITY_VERSION >= 60000000
|
|
float w = ComputeLineWidthFactor(invM, ortho, orthoSq);
|
|
#else
|
|
float w = ComputeLineWidthFactor(invM, ortho);
|
|
#endif
|
|
ltcValue.a = I_diffuse_line(C, A, halfLength) * w;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ltcValue;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// PreLightData Initialization
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Initialize PreLightData for area light evaluation
|
|
BGPreLightData GetAreaLightPreLightData(
|
|
float3 V, float3 N,
|
|
float perceptualRoughness, float3 fresnel0,
|
|
uint bsdfModelDiffuse, uint bsdfModelSpecular)
|
|
{
|
|
BGPreLightData preLightData;
|
|
|
|
// Initialize all fields to zero
|
|
preLightData.NdotV = 0.0;
|
|
preLightData.specularFGD = float3(0, 0, 0);
|
|
preLightData.diffuseFGD = 0.0;
|
|
preLightData.reflectivity = 0.0;
|
|
preLightData.energyCompensation = 0.0;
|
|
preLightData.orthoBasisViewNormal = (float3x3)0;
|
|
preLightData.ltcTransformDiffuse = (float3x3)0;
|
|
preLightData.ltcTransformSpecular = (float3x3)0;
|
|
|
|
// Compute NdotV
|
|
preLightData.NdotV = dot(N, V);
|
|
float clampedNdotV = ClampNdotV(preLightData.NdotV);
|
|
|
|
// Compute pre-integrated FGD (Fresnel, Geometric, Diffuse) terms
|
|
float specularReflectivity;
|
|
#ifdef USE_DIFFUSE_LAMBERT_BRDF
|
|
// Use Lambertian diffuse FGD (diffuseFGD = 1.0)
|
|
GetPreIntegratedFGDGGXAndLambert(
|
|
clampedNdotV,
|
|
perceptualRoughness,
|
|
fresnel0,
|
|
preLightData.specularFGD,
|
|
preLightData.diffuseFGD,
|
|
preLightData.reflectivity
|
|
);
|
|
specularReflectivity = preLightData.reflectivity;
|
|
#else
|
|
// Use Disney Diffuse FGD
|
|
GetPreIntegratedFGDGGXAndDisneyDiffuse(
|
|
clampedNdotV,
|
|
perceptualRoughness,
|
|
fresnel0,
|
|
1,
|
|
preLightData.specularFGD,
|
|
preLightData.diffuseFGD,
|
|
preLightData.reflectivity
|
|
);
|
|
specularReflectivity = preLightData.reflectivity;
|
|
#endif
|
|
|
|
// Compute energy compensation for multiscattering
|
|
preLightData.energyCompensation = (specularReflectivity > 0.0) ? (1.0 / specularReflectivity - 1.0) : 0.0;
|
|
|
|
// Build orthogonal basis around normal (view-dependent)
|
|
preLightData.orthoBasisViewNormal = GetOrthoBasisViewNormal(V, N, preLightData.NdotV);
|
|
|
|
// Sample LTC matrices for diffuse
|
|
// HDRP style: Use compile-time macro to choose between Lambertian and other BRDF models
|
|
#ifdef USE_DIFFUSE_LAMBERT_BRDF
|
|
// Use identity matrix for Lambertian (no texture sampling)
|
|
preLightData.ltcTransformDiffuse = k_identity3x3;
|
|
#else
|
|
// Sample LTC matrix for the specified BRDF model (e.g., Disney Diffuse)
|
|
preLightData.ltcTransformDiffuse = SampleLtcMatrix(perceptualRoughness, clampedNdotV, bsdfModelDiffuse);
|
|
#endif
|
|
|
|
// Sample LTC matrix for specular
|
|
preLightData.ltcTransformSpecular = SampleLtcMatrix(perceptualRoughness, clampedNdotV, bsdfModelSpecular);
|
|
|
|
return preLightData;
|
|
}
|
|
|
|
// Area light lighting function compatible with URP's LightingPhysicallyBased style
|
|
// This function can be used in URP's additional lights loop
|
|
half3 LightingPhysicallyBasedAreaLight(
|
|
BGAreaLightData areaLightData,
|
|
BGPreLightData preLightData,
|
|
float3 positionWS,
|
|
half3 normalWS,
|
|
half3 viewDirectionWS,
|
|
half3 brdfDiffuse,
|
|
half3 brdfSpecular,
|
|
bool specularHighlightsOff)
|
|
{
|
|
// Step 1: Calculate light-to-surface vector and half dimensions
|
|
float3 unL = areaLightData.positionWS.xyz - positionWS;
|
|
float halfLength = areaLightData.size.x * 0.5;
|
|
float halfHeight = areaLightData.size.y * 0.5;
|
|
bool isRectLight = areaLightData.rangeParams.w > 0.5;
|
|
|
|
// Step 2: Check if light is front-facing (for rectangular lights only)
|
|
// Light forward points in the direction the light is facing (light emission direction)
|
|
// If dot(forward, unL) < 0, the point is behind the light (not illuminated)
|
|
if (isRectLight && dot(areaLightData.forward.xyz, unL) >= 0)
|
|
return half3(0, 0, 0);
|
|
|
|
// Step 3: Calculate intensity attenuation (matching HDRP implementation)
|
|
// HDRP uses PillowWindowing for all area lights (rect and line)
|
|
// For line lights, halfHeight = 0, so PillowWindowing degrades to CapsuleWindowing behavior
|
|
float intensity = PillowWindowing(unL, areaLightData.right.xyz, areaLightData.up.xyz,
|
|
halfLength, halfHeight,
|
|
areaLightData.rangeParams.y, // rangeAttenuationScale
|
|
areaLightData.rangeParams.z); // rangeAttenuationBias
|
|
|
|
// Early exit if light is not visible
|
|
if (intensity <= 0)
|
|
return half3(0, 0, 0);
|
|
|
|
// Step 4: Transform light vectors into local coordinate system (using pre-computed basis)
|
|
float3 center = mul(preLightData.orthoBasisViewNormal, unL);
|
|
float3 right = mul(preLightData.orthoBasisViewNormal, areaLightData.right.xyz);
|
|
float3 up = mul(preLightData.orthoBasisViewNormal, areaLightData.up.xyz);
|
|
|
|
// Step 5: Evaluate diffuse part (using pre-computed LTC matrix)
|
|
float4 ltcDiffuse = EvaluateLTC_Area(isRectLight,
|
|
center, right, up,
|
|
halfLength, halfHeight,
|
|
transpose(preLightData.ltcTransformDiffuse),
|
|
1.0); // Roughness = 1 for diffuse
|
|
|
|
// Step 6: Evaluate specular part (using pre-computed LTC matrix)
|
|
half3 lighting = half3(0, 0, 0);
|
|
|
|
// Diffuse contribution (FGD from preLightData)
|
|
lighting += brdfDiffuse * ltcDiffuse.a * preLightData.diffuseFGD;
|
|
|
|
// Specular contribution (FGD from preLightData)
|
|
half3 specularLighting = half3(0, 0, 0);
|
|
#ifndef _SPECULARHIGHLIGHTS_OFF
|
|
[branch] if (!specularHighlightsOff)
|
|
{
|
|
float4 ltcSpecular = EvaluateLTC_Area(isRectLight,
|
|
center, right, up,
|
|
halfLength, halfHeight,
|
|
transpose(preLightData.ltcTransformSpecular),
|
|
1.0); // Roughness is handled by LTC matrix
|
|
|
|
specularLighting = brdfSpecular * preLightData.specularFGD * ltcSpecular.a;
|
|
|
|
// Apply energy compensation for multiscattering (matching HDRP)
|
|
specularLighting *= (1.0 + preLightData.energyCompensation);
|
|
}
|
|
#endif
|
|
|
|
// Combine diffuse and specular
|
|
lighting += specularLighting;
|
|
|
|
// Step 7: Apply intensity and light color
|
|
lighting *= intensity * areaLightData.colorIntensity.rgb * areaLightData.colorIntensity.w;
|
|
|
|
return lighting;
|
|
}
|
|
|
|
half3 LightingPhysicallyBasedAreaLight(
|
|
BGAreaLightData areaLightData,
|
|
BGPreLightData preLightData,
|
|
float3 positionWS,
|
|
half3 normalWS,
|
|
half3 viewDirectionWS,
|
|
half3 brdfDiffuse,
|
|
half3 brdfSpecular)
|
|
{
|
|
return LightingPhysicallyBasedAreaLight(areaLightData, preLightData, positionWS,
|
|
normalWS, viewDirectionWS,
|
|
brdfDiffuse, brdfSpecular, false);
|
|
}
|
|
|
|
half3 LightingPhysicallyBasedAreaLightWithShadow(
|
|
uint areaLightIndex,
|
|
BGAreaLightData areaLightData,
|
|
BGPreLightData preLightData,
|
|
float3 positionWS,
|
|
half3 normalWS,
|
|
half3 viewDirectionWS,
|
|
half3 brdfDiffuse,
|
|
half3 brdfSpecular,
|
|
bool specularHighlightsOff)
|
|
{
|
|
// Calculate base lighting (without shadow)
|
|
half3 lighting = LightingPhysicallyBasedAreaLight(
|
|
areaLightData, preLightData, positionWS,
|
|
normalWS, viewDirectionWS,
|
|
brdfDiffuse, brdfSpecular, specularHighlightsOff);
|
|
|
|
// Apply shadow attenuation
|
|
half shadowAttenuation = SampleAreaLightShadow(areaLightIndex, positionWS);
|
|
lighting *= shadowAttenuation;
|
|
|
|
return lighting;
|
|
}
|
|
|
|
half3 LightingPhysicallyBasedAreaLightWithShadow(
|
|
uint areaLightIndex,
|
|
BGAreaLightData areaLightData,
|
|
BGPreLightData preLightData,
|
|
float3 positionWS,
|
|
half3 normalWS,
|
|
half3 viewDirectionWS,
|
|
half3 brdfDiffuse,
|
|
half3 brdfSpecular)
|
|
{
|
|
return LightingPhysicallyBasedAreaLightWithShadow(
|
|
areaLightIndex, areaLightData, preLightData, positionWS,
|
|
normalWS, viewDirectionWS,
|
|
brdfDiffuse, brdfSpecular, false);
|
|
}
|
|
|
|
half3 EvaluateAreaLight(
|
|
float3 positionWS,
|
|
half3 normalWS,
|
|
half3 viewDirectionWS,
|
|
half3 brdfDiffuse,
|
|
half3 brdfSpecular,
|
|
float perceptualRoughness,
|
|
float3 fresnel0,
|
|
bool specularHighlightsOff)
|
|
{
|
|
half3 totalLighting = half3(0, 0, 0);
|
|
|
|
if (_AreaLightDataBufferCount <= 0)
|
|
{
|
|
return totalLighting;
|
|
}
|
|
|
|
uint bsdfModelDiffuse = LTCLIGHTINGMODEL_DISNEY_DIFFUSE;
|
|
uint bsdfModelSpecular = LTCLIGHTINGMODEL_GGX;
|
|
|
|
BGPreLightData preLightData = GetAreaLightPreLightData(
|
|
viewDirectionWS,
|
|
normalWS,
|
|
perceptualRoughness,
|
|
fresnel0,
|
|
bsdfModelDiffuse,
|
|
bsdfModelSpecular
|
|
);
|
|
|
|
#ifdef _LIGHT_LAYERS
|
|
uint meshRenderingLayers = GetMeshRenderingLayer();
|
|
#endif
|
|
|
|
for (uint i = 0; i < (uint)_AreaLightDataBufferCount; ++i)
|
|
{
|
|
BGAreaLightData areaLightData = GetAreaLightData(i);
|
|
|
|
#ifdef _LIGHT_LAYERS
|
|
uint lightLayerMask = asuint(areaLightData.renderingLayerMask.x);
|
|
if (!IsMatchingLightLayer(lightLayerMask, meshRenderingLayers))
|
|
{
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
half3 lightContribution = LightingPhysicallyBasedAreaLightWithShadow(
|
|
i, // areaLightIndex
|
|
areaLightData,
|
|
preLightData,
|
|
positionWS,
|
|
normalWS,
|
|
viewDirectionWS,
|
|
brdfDiffuse,
|
|
brdfSpecular,
|
|
specularHighlightsOff);
|
|
|
|
totalLighting += lightContribution;
|
|
}
|
|
|
|
return totalLighting;
|
|
}
|
|
|
|
half3 EvaluateAreaLight(
|
|
float3 positionWS,
|
|
half3 normalWS,
|
|
half3 viewDirectionWS,
|
|
half3 brdfDiffuse,
|
|
half3 brdfSpecular,
|
|
float perceptualRoughness,
|
|
float3 fresnel0)
|
|
{
|
|
return EvaluateAreaLight(
|
|
positionWS, normalWS, viewDirectionWS,
|
|
brdfDiffuse, brdfSpecular,
|
|
perceptualRoughness, fresnel0,
|
|
false);
|
|
}
|
|
|
|
half3 EvaluateAreaLight(InputData inputData, SurfaceData surfaceData)
|
|
{
|
|
BRDFData brdfData;
|
|
InitializeBRDFData(surfaceData, brdfData);
|
|
|
|
float perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surfaceData.smoothness);
|
|
float3 fresnel0 = brdfData.specular;
|
|
|
|
// Check if specular highlights are disabled
|
|
bool specularHighlightsOff = false;
|
|
#if defined(_SPECULARHIGHLIGHTS_OFF)
|
|
specularHighlightsOff = true;
|
|
#endif
|
|
|
|
return EvaluateAreaLight(
|
|
inputData.positionWS,
|
|
inputData.normalWS,
|
|
inputData.viewDirectionWS,
|
|
brdfData.diffuse,
|
|
brdfData.specular,
|
|
perceptualRoughness,
|
|
fresnel0,
|
|
specularHighlightsOff);
|
|
}
|
|
|
|
|
|
#endif // BADDOG_AREA_LIGHTING_INCLUDED
|
|
|