Refactor material shaders generator to use modular features as extensions

This commit is contained in:
Wojtek Figat
2021-02-05 11:22:47 +01:00
parent b5847eb0d6
commit 01777a2c1b
16 changed files with 182 additions and 563 deletions

View File

@@ -0,0 +1,123 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
@0// Forward Shading: Defines
#define MAX_LOCAL_LIGHTS 4
@1// Forward Shading: Includes
#include "./Flax/LightingCommon.hlsl"
#if USE_REFLECTIONS
#include "./Flax/ReflectionsCommon.hlsl"
#endif
#include "./Flax/Lighting.hlsl"
#include "./Flax/ShadowsSampling.hlsl"
#include "./Flax/ExponentialHeightFog.hlsl"
@2// Forward Shading: Constants
LightData DirectionalLight;
LightShadowData DirectionalLightShadow;
LightData SkyLight;
ProbeData EnvironmentProbe;
ExponentialHeightFogData ExponentialHeightFog;
float3 Dummy2;
uint LocalLightsCount;
LightData LocalLights[MAX_LOCAL_LIGHTS];
@3// Forward Shading: Resources
TextureCube EnvProbe : register(t__SRV__);
TextureCube SkyLightTexture : register(t__SRV__);
Texture2DArray DirectionalLightShadowMap : register(t__SRV__);
@4// Forward Shading: Utilities
DECLARE_LIGHTSHADOWDATA_ACCESS(DirectionalLightShadow);
@5// Forward Shading: Shaders
// Pixel Shader function for Forward Pass
META_PS(USE_FORWARD, FEATURE_LEVEL_ES2)
float4 PS_Forward(PixelInput input) : SV_Target0
{
float4 output = 0;
#if USE_DITHERED_LOD_TRANSITION
// LOD masking
ClipLODTransition(input);
#endif
// Get material parameters
MaterialInput materialInput = GetMaterialInput(input);
Material material = GetMaterialPS(materialInput);
// Masking
#if MATERIAL_MASKED
clip(material.Mask - MATERIAL_MASK_THRESHOLD);
#endif
// Add emissive light
output = float4(material.Emissive, material.Opacity);
#if MATERIAL_SHADING_MODEL != SHADING_MODEL_UNLIT
// Setup GBuffer data as proxy for lighting
GBufferSample gBuffer;
gBuffer.Normal = material.WorldNormal;
gBuffer.Roughness = material.Roughness;
gBuffer.Metalness = material.Metalness;
gBuffer.Color = material.Color;
gBuffer.Specular = material.Specular;
gBuffer.AO = material.AO;
gBuffer.ViewPos = mul(float4(materialInput.WorldPosition, 1), ViewMatrix).xyz;
#if MATERIAL_SHADING_MODEL == SHADING_MODEL_SUBSURFACE
gBuffer.CustomData = float4(material.SubsurfaceColor, material.Opacity);
#elif MATERIAL_SHADING_MODEL == SHADING_MODEL_FOLIAGE
gBuffer.CustomData = float4(material.SubsurfaceColor, material.Opacity);
#else
gBuffer.CustomData = float4(0, 0, 0, 0);
#endif
gBuffer.WorldPos = materialInput.WorldPosition;
gBuffer.ShadingModel = MATERIAL_SHADING_MODEL;
// Calculate lighting from a single directional light
float4 shadowMask = 1.0f;
if (DirectionalLight.CastShadows > 0)
{
LightShadowData directionalLightShadowData = GetDirectionalLightShadowData();
shadowMask.r = SampleShadow(DirectionalLight, directionalLightShadowData, DirectionalLightShadowMap, gBuffer, shadowMask.g);
}
float4 light = GetLighting(ViewPos, DirectionalLight, gBuffer, shadowMask, false, false);
// Calculate lighting from sky light
light += GetSkyLightLighting(SkyLight, gBuffer, SkyLightTexture);
// Calculate lighting from local lights
LOOP
for (uint localLightIndex = 0; localLightIndex < LocalLightsCount; localLightIndex++)
{
const LightData localLight = LocalLights[localLightIndex];
bool isSpotLight = localLight.SpotAngles.x > -2.0f;
shadowMask = 1.0f;
light += GetLighting(ViewPos, localLight, gBuffer, shadowMask, true, isSpotLight);
}
#if USE_REFLECTIONS
// Calculate reflections
light.rgb += GetEnvProbeLighting(ViewPos, EnvProbe, EnvironmentProbe, gBuffer) * light.a;
#endif
// Add lighting (apply ambient occlusion)
output.rgb += light.rgb * gBuffer.AO;
#if USE_FOG
// Calculate exponential height fog
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0);
// Apply fog to the output color
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE
output = float4(output.rgb * fog.a + fog.rgb, output.a);
#elif MATERIAL_BLEND == MATERIAL_BLEND_TRANSPARENT
output = float4(output.rgb * fog.a + fog.rgb, output.a);
#elif MATERIAL_BLEND == MATERIAL_BLEND_ADDITIVE
output = float4(output.rgb * fog.a + fog.rgb, output.a * fog.a);
#elif MATERIAL_BLEND == MATERIAL_BLEND_MULTIPLY
output = float4(lerp(float3(1, 1, 1), output.rgb, fog.aaa * fog.aaa), output.a);
#endif
#endif
#endif
return output;
}

