Fixes for Foliage with Large Worlds usage

This commit is contained in:
Wojtek Figat
2022-07-03 16:08:22 +02:00
parent 62ff305fad
commit d9dc23afc1
8 changed files with 61 additions and 56 deletions

View File

@@ -104,12 +104,15 @@ void Foliage::DrawInstance(RenderContext& renderContext, FoliageInstance& instan
// Add instance to the draw batch
auto& instanceData = e->Instances.AddOne();
instanceData.InstanceOrigin = Float3(instance.World.M41, instance.World.M42, instance.World.M43);
Matrix world;
const Transform transform = _transform.LocalToWorld(instance.Transform);
renderContext.View.GetWorldMatrix(transform, world);
instanceData.InstanceOrigin = Float3(world.M41, world.M42, world.M43);
instanceData.PerInstanceRandom = instance.Random;
instanceData.InstanceTransform1 = Float3(instance.World.M11, instance.World.M12, instance.World.M13);
instanceData.InstanceTransform1 = Float3(world.M11, world.M12, world.M13);
instanceData.LODDitherFactor = lodDitherFactor;
instanceData.InstanceTransform2 = Float3(instance.World.M21, instance.World.M22, instance.World.M23);
instanceData.InstanceTransform3 = Float3(instance.World.M31, instance.World.M32, instance.World.M33);
instanceData.InstanceTransform2 = Float3(world.M21, world.M22, world.M23);
instanceData.InstanceTransform3 = Float3(world.M31, world.M32, world.M33);
instanceData.InstanceLightmapArea = Half4(instance.Lightmap.UVsArea);
}
}
@@ -117,7 +120,8 @@ void Foliage::DrawInstance(RenderContext& renderContext, FoliageInstance& instan
void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, FoliageType& type, DrawCallsList* drawCallsLists, BatchedDrawCalls& result) const
{
// Skip clusters that around too far from view
if (Vector3::Distance(renderContext.View.Position, cluster->TotalBoundsSphere.Center) - cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance)
const Vector3 viewOrigin = renderContext.View.Origin;
if (Float3::Distance(renderContext.View.Position, cluster->TotalBoundsSphere.Center - viewOrigin) - (float)cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance)
return;
//DebugDraw::DrawBox(cluster->Bounds, Color::Red);
@@ -128,8 +132,12 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster,
// Don't store instances in non-leaf nodes
ASSERT_LOW_LAYER(cluster->Instances.IsEmpty());
BoundingBox box;
#define DRAW_CLUSTER(idx) \
if (renderContext.View.CullingFrustum.Intersects(cluster->Children[idx]->TotalBounds)) \
box = cluster->Children[idx]->TotalBounds; \
box.Minimum -= viewOrigin; \
box.Maximum -= viewOrigin; \
if (renderContext.View.CullingFrustum.Intersects(box)) \
DrawCluster(renderContext, cluster->Children[idx], type, drawCallsLists, result)
DRAW_CLUSTER(0);
DRAW_CLUSTER(1);
@@ -145,13 +153,15 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster,
for (int32 i = 0; i < cluster->Instances.Count(); i++)
{
auto& instance = *cluster->Instances[i];
if (Vector3::Distance(renderContext.View.Position, instance.Bounds.Center) - instance.Bounds.Radius < instance.CullDistance &&
renderContext.View.CullingFrustum.Intersects(instance.Bounds))
BoundingSphere sphere = instance.Bounds;
sphere.Center -= viewOrigin;
if (Float3::Distance(renderContext.View.Position, sphere.Center) - (float)sphere.Radius < instance.CullDistance &&
renderContext.View.CullingFrustum.Intersects(sphere))
{
const auto modelFrame = instance.DrawState.PrevFrame + 1;
// Select a proper LOD index (model may be culled)
int32 lodIndex = RenderTools::ComputeModelLOD(model, instance.Bounds.Center, (float)instance.Bounds.Radius, renderContext); // TODO: large-worlds
int32 lodIndex = RenderTools::ComputeModelLOD(model, sphere.Center, (float)sphere.Radius, renderContext);
if (lodIndex == -1)
{
// Handling model fade-out transition
@@ -239,7 +249,8 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster,
void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster, Mesh::DrawInfo& draw)
{
// Skip clusters that around too far from view
if (Vector3::Distance(renderContext.View.Position, cluster->TotalBoundsSphere.Center) - cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance)
const Vector3 viewOrigin = renderContext.View.Origin;
if (Float3::Distance(renderContext.View.Position, cluster->TotalBoundsSphere.Center - viewOrigin) - (float)cluster->TotalBoundsSphere.Radius > cluster->MaxCullDistance)
return;
//DebugDraw::DrawBox(cluster->Bounds, Color::Red);
@@ -250,8 +261,12 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster,
// Don't store instances in non-leaf nodes
ASSERT_LOW_LAYER(cluster->Instances.IsEmpty());
BoundingBox box;
#define DRAW_CLUSTER(idx) \
if (renderContext.View.CullingFrustum.Intersects(cluster->Children[idx]->TotalBounds)) \
box = cluster->Children[idx]->TotalBounds; \
box.Minimum -= viewOrigin; \
box.Maximum -= viewOrigin; \
if (renderContext.View.CullingFrustum.Intersects(box)) \
DrawCluster(renderContext, cluster->Children[idx], draw)
DRAW_CLUSTER(0);
DRAW_CLUSTER(1);
@@ -267,22 +282,28 @@ void Foliage::DrawCluster(RenderContext& renderContext, FoliageCluster* cluster,
{
auto& instance = *cluster->Instances[i];
auto& type = FoliageTypes[instance.Type];
BoundingSphere sphere = instance.Bounds;
sphere.Center -= viewOrigin;
// Check if can draw this instance
if (type._canDraw &&
Vector3::Distance(renderContext.View.Position, instance.Bounds.Center) - instance.Bounds.Radius < instance.CullDistance &&
renderContext.View.CullingFrustum.Intersects(instance.Bounds))
Float3::Distance(renderContext.View.Position, sphere.Center) - (float)sphere.Radius < instance.CullDistance &&
renderContext.View.CullingFrustum.Intersects(sphere))
{
Matrix world;
const Transform transform = _transform.LocalToWorld(instance.Transform);
renderContext.View.GetWorldMatrix(transform, world);
// Disable motion blur
instance.DrawState.PrevWorld = instance.World;
instance.DrawState.PrevWorld = world;
// Draw model
draw.Lightmap = _scene->LightmapsData.GetReadyLightmap(instance.Lightmap.TextureIndex);
draw.LightmapUVs = &instance.Lightmap.UVsArea;
draw.Buffer = &type.Entries;
draw.World = &instance.World;
draw.World = &world;
draw.DrawState = &instance.DrawState;
draw.Bounds = instance.Bounds;
draw.Bounds = sphere;
draw.PerInstanceRandom = instance.Random;
draw.DrawModes = type._drawModes;
type.Model->Draw(renderContext, draw);
@@ -411,13 +432,6 @@ void Foliage::AddInstance(const FoliageInstance& instance)
data->Random = Random::Rand();
data->CullDistance = type->CullDistance + type->CullDistanceRandomRange * data->Random;
// Calculate foliage instance geometry transformation matrix
Matrix matrix, world;
GetLocalToWorldMatrix(world);
data->Transform.GetWorld(matrix);
Matrix::Multiply(matrix, world, data->World);
data->DrawState.PrevWorld = data->World;
// Validate foliage type model
if (!type->IsReady())
return;
@@ -425,13 +439,14 @@ void Foliage::AddInstance(const FoliageInstance& instance)
// Update bounds
Vector3 corners[8];
auto& meshes = type->Model->LODs[0].Meshes;
const Transform transform = _transform.LocalToWorld(data->Transform);
for (int32 j = 0; j < meshes.Count(); j++)
{
meshes[j].GetBox().GetCorners(corners);
for (int32 k = 0; k < 8; k++)
{
Vector3::Transform(corners[k], data->World, corners[k]);
Vector3::Transform(corners[k], transform, corners[k]);
}
BoundingSphere meshBounds;
BoundingSphere::FromPoints(corners, 8, meshBounds);
@@ -455,25 +470,20 @@ void Foliage::SetInstanceTransform(int32 index, const Transform& value)
// Change transform
instance.Transform = value;
// Update world matrix
Matrix matrix, world;
GetLocalToWorldMatrix(world);
instance.Transform.GetWorld(matrix);
Matrix::Multiply(matrix, world, instance.World);
// Update bounds
instance.Bounds = BoundingSphere::Empty;
if (!type->IsReady())
return;
Vector3 corners[8];
auto& meshes = type->Model->LODs[0].Meshes;
const Transform transform = _transform.LocalToWorld(instance.Transform);
for (int32 j = 0; j < meshes.Count(); j++)
{
meshes[j].GetBox().GetCorners(corners);
for (int32 k = 0; k < 8; k++)
{
Vector3::Transform(corners[k], instance.World, corners[k]);
Vector3::Transform(corners[k], transform, corners[k]);
}
BoundingSphere meshBounds;
BoundingSphere::FromPoints(corners, 8, meshBounds);
@@ -507,6 +517,7 @@ void Foliage::OnFoliageTypeModelLoaded(int32 index)
if (instance.Type != index)
continue;
instance.Bounds = BoundingSphere::Empty;
const Transform transform = _transform.LocalToWorld(instance.Transform);
// Include all meshes
for (int32 j = 0; j < meshes.Count(); j++)
@@ -517,7 +528,7 @@ void Foliage::OnFoliageTypeModelLoaded(int32 index)
// TODO: use SIMD
for (int32 k = 0; k < 8; k++)
{
Vector3::Transform(corners[k], instance.World, corners[k]);
Vector3::Transform(corners[k], transform, corners[k]);
}
BoundingSphere meshBounds;
BoundingSphere::FromPoints(corners, 8, meshBounds);
@@ -1271,22 +1282,19 @@ void Foliage::OnTransformChanged()
auto& instance = *i;
auto type = &FoliageTypes[instance.Type];
// Update world matrix
instance.Transform.GetWorld(matrix);
Matrix::Multiply(matrix, world, instance.World);
// Update bounds
instance.Bounds = BoundingSphere::Empty;
if (!type->IsReady())
continue;
auto& meshes = type->Model->LODs[0].Meshes;
const Transform transform = _transform.LocalToWorld(instance.Transform);
for (int32 j = 0; j < meshes.Count(); j++)
{
meshes[j].GetBox().GetCorners(corners);
for (int32 k = 0; k < 8; k++)
{
Vector3::Transform(corners[k], instance.World, corners[k]);
Vector3::Transform(corners[k], transform, corners[k]);
}
BoundingSphere meshBounds;
BoundingSphere::FromPoints(corners, 8, meshBounds);

View File

@@ -118,7 +118,8 @@ bool FoliageCluster::Intersects(Foliage* foliage, const Ray& ray, Real& distance
{
auto& ii = *Instances[i];
auto& type = foliage->FoliageTypes[ii.Type];
if (type.IsReady() && ii.Bounds.Intersects(ray) && type.Model->Intersects(ray, ii.World, distance, normal, &mesh) && minDistance > distance)
const Transform transform = foliage->GetTransform().LocalToWorld(ii.Transform);
if (type.IsReady() && ii.Bounds.Intersects(ray) && type.Model->Intersects(ray, transform, distance, normal, &mesh) && minDistance > distance)
{
minDistanceNormal = normal;
minDistance = distance;

View File

@@ -19,11 +19,6 @@ API_STRUCT(NoPod) struct FLAXENGINE_API FoliageInstance
/// </summary>
API_FIELD() Transform Transform;
/// <summary>
/// The cached world transformation matrix of this instance.
/// </summary>
API_FIELD() Matrix World;
/// <summary>
/// The model drawing state.
/// </summary>

View File

@@ -72,6 +72,7 @@ namespace
{
Actor* FindActorByDrawCall(Actor* actor, const DrawCall& drawCall, float& scaleInLightmap)
{
// TODO: large-worlds
const auto asStaticModel = ScriptingObject::Cast<StaticModel>(actor);
if (asStaticModel && asStaticModel->GetPerInstanceRandom() == drawCall.PerInstanceRandom && asStaticModel->GetPosition() == drawCall.ObjectPosition)
{

View File

@@ -188,7 +188,9 @@ void ShadowsOfMordor::Builder::onJobRender(GPUContext* context)
auto& instance = foliage->Instances[entry.AsFoliage.InstanceIndex];
auto& type = foliage->FoliageTypes[entry.AsFoliage.TypeIndex];
Matrix::Transpose(instance.World, shaderData.WorldMatrix);
Matrix world;
foliage->GetTransform().LocalToWorld(instance.Transform).GetWorld(world);
Matrix::Transpose(world, shaderData.WorldMatrix);
shaderData.LightmapArea = instance.Lightmap.UVsArea;
context->UpdateCB(cb, &shaderData);