使用 OpenGL (JOGL) 的良好 3D 爆炸和粒子效果?

Posted

技术标签:

【中文标题】使用 OpenGL (JOGL) 的良好 3D 爆炸和粒子效果?【英文标题】:good 3D explosion & particles effect using OpenGL (JOGL)? 【发布时间】:2012-09-08 22:27:46 【问题描述】:

我想写它已经有一段时间了……作为大学的一个项目,我(和朋友)写了一个需要良好爆炸和粒子效果的游戏。我们遇到了一些问题,我们很优雅地解决了(我认为),我想分享知识。

好吧,所以我们找到了这个教程:Make a Particle Explosion Effect,它似乎很容易使用 Java 和 JOGL 来实现。在我回答我们是如何实现本教程之前,我将解释渲染是如何完成的:

Camera:只是一个orthonormal basis,这基本上意味着它包含 3 个归一化正交向量和一个表示摄像机位置的第 4 个向量。渲染使用gluLookAt:

glu.gluLookAt(cam.getPosition().getX(), cam.getPosition().getY(), cam.getPosition().getZ(), 
              cam.getZ_Vector().getX(), cam.getZ_Vector().getY(), cam.getZ_Vector().getZ(), 
              cam.getY_Vector().getX(), cam.getY_Vector().getY(), cam.getY_Vector().getZ());

这样相机的z 向量实际上是目标,y 向量是“向上”向量,而位置是,嗯……位置。

那么(如果放到疑问句式中),如何实现好的粒子效果?

P.S:所有代码示例和游戏截图(包括答案​​和问题)均取自游戏,游戏托管在此处:Astroid Shooter

【问题讨论】:

应该把它变成一个社区维基吗? @DownVoters - 如果您能解释为什么投反对票,将不胜感激...... 您很可能会被否决,因为您似乎在有用的问题和广告垃圾邮件之间走得很细,而社区通常对此表示不满。很高兴您决定为此编写一个有用的解决方案,但通常我们不希望每个帖子都以 " 结尾...您可以在我的 ios 应用商店的新应用中看到这个快速排序实现!" @Tim 谢谢,虽然我不认为这是垃圾邮件。我一直在努力研究这个问题,并且研究了很长时间。在这里找不到解决方案,也找不到其他任何地方。我的想法是,恕我直言,一个特殊的解决方案就像顿悟一样降临到我身上,我想分享它。我相信这个想法是独特的、有用的和原创的。这篇文章来自于回馈这个美好社区的愿望,我在过去遇到的问题上得到了很多有用的解决方案。而且绝对不是垃圾邮件... 【参考方案1】:

好吧,让我们看看我们如何首先处理粒子的实现:我们有一个抽象类Sprite,它代表一个粒子:

protected void draw(GLAutoDrawable gLDrawable) 
    // each sprite has a different blending function.
    changeBlendingFunc(gLDrawable);

    // getting the quad as an array of length 4, containing vectors
    Vector[] bb = getQuadBillboard();
    GL gl = gLDrawable.getGL();

    // getting the texture
    getTexture().bind();

    // getting the colors
    float[] rgba = getRGBA();
    gl.glColor4f(rgba[0],rgba[1],rgba[2],rgba[3]);

    //draw the sprite on the computed quad
    gl.glBegin(GL.GL_QUADS);
    gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3d(bb[0].x, bb[0].y, bb[0].z);
    gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3d(bb[1].x, bb[1].y, bb[1].z);
    gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3d(bb[2].x, bb[2].y, bb[2].z);
    gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3d(bb[3].x, bb[3].y, bb[3].z);
    gl.glEnd();

