Simplify shader code for point/spot lights to use permutations instead
This commit is contained in:
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -10,6 +10,7 @@ template<int Size>
|
||||
class GPUPipelineStatePermutations
|
||||
{
|
||||
public:
|
||||
enum { StaticSize = Size };
|
||||
GPUPipelineState* States[Size];
|
||||
|
||||
public:
|
||||
@@ -97,13 +98,13 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
bool Create(GPUPipelineState::Description& desc, GPUShader* shader, const StringAnsiView& psName)
|
||||
bool Create(GPUPipelineState::Description& desc, GPUShader* shader, const StringAnsiView& psName, int32 permutationOffset = 0)
|
||||
{
|
||||
for (int i = 0; i < Size; i++)
|
||||
{
|
||||
ASSERT(Base::States[i]);
|
||||
|
||||
desc.PS = shader->GetPS(psName, i);
|
||||
desc.PS = shader->GetPS(psName, i + permutationOffset);
|
||||
if (Base::States[i]->Init(desc))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -31,10 +31,8 @@ bool LightPass::Init()
|
||||
{
|
||||
// Create pipeline states
|
||||
_psLightDir.CreatePipelineStates();
|
||||
_psLightPoint.CreatePipelineStates();
|
||||
_psLightPointInside.CreatePipelineStates();
|
||||
_psLightSpot.CreatePipelineStates();
|
||||
_psLightSpotInside.CreatePipelineStates();
|
||||
_psLightLocal.CreatePipelineStates();
|
||||
_psLightLocalInside.CreatePipelineStates();
|
||||
_psLightSky = GPUDevice::Instance->CreatePipelineState();
|
||||
_psLightSkyInside = GPUDevice::Instance->CreatePipelineState();
|
||||
_depthBounds = GPUDevice::Instance->Limits.HasDepthBounds && GPUDevice::Instance->Limits.HasReadOnlyDepth;
|
||||
@@ -81,7 +79,7 @@ bool LightPass::setupResources()
|
||||
if (_psLightDir.Create(psDesc, shader, "PS_Directional"))
|
||||
return true;
|
||||
}
|
||||
if (!_psLightPoint.IsValid())
|
||||
if (!_psLightLocal.IsValid())
|
||||
{
|
||||
psDesc = GPUPipelineState::Description::DefaultNoDepth;
|
||||
psDesc.BlendMode = BlendingMode::Add;
|
||||
@@ -90,27 +88,11 @@ bool LightPass::setupResources()
|
||||
psDesc.DepthEnable = true;
|
||||
psDesc.DepthBoundsEnable = _depthBounds;
|
||||
psDesc.CullMode = CullMode::Normal;
|
||||
if (_psLightPoint.Create(psDesc, shader, "PS_Point"))
|
||||
if (_psLightLocal.Create(psDesc, shader, "PS_LocalLight"))
|
||||
return true;
|
||||
psDesc.DepthFunc = ComparisonFunc::Greater;
|
||||
psDesc.CullMode = CullMode::Inverted;
|
||||
if (_psLightPointInside.Create(psDesc, shader, "PS_Point"))
|
||||
return true;
|
||||
}
|
||||
if (!_psLightSpot.IsValid())
|
||||
{
|
||||
psDesc = GPUPipelineState::Description::DefaultNoDepth;
|
||||
psDesc.BlendMode = BlendingMode::Add;
|
||||
psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::RGB;
|
||||
psDesc.VS = shader->GetVS("VS_Model");
|
||||
psDesc.DepthEnable = true;
|
||||
psDesc.DepthBoundsEnable = _depthBounds;
|
||||
psDesc.CullMode = CullMode::Normal;
|
||||
if (_psLightSpot.Create(psDesc, shader, "PS_Spot"))
|
||||
return true;
|
||||
psDesc.DepthFunc = ComparisonFunc::Greater;
|
||||
psDesc.CullMode = CullMode::Inverted;
|
||||
if (_psLightSpotInside.Create(psDesc, shader, "PS_Spot"))
|
||||
if (_psLightLocalInside.Create(psDesc, shader, "PS_LocalLight"))
|
||||
return true;
|
||||
}
|
||||
if (!_psLightSky->IsValid())
|
||||
@@ -141,10 +123,8 @@ void LightPass::Dispose()
|
||||
|
||||
// Cleanup
|
||||
_psLightDir.Delete();
|
||||
_psLightPoint.Delete();
|
||||
_psLightPointInside.Delete();
|
||||
_psLightSpot.Delete();
|
||||
_psLightSpotInside.Delete();
|
||||
_psLightLocal.Delete();
|
||||
_psLightLocalInside.Delete();
|
||||
SAFE_DELETE_GPU_RESOURCE(_psLightSky);
|
||||
SAFE_DELETE_GPU_RESOURCE(_psLightSkyInside);
|
||||
SAFE_DELETE_GPU_RESOURCE(_psClearDiffuse);
|
||||
@@ -301,7 +281,7 @@ void LightPass::RenderLights(RenderContextBatch& renderContextBatch, GPUTextureV
|
||||
context->BindCB(0, cb0);
|
||||
context->BindCB(1, cb1);
|
||||
int32 permutationIndex = (disableSpecular ? 1 : 0) + (useIES ? 2 : 0);
|
||||
context->SetState((isViewInside ? _psLightPointInside : _psLightPoint).Get(permutationIndex));
|
||||
context->SetState((isViewInside ? _psLightLocalInside : _psLightLocal).Get(permutationIndex));
|
||||
sphereMesh.Render(context);
|
||||
}
|
||||
|
||||
@@ -349,7 +329,7 @@ void LightPass::RenderLights(RenderContextBatch& renderContextBatch, GPUTextureV
|
||||
context->BindCB(0, cb0);
|
||||
context->BindCB(1, cb1);
|
||||
int32 permutationIndex = (disableSpecular ? 1 : 0) + (useIES ? 2 : 0);
|
||||
context->SetState((isViewInside ? _psLightSpotInside : _psLightSpot).Get(permutationIndex));
|
||||
context->SetState((isViewInside ? _psLightLocalInside : _psLightLocal).Get(permutationIndex));
|
||||
sphereMesh.Render(context);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,8 @@ class LightPass : public RendererPass<LightPass>
|
||||
private:
|
||||
AssetReference<Shader> _shader;
|
||||
GPUPipelineStatePermutationsPs<2> _psLightDir;
|
||||
GPUPipelineStatePermutationsPs<4> _psLightPoint;
|
||||
GPUPipelineStatePermutationsPs<4> _psLightPointInside;
|
||||
GPUPipelineStatePermutationsPs<4> _psLightSpot;
|
||||
GPUPipelineStatePermutationsPs<4> _psLightSpotInside;
|
||||
GPUPipelineStatePermutationsPs<4> _psLightLocal;
|
||||
GPUPipelineStatePermutationsPs<4> _psLightLocalInside;
|
||||
GPUPipelineState* _psLightSky = nullptr;
|
||||
GPUPipelineState* _psLightSkyInside = nullptr;
|
||||
GPUPipelineState* _psClearDiffuse = nullptr;
|
||||
@@ -45,10 +43,8 @@ private:
|
||||
void OnShaderReloading(Asset* obj)
|
||||
{
|
||||
_psLightDir.Release();
|
||||
_psLightPoint.Release();
|
||||
_psLightPointInside.Release();
|
||||
_psLightSpot.Release();
|
||||
_psLightSpotInside.Release();
|
||||
_psLightLocal.Release();
|
||||
_psLightLocalInside.Release();
|
||||
_psLightSky->ReleaseGPU();
|
||||
_psLightSkyInside->ReleaseGPU();
|
||||
invalidateResources();
|
||||
|
||||
@@ -525,6 +525,7 @@ bool ShadowsPass::setupResources()
|
||||
if (_psShadowDir.Create(psDesc, shader, "PS_DirLight"))
|
||||
return true;
|
||||
}
|
||||
StringAnsiView psLocalLight("PS_LocalLight");
|
||||
if (!_psShadowPoint.IsValid())
|
||||
{
|
||||
psDesc = GPUPipelineState::Description::DefaultNoDepth;
|
||||
@@ -533,11 +534,11 @@ bool ShadowsPass::setupResources()
|
||||
psDesc.DepthEnable = true;
|
||||
psDesc.DepthBoundsEnable = _depthBounds;
|
||||
psDesc.CullMode = CullMode::Normal;
|
||||
if (_psShadowPoint.Create(psDesc, shader, "PS_PointLight"))
|
||||
if (_psShadowPoint.Create(psDesc, shader, psLocalLight))
|
||||
return true;
|
||||
psDesc.DepthFunc = ComparisonFunc::Greater;
|
||||
psDesc.CullMode = CullMode::Inverted;
|
||||
if (_psShadowPointInside.Create(psDesc, shader, "PS_PointLight"))
|
||||
if (_psShadowPointInside.Create(psDesc, shader, psLocalLight))
|
||||
return true;
|
||||
}
|
||||
if (!_psShadowSpot.IsValid())
|
||||
@@ -548,11 +549,11 @@ bool ShadowsPass::setupResources()
|
||||
psDesc.DepthEnable = true;
|
||||
psDesc.DepthBoundsEnable = _depthBounds;
|
||||
psDesc.CullMode = CullMode::Normal;
|
||||
if (_psShadowSpot.Create(psDesc, shader, "PS_SpotLight"))
|
||||
if (_psShadowSpot.Create(psDesc, shader, psLocalLight, 8))
|
||||
return true;
|
||||
psDesc.DepthFunc = ComparisonFunc::Greater;
|
||||
psDesc.CullMode = CullMode::Inverted;
|
||||
if (_psShadowSpotInside.Create(psDesc, shader, "PS_SpotLight"))
|
||||
if (_psShadowSpotInside.Create(psDesc, shader, psLocalLight, 8))
|
||||
return true;
|
||||
}
|
||||
if (_psDepthClear == nullptr)
|
||||
|
||||
@@ -209,7 +209,7 @@ float4 PS_Lighting(AtlasVertexOutput input) : SV_Target
|
||||
|
||||
// Calculate lighting
|
||||
#if RADIAL_LIGHT
|
||||
bool isSpotLight = Light.SpotAngles.x > -2.0f;
|
||||
bool isSpotLight = IsSpotLight(Light);
|
||||
#else
|
||||
bool isSpotLight = false;
|
||||
#endif
|
||||
|
||||
@@ -58,6 +58,11 @@ struct LightSample
|
||||
float3 Transmission;
|
||||
};
|
||||
|
||||
bool IsSpotLight(LightData lightData)
|
||||
{
|
||||
return lightData.SpotAngles.x > -2.0f;
|
||||
}
|
||||
|
||||
// Calculates radial light (point or spot) attenuation factors (distance, spot and radius mask)
|
||||
void GetRadialLightAttenuation(
|
||||
LightData lightData,
|
||||
|
||||
@@ -70,13 +70,13 @@ void PS_Directional(Quad_VS2PS input, out float4 output : SV_Target0)
|
||||
output = GetLighting(gBufferData.ViewPos, Light, gBuffer, shadowMask, false, false);
|
||||
}
|
||||
|
||||
// Pixel shader for point light rendering
|
||||
// Pixel shader for point/spot light rendering
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
META_PERMUTATION_2(LIGHTING_NO_SPECULAR=0, USE_IES_PROFILE=0)
|
||||
META_PERMUTATION_2(LIGHTING_NO_SPECULAR=1, USE_IES_PROFILE=0)
|
||||
META_PERMUTATION_2(LIGHTING_NO_SPECULAR=0, USE_IES_PROFILE=1)
|
||||
META_PERMUTATION_2(LIGHTING_NO_SPECULAR=1, USE_IES_PROFILE=1)
|
||||
void PS_Point(Model_VS2PS input, out float4 output : SV_Target0)
|
||||
void PS_LocalLight(Model_VS2PS input, out float4 output : SV_Target0)
|
||||
{
|
||||
output = 0;
|
||||
|
||||
@@ -103,48 +103,7 @@ void PS_Point(Model_VS2PS input, out float4 output : SV_Target0)
|
||||
}
|
||||
|
||||
// Calculate lighting
|
||||
output = GetLighting(gBufferData.ViewPos, Light, gBuffer, shadowMask, true, false);
|
||||
|
||||
// Apply IES texture
|
||||
#if USE_IES_PROFILE
|
||||
output *= ComputeLightProfileMultiplier(IESTexture, gBuffer.WorldPos, Light.Position, -Light.Direction);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Pixel shader for spot light rendering
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
META_PERMUTATION_2(LIGHTING_NO_SPECULAR=0, USE_IES_PROFILE=0)
|
||||
META_PERMUTATION_2(LIGHTING_NO_SPECULAR=1, USE_IES_PROFILE=0)
|
||||
META_PERMUTATION_2(LIGHTING_NO_SPECULAR=0, USE_IES_PROFILE=1)
|
||||
META_PERMUTATION_2(LIGHTING_NO_SPECULAR=1, USE_IES_PROFILE=1)
|
||||
void PS_Spot(Model_VS2PS input, out float4 output : SV_Target0)
|
||||
{
|
||||
output = 0;
|
||||
|
||||
// Obtain UVs corresponding to the current pixel
|
||||
float2 uv = (input.ScreenPos.xy / input.ScreenPos.w) * float2(0.5, -0.5) + float2(0.5, 0.5);
|
||||
|
||||
// Sample GBuffer
|
||||
GBufferData gBufferData = GetGBufferData();
|
||||
GBufferSample gBuffer = SampleGBuffer(gBufferData, uv);
|
||||
|
||||
// Check if cannot shadow pixel
|
||||
BRANCH
|
||||
if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT)
|
||||
{
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
// Sample shadow mask
|
||||
float4 shadowMask = 1;
|
||||
if (Light.ShadowsBufferAddress != 0)
|
||||
{
|
||||
shadowMask = SAMPLE_RT(Shadow, uv);
|
||||
}
|
||||
|
||||
// Calculate lighting
|
||||
output = GetLighting(gBufferData.ViewPos, Light, gBuffer, shadowMask, true, true);
|
||||
output = GetLighting(gBufferData.ViewPos, Light, gBuffer, shadowMask, true, IsSpotLight(Light));
|
||||
|
||||
// Apply IES texture
|
||||
#if USE_IES_PROFILE
|
||||
|
||||
@@ -70,36 +70,6 @@ Model_VS2PS VS_Model(ModelInput_PosOnly input)
|
||||
return output;
|
||||
}
|
||||
|
||||
// Pixel shader for point light shadow rendering
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=0,CONTACT_SHADOWS=0)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=1,CONTACT_SHADOWS=0)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=2,CONTACT_SHADOWS=0)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=3,CONTACT_SHADOWS=0)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=0,CONTACT_SHADOWS=1)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=1,CONTACT_SHADOWS=1)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=2,CONTACT_SHADOWS=1)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=3,CONTACT_SHADOWS=1)
|
||||
float4 PS_PointLight(Model_VS2PS input) : SV_Target0
|
||||
{
|
||||
// Obtain texture coordinates corresponding to the current pixel
|
||||
float2 uv = (input.ScreenPos.xy / input.ScreenPos.w) * float2(0.5, -0.5) + float2(0.5, 0.5);
|
||||
|
||||
// Sample GBuffer
|
||||
GBufferData gBufferData = GetGBufferData();
|
||||
GBufferSample gBuffer = SampleGBuffer(gBufferData, uv);
|
||||
|
||||
// Sample shadow
|
||||
ShadowSample shadow = SamplePointLightShadow(Light, ShadowsBuffer, ShadowMap, gBuffer);
|
||||
|
||||
#if CONTACT_SHADOWS && SHADOWS_QUALITY > 0
|
||||
// Calculate screen-space contact shadow
|
||||
shadow.SurfaceShadow *= RayCastScreenSpaceShadow(gBufferData, gBuffer, gBuffer.WorldPos, normalize(Light.Position - gBuffer.WorldPos), ContactShadowsLength);
|
||||
#endif
|
||||
|
||||
return GetShadowMask(shadow);
|
||||
}
|
||||
|
||||
// Pixel shader for directional light shadow rendering
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=0,CONTACT_SHADOWS=0,SHADOWS_CSM_BLENDING=0)
|
||||
@@ -135,17 +105,25 @@ float4 PS_DirLight(Quad_VS2PS input) : SV_Target0
|
||||
return GetShadowMask(shadow);
|
||||
}
|
||||
|
||||
// Pixel shader for spot light shadow rendering
|
||||
// Pixel shader for point/spot light shadow rendering
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=0,CONTACT_SHADOWS=0)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=1,CONTACT_SHADOWS=0)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=2,CONTACT_SHADOWS=0)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=3,CONTACT_SHADOWS=0)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=0,CONTACT_SHADOWS=1)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=1,CONTACT_SHADOWS=1)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=2,CONTACT_SHADOWS=1)
|
||||
META_PERMUTATION_2(SHADOWS_QUALITY=3,CONTACT_SHADOWS=1)
|
||||
float4 PS_SpotLight(Model_VS2PS input) : SV_Target0
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=0,CONTACT_SHADOWS=0,LIGHT_TYPE=0) // Point light
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=1,CONTACT_SHADOWS=0,LIGHT_TYPE=0)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=2,CONTACT_SHADOWS=0,LIGHT_TYPE=0)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=3,CONTACT_SHADOWS=0,LIGHT_TYPE=0)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=0,CONTACT_SHADOWS=1,LIGHT_TYPE=0)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=1,CONTACT_SHADOWS=1,LIGHT_TYPE=0)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=2,CONTACT_SHADOWS=1,LIGHT_TYPE=0)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=3,CONTACT_SHADOWS=1,LIGHT_TYPE=0)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=0,CONTACT_SHADOWS=0,LIGHT_TYPE=1) // Spot light
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=1,CONTACT_SHADOWS=0,LIGHT_TYPE=1)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=2,CONTACT_SHADOWS=0,LIGHT_TYPE=1)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=3,CONTACT_SHADOWS=0,LIGHT_TYPE=1)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=0,CONTACT_SHADOWS=1,LIGHT_TYPE=1)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=1,CONTACT_SHADOWS=1,LIGHT_TYPE=1)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=2,CONTACT_SHADOWS=1,LIGHT_TYPE=1)
|
||||
META_PERMUTATION_3(SHADOWS_QUALITY=3,CONTACT_SHADOWS=1,LIGHT_TYPE=1)
|
||||
float4 PS_LocalLight(Model_VS2PS input) : SV_Target0
|
||||
{
|
||||
// Obtain texture coordinates corresponding to the current pixel
|
||||
float2 uv = (input.ScreenPos.xy / input.ScreenPos.w) * float2(0.5, -0.5) + float2(0.5, 0.5);
|
||||
@@ -155,7 +133,13 @@ float4 PS_SpotLight(Model_VS2PS input) : SV_Target0
|
||||
GBufferSample gBuffer = SampleGBuffer(gBufferData, uv);
|
||||
|
||||
// Sample shadow
|
||||
#if LIGHT_TYPE == 0
|
||||
ShadowSample shadow = SamplePointLightShadow(Light, ShadowsBuffer, ShadowMap, gBuffer);
|
||||
#elif LIGHT_TYPE == 1
|
||||
ShadowSample shadow = SampleSpotLightShadow(Light, ShadowsBuffer, ShadowMap, gBuffer);
|
||||
#else
|
||||
ShadowSample shadow = (ShadowSample)0;
|
||||
#endif
|
||||
|
||||
#if CONTACT_SHADOWS && SHADOWS_QUALITY > 0
|
||||
// Calculate screen-space contact shadow
|
||||
|
||||
@@ -175,7 +175,7 @@ float4 PS_InjectLight(Quad_GS2PS input) : SV_Target0
|
||||
uint samplesCount = historyAlpha < 0.01f ? MissedHistorySamplesCount : 1;
|
||||
|
||||
float NoL = 0;
|
||||
bool isSpotLight = LocalLight.SpotAngles.x > -2.0f;
|
||||
bool isSpotLight = IsSpotLight(LocalLight);
|
||||
float4 scattering = 0;
|
||||
for (uint sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user