/ appendices / VK_NV_clip_space_w_scaling.txt
VK_NV_clip_space_w_scaling.txt
1 include::meta/VK_NV_clip_space_w_scaling.txt[] 2 3 *Last Modified Date*:: 4 2017-02-15 5 *Contributors*:: 6 - Eric Werness, NVIDIA 7 - Kedarnath Thangudu, NVIDIA 8 9 Virtual Reality (VR) applications often involve a post-processing step to 10 apply a "`barrel`" distortion to the rendered image to correct the 11 "`pincushion`" distortion introduced by the optics in a VR device. 12 The barrel distorted image has lower resolution along the edges compared to 13 the center. 14 Since the original image is rendered at high resolution, which is uniform 15 across the complete image, a lot of pixels towards the edges do not make it 16 to the final post-processed image. 17 18 This extension provides a mechanism to render VR scenes at a non-uniform 19 resolution, in particular a resolution that falls linearly from the center 20 towards the edges. 21 This is achieved by scaling the [eq]#w# coordinate of the vertices in the 22 clip space before perspective divide. 23 The clip space [eq]#w# coordinate of the vertices can: be offset as of a 24 function of [eq]#x# and [eq]#y# coordinates as follows: 25 26 [eq]#w' = w + Ax + By# 27 28 In the intended use case for viewport position scaling, an application 29 should use a set of four viewports, one for each of the four quadrants of a 30 Cartesian coordinate system. 31 Each viewport is set to the dimension of the image, but is scissored to the 32 quadrant it represents. 33 The application should specify [eq]#A# and [eq]#B# coefficients of the 34 [eq]#w#-scaling equation above, that have the same value, but different 35 signs, for each of the viewports. 36 The signs of [eq]#A# and [eq]#B# should match the signs of [eq]#x# and 37 [eq]#y# for the quadrant that they represent such that the value of [eq]#w'# 38 will always be greater than or equal to the original [eq]#w# value for the 39 entire image. 40 Since the offset to [eq]#w#, ([eq]#Ax + By#), is always positive, and 41 increases with the absolute values of [eq]#x# and [eq]#y#, the effective 42 resolution will fall off linearly from the center of the image to its edges. 43 44 === New Object Types 45 46 None. 47 48 === New Enum Constants 49 50 * Extending elink:VkStructureType: 51 ** ename:VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV 52 * Extending elink:VkDynamicState: 53 ** ename:VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV 54 55 === New Enums 56 57 None. 58 59 === New Structures 60 61 * slink:VkViewportWScalingNV 62 * slink:VkPipelineViewportWScalingStateCreateInfoNV 63 64 === New Functions 65 66 * flink:vkCmdSetViewportWScalingNV 67 68 === Issues 69 70 1) Is the pipeline struct name too long? 71 72 *RESOLVED*: It fits with the naming convention. 73 74 2) Separate W scaling section or fold into coordinate transformations? 75 76 *RESOLVED*: Leaving it as its own section for now. 77 78 === Examples 79 80 [source,c++] 81 -------------------------------------- 82 83 VkViewport viewports[4]; 84 VkRect2D scissors[4]; 85 VkViewportWScalingNV scalings[4]; 86 87 for (int i = 0; i < 4; i++) { 88 int x = (i & 2) ? 0 : currentWindowWidth / 2; 89 int y = (i & 1) ? 0 : currentWindowHeight / 2; 90 91 viewports[i].x = 0; 92 viewports[i].y = 0; 93 viewports[i].width = currentWindowWidth; 94 viewports[i].height = currentWindowHeight; 95 viewports[i].minDepth = 0.0f; 96 viewports[i].maxDepth = 1.0f; 97 98 scissors[i].offset.x = x; 99 scissors[i].offset.y = y; 100 scissors[i].extent.width = currentWindowWidth/2; 101 scissors[i].extent.height = currentWindowHeight/2; 102 103 const float factor = 0.15; 104 scalings[i].xcoeff = ((i & 2) ? -1.0 : 1.0) * factor; 105 scalings[i].ycoeff = ((i & 1) ? -1.0 : 1.0) * factor; 106 } 107 108 VkPipelineViewportWScalingStateCreateInfoNV vpWScalingStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV }; 109 110 vpWScalingStateInfo.viewportWScalingEnable = VK_TRUE; 111 vpWScalingStateInfo.viewportCount = 4; 112 vpWScalingStateInfo.pViewportWScalings = &scalings[0]; 113 114 VkPipelineViewportStateCreateInfo vpStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; 115 vpStateInfo.viewportCount = 4; 116 vpStateInfo.pViewports = &viewports[0]; 117 vpStateInfo.scissorCount = 4; 118 vpStateInfo.pScissors = &scissors[0]; 119 vpStateInfo.pNext = &vpWScalingStateInfo; 120 121 -------------------------------------- 122 123 Example shader to read from a w-scaled texture: 124 125 [source,c++] 126 -------------------------------------- 127 128 // Vertex Shader 129 // Draw a triangle that covers the whole screen 130 const vec4 positions[3] = vec4[3](vec4(-1, -1, 0, 1), 131 vec4( 3, -1, 0, 1), 132 vec4(-1, 3, 0, 1)); 133 out vec2 uv; 134 void main() 135 { 136 vec4 pos = positions[ gl_VertexID ]; 137 gl_Position = pos; 138 uv = pos.xy; 139 } 140 141 // Fragment Shader 142 uniform sampler2D tex; 143 uniform float xcoeff; 144 uniform float ycoeff; 145 out vec4 Color; 146 in vec2 uv; 147 148 void main() 149 { 150 // Handle uv as if upper right quadrant 151 vec2 uvabs = abs(uv); 152 153 // unscale: transform w-scaled image into an unscaled image 154 // scale: transform unscaled image int a w-scaled image 155 float unscale = 1.0 / (1 + xcoeff * uvabs.x + xcoeff * uvabs.y); 156 //float scale = 1.0 / (1 - xcoeff * uvabs.x - xcoeff * uvabs.y); 157 158 vec2 P = vec2(unscale * uvabs.x, unscale * uvabs.y); 159 160 // Go back to the right quadrant 161 P *= sign(uv); 162 163 Color = texture(tex, P * 0.5 + 0.5); 164 } 165 -------------------------------------- 166 167 === Version History 168 169 * Revision 1, 2017-02-15 (Eric Werness) 170 - Internal revisions