Nebi Sarikaya
Nebi Sarikaya

Reputation: 67

Efficient Way to Draw Lots of Triangles (OpenGL)

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<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();

   }
}

First Picture

Second Picture

Upvotes: 1

Views: 804

Answers (1)

OutOfBound
OutOfBound

Reputation: 2004

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.

Upvotes: 0

Related Questions