Dev:2.8/Source/OpenGL/Geometry

提供: wiki
< Dev:2.8/Source‎ | OpenGL
2018年6月29日 (金) 06:15時点におけるYamyam (トーク | 投稿記録)による版 (1版 をインポートしました)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
移動先: 案内検索

OpenGL Refactoring: Geometry

Overview

glBegin / glVertex / glEnd is deprecated in GL 3 and totally removed from the core profile. Instead we must store vertex attributes in vertex buffer objects (VBOs) and draw them with glDrawArrays / glDrawElements. Most of the mesh drawing API already supports VBOs, though there are still a few things that need to be switched over.

For UI drawing we also use immediate mode everywhere, what the API for that will look like is unclear still. One option would be to write an API that reimplements a subset of immediate mode on top of VBOs, but this will not give ideal performance.

Common shapes like the various button types, 3D view manipulators or armature bones could be created once as vertex arrays objects (VAOs) and cached for reuse.

Dupli object drawing used display lists for fast repeated drawing of objects, but now draws them one at a time. Instanced drawing became a core feature in GL 3.1 so we should use that instead.

Immediate Mode In Depth

When we say "immediate mode" we are referring to the old-style OpenGL geometry submission method using the glBegin / glVertex / glEnd family of functions. To draw a single 2D point you would write this:

glBegin(GL_POINTS);
  glVertex2f(x, y);
glEnd();

And to draw a 3D triangle with red, green and blue corners:

glBegin(GL_TRIANGLES);
  glColor3ub(255, 0, 0);
  glVertex3f(x1, y1, z1);
  glColor3ub(0, 255, 0);
  glVertex3f(x2, y2, z2);
  glColor3ub(0, 0, 255);
  glVertex3f(x3, y3, z3);
glEnd();

This is easy to learn and allows you to quickly prototype drawing of simple shapes. So naturally, the OpenGL gods have removed it :) For very good reasons actually.

Not-So-Obvious Points

  • Each glBegin/End pair is technically a single "draw call", similar to glDrawArrays. Immediate mode uses more function calls but not necessarily more GPU time.
  • glVertex has a dual purpose: it provides vertex position values and finalizes the current vertex. The functions for all other vertex attributes (glColor, glNormal, etc.) just provide values.
  • OpenGL keeps track of "current" values for various attributes. So if you don't specify a vertex's color it will use the current color. This isn't a default value, simply the most recent color used.
  • Because of the previous point, if you call glColor 100 times followed by glVertex, only the most recent color will be used.
  • Current attribute values are stored as vec4 data (4 32-bit floating-point numbers). Whatever format you provide is converted to vec4 by the GL implementation.
  • You are free to submit 50 vertices with color + position, then the 51st with color + normal + position. Also you can mix 2D and 3D vertex positions. This is all legal and well defined in the spec. Handling such crazy amount of flexibility adds complexity to the GL implementation.
  • Since you don't specify how many vertices or primitives up front, OpenGL must be ready for any amount of data. This is another example of programmer convenience vs. driver complexity.

Design

Immediate Mode Replacement

Some drawing can easily be converted to raw VBO / DrawArrays style code. Other drawing might actually benefit from an immediate mode style. When converting code, take a moment to consider whether changing style actually improves clarity and performance.

Designing and using an immediate-like API is an option as mentioned in the overview. I (merwin) have some ideas and prototype code for this, and will share soon so we can hammer out the details. Any replacement should address the sticky points listed above. We might add some inconveniences that make implementation simpler or faster, such as needing to pre-specify how many triangles you're going to draw. Definitely will need to specify your attribute types and sizes.

Update: this all works! And we are nearly done converting. See Phab task and Immediate Mode Replacement call for help.

Array Drawing

For now use GL's standard VBO and VAO mechanisms to specify data, DrawArrays or DrawElements to draw primitives. For forward-looking work (anything for Blender 2.8) use generic vertex attributes only. We might introduce an internal API to make all this easier to get correct and fast.