483 lines
21 KiB
HLSL
483 lines
21 KiB
HLSL
#ifndef UTS_LIGHT_LOOP
|
|
#define UTS_LIGHT_LOOP
|
|
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Macros.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/PhysicalCamera.hlsl"
|
|
#include "Packages/com.misaki.hdrp-toon/Runtime/Shaders/Includes/Lighting/UtsLightEvaluation.hlsl"
|
|
#include "Packages/com.misaki.hdrp-toon/Runtime/Models/SurfaceFeatureFlags.cs.hlsl"
|
|
|
|
// Channel mask enum.
|
|
// this must be same to UI cs code
|
|
// HDRPToonGUI._ChannelEnum
|
|
int eBaseColor = 0;
|
|
int eFirstShade = 1;
|
|
int eSecondShade = 2;
|
|
int eHighlight = 3;
|
|
int eAngelRing = 4;
|
|
int eRimLight = 5;
|
|
int eOutline = 6;
|
|
|
|
int GetNextDirectionalLightIndex(BuiltinData builtinData, int currentIndex, int mainLightIndex)
|
|
{
|
|
int i = 0; // Declare once to avoid the D3D11 compiler warning.
|
|
for (i = 0; i < (int)_DirectionalLightCount; ++i)
|
|
{
|
|
if (IsMatchingLightLayer(_DirectionalLightDatas[i].lightLayers, builtinData.renderingLayers))
|
|
{
|
|
if (mainLightIndex != i)
|
|
{
|
|
if (currentIndex < i)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return -1; // not found
|
|
}
|
|
|
|
int GetUtsMainLightIndex(BuiltinData builtinData)
|
|
{
|
|
int mainLightIndex = -1;
|
|
float3 lightColor = float3(0.0f, 0.0f, 0.0f);
|
|
float lightAttenuation = 0.0f;
|
|
uint i = 0; // Declare once to avoid the D3D11 compiler warning.
|
|
for (i = 0; i < _DirectionalLightCount; ++i)
|
|
{
|
|
if (IsMatchingLightLayer(_DirectionalLightDatas[i].lightLayers, builtinData.renderingLayers))
|
|
{
|
|
float3 currentLightColor = _DirectionalLightDatas[i].color;
|
|
float currentLightAttenuation = GetColorAttenuation(currentLightColor);
|
|
|
|
if (mainLightIndex == -1 || (currentLightAttenuation > lightAttenuation))
|
|
{
|
|
mainLightIndex = i;
|
|
lightAttenuation = currentLightAttenuation;
|
|
|
|
lightColor = currentLightColor;
|
|
}
|
|
}
|
|
}
|
|
|
|
return mainLightIndex;
|
|
}
|
|
|
|
bool UtsUseScreenSpaceShadow(DirectionalLightData light, float3 normalWS)
|
|
{
|
|
#if defined(RAY_TRACED_SCREEN_SPACE_SHADOW_FLAG)
|
|
// Two different options are possible here
|
|
// - We have a ray trace shadow in which case we have no valid signal for a transmission and we need to fallback on the rasterized shadow
|
|
// - We have a screen space shadow and it already contains the transmission shadow and we can use it straight away
|
|
bool visibleLight = 0.5 * dot(normalWS, -light.forward) + 0.5 > 0.0;
|
|
bool validScreenSpaceShadow = (light.screenSpaceShadowIndex & SCREEN_SPACE_SHADOW_INDEX_MASK) != INVALID_SCREEN_SPACE_SHADOW;
|
|
bool rayTracedShadow = (light.screenSpaceShadowIndex & RAY_TRACED_SCREEN_SPACE_SHADOW_FLAG) != 0.0;
|
|
return (validScreenSpaceShadow && ((rayTracedShadow && visibleLight) || !rayTracedShadow));
|
|
#else
|
|
return ((light.screenSpaceShadowIndex & SCREEN_SPACE_SHADOW_INDEX_MASK) != INVALID_SCREEN_SPACE_SHADOW);
|
|
#endif
|
|
}
|
|
|
|
void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bsdfData, BuiltinData builtinData,
|
|
float3 V, uint featureFlags, out LightLoopOutput lightLoopOutput)
|
|
{
|
|
LightLoopContext context;
|
|
context.shadowContext = InitShadowContext();
|
|
context.shadowValue = 1;
|
|
context.sampleReflection = 0;
|
|
#ifdef APPLY_FOG_ON_SKY_REFLECTIONS
|
|
context.positionWS = posInput.positionWS;
|
|
#endif
|
|
|
|
// Initialize the contactShadow and contactShadowFade fields
|
|
InitContactShadow(posInput, context);
|
|
|
|
#if _RECEIVE_LIGHT_SHADOW_ON
|
|
// First of all we compute the shadow value of the directional light to reduce the VGPR pressure
|
|
if (featureFlags & LIGHTFEATUREFLAGS_DIRECTIONAL)
|
|
{
|
|
// Evaluate sun shadows.
|
|
if (_DirectionalShadowIndex >= 0)
|
|
{
|
|
DirectionalLightData light = _DirectionalLightDatas[_DirectionalShadowIndex];
|
|
|
|
#if defined(SCREEN_SPACE_SHADOWS_ON) && !defined(_SURFACE_TYPE_TRANSPARENT) && defined(_RECEIVE_SCREEN_SPACE_SHADOW_ON)
|
|
if (UtsUseScreenSpaceShadow(light, bsdfData.normalWS))
|
|
{
|
|
context.shadowValue = GetScreenSpaceColorShadow(posInput, light.screenSpaceShadowIndex).SHADOW_TYPE_SWIZZLE;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
float3 L = -light.forward;
|
|
|
|
// Is it worth sampling the shadow map?
|
|
if ((light.lightDimmer > 0) && (light.shadowDimmer > 0) && // Note: Volumetric can have different dimmer, thus why we test it here
|
|
dot(bsdfData.normalWS, L) > 0.0)
|
|
{
|
|
context.shadowValue = GetDirectionalShadowAttenuation(context.shadowContext,
|
|
posInput.positionSS, posInput.positionWS + L * _ShadowDistanceBias, UtsGetShadowNormal(bsdfData),
|
|
light.shadowIndex, L);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
PreLightData preLightData = GetPreLightData_UTS(V, posInput, bsdfData);
|
|
|
|
AggregateLighting aggregateLighting;
|
|
ZERO_INITIALIZE(AggregateLighting, aggregateLighting);
|
|
|
|
// Evaluate the punctual lights.
|
|
if (featureFlags & LIGHTFEATUREFLAGS_PUNCTUAL)
|
|
{
|
|
uint lightCount, lightStart;
|
|
|
|
#ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
|
|
GetCountAndStart(posInput, LIGHTCATEGORY_PUNCTUAL, lightStart, lightCount);
|
|
#else // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
|
|
lightCount = _PunctualLightCount;
|
|
lightStart = 0;
|
|
#endif
|
|
|
|
bool fastPath = false;
|
|
#if SCALARIZE_LIGHT_LOOP
|
|
uint lightStartLane0;
|
|
fastPath = IsFastPath(lightStart, lightStartLane0);
|
|
|
|
if (fastPath)
|
|
{
|
|
lightStart = lightStartLane0;
|
|
}
|
|
#endif
|
|
|
|
// Scalarized loop. All lights that are in a tile/cluster touched by any pixel in the wave are loaded (scalar load), only the one relevant to current thread/pixel are processed.
|
|
// For clarity, the following code will follow the convention: variables starting with s_ are meant to be wave uniform (meant for scalar register),
|
|
// v_ are variables that might have different value for each thread in the wave (meant for vector registers).
|
|
// This will perform more loads than it is supposed to, however, the benefits should offset the downside, especially given that light data accessed should be largely coherent.
|
|
// Note that the above is valid only if wave intriniscs are supported.
|
|
uint v_lightListOffset = 0;
|
|
uint v_lightIdx = lightStart;
|
|
|
|
[loop] // vulkan shader compiler can not unroll.
|
|
#if NEED_TO_CHECK_HELPER_LANE
|
|
// On some platform helper lanes don't behave as we'd expect, therefore we prevent them from entering the loop altogether.
|
|
// IMPORTANT! This has implications if ddx/ddy is used on results derived from lighting, however given Lightloop is called in compute we should be
|
|
// sure it will not happen.
|
|
bool isHelperLane = WaveIsHelperLane();
|
|
while (!isHelperLane && v_lightListOffset < lightCount)
|
|
#else
|
|
while (v_lightListOffset < lightCount)
|
|
#endif
|
|
{
|
|
v_lightIdx = FetchIndex(lightStart, v_lightListOffset);
|
|
#if SCALARIZE_LIGHT_LOOP
|
|
uint s_lightIdx = ScalarizeElementIndex(v_lightIdx, fastPath);
|
|
#else
|
|
uint s_lightIdx = v_lightIdx;
|
|
#endif
|
|
if (s_lightIdx == -1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
LightData s_lightData = FetchLight(s_lightIdx);
|
|
|
|
// If current scalar and vector light index match, we process the light. The v_lightListOffset for current thread is increased.
|
|
// Note that the following should really be ==, however, since helper lanes are not considered by WaveActiveMin, such helper lanes could
|
|
// end up with a unique v_lightIdx value that is smaller than s_lightIdx hence being stuck in a loop. All the active lanes will not have this problem.
|
|
if (s_lightIdx >= v_lightIdx)
|
|
{
|
|
v_lightListOffset++;
|
|
if (IsMatchingLightLayer(s_lightData.lightLayers, builtinData.renderingLayers))
|
|
{
|
|
DirectLighting lighting = UtsEvaluateBSDF_Punctual(context, posInput, builtinData, s_lightData, bsdfData, preLightData, V, fragInputs.texCoord0.xy);
|
|
AccumulateDirectLighting(lighting, aggregateLighting);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Evaluate the directional lights.
|
|
if (featureFlags & LIGHTFEATUREFLAGS_DIRECTIONAL)
|
|
{
|
|
uint i = 0; // Declare once to avoid the D3D11 compiler warning.
|
|
for (i = 0; i < _DirectionalLightCount; ++i)
|
|
{
|
|
if (IsMatchingLightLayer(_DirectionalLightDatas[i].lightLayers, builtinData.renderingLayers))
|
|
{
|
|
DirectLighting lighting = UtsEvaluateBSDF_Directional(context, posInput, builtinData, _DirectionalLightDatas[i], bsdfData, preLightData, V, fragInputs.texCoord0.xy);
|
|
AccumulateDirectLighting(lighting, aggregateLighting);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Evaluate the environment lights.
|
|
if (featureFlags & (LIGHTFEATUREFLAGS_ENV | LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_SSREFRACTION | LIGHTFEATUREFLAGS_SSREFLECTION))
|
|
{
|
|
float reflectionHierarchyWeight = 0.0; // Max: 1.0
|
|
|
|
uint envLightStart, envLightCount;
|
|
|
|
// Fetch first env light to provide the scene proxy for screen space computation
|
|
#ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
|
|
GetCountAndStart(posInput, LIGHTCATEGORY_ENV, envLightStart, envLightCount);
|
|
#else
|
|
envLightCount = _EnvLightCount;
|
|
envLightStart = 0;
|
|
#endif
|
|
|
|
bool fastPath = false;
|
|
#if SCALARIZE_LIGHT_LOOP
|
|
uint envStartFirstLane;
|
|
fastPath = IsFastPath(envLightStart, envStartFirstLane);
|
|
#endif
|
|
|
|
// Reflection hierarchy is
|
|
// 1. Screen Space Reflection
|
|
// 2. Environment Reflection
|
|
// 3. Sky Reflection
|
|
|
|
// Apply SSR.
|
|
#if (defined(_SURFACE_TYPE_TRANSPARENT) && !defined(_DISABLE_SSR_TRANSPARENT)) || (!defined(_SURFACE_TYPE_TRANSPARENT) && !defined(_DISABLE_SSR))
|
|
{
|
|
IndirectLighting lighting = UtsEvaluateBSDF_ScreenSpaceReflection(posInput, preLightData, reflectionHierarchyWeight);
|
|
AccumulateIndirectLighting(lighting, aggregateLighting);
|
|
}
|
|
#endif
|
|
|
|
float3 lightInReflDir = 0.0;
|
|
#ifdef _INDIRECT_DIFFUSE_MODE_OFF
|
|
|
|
#elif _INDIRECT_DIFFUSE_MODE_IBL
|
|
bool replaceBakeDiffuseLighting = false;
|
|
#if !defined(_SURFACE_TYPE_TRANSPARENT) // No SSGI/RTGI/Mixed effect on transparent
|
|
if (_IndirectDiffuseMode != INDIRECTDIFFUSEMODE_OFF)
|
|
{
|
|
replaceBakeDiffuseLighting = true;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
|
|
if (!builtinData.isLightmap)
|
|
{
|
|
replaceBakeDiffuseLighting = true;
|
|
}
|
|
#endif
|
|
|
|
#if defined(LIGHT_EVALUATION_SKIP_INDIRECT_DIFFUSE)
|
|
replaceBakeDiffuseLighting = false;
|
|
#endif
|
|
|
|
if (replaceBakeDiffuseLighting)
|
|
{
|
|
UtsEvaluateBSDF_BakeDiffuse(posInput, preLightData, bsdfData, V, builtinData, lightInReflDir);
|
|
}
|
|
#elif _INDIRECT_DIFFUSE_MODE_MATCAP
|
|
//builtinData.bakeDiffuseLighting = UtsEvaluateColor_MatCap(posInput.positionWS, bsdfData.normalWS, 0.0);
|
|
UtsEvaluateBSDF_MatCapDiffuse(posInput.positionWS, bsdfData.normalWS, builtinData);
|
|
#elif _INDIRECT_DIFFUSE_MODE_RAMP
|
|
UtsEvaluateBSDF_Ramp(posInput, bsdfData, builtinData);
|
|
#endif
|
|
|
|
if (featureFlags & LIGHTFEATUREFLAGS_ENV)
|
|
{
|
|
#if _INDIRECT_SPECULAR_MODE_OFF
|
|
|
|
#elif _INDIRECT_SPECULAR_MODE_IBL
|
|
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES;
|
|
|
|
#if SCALARIZE_LIGHT_LOOP
|
|
if (fastPath)
|
|
{
|
|
envLightStart = envStartFirstLane;
|
|
}
|
|
#endif
|
|
|
|
// Scalarized loop, same rationale of the punctual light version
|
|
uint v_envLightListOffset = 0;
|
|
uint v_envLightIdx = envLightStart;
|
|
#if NEED_TO_CHECK_HELPER_LANE
|
|
// On some platform helper lanes don't behave as we'd expect, therefore we prevent them from entering the loop altogether.
|
|
// IMPORTANT! This has implications if ddx/ddy is used on results derived from lighting, however given Lightloop is called in compute we should be
|
|
// sure it will not happen.
|
|
bool isHelperLane = WaveIsHelperLane();
|
|
while (!isHelperLane && v_envLightListOffset < envLightCount)
|
|
#else
|
|
while (v_envLightListOffset < envLightCount)
|
|
#endif
|
|
{
|
|
v_envLightIdx = FetchIndex(envLightStart, v_envLightListOffset);
|
|
#if SCALARIZE_LIGHT_LOOP
|
|
uint s_envLightIdx = ScalarizeElementIndex(v_envLightIdx, fastPath);
|
|
#else
|
|
uint s_envLightIdx = v_envLightIdx;
|
|
#endif
|
|
if (s_envLightIdx == -1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
EnvLightData s_envLightData = FetchEnvLight(s_envLightIdx);
|
|
|
|
// If current scalar and vector light index match, we process the light. The v_envLightListOffset for current thread is increased.
|
|
// Note that the following should really be ==, however, since helper lanes are not considered by WaveActiveMin, such helper lanes could
|
|
// end up with a unique v_envLightIdx value that is smaller than s_envLightIdx hence being stuck in a loop. All the active lanes will not have this problem.
|
|
if (s_envLightIdx >= v_envLightIdx)
|
|
{
|
|
v_envLightListOffset++;
|
|
if (reflectionHierarchyWeight < 1.0)
|
|
{
|
|
if (IsMatchingLightLayer(s_envLightData.lightLayers, builtinData.renderingLayers))
|
|
{
|
|
IndirectLighting lighting = UtsEvaluateBSDF_Env(context, posInput, preLightData, s_envLightData, bsdfData, s_envLightData.influenceShapeType, GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION, reflectionHierarchyWeight);
|
|
#if defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
|
|
|
|
if (s_envLightData.normalizeWithAPV > 0 && all(lightInReflDir >= 0))
|
|
{
|
|
float factor = GetReflectionProbeNormalizationFactor(lightInReflDir, bsdfData.normalWS, s_envLightData.L0L1, s_envLightData.L2_1, s_envLightData.L2_2);
|
|
lighting.specularReflected *= factor;
|
|
}
|
|
#endif
|
|
|
|
AccumulateIndirectLighting(lighting, aggregateLighting);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
#elif _INDIRECT_SPECULAR_MODE_MATCAP
|
|
IndirectLighting lighting = UtsEvaluateBSDF_MatCapSpecular(posInput.positionWS, bsdfData, preLightData);
|
|
AccumulateIndirectLighting(lighting, aggregateLighting);
|
|
#endif
|
|
}
|
|
|
|
#if _INDIRECT_SPECULAR_MODE_IBL
|
|
// Only apply the sky IBL if the sky texture is available
|
|
if ((featureFlags & LIGHTFEATUREFLAGS_SKY) && _EnvLightSkyEnabled)
|
|
{
|
|
// The sky is a single cubemap texture separate from the reflection probe texture array (different resolution and compression)
|
|
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_SKY;
|
|
|
|
// The sky data are generated on the fly so the compiler can optimize the code
|
|
EnvLightData envLightSky = InitSkyEnvLightData(0);
|
|
|
|
// Only apply the sky if we haven't yet accumulated enough IBL lighting.
|
|
if (reflectionHierarchyWeight < 1.0)
|
|
{
|
|
IndirectLighting lighting = UtsEvaluateBSDF_Env(context, posInput, preLightData, envLightSky, bsdfData, envLightSky.influenceShapeType, GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION, reflectionHierarchyWeight);
|
|
AccumulateIndirectLighting(lighting, aggregateLighting);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (HasFlag(bsdfData.surfaceFeatures, SURFACEFEATUREFLAGS_ANGEL_RING))
|
|
{
|
|
DirectLighting lighting = UtsEvaluateAngelRing(fragInputs, bsdfData.normalWS, V);
|
|
AccumulateDirectLighting(lighting, aggregateLighting);
|
|
}
|
|
|
|
UtsPostEvaluateBSDF(posInput, preLightData, bsdfData, builtinData, aggregateLighting, lightLoopOutput);
|
|
}
|
|
|
|
// UTSLightData GetUTSMainPunctualLightData(BuiltinData builtinData, PositionInputs posInput)
|
|
// {
|
|
// UTSLightData mainPunctualLight;
|
|
|
|
// uint lightCount, lightStart;
|
|
|
|
// #ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
|
|
// GetCountAndStart(posInput, LIGHTCATEGORY_PUNCTUAL, lightStart, lightCount);
|
|
// #else // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
|
|
// lightCount = _PunctualLightCount;
|
|
// lightStart = 0;
|
|
// #endif
|
|
// bool fastPath = false;
|
|
// #if SCALARIZE_LIGHT_LOOP
|
|
// uint lightStartLane0;
|
|
// fastPath = IsFastPath(lightStart, lightStartLane0);
|
|
|
|
// if (fastPath)
|
|
// {
|
|
// lightStart = lightStartLane0;
|
|
// }
|
|
// #endif
|
|
|
|
// uint v_lightListOffset = 0;
|
|
// uint v_lightIdx = lightStart;
|
|
// float channelAlpha = 0.0f;
|
|
// [loop] // vulkan shader compiler can not unroll.
|
|
// while (v_lightListOffset < lightCount)
|
|
// {
|
|
// v_lightIdx = FetchIndex(lightStart, v_lightListOffset);
|
|
// #if SCALARIZE_LIGHT_LOOP
|
|
// uint s_lightIdx = ScalarizeElementIndex(v_lightIdx, fastPath);
|
|
// #else
|
|
// uint s_lightIdx = v_lightIdx;
|
|
// #endif
|
|
// if (s_lightIdx == -1)
|
|
// break;
|
|
|
|
// LightData s_lightData = FetchLight(s_lightIdx);
|
|
|
|
// // If current scalar and vector light index match, we process the light. The v_lightListOffset for current thread is increased.
|
|
// // Note that the following should really be ==, however, since helper lanes are not considered by WaveActiveMin, such helper lanes could
|
|
// // end up with a unique v_lightIdx value that is smaller than s_lightIdx hence being stuck in a loop. All the active lanes will not have this problem.
|
|
// if (s_lightIdx >= v_lightIdx)
|
|
// {
|
|
// v_lightListOffset++;
|
|
// if (IsMatchingLightLayer(s_lightData.lightLayers, builtinData.renderingLayers))
|
|
// {
|
|
// float3 lightDirection;
|
|
// float4 distances; // {d, d^2, 1/d, d_proj}
|
|
// GetPunctualLightVectors(posInput.positionWS, s_lightData, lightDirection, distances);
|
|
// float4 lightColor = EvaluateLight_Punctual(context, posInput, s_lightData, lightDirection, distances);
|
|
// float3 additionalLightColor = ApplyCurrentExposureMultiplier(lightColor.rgb) * lightColor.a;
|
|
// const float notDirectional = 1.0f;
|
|
|
|
// UTSLightData utsLightData;
|
|
// utsLightData.lightColor = additionalLightColor;
|
|
// utsLightData.lightDirection = lightDirection;
|
|
// utsLightData.diffuseDimmer = s_lightData.diffuseDimmer;
|
|
// utsLightData.specularDimmer = s_lightData.specularDimmer;
|
|
// utsLightData.shadowTint = s_lightData.shadowTint;
|
|
// utsLightData.penumbraTint = s_lightData.penumbraTint;
|
|
|
|
// if(length(additionalLightColor) >= length(mainPunctualLight.lightColor))
|
|
// {
|
|
// mainPunctualLight = utsLightData;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// return mainPunctualLight;
|
|
// }
|
|
|
|
// Todo: calculate the acutal main lighboth dorectional and punctual)t based on the light attenuation, rather than using the main directional light
|
|
UTSLightData GetCustomMainLightData(BuiltinData builtinData, UTSLightData mainPunctualLight)
|
|
{
|
|
UTSLightData utsLightData;
|
|
int mainLightIndex;
|
|
|
|
mainLightIndex = GetUtsMainLightIndex(builtinData);
|
|
|
|
if (mainLightIndex == -1 || length(_DirectionalLightDatas[mainLightIndex].color) < length(mainPunctualLight.lightColor))
|
|
{
|
|
utsLightData = mainPunctualLight;
|
|
}
|
|
else
|
|
{
|
|
utsLightData.lightColor = ApplyCurrentExposureMultiplier(_DirectionalLightDatas[mainLightIndex].color);
|
|
utsLightData.lightDirection = -_DirectionalLightDatas[mainLightIndex].forward;
|
|
utsLightData.diffuseDimmer = _DirectionalLightDatas[mainLightIndex].diffuseDimmer;
|
|
utsLightData.specularDimmer = _DirectionalLightDatas[mainLightIndex].specularDimmer;
|
|
utsLightData.shadowTint = _DirectionalLightDatas[mainLightIndex].shadowTint;
|
|
utsLightData.penumbraTint = _DirectionalLightDatas[mainLightIndex].penumbraTint;
|
|
}
|
|
|
|
return utsLightData;
|
|
}
|
|
|
|
#endif |