You're breathtaking!
This commit is contained in:
228
Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp
Normal file
228
Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "LightmapUVsDensity.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Assets/Model.h"
|
||||
#include "Engine/Graphics/GPUPipelineState.h"
|
||||
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
#include "Engine/Foliage/Foliage.h"
|
||||
#include "Engine/ShadowsOfMordor/Builder.Config.h"
|
||||
#include "Engine/Level/Level.h"
|
||||
#include "Engine/Level/Scene/Scene.h"
|
||||
#include "Engine/Level/Actors/StaticModel.h"
|
||||
|
||||
PACK_STRUCT(struct LightmapUVsDensityMaterialShaderData {
|
||||
Matrix ViewProjectionMatrix;
|
||||
Matrix WorldMatrix;
|
||||
Rectangle LightmapArea;
|
||||
Vector3 WorldInvScale;
|
||||
float LightmapTexelsPerWorldUnit;
|
||||
Vector3 Dummy0;
|
||||
float LightmapSize;
|
||||
});
|
||||
|
||||
LightmapUVsDensityMaterialShader::LightmapUVsDensityMaterialShader()
|
||||
{
|
||||
_ps = GPUDevice::Instance->CreatePipelineState();
|
||||
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/Editor/LightmapUVsDensity"));
|
||||
if (!_shader)
|
||||
return;
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
_shader.Get()->OnReloading.Bind<LightmapUVsDensityMaterialShader, &LightmapUVsDensityMaterialShader::OnShaderReloading>(this);
|
||||
#endif
|
||||
_gridTexture = Content::LoadAsyncInternal<Texture>(TEXT("Engine/Textures/Tiles_M"));
|
||||
}
|
||||
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
|
||||
void LightmapUVsDensityMaterialShader::OnShaderReloading(Asset* obj)
|
||||
{
|
||||
_ps->ReleaseGPU();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const MaterialInfo& LightmapUVsDensityMaterialShader::GetInfo() const
|
||||
{
|
||||
return _info;
|
||||
}
|
||||
|
||||
bool LightmapUVsDensityMaterialShader::IsReady() const
|
||||
{
|
||||
return _shader && _shader->IsLoaded();
|
||||
}
|
||||
|
||||
DrawPass LightmapUVsDensityMaterialShader::GetDrawModes() const
|
||||
{
|
||||
return DrawPass::GBuffer;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
Actor* FindActorByDrawCall(Actor* actor, const DrawCall& drawCall, float& scaleInLightmap)
|
||||
{
|
||||
const auto asStaticModel = ScriptingObject::Cast<StaticModel>(actor);
|
||||
if (asStaticModel && asStaticModel->GetPerInstanceRandom() == drawCall.PerInstanceRandom && asStaticModel->GetPosition() == drawCall.ObjectPosition)
|
||||
{
|
||||
scaleInLightmap = asStaticModel->GetScaleInLightmap();
|
||||
return asStaticModel;
|
||||
}
|
||||
const auto asFoliage = ScriptingObject::Cast<Foliage>(actor);
|
||||
if (asFoliage)
|
||||
{
|
||||
for (auto i = asFoliage->Instances.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
auto& instance = *i;
|
||||
if (instance.Random == drawCall.PerInstanceRandom && instance.Transform.Translation == drawCall.ObjectPosition)
|
||||
{
|
||||
scaleInLightmap = asFoliage->FoliageTypes[instance.Type].ScaleInLightmap;
|
||||
return asFoliage;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Actor* child : actor->Children)
|
||||
{
|
||||
const auto other = FindActorByDrawCall(child, drawCall, scaleInLightmap);
|
||||
if (other)
|
||||
return other;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void LightmapUVsDensityMaterialShader::Bind(BindParameters& params)
|
||||
{
|
||||
// Prepare
|
||||
auto context = params.GPUContext;
|
||||
auto& drawCall = *params.FirstDrawCall;
|
||||
|
||||
// Setup
|
||||
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 static model that produced this draw call
|
||||
const Actor* drawCallActor = nullptr;
|
||||
float scaleInLightmap = 1.0f;
|
||||
if (params.RenderContext.Task)
|
||||
{
|
||||
if (params.RenderContext.Task->ActorsSource & ActorsSources::CustomActors)
|
||||
{
|
||||
for (auto actor : params.RenderContext.Task->CustomActors)
|
||||
{
|
||||
drawCallActor = FindActorByDrawCall(actor, drawCall, scaleInLightmap);
|
||||
if (drawCallActor)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!drawCallActor && params.RenderContext.Task->ActorsSource & ActorsSources::Scenes)
|
||||
{
|
||||
for (auto& scene : Level::Scenes)
|
||||
{
|
||||
drawCallActor = FindActorByDrawCall(scene, drawCall, scaleInLightmap);
|
||||
if (drawCallActor)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the model that produced this draw call
|
||||
const Model* drawCallModel = nullptr;
|
||||
const ModelLOD* drawCallModelLod = nullptr;
|
||||
const Mesh* drawCallMesh = nullptr;
|
||||
for (auto& e : Content::GetAssetsRaw())
|
||||
{
|
||||
auto model = ScriptingObject::Cast<Model>(e.Value);
|
||||
if (!model)
|
||||
continue;
|
||||
for (const auto& lod : model->LODs)
|
||||
{
|
||||
for (const auto& mesh : lod.Meshes)
|
||||
{
|
||||
if (mesh.GetIndexBuffer() == drawCall.Geometry.IndexBuffer)
|
||||
{
|
||||
drawCallModel = model;
|
||||
drawCallModelLod = &lod;
|
||||
drawCallMesh = &mesh;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (drawCallModel)
|
||||
break;
|
||||
}
|
||||
|
||||
// Bind constants
|
||||
if (cb && cb->GetSize())
|
||||
{
|
||||
ASSERT(cb->GetSize() == sizeof(LightmapUVsDensityMaterialShaderData));
|
||||
LightmapUVsDensityMaterialShaderData 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.LightmapTexelsPerWorldUnit = ShadowsOfMordor::LightmapTexelsPerWorldUnit;
|
||||
data.LightmapSize = 1024.0f;
|
||||
data.LightmapArea = drawCall.LightmapUVsArea;
|
||||
if (drawCallModel)
|
||||
{
|
||||
// Calculate current lightmap slot size for the object (matches the ShadowsOfMordor calculations when baking the lighting)
|
||||
float globalObjectsScale = 1.0f;
|
||||
int32 atlasSize = 1024;
|
||||
int32 chartsPadding = 3;
|
||||
if (drawCallActor)
|
||||
{
|
||||
const Scene* drawCallScene = drawCallActor->GetScene();
|
||||
if (drawCallScene)
|
||||
{
|
||||
globalObjectsScale = drawCallScene->Info.LightmapSettings.GlobalObjectsScale;
|
||||
atlasSize = (int32)drawCallScene->Info.LightmapSettings.AtlasSize;
|
||||
chartsPadding = drawCallScene->Info.LightmapSettings.ChartsPadding;
|
||||
}
|
||||
}
|
||||
BoundingBox box = drawCallModelLod->GetBox(drawCall.World);
|
||||
Vector3 size = box.GetSize();
|
||||
float dimensionsCoeff = size.AverageArithmetic();
|
||||
if (size.X <= 1.0f)
|
||||
dimensionsCoeff = Vector2(size.Y, size.Z).AverageArithmetic();
|
||||
else if (size.Y <= 1.0f)
|
||||
dimensionsCoeff = Vector2(size.X, size.Z).AverageArithmetic();
|
||||
else if (size.Z <= 1.0f)
|
||||
dimensionsCoeff = Vector2(size.Y, size.X).AverageArithmetic();
|
||||
float scale = globalObjectsScale * scaleInLightmap * ShadowsOfMordor::LightmapTexelsPerWorldUnit * dimensionsCoeff;
|
||||
if (scale <= ZeroTolerance)
|
||||
scale = 0.0f;
|
||||
const int32 maximumChartSize = atlasSize - chartsPadding * 2;
|
||||
int32 width = Math::Clamp(Math::CeilToInt(scale), ShadowsOfMordor::LightmapMinChartSize, maximumChartSize);
|
||||
int32 height = Math::Clamp(Math::CeilToInt(scale), ShadowsOfMordor::LightmapMinChartSize, maximumChartSize);
|
||||
float invSize = 1.0f / atlasSize;
|
||||
data.LightmapArea = Rectangle(0, 0, width * invSize, height * invSize);
|
||||
data.LightmapSize = (float)atlasSize;
|
||||
}
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
}
|
||||
|
||||
// Bind grid texture
|
||||
context->BindSR(0, _gridTexture ? _gridTexture->GetTexture() : GPUDevice::Instance->GetDefaultWhiteTexture());
|
||||
|
||||
// Bind pipeline
|
||||
context->SetState(_ps);
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user