如何将Bullet物理引擎应用于绘制的OpenGL 3D形状

7
我想知道是否有一种方法可以将Bullet物理引擎应用于OpenGL绘制的对象(使用glVertex3f或使用glVertexAttribPointer创建的三角形网格)。我目前正在使用jogl和jbullet将物理应用于我的3D对象。具体来说,如果我为三角形网格形状的顶点提供一个缓冲区,则需要Bullet基于三角形网格形状创建CollisionShape,并对其应用物理,同时对绘制的OpenGL对象应用物理。目前,物理碰撞形状可能会移动(在Bullet中),但绘制的OpenGL形状不会移动。
否则,我可以创建一个碰撞形状,在每次模拟步骤后获取碰撞形状的顶点,然后根据顶点的位置绘制对象。我已经查看了Bullet的Hello world示例,但它只能帮助我在OpenGL对象的位置上应用物理(基于z,y,x轴),而不能像例如立方体的一个角落撞击平面开始滚动和旋转等酷炫效果。
如果有人可以给我一些代码或演示文稿来实现这一点,那就太好了。或者给我一些提示,告诉我如何使这个工作。我已经查看了此教程:http://www.raywenderlich.com/53077/bullet-physics-tutorial-getting-started。但我似乎找不到关于如何将Bullet应用于OpenGL对象的信息。
4个回答

6
在下载了Bullet Physics SDK之后,打开GL_ShapeDrawer.cpp文件,你会发现一些有趣的函数,例如drawSphere、 drawCylinder、 drawOpenGl等等,我提到的最后一个函数可以让你绘制任何类型的支持形状:
CUSTOM_CONVEX_SHAPE_TYPE BOX_SHAPE_PROXYTYPE UNIFORM_SCALING_SHAPE_PROXYTYPE COMPOUND_SHAPE_PROXYTYPE BOX_SHAPE_PROXYTYPE SPHERE_SHAPE_PROXYTYPE
每种类型的形状都有自己专门的OpenGL渲染函数。
但是我的方法包括:
1 - 用网格加载器加载3D模型 2 - 使用OpenGL函数创建图形形状,使用先前的网格加载器 3 - 从网格加载器使用的顶点创建bullet形状 4 - 实现Bullet Motion State(当形状将被旋转、平移或只是“变换”时,你将你的bullet形状的“btTransform”与图形形状的变换矩阵同步,然后更新图形顶点)
个人而言,我使用Irrlicht,因为Irrlicht是OpenGL的“写得少,做得多”的解决方案 :p

谢谢您的帖子。非常全面,也许正是我正在寻找的。我只是想知道如何“将子弹形状的btTransform与图形形状的变换矩阵同步”。我应该如何使用btTransform和形状?是为形状的每个顶点进行转换吗?还是OpenGL中有一个函数可以将旋转和平移应用于整个形状? - Noir
在OpenGL中没有任何函数可以让你对整个形状进行旋转和平移,因为在OpenGL中你只能操作顶点,所以我认为你需要创建自己的图形形状类。这个类至少必须包含用于表示你的图形形状的所有顶点。假设你的图形形状类有一个函数,它可以让你平移其中包含的所有顶点,还有另一个函数可以让你旋转其所有顶点。 - Irrmich
感谢user3817643的澄清。我对Opengl还很陌生,不太清楚它能做什么或不能做什么。 - Noir
最重要的一点是:你必须重新实现btMotionState。当你创建一个btRigidBody时,也许你习惯于写*btRigidBody anyBody = new btRigidBody(mass,new btDefaultMotionState,shape,localInertia);**。这个btDefaultMotionState的实例化必须被你派生的btMotionState类的任何实例化所替换。它是如何工作的?事实上,对于Bullet世界的每一个单独步骤,与每个移动的子弹形状相关联的运动状态都会被调用。btMotionState的setWorldTransform函数必须包含渲染形状的代码。 - Irrmich
1
我认为默认情况下GL_ShapeDrawer.cpp已被OpenGL 3的GLInstancingRenderer.cpp所替代:https://dev59.com/questions/d4Xca4cB1Zd3GeqPFDai#37059619 - Ciro Santilli OurBigBook.com

5

示例浏览器

内置的示例浏览器具有一些OpenGL物理绑定,因此您可以轻松地可视化模拟。

要查看其工作原理,您可以使用以下命令进行编译和运行:

sudo apt build-dep libbullet-dev
git clone https://github.com/bulletphysics/bullet3
cd bullet3
git checkout 2.89
./build_cmake_pybullet_double.sh
./build_cmake/examples/ExampleBrowser/App_ExampleBrowser

截图:

enter image description here

在Ubuntu 20.04上测试通过。

示例浏览器2.83代码分析

示例浏览器已经从默认的examples/ExampleBrowser/GL_ShapeDrawer.cpp中移除,该文件使用过时的immediate OpenGL 2方法。具体取决于NO_OPENGL3宏和命令行参数,仍可打开。

OpenGLWindow/GLInstancingRenderer.cpp是新的OpenGL 3渲染中心,包含GLInstancingRenderer::registerShape中的glBindVertexArray调用。

