Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
/active_project
/test/assets/assets.db
/test/products/
_codeql_detected_source_root
10 changes: 10 additions & 0 deletions runtime/core/include/core/shapes/AABB.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ namespace sky {
inline constexpr AABB(Vector3 min_, Vector3 max_) : min(min_), max(max_) {}

static AABB Transform(const AABB& box, const Matrix4 &matrix);

inline Vector3 GetCenter() const { return (min + max) / 2.f; }
inline Vector3 GetExtent() const { return (max - min) / 2.f; }
inline bool IsValid() const { return min.x <= max.x && min.y <= max.y && min.z <= max.z; }
inline bool Contains(const Vector3 &point) const
{
return point.x >= min.x && point.x <= max.x &&
point.y >= min.y && point.y <= max.y &&
point.z >= min.z && point.z <= max.z;
}
};

void Merge(const AABB &a, const AABB &b, AABB &out);
Expand Down
87 changes: 87 additions & 0 deletions runtime/core/include/core/shapes/BoundingVolume.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// Created for volume management system
//

#pragma once

#include <cstdint>
#include <core/shapes/AABB.h>
#include <core/shapes/Base.h>
#include <core/shapes/Frustum.h>
#include <core/shapes/Shapes.h>

namespace sky {

class BoundingVolume {
public:
enum class Type : uint8_t {
NONE,
BOX,
SPHERE
};

BoundingVolume() = default;
explicit BoundingVolume(const AABB &aabb) : type(Type::BOX), aabb(aabb) {}
explicit BoundingVolume(const Sphere &sphere) : type(Type::SPHERE), sphere(sphere) {}

Type GetType() const { return type; }

const AABB &GetAABB() const { return aabb; }
const Sphere &GetSphere() const { return sphere; }

void SetAABB(const AABB &box)
{
type = Type::BOX;
aabb = box;
}

void SetSphere(const Sphere &sph)
{
type = Type::SPHERE;
sphere = sph;
}

AABB ToAABB() const
{
switch (type) {
case Type::BOX:
return aabb;
case Type::SPHERE:
return AABB{sphere.center - Vector3(sphere.radius),
sphere.center + Vector3(sphere.radius)};
default:
return {};
}
}

bool IntersectsFrustum(const Frustum &frustum) const
{
switch (type) {
case Type::BOX:
return Intersection(aabb, frustum);
case Type::SPHERE:
return Intersection(sphere, frustum);
default:
return false;
}
}

bool IntersectsAABB(const AABB &other) const
{
switch (type) {
case Type::BOX:
return Intersection(aabb, other);
case Type::SPHERE:
return Intersection(sphere, other);
default:
return false;
}
}

private:
Type type = Type::NONE;
AABB aabb;
Sphere sphere;
};

} // namespace sky
3 changes: 3 additions & 0 deletions runtime/core/include/core/shapes/Shapes.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ namespace sky {
bool Intersection(const AABB &lhs, const AABB &rhs);
bool Intersection(const AABB &aabb, const Frustum &frustum);
std::pair<bool, int> Intersection(const AABB &aabb, const Plane &plane);
bool Intersection(const Sphere &sphere, const Frustum &frustum);
bool Intersection(const Sphere &sphere, const AABB &aabb);
std::pair<bool, int> Intersection(const Sphere &sphere, const Plane &plane);

// utils
Plane CreatePlaneByVertices(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3);
Expand Down
31 changes: 31 additions & 0 deletions runtime/core/include/core/tree/OctTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,37 @@ namespace sky {
ForeachWithBoundTestWith(0, bounds, func);
}

template <typename NodeTest, typename Func>
void ForeachWithNodeTestWith(NodeIndex index, const NodeTest &nodeTest, const Func &func)
{
if (nodes[index].numElements > 0) {
AABB nodeBox{
nodes[index].origin - Vector3(nodes[index].ext),
nodes[index].origin + Vector3(nodes[index].ext)
};
if (!nodeTest(nodeBox)) {
return;
}

for (auto &element : elements[index]) {
func(element);
}

if (!nodes[index].IsLeaf()) {
auto childStart = nodes[index].idxChild;
for (uint8_t i = 0; i < 8; ++i) {
ForeachWithNodeTestWith(childStart + i, nodeTest, func);
}
}
}
}

template <typename NodeTest, typename Func>
void ForeachWithNodeTest(const NodeTest &nodeTest, const Func &func)
{
ForeachWithNodeTestWith(0, nodeTest, func);
}

explicit Octree(float maxExtent, const Vector3 &ori = VEC3_ZERO)
: leafExtent(maxExtent * std::pow(0.5f, static_cast<float>(MAX_DEPTH)))
{
Expand Down
118 changes: 118 additions & 0 deletions runtime/core/include/core/tree/VolumeManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//
// Created for volume management system
//

#pragma once

#include <cstdint>
#include <unordered_map>
#include <core/shapes/AABB.h>
#include <core/shapes/Frustum.h>
#include <core/shapes/Shapes.h>
#include <core/tree/OctTree.h>

namespace sky {

using VolumeID = uint32_t;
static constexpr VolumeID INVALID_VOLUME_ID = ~(0U);

struct VolumeEntry {
VolumeID id = INVALID_VOLUME_ID;
AABB worldBound;
void *userData = nullptr;

mutable Octree<VolumeEntry*>::ElementIndex octreeIndex;
};

template <>
struct OctreeTraits<VolumeEntry*> {
static constexpr uint32_t MAX_DEPTH = 8;
static constexpr uint32_t MAX_ELEMENT_LEAF = 8;

using BoundType = AABB;

static const AABB &GetBounds(VolumeEntry *const &entry)
{
return entry->worldBound;
}

static void IndexChanged(VolumeEntry *const &entry, const Octree<VolumeEntry*>::ElementIndex &index)
{
entry->octreeIndex = index;
}
};

class VolumeManager {
public:
explicit VolumeManager(float worldExtent = 2048.f, const Vector3 &origin = VEC3_ZERO)
: octree(worldExtent, origin)
{
}

~VolumeManager() = default;

VolumeID AddVolume(const AABB &worldBound, void *userData = nullptr)
{
VolumeID id = nextID++;
auto [it, ok] = entries.emplace(id, VolumeEntry{id, worldBound, userData});
octree.AddElement(&it->second);
return id;
}

void RemoveVolume(VolumeID id)
{
auto it = entries.find(id);
if (it != entries.end()) {
octree.RemoveElement(it->second.octreeIndex);
entries.erase(it);
}
}

void UpdateVolume(VolumeID id, const AABB &newBound)
{
auto it = entries.find(id);
if (it != entries.end()) {
octree.RemoveElement(it->second.octreeIndex);
it->second.worldBound = newBound;
octree.AddElement(&it->second);
}
}

template <typename Func>
void FrustumCull(const Frustum &frustum, const Func &callback)
{
octree.ForeachWithNodeTest(
[&frustum](const AABB &nodeBox) {
return Intersection(nodeBox, frustum);
},
[&callback, &frustum](VolumeEntry *entry) {
if (Intersection(entry->worldBound, frustum)) {
callback(*entry);
}
}
);
}

template <typename Func>
void QueryByAABB(const AABB &queryBound, const Func &callback)
{
octree.ForeachWithBoundTest(queryBound, [&callback](VolumeEntry *entry) {
callback(*entry);
});
}

size_t GetVolumeCount() const { return entries.size(); }

const VolumeEntry *FindVolume(VolumeID id) const
{
auto it = entries.find(id);
return it != entries.end() ? &it->second : nullptr;
}

private:
VolumeID nextID = 0;
std::unordered_map<VolumeID, VolumeEntry> entries;
Octree<VolumeEntry*> octree;
};

} // namespace sky
34 changes: 34 additions & 0 deletions runtime/core/src/shapes/Shapes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,40 @@ namespace sky {
});
}