View File

@@ -3,7 +3,6 @@
#define MATERIAL 1
@3
#include "./Flax/Common.hlsl"
#include "./Flax/MaterialCommon.hlsl"
#include "./Flax/GBufferCommon.hlsl"
@@ -22,7 +21,7 @@ float4 ViewInfo;
float4 ScreenSize;
@1META_CB_END
// Material shader resources
// Shader resources
@2
// Interpolants passed from the vertex shader
struct VertexOutput

View File

@@ -2,19 +2,13 @@
// Version: @0
#define MATERIAL 1
#define MAX_LOCAL_LIGHTS 4
@3
// Ribbons don't use sorted indices so overlap the segment distances buffer on the slot
#define HAS_SORTED_INDICES (!defined(_VS_Ribbon))
#include "./Flax/Common.hlsl"
#include "./Flax/MaterialCommon.hlsl"
#include "./Flax/GBufferCommon.hlsl"
#include "./Flax/LightingCommon.hlsl"
#if USE_REFLECTIONS
#include "./Flax/ReflectionsCommon.hlsl"
#endif
#include "./Flax/Lighting.hlsl"
#include "./Flax/ShadowsSampling.hlsl"
#include "./Flax/ExponentialHeightFog.hlsl"
#include "./Flax/Matrix.hlsl"
@7
struct SpriteInput
@@ -55,44 +49,19 @@ uint RibbonSegmentCount;
float4x4 WorldMatrixInverseTransposed;
@1META_CB_END
// Secondary constantant buffer (for lighting)
META_CB_BEGIN(1, LightingData)
LightData DirectionalLight;
LightShadowData DirectionalLightShadow;
LightData SkyLight;
ProbeData EnvironmentProbe;
ExponentialHeightFogData ExponentialHeightFog;
float3 Dummy1;
uint LocalLightsCount;
LightData LocalLights[MAX_LOCAL_LIGHTS];
META_CB_END
DECLARE_LIGHTSHADOWDATA_ACCESS(DirectionalLightShadow);
// Particles attributes buffer
ByteAddressBuffer ParticlesData : register(t0);
// Ribbons don't use sorted indices so overlap the segment distances buffer on the slot
#define HAS_SORTED_INDICES (!defined(_VS_Ribbon))
#if HAS_SORTED_INDICES
// Sorted particles indices
Buffer<uint> SortedIndices : register(t1);
#else
// Ribbon particles segments distances buffer
Buffer<float> SegmentDistances : register(t1);
#endif
// Shader resources
TextureCube EnvProbe : register(t2);
TextureCube SkyLightTexture : register(t3);
Texture2DArray DirectionalLightShadowMap : register(t4);
@2
// Interpolants passed from the vertex shader
struct VertexOutput
{
@@ -711,97 +680,6 @@ VertexOutput VS_Ribbon(uint vertexIndex : SV_VertexID)
return output;
}
// Pixel Shader function for Forward Pass
META_PS(USE_FORWARD, FEATURE_LEVEL_ES2)
float4 PS_Forward(PixelInput input) : SV_Target0
{
float4 output = 0;
// Get material parameters
MaterialInput materialInput = GetMaterialInput(input);
Material material = GetMaterialPS(materialInput);
// Masking
#if MATERIAL_MASKED
clip(material.Mask - MATERIAL_MASK_THRESHOLD);
#endif
// Add emissive light
output = float4(material.Emissive, material.Opacity);
#if MATERIAL_SHADING_MODEL != SHADING_MODEL_UNLIT
// Setup GBuffer data as proxy for lighting
GBufferSample gBuffer;
gBuffer.Normal = material.WorldNormal;
gBuffer.Roughness = material.Roughness;
gBuffer.Metalness = material.Metalness;
gBuffer.Color = material.Color;
gBuffer.Specular = material.Specular;
gBuffer.AO = material.AO;
gBuffer.ViewPos = mul(float4(materialInput.WorldPosition, 1), ViewMatrix).xyz;
#if MATERIAL_SHADING_MODEL == SHADING_MODEL_SUBSURFACE
gBuffer.CustomData = float4(material.SubsurfaceColor, material.Opacity);
#elif MATERIAL_SHADING_MODEL == SHADING_MODEL_FOLIAGE
gBuffer.CustomData = float4(material.SubsurfaceColor, material.Opacity);
#else
gBuffer.CustomData = float4(0, 0, 0, 0);
#endif
gBuffer.WorldPos = materialInput.WorldPosition;
gBuffer.ShadingModel = MATERIAL_SHADING_MODEL;
// Calculate lighting from a single directional light
float4 shadowMask = 1.0f;
if (DirectionalLight.CastShadows > 0)
{
LightShadowData directionalLightShadowData = GetDirectionalLightShadowData();
shadowMask.r = SampleShadow(DirectionalLight, directionalLightShadowData, DirectionalLightShadowMap, gBuffer, shadowMask.g);
}
float4 light = GetLighting(ViewPos, DirectionalLight, gBuffer, shadowMask, false, false);
// Calculate lighting from sky light
light += GetSkyLightLighting(SkyLight, gBuffer, SkyLightTexture);
// Calculate lighting from local lights
LOOP
for (uint localLightIndex = 0; localLightIndex < LocalLightsCount; localLightIndex++)
{
const LightData localLight = LocalLights[localLightIndex];
bool isSpotLight = localLight.SpotAngles.x > -2.0f;
shadowMask = 1.0f;
light += GetLighting(ViewPos, localLight, gBuffer, shadowMask, true, isSpotLight);
}
#if USE_REFLECTIONS
// Calculate reflections
light.rgb += GetEnvProbeLighting(ViewPos, EnvProbe, EnvironmentProbe, gBuffer) * light.a;
#endif
// Add lighting (apply ambient occlusion)
output.rgb += light.rgb * gBuffer.AO;
#if USE_FOG
// Calculate exponential height fog
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0);
// Apply fog to the output color
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE
output = float4(output.rgb * fog.a + fog.rgb, output.a);
#elif MATERIAL_BLEND == MATERIAL_BLEND_TRANSPARENT
output = float4(output.rgb * fog.a + fog.rgb, output.a);
#elif MATERIAL_BLEND == MATERIAL_BLEND_ADDITIVE
output = float4(output.rgb * fog.a + fog.rgb, output.a * fog.a);
#elif MATERIAL_BLEND == MATERIAL_BLEND_MULTIPLY
output = float4(lerp(float3(1, 1, 1), output.rgb, fog.aaa * fog.aaa), output.a);
#endif
#endif
#endif
return output;
}
// Pixel Shader function for Depth Pass
META_PS(true, FEATURE_LEVEL_ES2)
void PS_Depth(PixelInput input

View File

@@ -20,7 +20,7 @@ float4 ScreenSize;
float4 TemporalAAJitter;
@1META_CB_END
// Material shader resources
// Shader resources
@2
// Interpolants passed to the pixel shader
struct PixelInput

View File

@@ -30,9 +30,8 @@ float3 GeometrySize;
float Dummy1;
@1META_CB_END
// Material shader resources
// Shader resources
@2
// Geometry data passed though the graphics rendering stages up to the pixel shader
struct GeometryData
{

View File

@@ -2,19 +2,10 @@
// Version: @0
#define MATERIAL 1
#define MAX_LOCAL_LIGHTS 4
@3
#include "./Flax/Common.hlsl"
#include "./Flax/MaterialCommon.hlsl"
#include "./Flax/GBufferCommon.hlsl"
#include "./Flax/LightingCommon.hlsl"
#if USE_REFLECTIONS
#include "./Flax/ReflectionsCommon.hlsl"
#endif
#include "./Flax/Lighting.hlsl"
#include "./Flax/ShadowsSampling.hlsl"
#include "./Flax/ExponentialHeightFog.hlsl"
@7
// Primary constant buffer (with additional material parameters)
META_CB_BEGIN(0, Data)
@@ -38,26 +29,8 @@ float3 GeometrySize;
float Dummy1;
@1META_CB_END
// Secondary constantant buffer (for lighting)
META_CB_BEGIN(1, LightingData)
LightData DirectionalLight;
LightShadowData DirectionalLightShadow;
LightData SkyLight;
ProbeData EnvironmentProbe;
ExponentialHeightFogData ExponentialHeightFog;
float3 Dummy2;
uint LocalLightsCount;
LightData LocalLights[MAX_LOCAL_LIGHTS];
META_CB_END
DECLARE_LIGHTSHADOWDATA_ACCESS(DirectionalLightShadow);
// Shader resources
TextureCube EnvProbe : register(t0);
TextureCube SkyLightTexture : register(t1);
Texture2DArray DirectionalLightShadowMap : register(t2);
@2
// Interpolants passed from the vertex shader
struct VertexOutput
{
@@ -564,103 +537,6 @@ void ClipLODTransition(PixelInput input)
#endif
// Pixel Shader function for Forward Pass
META_PS(USE_FORWARD, FEATURE_LEVEL_ES2)
float4 PS_Forward(PixelInput input) : SV_Target0
{
float4 output = 0;
#if USE_DITHERED_LOD_TRANSITION
// LOD masking
ClipLODTransition(input);
// TODO: make model LOD transition smoother for transparent materials by using opacity to reduce aliasing
#endif
// Get material parameters
MaterialInput materialInput = GetMaterialInput(input);
Material material = GetMaterialPS(materialInput);
// Masking
#if MATERIAL_MASKED
clip(material.Mask - MATERIAL_MASK_THRESHOLD);
#endif
// Add emissive light
output = float4(material.Emissive, material.Opacity);
#if MATERIAL_SHADING_MODEL != SHADING_MODEL_UNLIT
// Setup GBuffer data as proxy for lighting
GBufferSample gBuffer;
gBuffer.Normal = material.WorldNormal;
gBuffer.Roughness = material.Roughness;
gBuffer.Metalness = material.Metalness;
gBuffer.Color = material.Color;
gBuffer.Specular = material.Specular;
gBuffer.AO = material.AO;
gBuffer.ViewPos = mul(float4(materialInput.WorldPosition, 1), ViewMatrix).xyz;
#if MATERIAL_SHADING_MODEL == SHADING_MODEL_SUBSURFACE
gBuffer.CustomData = float4(material.SubsurfaceColor, material.Opacity);
#elif MATERIAL_SHADING_MODEL == SHADING_MODEL_FOLIAGE
gBuffer.CustomData = float4(material.SubsurfaceColor, material.Opacity);
#else
gBuffer.CustomData = float4(0, 0, 0, 0);
#endif
gBuffer.WorldPos = materialInput.WorldPosition;
gBuffer.ShadingModel = MATERIAL_SHADING_MODEL;
// Calculate lighting from a single directional light
float4 shadowMask = 1.0f;
if (DirectionalLight.CastShadows > 0)
{
LightShadowData directionalLightShadowData = GetDirectionalLightShadowData();
shadowMask.r = SampleShadow(DirectionalLight, directionalLightShadowData, DirectionalLightShadowMap, gBuffer, shadowMask.g);
}
float4 light = GetLighting(ViewPos, DirectionalLight, gBuffer, shadowMask, false, false);
// Calculate lighting from sky light
light += GetSkyLightLighting(SkyLight, gBuffer, SkyLightTexture);
// Calculate lighting from local lights
LOOP
for (uint localLightIndex = 0; localLightIndex < LocalLightsCount; localLightIndex++)
{
const LightData localLight = LocalLights[localLightIndex];
bool isSpotLight = localLight.SpotAngles.x > -2.0f;
shadowMask = 1.0f;
light += GetLighting(ViewPos, localLight, gBuffer, shadowMask, true, isSpotLight);
}
#if USE_REFLECTIONS
// Calculate reflections
light.rgb += GetEnvProbeLighting(ViewPos, EnvProbe, EnvironmentProbe, gBuffer) * light.a;
#endif
// Add lighting (apply ambient occlusion)
output.rgb += light.rgb * gBuffer.AO;
#if USE_FOG
// Calculate exponential height fog
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0);
// Apply fog to the output color
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE
output = float4(output.rgb * fog.a + fog.rgb, output.a);
#elif MATERIAL_BLEND == MATERIAL_BLEND_TRANSPARENT
output = float4(output.rgb * fog.a + fog.rgb, output.a);
#elif MATERIAL_BLEND == MATERIAL_BLEND_ADDITIVE
output = float4(output.rgb * fog.a + fog.rgb, output.a * fog.a);
#elif MATERIAL_BLEND == MATERIAL_BLEND_MULTIPLY
output = float4(lerp(float3(1, 1, 1), output.rgb, fog.aaa * fog.aaa), output.a);
#endif
#endif
#endif
return output;
}
// Pixel Shader function for Depth Pass
META_PS(true, FEATURE_LEVEL_ES2)
void PS_Depth(PixelInput input

View File

@@ -42,9 +42,8 @@ Texture2D Heightmap : register(t0);
Texture2D Splatmap0 : register(t1);
Texture2D Splatmap1 : register(t2);
// Material shader resources
// Shader resources
@2
// Geometry data passed though the graphics rendering stages up to the pixel shader
struct GeometryData
{

View File

@@ -4,13 +4,14 @@
#include "MaterialShaderFeatures.h"
#include "MaterialParams.h"
#include "Engine/Engine/Time.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/GPULimits.h"
#include "Engine/Graphics/Models/SkinnedMeshDrawData.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Level/Actors/EnvironmentProbe.h"
#include "Engine/Renderer/DepthOfFieldPass.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/Models/SkinnedMeshDrawData.h"
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/ShadowsPass.h"
#include "Engine/Renderer/RenderList.h"
#if USE_EDITOR
#include "Engine/Renderer/Lightmaps.h"
@@ -39,17 +40,6 @@ PACK_STRUCT(struct ForwardMaterialShaderData {
float Dummy1;
});
PACK_STRUCT(struct ForwardMaterialShaderLightingData {
LightData DirectionalLight;
LightShadowData DirectionalLightShadow;
LightData SkyLight;
ProbeData EnvironmentProbe;
ExponentialHeightFogData ExponentialHeightFog;
Vector3 Dummy2;
uint32 LocalLightsCount;
LightData LocalLights[MAX_LOCAL_LIGHTS];
});
DrawPass ForwardMaterialShader::GetDrawModes() const
{
return _drawModes;
@@ -66,19 +56,17 @@ void ForwardMaterialShader::Bind(BindParameters& params)
// Prepare
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto cache = params.RenderContext.List;
auto& drawCall = *params.FirstDrawCall;
const auto cb0 = _shader->GetCB(0);
const bool hasCb0 = cb0 && cb0->GetSize() != 0;
ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing
const auto cb1 = _shader->GetCB(1);
const bool hasCb1 = cb1 && cb1->GetSize() != 0;
byte* cb = _cb0Data.Get();
auto materialData = reinterpret_cast<ForwardMaterialShaderData*>(cb);
cb += sizeof(ForwardMaterialShaderData);
int32 srv = 0;
// Setup features
ForwardShadingFeature::Bind(params, cb, srv);
// Setup parameters
MaterialParameter::BindMeta bindMeta;
@@ -131,124 +119,12 @@ void ForwardMaterialShader::Bind(BindParameters& params)
materialData->GeometrySize = drawCall.Surface.GeometrySize;
}
// Setup lighting constants data
if (hasCb1)
{
auto& lightingData = *reinterpret_cast<ForwardMaterialShaderLightingData*>(_cb1Data.Get());
const int32 envProbeShaderRegisterIndex = 0;
const int32 skyLightShaderRegisterIndex = 1;
const int32 dirLightShaderRegisterIndex = 2;
// Set fog input
if (cache->Fog)
{
cache->Fog->GetExponentialHeightFogData(view, lightingData.ExponentialHeightFog);
}
else
{
lightingData.ExponentialHeightFog.FogMinOpacity = 1.0f;
lightingData.ExponentialHeightFog.ApplyDirectionalInscattering = 0.0f;
}
// Set directional light input
if (cache->DirectionalLights.HasItems())
{
const auto& dirLight = cache->DirectionalLights.First();
const auto shadowPass = ShadowsPass::Instance();
const bool useShadow = shadowPass->LastDirLightIndex == 0;
if (useShadow)
{
lightingData.DirectionalLightShadow = shadowPass->LastDirLight;
context->BindSR(dirLightShaderRegisterIndex, shadowPass->LastDirLightShadowMap);
}
else
{
context->UnBindSR(dirLightShaderRegisterIndex);
}
dirLight.SetupLightData(&lightingData.DirectionalLight, view, useShadow);
}
else
{
lightingData.DirectionalLight.Color = Vector3::Zero;
lightingData.DirectionalLight.CastShadows = 0.0f;
context->UnBindSR(dirLightShaderRegisterIndex);
}
// Set sky light
if (cache->SkyLights.HasItems())
{
auto& skyLight = cache->SkyLights.First();
skyLight.SetupLightData(&lightingData.SkyLight, view, false);
const auto texture = skyLight.Image ? skyLight.Image->GetTexture() : nullptr;
context->BindSR(skyLightShaderRegisterIndex, GET_TEXTURE_VIEW_SAFE(texture));
}
else
{
Platform::MemoryClear(&lightingData.SkyLight, sizeof(lightingData.SkyLight));
context->UnBindSR(skyLightShaderRegisterIndex);
}
// Set reflection probe data
EnvironmentProbe* probe = nullptr;
// TODO: optimize env probe searching for a transparent material - use spatial cache for renderer to find it
for (int32 i = 0; i < cache->EnvironmentProbes.Count(); i++)
{
const auto p = cache->EnvironmentProbes[i];
if (p->GetSphere().Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
probe = p;
break;
}
}
if (probe && probe->GetProbe())
{
probe->SetupProbeData(&lightingData.EnvironmentProbe);
const auto texture = probe->GetProbe()->GetTexture();
context->BindSR(envProbeShaderRegisterIndex, GET_TEXTURE_VIEW_SAFE(texture));
}
else
{
lightingData.EnvironmentProbe.Data1 = Vector4::Zero;
context->UnBindSR(envProbeShaderRegisterIndex);
}
// Set local lights
lightingData.LocalLightsCount = 0;
for (int32 i = 0; i < cache->PointLights.Count(); i++)
{
const auto& light = cache->PointLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
lightingData.LocalLightsCount++;
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
break;
}
}
for (int32 i = 0; i < cache->SpotLights.Count(); i++)
{
const auto& light = cache->SpotLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
lightingData.LocalLightsCount++;
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
break;
}
}
}
// Bind constants
if (hasCb0)
{
context->UpdateCB(cb0, _cb0Data.Get());
context->BindCB(0, cb0);
}
if (hasCb1)
{
context->UpdateCB(cb1, _cb1Data.Get());
context->BindCB(1, cb1);
}
// Select pipeline state based on current pass and render mode
const bool wireframe = (_info.FeaturesFlags & MaterialFeaturesFlags::Wireframe) != 0 || view.Mode == ViewMode::Wireframe;

View File

@@ -143,11 +143,6 @@ bool MaterialShader::Load(MemoryReadStream& shaderCacheStream, const MaterialInf
{
_cb0Data.Resize(cb0->GetSize(), false);
}
const auto cb1 = _shader->GetCB(1);
if (cb1)
{
_cb1Data.Resize(cb1->GetSize(), false);
}
// Initialize the material based on type (create pipeline states and setup)
if (Load())
@@ -163,6 +158,5 @@ void MaterialShader::Unload()
{
_isLoaded = false;
_cb0Data.Resize(0, false);
_cb1Data.Resize(0, false);
_shader->ReleaseGPU();
}

View File

@@ -53,7 +53,6 @@ protected:
bool _isLoaded;
GPUShader* _shader;
Array<byte> _cb0Data;
Array<byte> _cb1Data;
MaterialInfo _info;
protected:

View File

@@ -155,23 +155,30 @@ bool LightmapFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, in
#if USE_EDITOR
void ForwardShadingFeature::Generate(GeneratorData& data)
{
data.Template = TEXT("Features/ForwardShading.hlsl");
data.ConstantsSize = sizeof(Data);
data.ResourcesCount = SRVs;
}
void TessellationFeature::Generate(GeneratorData& data)
{
data.Template = TEXT("Tessellation.hlsl");
data.Template = TEXT("Features/Tessellation.hlsl");
data.ConstantsSize = 0;
data.ResourcesCount = 0;
}
void LightmapFeature::Generate(GeneratorData& data)
{
data.Template = TEXT("Lightmap.hlsl");
data.Template = TEXT("Features/Lightmap.hlsl");
data.ConstantsSize = sizeof(Data);
data.ResourcesCount = SRVs;
}
void DistortionFeature::Generate(GeneratorData& data)
{
data.Template = TEXT("Distortion.hlsl");
data.Template = TEXT("Features/Distortion.hlsl");
data.ConstantsSize = 0;
data.ResourcesCount = 0;
}

View File

@@ -38,6 +38,9 @@ struct ForwardShadingFeature : MaterialShaderFeature
});
static void Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv);
#if USE_EDITOR
static void Generate(GeneratorData& data);
#endif
};
// Material shader feature that adds geometry hardware tessellation (using Hull and Domain shaders).

