diff --git a/src/Engine.cpp b/src/Engine.cpp index c213393..ad90069 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -1419,7 +1419,6 @@ void Engine::setParent(int childId, int parentId) { if (projectManager.currentProject.isLoaded) { projectManager.currentProject.hasUnsavedChanges = true; } - logToConsole("Reparented object"); } void Engine::addConsoleMessage(const std::string& message, ConsoleMessageType type) { diff --git a/src/ModelLoader.cpp b/src/ModelLoader.cpp index f40fd6b..7eec0bf 100644 --- a/src/ModelLoader.cpp +++ b/src/ModelLoader.cpp @@ -173,6 +173,13 @@ ModelLoadResult ModelLoader::loadModel(const std::string& filepath) { loaded.boundsMin = raw.boundsMin; loaded.boundsMax = raw.boundsMax; loaded.triangleVertices = std::move(triPositions); + loaded.positions = raw.positions; + loaded.triangleIndices.reserve(raw.faces.size() * 3); + for (const auto& face : raw.faces) { + loaded.triangleIndices.push_back(face.x); + loaded.triangleIndices.push_back(face.y); + loaded.triangleIndices.push_back(face.z); + } loadedMeshes.push_back(std::move(loaded)); @@ -209,6 +216,8 @@ ModelLoadResult ModelLoader::loadModel(const std::string& filepath) { glm::vec3 boundsMin(FLT_MAX); glm::vec3 boundsMax(-FLT_MAX); std::vector triPositions; + std::vector positions; + std::vector indices; // Process all meshes in the scene std::vector vertices; @@ -218,7 +227,7 @@ ModelLoadResult ModelLoader::loadModel(const std::string& filepath) { result.hasTangents = false; // Process the root node recursively - processNode(scene->mRootNode, scene, aiMatrix4x4(), vertices, triPositions, boundsMin, boundsMax); + processNode(scene->mRootNode, scene, aiMatrix4x4(), vertices, triPositions, positions, indices, boundsMin, boundsMax); // Check mesh properties for (unsigned int i = 0; i < scene->mNumMeshes; i++) { @@ -248,6 +257,8 @@ ModelLoadResult ModelLoader::loadModel(const std::string& filepath) { loaded.boundsMin = boundsMin; loaded.boundsMax = boundsMax; loaded.triangleVertices = std::move(triPositions); + loaded.positions = std::move(positions); + loaded.triangleIndices = std::move(indices); loadedMeshes.push_back(std::move(loaded)); @@ -521,6 +532,14 @@ bool ModelLoader::updateRawMesh(int meshIndex, const RawMeshAsset& asset, std::s loaded.boundsMin = asset.boundsMin; loaded.boundsMax = asset.boundsMax; loaded.triangleVertices = std::move(triPositions); + loaded.positions = asset.positions; + loaded.triangleIndices.clear(); + loaded.triangleIndices.reserve(asset.faces.size() * 3); + for (const auto& face : asset.faces) { + loaded.triangleIndices.push_back(face.x); + loaded.triangleIndices.push_back(face.y); + loaded.triangleIndices.push_back(face.z); + } return true; } @@ -589,27 +608,54 @@ static void collectRawMeshData(aiNode* node, const aiScene* scene, const aiMatri } } -void ModelLoader::processNode(aiNode* node, const aiScene* scene, const aiMatrix4x4& parentTransform, std::vector& vertices, std::vector& triPositions, glm::vec3& boundsMin, glm::vec3& boundsMax) { +void ModelLoader::processNode(aiNode* node, const aiScene* scene, const aiMatrix4x4& parentTransform, + std::vector& vertices, std::vector& triPositions, + std::vector& positions, std::vector& indices, + glm::vec3& boundsMin, glm::vec3& boundsMax) { aiMatrix4x4 currentTransform = parentTransform * node->mTransformation; // Process all meshes in this node for (unsigned int i = 0; i < node->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; - processMesh(mesh, currentTransform, vertices, triPositions, boundsMin, boundsMax); + processMesh(mesh, currentTransform, vertices, triPositions, positions, indices, boundsMin, boundsMax); } // Process children nodes for (unsigned int i = 0; i < node->mNumChildren; i++) { - processNode(node->mChildren[i], scene, currentTransform, vertices, triPositions, boundsMin, boundsMax); + processNode(node->mChildren[i], scene, currentTransform, vertices, triPositions, positions, indices, boundsMin, boundsMax); } } -void ModelLoader::processMesh(aiMesh* mesh, const aiMatrix4x4& transform, std::vector& vertices, std::vector& triPositions, glm::vec3& boundsMin, glm::vec3& boundsMax) { +void ModelLoader::processMesh(aiMesh* mesh, const aiMatrix4x4& transform, + std::vector& vertices, std::vector& triPositions, + std::vector& positions, std::vector& indices, + glm::vec3& boundsMin, glm::vec3& boundsMax) { glm::mat4 gTransform = aiToGlm(transform); glm::mat3 normalMat = glm::transpose(glm::inverse(glm::mat3(gTransform))); + size_t baseIndex = positions.size(); + positions.reserve(baseIndex + mesh->mNumVertices); + for (unsigned int v = 0; v < mesh->mNumVertices; v++) { + glm::vec3 pos(mesh->mVertices[v].x, mesh->mVertices[v].y, mesh->mVertices[v].z); + glm::vec4 transformed = gTransform * glm::vec4(pos, 1.0f); + glm::vec3 finalPos = glm::vec3(transformed) / (transformed.w == 0.0f ? 1.0f : transformed.w); + positions.push_back(finalPos); + + boundsMin.x = std::min(boundsMin.x, finalPos.x); + boundsMin.y = std::min(boundsMin.y, finalPos.y); + boundsMin.z = std::min(boundsMin.z, finalPos.z); + boundsMax.x = std::max(boundsMax.x, finalPos.x); + boundsMax.y = std::max(boundsMax.y, finalPos.y); + boundsMax.z = std::max(boundsMax.z, finalPos.z); + } + // Process each face for (unsigned int i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; + if (face.mNumIndices == 3) { + indices.push_back(static_cast(baseIndex + face.mIndices[0])); + indices.push_back(static_cast(baseIndex + face.mIndices[1])); + indices.push_back(static_cast(baseIndex + face.mIndices[2])); + } // Process each vertex of the face for (unsigned int j = 0; j < face.mNumIndices; j++) { @@ -627,13 +673,6 @@ void ModelLoader::processMesh(aiMesh* mesh, const aiMatrix4x4& transform, std::v triPositions.push_back(finalPos); - boundsMin.x = std::min(boundsMin.x, finalPos.x); - boundsMin.y = std::min(boundsMin.y, finalPos.y); - boundsMin.z = std::min(boundsMin.z, finalPos.z); - boundsMax.x = std::max(boundsMax.x, finalPos.x); - boundsMax.y = std::max(boundsMax.y, finalPos.y); - boundsMax.z = std::max(boundsMax.z, finalPos.z); - // Normal if (mesh->mNormals) { glm::vec3 n(mesh->mNormals[index].x, diff --git a/src/ModelLoader.h b/src/ModelLoader.h index 3802ae3..aa1a0fd 100644 --- a/src/ModelLoader.h +++ b/src/ModelLoader.h @@ -89,8 +89,14 @@ private: ModelLoader& operator=(const ModelLoader&) = delete; // Process Assimp scene - void processNode(aiNode* node, const aiScene* scene, const aiMatrix4x4& parentTransform, std::vector& vertices, std::vector& triPositions, glm::vec3& boundsMin, glm::vec3& boundsMax); - void processMesh(aiMesh* mesh, const aiMatrix4x4& transform, std::vector& vertices, std::vector& triPositions, glm::vec3& boundsMin, glm::vec3& boundsMax); + void processNode(aiNode* node, const aiScene* scene, const aiMatrix4x4& parentTransform, + std::vector& vertices, std::vector& triPositions, + std::vector& positions, std::vector& indices, + glm::vec3& boundsMin, glm::vec3& boundsMax); + void processMesh(aiMesh* mesh, const aiMatrix4x4& transform, + std::vector& vertices, std::vector& triPositions, + std::vector& positions, std::vector& indices, + glm::vec3& boundsMin, glm::vec3& boundsMax); // Storage for loaded meshes (reusing OBJLoader::LoadedMesh structure) std::vector loadedMeshes; diff --git a/src/PhysicsSystem.cpp b/src/PhysicsSystem.cpp index 84bdbca..ca156d9 100644 --- a/src/PhysicsSystem.cpp +++ b/src/PhysicsSystem.cpp @@ -5,6 +5,7 @@ #include "ModelLoader.h" #include #include +#include #include "extensions/PxRigidBodyExt.h" using namespace physx; @@ -72,6 +73,7 @@ bool PhysicsSystem::init() { mCookParams = PxCookingParams(scale); mCookParams.meshPreprocessParams |= PxMeshPreprocessingFlag::eDISABLE_ACTIVE_EDGES_PRECOMPUTE; mCookParams.meshPreprocessParams |= PxMeshPreprocessingFlag::eWELD_VERTICES; + mCookParams.meshWeldTolerance = std::max(0.0001f, 0.001f * scale.length); PxSceneDesc sceneDesc(mPhysics->getTolerancesScale()); sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f); @@ -110,7 +112,21 @@ bool PhysicsSystem::gatherMeshData(const SceneObject& obj, std::vector& } else if (obj.type == ObjectType::Model && obj.meshId >= 0) { meshInfo = getModelLoader().getMeshInfo(obj.meshId); } - if (!meshInfo || meshInfo->triangleVertices.empty()) { + if (!meshInfo) { + return false; + } + + if (!meshInfo->positions.empty() && meshInfo->triangleIndices.size() >= 3) { + vertices.reserve(meshInfo->positions.size()); + indices.reserve(meshInfo->triangleIndices.size()); + for (const auto& v : meshInfo->positions) { + vertices.emplace_back(v.x, v.y, v.z); + } + indices.insert(indices.end(), meshInfo->triangleIndices.begin(), meshInfo->triangleIndices.end()); + return !vertices.empty() && (indices.size() % 3 == 0); + } + + if (meshInfo->triangleVertices.empty()) { return false; } @@ -130,38 +146,46 @@ PxTriangleMesh* PhysicsSystem::cookTriangleMesh(const std::vector& verti const std::vector& indices) const { if (vertices.empty() || indices.size() < 3) return nullptr; - PxTriangleMeshDesc desc; - desc.points.count = static_cast(vertices.size()); - desc.points.stride = sizeof(PxVec3); - desc.points.data = vertices.data(); - desc.triangles.count = static_cast(indices.size() / 3); - desc.triangles.stride = 3 * sizeof(uint32_t); - desc.triangles.data = indices.data(); + try { + PxTriangleMeshDesc desc; + desc.points.count = static_cast(vertices.size()); + desc.points.stride = sizeof(PxVec3); + desc.points.data = vertices.data(); + desc.triangles.count = static_cast(indices.size() / 3); + desc.triangles.stride = 3 * sizeof(uint32_t); + desc.triangles.data = indices.data(); - PxDefaultMemoryOutputStream buf; - if (!PxCookTriangleMesh(mCookParams, desc, buf)) { + PxDefaultMemoryOutputStream buf; + if (!PxCookTriangleMesh(mCookParams, desc, buf)) { + return nullptr; + } + PxDefaultMemoryInputData input(buf.getData(), buf.getSize()); + return mPhysics->createTriangleMesh(input); + } catch (const std::bad_alloc&) { return nullptr; } - PxDefaultMemoryInputData input(buf.getData(), buf.getSize()); - return mPhysics->createTriangleMesh(input); } PxConvexMesh* PhysicsSystem::cookConvexMesh(const std::vector& vertices) const { if (vertices.size() < 4) return nullptr; - PxConvexMeshDesc desc; - desc.points.count = static_cast(vertices.size()); - desc.points.stride = sizeof(PxVec3); - desc.points.data = vertices.data(); - desc.flags = PxConvexFlag::eCOMPUTE_CONVEX | PxConvexFlag::eCHECK_ZERO_AREA_TRIANGLES; - desc.vertexLimit = 255; + try { + PxConvexMeshDesc desc; + desc.points.count = static_cast(vertices.size()); + desc.points.stride = sizeof(PxVec3); + desc.points.data = vertices.data(); + desc.flags = PxConvexFlag::eCOMPUTE_CONVEX | PxConvexFlag::eCHECK_ZERO_AREA_TRIANGLES; + desc.vertexLimit = 255; - PxDefaultMemoryOutputStream buf; - if (!PxCookConvexMesh(mCookParams, desc, buf)) { + PxDefaultMemoryOutputStream buf; + if (!PxCookConvexMesh(mCookParams, desc, buf)) { + return nullptr; + } + PxDefaultMemoryInputData input(buf.getData(), buf.getSize()); + return mPhysics->createConvexMesh(input); + } catch (const std::bad_alloc&) { return nullptr; } - PxDefaultMemoryInputData input(buf.getData(), buf.getSize()); - return mPhysics->createConvexMesh(input); } bool PhysicsSystem::attachPrimitiveShape(PxRigidActor* actor, const SceneObject& obj, bool isDynamic) const { @@ -255,36 +279,98 @@ bool PhysicsSystem::attachColliderShape(PxRigidActor* actor, const SceneObject& } minDim = std::min(radius * 2.0f, halfHeight * 2.0f); } else { - std::vector verts; - std::vector indices; - if (!gatherMeshData(obj, verts, indices)) { + const OBJLoader::LoadedMesh* meshInfo = nullptr; + if (obj.type == ObjectType::OBJMesh && obj.meshId >= 0) { + meshInfo = g_objLoader.getMeshInfo(obj.meshId); + } else if (obj.type == ObjectType::Model && obj.meshId >= 0) { + meshInfo = getModelLoader().getMeshInfo(obj.meshId); + } + if (!meshInfo) { + return false; + } + const bool hasIndexed = !meshInfo->positions.empty() && meshInfo->triangleIndices.size() >= 3; + const bool hasTriVerts = !meshInfo->triangleVertices.empty(); + if (!hasIndexed && !hasTriVerts) { return false; } - bool useConvex = obj.collider.convex || obj.collider.type == ColliderType::ConvexMesh || isDynamic; - glm::vec3 boundsMin(FLT_MAX); - glm::vec3 boundsMax(-FLT_MAX); - for (auto& v : verts) { - boundsMin.x = std::min(boundsMin.x, v.x * obj.scale.x); - boundsMin.y = std::min(boundsMin.y, v.y * obj.scale.y); - boundsMin.z = std::min(boundsMin.z, v.z * obj.scale.z); - boundsMax.x = std::max(boundsMax.x, v.x * obj.scale.x); - boundsMax.y = std::max(boundsMax.y, v.y * obj.scale.y); - boundsMax.z = std::max(boundsMax.z, v.z * obj.scale.z); - } - minDim = std::max(0.01f, std::min({boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y, boundsMax.z - boundsMin.z})); - if (useConvex) { - PxConvexMesh* convex = cookConvexMesh(verts); - if (!convex) return false; - PxConvexMeshGeometry geom(convex, PxMeshScale(ToPxVec3(obj.scale), PxQuat(PxIdentity))); - shape = mPhysics->createShape(geom, *mDefaultMaterial, true); - convex->release(); + auto makeBoundsShape = [&](const glm::vec3& boundsMin, const glm::vec3& boundsMax) { + glm::vec3 halfExtents = glm::max((boundsMax - boundsMin) * 0.5f, glm::vec3(0.01f)); + glm::vec3 center = (boundsMax + boundsMin) * 0.5f; + PxShape* box = mPhysics->createShape(PxBoxGeometry(ToPxVec3(halfExtents)), *mDefaultMaterial, true); + if (box) { + box->setLocalPose(PxTransform(ToPxVec3(center), PxQuat(PxIdentity))); + } + return box; + }; + + constexpr size_t kMaxCookVertices = 1000000; + size_t cookVertices = hasIndexed ? meshInfo->positions.size() : meshInfo->triangleVertices.size(); + if (cookVertices > kMaxCookVertices) { + glm::vec3 boundsMin(FLT_MAX); + glm::vec3 boundsMax(-FLT_MAX); + const auto& sourceVerts = hasIndexed ? meshInfo->positions : meshInfo->triangleVertices; + for (const auto& v : sourceVerts) { + glm::vec3 scaled = v * obj.scale; + boundsMin = glm::min(boundsMin, scaled); + boundsMax = glm::max(boundsMax, scaled); + } + minDim = std::max(0.01f, std::min({boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y, boundsMax.z - boundsMin.z})); + shape = makeBoundsShape(boundsMin, boundsMax); } else { - PxTriangleMesh* tri = cookTriangleMesh(verts, indices); - if (!tri) return false; - PxTriangleMeshGeometry geom(tri, PxMeshScale(ToPxVec3(obj.scale), PxQuat(PxIdentity))); - shape = mPhysics->createShape(geom, *mDefaultMaterial, true); - tri->release(); + std::vector verts; + std::vector indices; + bool hasMeshData = false; + try { + hasMeshData = gatherMeshData(obj, verts, indices); + } catch (const std::bad_alloc&) { + hasMeshData = false; + } + + if (!hasMeshData) { + glm::vec3 boundsMin(FLT_MAX); + glm::vec3 boundsMax(-FLT_MAX); + const auto& sourceVerts = hasIndexed ? meshInfo->positions : meshInfo->triangleVertices; + for (const auto& v : sourceVerts) { + glm::vec3 scaled = v * obj.scale; + boundsMin = glm::min(boundsMin, scaled); + boundsMax = glm::max(boundsMax, scaled); + } + minDim = std::max(0.01f, std::min({boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y, boundsMax.z - boundsMin.z})); + shape = makeBoundsShape(boundsMin, boundsMax); + } else { + bool useConvex = obj.collider.convex || obj.collider.type == ColliderType::ConvexMesh || isDynamic; + glm::vec3 boundsMin(FLT_MAX); + glm::vec3 boundsMax(-FLT_MAX); + for (auto& v : verts) { + boundsMin.x = std::min(boundsMin.x, v.x * obj.scale.x); + boundsMin.y = std::min(boundsMin.y, v.y * obj.scale.y); + boundsMin.z = std::min(boundsMin.z, v.z * obj.scale.z); + boundsMax.x = std::max(boundsMax.x, v.x * obj.scale.x); + boundsMax.y = std::max(boundsMax.y, v.y * obj.scale.y); + boundsMax.z = std::max(boundsMax.z, v.z * obj.scale.z); + } + minDim = std::max(0.01f, std::min({boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y, boundsMax.z - boundsMin.z})); + if (useConvex) { + PxConvexMesh* convex = cookConvexMesh(verts); + if (convex) { + PxConvexMeshGeometry geom(convex, PxMeshScale(ToPxVec3(obj.scale), PxQuat(PxIdentity))); + shape = mPhysics->createShape(geom, *mDefaultMaterial, true); + convex->release(); + } + } else { + PxTriangleMesh* tri = cookTriangleMesh(verts, indices); + if (tri) { + PxTriangleMeshGeometry geom(tri, PxMeshScale(ToPxVec3(obj.scale), PxQuat(PxIdentity))); + shape = mPhysics->createShape(geom, *mDefaultMaterial, true); + tri->release(); + } + } + + if (!shape) { + shape = makeBoundsShape(boundsMin, boundsMax); + } + } } } @@ -385,6 +471,51 @@ void PhysicsSystem::onPlayStart(const std::vector& objects) { clearActors(); createGroundPlane(); + struct MeshCookInfo { + std::string name; + size_t vertices = 0; + size_t triangles = 0; + size_t duplicateVertices = 0; + }; + std::vector cookInfos; + cookInfos.reserve(objects.size()); + + for (const auto& obj : objects) { + if (!obj.enabled || !obj.hasCollider || !obj.collider.enabled) continue; + if (obj.collider.type == ColliderType::Box || obj.collider.type == ColliderType::Capsule) continue; + const OBJLoader::LoadedMesh* meshInfo = nullptr; + if (obj.type == ObjectType::OBJMesh && obj.meshId >= 0) { + meshInfo = g_objLoader.getMeshInfo(obj.meshId); + } else if (obj.type == ObjectType::Model && obj.meshId >= 0) { + meshInfo = getModelLoader().getMeshInfo(obj.meshId); + } + if (!meshInfo) continue; + const bool hasIndexed = !meshInfo->positions.empty() && meshInfo->triangleIndices.size() >= 3; + const bool hasTriVerts = !meshInfo->triangleVertices.empty(); + if (!hasIndexed && !hasTriVerts) continue; + MeshCookInfo info; + info.name = obj.name; + info.vertices = hasIndexed ? meshInfo->positions.size() : meshInfo->triangleVertices.size(); + info.triangles = hasIndexed ? (meshInfo->triangleIndices.size() / 3) : (meshInfo->triangleVertices.size() / 3); + info.duplicateVertices = meshInfo->triangleVertices.size(); + cookInfos.push_back(info); + } + + if (!cookInfos.empty()) { + std::sort(cookInfos.begin(), cookInfos.end(), + [](const MeshCookInfo& a, const MeshCookInfo& b) { return a.vertices > b.vertices; }); + size_t reportCount = std::min(cookInfos.size(), 5); + std::cerr << "[Physics] Mesh collider stats (top " << reportCount << " by vertex count):\n"; + for (size_t i = 0; i < reportCount; ++i) { + const auto& info = cookInfos[i]; + std::cerr << " " << info.name + << " verts=" << info.vertices + << " tris=" << info.triangles + << " dupVerts=" << info.duplicateVertices + << "\n"; + } + } + for (const auto& obj : objects) { if (!obj.enabled) continue; ActorRecord rec = createActorFor(obj); diff --git a/src/Rendering.cpp b/src/Rendering.cpp index 429b07f..b7cc4d4 100644 --- a/src/Rendering.cpp +++ b/src/Rendering.cpp @@ -363,6 +363,13 @@ int OBJLoader::loadOBJ(const std::string& filepath, std::string& errorMsg) { glm::vec3 boundsMin(FLT_MAX); glm::vec3 boundsMax(-FLT_MAX); std::vector triPositions; + std::vector positions; + std::vector triangleIndices; + + positions.reserve(attrib.vertices.size() / 3); + for (size_t i = 0; i + 2 < attrib.vertices.size(); i += 3) { + positions.emplace_back(attrib.vertices[i], attrib.vertices[i + 1], attrib.vertices[i + 2]); + } for (const auto& shape : shapes) { size_t indexOffset = 0; @@ -376,6 +383,8 @@ int OBJLoader::loadOBJ(const std::string& filepath, std::string& errorMsg) { bool hasNormal = false; }; std::vector faceVerts; + std::vector facePosIndices; + facePosIndices.reserve(static_cast(fv)); for (int v = 0; v < fv; v++) { tinyobj::index_t idx = shape.mesh.indices[indexOffset + v]; @@ -407,6 +416,7 @@ int OBJLoader::loadOBJ(const std::string& filepath, std::string& errorMsg) { } faceVerts.push_back(tv); + facePosIndices.push_back(idx.vertex_index); } if (!hasNormalsInFile && fv >= 3) { @@ -424,6 +434,15 @@ int OBJLoader::loadOBJ(const std::string& filepath, std::string& errorMsg) { for (int v = 1; v < fv - 1; v++) { const TempVertex* tri[3] = { &faceVerts[0], &faceVerts[v], &faceVerts[v+1] }; + int idx0 = facePosIndices[0]; + int idx1 = facePosIndices[v]; + int idx2 = facePosIndices[v + 1]; + if (idx0 >= 0 && idx1 >= 0 && idx2 >= 0) { + triangleIndices.push_back(static_cast(idx0)); + triangleIndices.push_back(static_cast(idx1)); + triangleIndices.push_back(static_cast(idx2)); + } + for (int i = 0; i < 3; i++) { triPositions.push_back(tri[i]->pos); vertices.push_back(tri[i]->pos.x); @@ -457,6 +476,8 @@ int OBJLoader::loadOBJ(const std::string& filepath, std::string& errorMsg) { loaded.boundsMin = boundsMin; loaded.boundsMax = boundsMax; loaded.triangleVertices = std::move(triPositions); + loaded.positions = std::move(positions); + loaded.triangleIndices = std::move(triangleIndices); loadedMeshes.push_back(std::move(loaded)); return static_cast(loadedMeshes.size() - 1); diff --git a/src/Rendering.h b/src/Rendering.h index fe47ae4..e9d711b 100644 --- a/src/Rendering.h +++ b/src/Rendering.h @@ -6,6 +6,7 @@ #include "../include/Textures/Texture.h" #include "../include/Skybox/Skybox.h" #include +#include // Cube vertex data (position + normal + texcoord) extern float vertices[]; @@ -41,6 +42,8 @@ public: glm::vec3 boundsMin = glm::vec3(FLT_MAX); glm::vec3 boundsMax = glm::vec3(-FLT_MAX); std::vector triangleVertices; // positions duplicated per-triangle for picking + std::vector positions; // unique vertex positions for physics + std::vector triangleIndices; // triangle indices into positions }; private: