高效绘制大量三角形的方法(OpenGL)

huangapple 未分类评论48阅读模式
英文:

Efficient Way to Draw Lots of Triangles (OpenGL)

问题

以下是翻译后的内容:

我对OpenGL还有些陌生。我正在尝试使用Java OpenGL和WorldWind Java绘制飞行器的3D动态航迹。我可以使用glDrawArrays来绘制它。由于飞行器的航迹在每一帧(25fps)中增加,我会将新的顶点值放入顶点缓冲区(verticeBuffer)。我还使用rightFloatBuffer和leftFloatBuffer来绘制航迹两侧的GL_LINE_STRIP,就像您在附图一中所见。由于随着飞行器飞行,航迹变得越来越长,我认为我需要为三角形(verticeBuffer)创建一个大的FloatBuffer,以及两个大的FloatBuffer(leftFloatBuffer和rightFloatBuffer)来绘制航迹的左右两侧。

我的第一个问题是:绘制许多三角形最有效的方法是什么?根据我的代码,我认为在飞行5个小时后,FloatBuffers将会填满。如果我尝试在每一帧中使用循环来更新值,并且如果同时有50-75架飞机,这将降低性能。正因为如此,我每帧只更新一个三角形。

第二个问题:我想绘制类似第二张图片中的航迹。如您所见,航迹靠近飞机时变得更透明。当飞机改变颜色时,航迹的底部看起来不同。我该如何实现?

第三个问题:我使用gl.DepthMask(false)绘制line_strip,然后使用gl.DepthMask(true)绘制平滑的线条,线条之间没有间隙。但是这样一来,首先添加到场景中的飞机航迹似乎总是位于顶部,无论它是否在另一个航迹下方。我该怎么办来解决这个问题?或者考虑顶点数量,我该如何绘制平滑的线条而没有间隙?

绘制航迹的代码如下:

private final FloatBuffer verticeBuffer = GLBuffers.newDirectFloatBuffer(3000000);
private final FloatBuffer rightFloatBuffer = GLBuffers.newDirectFloatBuffer(1500000);
private final FloatBuffer leftFloatBuffer = GLBuffers.newDirectFloatBuffer(1500000);

protected void drawTrail() {
   gl.glPushAttrib(GL2.GL_CURRENT_BIT | GL2.GL_COLOR_BUFFER_BIT | GL2.GL_LINE_BIT | GL2.GL_ENABLE_BIT
                | GL2.GL_DEPTH_BUFFER_BIT);
   try {
        gl.glEnable(GL.GL_BLEND);
        gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
        gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);

        doDrawTrail(dc);

        gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
        gl.glDisable(GL.GL_BLEND);
   } finally {
        gl.glPopAttrib();
   }
}

protected void doDrawTrail() {
   updateTrailVertices();

   float[] colors = new float[]{trailColor.getRed() / 255.f, trailColor.getGreen() / 255.f, trailColor.getBlue() / 255.f};
   gl.glColor4f(colors[0], colors[1], colors[2], 0.6f);

   gl.glEnable(GL2.GL_LINE_SMOOTH);
   gl.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST);

   gl.glVertexPointer(3, GL.GL_FLOAT, 0, verticeBuffer.rewind());
   gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, verticeBuffer.limit() / 3);

   gl.glColor3f(colors[0], colors[1], colors[2]);

   gl.glLineWidth(3f);

   // 绘制平滑线条
   gl.glDepthMask(false);

   gl.glVertexPointer(3, GL.GL_FLOAT, 0, rightFloatBuffer.rewind());
   gl.glDrawArrays(GL.GL_LINE_STRIP, 0, rightFloatBuffer.limit() / 3);

   gl.glVertexPointer(3, GL.GL_FLOAT, 0, leftFloatBuffer.rewind());
   gl.glDrawArrays(GL.GL_LINE_STRIP, 0, leftFloatBuffer.limit() / 3);

   gl.glDepthMask(true);
}

