1Name 2 3 NV_clip_space_w_scaling 4 5Name Strings 6 7 GL_NV_clip_space_w_scaling 8 9Contact 10 11 Kedarnath Thangudu, NVIDIA Corporation (kthangudu 'at' nvidia.com) 12 13Contributors 14 15 Eric Werness, NVIDIA Corporation 16 Ingo Esser, NVIDIA Corporation 17 Pat Brown, NVIDIA Corporation 18 Mark Kilgard, NVIDIA Corporation 19 Jason Schmidt, NVIDIA Corporation 20 21Status 22 23 Shipping in NVIDIA release 367.XX drivers and up. 24 25Version 26 27 Last Modified Date: November 25, 2017 28 Revision: 4 29 30Number 31 32 OpenGL Extension #486 33 OpenGL ES Extension #295 34 35Dependencies 36 37 This extension is written against OpenGL 4.5 Specification 38 (Compatibility Profile). 39 40 This extension interacts with the OpenGL ES 3.1 Specification. 41 42 This extension requires NV_viewport_array2. 43 44 If implemented in OpenGL ES, one of NV_viewport_array or OES_viewport_array 45 is required. 46 47Overview 48 49 Virtual Reality (VR) applications often involve a post-processing step to 50 apply a "barrel" distortion to the rendered image to correct the 51 "pincushion" distortion introduced by the optics in a VR device. The 52 barrel distorted image has lower resolution along the edges compared to 53 the center. Since the original image is rendered at high resolution, 54 which is uniform across the complete image, a lot of pixels towards the 55 edges do not make it to the final post-processed image. 56 57 This extension also provides a mechanism to render VR scenes at a 58 non-uniform resolution, in particular a resolution that falls linearly 59 from the center towards the edges. This is achieved by scaling the "w" 60 coordinate of the vertices in the clip space before perspective divide. 61 The clip space "w" coordinate of the vertices may be offset as of a 62 function of "x" and "y" coordinates as follows: 63 64 w' = w + Ax + By 65 66 In the intended use case for viewport position scaling, an application 67 should use a set of 4 viewports, one for each of the 4 quadrants of a 68 Cartesian coordinate system. Each viewport is set to the dimension of the 69 image, but is scissored to the quadrant it represents. The application 70 should specify A and B coefficients of the w-scaling equation above, 71 that have the same value, but different signs, for each of the viewports. 72 The signs of A and B should match the signs of X and Y for the quadrant 73 that they represent such that the value of "w'" will always be greater 74 than or equal to the original "w" value for the entire image. Since the 75 offset to "w", (Ax + By), is always positive and increases with the 76 absolute values of "x" and "y", the effective resolution will fall off 77 linearly from the center of the image to its edges. 78 79New Procedures and Functions 80 81 void ViewportPositionWScaleNV(uint index, float xcoeff, float ycoeff) 82 83New Tokens 84 85 Accepted by the <cap> parameter of Enable, Disable, IsEnabled: 86 87 VIEWPORT_POSITION_W_SCALE_NV 0x937C 88 89 Accepted by the <pname> parameter of GetBooleani_v, GetDoublei_v, 90 GetIntegeri_v, GetFloati_v, and GetInteger64i_v: 91 92 VIEWPORT_POSITION_W_SCALE_X_COEFF_NV 0x937D 93 VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV 0x937E 94 95Additions to Chapter 13 of the OpenGL 4.5 (Compatibility Profile) 96Specification (Fixed-Function Vertex Post-Processing) 97 98 Modify Section 13.2 (Transform Feedback), p. 453 [section 12.1 in OpenGL ES] 99 100 Modify the first paragraph: 101 102 ...The vertices are fed back after vertex color clamping, but before 103 viewport mask expansion, w coordinate warping, flat-shading, and clipping... 104 105 Add a new Section 13.X (Viewport W Coordinate Scaling) 106 107 If VIEWPORT_POSITION_W_SCALE_NV is enabled, the w coordinates for each 108 primitive sent to a given viewport will be scaled as a function of 109 its x and y coordinates using the following equation: 110 111 w' = xcoeff * x + ycoeff * y + w; 112 113 The coefficients for "x" and "y" used in the above equation depend on the 114 viewport index, and are controlled by the command 115 116 void ViewportPositionWScaleNV(uint index, float xcoeff, float ycoeff); 117 118 The viewport specified by <index> has its coefficients for "x" and "y" 119 set to the <xcoeff> and <ycoeff> values. Specifying these coefficients 120 enables rendering images at a non-uniform resolution, in particular a 121 resolution that falls off linearly from the center towards the edges, 122 which is useful for VR applications. VR applications often involve a 123 post-processing step to apply a "barrel" distortion to the rendered image 124 to correct the "pincushion" distortion introduced by the optics in a VR 125 device. The barrel distorted image, has lower resolution along the edges 126 compared to the center. Since the original image is rendered at high 127 resolution, which is uniform across the complete image, a lot of pixels 128 towards the edges do not make it to the final post-processed image. 129 VR applications may use the w-scaling to minimize the processing of unused 130 fragments. To achieve the intended effect, applications should use a set of 131 4 viewports one for each of the 4 quadrants of a Cartesian coordinate 132 system. Each viewport is set to the dimension of the image, but is 133 scissored to the quadrant it represents. The application should specify 134 the x and y coefficients of the w-scaling equation above, that have the 135 same value, but different signs, for each of the viewports. The signs of 136 <xcoeff> and <ycoeff> should match the signs of X and Y for the quadrant 137 that they represent such that the value of "w'" will always be greater 138 than or equal to the original "w" value for the entire image. Since the 139 offset to "w", (Ax + By), is always positive and increases with the 140 absolute values of "x" and "y", the effective resolution will fall off 141 linearly from the center of the image to its edges. 142 143 Errors: 144 145 - The error INVALID_VALUE is generated if <index> is greater than or equal 146 to the value of MAX_VIEWPORTS. 147 148New Implementation Dependent State 149 150 None. 151 152New State 153 154 Initial 155 Get Value Get Command Type Value Description Sec. Attribute 156 ------------------------------------ ----------- ---- ------- ----------- ---- --------- 157 VIEWPORT_POSITION_W_SCALE_NV IsEnabled B FALSE Enable W coordinate Scaling 13.X enable 158 VIEWPORT_POSITION_W_SCALE_X_COEFF_NV GetFloati_v R 0 x coefficient for the w 13.X viewport 159 coordinate scaling equation 160 VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV GetFloati_v R 0 y coefficient for the w 13.X viewport 161 coordinate scaling equation 162 163Additions to the AGL/GLX/WGL/EGL Specifications 164 165 None. 166 167GLX Protocol 168 169 None. 170 171Errors 172 173 None. 174 175Interactions with OpenGL ES 3.1 176 177 If implemented in OpenGL ES, remove all references to GetDoublei_v. 178 If NV_viewport_array is supported, replace all references to MAX_VIEWPORTS 179 and GetFloati_v with MAX_VIEWPORTS_NV and GetFloati_vNV respectively. 180 If OES_viewport_array is supported, replace all references to MAX_VIEWPORTS 181 and GetFloati_v with MAX_VIEWPORTS_OES and GetFloati_vOES respectively. 182 183Issues 184 185 (1) Does this extension provide any functionality to convert the w-scaled 186 image to the barrel distorted image used in VR? 187 188 RESOLVED: No. VR applications would still require a post-processing step to 189 generate a barrel distorted image to compensate for the lens distortion. 190 The following vertex and fragment shader pair un-warps a w-scaled image. 191 It can be incorporated into an existing post-processing shader to directly 192 convert a w-scaled image to the barrel distorted image. 193 194 // Vertex Shader 195 // Draw a triangle that covers the whole screen 196 const vec4 positions[3] = vec4[3](vec4(-1, -1, 0, 1), 197 vec4( 3, -1, 0, 1), 198 vec4(-1, 3, 0, 1)); 199 out vec2 uv; 200 void main() 201 { 202 vec4 pos = positions[ gl_VertexID ]; 203 gl_Position = pos; 204 uv = pos.xy; 205 } 206 207 // Fragment Shader 208 uniform sampler2D tex; 209 uniform float xcoeff; 210 uniform float ycoeff; 211 out vec4 Color; 212 in vec2 uv; 213 214 void main() 215 { 216 // Handle uv as if upper right quadrant 217 vec2 uvabs = abs(uv); 218 219 // unscale: transform w-scaled image into an unscaled image 220 // scale: transform unscaled image int a w-scaled image 221 float unscale = 1.0 / (1 + xcoeff * uvabs.x + xcoeff * uvabs.y); 222 //float scale = 1.0 / (1 - xcoeff * uvabs.x - xcoeff * uvabs.y); 223 224 vec2 P = vec2(unscale * uvabs.x, unscale * uvabs.y); 225 226 // Go back to the right quadrant 227 P *= sign(uv); 228 229 Color = texture(tex, P * 0.5 + 0.5); 230 } 231 232 (2) In the standard use case a application sets up 4 viewports, one for 233 each quadrant. Does each primitive have to be broadcast to all the 4 234 viewports? 235 236 RESOLVED: No. Applications may see a better performance if the viewport 237 mask for each primitive is limited to the viewports corresponding 238 to the quadrants it falls in. 239 240 241Revision History 242 243 Revision 1 244 - Internal revisions. 245 Revision 2 246 - Add _NV suffixes to _COEFF tokens 247 Revision 3 248 - Add ES interactions. 249 - Add requirement for NV_viewport_array2 250 Revision 4, 2017/11/25 (pbrown) 251 - Add to the OpenGL ES Extension Registry 252