我们这里的大多数方法调用都很容易理解,这并不奇怪。渲染非常简单。在display 方法中,我们首先绘制所有不透明对象,然后,我们获取所有Sprites 并对它们进行排序(与相机的平方距离),然后绘制粒子,这样首先绘制离相机较远的位置。但我们必须在这里深入研究的是方法getQuadBillboard。我们可以理解,每个粒子都必须“坐在”垂直于相机位置的平面上,如下所示: 像这样计算垂直平面的方法并不难:

    substruct粒子位置从相机位置得到一个垂直于平面的向量,并对其进行归一化,因此它可以用作平面的法线。现在一个平面由一个法线和位置紧密定义,我们现在有(粒子位置是平面经过的点)

    通过标准化相机的Y 向量在平面上的投影来计算四边形的“高度”。可以通过计算得到投影向量:H = cam.Y - normal * (cam.Y dot normal)

    通过计算W = H cross normal创建四边形的“宽度”

    返回 4 个点/向量:position+H+W,position+H-W,position-H-W,position-H+W

但不是所有的精灵都这样,有些不是垂直的。例如,冲击波环精灵,或飞溅的火花/烟雾轨迹: 所以每个精灵都必须给它自己独特的“广告牌”。顺便说一句,烟雾轨迹和飞行精灵火花的计算也是一个挑战。我们创建了另一个抽象类,我们称之为:LineSprite。我将跳过这里的解释,您可以在这里查看代码:LineSprite

嗯,第一次尝试很好,但是出现了一个意想不到的问题。这是说明问题的屏幕截图: 如您所见,精灵彼此相交,所以如果我们看两个相交的精灵,第一个精灵的一部分在第二个精灵的后面,另一部分在第二个精灵的前面,这导致了一些奇怪的现象渲染,交点的线是可见的。请注意,即使我们禁用了glDepthMask,在渲染粒子时,结果仍然会看到相交线,因为每个精灵中发生了不同的混合。所以我们必须以某种方式使精灵不相交。我们的想法真的很酷。

你知道所有这些真的很酷3D street art吗? 这是一张强调这个想法的图片:

我们认为这个想法可以在我们的游戏中实现,所以精灵不会相互交叉。这是一张图片来说明这个想法:

基本上,我们使所有精灵都在平行平面上,因此不会发生交叉。并且它没有影响可见数据,因为它保持不变。从其他角度看,它会显得有些拉长,但从相机的角度来看,它仍然看起来很棒。所以对于实施:

当得到代表一个四边形广告牌的4个向量,以及粒子的位置时,我们需要输出一组新的4个向量,代表原来的四边形广告牌。如何做到这一点的想法在这里得到了很好的解释:Intersection of a plane and a line。我们有由相机位置和 4 个向量中的每一个定义的“线”。我们有飞机,因为我们可以使用我们的相机Z 向量作为法线,以及粒子的位置。此外,用于对精灵进行排序的比较函数会有一个小的变化。它现在应该使用由我们的相机正交基定义的齐次矩阵,实际上,计算就像计算一样简单:cam.getZ_Vector().getX()*pos.getX() + cam.getZ_Vector().getY()*pos.getY() + cam.getZ_Vector().getZ()*pos.getZ();。我们应该注意的另一件事是,如果一个粒子超出了相机的视角,即在相机后面,我们不想看到它,尤其是,我们不想计算它的投影(可以导致一些非常奇怪和迷幻的效果......)。 剩下的就是展示最终的Sprite class

结果非常好:

希望它有所帮助,希望您的 cmets 在这篇“文章”(或游戏 : 上,您可以随意探索、分叉和使用...)

【讨论】:

你获取广告牌基向量的方法太复杂了。只需利用模型视图矩阵的左上部分包含视图旋转的事实,纯旋转矩阵是正交的,这意味着转置是逆矩阵。因此,广告牌的基向量只是模型视图矩阵前 3 行的前 3 个元素。 您能否详细说明它是如何完成的?我不确定你指的是什么矩阵......

以上是关于使用 OpenGL (JOGL) 的良好 3D 爆炸和粒子效果?的主要内容,如果未能解决你的问题,请参考以下文章

您可以使用 JOGL 创建 3D 组件吗?

在 jogl 中使用顶点缓冲区,当三角形太多时崩溃

Qt Jambi vs JOGL 用于 java OpenGL 开发?

JOGL/OpenGL VBO - 如何渲染顶点?

Jogl:如何在 com.jogamp.opengl.swt.GLCanvas 上制作透明背景?

全网首发:j3d/jogl多个崩溃分析总结