Various fixes and improvements for large worlds rendering

This commit is contained in:
Wojtek Figat
2022-06-28 20:26:01 +02:00
parent b1640515c4
commit 27d266546e
18 changed files with 80 additions and 70 deletions

Binary file not shown.

BIN
Content/Shaders/Sky.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -19,6 +19,8 @@
PACK_STRUCT(struct Data { PACK_STRUCT(struct Data {
Matrix WVP; Matrix WVP;
Float3 ViewOffset;
float Padding;
GBufferData GBuffer; GBufferData GBuffer;
AtmosphericFogData Fog; AtmosphericFogData Fog;
}); });
@@ -178,6 +180,7 @@ void Sky::DrawFog(GPUContext* context, RenderContext& renderContext, GPUTextureV
// Setup constants data // Setup constants data
Data data; Data data;
GBufferPass::SetInputs(renderContext.View, data.GBuffer); GBufferPass::SetInputs(renderContext.View, data.GBuffer);
data.ViewOffset = renderContext.View.Origin + GetPosition();
InitConfig(data.Fog); InitConfig(data.Fog);
data.Fog.AtmosphericFogSunPower *= SunLight ? SunLight->Brightness : 1.0f; data.Fog.AtmosphericFogSunPower *= SunLight ? SunLight->Brightness : 1.0f;
bool useSpecularLight = (renderContext.View.Flags & ViewFlags::SpecularLight) != 0; bool useSpecularLight = (renderContext.View.Flags & ViewFlags::SpecularLight) != 0;
@@ -216,6 +219,7 @@ void Sky::ApplySky(GPUContext* context, RenderContext& renderContext, const Matr
Matrix::Multiply(world, renderContext.View.Frustum.GetMatrix(), m); Matrix::Multiply(world, renderContext.View.Frustum.GetMatrix(), m);
Matrix::Transpose(m, data.WVP); Matrix::Transpose(m, data.WVP);
GBufferPass::SetInputs(renderContext.View, data.GBuffer); GBufferPass::SetInputs(renderContext.View, data.GBuffer);
data.ViewOffset = renderContext.View.Origin + GetPosition();
InitConfig(data.Fog); InitConfig(data.Fog);
//data.Fog.AtmosphericFogSunPower *= SunLight ? SunLight->Brightness : 1.0f; //data.Fog.AtmosphericFogSunPower *= SunLight ? SunLight->Brightness : 1.0f;
bool useSpecularLight = (renderContext.View.Flags & ViewFlags::SpecularLight) != 0; bool useSpecularLight = (renderContext.View.Flags & ViewFlags::SpecularLight) != 0;

View File

@@ -37,6 +37,15 @@ float SkyLight::GetScaledRadius() const
return _radius * _transform.Scale.MaxValue(); return _radius * _transform.Scale.MaxValue();
} }
CubeTexture* SkyLight::GetSource() const
{
if (Mode == Modes::CaptureScene)
return _bakedProbe;
if (Mode == Modes::CustomTexture)
return CustomTexture.Get();
return nullptr;
}
void SkyLight::Bake(float timeout) void SkyLight::Bake(float timeout)
{ {
#if COMPILE_WITH_PROBES_BAKING #if COMPILE_WITH_PROBES_BAKING

View File

@@ -63,7 +63,6 @@ public:
/// <summary> /// <summary>
/// Gets the radius. /// Gets the radius.
/// </summary> /// </summary>
/// <returns>The value.</returns>
API_PROPERTY(Attributes="EditorOrder(29), DefaultValue(1000000.0f), Limit(0), EditorDisplay(\"Light\")") API_PROPERTY(Attributes="EditorOrder(29), DefaultValue(1000000.0f), Limit(0), EditorDisplay(\"Light\")")
FORCE_INLINE float GetRadius() const FORCE_INLINE float GetRadius() const
{ {
@@ -73,8 +72,7 @@ public:
/// <summary> /// <summary>
/// Sets the radius. /// Sets the radius.
/// </summary> /// </summary>
/// <param name="value">The value.</param> API_PROPERTY() void SetRadius(float value);
void SetRadius(float value);
/// <summary> /// <summary>
/// Gets the scaled radius of the sky light. /// Gets the scaled radius of the sky light.
@@ -84,15 +82,7 @@ public:
/// <summary> /// <summary>
/// Gets the light source texture. /// Gets the light source texture.
/// </summary> /// </summary>
/// <returns>The cube texture.</returns> CubeTexture* GetSource() const;
CubeTexture* GetSource() const
{
if (Mode == Modes::CaptureScene)
return _bakedProbe;
if (Mode == Modes::CustomTexture)
return CustomTexture.Get();
return nullptr;
}
public: public:
/// <summary> /// <summary>

View File

@@ -232,20 +232,18 @@ void StaticModel::Draw(RenderContext& renderContext)
const DrawPass drawModes = (DrawPass)(DrawModes & renderContext.View.Pass); const DrawPass drawModes = (DrawPass)(DrawModes & renderContext.View.Pass);
if (!Model || !Model->IsLoaded() || !Model->CanBeRendered() || drawModes == DrawPass::None) if (!Model || !Model->IsLoaded() || !Model->CanBeRendered() || drawModes == DrawPass::None)
return; return;
Matrix world;
renderContext.View.GetWorldMatrix(_transform, world);
if (renderContext.View.Pass == DrawPass::GlobalSDF) if (renderContext.View.Pass == DrawPass::GlobalSDF)
{ {
GlobalSignDistanceFieldPass::Instance()->RasterizeModelSDF(this, Model->SDF, world, _box); GlobalSignDistanceFieldPass::Instance()->RasterizeModelSDF(this, Model->SDF, _transform, _box);
return; return;
} }
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas) if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
{ {
GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, world, Model->LODs.Last().GetBox()); GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, _transform, Model->LODs.Last().GetBox());
return; return;
} }
Matrix world;
renderContext.View.GetWorldMatrix(_transform, world);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world); GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
// Flush vertex colors if need to // Flush vertex colors if need to

