| Name |
| |
| ARB_clip_control |
| |
| Name Strings |
| |
| GL_ARB_clip_control |
| |
| Contact |
| |
| Mark J. Kilgard, NVIDIA Corporation (mjk 'at' nvidia.com) |
| |
| Contributors |
| |
| Timo Suoranta, Broadcom |
| Piers Daniell, NVIDIA |
| Stefan Dösinger, CodeWeavers |
| Jeff Bolz, NVIDIA |
| John McDonald, NVIDIA |
| Brian Paul, VMware, Mesa3D |
| Jason Mitchell, Valve |
| Alex Corscadden, VMware |
| Simon Bennett, VMware |
| Mark Callow, HI Corporation |
| Patrick Doane, Blizzard |
| Pat Brown, NVIDIA |
| Brano Kemen |
| |
| Notice |
| |
| Copyright (c) 2014 The Khronos Group Inc. Copyright terms at |
| http://www.khronos.org/registry/speccopyright.html |
| |
| Specification Update Policy |
| |
| Khronos-approved extension specifications are updated in response to |
| issues and bugs prioritized by the Khronos OpenGL Working Group. For |
| extensions which have been promoted to a core Specification, fixes will |
| first appear in the latest version of that core Specification, and will |
| eventually be backported to the extension document. This policy is |
| described in more detail at |
| https://www.khronos.org/registry/OpenGL/docs/update_policy.php |
| |
| Status |
| |
| Complete. |
| Approved by the ARB on June 26, 2014. |
| Ratified by the Khronos Board of Promoters on August 7, 2014. |
| |
| Version |
| |
| Last Modified Date: 2018/04/06 |
| NVIDIA Revision: 19 |
| |
| Number |
| |
| ARB Extension #160 |
| |
| Dependencies |
| |
| Written based on the wording of the OpenGL 4.4 (Compatibility Profile) |
| specification. |
| |
| Overview |
| |
| This extension provides additional clip control modes to configure how |
| clip space is mapped to window space. This extension's goal is to 1) |
| allow OpenGL to effectively match Direct3D's coordinate system |
| conventions, and 2) potentially improve the numerical precision of the Z |
| coordinate mapping. |
| |
| Developers interested in this functionality may be porting content |
| from Direct3D to OpenGL and/or interested in improving the numerical |
| accuracy of depth testing, particularly with floating-point depth |
| buffers. |
| |
| OpenGL's initial and conventional clip control state is configured by: |
| |
| glClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); |
| |
| where geometry with (x,y) normalized device coordinates of (-1,-1) |
| correspond to the lower-left corner of the viewport and the near and far |
| planes correspond to z normalized device coordinates of -1 and +1, |
| respectively. |
| |
| This extension can be used to render content used in a Direct3D |
| application in OpenGL in a straightforward way without modifying vertex or |
| matrix data. When rendering into a window, the command |
| |
| glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); |
| |
| configures the near clip plane to correspond to a z normalized device |
| coordinate of 0 as in Direct3D. Geometry with (x,y) normalized device |
| coordinates of (-1,-1) correspond to the lower-left corner of the viewport |
| in Direct3D, so no change relative to OpenGL conventions is needed there. |
| Other state related to screen-space coordinates may need to be modified |
| for the application to map from Direct3D to OpenGL window coordinate |
| conventions. For example, the viewport rectangle in Direct3D needs to be |
| inverted within the window to work properly in OpenGL windowed rendering: |
| |
| glViewport(d3d_viewport_x, |
| window_height - (d3d_viewport_y + d3d_viewport_height), |
| d3d_viewport_width, d3d_viewport_height); |
| |
| When rendering Direct3D content into a framebuffer object in OpenGL, there |
| is one complication -- how to get a correct image *out* of the related |
| textures. Direct3D applications would expect a texture coordinate of |
| (0,0) to correspond to the upper-left corner of a rendered image, while |
| OpenGL FBO conventions would map (0,0) to the lower-left corner of the |
| rendered image. For applications wishing to use Direct3D content with |
| unmodified texture coordinates, the command |
| |
| glClipControl(GL_UPPER_LEFT, GL_ZERO_TO_ONE); |
| |
| configures the OpenGL to invert geometry vertically inside the viewport. |
| Content at the top of the viewport for Direct3D will be rendered to the |
| bottom of the viewport from the point of view of OpenGL, but will have a |
| <t> texture coordinate of zero in both cases. When operating in this |
| mode, applications need not invert the programmed viewport rectangle as |
| recommended for windowed rendering above. |
| |
| Applications happy with OpenGL's origin conventions but seeking |
| potentially improved depth precision can configure clip controls using: |
| |
| glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); |
| |
| to avoid the loss of precision from the DepthRange transformation |
| (which by default is z_window = z_ndc * 0.5 + 0.5). |
| |
| New Procedures and Functions |
| |
| void ClipControl(enum origin, enum depth); |
| |
| New Tokens |
| |
| Accepted by the <origin> parameter of ClipControl: |
| |
| LOWER_LEFT 0x8CA1 |
| UPPER_LEFT 0x8CA2 |
| |
| Accepted by the <depth> parameter of ClipControl: |
| |
| NEGATIVE_ONE_TO_ONE 0x935E |
| ZERO_TO_ONE 0x935F |
| |
| Accepted by the <pname> parameter of GetBooleanv, GetIntegerv, |
| GetFloatv, and GetDoublev: |
| |
| CLIP_ORIGIN 0x935C |
| CLIP_DEPTH_MODE 0x935D |
| |
| Additions to Chapter 13 of the OpenGL 4.4 (Compatibility Profile) |
| Specification (Fixed-Function Vertex Post-Processing) |
| |
| -- Modify section 13.5 "Primitive Clipping" |
| |
| Insert before the 1st paragraph... |
| |
| "The command |
| |
| ClipControl(enum origin, enum depth); |
| |
| controls the clipping volume behavior. /origin/ must be either |
| LOWER_LEFT or UPPER_LEFT, otherwise the error INVALID_ENUM is |
| generated. /depth/ must be either NEGATIVE_ONE_TO_ONE or |
| ZERO_TO_ONE, otherwise the error INVALID_ENUM is generated. |
| |
| These parameters update the clip control origin and |
| depth mode respectively. The state required for clip control is one |
| bit for clip control origin and one bit for clip control depth mode. |
| The initial value of the clip control origin is LOWER_LEFT and the |
| initial value of the depth mode is NEGATIVE_ONE_TO_ONE. |
| |
| The error INVALID_OPERATION is generated if ClipControl is |
| executed between the execution of Begin and the corresponding |
| execution of End." |
| |
| Replace the first paragraph with... |
| |
| "Primitives are clipped to the clip volume. In clip coordinates, |
| the view volume is defined by |
| |
| -w_c <= x_c <= w_c |
| -w_c <= y_c <= w_c |
| zm <= z_c <= w_c |
| |
| where zm is -w_c when the clip control depth mode is |
| NEGATIVE_ONE_TO_ONE or zero when the mode is ZERO_TO_ONE." |
| |
| Change the last sentence of the 7th paragraph to read... |
| |
| "If depth clamping is enabled, the |
| |
| zm <= z_c <= w_c |
| |
| plane equation (see the clip volume definition) is ignored by |
| view volume clipping (effectively, there is no near or far plane |
| clipping)." |
| |
| -- Modify section 13.6 "Coordinate Transformations" |
| |
| Replace the 3rd paragraph with (where ^T means transpose): |
| |
| "If a vertex in clip coordinates is given by (x_c y_c z_c w_c)^T |
| then the vertex's normalized device coordinates are (x_d y_d z_d)^T = |
| (x_c/w_c f*y_c/w_c z_c/w_c)^T where /f/ is +1 when the clip control |
| origin is LOWER_LEFT and -1 when the origin is UPPER_LEFT." |
| |
| -- Modify section 13.6.1 "Controlling the Viewport" |
| |
| Replace the 2nd sentence of the 1st paragraph with (where ^T means |
| transpose): |
| |
| "The vertex's window coordinates, (x_w y_w z_w)^T are given by: |
| |
| ( x_w ) ( p_x/2 x_d + o_x ) |
| ( y_w ) = ( p_y/2 y_d + o_y ) |
| ( z_w ) ( s z_d + b ) |
| |
| where s is (f-n)/2 and b is (n+f)/2 when the clip control depth mode |
| is NEGATIVE_ONE_TO_ONE; or s is (f-n) and b is n when the mode |
| is ZERO_TO_ONE." |
| |
| Additions to Chapter 14 of the OpenGL 4.4 (Compatibility Profile) |
| Specification (Fixed-Function Primitive Assembly and Rasterization) |
| |
| -- Modify section 14.6.1 "Basic Polygon Rasterization" |
| |
| Replace the 3rd sentence of the 1st paragraph with: |
| |
| "One way to compute this area is |
| |
| n-1 |
| ___ |
| \ |
| a = 1/2 f \ x^i_w * y^i(+)1_w - x^i(+)1_w * y^i_w |
| / |
| /__ |
| |
| where f is +1 when the clip control origin is LOWER_LEFT and -1 when |
| the origin is UPPER_LEFT, x^i_w and y^i_w are the x and y window |
| coordinates of the ith vertex of the n-vertex polygon (vertices |
| are numbered starting at zero for purposes of this computation), |
| and i(+)1 is (i+1) mod n." |
| |
| Additions to the AGL/GLX/WGL Specifications |
| |
| None |
| |
| GLX Protocol |
| |
| A new GL rendering command is added. The following command is sent to the |
| server as part of a glXRender request: |
| |
| ClipControl |
| 2 12 rendering command length |
| 2 1340 rendering command opcode |
| 4 ENUM origin |
| 4 ENUM depth |
| |
| Errors |
| |
| The error INVALID_ENUM is generated by ClipControl if origin is not |
| LOWER_LEFT or UPPER_LEFT. |
| |
| The error INVALID_ENUM is generated by ClipControl if depth is not |
| NEGATIVE_ONE_TO_ONE or ZERO_TO_ONE. |
| |
| The error INVALID_OPERATION is generated if ClipControl is executed |
| between the execution of Begin and the corresponding execution of |
| End. |
| |
| New State |
| |
| Get Value Type Get Command Initial Value Description Sec Attribute |
| ---------------- ---- ----------- ------------------- --------------- ---- --------- |
| CLIP_ORIGIN Z2 GetIntegerv LOWER_LEFT Clip origin 13.5 xform |
| CLIP_DEPTH_MODE Z2 GetIntegerv NEGATIVE_ONE_TO_ONE Clip depth mode 13.5 xform |
| |
| New Implementation Dependent State |
| |
| None |
| |
| Issues |
| |
| 1) What should this extension be called? |
| |
| RESOLVED: ARB_clip_control |
| |
| We frame this extension in terms of how the fixed-function |
| transformation from clip coordinates to window coordinates |
| is specified. The crucial modifications to OpenGL's existing |
| behavior involve controlling how clip space is interpreted. |
| |
| An upper-left origin is really simply negating (flipping) the |
| clip space Y coordinate. Subsequently the sense of counter-clockwise |
| and clockwise for face culling must be adjusted (flipped). |
| |
| A zero-to-one Z mode involves adjusting the clipping equation |
| for the clip space Z coordinate. Subsequently the depth range |
| transform equation must be adjusted (scaled and biased). |
| |
| Hence clip control is a sensible name. |
| |
| 2) Should this functionality be exposed with glEnable/glDisable or |
| with a new command. |
| |
| RESOLVED: With a new command, glClipControl. |
| |
| We note that this extension does not actually enable or disable |
| functionality, but rather modifies an existing transformation. |
| |
| We note that Direct3D is different in two ways: clip Y inversion |
| and zero-to-one clip Z. |
| |
| We note the difficulty of a clear enable name. |
| GL_NEGATIVE_ONE_TO_ONE and GL_ZERO_TO_ONE |
| are very explicit about how the Z clip coordinate is treated by |
| the clip equations. Likewise, GL_LOWER_LEFT and GL_UPPER_LEFT |
| are explicit (and match the token names and meaning for the |
| point sprite functionality). |
| |
| We also note the possibility for other possible conventions. |
| For example, an origin at the center of the window. Hence an |
| enumeration of clip modes is a better choice. Likewise, a future |
| Z mode could expose W-buffering. |
| |
| 3) Why does unextended OpenGL have symmetric clip equations? |
| |
| RESOLVED: This is a legacy of implementation worthy of some |
| explanation... |
| |
| Handling the X, Y, and Z directions the same way better |
| facilitates vector operation for hardware efficiency. |
| |
| When transformations are done with 32-bit IEEE-754 floating-point |
| values, after transformation to clip space for clipping, the |
| Z values are typically converted to fixed-point for use by a |
| conventional 24-bit fixed-point depth buffer. |
| |
| The process of scaling by 0.5 and adding 0.5 to a 32-bit |
| floating-point number in the range [-1,+1] has the effect of |
| appropriately rounding the value so it can be efficiently |
| bit-shifted into a 24-bit fixed-point value in the [0,1] |
| range suitable for depth buffering via linear fixed-point |
| interpolation. |
| |
| 4) Should the face culling behavior be modified in GL_UPPER_LEFT |
| clip origin mode? |
| |
| RESOLVED: Yes. |
| |
| See how the modifications to section 14.6.1 "Basic Polygon |
| Rasterization" negate the sign of the polygon area when the clip |
| control origin is GL_UPPER_LEFT. |
| |
| Since culling behavior is specified as CW (clockwise) or CCW |
| (counter-clockwise) different triangle faces would be culled |
| when the clip origin is changed, which would be an unacceptable |
| side effect. |
| |
| 5) Are the projective matrices generated by glFrustum and glOrtho |
| appropriate when the clip Z mode is GL_ZERO_TO_ONE? |
| |
| RESOLVED: No. |
| |
| 6) Should the behavior of glFrustum and glOrtho change? |
| |
| RESOLVED: No. |
| |
| It's not worth encumbering these routines with adjustments, |
| plus it is easy to make the proper adjustments... |
| |
| Taking advantage of how matrix changes concatenate... |
| |
| If your clip control origin is GL_UPPER_LEFT, prior to your |
| glFrustum or glOrtho command by: |
| |
| glScalef(1,-1,1); |
| |
| If your clip control depth mode is GL_ZERO_TO_ONE, precede |
| your glFrustum or glOrtho command by: |
| |
| glTranslatef(0,0,0.5); |
| glScalef(1,1,0.5); |
| |
| For example, if your code to configure the projection matrix |
| reads: |
| |
| glMatrixMode(GL_PROJECTION); |
| glLoadIdentity(); |
| glFrustum(-0.5, 0.5, -0.5, 0.5, 1, 3); |
| |
| And you wanted to call: |
| |
| glClipControl(GL_UPPER_LEFT, GL_ZERO_TO_ONE); |
| |
| Then configure your projection matrix as |
| |
| glMatrixMode(GL_PROJECTION); |
| glLoadIdentity(); |
| // adjust for GL_UPPER_LEFT |
| glScalef(1,-1,1); |
| // adjust for GL_ZERO_TO_ONE |
| glTranslatef(0,0,0.5); |
| glScalef(1,1,0.5); |
| glFrustum(-0.5, 0.5, -0.5, 0.5, 1, 3); |
| |
| Technically, the two glScalef could be combined as |
| glScalef(1,-1,0.5); |
| |
| 7) Has this topic been discussed elsewhere? |
| |
| RESOLVED: Yes, see: |
| |
| "Maximizing Depth Buffer Range and Precision" |
| Brano Kemen |
| http://outerra.blogspot.co.uk/2012/11/maximizing-depth-buffer-range-and.html |
| November 28, 2012 |
| |
| "Minimum Triangle Separation for Correct Z-Buffer" |
| Kurt Akeley and Jonathan Su |
| http://research.microsoft.com/apps/pubs/default.aspx?id=79213 |
| August 2006 |
| |
| "Tightening the Precision of Perspective Rendering" |
| Paul Upchurch and Mathieu Desbrun |
| http://www.geometry.caltech.edu/pubs/UD12.pdf |
| Journal of Graphics Tools, Volume 16, Issue 1, 2012. |
| |
| 8) How does this extension interact with the unclamped depth range |
| parameters of NV_depth_buffer_float's glDepthRangedNV and OpenGL |
| 4.3? |
| |
| RESOLVED: Simply apply the equations as specified. |
| |
| The implications of this are explored... |
| |
| An unclamped depth range applies to floating-point depth buffers. |
| |
| (For a conventional [0,1] fixed-point depth buffer, the depth |
| range is clamped to "the range appropriate to the depth buffer's |
| representation." In practice, this means that unclamped depth |
| values are clamped to the [0,1] range when used with a |
| conventional depth buffer so are effectively still clamped.) |
| |
| If an application were to mix the two like this: |
| |
| glDepthRangedNV(-1,1); |
| glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); |
| |
| this would lead to generating interpolated depth values in a |
| [-1,+1] range. Because floating-point has more precision in the |
| neighborhood of zero, the depth buffer precision is concentrated |
| at zero in window-space Z. This corresponds to 0.5 in normalized |
| device coordinates. |
| |
| Consider if our projection matrix mapped eye-space 2 to |
| clip-space 0.0 and eye-space 1000 to 1.0 with the Z matrix row: |
| |
| [ 0 0 (n+f)/(n-f) f*n/(n-f) ] |
| |
| so that |
| |
| Zc = -0.5 = 0*x_e + 0*y_e + ((2+1000)/(2-1000))*z_e + (2*1000/(2-1000))*w_e |
| |
| solving for z_e when w_e is one, means z_e equals -1.498 |
| |
| OpenGL 4.3 made a slightly incompatible change in the parameter |
| types for glDepthRange (and related commands) from clamped |
| floating-point types (GLclampd) to unclamped floating-point |
| types (GLdouble). Hence the functionality of glDepthRangedNV |
| also applies to OpenGL 4.3 in the case of floating-point depth |
| buffers. |
| |
| 9) Can an application be guaranteed the exact same pixels being |
| rasterized when the clip control origin is GL_UPPER_LEFT versus |
| GL_LOWER_LEFT, except having the scanlines reversed? |
| |
| RESOLVED: No such rasterization invariance is reasonable to |
| guarantee. Slight pixel variances are possible. |
| |
| The polygon rasterization rules for OpenGL (section 14.6.1, |
| "Polygon Rasterization") states: In such a case [fragment's center |
| lies on a polygon boundary edge] we require that if two polygons |
| lie on either side of a common edge (with identical endpoints) |
| on which a fragment center lies, then exactly one of the polygons |
| results in the production of the fragment during rasterization." |
| |
| The specification leaves it to implementations to define the |
| exact edge rule in this case. If the sense of Y in clip space |
| is flipped, this rule may be decided differently. |
| |
| This is further complicated by multisampling where the sample pattern |
| is unlikely to be mirrored in the Y direction. |
| |
| These issues are razor's edge cases and should not be an issue |
| for real applications. |
| |
| 10) Are all the possible combinations of glClipControl useful? |
| |
| RESOLVED: Yes, the initial state (GL_LOWER_LEFT/ |
| GL_NEGATIVE_ONE_TO_ONE) corresponds to OpenGL's traditional |
| behavior. |
| |
| The state GL_LOWER_LEFT/GL_ZERO_TO_ONE corresponds to OpenGL's |
| traditional origin and Direct3D's depth mode. |
| |
| The state GL_UPPER_LEFT/GL_ZERO_TO_ONE corresponds to Direct3D's |
| clip volume definition. |
| |
| The state GL_UPPER_LEFT/GL_NEGATIVE_ONE_TO_ONE is consistent with |
| the upper-left origin of the window coordinate system of Microsoft |
| Windows and the X Window System. |
| |
| 11) Should all the possible combinations of glClipControl |
| parameters supported be supported? |
| |
| RESOLVED: Yes, all the combinations should be supported. The cost |
| is low and this provides orthogonality. |
| |
| So it is legal to call: |
| |
| glClipControl(GL_UPPER_LEFT, GL_NEGATIVE_ONE_TO_ONE); |
| |
| 12) Does setting the clip control origin to GL_UPPER_LEFT change the |
| origin of the window coordinate system use for commands such as |
| glViewport, glScissor, glWindowPos2i, and glReadPixels? |
| |
| RESOLVED: No. |
| |
| The (x,y) window space location passed to these commands have the |
| (0,0) origin at the lower left corner of the window, independent |
| of the state of the clip control origin. |
| |
| So, for example, an application wanting a Direct3D upper-left orign |
| specifying the scissor with upper-left (x,y) coordinates would call: |
| |
| glScissor(upper_left_x, |
| window_height - upper_left_y, |
| window_width, window_height); |
| |
| The rationale for this choice is to avoid confusion for how |
| window space coordinates are passed to commands. When rendering |
| to resizable windows, the window width and height can change |
| asychronously. This would mean the scissor command would need |
| to specify a "gravity" for the window origin. There would also |
| need to be a way to "query" this state relative to difference |
| origin conventions and subject asynchronous window resizes. |
| |
| Moreover, this extension is not changing how window space is |
| specified but rather how clip space is specified. |
| |
| 13) Does the polygon stipple orientation change when the clip control |
| origin is set to GL_UPPER_LEFT? |
| |
| RESOLVED: No. |
| |
| 14) Will using the GL_ZERO_TO_ONE clip control depth mode improve |
| my depth precision? |
| |
| RESOLVED: Yes, if you use a floating-point depth buffer and |
| place the near and far values at 1.0 and 0.0 (reversed from the |
| normal convention). |
| |
| But not much if you use a conventional fixed-point depth buffer. |
| |
| This really depends on whether the particular hardware |
| implementation can numerically improve its depth interpolation |
| result. This depends on a lot of things including the quality |
| of the depth plane equation setup, the number of bits of |
| sub-pixel precision available, and how the depth interpolation |
| is performed. |
| |
| With a conventional 24-bit fixed-point depth buffer, applications |
| may be able to achieve half a least significant bit (LSB) of |
| improved depth buffer precision. |
| |
| There are typically far better strategies for improving depth |
| precision such as W-buffering, avoiding concatenation of the |
| modelview and projection matrices, and (probably the easiest) |
| better managing your scene's near and far planes. |
| |
| With a floating-point depth buffer, it is more likely the |
| GL_ZERO_TO_ONE depth mode will improve depth precision. |
| Unfortunately in the conventional depth range [0,1], the |
| improvement is primarily close to the near plane where there |
| is already excessive precision. Reversing the depth range with |
| the command |
| |
| glDepthRange(1.0, 0.0); |
| |
| effectively reverses the near and far values in the depth |
| buffer. Also remember to reverse the depth function; so |
| glDepthFunc(GL_LESS) should become glDepthFunc(GL_GREATER). |
| However, this involves computing 1-Z which effectively truncates |
| far values (for much the same reason adding +0.5 does). |
| |
| Alternatively, the reversal of near and far can happen as part |
| of the projection transformation so the depth range specified |
| with glDepthRange can be the conventional range [0,1]. Arguably |
| folding the near and far reversal into the projection matrix is |
| slightly better than reversing the depth range. However the |
| problem remains that a very large value is added with a small |
| value close to the far plane so effective depth precision is |
| not substantially improved with a fixed-point depth buffer but |
| has a substantial advantage for a floating-point depth buffer. |
| |
| 15) How does this extension interact with geometry shaders? |
| |
| RESOLVED: If there is a geometry shader active, it is the |
| geometry shader which is actually writing the clip space position |
| (not the vertex shader). |
| |
| One way to implement this extension (ignoring geometry shaders |
| for now) would be to add an epilogue to the application's vertex |
| shader to invert the clip space Y output when the clip control |
| origin is GL_UPPER_LEFT and perform a scale by 2 and bias by negative |
| clip space W to the clip space Z (biasing by negative clip space |
| W is like subtracting 1 in normalized device coordinates). |
| |
| However, this epilogue would need to be moved to the geometry |
| shader if a geometry shader was active. |
| |
| 16) How does this extension interact with tessellation evaluation |
| shaders (without a geometry shader)? |
| |
| RESOLVED: Then the epilogue discussed in issue #15 would need to |
| be added to the tessellation evaluation shader (and not the vertex |
| shader since it is really transforming patch control points). |
| |
| If there was a geometry shader active, the geometry shader is |
| where the epilogue would be done. |
| |
| 17) Does the discussion of the use an epilogue in the last two issues |
| mean using the GL_UPPER_LEFT or GL_ZERO_TO_ONE modes is |
| necessarily slower? |
| |
| RESOLVED: Generally no. |
| |
| GPUs that support Direct3D are expected to have a mode to support |
| GL_UPPER_LEFT and GL_ZERO_TO_ONE at full speed and OpenGL |
| implementations for such GPUs should operate at full speed. |
| |
| 18) Should the clip control state be changed frequently? |
| |
| RESOLVED: Most applications are expected to set the clip control |
| conventions once; for example, to match the Direct3D conventions. |
| |
| Some implementations may introduce a flush when changing the |
| clip control state. Hence frequent clip control changes are |
| not recommended. |
| |
| No flush is explicitly required when the clip control changes |
| and some implementations (NVIDIA) will have no significant |
| performance penalty for changing the clip control state. |
| |
| 19) Issue #6 addresses fixed-function vertex processing adjustments |
| under different clip control modes. How would a GLSL vertex |
| shader be adjusted, assuming how the shader computes its |
| clip-space position does not change, for different clip control |
| conventions? |
| |
| RESOLVED: The following GLSL epilogues could be added... |
| |
| If the clip control origin is GL_UPPER_LEFT, you could add a final |
| operation to negate the clip-space Y component. So: |
| |
| gl_Position.y *= -1; |
| |
| If the clip control depth mode is GL_ZERO_TO_ONE, you |
| could scale and bias the conventional [-1,+1] range of |
| normalized-device-coordinate-space Z to the [0,1] range like |
| this: |
| |
| gl_Position.z = 0.5*gl_Positon.z + 0.5*gl_Position.w; |
| |
| Because |
| |
| z_ndc = z_c / w_c |
| |
| so the epilogue above computes an adjusted z_ndc': |
| |
| z_ndc' = (0.5*z_c + 0.5+w_c)/w_c |
| |
| which is the same as: |
| |
| z_ndc' = 0.5*z_c/w_c + 0.5 |
| = 0.5*z_ndc + 0.5 |
| |
| and scaling a [-1,+1] range by 0.5 and biasing by 0.5 computes |
| a linear mapping to the range [0,1]. |
| |
| Alternatively, rather than adding an epilogue as described, |
| the adjustments above could be folded into the transform matrix |
| typically used to transform object-space to clip-space. This is |
| a faster approach since it avoids extra math operations in the |
| vertex shaders. |
| |
| 20) Explain the numerical advantage for potential increased depth |
| precision for the GL_ZERO_TO_ONE clip control depth mode. |
| |
| RESOLVED: If the normal depth range sets near to 0.0 and far |
| to 1.0, this means the effective viewport transform for Z (see |
| section 13.6.1 "Controlling the Viewport") becomes an identity |
| mapping. So the mapping in GL_ZERO_TO_ONE depth mode is: |
| |
| z_w = (f-n) * z_d + n |
| |
| and when near (n) is 0.0 and far (f) is 1.0, this becomes simply: |
| |
| z_w = z_d; |
| |
| This identity mapping results in no lose or change in the |
| per-vertex window space position. |
| |
| Contrast this with the same situation with the |
| GL_NEGATIVE_ONE_TO_ONE depth mode with the mapping: |
| |
| z_w = (f-n)/2 * z_d + (n+f)/2 |
| |
| and when near (n) is 0.0 and far (f) is 1.0, this becomes simply: |
| |
| z_w = 0.5 * z_d + 0.5 |
| |
| While multiplying z_d by 0.5 has no precision loss (ignoring |
| denorms, this scale simply decrements the exponent by 1 without |
| disturbing the mantissa). However a bias by 0.5 does distrurb |
| the floating-point precision (also see Issue #3), losing one |
| least-significant-bit (LSB) of precision. |
| |
| 21) What should the state to control the GL_NEGATIVE_ONE_TO_ONE |
| and GL_ZERO_TO_ONE convention be called? |
| |
| RESOLVED: GL_CLIP_DEPTH_MODE. |
| |
| An alternative would be GL_CLIP_Z_MODE but the convention |
| is well-established in the OpenGL API that Z values that are |
| interpreted as depth values are described as DEPTH. |
| |
| 22) Direct3D 8 and 9 have a window-space coordinate system where |
| pixel centers are centered on integer coordinates. OpenGL |
| (and Direct3D 10 and 11) position pixel centers at half-pixel |
| locations. Should ARB_clip_control account for the older Direct3D |
| integer pixel center convention? |
| |
| RESOLVED: No, because existing functionality covers this... |
| |
| The EXT_viewport_array extension (made a core part of OpenGL |
| with version 4.1) extends the viewport state to be specified as |
| floating-point (technically fixed-point) values. Prior to this |
| extension, the viewport parameters were integral. |
| |
| With the EXT_viewport_array functionality, you can add a bias of |
| (0.5,0.5) to the viewport (x,y) to shift integer Direct3D 8/9 |
| style window space locations to OpenGL's half-pixel convention. |
| |
| If you had a Direct3D upper-left viewport (x,y), you'd match |
| the Direct3D clip-space AND window-space conventions like this: |
| |
| glClipControl(GL_UPPER_LEFT, GL_ZERO_TO_ONE); |
| const GLuint viewport_index = 0; // Prior to DirectX 10, there's only a single viewport |
| glViewportIndexedf(viewport_index, |
| x + 0.5f, window_height - (y + view_height) + 0.5f, |
| view_width, view_height); |
| |
| where window_height is the height of the window/surface in pixels. |
| |
| Also note the EXT_fragment_coord_conventions (made a core part |
| of OpenGL with version 3.2) allows the window position varying |
| input to fragment shaders to reflect the Direct3D 9 window-space |
| convention. See that extension for details. |
| |
| 23) Does this extension's state affect user clip planes? |
| |
| RESOLVED: No, user clip planes operate on eye-space coordinates |
| which are not affected by this extension's state. |
| |
| 24) Does this extension's state affect fixed-function fog? |
| |
| RESOLVED: No, fixed-function fog operates on eye-space distance |
| which is not affected by this extension's state. |
| |
| 25) Does this extension's state affect the point sprite origin? |
| |
| RESOLVED: No. |
| |
| When the EXT_point_sprite functionality was promoted to a core |
| feature in OpenGL 2.0, the GL_POINT_SPRITE_ORIGIN state was added |
| to specify whether the 2D texture coordinate has a lower-left |
| (OpenGL's convention in EXT_point_sprite and NV_point_sprite) |
| or upper-left (Direct3D convention). |
| |
| An application wanting to emulate Direct3D's upper-left point |
| sprite texture coordinate origin should change the origin state |
| with an explicit point parameter command. Specifically: |
| |
| glPointParameteri(GL_POINT_SPRITE_ORIGIN, GL_UPPER_LEFT); |
| |
| This command is in addition to calling glClipControl and |
| specifying a GL_UPPER_LEFT origin. |
| |
| 26) Issue #12 says the origin for glWindowPos2i and other glWindowPos* |
| commands is lower-left independent of the clip control state. |
| What about glRasterPos2i and other glRasterPos* commands? |
| |
| RESOLVED: Yes, the raster position specified by glRasterPos2i, |
| etc. is affected by the clip control state because the |
| object-space position is transformed and clipped just as a point |
| vertex position would be to arrive at the clip-space raster |
| position that is further transformed to window space. |
| |
| 27) Is the depth value specified for glClearDepth affected by this |
| extension's clip control state? |
| |
| RESOLVED: No, glClearDepth takes a window-space depth value. |
| |
| This extension only affects how clip space clipping and the |
| transformation from clip space to window space operates. |
| |
| Likewise depth values read (glReadPixels), drawn (glDrawPixels), |
| or copied (glCopyPixels, glBlitFramebuffer) are unaffected by |
| this extension's clip control state. |
| |
| 28) Does this extension's state affect the operation of polygon |
| offset? |
| |
| RESOLVED: No, polygon offset operates on window-space depth |
| values. This extension's clip control state operates prior |
| to polygon offset. |
| |
| 29) Can glClipControl be display listed? |
| |
| RESOLVED: Yes. |
| |
| 30) Should the command be glClipParameteri to anticipate more |
| control of clipping state? |
| |
| RESOLVED: No. Given over 20 years with basically zero extensions |
| in the area of clipping state, we realistically don't anticipate |
| more clipping parameters. Even in the case of this extension, the |
| rationale for this extension is quite limited and not about adding |
| any "features" to clipping. Instead the purpose is simply to |
| match the conventions of Direct3D (not a functional change). |
| While Direct3D's convention is different from OpenGL, there |
| simply aren't any futher 3D APIs or standards which clip |
| differently. |
| |
| Also glClipControl maintains consistency with the existing |
| glClipPlane command pattern for the clipping API. |
| |
| Historically "Parameter" has been used for commands that affect |
| managed "object" state and/or have a speciailized "Get" query |
| command (glGetColorTableParameter*) rather than fixed-function |
| pipeline state. This isn't completely uniform (exceptions: |
| point parameters, patch parameters) but the vast majority of |
| fixed-function rendering state isn't set with gl*Parameter |
| style commands. When "Parameter" commands are used there |
| is typically a plurality of state settings with different |
| integer/float/double/boolean types. None of the situations |
| that justify gl*Parameter style commands are present in this |
| extension. |
| |
| 31) This extension is only useful if it is widely available. So how |
| easy would this extension be to implement? |
| |
| RESOLVED: No special hardware is required due to the careful |
| way this extension is specified. The clip control functionality |
| could all be done by inexpensive epilogue math appended to the |
| last shader in the graphics pipeline. The Y inversion could be |
| performed as part of the viewport transform. |
| |
| Given the prevalance of Direct3D-capable hardware, we expect |
| some hardware vendors will implement this extension with |
| special existing modes in their hardware to handle the Direct3D |
| conventions. However we emphasize no special hardware is required |
| and the performance benefit attributable to such hardware is |
| likely to be extremely meager. |
| |
| With respect to Mesa3D and Gallium, Brian Paul observes: "This |
| extension should be pretty easy to implement in Mesa/gallium. |
| In Gallium we already have a state variable for Z 0/1 vs. -1/+1 |
| clipping. And I think we could implement the Y origin via our |
| viewport state (which is specified in floats)." |
| |
| 32) Is support for the GL_UPPER_LEFT convention just to match |
| Direct3D/Windows? |
| |
| RESOLVED: No. Along with Windows/Direct3D/Direct2D, X11 and |
| Java also have upper-left graphics device coordinate systems. |
| |
| OpenGL, PostScript, PHIGS, GKS, and Apple's Core Graphics |
| (Quartz 2D) have lower-left graphics device coordinate systems. |
| |
| 33) When rendering to off-screen framebuffer objects (FBOs) that |
| will subsequently be textured from, how do I make sure the texture |
| coordinate origin and the window space origin are consistent? |
| |
| RESOLVED: Use GL_LOWER_LEFT for the origin parameter of |
| glClipControl in this case. Use the GL_UPPER_LEFT for the |
| origin parameter when matching Direct3D's origin *and* drawing |
| into a window framebuffer to be directly presented. |
| |
| 34) Can you provide an example illustrating how applications using the |
| coordinate system conventions of Direct3D map onto this extension? |
| |
| RESOLVED: Consider a Direct3D application rendering a triangle ABC |
| (with counter-clockwise orientation) to a viewport in the upper-left |
| quadrant of the destination surface. The surface (with Direct3D |
| window coordinates) is illustrated here. |
| |
| (0,0) (960,0) (1920,0) |
| +------(A)-------+----------------+ |
| |^ Y_c == +W_c ^ | | |
| | | | |
| | | | |
| | | | |
| |v Y_c == -W_c v | | |
| +-(B)--------(C)-+----------------+ |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| +----------------+----------------+ |
| (0,1080) (1920,1080) |
| |
| In this example, assume vertices A, B, and C have clip coordinates of: |
| |
| A = (+0.0, +1.0, +0.5, +1.0) |
| B = (-0.8, -1.0, +0.5, +1.0) |
| C = (+0.8, -1.0, +0.5, +1.0) |
| |
| Direct3D's coordinate transformations are functionally similar to |
| OpenGL's, except that (a) the Y coordinate is inverted as part of the |
| viewport transformation mapping normalized device coordinates (NDCs) |
| to window coordinates and (b) the depth range transformation maps Z==0 |
| to the near value instead of halfway between near and far as in |
| OpenGL: |
| |
| http://msdn.microsoft.com/en-us/library/windows/desktop/ |
| bb206341%28v=vs.85%29.aspx |
| |
| Because of the Y inversion from (a), vertices in Direct3D with a Y NDC |
| of -1.0 map to the bottom of the viewport (larger Y window coordinates |
| in the Direct3D coordinate system). This is exactly like OpenGL |
| windowed rendering, where a Y NDC of -1 maps to smaller Y window |
| coordinates (bottom) in the OpenGL coordinate system. Thanks to this |
| inversion in the Direct3D viewport transformation, rendering a |
| Direct3D scene with the same coordinates and matrices in OpenGL will |
| produce an image with identical vertical orientation and winding |
| (CW/CCW). However, since the viewport rectangle itself is programmed |
| in window coordinates, a Direct3D-centric viewport of (0,0,960,540) |
| needs to be flipped to (0,540,960,540) to work in OpenGL. |
| Additionally, to get identical near/far clipping and Z values, it's |
| necessary to use the ZERO_TO_ONE mode in this extension to have OpenGL |
| process Z coordinates identically to Direct3D. |
| |
| When rendering to off-screen surfaces later used as textures, the |
| issue is a little bit more complex. A Direct3D application will use |
| the texture coordinates (0,0) to refer to the upper left corner of the |
| upper leftmost pixel of the image. However, in OpenGL, texture |
| coordinates of (0,0) refer to the lower-left corner of the |
| lower-leftmost pixel of the image. One way to compensate for this is |
| to remap the <t> texture coordinate with: |
| |
| t_OpenGL = 1.0 - t_Direct3D |
| |
| Unfortunately, that requires a modification to shaders or other input |
| data in the application. Instead of doing this, the UPPER_LEFT mode |
| in this extension provides a simple way to use Direct3D texture |
| coordinate conventions -- by rendering the entire scene *upside-down* |
| from the point of view of OpenGL. The image we want to produce using |
| this technique (below) is a vertically inverted version of the |
| previous image, where OpenGL lower-left window coordinates are |
| depicted in the figure. |
| |
| (0,1080) (1920,1080) |
| +----------------+----------------+ |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| +-(B)--------(C)-+----------------+ |
| |v Y_c == -W_c v | | |
| | | | |
| | | | |
| | | | |
| |^ Y_c == +W_c ^ | | |
| +------(A)-------+----------------+ |
| (0,0) (960,0) (1920,0) |
| |
| In this example, the UPPER_LEFT mode in this extension inverts the |
| geometry as part of the transformation from clip coordinates to NDCs, |
| so that vertex A has a Y NDC of -1.0 instead of +1.0. This puts A at |
| the bottom of the viewport, while B and C remain at the top. One |
| thing to note is that the inversion changes the orientation of |
| triangle ABC, which is now clockwise instead of counter-clockwise. To |
| compensate, this extension also inverts the value computed to compute |
| face direction when in UPPER_LEFT mode. The one other thing to note |
| here is that when rendering this way, the Direct3D viewport should be |
| used as-is in OpenGL. |
| |
| Note that a similar inversion technique can be used to implement |
| OpenGL FBO rendering on graphics hardware supporting only Direct3D |
| coordinate systems. If this technique is used on an implementation |
| doing something like this, the two inversions cancel each other out. |
| |
| 35) Does this extension affect the primitive's winding order in tessellation |
| evaluation shader when origin is changed to GL_UPPER_LEFT? |
| |
| RESOLVED: No, the winding order is not affected. If a change in winding |
| order of the primitive is needed, it must be done from the tessellation |
| shader explicitly. |
| |
| Revision History |
| |
| Rev. Date Author Changes |
| ---- -------- --------- ---------------------------------------------- |
| 3 04/26/13 mjk Add issues 15 to 21 |
| Change CLIP_Z_MODE to CLIP_DEPTH_MODE |
| 4 04/30/13 mjk Add issue 22 |
| 5 05/01/13 mjk Add issues 22 to 28, fix typos |
| 6 05/09/13 mjk Add issue 29 to 31 |
| 7 05/13/13 pdaniell Internal revisions |
| 8 05/13/13 mjk Valve feedback; change to KHR in issues |
| 9 05/13/13 mjk Change to KHR in issues |
| 10 05/28/13 pdaniell Fold in feedback from Mark Callow in bug 10245 |
| 11 05/30/13 pdaniell Internal revisions |
| 12 06/06/13 pdaniell Internal revisions |
| 13 06/17/13 pdaniell Fix the enum token values |
| 14 07/03/13 mjk D3D off-screen discussion; issue 32 and 33 |
| 15 04/16/14 pdaniell Prepare spec for OpenGL 4.5 |
| 16 04/17/14 pdaniell Fixes "UPPER_RIGHT" typos to UPPER_LEFT |
| 17 07/30/14 pbrown Fix incorrect language in the overview |
| describing when to use UPPER_LEFT and LOWER_LEFT |
| modes; add detailed examples in issue 34. |
| 18 09/17/15 Jon Leech Correct typo in issue 7 and add contributor |
| Brano Kemen from that issue. |
| 19 04/06/18 Vikram Add issue 35 |