protected void updateTrailVertices() {
  // 在每一帧中,当飞机位置发生变化时,此函数会更新最后的顶点
  if (positionChange) {
      positionChange = false;

      // 需要设置缓冲区的位置和限制,以仅绘制已更新的部分
      verticeBuffer.position(lastIndex * 2);

      rightFloatBuffer.position(lastIndex);
      leftFloatBuffer.position(lastIndex);

      verticeBuffer.limit((lastIndex * 2) + 6);

      rightFloatBuffer.limit(lastIndex + 3);
      leftFloatBuffer.limit(lastIndex + 3);

      List<Vec4> pointEdges = computeVec4(this.currentPosition, this.currentHeading, this.currentRoll, this.span);

      verticeBuffer.put((float) pointEdges.get(0).x).put((float) pointEdges.get(0).y).put((float) pointEdges.get(0).z);
      verticeBuffer.put((float) pointEdges.get(1).x).put((float) pointEdges.get(1).y).put((float) pointEdges.get(1).z);

      rightFloatBuffer.put((float) pointEdges.get(0).x).put((float) pointEdges.get(0).y).put((float) pointEdges.get(0).z);
      leftFloatBuffer.put((float) pointEdges.get(1).x).put((float) pointEdges.get(1).y).put((float) pointEdges.get(1).z);

      lastIndex = rightFloatBuffer.position();
   }
}

如果您还有其他问题或需要进一步帮助,请随时问我。

英文:

I am a little bit new to OpenGL. I am trying to draw 3D dynamic trail for aircraft using Java OpenGL and WorldWind Java I can draw it by using glDrawArrays. Since the trail of the aircraft increases in every frame(25fps) I put new vertice values to verticeBuffer. I also use rightFloatBuffer and leftFloatBuffer to draw GL_LINE_STRIP to the both sides of the trail as you may see in the attached firstpicture. Since the trail gets longer and longer as the aircraft flies I thought that I need to create a large FloatBuffer for the triangles (verticeBuffer) and 2 large FloatBuffers for the left and right lines.

My first question: What is the most efficient way to draw to many triangles? Based on my code I think after 5 hours of flight the FloatBuffers will be full. If I try to update values with for loop in each frame and if I have, say 50-75 aircraft at the same time, this will reduce the performance. And because of that, I update one triangle at each frame.

Second question: I want to draw a trail like in the second picture. As you see trail gets more transparent as it gets closer to aircraft. And when the aircraft turns color the bottom side of the trail seems different. How can I do it?

Third question: I use gl.DepthMask(false) and draw line_strip and gl.DepthMask(true) to draw smooth lines without a gap between the lines. But this time aircraft trail which is added to the scene first always seems on the top no matter if it is under another trail. What can I do to overcome this? Or what can I do to draw smooth lines without gaps considering the amount of the vertices?

My code to draw the trail is below:


private final FloatBuffer verticeBuffer = GLBuffers.newDirectFloatBuffer(3000000);
private final FloatBuffer rightFloatBuffer = GLBuffers.newDirectFloatBuffer(1500000);
private final FloatBuffer leftFloatBuffer = GLBuffers.newDirectFloatBuffer(1500000);

protected void drawTrail() {

   gl.glPushAttrib(GL2.GL_CURRENT_BIT | GL2.GL_COLOR_BUFFER_BIT | GL2.GL_LINE_BIT | GL2.GL_ENABLE_BIT
                | GL2.GL_DEPTH_BUFFER_BIT);
   try {
        gl.glEnable(GL.GL_BLEND);
        gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
        gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);

        doDrawTrail(dc);

        gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
        gl.glDisable(GL.GL_BLEND);
   } finally {
        gl.glPopAttrib();
   }
}

protected void doDrawTrail() {

   updateTrailVertices();

   float[] colors = new float[]{trailColor.getRed() / 255.f, trailColor.getGreen() / 255.f, trailColor.getBlue() / 255.f};
   gl.glColor4f(colors[0], colors[1], colors[2], 0.6f);

   gl.glEnable(GL2.GL_LINE_SMOOTH);
   gl.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST);

   gl.glVertexPointer(3, GL.GL_FLOAT, 0, verticeBuffer.rewind());
   gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, verticeBuffer.limit() / 3);

   gl.glColor3f(colors[0], colors[1], colors[2]);

   gl.glLineWidth(3f);

   //To draw smooth lines
   gl.glDepthMask(false);

   gl.glVertexPointer(3, GL.GL_FLOAT, 0, rightFloatBuffer.rewind());
   gl.glDrawArrays(GL.GL_LINE_STRIP, 0, rightFloatBuffer.limit() / 3);

   gl.glVertexPointer(3, GL.GL_FLOAT, 0, leftFloatBuffer.rewind());
   gl.glDrawArrays(GL.GL_LINE_STRIP, 0, leftFloatBuffer.limit() / 3);

   gl.glDepthMask(true);

}

protected void updateTrailVertices() {
     
     // In each frame when the aircraft position changes this function updates the last vertices
  if (positionChange) {

      positionChange = false;

      //I need to set the position and the limit of the buffers to draw only updated parts
      verticeBuffer.position(lastIndex * 2);

      rightFloatBuffer.position(lastIndex);
      leftFloatBuffer.position(lastIndex);

      verticeBuffer.limit((lastIndex * 2) + 6);

      rightFloatBuffer.limit(lastIndex + 3);
      leftFloatBuffer.limit(lastIndex + 3);

      List&lt;Vec4&gt; pointEdges = computeVec4(this.currentPosition, this.currentHeading, this.currentRoll, this.span);

      verticeBuffer.put((float) pointEdges.get(0).x).put((float) pointEdges.get(0).y).put((float) pointEdges.get(0).z);
      verticeBuffer.put((float) pointEdges.get(1).x).put((float) pointEdges.get(1).y).put((float) pointEdges.get(1).z);

      rightFloatBuffer.put((float) pointEdges.get(0).x).put((float) pointEdges.get(0).y).put((float) pointEdges.get(0).z);
      leftFloatBuffer.put((float) pointEdges.get(1).x).put((float) pointEdges.get(1).y).put((float) pointEdges.get(1).z);

      lastIndex = rightFloatBuffer.position();

   }
}

高效绘制大量三角形的方法(OpenGL)

高效绘制大量三角形的方法(OpenGL)

答案1

得分: 0

如果您可以使用几何着色器,显示飞行轨迹的最有效方法是拥有一个顶点缓冲区,并将其呈现为线条带。顶点缓冲区包含了之前的位置和法线向量(飞机的上方方向)。利用这两个值,您可以在几何着色器中将其转换为四边形。这些四边形应该包含纹理坐标,这些坐标可以在片段着色器中用于显示边界。

您只需要一个绘制调用,并将存储在GPU上的数据减少到绝对最小。

飞行轨迹的淡化可以通过使用与飞机坐标相关的统一变量来实现。您的一种着色器可以计算到飞机的距离,并由此为像素计算一个alpha值。

英文:

If you can use geometry shaders, the most efficient way to display the flight track is to have one vertexbuffer and render it as a line strip. The vertexbuffer contains the earlier locations and a normal vector (plane up direction). With these two values the the geometry shader you can transform it into quads. These quads should contain texture coordinates, which can be used in the fragment shader to display the borders.

You need only one draw call and reduce the data stored on the gpu to the absolute minimum.

The fading of the flight track can be done by using a uniform with the plane coordinates. One of your shades can calculate the distance to the plane and with that a alpha value for the pixel.

huangapple
  • 本文由 发表于 2020年5月5日 14:26:55
  • 转载请务必保留本文链接:https://java.coder-hub.com/61607004.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定