View File

@@ -1282,8 +1282,7 @@ void GlobalSurfaceAtlasPass::RasterizeActor(Actor* actor, void* actorObject, con
// Calculate object bounds size in the view // Calculate object bounds size in the view
OrientedBoundingBox viewBounds(object->Bounds); OrientedBoundingBox viewBounds(object->Bounds);
viewBounds.Transform(tile->ViewMatrix); viewBounds.Transform(tile->ViewMatrix);
Float3 viewExtent; Float3 viewExtent = viewBounds.Transformation.LocalToWorldVector(viewBounds.Extents);
viewExtent = viewBounds.Transformation.LocalToWorldVector(viewBounds.Extents);
tile->ViewBoundsSize = viewExtent.GetAbsolute() * 2.0f; tile->ViewBoundsSize = viewExtent.GetAbsolute() * 2.0f;
// Per-tile data // Per-tile data

View File

@@ -80,7 +80,7 @@ public:
void RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output); void RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output);
// Rasterize actor into the Global Surface Atlas. Call it from actor Draw() method during DrawPass::GlobalSurfaceAtlas. // Rasterize actor into the Global Surface Atlas. Call it from actor Draw() method during DrawPass::GlobalSurfaceAtlas.
void RasterizeActor(Actor* actor, void* actorObject, const BoundingSphere& actorObjectBounds, const Matrix& localToWorld, const BoundingBox& localBounds, uint32 tilesMask = MAX_uint32, bool useVisibility = true); void RasterizeActor(Actor* actor, void* actorObject, const BoundingSphere& actorObjectBounds, const Transform& localToWorld, const BoundingBox& localBounds, uint32 tilesMask = MAX_uint32, bool useVisibility = true);
private: private:
#if COMPILE_WITH_DEV_ENV #if COMPILE_WITH_DEV_ENV

View File

