Add LOD Preview debug view mode
This commit is contained in:
BIN
Content/Shaders/Editor/LODPreview.flax
(Stored with Git LFS)
Normal file
BIN
Content/Shaders/Editor/LODPreview.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -1397,6 +1397,7 @@ namespace FlaxEditor.Viewport
|
||||
new ViewModeOptions(ViewMode.LightmapUVsDensity, "Lightmap UVs Density"),
|
||||
new ViewModeOptions(ViewMode.VertexColors, "Vertex Colors"),
|
||||
new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders"),
|
||||
new ViewModeOptions(ViewMode.LODPreview, "LOD Preview"),
|
||||
};
|
||||
|
||||
private void WidgetCamSpeedShowHide(Control cm)
|
||||
|
||||
@@ -813,6 +813,11 @@ API_ENUM() enum class ViewMode
|
||||
/// Draw physics colliders debug view
|
||||
/// </summary>
|
||||
PhysicsColliders = 20,
|
||||
|
||||
/// <summary>
|
||||
/// Draw Level Of Detail number as colors to debug LOD switches.
|
||||
/// </summary>
|
||||
LODPreview = 21,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
127
Source/Engine/Renderer/Editor/LODPreview.cpp
Normal file
127
Source/Engine/Renderer/Editor/LODPreview.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "LODPreview.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Assets/Model.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/GPUPipelineState.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
|
||||
PACK_STRUCT(struct LODPreviewMaterialShaderData {
|
||||
Matrix ViewProjectionMatrix;
|
||||
Matrix WorldMatrix;
|
||||
Color Color;
|
||||
Vector3 WorldInvScale;
|
||||
float LODDitherFactor;
|
||||
});
|
||||
|
||||
LODPreviewMaterialShader::LODPreviewMaterialShader()
|
||||
{
|
||||
_ps = GPUDevice::Instance->CreatePipelineState();
|
||||
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/Editor/LODPreview"));
|
||||
if (!_shader)
|
||||
return;
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
_shader.Get()->OnReloading.Bind<LODPreviewMaterialShader, &LODPreviewMaterialShader::OnShaderReloading>(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
|
||||
void LODPreviewMaterialShader::OnShaderReloading(Asset* obj)
|
||||
{
|
||||
_ps->ReleaseGPU();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const MaterialInfo& LODPreviewMaterialShader::GetInfo() const
|
||||
{
|
||||
return _info;
|
||||
}
|
||||
|
||||
bool LODPreviewMaterialShader::IsReady() const
|
||||
{
|
||||
return _shader && _shader->IsLoaded();
|
||||
}
|
||||
|
||||
DrawPass LODPreviewMaterialShader::GetDrawModes() const
|
||||
{
|
||||
return DrawPass::GBuffer;
|
||||
}
|
||||
|
||||
void LODPreviewMaterialShader::Bind(BindParameters& params)
|
||||
{
|
||||
auto context = params.GPUContext;
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
auto shader = _shader->GetShader();
|
||||
auto cb = shader->GetCB(0);
|
||||
if (!_ps->IsValid())
|
||||
{
|
||||
auto psDesc = GPUPipelineState::Description::Default;
|
||||
psDesc.VS = shader->GetVS("VS");
|
||||
psDesc.PS = shader->GetPS("PS");
|
||||
_ps->Init(psDesc);
|
||||
}
|
||||
|
||||
// Find the LOD that produced this draw call
|
||||
int32 lodIndex = 0;
|
||||
for (auto& e : Content::GetAssetsRaw())
|
||||
{
|
||||
auto model = ScriptingObject::Cast<Model>(e.Value);
|
||||
if (!model)
|
||||
continue;
|
||||
bool found = false;
|
||||
for (const auto& lod : model->LODs)
|
||||
{
|
||||
for (const auto& mesh : lod.Meshes)
|
||||
{
|
||||
if (mesh.GetIndexBuffer() == drawCall.Geometry.IndexBuffer)
|
||||
{
|
||||
lodIndex = mesh.GetLODIndex();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
|
||||
// Bind
|
||||
if (cb && cb->GetSize())
|
||||
{
|
||||
ASSERT(cb->GetSize() == sizeof(LODPreviewMaterialShaderData));
|
||||
LODPreviewMaterialShaderData 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);
|
||||
const Color colors[MODEL_MAX_LODS] = {
|
||||
Color::White,
|
||||
Color::Red,
|
||||
Color::Orange,
|
||||
Color::Yellow,
|
||||
Color::Green,
|
||||
Color::Blue,
|
||||
};
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
||||
47
Source/Engine/Renderer/Editor/LODPreview.h
Normal file
47
Source/Engine/Renderer/Editor/LODPreview.h
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Content/Assets/Shader.h"
|
||||
#include "Engine/Content/Assets/Texture.h"
|
||||
#include "Engine/Graphics/Materials/IMaterial.h"
|
||||
|
||||
class GPUPipelineState;
|
||||
|
||||
/// <summary>
|
||||
/// Rendering Level Of Detail number as colors to debug LOD switches in editor.
|
||||
/// </summary>
|
||||
class LODPreviewMaterialShader : public IMaterial
|
||||
{
|
||||
private:
|
||||
|
||||
AssetReference<Shader> _shader;
|
||||
GPUPipelineState* _ps = nullptr;
|
||||
MaterialInfo _info;
|
||||
|
||||
public:
|
||||
|
||||
LODPreviewMaterialShader();
|
||||
virtual ~LODPreviewMaterialShader()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
void OnShaderReloading(Asset* obj);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
// [IMaterial]
|
||||
const MaterialInfo& GetInfo() const override;
|
||||
bool IsReady() const override;
|
||||
DrawPass GetDrawModes() const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
#include "GBufferPass.h"
|
||||
#include "RenderList.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Renderer/Editor/VertexColors.h"
|
||||
#include "Engine/Renderer/Editor/LightmapUVsDensity.h"
|
||||
#include "Engine/Renderer/Editor/LODPreview.h"
|
||||
#endif
|
||||
#include "Engine/Core/Collections/Sorting.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/GPUContext.h"
|
||||
@@ -87,11 +90,37 @@ void GBufferPass::Dispose()
|
||||
_skyModel = nullptr;
|
||||
_boxModel = nullptr;
|
||||
#if USE_EDITOR
|
||||
SAFE_DELETE(_lightmapUVsDensityMaterialShader);
|
||||
SAFE_DELETE(_vertexColorsMaterialShader);
|
||||
SAFE_DELETE(_lightmapUVsDensity);
|
||||
SAFE_DELETE(_vertexColors);
|
||||
SAFE_DELETE(_lodPreview);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void DebugOverrideDrawCallsMaterial(RenderContext& renderContext, IMaterial* material)
|
||||
{
|
||||
if (material->IsReady())
|
||||
{
|
||||
auto& drawCallsList = renderContext.List->DrawCallsLists[(int32)DrawCallsListType::GBuffer];
|
||||
for (int32 i : drawCallsList.Indices)
|
||||
{
|
||||
auto& drawCall = renderContext.List->DrawCalls[i];
|
||||
if (drawCall.Material->IsSurface())
|
||||
{
|
||||
drawCall.Material = material;
|
||||
}
|
||||
}
|
||||
IMaterial::InstancingHandler handler;
|
||||
if (!material->CanUseInstancing(handler))
|
||||
{
|
||||
drawCallsList.CanUseInstancing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer)
|
||||
{
|
||||
PROFILE_GPU_CPU("GBuffer");
|
||||
@@ -133,47 +162,21 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer
|
||||
// Override draw calls material to use material debug shader
|
||||
if (renderContext.View.Mode == ViewMode::LightmapUVsDensity)
|
||||
{
|
||||
if (!_lightmapUVsDensityMaterialShader)
|
||||
_lightmapUVsDensityMaterialShader = New<LightmapUVsDensityMaterialShader>();
|
||||
if (_lightmapUVsDensityMaterialShader->IsReady())
|
||||
{
|
||||
auto& drawCallsList = renderContext.List->DrawCallsLists[(int32)DrawCallsListType::GBuffer];
|
||||
for (int32 i : drawCallsList.Indices)
|
||||
{
|
||||
auto& drawCall = renderContext.List->DrawCalls[i];
|
||||
if (drawCall.Material->IsSurface())
|
||||
{
|
||||
drawCall.Material = _lightmapUVsDensityMaterialShader;
|
||||
}
|
||||
}
|
||||
IMaterial::InstancingHandler handler;
|
||||
if (!_lightmapUVsDensityMaterialShader->CanUseInstancing(handler))
|
||||
{
|
||||
drawCallsList.CanUseInstancing = false;
|
||||
}
|
||||
}
|
||||
if (!_lightmapUVsDensity)
|
||||
_lightmapUVsDensity = New<LightmapUVsDensityMaterialShader>();
|
||||
DebugOverrideDrawCallsMaterial(renderContext, _lightmapUVsDensity);
|
||||
}
|
||||
else if (renderContext.View.Mode == ViewMode::VertexColors)
|
||||
{
|
||||
if (!_vertexColorsMaterialShader)
|
||||
_vertexColorsMaterialShader = New<VertexColorsMaterialShader>();
|
||||
if (_vertexColorsMaterialShader->IsReady())
|
||||
{
|
||||
auto& drawCallsList = renderContext.List->DrawCallsLists[(int32)DrawCallsListType::GBuffer];
|
||||
for (int32 i : drawCallsList.Indices)
|
||||
{
|
||||
auto& drawCall = renderContext.List->DrawCalls[i];
|
||||
if (drawCall.Material->IsSurface())
|
||||
{
|
||||
drawCall.Material = _vertexColorsMaterialShader;
|
||||
}
|
||||
}
|
||||
IMaterial::InstancingHandler handler;
|
||||
if (!_vertexColorsMaterialShader->CanUseInstancing(handler))
|
||||
{
|
||||
drawCallsList.CanUseInstancing = false;
|
||||
}
|
||||
}
|
||||
if (!_vertexColors)
|
||||
_vertexColors = New<VertexColorsMaterialShader>();
|
||||
DebugOverrideDrawCallsMaterial(renderContext, _vertexColors);
|
||||
}
|
||||
else if (renderContext.View.Mode == ViewMode::LODPreview)
|
||||
{
|
||||
if (!_lodPreview)
|
||||
_lodPreview = New<LODPreviewMaterialShader>();
|
||||
DebugOverrideDrawCallsMaterial(renderContext, _lodPreview);
|
||||
}
|
||||
if (renderContext.View.Mode == ViewMode::PhysicsColliders)
|
||||
{
|
||||
|
||||
@@ -16,8 +16,9 @@ private:
|
||||
AssetReference<Model> _skyModel;
|
||||
AssetReference<Model> _boxModel;
|
||||
#if USE_EDITOR
|
||||
class LightmapUVsDensityMaterialShader* _lightmapUVsDensityMaterialShader = nullptr;
|
||||
class VertexColorsMaterialShader* _vertexColorsMaterialShader = nullptr;
|
||||
class LightmapUVsDensityMaterialShader* _lightmapUVsDensity = nullptr;
|
||||
class VertexColorsMaterialShader* _vertexColors = nullptr;
|
||||
class LODPreviewMaterialShader* _lodPreview = nullptr;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
89
Source/Shaders/Editor/LODPreview.shader
Normal file
89
Source/Shaders/Editor/LODPreview.shader
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#define MATERIAL 1
|
||||
|
||||
#include "./Flax/Common.hlsl"
|
||||
#include "./Flax/MaterialCommon.hlsl"
|
||||
|
||||
META_CB_BEGIN(0, Data)
|
||||
float4x4 ViewProjectionMatrix;
|
||||
float4x4 WorldMatrix;
|
||||
float4 Color;
|
||||
float3 WorldInvScale;
|
||||
float LODDitherFactor;
|
||||
META_CB_END
|
||||
|
||||
struct VertexOutput
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldNormal : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct PixelInput
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float3 WorldNormal : TEXCOORD0;
|
||||
};
|
||||
|
||||
float3x3 RemoveScaleFromLocalToWorld(float3x3 localToWorld)
|
||||
{
|
||||
localToWorld[0] *= WorldInvScale.x;
|
||||
localToWorld[1] *= WorldInvScale.y;
|
||||
localToWorld[2] *= WorldInvScale.z;
|
||||
return localToWorld;
|
||||
}
|
||||
|
||||
float3x3 CalcTangentToWorld(float4x4 world, float3x3 tangentToLocal)
|
||||
{
|
||||
float3x3 localToWorld = RemoveScaleFromLocalToWorld((float3x3)world);
|
||||
return mul(tangentToLocal, localToWorld);
|
||||
}
|
||||
|
||||
float4 PerformFakeLighting(float3 n, float4 c)
|
||||
{
|
||||
c.rgb *= saturate(abs(dot(n, float3(0, 1, 0))) + 0.5f);
|
||||
return c;
|
||||
}
|
||||
|
||||
void ClipLODTransition(float4 svPosition, float ditherFactor)
|
||||
{
|
||||
if (abs(ditherFactor) > 0.001)
|
||||
{
|
||||
float randGrid = cos(dot(floor(svPosition.xy), float2(347.83452793, 3343.28371863)));
|
||||
float randGridFrac = frac(randGrid * 1000.0);
|
||||
half mask = (ditherFactor < 0.0) ? (ditherFactor + 1.0 > randGridFrac) : (ditherFactor < randGridFrac);
|
||||
clip(mask - 0.001);
|
||||
}
|
||||
}
|
||||
|
||||
META_VS(true, FEATURE_LEVEL_ES2)
|
||||
META_VS_IN_ELEMENT(POSITION, 0, R32G32B32_FLOAT, 0, 0, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(TEXCOORD, 0, R16G16_FLOAT, 1, 0, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(NORMAL, 0, R10G10B10A2_UNORM, 1, ALIGN, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(TANGENT, 0, R10G10B10A2_UNORM, 1, ALIGN, PER_VERTEX, 0, true)
|
||||
META_VS_IN_ELEMENT(TEXCOORD, 1, R16G16_FLOAT, 1, ALIGN, PER_VERTEX, 0, true)
|
||||
VertexOutput VS(ModelInput input)
|
||||
{
|
||||
float bitangentSign = input.Tangent.w ? -1.0f : +1.0f;
|
||||
float3 normal = input.Normal.xyz * 2.0 - 1.0;
|
||||
float3 tangent = input.Tangent.xyz * 2.0 - 1.0;
|
||||
float3 bitangent = cross(normal, tangent) * bitangentSign;
|
||||
float3x3 tangentToLocal = float3x3(tangent, bitangent, normal);
|
||||
float3x3 tangentToWorld = CalcTangentToWorld(WorldMatrix, tangentToLocal);
|
||||
float3 worldPosition = mul(float4(input.Position.xyz, 1), WorldMatrix).xyz;
|
||||
|
||||
VertexOutput output;
|
||||
output.Position = mul(float4(worldPosition, 1), ViewProjectionMatrix);
|
||||
output.WorldNormal = tangentToWorld[2];
|
||||
return output;
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
void PS(in PixelInput input, out float4 Light : SV_Target0, out float4 RT0 : SV_Target1, out float4 RT1 : SV_Target2, out float4 RT2 : SV_Target3)
|
||||
{
|
||||
ClipLODTransition(input.Position, LODDitherFactor);
|
||||
Light = PerformFakeLighting(input.WorldNormal, Color);
|
||||
RT0 = float4(0, 0, 0, 0);
|
||||
RT1 = float4(input.WorldNormal * 0.5 + 0.5, SHADING_MODEL_LIT * (1.0 / 3.0));
|
||||
RT2 = float4(0.4, 0, 0.5, 0);
|
||||
}
|
||||
Reference in New Issue
Block a user