ADD: AABB
This commit is contained in:
parent
023016c6a2
commit
b879f2a636
@ -166,6 +166,9 @@ add_library(Engine STATIC
|
||||
engine/src/renderer/DebugRenderer.h
|
||||
engine/src/layer/DebugLayer.cpp
|
||||
engine/src/layer/DebugLayer.h
|
||||
engine/src/loader/models/AABB.cpp
|
||||
engine/src/loader/models/AABB.h
|
||||
engine/src/loader/models/Ray.h
|
||||
)
|
||||
target_include_directories(Engine PUBLIC engine/src)
|
||||
target_link_libraries(Engine PUBLIC OpenGL::GL glfw glad glm::glm imgui spdlog::spdlog tinyobjloader stb_image)
|
||||
|
||||
@ -4,9 +4,11 @@
|
||||
|
||||
#ifndef COLORRACE_PICKABLECOMPONENT_H
|
||||
#define COLORRACE_PICKABLECOMPONENT_H
|
||||
#include "loader/models/AABB.h"
|
||||
|
||||
namespace engine {
|
||||
struct PickableComponent {
|
||||
float radius;
|
||||
AABB aabb;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -42,10 +42,10 @@ namespace engine {
|
||||
|
||||
for (const auto& [entity, pickable] : registry.getPool<PickableComponent>()) {
|
||||
const auto transform = registry.getComponent<TransformComponent>(entity);
|
||||
if (float t; raySphereIntersect(origin, dir, transform.m_position, pickable.radius, t) && t < closestT) {
|
||||
closestT = t;
|
||||
hit = entity;
|
||||
}
|
||||
// if (float t; raySphereIntersect(origin, dir, transform.m_position, pickable.radius, t) && t < closestT) {
|
||||
// closestT = t;
|
||||
// hit = entity;
|
||||
// }
|
||||
}
|
||||
|
||||
return hit;
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "renderer/RenderQueue.h"
|
||||
#include "renderer/primitives/SphereFactory.h"
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
|
||||
void engine::DebugLayer::onUpdate(float deltaTime) {
|
||||
@ -27,7 +27,9 @@ void engine::DebugLayer::onRender() {
|
||||
|
||||
for (auto& [entity, pickableComponent] : pickablePool) {
|
||||
if (transforms.has(entity)) {
|
||||
const auto sphereTransformComp = TransformComponent(transforms.get(entity).m_position, {0,0,0}, {pickableComponent.radius, pickableComponent.radius, pickableComponent.radius});
|
||||
glm::vec3 halfExtent = pickableComponent.aabb.getHalfExtent();
|
||||
spdlog::info(std::to_string(halfExtent.x) + " " + std::to_string(halfExtent.y) + " " + std::to_string(halfExtent.z));
|
||||
const auto sphereTransformComp = TransformComponent(transforms.get(entity).m_position, {0,0,0}, halfExtent);
|
||||
glm::mat4 modelMatrix = sphereTransformComp.computeModelMatrix();
|
||||
|
||||
RenderCommand renderCommand(m_sphereModel, modelMatrix);
|
||||
|
||||
76
engine/src/loader/models/AABB.cpp
Normal file
76
engine/src/loader/models/AABB.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
//
|
||||
// Created by sebastian on 04.08.26.
|
||||
//
|
||||
|
||||
#include "AABB.h"
|
||||
|
||||
#include "glm/glm.hpp"
|
||||
|
||||
void engine::AABB::expandToInclude(const glm::vec3 &point) {
|
||||
m_min = glm::min(m_min, point);
|
||||
m_max = glm::max(m_max, point);
|
||||
}
|
||||
|
||||
void engine::AABB::expandToInclude(const AABB &other) {
|
||||
m_min = glm::min(m_min, other.getMin());
|
||||
m_max = glm::max(m_max, other.getMax());
|
||||
}
|
||||
|
||||
engine::AABB engine::AABB::transformed(const glm::mat4 &transform) const {
|
||||
glm::vec3 corners[8] = {
|
||||
{m_min.x, m_min.y, m_min.z}, {m_max.x, m_min.y, m_min.z},
|
||||
{m_min.x, m_max.y, m_min.z}, {m_max.x, m_max.y, m_min.z},
|
||||
{m_min.x, m_min.y, m_max.z}, {m_max.x, m_min.y, m_max.z},
|
||||
{m_min.x, m_max.y, m_max.z}, {m_max.x, m_max.y, m_max.z},
|
||||
};
|
||||
|
||||
glm::vec3 newMin(std::numeric_limits<float>::max());
|
||||
glm::vec3 newMax(std::numeric_limits<float>::lowest());
|
||||
|
||||
for (const auto& corner : corners) {
|
||||
glm::vec3 transformed = glm::vec3(transform * glm::vec4(corner, 1.0f));
|
||||
newMin = glm::min(newMin, transformed);
|
||||
newMax = glm::max(newMax, transformed);
|
||||
}
|
||||
|
||||
return {newMin, newMax};
|
||||
}
|
||||
|
||||
std::optional<engine::RayHit> engine::AABB::intersects(const Ray &ray, float maxDistance) const {
|
||||
// Slab-Methode: Prüft für jede Achse (x, y, z) das Intervall, in dem der Ray
|
||||
// innerhalb der beiden "Slabs" (Ebenenpaare) dieser Achse liegt. Der Ray trifft
|
||||
// die AABB genau dann, wenn sich alle drei Achsen-Intervalle überschneiden.
|
||||
float tMin = 0.0f;
|
||||
float tMax = maxDistance;
|
||||
|
||||
for (int axis = 0; axis < 3; ++axis) {
|
||||
float origin = ray.origin[axis];
|
||||
float dir = ray.direction[axis];
|
||||
float minBound = m_min[axis];
|
||||
float maxBound = m_max[axis];
|
||||
|
||||
if (std::abs(dir) < 1e-8f) {
|
||||
// Ray verläuft parallel zu dieser Achse - kein Treffer, falls Origin außerhalb des Slabs liegt
|
||||
if (origin < minBound || origin > maxBound) {
|
||||
return std::nullopt;
|
||||
}
|
||||
} else {
|
||||
float invDir = 1.0f / dir;
|
||||
float t1 = (minBound - origin) * invDir;
|
||||
float t2 = (maxBound - origin) * invDir;
|
||||
if (t1 > t2) std::swap(t1, t2);
|
||||
|
||||
tMin = std::max(tMin, t1);
|
||||
tMax = std::min(tMax, t2);
|
||||
|
||||
if (tMin > tMax) {
|
||||
return std::nullopt; // Intervalle überschneiden sich nicht -> kein Treffer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RayHit hit;
|
||||
hit.distance = tMin;
|
||||
hit.intersectionPoint = ray.origin + ray.direction * tMin;
|
||||
return hit;
|
||||
}
|
||||
57
engine/src/loader/models/AABB.h
Normal file
57
engine/src/loader/models/AABB.h
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// Created by sebastian on 04.08.26.
|
||||
//
|
||||
|
||||
#ifndef COLORRACE_AABB_H
|
||||
#define COLORRACE_AABB_H
|
||||
#include <optional>
|
||||
|
||||
#include "Ray.h"
|
||||
#include "glm/fwd.hpp"
|
||||
#include "glm/vec3.hpp"
|
||||
|
||||
|
||||
namespace engine {
|
||||
class AABB {
|
||||
public:
|
||||
AABB() = default;
|
||||
AABB(const glm::vec3& min, const glm::vec3& max) : m_min(min), m_max(max) {}
|
||||
|
||||
static AABB fromCenterAndHalfExtent(const glm::vec3& center, const glm::vec3& halfExtent) {
|
||||
return AABB(center - halfExtent, center + halfExtent);
|
||||
}
|
||||
|
||||
const glm::vec3& getMin() const { return m_min; }
|
||||
const glm::vec3& getMax() const { return m_max; }
|
||||
|
||||
glm::vec3 getCenter() const { return (m_min + m_max) * 0.5f; }
|
||||
glm::vec3 getHalfExtent() const { return (m_max - m_min) * 0.5f; }
|
||||
glm::vec3 getSize() const { return m_max - m_min; }
|
||||
|
||||
void expandToInclude(const glm::vec3& point);
|
||||
void expandToInclude(const AABB& other);
|
||||
|
||||
AABB transformed(const glm::mat4& transform) const;
|
||||
|
||||
[[nodiscard]] bool contains(const glm::vec3 &point) const {
|
||||
return point.x >= m_min.x && point.x <= m_max.x
|
||||
&& point.y >= m_min.y && point.y <= m_max.y
|
||||
&& point.z >= m_min.z && point.z <= m_max.z;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool intersects(const AABB &other) const {
|
||||
return m_min.x <= other.m_max.x && m_max.x >= other.m_min.x
|
||||
&& m_min.y <= other.m_max.y && m_max.y >= other.m_min.y
|
||||
&& m_min.z <= other.m_max.z && m_max.z >= other.m_min.z;
|
||||
}
|
||||
|
||||
std::optional<RayHit> intersects(const Ray &ray, float maxDistance = std::numeric_limits<float>::max()) const;
|
||||
|
||||
private:
|
||||
glm::vec3 m_min{0.f};
|
||||
glm::vec3 m_max{0.f};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //COLORRACE_AABB_H
|
||||
@ -11,6 +11,7 @@
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "AABB.h"
|
||||
#include "Material.h"
|
||||
#include "glm/glm.hpp"
|
||||
|
||||
@ -21,6 +22,7 @@ namespace engine {
|
||||
unsigned int indexOffset; // in Indizes, nicht Bytes
|
||||
unsigned int indexCount;
|
||||
glm::vec3 centroid;
|
||||
AABB aabb;
|
||||
std::shared_ptr<Material> material;
|
||||
};
|
||||
|
||||
|
||||
@ -19,7 +19,19 @@ void Model::unbind() const {
|
||||
}
|
||||
|
||||
Model::Model(std::unique_ptr<Vao> vao, int vertexCount, std::vector<MeshSection> sections)
|
||||
: m_vao(std::move(vao)), m_vertexCount(vertexCount), m_isIndexed(true), m_sections(std::move(sections)) {}
|
||||
: m_vao(std::move(vao)), m_vertexCount(vertexCount), m_isIndexed(true), m_sections(std::move(sections)) {
|
||||
if (!sections.empty()) {
|
||||
spdlog::info("Calculate AABB for model {}", vao->getId());
|
||||
AABB aabb = sections[0].aabb;
|
||||
for (const auto& section : sections) {
|
||||
aabb.expandToInclude(section.aabb);
|
||||
}
|
||||
m_aabb = aabb;
|
||||
}
|
||||
}
|
||||
|
||||
Model::Model(std::unique_ptr<Vao> vao, int vertexCount, std::vector<MeshSection> sections, AABB aabb) : m_vao(std::move(vao)), m_vertexCount(vertexCount), m_isIndexed(true), m_sections(std::move(sections)), m_aabb(aabb) {
|
||||
}
|
||||
|
||||
void Model::draw() const {
|
||||
bind();
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#define COLORRACE_MODEL_H
|
||||
#include <memory>
|
||||
|
||||
#include "AABB.h"
|
||||
#include "MeshSection.h"
|
||||
#include "utils/openglWrapper/openglObjects/Vao.h"
|
||||
|
||||
@ -16,6 +17,7 @@ namespace engine {
|
||||
Model(std::unique_ptr<Vao> vao, int vertexCount, bool isIndexed);
|
||||
Model(std::unique_ptr<Vao> vao, int vertexCount);
|
||||
Model(std::unique_ptr<Vao> vao, int vertexCount, std::vector<MeshSection> sections); // neu
|
||||
Model(std::unique_ptr<Vao> vao, int vertexCount, std::vector<MeshSection> sections, AABB aabb); // neu
|
||||
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
@ -27,8 +29,11 @@ namespace engine {
|
||||
[[nodiscard]] bool isIndexed() const { return m_isIndexed; }
|
||||
[[nodiscard]] bool hasSections() const { return !m_sections.empty(); }
|
||||
[[nodiscard]] const std::vector<MeshSection>& getSections() const { return m_sections; }
|
||||
[[nodiscard]] const AABB& getAABB() const { return m_aabb; }
|
||||
|
||||
|
||||
private:
|
||||
AABB m_aabb;
|
||||
std::unique_ptr<Vao> m_vao;
|
||||
int m_vertexCount;
|
||||
bool m_isIndexed;
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include "glm/vec3.hpp"
|
||||
#include "loader/textures/TextureUploader.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "AABB.h"
|
||||
|
||||
std::vector<engine::LoadedAsset> engine::ModelUploader::upload(const engine::RawModelBundle &bundle, engine::ModelSplitPolicy policy) {
|
||||
std::vector<engine::LoadedAsset> results;
|
||||
@ -105,6 +106,15 @@ engine::Model engine::ModelUploader::uploadSections(const std::vector<RawMeshSec
|
||||
}
|
||||
meshSection.centroid = centroidSum / static_cast<float>(section.vertices.size() / 3);
|
||||
|
||||
//Calculate AABB
|
||||
AABB aabb(
|
||||
glm::vec3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max()),
|
||||
glm::vec3(std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest())
|
||||
);
|
||||
for (size_t i = 0; i < section.vertices.size(); i += 3) {
|
||||
aabb.expandToInclude(glm::vec3(section.vertices[i], section.vertices[i+1], section.vertices[i+2]));
|
||||
}
|
||||
|
||||
vertexOffset += static_cast<unsigned int>(section.vertices.size() / 3);
|
||||
meshSections.push_back(std::move(meshSection));
|
||||
}
|
||||
@ -120,7 +130,15 @@ engine::Model engine::ModelUploader::uploadSections(const std::vector<RawMeshSec
|
||||
|
||||
vao->unbind();
|
||||
|
||||
return Model(std::move(vao), static_cast<int>(indices.size()), std::move(meshSections));
|
||||
AABB modelAABB = AABB(
|
||||
glm::vec3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max()),
|
||||
glm::vec3(std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest())
|
||||
);
|
||||
for (int i = 0; i < static_cast<int>(vertices.size()); i+=3) {
|
||||
modelAABB.expandToInclude(glm::vec3(vertices[i], vertices[i+1], vertices[i+2]));
|
||||
}
|
||||
|
||||
return Model(std::move(vao), static_cast<int>(indices.size()), std::move(meshSections), modelAABB);
|
||||
}
|
||||
|
||||
engine::Model engine::ModelUploader::buildCombinedByObject(const std::vector<RawObjectData> &objects, const MaterialMap &materials) {
|
||||
|
||||
21
engine/src/loader/models/Ray.h
Normal file
21
engine/src/loader/models/Ray.h
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// Created by sebastian on 04.08.26.
|
||||
//
|
||||
|
||||
#ifndef COLORRACE_RAY_H
|
||||
#define COLORRACE_RAY_H
|
||||
#include "glm/vec3.hpp"
|
||||
|
||||
namespace engine {
|
||||
struct Ray {
|
||||
glm::vec3 origin;
|
||||
glm::vec3 direction;
|
||||
};
|
||||
|
||||
struct RayHit {
|
||||
float distance;
|
||||
glm::vec3 intersectionPoint;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //COLORRACE_RAY_H
|
||||
@ -63,5 +63,14 @@ std::shared_ptr<engine::Model> engine::SphereFactory::createUVSphere(float radiu
|
||||
vao->createIndexBuffer(indices.data(), indices.size());
|
||||
vao->unbind();
|
||||
|
||||
return std::make_shared<Model>(std::move(vao), static_cast<int>(indices.size()), true);
|
||||
AABB modelAABB = AABB(
|
||||
glm::vec3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max()),
|
||||
glm::vec3(std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest())
|
||||
);
|
||||
for (int i = 0; i < static_cast<int>(vertices.size()); i+=3) {
|
||||
modelAABB.expandToInclude(glm::vec3(vertices[i], vertices[i+1], vertices[i+2]));
|
||||
}
|
||||
|
||||
std::vector<MeshSection> meshSections;
|
||||
return std::make_shared<Model>(std::move(vao), static_cast<int>(indices.size()), meshSections, modelAABB);
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ void ludo::PiecePresenter::spawnPieces(const ludo::LudoGameState &state) {
|
||||
{0.334296f, 0.334296f, 0.334296f});
|
||||
m_registry.addComponent<engine::TransformComponent>(entity, transform);
|
||||
m_registry.addComponent<engine::MeshComponent>(entity, engine::MeshComponent(m_pieceModels[std::string(ludo::toString(piece.color))]));
|
||||
m_registry.addComponent<engine::PickableComponent>(entity, engine::PickableComponent(kPieceRadius));
|
||||
m_registry.addComponent<engine::PickableComponent>(entity, engine::PickableComponent(m_pieceModels[std::string(toString(piece.color))]->getAABB()));
|
||||
m_pieceEntities.push_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,10 +14,10 @@ void ludo::HighlightSystem::update(const engine::Mouse& mouse, engine::EntityReg
|
||||
|
||||
for (const auto& [entity, pickable] : registry.getPool<engine::PickableComponent>()) {
|
||||
const auto transform = registry.getComponent<engine::TransformComponent>(entity);
|
||||
if (float t; engine::PickingSystem::raySphereIntersect(origin, dir, transform.m_position, pickable.radius, t) && t < closestT) {
|
||||
closestT = t;
|
||||
hit = entity;
|
||||
}
|
||||
// if (float t; engine::PickingSystem::raySphereIntersect(origin, dir, transform.m_position, pickable.radius, t) && t < closestT) {
|
||||
// closestT = t;
|
||||
// hit = entity;
|
||||
// }
|
||||
}
|
||||
|
||||
if (hit.has_value()) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user