赞
踩
open dynamics engine
是一个很老的高性能刚体物理运算库。
#include <vector> #include <map> #include "ode/ode.h" #include "raylib.h" int screenWidth = 1280; // 窗口宽 int screenHeight = 720; //窗口高 int fps = 60; // 帧率 int count = 15; // 单摆数量 double interval = .001; //每个小球之间的间隙 double phyicsStep = 0.0001; // 每次物理运算经过的时间 int subStep = 300; // 每一帧物理运算次数 dWorldID world; dJointGroupID contactgroup; dSpaceID space; dMass m1; std::map<dGeomID, dJointID> g2j; std::map<dGeomID, Color> g2c; const dReal *pos, *R; struct MyObject { dBodyID body; dGeomID geom; Model model; dReal size; }; void nearCallback(void *data, dGeomID o1, dGeomID o2) { if (g2j.contains(o1) && g2j.contains(o2) && g2j[o1] == g2j[o2]) { return; } int N = 1; dContact contact[N]; int n = dCollide(o1, o2, N, &contact[0].geom, sizeof(dContact)); if (n > 0) { g2c[o1] = RED; g2c[o2] = RED; } for (int i = 0; i < n; i++) { contact[i].surface.mode = dContactBounce; contact[i].surface.mu = dInfinity; contact[i].surface.bounce = .99; contact[i].surface.bounce_vel = 0.; dJointID c = dJointCreateContact(world, contactgroup, &contact[i]); dJointAttach(c, dGeomGetBody(contact[i].geom.g1), dGeomGetBody(contact[i].geom.g2)); } } void setTransform(const dReal R[12], Matrix *matrix) { matrix->m0 = float(R[0]); matrix->m1 = float(R[4]); matrix->m2 = float(R[8]); matrix->m4 = float(R[1]); matrix->m5 = float(R[5]); matrix->m6 = float(R[9]); matrix->m8 = float(R[2]); matrix->m9 = float(R[6]); matrix->m10 = float(R[10]); } struct MyJoint { MyObject ball; MyObject pole; }; MyJoint createAobj(int i) { MyObject ball{ .body = dBodyCreate(world), .size = 2., }; ball.model = LoadModelFromMesh(GenMeshSphere(float(ball.size), 9, 16)); dMassSetZero(&m1); dMassSetSphereTotal(&m1, 1., ball.size); dBodySetMass(ball.body, &m1); dBodySetPosition(ball.body, (double(i) - double(count - 1) / 2.) * ball.size * (ball.size + interval), 4., 0.); ball.geom = dCreateSphere(space, ball.size); dGeomSetBody(ball.geom, ball.body); g2c[ball.geom] = WHITE; MyObject pole{ .body = dBodyCreate(world), .size = 0.25, }; pole.model = LoadModelFromMesh(GenMeshCube(float(pole.size), float(pole.size) * 40.f, float(pole.size))); dMassSetZero(&m1); dMassSetBoxTotal(&m1, .001, pole.size, pole.size * 40., pole.size); dBodySetMass(pole.body, &m1); dBodySetPosition(pole.body, (double(i) - double(count - 1) / 2.) * ball.size * (ball.size + interval), 0.5 * pole.size * 40. + ball.size + 4., 0.); pole.geom = dCreateBox(space, pole.size, pole.size * 40., pole.size); dGeomSetBody(pole.geom, pole.body); dJointID joint = dJointCreateHinge(world, nullptr); dJointAttach(joint, ball.body, pole.body); dJointSetHingeAnchor(joint, (double(i) - double(count - 1) / 2.) * ball.size * (ball.size + interval), ball.size + 4., 0.); dJointSetHingeAxis(joint, 0, 0, 1); g2j[pole.geom] = joint; g2j[ball.geom] = joint; dJointID jt = dJointCreateHinge(world, nullptr); dJointAttach(jt, pole.body, nullptr); dJointSetHingeAnchor(jt, (double(i) - double(count - 1) / 2.) * ball.size * (ball.size + interval), ball.size + 4. + pole.size * 40., 0.); dJointSetHingeAxis(jt, 0, 0, 1); return MyJoint{ .ball = ball, .pole = pole, }; } int main() { SetConfigFlags(FLAG_MSAA_4X_HINT); SetConfigFlags(FLAG_WINDOW_RESIZABLE); InitWindow(screenWidth, screenHeight, "raylib ODE"); Camera3D camera = {0}; camera.position = (Vector3) {0.f, 10.f, float((count + 5) * 2)}; camera.target = (Vector3) {0.f, 10.f, 0.f}; camera.up = (Vector3) {0.f, 1.f, 0.f}; camera.fovy = 60.0f; camera.projection = CAMERA_PERSPECTIVE; SetCameraMode(camera, CAMERA_FREE); SetCameraAltControl(KEY_LEFT_SHIFT); SetCameraPanControl(MOUSE_BUTTON_RIGHT); SetTargetFPS(fps); dInitODE(); world = dWorldCreate(); space = dHashSpaceCreate(nullptr); contactgroup = dJointGroupCreate(0); dWorldSetGravity(world, 0., -98, 0.); std::vector<MyJoint> objs; for (int i = 0; i < count; ++i) { objs.push_back(createAobj(i)); } while (!WindowShouldClose()) { for (int i = 0; i < subStep; ++i) { if (IsKeyDown(KEY_SPACE)) { dBodySetTorque(objs[0].pole.body, 0, 0, -300); dBodySetForce(objs[0].ball.body, -50, 10, 0); } dSpaceCollide(space, nullptr, &nearCallback); dWorldStep(world, phyicsStep); dJointGroupEmpty(contactgroup); } UpdateCamera(&camera); BeginDrawing(); ClearBackground(BLACK); BeginMode3D(camera); for (auto &obj : objs) { pos = dBodyGetPosition(obj.ball.body); R = dBodyGetRotation(obj.ball.body); setTransform(R, &obj.ball.model.transform); DrawModelWires(obj.ball.model, Vector3{float(pos[0]), float(pos[1]), float(pos[2])}, 1.f, BLACK); DrawModel(obj.ball.model, Vector3{float(pos[0]), float(pos[1]), float(pos[2])}, 1.f, g2c[obj.ball.geom]); pos = dBodyGetPosition(obj.pole.body); R = dBodyGetRotation(obj.pole.body); setTransform(R, &obj.pole.model.transform); DrawModelWires(obj.pole.model, Vector3{float(pos[0]), float(pos[1]), float(pos[2])}, 1.f, BLACK); DrawModel(obj.pole.model, Vector3{float(pos[0]), float(pos[1]), float(pos[2])}, 1.f, WHITE); } EndMode3D(); DrawFPS(10, 10); EndDrawing(); for (auto &c : g2c) { c.second = WHITE; } } dWorldDestroy(world); dCloseODE(); CloseWindow(); return 0; }
首先需要安装 raylib
和 ode
,ArchLinux 可通过 pacman
直接安装:
sudo pacman -S raylib ode
也要有 c++
编译器,执行编译命令:
g++ -O2 -lraylib -lode --std=c++23 main.cpp
执行生成的 a.out
即可。
鼠标右键
并 移动鼠标:拖动场景Shift
,然后长按 鼠标右键
并 移动鼠标:旋转场景空格
:拉起第一颗球Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。