Fixes for Foliage with Large Worlds usage
This commit is contained in:
@@ -216,10 +216,9 @@ namespace FlaxEditor.Tools.Foliage
|
||||
var model = foliage.GetFoliageType(instance.Type).Model;
|
||||
if (model)
|
||||
{
|
||||
foliage.GetLocalToWorldMatrix(out var world);
|
||||
instance.Transform.GetWorld(out var matrix);
|
||||
Matrix.Multiply(ref matrix, ref world, out var instanceWorld);
|
||||
model.Draw(ref renderContext, _highlightMaterial, ref instanceWorld, StaticFlags.None, false);
|
||||
var transform = foliage.Transform.LocalToWorld(instance.Transform);
|
||||
renderContext.View.GetWorldMatrix(ref transform, out var world);
|
||||
model.Draw(ref renderContext, _highlightMaterial, ref world, StaticFlags.None, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -250,11 +250,13 @@ void FoliageTools::Paint(Foliage* foliage, Span<int32> foliageTypesIndices, cons
|
||||
{
|
||||
// Skip if any places instance is close that placement location
|
||||
bool isInvalid = false;
|
||||
const Transform foliageTransform = foliage->GetTransform();
|
||||
// TODO: use quad tree to boost this logic
|
||||
for (auto i = foliage->Instances.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
const auto& instance = *i;
|
||||
if (Vector3::DistanceSquared(instance.World.GetTranslation(), placement.Location) <= paintRadiusSqr)
|
||||
const Vector3 instancePosition = foliageTransform.LocalToWorld(instance.Transform.Translation);
|
||||
if (Vector3::DistanceSquared(instancePosition, placement.Location) <= paintRadiusSqr)
|
||||
{
|
||||
isInvalid = true;
|
||||
break;
|
||||
@@ -339,11 +341,6 @@ void FoliageTools::Paint(Foliage* foliage, Span<int32> foliageTypesIndices, cons
|
||||
// Convert instance transformation into the local-space of the foliage actor
|
||||
foliage->GetTransform().WorldToLocal(instance.Transform, instance.Transform);
|
||||
|
||||
// Calculate foliage instance geometry transformation matrix
|
||||
instance.Transform.GetWorld(matrix);
|
||||
Matrix::Multiply(matrix, world, instance.World);
|
||||
instance.DrawState.PrevWorld = instance.World;
|
||||
|
||||
// Add foliage instance
|
||||
foliage->AddInstance(instance);
|
||||
}
|
||||
@@ -361,12 +358,14 @@ void FoliageTools::Remove(Foliage* foliage, Span<int32> foliageTypesIndices, con
|
||||
|
||||
// For each selected foliage instance type try to remove something
|
||||
const BoundingSphere brush(brushPosition, brushRadius);
|
||||
const Transform foliageTransform = foliage->GetTransform();
|
||||
for (auto i = foliage->Instances.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
auto& instance = *i;
|
||||
|
||||
// Skip instances outside the brush
|
||||
if (CollisionsHelper::SphereContainsPoint(brush, instance.World.GetTranslation()) == ContainmentType::Disjoint)
|
||||
const Vector3 instancePosition = foliageTransform.LocalToWorld(instance.Transform.Translation);
|
||||
if (CollisionsHelper::SphereContainsPoint(brush, instancePosition) == ContainmentType::Disjoint)
|
||||
continue;
|
||||
|
||||
// Skip instances not existing in a filter
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace FlaxEditor.Tools.Foliage
|
||||
rotation = Quaternion.RotationZ(Mathf.Pi);
|
||||
else
|
||||
rotation = Quaternion.LookRotation(Vector3.Cross(Vector3.Cross(brushNormal, Vector3.Forward), brushNormal), brushNormal);
|
||||
Matrix transform = Matrix.Scaling(Mode.CurrentBrush.Size * 0.01f) * Matrix.RotationQuaternion(rotation) * Matrix.Translation(brushPosition);
|
||||
Matrix transform = Matrix.Scaling(Mode.CurrentBrush.Size * 0.01f) * Matrix.RotationQuaternion(rotation) * Matrix.Translation(brushPosition - renderContext.View.Origin);
|
||||
_brushModel.Draw(ref renderContext, brushMaterial, ref transform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user