@@ -173,6 +173,7 @@ public:
int32 Resolution = 0; int32 Resolution = 0;
GPUTexture* Texture = nullptr; GPUTexture* Texture = nullptr;
GPUTexture* TextureMip = nullptr; GPUTexture* TextureMip = nullptr;
Vector3 Origin = Vector3::Zero;
Array<CascadeData, FixedAllocation<4>> Cascades; Array<CascadeData, FixedAllocation<4>> Cascades;
HashSet<ScriptingTypeHandle> ObjectTypes; HashSet<ScriptingTypeHandle> ObjectTypes;
HashSet<GPUTexture*> SDFTextures; HashSet<GPUTexture*> SDFTextures;
@@ -431,7 +432,6 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
} }
desc.Width = resolutionMip * cascadesCount; desc.Width = resolutionMip * cascadesCount;
desc.Height = desc.Depth = resolutionMip; desc.Height = desc.Depth = resolutionMip;
for (auto& cascade : sdfData.Cascades)
{ {
GPUTexture*& texture = sdfData.TextureMip; GPUTexture*& texture = sdfData.TextureMip;
if (texture && texture->Width() != desc.Width) if (texture && texture->Width() != desc.Width)
@@ -446,6 +446,13 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
return true; return true;
} }
} }
uint64 memoryUsage = sdfData.Texture->GetMemoryUsage() + sdfData.TextureMip->GetMemoryUsage();
LOG(Info, "Global SDF memory usage: {0} MB", memoryUsage / 1024 / 1024);
}
if (sdfData.Origin != renderContext.View.Origin)
{
sdfData.Origin = renderContext.View.Origin;
updated = true;
} }
GPUTexture* tmpMip = nullptr; GPUTexture* tmpMip = nullptr;
if (updated) if (updated)
@@ -456,23 +463,20 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
cascade.NonEmptyChunks.Clear(); cascade.NonEmptyChunks.Clear();
cascade.StaticChunks.Clear(); cascade.StaticChunks.Clear();
} }
uint64 memoryUsage = sdfData.Texture->GetMemoryUsage();
context->ClearUA(sdfData.Texture, Float4::One); context->ClearUA(sdfData.Texture, Float4::One);
memoryUsage += sdfData.TextureMip->GetMemoryUsage();
context->ClearUA(sdfData.TextureMip, Float4::One); context->ClearUA(sdfData.TextureMip, Float4::One);
LOG(Info, "Global SDF memory usage: {0} MB", memoryUsage / 1024 / 1024);
} }
for (SceneRendering* scene : renderContext.List->Scenes) for (SceneRendering* scene : renderContext.List->Scenes)
sdfData.ListenSceneRendering(scene); sdfData.ListenSceneRendering(scene);
// Calculate origin for Global SDF by shifting it towards the view direction to account for better view frustum coverage // Calculate origin for Global SDF by shifting it towards the view direction to account for better view frustum coverage
Float3 viewOrigin = renderContext.View.Position; Float3 viewPosition = renderContext.View.Position;
{ {
Float3 viewDirection = renderContext.View.Direction; Float3 viewDirection = renderContext.View.Direction;
const float cascade0Distance = distanceExtent * cascadesDistanceScales[0]; const float cascade0Distance = distanceExtent * cascadesDistanceScales[0];
const Vector2 viewRayHit = CollisionsHelper::LineHitsBox(viewOrigin, viewOrigin + viewDirection * (cascade0Distance * 2.0f), viewOrigin - cascade0Distance, viewOrigin + cascade0Distance); const Vector2 viewRayHit = CollisionsHelper::LineHitsBox(viewPosition, viewPosition + viewDirection * (cascade0Distance * 2.0f), viewPosition - cascade0Distance, viewPosition + cascade0Distance);
const float viewOriginOffset = (float)viewRayHit.Y * cascade0Distance * 0.6f; const float viewOriginOffset = (float)viewRayHit.Y * cascade0Distance * 0.6f;
viewOrigin += viewDirection * viewOriginOffset; viewPosition += viewDirection * viewOriginOffset;
} }
// Rasterize world geometry into Global SDF // Rasterize world geometry into Global SDF
@@ -499,7 +503,7 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
const float cascadeVoxelSize = cascadeMaxDistance / (float)resolution; const float cascadeVoxelSize = cascadeMaxDistance / (float)resolution;
const float cascadeChunkSize = cascadeVoxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_SIZE; const float cascadeChunkSize = cascadeVoxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_SIZE;
static_assert(GLOBAL_SDF_RASTERIZE_CHUNK_SIZE % GLOBAL_SDF_RASTERIZE_MIP_FACTOR == 0, "Adjust chunk size to match the mip factor scale."); static_assert(GLOBAL_SDF_RASTERIZE_CHUNK_SIZE % GLOBAL_SDF_RASTERIZE_MIP_FACTOR == 0, "Adjust chunk size to match the mip factor scale.");
const Float3 center = Float3::Floor(viewOrigin / cascadeChunkSize) * cascadeChunkSize; const Float3 center = Float3::Floor(viewPosition / cascadeChunkSize) * cascadeChunkSize;
//const Float3 center = Float3::Zero; //const Float3 center = Float3::Zero;
BoundingBox cascadeBounds(center - cascadeDistance, center + cascadeDistance); BoundingBox cascadeBounds(center - cascadeDistance, center + cascadeDistance);
// TODO: add scene detail scale factor to PostFx settings (eg. to increase or decrease scene details and quality) // TODO: add scene detail scale factor to PostFx settings (eg. to increase or decrease scene details and quality)
@@ -533,11 +537,14 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
_sdfData = &sdfData; _sdfData = &sdfData;
{ {
PROFILE_CPU_NAMED("Draw"); PROFILE_CPU_NAMED("Draw");
BoundingBox cascadeBoundsWorld = cascadeBounds;
cascadeBoundsWorld.Minimum += sdfData.Origin;
cascadeBoundsWorld.Maximum += sdfData.Origin;
for (SceneRendering* scene : renderContext.List->Scenes) for (SceneRendering* scene : renderContext.List->Scenes)
{ {
for (const auto& e : scene->Actors) for (const auto& e : scene->Actors)
{ {
if (viewMask & e.LayerMask && e.Bounds.Radius >= minObjectRadius && CollisionsHelper::BoxIntersectsSphere(cascadeBounds, e.Bounds)) if (viewMask & e.LayerMask && e.Bounds.Radius >= minObjectRadius && CollisionsHelper::BoxIntersectsSphere(cascadeBoundsWorld, e.Bounds))
{ {
e.Actor->Draw(renderContext); e.Actor->Draw(renderContext);
} }
@@ -578,7 +585,6 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
// TODO: don't stall with UAV barrier on D3D12/Vulkan if UAVs don't change between dispatches // TODO: don't stall with UAV barrier on D3D12/Vulkan if UAVs don't change between dispatches
} }
} }
// TODO: rasterize models into global sdf relative to the cascade origin to prevent fp issues on large worlds
{ {
PROFILE_GPU_CPU("Rasterize Chunks"); PROFILE_GPU_CPU("Rasterize Chunks");
@@ -838,7 +844,7 @@ void GlobalSignDistanceFieldPass::RenderDebug(RenderContext& renderContext, GPUC
context->DrawFullscreenTriangle(); context->DrawFullscreenTriangle();
} }
void GlobalSignDistanceFieldPass::RasterizeModelSDF(Actor* actor, const ModelBase::SDFData& sdf, const Matrix& localToWorld, const BoundingBox& objectBounds) void GlobalSignDistanceFieldPass::RasterizeModelSDF(Actor* actor, const ModelBase::SDFData& sdf, const Transform& localToWorld, const BoundingBox& objectBounds)
{ {
if (!sdf.Texture || sdf.Texture->ResidentMipLevels() == 0) if (!sdf.Texture || sdf.Texture->ResidentMipLevels() == 0)
return; return;
@@ -846,15 +852,16 @@ void GlobalSignDistanceFieldPass::RasterizeModelSDF(Actor* actor, const ModelBas
// Setup object data // Setup object data
BoundingBox objectBoundsCascade; BoundingBox objectBoundsCascade;
const float objectMargin = _voxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN; const float objectMargin = _voxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN;
Vector3::Clamp(objectBounds.Minimum - objectMargin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum); Vector3::Clamp(objectBounds.Minimum - _sdfData->Origin - objectMargin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum);
Vector3::Subtract(objectBoundsCascade.Minimum, _cascadeBounds.Minimum, objectBoundsCascade.Minimum); Vector3::Subtract(objectBoundsCascade.Minimum, _cascadeBounds.Minimum, objectBoundsCascade.Minimum);
Vector3::Clamp(objectBounds.Maximum + objectMargin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum); Vector3::Clamp(objectBounds.Maximum - _sdfData->Origin + objectMargin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum);
Vector3::Subtract(objectBoundsCascade.Maximum, _cascadeBounds.Minimum, objectBoundsCascade.Maximum); Vector3::Subtract(objectBoundsCascade.Maximum, _cascadeBounds.Minimum, objectBoundsCascade.Maximum);
const float chunkSize = _voxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_SIZE; const float chunkSize = _voxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_SIZE;
Int3 objectChunkMin(objectBoundsCascade.Minimum / chunkSize); Int3 objectChunkMin(objectBoundsCascade.Minimum / chunkSize);
Int3 objectChunkMax(objectBoundsCascade.Maximum / chunkSize); Int3 objectChunkMax(objectBoundsCascade.Maximum / chunkSize);
Matrix worldToLocal, volumeToWorld; Matrix localToWorldM, worldToLocal, volumeToWorld;
Matrix::Invert(localToWorld, worldToLocal); Matrix::Transformation(localToWorld.Scale, localToWorld.Orientation, localToWorld.Translation - _sdfData->Origin, localToWorldM);
Matrix::Invert(localToWorldM, worldToLocal);
BoundingBox localVolumeBounds(sdf.LocalBoundsMin, sdf.LocalBoundsMax); BoundingBox localVolumeBounds(sdf.LocalBoundsMin, sdf.LocalBoundsMax);
Float3 volumeLocalBoundsExtent = localVolumeBounds.GetSize() * 0.5f; Float3 volumeLocalBoundsExtent = localVolumeBounds.GetSize() * 0.5f;
Matrix worldToVolume = worldToLocal * Matrix::Translation(-(localVolumeBounds.Minimum + volumeLocalBoundsExtent)); Matrix worldToVolume = worldToLocal * Matrix::Translation(-(localVolumeBounds.Minimum + volumeLocalBoundsExtent));
@@ -862,7 +869,7 @@ void GlobalSignDistanceFieldPass::RasterizeModelSDF(Actor* actor, const ModelBas
// Pick the SDF mip for the cascade // Pick the SDF mip for the cascade
int32 mipLevelIndex = 1; int32 mipLevelIndex = 1;
float worldUnitsPerVoxel = sdf.WorldUnitsPerVoxel * localToWorld.GetScaleVector().MaxValue() * 2; float worldUnitsPerVoxel = sdf.WorldUnitsPerVoxel * localToWorld.Scale.MaxValue() * 2;
while (_voxelSize > worldUnitsPerVoxel && mipLevelIndex < sdf.Texture->MipLevels()) while (_voxelSize > worldUnitsPerVoxel && mipLevelIndex < sdf.Texture->MipLevels())
{ {
mipLevelIndex++; mipLevelIndex++;
@@ -925,7 +932,7 @@ void GlobalSignDistanceFieldPass::RasterizeModelSDF(Actor* actor, const ModelBas
} }
} }
void GlobalSignDistanceFieldPass::RasterizeHeightfield(Actor* actor, GPUTexture* heightfield, const Matrix& localToWorld, const BoundingBox& objectBounds, const Float4& localToUV) void GlobalSignDistanceFieldPass::RasterizeHeightfield(Actor* actor, GPUTexture* heightfield, const Transform& localToWorld, const BoundingBox& objectBounds, const Float4& localToUV)
{ {
if (!heightfield || heightfield->ResidentMipLevels() == 0) if (!heightfield || heightfield->ResidentMipLevels() == 0)
return; return;
@@ -933,9 +940,9 @@ void GlobalSignDistanceFieldPass::RasterizeHeightfield(Actor* actor, GPUTexture*
// Setup object data // Setup object data
BoundingBox objectBoundsCascade; BoundingBox objectBoundsCascade;
const float objectMargin = _voxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN; const float objectMargin = _voxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN;
Vector3::Clamp(objectBounds.Minimum - objectMargin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum); Vector3::Clamp(objectBounds.Minimum - _sdfData->Origin - objectMargin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum);
Vector3::Subtract(objectBoundsCascade.Minimum, _cascadeBounds.Minimum, objectBoundsCascade.Minimum); Vector3::Subtract(objectBoundsCascade.Minimum, _cascadeBounds.Minimum, objectBoundsCascade.Minimum);
Vector3::Clamp(objectBounds.Maximum + objectMargin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum); Vector3::Clamp(objectBounds.Maximum - _sdfData->Origin + objectMargin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum);
Vector3::Subtract(objectBoundsCascade.Maximum, _cascadeBounds.Minimum, objectBoundsCascade.Maximum); Vector3::Subtract(objectBoundsCascade.Maximum, _cascadeBounds.Minimum, objectBoundsCascade.Maximum);
const float chunkSize = _voxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_SIZE; const float chunkSize = _voxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_SIZE;
const Int3 objectChunkMin(objectBoundsCascade.Minimum / chunkSize); const Int3 objectChunkMin(objectBoundsCascade.Minimum / chunkSize);
@@ -944,10 +951,11 @@ void GlobalSignDistanceFieldPass::RasterizeHeightfield(Actor* actor, GPUTexture*
// Add object data for the GPU buffer // Add object data for the GPU buffer
uint16 objectIndex = _objectsBufferCount++; uint16 objectIndex = _objectsBufferCount++;
ObjectRasterizeData objectData; ObjectRasterizeData objectData;
Matrix worldToLocal; Matrix localToWorldM, worldToLocal;
Matrix::Invert(localToWorld, worldToLocal); Matrix::Transformation(localToWorld.Scale, localToWorld.Orientation, localToWorld.Translation - _sdfData->Origin, localToWorldM);
Matrix::Invert(localToWorldM, worldToLocal);
Matrix::Transpose(worldToLocal, objectData.WorldToVolume); Matrix::Transpose(worldToLocal, objectData.WorldToVolume);
Matrix::Transpose(localToWorld, objectData.VolumeToWorld); Matrix::Transpose(localToWorldM, objectData.VolumeToWorld);
objectData.VolumeToUVWMul = Float3(localToUV.X, 1.0f, localToUV.Y); objectData.VolumeToUVWMul = Float3(localToUV.X, 1.0f, localToUV.Y);
objectData.VolumeToUVWAdd = Float3(localToUV.Z, 0.0f, localToUV.W); objectData.VolumeToUVWAdd = Float3(localToUV.Z, 0.0f, localToUV.W);
objectData.MipOffset = (float)_cascadeIndex * 0.5f; // Use lower-quality mip for far cascades objectData.MipOffset = (float)_cascadeIndex * 0.5f; // Use lower-quality mip for far cascades

View File

@@ -76,9 +76,9 @@ public:
void RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output); void RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output);
// Rasterize Model SDF into the Global SDF. Call it from actor Draw() method during DrawPass::GlobalSDF. // Rasterize Model SDF into the Global SDF. Call it from actor Draw() method during DrawPass::GlobalSDF.
void RasterizeModelSDF(Actor* actor, const ModelBase::SDFData& sdf, const Matrix& localToWorld, const BoundingBox& objectBounds); void RasterizeModelSDF(Actor* actor, const ModelBase::SDFData& sdf, const Transform& localToWorld, const BoundingBox& objectBounds);
void RasterizeHeightfield(Actor* actor, GPUTexture* heightfield, const Matrix& localToWorld, const BoundingBox& objectBounds, const Float4& localToUV); void RasterizeHeightfield(Actor* actor, GPUTexture* heightfield, const Transform& localToWorld, const BoundingBox& objectBounds, const Float4& localToUV);
private: private:
#if COMPILE_WITH_DEV_ENV #if COMPILE_WITH_DEV_ENV

View File

@@ -512,7 +512,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
context->ResetRenderTarget(); context->ResetRenderTarget();
context->ResetSR(); context->ResetSR();
context->FlushState(); context->FlushState();
// Custom Post Processing // Custom Post Processing
renderContext.List->RunMaterialPostFxPass(context, renderContext, MaterialPostFxLocation::AfterPostProcessingPass, frameBuffer, tempBuffer); renderContext.List->RunMaterialPostFxPass(context, renderContext, MaterialPostFxLocation::AfterPostProcessingPass, frameBuffer, tempBuffer);
renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::Default, frameBuffer, tempBuffer); renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::Default, frameBuffer, tempBuffer);

View File

@@ -257,6 +257,7 @@ void ShadowsPass::Prepare(RenderContext& renderContext, GPUContext* context)
shadowView.ModelLODBias = view.ModelLODBias + view.ShadowModelLODBias; shadowView.ModelLODBias = view.ModelLODBias + view.ShadowModelLODBias;
shadowView.ModelLODDistanceFactor = view.ModelLODDistanceFactor * view.ShadowModelLODDistanceFactor; shadowView.ModelLODDistanceFactor = view.ModelLODDistanceFactor * view.ShadowModelLODDistanceFactor;
shadowView.Pass = DrawPass::Depth; shadowView.Pass = DrawPass::Depth;
shadowView.Origin = view.Origin;
_shadowContext.List = &_shadowCache; _shadowContext.List = &_shadowCache;
} }

View File

@@ -152,7 +152,8 @@ void ShadowsOfMordor::Builder::onJobRender(GPUContext* context)
auto chunkSize = terrain->GetChunkSize(); auto chunkSize = terrain->GetChunkSize();
const auto heightmap = patch->Heightmap.Get()->GetTexture(); const auto heightmap = patch->Heightmap.Get()->GetTexture();
const Matrix& world = chunk->GetWorld(); Matrix world;
chunk->GetTransform().GetWorld(world);
Matrix::Transpose(world, shaderData.WorldMatrix); Matrix::Transpose(world, shaderData.WorldMatrix);
shaderData.LightmapArea = chunk->Lightmap.UVsArea; shaderData.LightmapArea = chunk->Lightmap.UVsArea;
shaderData.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize; shaderData.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;

View File

@@ -512,7 +512,6 @@ void Terrain::Draw(RenderContext& renderContext)
const float chunkSize = TERRAIN_UNITS_PER_VERTEX * (float)_chunkSize; const float chunkSize = TERRAIN_UNITS_PER_VERTEX * (float)_chunkSize;
const float posToUV = 0.25f / chunkSize; const float posToUV = 0.25f / chunkSize;
Float4 localToUV(posToUV, posToUV, 0.0f, 0.0f); Float4 localToUV(posToUV, posToUV, 0.0f, 0.0f);
Matrix localToWorld;
for (const TerrainPatch* patch : _patches) for (const TerrainPatch* patch : _patches)
{ {
if (!patch->Heightmap) if (!patch->Heightmap)
@@ -522,8 +521,7 @@ void Terrain::Draw(RenderContext& renderContext)
patchTransform.Orientation = Quaternion::Identity; patchTransform.Orientation = Quaternion::Identity;
patchTransform.Scale = Float3(1.0f, patch->_yHeight, 1.0f); patchTransform.Scale = Float3(1.0f, patch->_yHeight, 1.0f);
patchTransform = _transform.LocalToWorld(patchTransform); patchTransform = _transform.LocalToWorld(patchTransform);
patchTransform.GetWorld(localToWorld); GlobalSignDistanceFieldPass::Instance()->RasterizeHeightfield(this, patch->Heightmap->GetTexture(), patchTransform, patch->_bounds, localToUV);
GlobalSignDistanceFieldPass::Instance()->RasterizeHeightfield(this, patch->Heightmap->GetTexture(), localToWorld, patch->_bounds, localToUV);
} }
return; return;
} }
@@ -533,16 +531,17 @@ void Terrain::Draw(RenderContext& renderContext)
{ {
if (!patch->Heightmap) if (!patch->Heightmap)
continue; continue;
Matrix worldToLocal; Matrix localToWorld, worldToLocal;
BoundingSphere chunkSphere; BoundingSphere chunkSphere;
BoundingBox localBounds; BoundingBox localBounds;
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++) for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
{ {
TerrainChunk* chunk = &patch->Chunks[chunkIndex]; TerrainChunk* chunk = &patch->Chunks[chunkIndex];
Matrix::Invert(chunk->GetWorld(), worldToLocal); chunk->GetTransform().GetWorld(localToWorld); // TODO: large-worlds
Matrix::Invert(localToWorld, worldToLocal);
BoundingBox::Transform(chunk->GetBounds(), worldToLocal, localBounds); BoundingBox::Transform(chunk->GetBounds(), worldToLocal, localBounds);
BoundingSphere::FromBox(chunk->GetBounds(), chunkSphere); BoundingSphere::FromBox(chunk->GetBounds(), chunkSphere);
GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, chunk, chunkSphere, chunk->GetWorld(), localBounds, 1 << 2, false); GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, chunk, chunkSphere, chunk->GetTransform(), localBounds, 1 << 2, false);
} }
} }
return; return;