View File

@@ -1,20 +1,19 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "ParticleMaterialShader.h"
#include "MaterialShaderFeatures.h"
#include "MaterialParams.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/ShadowsPass.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
#include "Engine/Engine/Time.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Graphics/GPULimits.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
#include "Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h"
#include "Engine/Content/Assets/CubeTexture.h"
#include "Engine/Level/Actors/EnvironmentProbe.h"
#define MAX_LOCAL_LIGHTS 4
@@ -49,17 +48,6 @@ PACK_STRUCT(struct ParticleMaterialShaderData {
Matrix WorldMatrixInverseTransposed;
});
PACK_STRUCT(struct ParticleMaterialShaderLightingData {
LightData DirectionalLight;
LightShadowData DirectionalLightShadow;
LightData SkyLight;
ProbeData EnvironmentProbe;
ExponentialHeightFogData ExponentialHeightFog;
Vector3 Dummy1;
uint32 LocalLightsCount;
LightData LocalLights[MAX_LOCAL_LIGHTS];
});
DrawPass ParticleMaterialShader::GetDrawModes() const
{
return _drawModes;
@@ -70,20 +58,18 @@ void ParticleMaterialShader::Bind(BindParameters& params)
// Prepare
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto cache = params.RenderContext.List;
auto& drawCall = *params.FirstDrawCall;
const uint32 sortedIndicesOffset = drawCall.Particle.Module->SortedIndicesOffset;
const auto cb0 = _shader->GetCB(0);
const bool hasCb0 = cb0->GetSize() != 0;
ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing
const auto cb1 = _shader->GetCB(1);
const bool hasCb1 = cb1 && cb1->GetSize() != 0;
byte* cb = _cb0Data.Get();
auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(cb);
cb += sizeof(ParticleMaterialShaderData);
int32 srv = 0;
int32 srv = 2;
// Setup features
ForwardShadingFeature::Bind(params, cb, srv);
// Setup parameters
MaterialParameter::BindMeta bindMeta;
@@ -95,25 +81,23 @@ void ParticleMaterialShader::Bind(BindParameters& params)
bindMeta.CanSampleGBuffer = true;
MaterialParams::Bind(params.ParamsLink, bindMeta);
// Setup particles data and attributes binding info
// Setup particles data
context->BindSR(0, drawCall.Particle.Particles->GPU.Buffer->View());
context->BindSR(1, drawCall.Particle.Particles->GPU.SortedIndices ? drawCall.Particle.Particles->GPU.SortedIndices->View() : nullptr);
// Setup particles attributes binding info
if (hasCb0)
{
context->BindSR(0, drawCall.Particle.Particles->GPU.Buffer->View());
if (drawCall.Particle.Particles->GPU.SortedIndices)
context->BindSR(1, drawCall.Particle.Particles->GPU.SortedIndices->View());
if (hasCb0)
const auto& p = *params.ParamsLink->This;
for (int32 i = 0; i < p.Count(); i++)
{
const auto& p = *params.ParamsLink->This;
for (int32 i = 0; i < p.Count(); i++)
const auto& param = p.At(i);
if (param.GetParameterType() == MaterialParameterType::Integer && param.GetName().StartsWith(TEXT("Particle.")))
{
const auto& param = p.At(i);
if (param.GetParameterType() == MaterialParameterType::Integer && param.GetName().StartsWith(TEXT("Particle.")))
{
auto name = StringView(param.GetName().Get() + 9);
auto name = StringView(param.GetName().Get() + 9);
const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
*((int32*)(bindMeta.Constants + param.GetBindOffset())) = offset;
}
const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
*((int32*)(bindMeta.Constants + param.GetBindOffset())) = offset;
}
}
}
@@ -147,8 +131,6 @@ void ParticleMaterialShader::Bind(BindParameters& params)
if (hasCb0)
{
const auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(_cb0Data.Get());
materialData->RibbonWidthOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonWidth, ParticleAttribute::ValueTypes::Float, -1);
materialData->RibbonTwistOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonTwist, ParticleAttribute::ValueTypes::Float, -1);
materialData->RibbonFacingVectorOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonFacingVector, ParticleAttribute::ValueTypes::Vector3, -1);
@@ -173,8 +155,6 @@ void ParticleMaterialShader::Bind(BindParameters& params)
// Setup material constants data
if (hasCb0)
{
const auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(_cb0Data.Get());
static StringView ParticlePosition(TEXT("Position"));
static StringView ParticleSpriteSize(TEXT("SpriteSize"));
static StringView ParticleSpriteFacingMode(TEXT("SpriteFacingMode"));
@@ -207,124 +187,12 @@ void ParticleMaterialShader::Bind(BindParameters& params)
Matrix::Invert(drawCall.World, materialData->WorldMatrixInverseTransposed);
}
// Setup lighting constants data
if (hasCb1)
{
auto& lightingData = *reinterpret_cast<ParticleMaterialShaderLightingData*>(_cb1Data.Get());
const int32 envProbeShaderRegisterIndex = 2;
const int32 skyLightShaderRegisterIndex = 3;
const int32 dirLightShaderRegisterIndex = 4;
// Set fog input
if (cache->Fog)
{
cache->Fog->GetExponentialHeightFogData(view, lightingData.ExponentialHeightFog);
}
else
{
lightingData.ExponentialHeightFog.FogMinOpacity = 1.0f;
lightingData.ExponentialHeightFog.ApplyDirectionalInscattering = 0.0f;
}
// Set directional light input
if (cache->DirectionalLights.HasItems())
{
const auto& dirLight = cache->DirectionalLights.First();
const auto shadowPass = ShadowsPass::Instance();
const bool useShadow = shadowPass->LastDirLightIndex == 0;
if (useShadow)
{
lightingData.DirectionalLightShadow = shadowPass->LastDirLight;
context->BindSR(dirLightShaderRegisterIndex, shadowPass->LastDirLightShadowMap);
}
else
{
context->UnBindSR(dirLightShaderRegisterIndex);
}
dirLight.SetupLightData(&lightingData.DirectionalLight, view, useShadow);
}
else
{
lightingData.DirectionalLight.Color = Vector3::Zero;
lightingData.DirectionalLight.CastShadows = 0.0f;
context->UnBindSR(dirLightShaderRegisterIndex);
}
// Set sky light
if (cache->SkyLights.HasItems())
{
auto& skyLight = cache->SkyLights.Last();
skyLight.SetupLightData(&lightingData.SkyLight, view, false);
const auto texture = skyLight.Image ? skyLight.Image->GetTexture() : nullptr;
context->BindSR(skyLightShaderRegisterIndex, texture);
}
else
{
Platform::MemoryClear(&lightingData.SkyLight, sizeof(lightingData.SkyLight));
context->UnBindSR(skyLightShaderRegisterIndex);
}
// Set reflection probe data
EnvironmentProbe* probe = nullptr;
// TODO: optimize env probe searching for a transparent material - use spatial cache for renderer to find it
for (int32 i = 0; i < cache->EnvironmentProbes.Count(); i++)
{
const auto p = cache->EnvironmentProbes[i];
if (p->GetSphere().Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
probe = p;
break;
}
}
if (probe && probe->GetProbe())
{
probe->SetupProbeData(&lightingData.EnvironmentProbe);
const auto texture = probe->GetProbe()->GetTexture();
context->BindSR(envProbeShaderRegisterIndex, texture);
}
else
{
lightingData.EnvironmentProbe.Data1 = Vector4::Zero;
context->UnBindSR(envProbeShaderRegisterIndex);
}
// Set local lights
lightingData.LocalLightsCount = 0;
for (int32 i = 0; i < cache->PointLights.Count(); i++)
{
const auto& light = cache->PointLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
lightingData.LocalLightsCount++;
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
break;
}
}
for (int32 i = 0; i < cache->SpotLights.Count(); i++)
{
const auto& light = cache->SpotLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
lightingData.LocalLightsCount++;
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
break;
}
}
}
// Bind constants
if (hasCb0)
{
context->UpdateCB(cb0, _cb0Data.Get());
context->BindCB(0, cb0);
}
if (hasCb1)
{
context->UpdateCB(cb1, _cb1Data.Get());
context->BindCB(1, cb1);
}
// Bind pipeline
context->SetState(state);

