Files
FlaxEngine/Source/Engine/Foliage/FoliageCluster.cpp
2021-01-02 14:28:49 +01:00

136 lines
4.1 KiB
C++

// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "FoliageCluster.h"
#include "FoliageInstance.h"
#include "Foliage.h"
void FoliageCluster::Init(const BoundingBox& bounds)
{
Bounds = bounds;
TotalBounds = bounds;
MaxCullDistance = 0.0f;
Children[0] = nullptr;
Children[1] = nullptr;
Children[2] = nullptr;
Children[3] = nullptr;
Instances.Clear();
}
void FoliageCluster::UpdateTotalBoundsAndCullDistance()
{
if (Children[0])
{
ASSERT(Instances.IsEmpty());
Children[0]->UpdateTotalBoundsAndCullDistance();
Children[1]->UpdateTotalBoundsAndCullDistance();
Children[2]->UpdateTotalBoundsAndCullDistance();
Children[3]->UpdateTotalBoundsAndCullDistance();
TotalBounds = Children[0]->TotalBounds;
BoundingBox::Merge(TotalBounds, Children[1]->TotalBounds, TotalBounds);
BoundingBox::Merge(TotalBounds, Children[2]->TotalBounds, TotalBounds);
BoundingBox::Merge(TotalBounds, Children[3]->TotalBounds, TotalBounds);
MaxCullDistance = Children[0]->MaxCullDistance;
MaxCullDistance = Math::Max(MaxCullDistance, Children[1]->MaxCullDistance);
MaxCullDistance = Math::Max(MaxCullDistance, Children[2]->MaxCullDistance);
MaxCullDistance = Math::Max(MaxCullDistance, Children[3]->MaxCullDistance);
}
else if (Instances.HasItems())
{
BoundingBox box;
BoundingBox::FromSphere(Instances[0]->Bounds, TotalBounds);
MaxCullDistance = Instances[0]->CullDistance;
for (int32 i = 1; i < Instances.Count(); i++)
{
BoundingBox::FromSphere(Instances[i]->Bounds, box);
BoundingBox::Merge(TotalBounds, box, TotalBounds);
MaxCullDistance = Math::Max(MaxCullDistance, Instances[i]->CullDistance);
}
}
else
{
TotalBounds = Bounds;
MaxCullDistance = 0;
}
BoundingSphere::FromBox(TotalBounds, TotalBoundsSphere);
}
void FoliageCluster::UpdateCullDistance()
{
if (Children[0])
{
Children[0]->UpdateCullDistance();
Children[1]->UpdateCullDistance();
Children[2]->UpdateCullDistance();
Children[3]->UpdateCullDistance();
MaxCullDistance = Children[0]->MaxCullDistance;
MaxCullDistance = Math::Max(MaxCullDistance, Children[1]->MaxCullDistance);
MaxCullDistance = Math::Max(MaxCullDistance, Children[2]->MaxCullDistance);
MaxCullDistance = Math::Max(MaxCullDistance, Children[3]->MaxCullDistance);
}
else if (Instances.HasItems())
{
MaxCullDistance = Instances[0]->CullDistance;
for (int32 i = 1; i < Instances.Count(); i++)
{
MaxCullDistance = Math::Max(MaxCullDistance, Instances[i]->CullDistance);
}
}
else
{
MaxCullDistance = 0;
}
}
bool FoliageCluster::Intersects(Foliage* foliage, const Ray& ray, float& distance, Vector3& normal, FoliageInstance*& instance)
{
bool result = false;
float minDistance = MAX_float;
Vector3 minDistanceNormal = Vector3::Up;
FoliageInstance* minInstance = nullptr;
if (Children[0])
{
#define CHECK_CHILD(idx) \
if (Children[idx]->TotalBounds.Intersects(ray) && Children[idx]->Intersects(foliage, ray, distance, normal, instance) && minDistance > distance) \
{ \
minDistanceNormal = normal; \
minDistance = distance; \
minInstance = instance; \
result = true; \
}
CHECK_CHILD(0);
CHECK_CHILD(1);
CHECK_CHILD(2);
CHECK_CHILD(3);
#undef CHECK_CHILD
}
else
{
Mesh* mesh;
for (int32 i = 0; i < Instances.Count(); i++)
{
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)
{
minDistanceNormal = normal;
minDistance = distance;
minInstance = &ii;
result = true;
}
}
}
distance = minDistance;
normal = minDistanceNormal;
instance = minInstance;
return result;
}