diff options
author | jjesswan <jessica_wan@brown.edu> | 2024-04-22 21:56:26 -0400 |
---|---|---|
committer | jjesswan <jessica_wan@brown.edu> | 2024-04-22 21:56:26 -0400 |
commit | a556b45abf18f1bd509daaf63b66b7d55e9fd291 (patch) | |
tree | bc9b8a2d184c12aee236e7f9f276a34b84ca552d /engine-ocean/Game/Components/CollisionComponents | |
parent | cd7c76017a12bb548036571c1ff13e551369d06d (diff) |
add engine version
Diffstat (limited to 'engine-ocean/Game/Components/CollisionComponents')
12 files changed, 616 insertions, 0 deletions
diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.cpp b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.cpp new file mode 100644 index 0000000..d39d118 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.cpp @@ -0,0 +1,88 @@ +#include "boundingdynamicmesh.h" +#include "Graphics/modeltransform.h" +#include <vector> + +// without mesh obj data +BoundingDynamicMesh::BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt, + const glm::vec3 &initial_pos) : + m_mt(mt) +{ + m_isMesh = false; + m_bounding_cylinder = std::make_shared<CylinderCollider>(initial_pos, mt->getScale()); +} + +// with mesh obj data +BoundingDynamicMesh::BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt, + const glm::vec3 &initial_pos, + std::vector<glm::vec3> &obj_data) : + m_mt(mt), + m_obj_data(obj_data) +{ + m_isMesh = true; + m_bounding_cylinder = std::make_shared<CylinderCollider>(initial_pos, mt->getScale()*getMeshDimensions()*2.f); +} + + +glm::vec3 BoundingDynamicMesh::getCenterPos(){ + return m_mt->getPos(); +} + +void BoundingDynamicMesh::updateCenterPos(glm::vec3 new_pos){ + m_mt->setPos(new_pos); + m_bounding_cylinder->updateCollisionPos(new_pos); +} + + + +glm::vec3 BoundingDynamicMesh::getMeshDimensions(){ + float max_x = m_obj_data[0].x; + float min_x = m_obj_data[0].x; + float max_y = m_obj_data[0].y; + float min_y = m_obj_data[0].y; + float max_z = m_obj_data[0].z; + float min_z = m_obj_data[0].z; + + for (const glm::vec3 &v : m_obj_data){ + // check max + if (v.x > max_x){ + max_x = v.x; + } + if (v.y > max_y){ + max_y = v.y; + } + if (v.z > max_z){ + max_z = v.z; + } + + // check mins + if (v.x < min_x){ + min_x = v.x; + } + if (v.y < min_y){ + min_y = v.y; + } + if (v.z < min_z){ + min_z = v.z; + } + } + + float r_x = (max_x - min_x)/2.f; + float r_y = (max_y - min_y)/2.f; + float r_z = (max_z - min_z)/2.f; + + return glm::vec3(r_x, r_y, r_z); +} + +glm::vec3 BoundingDynamicMesh::getEllipsoidDimensions(){ + if (m_isMesh){ + return m_mt->getScale()*getMeshDimensions(); + } + + return m_mt->getScale()/2.f; +} + +Cylinder BoundingDynamicMesh::getCylinder(){ + return m_bounding_cylinder->getCylinder(); +} + + diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.h b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.h new file mode 100644 index 0000000..5d24ac8 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.h @@ -0,0 +1,32 @@ +#ifndef BOUNDINGDYNAMICMESH_H +#define BOUNDINGDYNAMICMESH_H +#include "Game/Components/CollisionComponents/CylinderCollider.h" +#include "Graphics/modeltransform.h" +#include "glm/glm.hpp" +#include <memory> +#include <vector> + + +class BoundingDynamicMesh : public BoundingShape +{ +public: + BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt, + const glm::vec3 &initial_pos); + BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt, + const glm::vec3 &initial_pos, + std::vector<glm::vec3> &obj_data); + glm::vec3 getCenterPos(); + void updateCenterPos(glm::vec3 new_pos); + glm::vec3 getEllipsoidDimensions(); + Cylinder getCylinder(); + +private: + glm::vec3 getMeshDimensions(); + + bool m_isMesh = false; + std::shared_ptr<ModelTransform> m_mt; + std::vector<glm::vec3> m_obj_data; + std::shared_ptr<CylinderCollider> m_bounding_cylinder; +}; + +#endif // BOUNDINGDYNAMICMESH_H diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingEllipsoid.h b/engine-ocean/Game/Components/CollisionComponents/BoundingEllipsoid.h new file mode 100644 index 0000000..8dce7c3 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingEllipsoid.h @@ -0,0 +1,21 @@ +#ifndef BOUNDINGELLIPSOID_H +#define BOUNDINGELLIPSOID_H +#include "glm/glm.hpp" +#include "BoundingShape.h" + +struct Ellipsoid{ + glm::vec3 R = glm::vec3(0.f); // holds Rx, Ry, Rz radii + glm::vec3 center_pos; +}; + +struct UnitSphere{ + glm::vec3 center_pos; +}; + +class BoundingEllipsoid : public BoundingShape +{ +public: + BoundingEllipsoid(); +}; + +#endif // BOUNDINGELLIPSOID_H diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingShape.cpp b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.cpp new file mode 100644 index 0000000..b3abba4 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.cpp @@ -0,0 +1,6 @@ +#include "BoundingShape.h" + +BoundingShape::BoundingShape() +{ + +} diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingShape.h b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.h new file mode 100644 index 0000000..1303628 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.h @@ -0,0 +1,15 @@ +#ifndef SHAPECOLLIDER_H +#define SHAPECOLLIDER_H + +struct CollisionShape{ + +}; + +class BoundingShape +{ +public: + BoundingShape(); + //virtual CollisionShape getCollisionShape() = 0; +}; + +#endif // SHAPECOLLIDER_H diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingTriangle.cpp b/engine-ocean/Game/Components/CollisionComponents/BoundingTriangle.cpp new file mode 100644 index 0000000..519d9c7 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingTriangle.cpp @@ -0,0 +1,200 @@ +#include "boundingtriangle.h" +#include "Graphics/global.h" +#include "Graphics/modeltransform.h" +#include <iostream> +#include "glm/gtx/hash.hpp" + +// ONLY FOR ENVIRONMENTS +BoundingTriangle::BoundingTriangle(const std::vector<glm::vec3> &obj_data, + const std::shared_ptr<ModelTransform> &mt, + bool isGround) : + obj_mt(mt), + m_isGround(isGround) +{ + populateTriangleData(obj_data); + calculateBounds(obj_data); + //m_datasize = obj_data.size(); +} + +glm::vec3 BoundingTriangle::getRandomSurfacePos(){ + int randomIndex = std::floor(Global::graphics.generateRandomNumbers(0, m_triangles.size()-1)); + int randomVertex = std::floor(Global::graphics.generateRandomNumbers(0, 3)); + + Triangle randomTri = m_triangles[randomIndex]; + + if (glm::dot(glm::vec3(0,1,0), randomTri.normal) > 0.2f){ + switch(randomVertex){ + case 0: + return randomTri.vertexA; + break; + case 1: + return randomTri.vertexB; + break; + default: + return randomTri.vertexC; + break; + } + } else { + // do again until returning a surface triangle + getRandomSurfacePos(); + } +} + + +void BoundingTriangle::addTriangle(const glm::vec3 &vertexA, const glm::vec3 &vertexB, const glm::vec3 &vertexC){ + Triangle tri; + tri.vertexA = vertexA; + tri.vertexB = vertexB; + tri.vertexC = vertexC; + + tri.edge1 = vertexB - vertexA; // edge ab + tri.edge2 = vertexC - vertexA; // edge bc + tri.normal = glm::normalize(glm::cross(tri.edge1, tri.edge2)); + tri.bounds = calculateTriangleBounds(vertexA, vertexB, vertexC); + + // if triangle is a ground triangle + if (m_isGround){ + if (glm::dot(glm::vec3(0,1,0), tri.normal) > 0.2f){ + //std::cout << "area: " << getArea(vertexA, vertexB, vertexC) << std::endl; + tesselateTriangle(vertexA, vertexB, vertexC); + } + } + + m_triangles.push_back(tri); +} + +float BoundingTriangle::getArea(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C){ + glm::vec3 AB = B-A; + glm::vec3 AC = C-A; + return .5f*glm::length((glm::cross(AB,AC))); + +} + +glm::vec3 BoundingTriangle::getCentroid(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C){ + return .333f*(A + B + C); +} + +// tesselation into smaller triangles +void BoundingTriangle::tesselateTriangle(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C){ + float min_area = 1.5f; + + // add centroid if area is small enough + if (getArea(A,B,C) <= min_area){ + m_surface_points.push_back(getCentroid(A, B, C)); + return; + } + + // otherwise divide triangle in 4 (tesselate) + + glm::vec3 ab_mid = .5f*(A+B); + glm::vec3 ac_mid = .5f*(A+C); + glm::vec3 bc_mid = .5f*(B+C); + m_surface_points.push_back(ab_mid); + m_surface_points.push_back(ac_mid); + m_surface_points.push_back(bc_mid); + + tesselateTriangle(ab_mid, ac_mid, A); + tesselateTriangle(bc_mid, ab_mid, B); + tesselateTriangle(bc_mid, ac_mid, C); + tesselateTriangle(ab_mid, ac_mid, bc_mid); +} + + +void BoundingTriangle::populateTriangleData(const std::vector<glm::vec3> &obj_data){ + for (int i=0; i<obj_data.size(); i += 3){ + // convert to worldspace + glm::mat4 modelMat = obj_mt->getModelMatrix(); + glm::vec3 v1 = modelMat*glm::vec4(obj_data[i],1.0); + glm::vec3 v2 = modelMat*glm::vec4(obj_data[i+1],1.0); + glm::vec3 v3 = modelMat*glm::vec4(obj_data[i+2],1.0); + + // make triangle + addTriangle(v1, v2, v3); + } + +// m_surface_points.reserve(m_unique_surface_points.size()); +// std::copy(m_unique_surface_points.begin(), m_unique_surface_points.end(), m_surface_points.begin()); +} + +Bounds3f BoundingTriangle::calculateTriangleBounds(const glm::vec3 &vertexA, + const glm::vec3 &vertexB, + const glm::vec3 &vertexC){ + Bounds3f bounds; + + float max_x, min_x = vertexA.x; + float max_y, min_y = vertexA.y; + float max_z, min_z = vertexA.z; + + if (vertexB.x > max_x) max_x = vertexB.x; + if (vertexB.y > max_y) max_y = vertexB.y; + if (vertexB.z > max_z) max_z = vertexB.z; + + if (vertexC.x > max_x) max_x = vertexC.x; + if (vertexC.y > max_y) max_y = vertexC.y; + if (vertexC.z > max_z) max_z = vertexC.z; + + if (vertexB.x < min_x) min_x = vertexB.x; + if (vertexB.y < min_y) min_y = vertexB.y; + if (vertexB.z < min_z) min_z = vertexB.z; + + if (vertexC.x < min_x) min_x = vertexC.x; + if (vertexC.y < min_y) min_y = vertexC.y; + if (vertexC.z < min_z) min_z = vertexC.z; + + + bounds.max = glm::vec3(max_x, max_y, max_z); + bounds.min = glm::vec3(min_x, min_y, min_z); + + return bounds; +} + +void BoundingTriangle::calculateBounds(const std::vector<glm::vec3> &obj_data){ + max_x = obj_data[0].x; + min_x = obj_data[0].x; + max_y = obj_data[0].y; + min_y = obj_data[0].y; + max_z = obj_data[0].z; + min_z = obj_data[0].z; + + for (const glm::vec3 &v : obj_data){ + // check max + if (v.x > max_x){ + max_x = v.x; + } + if (v.y > max_y){ + max_y = v.y; + } + if (v.z > max_z){ + max_z = v.z; + } + + // check mins + if (v.x < min_x){ + min_x = v.x; + } + if (v.y < min_y){ + min_y = v.y; + } + if (v.z < min_z){ + min_z = v.z; + } + } +} + +Bounds3f BoundingTriangle::getMeshBounds(){ + Bounds3f bounds; + bounds.max = glm::vec3(max_x, max_y, max_z); + bounds.min = glm::vec3(min_x, min_y, min_z); + return bounds; +} + +std::vector<glm::vec3> BoundingTriangle::getSurfacePoints(){ + if (!m_isGround){ + std::cout << "getting surface points of not-ground object!" << std::endl; + } + return m_surface_points; +} + +std::vector<Triangle> BoundingTriangle::getTriangleData(){ + return m_triangles; +} diff --git a/engine-ocean/Game/Components/CollisionComponents/CollisionComponent.cpp b/engine-ocean/Game/Components/CollisionComponents/CollisionComponent.cpp new file mode 100644 index 0000000..bea3f9e --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/CollisionComponent.cpp @@ -0,0 +1,47 @@ +#include "collisioncomponent.h" +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Game/Components/CollisionComponents/CylinderCollider.h" +#include "Game/Components/CollisionComponents/BoundingDynamicMesh.h" +#include "Graphics/shape.h" +#include <memory> + +// for dynamic objects +CollisionComponent::CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos) +{ + if (shapeType == "dynamic_mesh"){ + //addCollisionShape<CylinderCollider>(std::make_shared<CylinderCollider>(initial_pos, initial_scale)); + addCollisionShape<BoundingDynamicMesh>(std::make_shared<BoundingDynamicMesh>(mt, initial_pos)); + } +} + +CollisionComponent::CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos, std::vector<glm::vec3> &obj_data) +{ + if (shapeType == "dynamic_mesh"){ + addCollisionShape<BoundingDynamicMesh>(std::make_shared<BoundingDynamicMesh>(mt, initial_pos, obj_data)); + } +} + +// for rigid meshes / environment +CollisionComponent::CollisionComponent(std::string shapeType, + const std::vector<glm::vec3> &obj_data, + const std::shared_ptr<ModelTransform> &mt, + bool isGround){ + if (shapeType == "obj"){ + addCollisionShape<BoundingTriangle>(std::make_shared<BoundingTriangle>(obj_data, mt, isGround)); + } + +} + + + +bool CollisionComponent::isRigidBody(){ + return m_isRigid; +} + +float CollisionComponent::getReboundVel(){ + return m_rebound_vel; +} + +float CollisionComponent::getAcceleration(){ + return m_acceleration; +} diff --git a/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.cpp b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.cpp new file mode 100644 index 0000000..3dfded9 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.cpp @@ -0,0 +1,47 @@ +#include "cylindercollider.h" +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Graphics/modeltransform.h" + +CylinderCollider::CylinderCollider(glm::vec3 initial_pos, glm::vec3 initial_scale){ + m_scale = initial_scale; + + m_cyl.point = glm::vec2(initial_pos.x, initial_pos.z); + m_cyl.radius = .5f * glm::max(initial_scale.x, initial_scale.z); + m_cyl.height = 1.f * abs(initial_scale.y); + m_cyl.min = initial_pos.y - (initial_scale.y/2.f); + m_cyl.max = initial_pos.y + (initial_scale.y/2.f); + + m_cyl.aabbDimensions = abs(glm::vec3(2*m_cyl.radius, m_cyl.height, 2*m_cyl.radius)); + m_cyl.aabbCenterPos = initial_pos; + + updateBounds(); +} + +void CylinderCollider::updateCollisionPos(glm::vec3 new_pos){ + m_cyl.point = glm::vec2(new_pos.x, new_pos.z); // x and z loc + m_cyl.radius = .5f * m_scale.x; // x and z dim + m_cyl.height = 1.f * m_scale.y; // y dimensions + m_cyl.min = new_pos.y - (m_scale.y/2.f); // y coord + m_cyl.max = new_pos.y + (m_scale.y/2.f); // y coord + m_cyl.aabbCenterPos = new_pos; + + updateBounds(); +} + + +void CylinderCollider::updateBounds(){ + Bounds3f bounds; + bounds.min = glm::vec3(m_cyl.aabbCenterPos-glm::vec3(m_cyl.aabbDimensions/2.f)); + bounds.max = glm::vec3(m_cyl.aabbCenterPos+glm::vec3(m_cyl.aabbDimensions/2.f)); + + m_cyl.bounds = bounds; +} + + +Cylinder CylinderCollider::getCylinder(){ + return m_cyl; +} + + + + diff --git a/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.h b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.h new file mode 100644 index 0000000..3363b84 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.h @@ -0,0 +1,37 @@ +#ifndef CYLINDERCOLLIDER_H +#define CYLINDERCOLLIDER_H + +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Graphics/modeltransform.h" +#include "glm/glm.hpp" +#include "BoundingShape.h" +#include <memory> + + +struct Cylinder { + glm::vec2 point; // bottom Center + float radius; + + // lines + float height; + float min; + float max; + + glm::vec3 aabbDimensions; + glm::vec3 aabbCenterPos; + Bounds3f bounds; +}; + +class CylinderCollider +{ +public: + CylinderCollider(glm::vec3 initial_pos, glm::vec3 initial_scale); + Cylinder getCylinder();// override; + void updateCollisionPos(glm::vec3 new_pos); + void updateBounds(); +private: + glm::vec3 m_scale; + Cylinder m_cyl; +}; + +#endif // CYLINDERCOLLIDER_H diff --git a/engine-ocean/Game/Components/CollisionComponents/boundingellipsoid.cpp b/engine-ocean/Game/Components/CollisionComponents/boundingellipsoid.cpp new file mode 100644 index 0000000..3f8ed07 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/boundingellipsoid.cpp @@ -0,0 +1,6 @@ +#include "boundingellipsoid.h" + +BoundingEllipsoid::BoundingEllipsoid() +{ + +} diff --git a/engine-ocean/Game/Components/CollisionComponents/boundingtriangle.h b/engine-ocean/Game/Components/CollisionComponents/boundingtriangle.h new file mode 100644 index 0000000..0263007 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/boundingtriangle.h @@ -0,0 +1,68 @@ +#ifndef BOUNDINGTRIANGLE_H +#define BOUNDINGTRIANGLE_H +#include "Graphics/modeltransform.h" +#include "glm/glm.hpp" +#include <set> +#include <vector> +#include "BoundingShape.h" + +struct Bounds3f { + glm::vec3 min; + glm::vec3 max; +}; + +struct Triangle{ + glm::vec3 vertexA; // one vertex + glm::vec3 vertexB; + glm::vec3 vertexC; + + glm::vec3 edge1; // two edges + glm::vec3 edge2; + + glm::vec3 normal;// = glm::cross(edge1, edge2); + Bounds3f bounds; + + +}; + +class BoundingTriangle : public BoundingShape +{ +public: + BoundingTriangle(const std::vector<glm::vec3> &obj_data, + const std::shared_ptr<ModelTransform> &mt, + bool isGround = false); + std::vector<Triangle> getTriangleData(); + + Bounds3f getMeshBounds(); + std::vector<glm::vec3> getSurfacePoints(); + glm::vec3 getRandomSurfacePos(); + + + +private: + void addTriangle(const glm::vec3 &vertexA, const glm::vec3 &vertexB, const glm::vec3 &vertexC); + void populateTriangleData(const std::vector<glm::vec3> &obj_data); + void calculateBounds(const std::vector<glm::vec3> &obj_data); + Bounds3f calculateTriangleBounds(const glm::vec3 &vertexA, const glm::vec3 &vertexB, const glm::vec3 &vertexC); + + float getArea(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C); + glm::vec3 getCentroid(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C); + void tesselateTriangle(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C); + + + int m_datasize = 0; + + + + + + std::vector<Triangle> m_triangles; + std::shared_ptr<ModelTransform> obj_mt; + std::set<glm::vec3> m_unique_surface_points; + std::vector<glm::vec3> m_surface_points; + bool m_isGround = false; + + float min_x, min_y, min_z, max_x, max_y, max_z; +}; + +#endif // BOUNDINGTRIANGLE_H diff --git a/engine-ocean/Game/Components/CollisionComponents/collisioncomponent.h b/engine-ocean/Game/Components/CollisionComponents/collisioncomponent.h new file mode 100644 index 0000000..daef723 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/collisioncomponent.h @@ -0,0 +1,49 @@ +#ifndef COLLISIONCOMPONENT_H +#define COLLISIONCOMPONENT_H + +#include "Game/Components/CollisionComponents/BoundingShape.h" +#include <map> +#include <string> +#include "Game/TypeMap.h" +#include "Graphics/modeltransform.h" +#include "glm/glm.hpp" +#include "Game/Components/Component.h" + + +class CollisionComponent : public Component +{ +public: + template <typename T> + void addCollisionShape(std::shared_ptr<T> &&component){ + m_collision_shapes.put<T>(std::forward<std::shared_ptr<T>>(component)); + } + + template <typename T> + bool hasCollisionShape(){ + return m_collision_shapes.contains<T>(); + } + + template <class T> + T* getCollisionShape(){ + auto comp = m_collision_shapes.find<T>(); + assert(comp != m_collision_shapes.end()); + return static_cast<T*>(comp->second.get()); + } + + CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos, std::vector<glm::vec3> &obj_data); + CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos); + CollisionComponent(std::string shapeType, const std::vector<glm::vec3> &obj_data, const std::shared_ptr<ModelTransform> &mt, + bool isGround = false); + + bool isRigidBody(); + float getReboundVel(); + float getAcceleration(); + +private: + TypeMap<std::shared_ptr<BoundingShape>> m_collision_shapes; + bool m_isRigid = true; + float m_rebound_vel = 0.f; + float m_acceleration = 0.f; +}; + +#endif // COLLISIONCOMPONENT_H |