Add Material Complexity debug view model
This commit is contained in:
BIN
Content/Editor/DebugMaterials/Single Color Decal.flax
(Stored with Git LFS)
Normal file
BIN
Content/Editor/DebugMaterials/Single Color Decal.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/Editor/DebugMaterials/Single Color Particle.flax
(Stored with Git LFS)
Normal file
BIN
Content/Editor/DebugMaterials/Single Color Particle.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/Editor/DebugMaterials/Single Color Surface Additive.flax
(Stored with Git LFS)
Normal file
BIN
Content/Editor/DebugMaterials/Single Color Surface Additive.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/Editor/DebugMaterials/Single Color Surface.flax
(Stored with Git LFS)
Normal file
BIN
Content/Editor/DebugMaterials/Single Color Surface.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/Editor/DebugMaterials/Single Color Terrain.flax
(Stored with Git LFS)
Normal file
BIN
Content/Editor/DebugMaterials/Single Color Terrain.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/Shaders/Editor/MaterialComplexity.flax
(Stored with Git LFS)
Normal file
BIN
Content/Shaders/Editor/MaterialComplexity.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -1398,6 +1398,7 @@ namespace FlaxEditor.Viewport
|
||||
new ViewModeOptions(ViewMode.VertexColors, "Vertex Colors"),
|
||||
new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders"),
|
||||
new ViewModeOptions(ViewMode.LODPreview, "LOD Preview"),
|
||||
new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity"),
|
||||
};
|
||||
|
||||
private void WidgetCamSpeedShowHide(Control cm)
|
||||
|
||||
@@ -818,6 +818,11 @@ API_ENUM() enum class ViewMode
|
||||
/// Draw Level Of Detail number as colors to debug LOD switches.
|
||||
/// </summary>
|
||||
LODPreview = 21,
|
||||
|
||||
/// <summary>
|
||||
/// Draw material shaders complexity to visualize performance of pixels rendering.
|
||||
/// </summary>
|
||||
MaterialComplexity = 22,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -56,6 +56,23 @@ bool GPUPipelineState::Init(const Description& desc)
|
||||
CHECK_STAGE(PS);
|
||||
#undef CHECK_STAGE
|
||||
|
||||
#if USE_EDITOR
|
||||
// Estimate somehow performance cost of this pipeline state for the content profiling
|
||||
const int32 textureLookupCost = 20;
|
||||
const int32 tessCost = 300;
|
||||
Complexity = Utilities::CountBits(_meta.UsedSRsMask) * textureLookupCost;
|
||||
if (desc.PS)
|
||||
Complexity += desc.PS->GetBindings().InstructionsCount;
|
||||
if (desc.HS || desc.DS)
|
||||
Complexity += tessCost;
|
||||
if (desc.DepthWriteEnable)
|
||||
Complexity += 5;
|
||||
if (desc.DepthTestEnable)
|
||||
Complexity += 5;
|
||||
if (desc.BlendMode.BlendEnable)
|
||||
Complexity += 20;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,9 @@ public:
|
||||
/// </summary>
|
||||
Description DebugDesc;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
int32 Complexity;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@@ -49,6 +49,9 @@ API_ENUM() enum class MaterialDomain : byte
|
||||
/// The particle shader used for volumetric effects rendering such as Volumetric Fog.
|
||||
/// </summary>
|
||||
VolumeParticle = 7,
|
||||
|
||||
API_ENUM(Attributes="HideInEditor")
|
||||
MAX
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -11,19 +11,20 @@
|
||||
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
|
||||
PACK_STRUCT(struct LODPreviewMaterialShaderData {
|
||||
PACK_STRUCT(struct SingleColorShaderData {
|
||||
Matrix ViewProjectionMatrix;
|
||||
Matrix WorldMatrix;
|
||||
Color Color;
|
||||
Vector3 WorldInvScale;
|
||||
Vector3 Dummy0;
|
||||
float LODDitherFactor;
|
||||
});
|
||||
|
||||
LODPreviewMaterialShader::LODPreviewMaterialShader()
|
||||
{
|
||||
_ps = GPUDevice::Instance->CreatePipelineState();
|
||||
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/Editor/LODPreview"));
|
||||
_psModel.CreatePipelineStates();
|
||||
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/Editor/SingleColor"));
|
||||
if (!_shader)
|
||||
return;
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
@@ -35,7 +36,7 @@ LODPreviewMaterialShader::LODPreviewMaterialShader()
|
||||
|
||||
void LODPreviewMaterialShader::OnShaderReloading(Asset* obj)
|
||||
{
|
||||
_ps->ReleaseGPU();
|
||||
_psModel.Release();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -50,6 +51,12 @@ bool LODPreviewMaterialShader::IsReady() const
|
||||
return _shader && _shader->IsLoaded();
|
||||
}
|
||||
|
||||
bool LODPreviewMaterialShader::CanUseInstancing(InstancingHandler& handler) const
|
||||
{
|
||||
handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, SurfaceDrawCallHandler::WriteDrawCall, };
|
||||
return true;
|
||||
}
|
||||
|
||||
DrawPass LODPreviewMaterialShader::GetDrawModes() const
|
||||
{
|
||||
return DrawPass::GBuffer;
|
||||
@@ -61,12 +68,14 @@ void LODPreviewMaterialShader::Bind(BindParameters& params)
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
auto shader = _shader->GetShader();
|
||||
auto cb = shader->GetCB(0);
|
||||
if (!_ps->IsValid())
|
||||
const int32 psIndex = params.DrawCallsCount == 1 ? 0 : 1;
|
||||
auto ps = _psModel[psIndex];
|
||||
if (!ps->IsValid())
|
||||
{
|
||||
auto psDesc = GPUPipelineState::Description::Default;
|
||||
psDesc.VS = shader->GetVS("VS");
|
||||
psDesc.PS = shader->GetPS("PS");
|
||||
_ps->Init(psDesc);
|
||||
psDesc.VS = shader->GetVS("VS_Model", psIndex);
|
||||
psDesc.PS = shader->GetPS("PS_GBuffer");
|
||||
ps->Init(psDesc);
|
||||
}
|
||||
|
||||
// Find the LOD that produced this draw call
|
||||
@@ -96,17 +105,11 @@ void LODPreviewMaterialShader::Bind(BindParameters& params)
|
||||
// Bind
|
||||
if (cb && cb->GetSize())
|
||||
{
|
||||
ASSERT(cb->GetSize() == sizeof(LODPreviewMaterialShaderData));
|
||||
LODPreviewMaterialShaderData data;
|
||||
ASSERT_LOW_LAYER(cb->GetSize() == sizeof(SingleColorShaderData));
|
||||
SingleColorShaderData data;
|
||||
Matrix::Transpose(params.RenderContext.View.Frustum.GetMatrix(), data.ViewProjectionMatrix);
|
||||
Matrix::Transpose(drawCall.World, data.WorldMatrix);
|
||||
const float scaleX = Vector3(drawCall.World.M11, drawCall.World.M12, drawCall.World.M13).Length();
|
||||
const float scaleY = Vector3(drawCall.World.M21, drawCall.World.M22, drawCall.World.M23).Length();
|
||||
const float scaleZ = Vector3(drawCall.World.M31, drawCall.World.M32, drawCall.World.M33).Length();
|
||||
data.WorldInvScale = Vector3(
|
||||
scaleX > 0.00001f ? 1.0f / scaleX : 0.0f,
|
||||
scaleY > 0.00001f ? 1.0f / scaleY : 0.0f,
|
||||
scaleZ > 0.00001f ? 1.0f / scaleZ : 0.0f);
|
||||
data.LODDitherFactor = drawCall.Surface.LODDitherFactor;
|
||||
const Color colors[MODEL_MAX_LODS] = {
|
||||
Color::White,
|
||||
Color::Red,
|
||||
@@ -117,11 +120,10 @@ void LODPreviewMaterialShader::Bind(BindParameters& params)
|
||||
};
|
||||
ASSERT(lodIndex < MODEL_MAX_LODS);
|
||||
data.Color = colors[lodIndex];
|
||||
data.LODDitherFactor = drawCall.Surface.LODDitherFactor;
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
}
|
||||
context->SetState(_ps);
|
||||
context->SetState(ps);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Content/Assets/Shader.h"
|
||||
#include "Engine/Content/Assets/Texture.h"
|
||||
#include "Engine/Graphics/Materials/IMaterial.h"
|
||||
#include "Engine/Graphics/GPUPipelineStatePermutations.h"
|
||||
|
||||
class GPUPipelineState;
|
||||
|
||||
@@ -19,7 +19,7 @@ class LODPreviewMaterialShader : public IMaterial
|
||||
private:
|
||||
|
||||
AssetReference<Shader> _shader;
|
||||
GPUPipelineState* _ps = nullptr;
|
||||
GPUPipelineStatePermutations<2> _psModel;
|
||||
MaterialInfo _info;
|
||||
|
||||
public:
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
// [IMaterial]
|
||||
const MaterialInfo& GetInfo() const override;
|
||||
bool IsReady() const override;
|
||||
bool CanUseInstancing(InstancingHandler& handler) const override;
|
||||
DrawPass GetDrawModes() const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
};
|
||||
|
||||
228
Source/Engine/Renderer/Editor/MaterialComplexity.cpp
Normal file
228
Source/Engine/Renderer/Editor/MaterialComplexity.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "MaterialComplexity.h"
|
||||
#include "Engine/Core/Types/Variant.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Assets/Model.h"
|
||||
#include "Engine/Profiler/Profiler.h"
|
||||
#include "Engine/Level/Actors/Decal.h"
|
||||
#include "Engine/Graphics/GPUContext.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/GPUPipelineState.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||
#include "Engine/Graphics/Textures/GPUTexture.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Graphics/RenderBuffers.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
#include "Engine/Renderer/Lightmaps.h"
|
||||
|
||||
// The limit for maximum material complexity (estimated based on shader textures, instructions and GPU stages usage).
|
||||
#define COMPLEXITY_LIMIT 1700
|
||||
|
||||
const MaterialInfo& MaterialComplexityMaterialShader::WrapperShader::GetInfo() const
|
||||
{
|
||||
if (MaterialAsset)
|
||||
return MaterialAsset->GetInfo();
|
||||
return Info;
|
||||
}
|
||||
|
||||
bool MaterialComplexityMaterialShader::WrapperShader::IsReady() const
|
||||
{
|
||||
return MaterialAsset && MaterialAsset->IsReady();
|
||||
}
|
||||
|
||||
bool MaterialComplexityMaterialShader::WrapperShader::CanUseInstancing(InstancingHandler& handler) const
|
||||
{
|
||||
return MaterialAsset && MaterialAsset->CanUseInstancing(handler);
|
||||
}
|
||||
|
||||
DrawPass MaterialComplexityMaterialShader::WrapperShader::GetDrawModes() const
|
||||
{
|
||||
return MaterialAsset->GetDrawModes();
|
||||
}
|
||||
|
||||
void MaterialComplexityMaterialShader::WrapperShader::Bind(BindParameters& params)
|
||||
{
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
|
||||
// Get original material from the draw call
|
||||
IMaterial* material = nullptr;
|
||||
switch (Domain)
|
||||
{
|
||||
case MaterialDomain::Surface:
|
||||
case MaterialDomain::Terrain:
|
||||
material = *(IMaterial**)&drawCall.Surface.Lightmap;
|
||||
break;
|
||||
case MaterialDomain::Particle:
|
||||
material = *(IMaterial**)&drawCall.ObjectPosition;
|
||||
break;
|
||||
case MaterialDomain::Decal:
|
||||
material = drawCall.Material;
|
||||
break;
|
||||
}
|
||||
|
||||
// Disable lightmaps
|
||||
const auto lightmapsEnable = EnableLightmapsUsage;
|
||||
EnableLightmapsUsage = false;
|
||||
|
||||
// Estimate the shader complexity
|
||||
ASSERT_LOW_LAYER(material && material->IsReady());
|
||||
material->Bind(params);
|
||||
GPUPipelineState* materialPs = params.GPUContext->GetState();
|
||||
const float complexity = (float)Math::Min(materialPs->Complexity, COMPLEXITY_LIMIT) / COMPLEXITY_LIMIT;
|
||||
|
||||
// Draw with custom color
|
||||
const Color color(complexity, complexity, complexity, 1.0f);
|
||||
MaterialAsset->SetParameterValue(TEXT("Color"), Variant(color));
|
||||
MaterialAsset->Bind(params);
|
||||
|
||||
EnableLightmapsUsage = lightmapsEnable;
|
||||
}
|
||||
|
||||
MaterialComplexityMaterialShader::MaterialComplexityMaterialShader()
|
||||
{
|
||||
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/Editor/MaterialComplexity"));
|
||||
|
||||
// Initialize material wrappers table with separate materials for each material domain type and shader configuration
|
||||
#define INIT_WRAPPER(i, domain, asset) _wrappers[i].Domain = MaterialDomain::domain; _wrappers[i].MaterialAsset = Content::LoadAsyncInternal<Material>(TEXT(asset))
|
||||
INIT_WRAPPER(0, Surface, "Editor/DebugMaterials/Single Color Surface");
|
||||
INIT_WRAPPER(1, Surface, "Editor/DebugMaterials/Single Color Surface Additive");
|
||||
INIT_WRAPPER(2, Terrain, "Editor/DebugMaterials/Single Color Terrain");
|
||||
INIT_WRAPPER(3, Particle, "Editor/DebugMaterials/Single Color Particle");
|
||||
INIT_WRAPPER(4, Decal, "Editor/DebugMaterials/Single Color Decal");
|
||||
// TODO: deformable splines rendering cost for complexity
|
||||
// TODO: volumetric fog particles rendering cost for complexity
|
||||
#undef INIT_WRAPPER
|
||||
}
|
||||
|
||||
void MaterialComplexityMaterialShader::DebugOverrideDrawCallsMaterial(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer)
|
||||
{
|
||||
// Cache 'ready' state for wrappers
|
||||
bool isReady[ARRAY_COUNT(_wrappers) + 1];
|
||||
for (int32 i = 0; i < ARRAY_COUNT(_wrappers); i++)
|
||||
isReady[i] = _wrappers[i].IsReady();
|
||||
isReady[ARRAY_COUNT(_wrappers)] = false;
|
||||
|
||||
// Override all draw calls
|
||||
for (auto& e : renderContext.List->DrawCalls)
|
||||
DebugOverrideDrawCallsMaterial(e, isReady);
|
||||
for (auto& e : renderContext.List->BatchedDrawCalls)
|
||||
DebugOverrideDrawCallsMaterial(e.DrawCall, isReady);
|
||||
|
||||
// Initialize background with complexity of the sky (uniform)
|
||||
if (renderContext.List->Sky)
|
||||
{
|
||||
renderContext.List->Sky->ApplySky(context, renderContext, Matrix::Identity);
|
||||
GPUPipelineState* materialPs = context->GetState();
|
||||
const float complexity = (float)Math::Min(materialPs->Complexity, COMPLEXITY_LIMIT) / COMPLEXITY_LIMIT;
|
||||
context->Clear(lightBuffer, Color(complexity, complexity, complexity, 1.0f));
|
||||
renderContext.List->Sky = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialComplexityMaterialShader::Draw(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer)
|
||||
{
|
||||
// Draw decals into Light buffer to include them into complexity drawing
|
||||
auto& decals = renderContext.List->Decals;
|
||||
auto boxModel = Content::LoadAsyncInternal<Model>(TEXT("Engine/Models/SimpleBox"));
|
||||
auto& decalsWrapper = _wrappers[4];
|
||||
if (decals.HasItems() && boxModel && boxModel->CanBeRendered() && decalsWrapper.IsReady())
|
||||
{
|
||||
PROFILE_GPU_CPU("Decals");
|
||||
DrawCall drawCall;
|
||||
MaterialBase::BindParameters bindParams(context, renderContext, drawCall);
|
||||
drawCall.WorldDeterminantSign = 1.0f;
|
||||
context->SetRenderTarget(lightBuffer);
|
||||
for (int32 i = 0; i < decals.Count(); i++)
|
||||
{
|
||||
const auto decal = decals[i];
|
||||
ASSERT(decal && decal->Material);
|
||||
decal->GetWorld(&drawCall.World);
|
||||
drawCall.ObjectPosition = drawCall.World.GetTranslation();
|
||||
drawCall.Material = decal->Material;
|
||||
drawCall.PerInstanceRandom = decal->GetPerInstanceRandom();
|
||||
decalsWrapper.Bind(bindParams);
|
||||
boxModel->Render(context);
|
||||
}
|
||||
context->ResetSR();
|
||||
}
|
||||
|
||||
// Draw transparency into Light buffer to include it into complexity drawing
|
||||
context->SetRenderTarget(*renderContext.Buffers->DepthBuffer, lightBuffer);
|
||||
auto& distortionList = renderContext.List->DrawCallsLists[(int32)DrawCallsListType::Distortion];
|
||||
if (!distortionList.IsEmpty())
|
||||
{
|
||||
PROFILE_GPU_CPU("Distortion");
|
||||
renderContext.View.Pass = DrawPass::Distortion;
|
||||
renderContext.List->ExecuteDrawCalls(renderContext, distortionList);
|
||||
}
|
||||
auto& forwardList = renderContext.List->DrawCallsLists[(int32)DrawCallsListType::Forward];
|
||||
if (!forwardList.IsEmpty())
|
||||
{
|
||||
PROFILE_GPU_CPU("Forward");
|
||||
renderContext.View.Pass = DrawPass::Forward;
|
||||
renderContext.List->ExecuteDrawCalls(renderContext, forwardList);
|
||||
}
|
||||
|
||||
// Draw accumulated complexity into colors gradient
|
||||
context->ResetRenderTarget();
|
||||
context->SetRenderTarget(renderContext.Task->GetOutputView());
|
||||
context->SetViewportAndScissors(renderContext.Task->GetOutputViewport());
|
||||
if (_shader && _shader->IsLoaded())
|
||||
{
|
||||
if (!_ps)
|
||||
{
|
||||
_ps = GPUDevice::Instance->CreatePipelineState();
|
||||
auto psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle;
|
||||
psDesc.PS = _shader->GetShader()->GetPS("PS");
|
||||
_ps->Init(psDesc);
|
||||
}
|
||||
context->BindSR(0, lightBuffer);
|
||||
context->SetState(_ps);
|
||||
context->DrawFullscreenTriangle();
|
||||
return;
|
||||
}
|
||||
context->Draw(lightBuffer);
|
||||
}
|
||||
|
||||
void MaterialComplexityMaterialShader::DebugOverrideDrawCallsMaterial(DrawCall& drawCall, const bool isReady[ARRAY_COUNT(_wrappers) + 1])
|
||||
{
|
||||
auto domain = drawCall.Material->GetInfo().Domain;
|
||||
auto wrapperIndex = ARRAY_COUNT(_wrappers);
|
||||
switch (domain)
|
||||
{
|
||||
case MaterialDomain::Surface:
|
||||
wrapperIndex = drawCall.Material->GetDrawModes() & DrawPass::Forward ? 1 : 0;
|
||||
break;
|
||||
case MaterialDomain::Terrain:
|
||||
wrapperIndex = 2;
|
||||
break;
|
||||
case MaterialDomain::Particle:
|
||||
wrapperIndex = 3;
|
||||
break;
|
||||
case MaterialDomain::Decal:
|
||||
wrapperIndex = 4;
|
||||
break;
|
||||
}
|
||||
if (isReady[wrapperIndex])
|
||||
{
|
||||
// Override draw call material and cache original material for later
|
||||
switch (domain)
|
||||
{
|
||||
case MaterialDomain::Surface:
|
||||
case MaterialDomain::Terrain:
|
||||
*(void**)&drawCall.Surface.Lightmap = drawCall.Material;
|
||||
break;
|
||||
case MaterialDomain::Particle:
|
||||
case MaterialDomain::Decal:
|
||||
*(void**)&drawCall.ObjectPosition = drawCall.Material;
|
||||
break;
|
||||
}
|
||||
drawCall.Material = &_wrappers[wrapperIndex];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
49
Source/Engine/Renderer/Editor/MaterialComplexity.h
Normal file
49
Source/Engine/Renderer/Editor/MaterialComplexity.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Content/Assets/Material.h"
|
||||
#include "Engine/Graphics/Materials/IMaterial.h"
|
||||
#include "Engine/Content/Assets/Shader.h"
|
||||
|
||||
class GPUPipelineState;
|
||||
|
||||
/// <summary>
|
||||
/// Rendering material shaders complexity to visualize performance of pixels rendering in editor.
|
||||
/// </summary>
|
||||
class MaterialComplexityMaterialShader
|
||||
{
|
||||
private:
|
||||
|
||||
class WrapperShader : public IMaterial
|
||||
{
|
||||
public:
|
||||
MaterialInfo Info;
|
||||
MaterialDomain Domain;
|
||||
AssetReference<Material> MaterialAsset;
|
||||
const MaterialInfo& GetInfo() const override;
|
||||
bool IsReady() const override;
|
||||
bool CanUseInstancing(InstancingHandler& handler) const override;
|
||||
DrawPass GetDrawModes() const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
};
|
||||
|
||||
WrapperShader _wrappers[5];
|
||||
AssetReference<Shader> _shader;
|
||||
GPUPipelineState* _ps = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
MaterialComplexityMaterialShader();
|
||||
void DebugOverrideDrawCallsMaterial(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer);
|
||||
void Draw(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer);
|
||||
|
||||
private:
|
||||
|
||||
void DebugOverrideDrawCallsMaterial(struct DrawCall& drawCall, const bool isReady[ARRAY_COUNT(_wrappers) + 1]);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Engine/Renderer/Editor/VertexColors.h"
|
||||
#include "Engine/Renderer/Editor/LightmapUVsDensity.h"
|
||||
#include "Engine/Renderer/Editor/LODPreview.h"
|
||||
#include "Engine/Renderer/Editor/MaterialComplexity.h"
|
||||
#endif
|
||||
#include "Engine/Core/Collections/Sorting.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
@@ -93,6 +94,7 @@ void GBufferPass::Dispose()
|
||||
SAFE_DELETE(_lightmapUVsDensity);
|
||||
SAFE_DELETE(_vertexColors);
|
||||
SAFE_DELETE(_lodPreview);
|
||||
SAFE_DELETE(_materialComplexity);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -100,7 +102,12 @@ void GBufferPass::Dispose()
|
||||
|
||||
void DebugOverrideDrawCallsMaterial(RenderContext& renderContext, IMaterial* material)
|
||||
{
|
||||
if (material->IsReady())
|
||||
if (!material->IsReady())
|
||||
return;
|
||||
IMaterial::InstancingHandler handler;
|
||||
const bool canUseInstancing = material->CanUseInstancing(handler);
|
||||
const auto drawModes = material->GetDrawModes();
|
||||
if (drawModes & DrawPass::GBuffer)
|
||||
{
|
||||
auto& drawCallsList = renderContext.List->DrawCallsLists[(int32)DrawCallsListType::GBuffer];
|
||||
for (int32 i : drawCallsList.Indices)
|
||||
@@ -111,11 +118,20 @@ void DebugOverrideDrawCallsMaterial(RenderContext& renderContext, IMaterial* mat
|
||||
drawCall.Material = material;
|
||||
}
|
||||
}
|
||||
IMaterial::InstancingHandler handler;
|
||||
if (!material->CanUseInstancing(handler))
|
||||
drawCallsList.CanUseInstancing &= canUseInstancing;
|
||||
}
|
||||
if (drawModes & DrawPass::GBuffer)
|
||||
{
|
||||
auto& drawCallsList = renderContext.List->DrawCallsLists[(int32)DrawCallsListType::GBufferNoDecals];
|
||||
for (int32 i : drawCallsList.Indices)
|
||||
{
|
||||
drawCallsList.CanUseInstancing = false;
|
||||
auto& drawCall = renderContext.List->DrawCalls[i];
|
||||
if (drawCall.Material->IsSurface())
|
||||
{
|
||||
drawCall.Material = material;
|
||||
}
|
||||
}
|
||||
drawCallsList.CanUseInstancing &= canUseInstancing;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +194,12 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer
|
||||
_lodPreview = New<LODPreviewMaterialShader>();
|
||||
DebugOverrideDrawCallsMaterial(renderContext, _lodPreview);
|
||||
}
|
||||
else if (renderContext.View.Mode == ViewMode::MaterialComplexity)
|
||||
{
|
||||
if (!_materialComplexity)
|
||||
_materialComplexity = New<MaterialComplexityMaterialShader>();
|
||||
_materialComplexity->DebugOverrideDrawCallsMaterial(renderContext, context, lightBuffer);
|
||||
}
|
||||
if (renderContext.View.Mode == ViewMode::PhysicsColliders)
|
||||
{
|
||||
context->ResetRenderTarget();
|
||||
@@ -258,6 +280,15 @@ void GBufferPass::RenderDebug(RenderContext& renderContext)
|
||||
context->ResetSR();
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void GBufferPass::DrawMaterialComplexity(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer)
|
||||
{
|
||||
_materialComplexity->Draw(renderContext, context, lightBuffer);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool GBufferPass::IsDebugView(ViewMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
|
||||
@@ -19,6 +19,7 @@ private:
|
||||
class LightmapUVsDensityMaterialShader* _lightmapUVsDensity = nullptr;
|
||||
class VertexColorsMaterialShader* _vertexColors = nullptr;
|
||||
class LODPreviewMaterialShader* _lodPreview = nullptr;
|
||||
class MaterialComplexityMaterialShader* _materialComplexity = nullptr;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -36,6 +37,10 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
void RenderDebug(RenderContext& renderContext);
|
||||
|
||||
#if USE_EDITOR
|
||||
void DrawMaterialComplexity(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
static bool IsDebugView(ViewMode mode);
|
||||
|
||||
@@ -326,7 +326,6 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
|
||||
// Check if debug emissive light
|
||||
if (renderContext.View.Mode == ViewMode::Emissive || renderContext.View.Mode == ViewMode::LightmapUVsDensity)
|
||||
{
|
||||
// Render reflections debug view
|
||||
context->ResetRenderTarget();
|
||||
context->SetRenderTarget(task->GetOutputView());
|
||||
context->SetViewportAndScissors(task->GetOutputViewport());
|
||||
@@ -334,6 +333,14 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
|
||||
RenderTargetPool::Release(lightBuffer);
|
||||
return;
|
||||
}
|
||||
#if USE_EDITOR
|
||||
if (renderContext.View.Mode == ViewMode::MaterialComplexity)
|
||||
{
|
||||
GBufferPass::Instance()->DrawMaterialComplexity(renderContext, context, lightBuffer->View());
|
||||
RenderTargetPool::Release(lightBuffer);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Render motion vectors
|
||||
MotionBlurPass::Instance()->RenderMotionVectors(renderContext);
|
||||
|
||||
33
Source/Shaders/Editor/MaterialComplexity.shader
Normal file
33
Source/Shaders/Editor/MaterialComplexity.shader
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "./Flax/Common.hlsl"
|
||||
|
||||
Texture2D Image : register(t0);
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS(Quad_VS2PS input) : SV_Target
|
||||
{
|
||||
const float4 colors[4] = {
|
||||
float4(0, 0.97f, 0.12f, 1),
|
||||
float4(0.2f, 0.2f, 0.7f, 1),
|
||||
float4(1, 0, 0, 1),
|
||||
float4(1, 0.95f, 0.95f, 1)
|
||||
};
|
||||
const float weights[4] = {
|
||||
0.0f,
|
||||
0.5f,
|
||||
0.8f,
|
||||
1.0f
|
||||
};
|
||||
|
||||
float complexity = saturate(Image.Sample(SamplerPointClamp, input.TexCoord).r);
|
||||
|
||||
float4 color;
|
||||
if (complexity < weights[1])
|
||||
color = lerp(colors[0], colors[1], complexity / weights[1]);
|
||||
else if (complexity < weights[2])
|
||||
color = lerp(colors[1], colors[2], (complexity - weights[1]) / (weights[2] - weights[1]));
|
||||
else
|
||||
color = lerp(colors[2], colors[3], (complexity - weights[2]) / (weights[3] - weights[2]));
|
||||
return color;
|
||||
}
|
||||
Reference in New Issue
Block a user