Reprinted please indicate the source for the klayge game engine, this article address for http://www.klayge.org/2011/07/17/%e8%b7%a8%e8%b6%8aopengl%e5%92%8cd3d%e7%9a%84%e9%b8%bf%e6%b2%9f%ef%bc%88%e4%ba%8c%ef%bc%89%ef%bc%9a%e7%8e%b0%e4%bb%a3opengl/
The previous article raised the basic problem of crossing OpenGL and d3d, and introduced some ways to eliminate the differences between OpenGL and d3d by inputting data without changing the API. This article focuses on how to use the extensions and new features provided by modern OpenGL to eliminate problems that cannot be solved at the upper layer.
Vertex color sequence
The most common vertex color format of d3d9 is bgra (d3dcolor), while OpenGL uses rgba by default. D3d9 uses bgra for purely historical reasons. Early hard parts do not support the ubyte4 format and can only use d3dcolor, and then call d3dcolortoubyte4 In the shader. Currently, all GPUs support ubyte4 and d3d10 + can also directly use rgba, so this is no longer a problem.
If you need to be compatible with the bgra format data that has been generated, modern OpenGL provides the gl_ext_vertex_array_bgra extension, you can also use bgra as the vertex color input format:
Glcolorpointer (gl_bgra, gl_unsigned_byte, stride, pointer );
Glsecondarycolorpointer (gl_bgra, gl_unsigned_byte, stride, pointer );
Glvertexattribpointer (gl_bgra, gl_unsigned_byte, stride, pointer );
This extension enters the core of OpenGL 3.2.
Flat Shading
The chance of using flat shading in rendering is much lower than that of Gouraud shading. Many people only know that flat shading selects the attribute of a vertex as the attribute of each pixel in primitive, but does not notice the difference between d3d and OpenGL in the selection of vertices. D3d uses the attributes of the first vertex of line or triangle. While OpenGL uses the attribute of the last vertex in line, triangle, or quad (but it uses the first attribute in polygon ).
Now, OpenGL has the gl_ext_provoking_vertex extension. You can choose which vertex attribute to drive (which means provoking) a primitive. It is easy to use:
// OpenGL native mode
Glprovokingvertex (gl_last_vertex_convention );
// D3d Mode
Glprovokingvertex (gl_first_vertex_convention );
This extension also enters the core of OpenGL 3.2.
Status Switch
Status switching of d3d9 is completed through functions such as setrenderstate, while OpenGL is completely based on the state machine structure. For example, to set the Model View matrix and ensure that the state is not affected, You need:
Void set_model_view_matrix (glfloat const matrix [16])
{
Glenum saved_mode;
Glgetintegerv (gl_matrix_mode, & saved_mode );
Glmatrixmode (gl_modelview );
Glloadmatrixf (matrix );
Glmatrixmode (saved_mode );
}
If this is not complicated, it is very likely that there is a problem in the 108,000. I believe that everyone who uses OpenGL has ever met, especially when many people work together. Errors in one status may cause disasters.
Now, the savior is here. The appearance of gl_ext_direct_state_access extension (DSA) greatly changed this point. This extension provides the ability to directly access the status. For example, to set the Model View matrix, you only need:
Void set_model_view_matrix (glfloat const matrix [16])
{
Glmatrixloadfext (gl_modelview, matrix );
}
It's much simpler. DSA adds a directly accessed version to the vast majority of OpenGL cores and the status provided by each extension, which is quite convenient. Theoretically, the performance can be improved. Unfortunately, DSA has not yet entered the core of OpenGL, although it can be used on the NV and ATI cards.
Window Origin
The difference in the coordinate system is mentioned in the previous article. Another similar difference occurs in the window orientation. D3d uses the upper left corner as the origin, while OpenGL uses the lower left corner. D3d9 uses the upper left corner of the pixel as the origin, while OpenGL and d3d10 + use the pixel center. This issue requires serious attention when the pixel and texture need to be. For details, see directly mapping texels to pixels.
The result of different window origins is that after the two APIs are used as render to texture, the resulting texture is opposite in the Y direction. This can be adjusted by adjusting the Project Matrix. In short, it is:
Glmatrixloadidentityext (gl_projection );
Glmatrixscalefext (gl_projection, 1,-1, 0); // returns the inverse value in the Y direction.
Glmatrixtranslatefext (gl_projection, 0.5f/win_width, 0.5f/win_height, 0); // if it is adjusted to d3d9, it must be offset by 0.5 pixels.
Because the y direction is reversed, you also need to call glfrontface (gl_cw) to reverse the front direction. Otherwise, the cull will fail. The window origin is solved through the upper-layer code.
However, only the origin of the window can be adjusted. The pixel coordinates under OpenGL are still in the lower left corner as the origin, while pixel coordinates are often used in post process. Therefore, OpenGL provides the gl_arb_fragment_coord_conventions extension to specify the origin and offset of pixel coordinates. Add attributes in the glsl declaration:
// OpenGL native mode
In vec4 gl_fragcoord;
// D3d9 Mode
Layout (origin_upper_left, pixel_center_integer) in vec4 gl_fragcoord;
// D3d10 +
Layout (origin_upper_left) in vec4 gl_fragcoord;
In this way, the pixel coordinates can be adjusted.
To sum up, with the support of modern OpenGL core and extension, we have completed some differences that were originally considered to be at the underlying level without any performance loss. Cracked the rumor 3 mentioned in the previous article. Next, we will analyze the functional similarities and differences between the two APIs and the possibility of direct mutual access.