View File

@@ -86,7 +86,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext) const
return; return;
drawCall.InstanceCount = 1; drawCall.InstanceCount = 1;
drawCall.Material = _cachedDrawMaterial; drawCall.Material = _cachedDrawMaterial;
drawCall.World = _world; renderContext.View.GetWorldMatrix(_transform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation(); drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.Terrain.Patch = _patch; drawCall.Terrain.Patch = _patch;
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias; drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
@@ -142,7 +142,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* materi
return; return;
drawCall.InstanceCount = 1; drawCall.InstanceCount = 1;
drawCall.Material = material; drawCall.Material = material;
drawCall.World = _world; renderContext.View.GetWorldMatrix(_transform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation(); drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.Terrain.Patch = _patch; drawCall.Terrain.Patch = _patch;
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias; drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
@@ -214,8 +214,7 @@ void TerrainChunk::UpdateTransform()
localTransform.Translation = _patch->_offset + Vector3(_x * size, _patch->_yOffset, _z * size); localTransform.Translation = _patch->_offset + Vector3(_x * size, _patch->_yOffset, _z * size);
localTransform.Orientation = Quaternion::Identity; localTransform.Orientation = Quaternion::Identity;
localTransform.Scale = Vector3(1.0f, _patch->_yHeight, 1.0f); localTransform.Scale = Vector3(1.0f, _patch->_yHeight, 1.0f);
localTransform = terrainTransform.LocalToWorld(localTransform); _transform = terrainTransform.LocalToWorld(localTransform);
localTransform.GetWorld(_world);
} }
void TerrainChunk::CacheNeighbors() void TerrainChunk::CacheNeighbors()