此方法是从OpenGLGuiHelper::autogenerateGraphicsObjects间接调用的,该方法循环遍历btDiscreteDynamicsWorld中的对象,并生成这些形状的图形版本。

转换的核心部分似乎是OpenGLGuiHelper::createCollisionShapeGraphicsObjectInternal

物体的颜色简单地循环使用OpenGLGuiHelper::sColors中的4种可能颜色。 autogenerateGraphicsObjects被调用于一些例子的initPhysics中。
还有一些明确编码的立方体和球体在SimpleOpenGL3App.cpp,如果你希望图形与物理不同,可以作为起点:图形应该更加详细,因为它们计算代价更小。那些只在少数例子中使用。
如果你要学习示例浏览器,我建议使用带有调试器的集成开发环境:从我的大脑静态分析来看,这是太多间接性了。我使用KDevelop4进行了这个分析。

3
Bullet与OpenGL无关,将转换应用于几何图形取决于您。您可以将转换存储到单独的对象中,而不是修改顶点。这是Vehicle Dynamics Engine Demo(JOGL + JBullet)和JMonkeyEngine 3所做的,它具有自己的Bullet绑定并基于JOGL 2(以及我不使用的其他渲染器)的渲染器。请查看我们使用JOGL和JBullet的演示:https://github.com/sgothel/jogl-demos/tree/master/src/jbullet

谢谢,我会查看演示并回复您。 - Noir
你好,我想知道是否可以帮我找到转换对象而不是顶点的代码?就像在RagDoll.java中,哪一部分代码实际上允许我转换对象?哪一部分显示了如何根据JBullet转换JOGL对象。我看了车辆动态引擎演示,但似乎找不到该演示的主类。 - Noir
看看这个类:https://github.com/sgothel/jogl-demos/blob/master/src/jbullet/src/javabullet/demos/opengl/GLShapeDrawer.java。关注drawOpenGL()中使用的CompoundShape(JBullet)的引用。变换存储在javabullet.linearmath.Transform中。 - gouessej
好的,谢谢,我明白了关于存储变换的部分。但是为什么要存储变换呢?每个世界步骤都有一个新的对象世界变换,对吧?最后一个问题是如何将变换应用于我的绘制几何图形(我知道你说这取决于我,但我想找到最快的方法)。例如,如果Bullet给我一个三角形的变换:将y轴平移10个单位。那么我应该将三角形的3个顶点向上平移10个单位,还是有一种更快的函数可以在jogl中将三角形向上平移10个单位。 - Noir
谢谢你的帮助,你是对的,存储变换是正确的方法,而不是直接修改每个顶点。 - Noir
显示剩余2条评论

0

没有研究Bullet或OpenGL的具体细节(我有一点OpenGL编码经验),但似乎您希望将Bullet应用于一个对象两次,一次用于CollisionShape(不管那是什么),一次用于绘制的OpenGL对象。

看起来这只是在内存对象中创建您的OpenGL对象,应用Bullet方法以获取CollisionShape(不管那是什么),将此数据保存在内存中,然后将Bullet方法应用于此新三角形列表以进行世界定位(如果我对您的问题的理解正确的话)。

这类似于在没有矩阵数学的情况下分别对对象应用2个不同的变换。您将根据旋转计算向量的新位置,然后在移动这些点时基于平移在世界中移动它们。您将有一个中间步骤,用于在内存中应用第二个平移。这是我在没有学习如何完成渲染的情况下制作的第一个3D渲染器的方式,以查看我是否可以自己想出来。

也许这会对你有所帮助,也许不会。如果没有帮助,也许你可以解释一下你遇到的问题,我(或其他人)可以研究OpenGL和Bullet的具体算法,为你提供实际的算法(虽然我相信它可能已经存在于某个地方)。如果你搜索足够多,你可能会在互联网上找到类似的代码,可以进行修改,或者你可以尝试自己编写。

我的方法可能行不通,但我认为如果我正确理解了你的问题(我不知道“CollisionShape”是什么),那么没有理由它不会奏效。


碰撞形状是子弹操作的边界对象。 - BDL
感谢您的回答。基本上,Bullet是一个库,它通过创建所谓的碰撞形状将物理应用于3D对象。碰撞形状用于碰撞检测和变换。它将根据物理定律对此碰撞形状应用旋转和平移。问题是我不知道如何使Bullet将这些变换应用于OpenGL中的3D对象(或至少顶点),因为它仅适用于“虚拟”的不可见形状,即绘制的OpenGL形状。虽然可以获取“虚拟”形状中顶点的变换信息。 - Noir
Bullet 不会对 OpenGL 对象应用变换。你需要手动查询并自己应用 OpenGL 变换。 - BDL
抱歉,BDL,你能详细解释一下吗?这是否意味着我必须将从Bullet到每个绘制的Opengl三角网格的单个顶点应用转换? - Noir
1
gouessej 在他的帖子中似乎指出了正确的解决方案。 - Serpardum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接