Эффективный способ рисования множества треугольников (OpenGL) - PullRequest
0 голосов
/ 05 мая 2020

Я немного новичок в OpenGL. Я пытаюсь нарисовать 3D динамический след c для самолета, используя Java OpenGL и WorldWind Java. Я могу нарисовать его с помощью glDrawArrays. Поскольку след самолета увеличивается с каждым кадром (25 кадров в секунду), я помещаю новые значения вершин в verticeBuffer. Я также использую rightFloatBuffer и leftFloatBuffer, чтобы нарисовать GL_LINE_STRIP по обеим сторонам следа, как вы можете видеть на прикрепленном первом изображении. Поскольку по мере полета самолет становится все длиннее и длиннее, я подумал, что мне нужно создать большой буфер FloatBuffer для треугольников (verticeBuffer) и 2 больших буфера FloatBuffer для левой и правой линий.

Мой первый вопрос: что такое самый эффективный способ нарисовать множество треугольников? Исходя из моего кода, я думаю, что через 5 часов полета FloatBuffers будет заполнен. Если я попытаюсь обновить значения с l oop в каждом кадре, и если у меня будет, скажем, 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);

   //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

1 Ответ

0 голосов
/ 05 мая 2020

Если вы можете использовать геометрические шейдеры, наиболее эффективным способом отображения трека полета является наличие одного вершинного буфера и визуализация его как линейной полосы. Вершинный буфер содержит более ранние местоположения и вектор нормали (направление плоскости вверх). С этими двумя значениями геометрического шейдера вы можете преобразовать его в квадраты. Эти квадраты должны содержать координаты текстуры, которые можно использовать во фрагментном шейдере для отображения границ. * Угасание траектории полета может быть выполнено с помощью униформы с координатами плоскости. Один из ваших оттенков может рассчитать расстояние до плоскости и, таким образом, альфа-значение для пикселя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...