C++新手Raylib开发:盒子与低多边形碰撞网格碰撞检测咨询
盒体与低多边形网格的碰撞检测方案(Raylib + C++)
核心思路
既然你用的是极低多边形的碰撞网格(比如3面柱体),最直接的高精度检测方式就是逐个检查盒体与网格的每个三角形是否相交,再补充检测盒体是否完全陷入网格内部(针对闭合网格)。Raylib本身提供了基础的碰撞检测函数,我们可以基于这些快速实现需求。
步骤拆解
- 提前提取低多边形模型的所有三角形顶点数据,每个三角形由3个
Vector3构成 - 遍历所有三角形,用Raylib内置的
CheckCollisionBoxTriangle判断盒体是否与三角形相交 - (可选)针对闭合网格,通过射线法判断盒体中心是否在网格内部,避免漏检完全包裹的情况
示例代码
#include "raylib.h" #include <vector> // 从Raylib Mesh中提取所有三角形的顶点数据 std::vector<Vector3> ExtractMeshTriangles(Mesh mesh) { std::vector<Vector3> triangles; triangles.reserve(mesh.triangleCount * 3); // Raylib的顶点数据是float数组,每3个元素对应一个顶点的x/y/z for (int i = 0; i < mesh.triangleCount * 3; i++) { int idx = i * 3; Vector3 vertex = { mesh.vertices[idx], mesh.vertices[idx + 1], mesh.vertices[idx + 2] }; triangles.push_back(vertex); } return triangles; } // 检测盒体是否与低多边形网格发生穿透 bool IsBoxMeshColliding(BoundingBox box, const std::vector<Vector3>& triangles) { // 第一步:检测盒体是否与任意三角形相交 for (size_t i = 0; i < triangles.size(); i += 3) { Vector3 v1 = triangles[i]; Vector3 v2 = triangles[i + 1]; Vector3 v3 = triangles[i + 2]; if (CheckCollisionBoxTriangle(box, v1, v2, v3)) { return true; } } // 第二步:检测盒体是否完全在闭合网格内部(可选) Vector3 boxCenter = { (box.min.x + box.max.x) / 2.0f, (box.min.y + box.max.y) / 2.0f, (box.min.z + box.max.z) / 2.0f }; // 沿X轴发射一条射线,统计与网格的交点数,奇数则在内部 Vector3 rayDir = {1.0f, 0.0f, 0.0f}; int hitCount = 0; for (size_t i = 0; i < triangles.size(); i += 3) { Vector3 v1 = triangles[i]; Vector3 v2 = triangles[i + 1]; Vector3 v3 = triangles[i + 2]; float distance; if (CheckCollisionRayTriangle(boxCenter, rayDir, v1, v2, v3, &distance)) { hitCount++; } } return (hitCount % 2 != 0); } int main() { InitWindow(800, 600, "Box-Mesh Collision Test"); SetTargetFPS(60); // 加载你的低多边形碰撞模型(替换为实际路径) Model collisionMesh = LoadModel("low_poly_stem.obj"); std::vector<Vector3> triangles = ExtractMeshTriangles(collisionMesh.meshes[0]); // 测试用的可移动盒体 BoundingBox testBox = {{-0.5f, -0.5f, -0.5f}, {0.5f, 0.5f, 0.5f}}; Vector3 boxPos = {0.0f, 0.0f, 0.0f}; while (!WindowShouldClose()) { // WSAD控制盒体移动 if (IsKeyDown(KEY_W)) boxPos.z -= 0.1f; if (IsKeyDown(KEY_S)) boxPos.z += 0.1f; if (IsKeyDown(KEY_A)) boxPos.x -= 0.1f; if (IsKeyDown(KEY_D)) boxPos.x += 0.1f; // 将局部盒体转换到世界空间 BoundingBox worldBox = testBox; worldBox.min = Vector3Add(worldBox.min, boxPos); worldBox.max = Vector3Add(worldBox.max, boxPos); // 执行碰撞检测 bool collision = IsBoxMeshColliding(worldBox, triangles); BeginDrawing(); ClearBackground(RAYWHITE); BeginMode3D(Camera3D{ {3.0f, 3.0f, 3.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, 45.0f, CAMERA_PERSPECTIVE }); // 绘制碰撞网格和盒体 DrawModel(collisionMesh, {0.0f, 0.0f, 0.0f}, 1.0f, DARKGRAY); DrawBoundingBox(worldBox, collision ? RED : LIME); EndMode3D(); DrawText(collision ? "COLLISION DETECTED!" : "NO COLLISION", 10, 10, 24, collision ? RED : LIME); EndDrawing(); } UnloadModel(collisionMesh); CloseWindow(); return 0; }
关键注意点
CheckCollisionBoxTriangle是Raylib原生函数,已经处理了盒体与三角形的所有相交情况,精度完全满足你的需求- 提取三角形时要注意Raylib的Mesh数据结构:
vertices是连续的float数组,每3个元素对应一个顶点坐标 - 如果你的碰撞网格是开放的(比如非闭合的面),可以去掉内部检测的代码,提升性能
- 建议提前提取所有模型的三角形数据并缓存,不要在每帧检测时重复提取,避免性能浪费
内容的提问来源于stack exchange,提问作者Reverend Speed
相关产品推荐
相关产品推荐