std::pair<bool, int> Intersection(const Sphere &sphere, const Plane &plane)
{
float dist = plane.normal.Dot(sphere.center) - plane.distance;
if (std::abs(dist) <= sphere.radius) {
return {true, 0};
}
return {false, dist > 0.f ? 1 : -1};
}

bool Intersection(const Sphere &sphere, const AABB &aabb)
{
float sqDist = 0.f;
for (int i = 0; i < 3; ++i) {
float v = sphere.center[i];
if (v < aabb.min[i]) {
float d = aabb.min[i] - v;
sqDist += d * d;
}
if (v > aabb.max[i]) {
float d = v - aabb.max[i];
sqDist += d * d;
}
}
return sqDist <= sphere.radius * sphere.radius;
}

bool Intersection(const Sphere &sphere, const Frustum &frustum)
{
return std::all_of(frustum.planes.begin(), frustum.planes.end(),
[&sphere](const Plane &plane) {
return Intersection(sphere, plane).second <= 0;
});
}


Plane CreatePlaneByVertices(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
{
Expand Down
3 changes: 3 additions & 0 deletions runtime/render/core/include/render/RenderPrimitive.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ namespace sky {
AABB localBound {Vector3(std::numeric_limits<float>::min()), Vector3(std::numeric_limits<float>::max())};
AABB worldBound {Vector3(std::numeric_limits<float>::min()), Vector3(std::numeric_limits<float>::max())};

// volume management
uint32_t volumeId = ~(0U);

// geometry
RenderVertexFlags vertexFlags;
RenderGeometryPtr geometry;
Expand Down
5 changes: 5 additions & 0 deletions runtime/render/core/include/render/RenderScene.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <vector>
#include <core/std/Container.h>
#include <core/tree/VolumeManager.h>
#include <render/SceneView.h>
#include <render/RenderPrimitive.h>
#include <render/RenderPipeline.h>
Expand Down Expand Up @@ -35,6 +36,9 @@ namespace sky {

const RenderPipelineFlags &GetRenderPipelineFlags() const { return renderFlags; }

VolumeManager &GetVolumeManager() { return volumeManager; }
const VolumeManager &GetVolumeManager() const { return volumeManager; }

template <typename T>
T *GetFeature() const
{
Expand All @@ -59,6 +63,7 @@ namespace sky {
PmrHashMap<Name, SceneView*> viewMap;
PmrVector<RenderPrimitive *> primitives;

VolumeManager volumeManager;
RenderPipelineFlags renderFlags;
};

Expand Down
6 changes: 6 additions & 0 deletions runtime/render/core/src/RenderScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ namespace sky {
auto iter = std::find(primitives.begin(), primitives.end(), primitive);
SKY_ASSERT(iter == primitives.end());
primitives.emplace_back(primitive);
primitive->volumeId = volumeManager.AddVolume(primitive->worldBound, primitive);
}

void RenderScene::RemovePrimitive(RenderPrimitive *primitive)
Expand All @@ -92,6 +93,11 @@ namespace sky {
return;
}

if (primitive->volumeId != INVALID_VOLUME_ID) {
volumeManager.RemoveVolume(primitive->volumeId);
primitive->volumeId = INVALID_VOLUME_ID;
}

primitives.erase(std::remove_if(primitives.begin(), primitives.end(), [primitive](const auto &v) {
return primitive == v;
}), primitives.end());
Expand Down
4 changes: 4 additions & 0 deletions runtime/render/core/src/mesh/MeshRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <render/mesh/MeshFeature.h>
#include <render/resource/Meshlet.h>
#include <render/RenderBuiltinLayout.h>
#include <render/RenderScene.h>
#include <render/Renderer.h>
#include <render/RHI.h>
#include <core/math/MathUtil.h>
Expand Down Expand Up @@ -183,6 +184,9 @@ namespace sky {

for (auto &prim : primitives) {
prim->worldBound = AABB::Transform(prim->localBound, matrix);
if (scene != nullptr && prim->volumeId != INVALID_VOLUME_ID) {
scene->GetVolumeManager().UpdateVolume(prim->volumeId, prim->worldBound);
}
}
}

Expand Down
Loading