View File

@@ -4,6 +4,7 @@
#include "Engine/Core/Math/BoundingBox.h" #include "Engine/Core/Math/BoundingBox.h"
#include "Engine/Core/Math/Matrix.h" #include "Engine/Core/Math/Matrix.h"
#include "Engine/Core/Math/Transform.h"
#include "Engine/Serialization/ISerializable.h" #include "Engine/Serialization/ISerializable.h"
#include "Engine/Content/Assets/MaterialBase.h" #include "Engine/Content/Assets/MaterialBase.h"
#include "Engine/Level/Scene/Lightmap.h" #include "Engine/Level/Scene/Lightmap.h"
@@ -26,7 +27,7 @@ private:
TerrainPatch* _patch; TerrainPatch* _patch;
uint16 _x, _z; uint16 _x, _z;
Float4 _heightmapUVScaleBias; Float4 _heightmapUVScaleBias;
Matrix _world; Transform _transform;
BoundingBox _bounds; BoundingBox _bounds;
Vector3 _boundsCenter; Vector3 _boundsCenter;
float _perInstanceRandom; float _perInstanceRandom;
@@ -85,11 +86,11 @@ public:
} }
/// <summary> /// <summary>
/// Gets the chunk world matrix transform. /// Gets the chunk transformation (world to local).
/// </summary> /// </summary>
FORCE_INLINE const Matrix& GetWorld() const FORCE_INLINE const Transform& GetTransform() const
{ {
return _world; return _transform;
} }
/// <summary> /// <summary>

