From 3fc20fcd4ee03015a14fd1f75a4c10a13db04233 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Sat, 29 Mar 2025 23:05:35 +0100 Subject: [PATCH] feat(part): added aabb calculation --- assets/shaders/ghost.fs | 20 ++++++++++++++ assets/shaders/ghost.vs | 18 +++++++++++++ core/src/datatypes/vector.cpp | 6 +++++ core/src/datatypes/vector.h | 2 ++ core/src/objects/part.cpp | 42 ++++++++++++++++++++++++----- core/src/objects/part.h | 3 +++ core/src/rendering/renderer.cpp | 47 +++++++++++++++++++++++++++++++-- 7 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 assets/shaders/ghost.fs create mode 100644 assets/shaders/ghost.vs diff --git a/assets/shaders/ghost.fs b/assets/shaders/ghost.fs new file mode 100644 index 0000000..ecbe775 --- /dev/null +++ b/assets/shaders/ghost.fs @@ -0,0 +1,20 @@ +#version 330 core + +in vec3 vPos; +in vec3 vNormal; + +out vec4 FragColor; + +#define NR_POINT_LIGHTS 4 + +uniform vec3 viewPos; +uniform float transparency; +uniform vec3 color; + + + +// Main + +void main() { + FragColor = vec4(color, 1) * (1-transparency); +} \ No newline at end of file diff --git a/assets/shaders/ghost.vs b/assets/shaders/ghost.vs new file mode 100644 index 0000000..3045d65 --- /dev/null +++ b/assets/shaders/ghost.vs @@ -0,0 +1,18 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aNormal; + +out vec3 vPos; +out vec3 vNormal; + +uniform mat4 model; +uniform mat3 normalMatrix; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); + vPos = vec3(model * vec4(aPos, 1.0)); + vNormal = normalMatrix * aNormal; +} diff --git a/core/src/datatypes/vector.cpp b/core/src/datatypes/vector.cpp index f854695..b70b5dc 100644 --- a/core/src/datatypes/vector.cpp +++ b/core/src/datatypes/vector.cpp @@ -25,6 +25,7 @@ Data::Vector3::operator glm::vec3() const { return vector; }; Data::Vector3::operator rp::Vector3() const { return rp::Vector3(X(), Y(), Z()); }; // Operators + Data::Vector3 Data::Vector3::operator *(float scale) const { return Data::Vector3(this->X() * scale, this->Y() * scale, this->Z() * scale); } @@ -33,6 +34,11 @@ Data::Vector3 Data::Vector3::operator /(float scale) const { return Data::Vector3(this->X() / scale, this->Y() / scale, this->Z() / scale); } +// Component-wise +Data::Vector3 Data::Vector3::operator *(Data::Vector3 other) const { + return Data::Vector3(this->X() * other.X(), this->Y() * other.Y(), this->Z() * other.Z()); +} + Data::Vector3 Data::Vector3::operator +(Data::Vector3 other) const { return Data::Vector3(this->X() + other.X(), this->Y() + other.Y(), this->Z() + other.Z()); } diff --git a/core/src/datatypes/vector.h b/core/src/datatypes/vector.h index 10f1017..5238646 100644 --- a/core/src/datatypes/vector.h +++ b/core/src/datatypes/vector.h @@ -35,6 +35,7 @@ namespace Data { inline float Z() const { return vector.z; } inline float Magnitude() const { return glm::length(vector); } inline Data::Vector3 Unit() const { return glm::normalize(vector); } + inline Data::Vector3 Abs() const { return glm::abs(vector); } Data::Vector3 Cross(Data::Vector3) const; float Dot(Data::Vector3) const; @@ -42,6 +43,7 @@ namespace Data { // Operators Data::Vector3 operator *(float) const; Data::Vector3 operator /(float) const; + Data::Vector3 operator *(Data::Vector3) const; // Component-wise Data::Vector3 operator +(Data::Vector3) const; Data::Vector3 operator -(Data::Vector3) const; Data::Vector3 operator -() const; diff --git a/core/src/objects/part.cpp b/core/src/objects/part.cpp index 043f86a..00ea64b 100644 --- a/core/src/objects/part.cpp +++ b/core/src/objects/part.cpp @@ -9,6 +9,8 @@ #include #include "physics/simulation.h" +using Data::Vector3; + // template // constexpr FieldCodec fieldCodecOf() { // return FieldCodec { @@ -25,7 +27,7 @@ constexpr FieldCodec cframePositionCodec() { return FieldCodec { .write = [](Data::Variant source, void* destination) { Data::CFrame* cframe = static_cast(destination); - *cframe = cframe->Rotation() + source.get(); + *cframe = cframe->Rotation() + source.get(); }, .read = [](void* source) -> Data::Variant { return *static_cast(source); @@ -37,7 +39,7 @@ constexpr FieldCodec cframeRotationCodec() { return FieldCodec { .write = [](Data::Variant source, void* destination) { Data::CFrame* cframe = static_cast(destination); - *cframe = Data::CFrame::FromEulerAnglesXYZ(source.get()) + cframe->Position(); + *cframe = Data::CFrame::FromEulerAnglesXYZ(source.get()) + cframe->Position(); }, .read = [](void* source) -> Data::Variant { return static_cast(source)->ToEulerAnglesXYZ(); @@ -71,13 +73,13 @@ Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(par .updateCallback = memberFunctionOf(&Part::onUpdated, this) }}, { "Position", { .backingField = &cframe, - .type = &Data::Vector3::TYPE, + .type = &Vector3::TYPE, .codec = cframePositionCodec(), .updateCallback = memberFunctionOf(&Part::onUpdated, this), .flags = PropertyFlags::PROP_NOSAVE }}, { "Rotation", { .backingField = &cframe, - .type = &Data::Vector3::TYPE, + .type = &Vector3::TYPE, .codec = cframeRotationCodec(), .updateCallback = memberFunctionOf(&Part::onUpdated, this), .flags = PropertyFlags::PROP_NOSAVE @@ -88,8 +90,8 @@ Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(par .updateCallback = memberFunctionOf(&Part::onUpdated, this), }}, { "Size", { .backingField = &size, - .type = &Data::Vector3::TYPE, - .codec = fieldCodecOf(), + .type = &Vector3::TYPE, + .codec = fieldCodecOf(), .updateCallback = memberFunctionOf(&Part::onUpdated, this) }}, { "Color", { .backingField = &color, @@ -122,4 +124,32 @@ void Part::OnParentUpdated(std::optional> oldParent, s void Part::onUpdated(std::string property) { syncPartPhysics(std::dynamic_pointer_cast(this->shared_from_this())); +} + +// Expands provided extents to fit point +static void expandMaxExtents(Vector3* min, Vector3* max, Vector3 point) { + *min = Vector3(glm::min(min->X(), point.X()), glm::min(min->Y(), point.Y()), glm::min(min->Z(), point.Z())); + *max = Vector3(glm::max(max->X(), point.X()), glm::max(max->Y(), point.Y()), glm::max(max->Z(), point.Z())); +} + +static Vector3 verts[8] { + {-1, -1, -1}, + {-1, -1, 1}, + {-1, 1, -1}, + {-1, 1, 1}, + {1, -1, -1}, + {1, -1, 1}, + {1, 1, -1}, + {1, 1, 1}, +}; + +Vector3 Part::GetAABB() { + Vector3 min(0, 0, 0); + Vector3 max(0, 0, 0); + for (Vector3 vert : verts) { + Vector3 worldVert = this->cframe.Rotation() * ((Data::Vector3)this->size * vert); + expandMaxExtents(&min, &max, worldVert); + } + + return (min - max).Abs() / 2; } \ No newline at end of file diff --git a/core/src/objects/part.h b/core/src/objects/part.h index e3c6944..98b1618 100644 --- a/core/src/objects/part.h +++ b/core/src/objects/part.h @@ -48,4 +48,7 @@ public: virtual const InstanceType* GetClass() override; inline Data::Vector3 position() { return cframe.Position(); } + + // Calculate size of axis-aligned bounding box + Data::Vector3 GetAABB(); }; \ No newline at end of file diff --git a/core/src/rendering/renderer.cpp b/core/src/rendering/renderer.cpp index 49b3c2a..1f7141e 100644 --- a/core/src/rendering/renderer.cpp +++ b/core/src/rendering/renderer.cpp @@ -29,6 +29,7 @@ Shader* shader = NULL; Shader* skyboxShader = NULL; Shader* handleShader = NULL; Shader* identityShader = NULL; +Shader* ghostShader = NULL; extern Camera camera; Skybox* skyboxTexture = NULL; Texture3D* studsTexture = NULL; @@ -63,6 +64,7 @@ void renderInit(GLFWwindow* window, int width, int height) { skyboxShader = new Shader("assets/shaders/skybox.vs", "assets/shaders/skybox.fs"); handleShader = new Shader("assets/shaders/handle.vs", "assets/shaders/handle.fs"); identityShader = new Shader("assets/shaders/identity.vs", "assets/shaders/identity.fs"); + ghostShader = new Shader("assets/shaders/ghost.vs", "assets/shaders/ghost.fs"); } void renderParts() { @@ -126,7 +128,7 @@ void renderParts() { sorted[distance] = part; } else { glm::mat4 model = part->cframe; - if (part->name == "camera") model = camera.getLookAt(); + // if (part->name == "camera") model = camera.getLookAt(); model = glm::scale(model, part->size); shader->set("model", model); shader->set("material", Material { @@ -149,7 +151,7 @@ void renderParts() { for (std::map>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); it++) { std::shared_ptr part = it->second; glm::mat4 model = part->cframe; - if (part->name == "camera") model = camera.getLookAt(); + // if (part->name == "camera") model = camera.getLookAt(); model = glm::scale(model, part->size); shader->set("model", model); shader->set("material", Material { @@ -256,6 +258,45 @@ void renderHandles() { } } +void renderAABB() { + glDepthMask(GL_TRUE); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CW); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Use shader + ghostShader->use(); + + // view/projection transformations + glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)viewportWidth / (float)viewportHeight, 0.1f, 1000.0f); + glm::mat4 view = camera.getLookAt(); + ghostShader->set("projection", projection); + ghostShader->set("view", view); + + // Pass in the camera position + ghostShader->set("viewPos", camera.cameraPos); + + ghostShader->set("transparency", 0.5f); + ghostShader->set("color", glm::vec3(1.f, 0.f, 0.f)); + + // Sort by nearest + for (InstanceRef inst : workspace()->GetChildren()) { + if (inst->GetClass()->className != "Part") continue; + std::shared_ptr part = std::dynamic_pointer_cast(inst); + glm::mat4 model = Data::CFrame::IDENTITY + part->cframe.Position(); + printf("AABB is supposedly (%f, %f, %f)\n", part->GetAABB().X(), part->GetAABB().Y(), part->GetAABB().Z()); + model = glm::scale(model, (glm::vec3)part->GetAABB()); + ghostShader->set("model", model); + glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model))); + ghostShader->set("normalMatrix", normalMatrix); + + CUBE_MESH->bind(); + glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount); + } +} + void render(GLFWwindow* window) { glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -263,6 +304,8 @@ void render(GLFWwindow* window) { renderSkyBox(); renderHandles(); renderParts(); + // TODO: Make this a debug flag + // renderAABB(); } void setViewport(int width, int height) {