[c++] 使用 raylib + ODE(open dynamics engine) 弄一个简易牛顿摆
Raylib
raylib
是一个简单易用的2D/3D图形库。
ODE
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
,然后长按鼠标右键
并 移动鼠标:旋转场景 - 长按
空格
:拉起第一颗球
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgafbhc
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24