View File

@@ -238,9 +238,9 @@ float4 PS_Debug(Quad_VS2PS input) : SV_Target
float zSlice = 0.6f; float zSlice = 0.6f;
float mip = 0; float mip = 0;
uint cascade = 0; uint cascade = 0;
float distance01 = GlobalSDFTex[cascade].SampleLevel(SamplerLinearClamp, float3(input.TexCoord, zSlice), mip).x; float distance01 = GlobalSDFTex.SampleLevel(SamplerLinearClamp, float3(input.TexCoord, zSlice), mip).x;
//float distance01 = GlobalSDFTex[cascade].SampleLevel(SamplerLinearClamp, float3((input.TexCoord.x + cascade) / (float)GlobalSDF.CascadesCount, input.TexCoord.y, zSlice), mip).x; //float distance01 = GlobalSDFTex.SampleLevel(SamplerLinearClamp, float3((input.TexCoord.x + cascade) / (float)GlobalSDF.CascadesCount, input.TexCoord.y, zSlice), mip).x;
//float distance01 = GlobalSDFMip[cascade].SampleLevel(SamplerLinearClamp, float3(input.TexCoord, zSlice), mip).x; //float distance01 = GlobalSDFMip.SampleLevel(SamplerLinearClamp, float3(input.TexCoord, zSlice), mip).x;
float distance = distance01 * GlobalSDF.CascadePosDistance[cascade].w; float distance = distance01 * GlobalSDF.CascadePosDistance[cascade].w;
if (abs(distance) < 1) if (abs(distance) < 1)
return float4(1, 0, 0, 1); return float4(1, 0, 0, 1);