View File

@@ -26,7 +26,6 @@ void PostFxMaterialShader::Bind(BindParameters& params)
// Prepare
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall;
const auto cb0 = _shader->GetCB(0);
const bool hasCb0 = cb0->GetSize() != 0;

View File

@@ -1,16 +1,16 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "GPUShaderDX11.h"
#if GRAPHICS_API_DIRECTX11
#include "GPUContextDX11.h"
#include "Engine/Core/Math/Viewport.h"
#include "Engine/Core/Math/Rectangle.h"
#include "GPUShaderDX11.h"
#include "GPUShaderProgramDX11.h"
#include "GPUPipelineStateDX11.h"
#include "GPUTextureDX11.h"
#include "GPUBufferDX11.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
#include "Engine/Core/Math/Viewport.h"
#include "Engine/Core/Math/Rectangle.h"
#include "Engine/Profiler/RenderStats.h"
#define DX11_CLEAR_SR_ON_STAGE_DISABLE 0

View File

@@ -59,7 +59,7 @@ namespace
bool FeatureData::Init()
{
// Load template file
const String path = Globals::EngineContentFolder / TEXT("Editor/MaterialTemplates/Features/") + Data.Template;
const String path = Globals::EngineContentFolder / TEXT("Editor/MaterialTemplates/") + Data.Template;
String contents;
if (File::ReadAllText(path, contents))
{
@@ -188,17 +188,20 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
ADD_FEATURE(LightmapFeature);
if (materialInfo.BlendMode != MaterialBlendMode::Opaque && (materialInfo.FeaturesFlags & MaterialFeaturesFlags::DisableDistortion) == 0)
ADD_FEATURE(DistortionFeature);
if (materialInfo.BlendMode != MaterialBlendMode::Opaque)
ADD_FEATURE(ForwardShadingFeature);
break;
case MaterialDomain::Terrain:
if (materialInfo.TessellationMode != TessellationMethod::None)
ADD_FEATURE(TessellationFeature);
ADD_FEATURE(LightmapFeature);
break;
default:
case MaterialDomain::Particle:
if (materialInfo.BlendMode != MaterialBlendMode::Opaque && (materialInfo.FeaturesFlags & MaterialFeaturesFlags::DisableDistortion) == 0)
ADD_FEATURE(DistortionFeature);
ADD_FEATURE(ForwardShadingFeature);
break;
default:
break;
}
#undef ADD_FEATURE
@@ -390,18 +393,14 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
int32 srv = 0;
switch (baseLayer->Domain)
{
case MaterialDomain::Surface:
if (materialInfo.BlendMode != MaterialBlendMode::Opaque)
srv = 3; // Forward shading resources
break;
case MaterialDomain::Decal:
srv = 1;
srv = 1; // Depth buffer
break;
case MaterialDomain::Terrain:
srv = 3; // Heightmap + 2 splatmaps
break;
case MaterialDomain::Particle:
srv = 5;
srv = 2; // Particles data + Sorted indices/Ribbon segments
break;
}
for (auto f : features)