View File

@@ -8,6 +8,8 @@
META_CB_BEGIN(0, Data) META_CB_BEGIN(0, Data)
float4x4 WVP; float4x4 WVP;
float3 ViewOffset;
float Padding;
GBufferData GBuffer; GBufferData GBuffer;
AtmosphericFogData AtmosphericFog; AtmosphericFogData AtmosphericFog;
META_CB_END META_CB_END
@@ -51,8 +53,7 @@ GBufferOutput PS_Sky(MaterialInput input)
float3 vsPos = GetViewPos(gBufferData, uv, LinearZ2DeviceDepth(gBufferData, 1)); float3 vsPos = GetViewPos(gBufferData, uv, LinearZ2DeviceDepth(gBufferData, 1));
float3 wsPos = mul(float4(vsPos, 1), gBufferData.InvViewMatrix).xyz; float3 wsPos = mul(float4(vsPos, 1), gBufferData.InvViewMatrix).xyz;
float3 viewVector = wsPos - gBufferData.ViewPos; float3 viewVector = wsPos - gBufferData.ViewPos;
float sceneDepth = length(viewVector); float4 color = GetAtmosphericFog(AtmosphericFog, gBufferData.ViewFar, wsPos + ViewOffset, gBufferData.ViewPos + ViewOffset);
float4 color = GetAtmosphericFog(AtmosphericFog, gBufferData.ViewFar, gBufferData.ViewPos, viewVector, sceneDepth, float3(0, 0, 0));
// Pack GBuffer // Pack GBuffer
output.Light = color; output.Light = color;