001/* 002 003*/ 004 005package renderer.pipeline; 006import renderer.scene.*; 007import renderer.framebuffer.*; 008 009import java.util.List; 010 011/** 012 Transform each {@link Vertex} of a {@link Model} from 013 projected camera coordinates (i.e., image plane 014 coordinates) to viewport coordinates. 015<p> 016 The image plane contains a view rectangle with 017 <pre>{@code 018 -1 <= x <= 1, 019 -1 <= y <= 1, 020 }</pre> 021 The view rectangle has the important job of determining 022 what part of the scene is visible to our renderer. 023<p> 024 In the previous pipeline stage, every vertex from the model was projected onto the image plane. We want only that part of each projected line segment contained in the view rectangle to be visible to our renderer and rasterized into the framebuffer's viewport. To prepare for the rasterization step, we need to convert each vertex's x and y coordinates 025 026 027<pre>{@code 028 (w+1/2,h+1/2) 029 y-axis +----------------------------------------+ 030 | | | 031 | (+1,+1) | | 032 +-----|-----+ | | 033 | | | | | 034 | | | | | 035----------+----------- x-axis | | 036 | | | | | 037 | | | | | 038 +-----|-----+ | | 039 (-1,-1) | | | 040 | | | 041 | | 042 View Rectangle +----------------------------------------+ 043 (in the view plane) (1/2,1/2) 044 Logical Viewport 045}</pre> 046 047 048 049Notice how the view rectangle is a square but the logical viewport is a reactangle (though it may be a square). 050 051The view rectangle always has -1.0 <= x <= 1.0 and -1.0 <= y <= 1.0. 052The logical viewport always has 0.5 <= x <= w+0.5 and 0.5 <= y <= h+0.5 where w and h are the width and height of the FrameBuffer's current viewport. 053 054If the aspect ratio, w/h, of the logical (and FrameBuffer) viewport is not 1, then the image in the view rectangle will be distorted when it is transformed to the logical viewport. (NOTE: Starting with Renderer 7, the aspect ratio of the viewport will usually match the aspect ratio of the renderer's view volume, so the distortion caused by the viewport transformation will undo the distortion caused by the normalization transformation. If the view volume and viewport aspect ratios do not match, then the final image in the framebuffer's viewport will be a distortion of the image in the view volume's view rectangle.). 055 056 057 058 For each {@link Vertex} object in each {@link Model} object, 059 transform the {@link Vertex} object from image plane coordinates 060 to viewport coordinates so that the view rectangle in the image 061 plane with 062 <pre>{@code 063 -1 <= x <= 1, 064 -1 <= y <= 1, 065 }</pre> 066 transforms into a viewport where 067 <pre>{@code 068 0.5 <= x < w + 0.5, 069 0.5 <= y < h + 0.5, 070 }</pre> 071 where 072 <pre>{@code 073 w = number of horizontal pixels in the viewport, 074 h = number of vertical pixels in the viewport. 075 }</pre> 076<p> 077 The goal of this transformation is to put a logical pixel with 078 integer coordinates at the center of each square physical pixel. 079 The logical pixel with integer coordinates (m, n) represents the 080 square pixel with 081 <pre>{@code 082 m - 0.5 <= x < m + 0.5, 083 n - 0.5 <= y < n + 0.5. 084 }</pre> 085 Notice that logical pixel integer coordinates (m.n) have 086 <pre>{@code 087 1 <= m <= w 088 1 <= n <= h. 089 }</pre> 090<p> 091 Let us derive the formulas for the viewport transformation (we will 092 derive the x-coordinate formula; the y-coordinate formula is similar). 093<p> 094 Let x_p denote an x-coordinate in the image plane and let x_vp denote 095 an x-coordinate in the viewport. If a vertex is on the left edge of 096 the view rectangle (with x_p = -1), then it should be transformed to 097 the left edge of the viewport (with x_vp = 0.5). And if a vertex is on 098 the right edge of the view rectangle (with x_p = 1), then it should be 099 transformed to the right edge of the viewport (with x_vp = w + 0.5). 100 These two facts are all we need to know to find the linear function 101 for the transformation of the x-coordinate. 102<p> 103 We need to calculate the slope m and intercept b of a linear function 104 <pre>{@code 105 x_vp = m * x_p + b 106 }</pre> 107 that converts image plane coordinates into viewport coordinates. We know, 108 from what we said above about the left and right edges of the view 109 rectangle, that 110 <pre>{@code 111 0.5 = (m * -1) + b, 112 w + 0.5 = (m * 1) + b. 113 }</pre> 114 If we add these last two equations together we get 115 <pre>{@code 116 w + 1 = 2*b 117 }</pre> 118 or 119 <pre>{@code 120 b = (w + 1)/2. 121 }</pre> 122 If we use b to solve for m we have 123 <pre>{@code 124 0.5 = (m * -1) + (w + 1)/2 125 1 = -2*m + w + 1 126 2*m = w 127 m = w/2. 128 }</pre> 129 So the linear transformation of the x-coordinate is 130 <pre>{@code 131 x_vp = (w/2) * x_p + (w+1)/2 132 = 0.5 + w/2 * (x_p + 1). 133 }</pre> 134 The equivalent formula for the y-coordinate is 135 <pre>{@code 136 y_vp = 0.5 + h/2 * (y_p + 1). 137 }</pre> 138*/ 139public class Viewport 140{ 141 /** 142 For each {@link LineSegment}, transform each {@link Vertex} 143 from image plane coordinates to viewport coordinates. 144 145 @param ls {@link LineSegment} to transform into viewport coordinates 146 @param done boolean array that keeps track of which vertices have been transformed 147 @param fb {@link FrameBuffer} that holds the current viewport 148 */ 149 public static void viewport(LineSegment ls, boolean[] done, FrameBuffer fb) 150 { 151 // Get the viewport dimensions. 152 int w = fb.getWidthVP(); 153 int h = fb.getHeightVP(); 154 155 // Transform the line segment's endpoints from 156 // image plane coordinates to viewport coordinates. 157 for (int i = 0; i <= 1; i++) 158 { 159 // Transform only those vertices that 160 // have not already been transformed. 161 int index = ls.index[i]; 162 if (! done[index]) 163 { 164 done[index] = true; 165 Vertex v = ls.model.vertexList.get( index ); 166 v.x = 0.5 + w/2.001 * (v.x + 1); //x_vp = 0.5 + w/2 * (x_p+1) 167 v.y = 0.5 + h/2.001 * (v.y + 1); //y_vp = 0.5 + h/2 * (y_p+1) 168 // NOTE: Notice the 2.001 fudge factor in the last two equations. 169 // This is explained on page 142 of 170 // "Jim Blinn's Corner: A Trip Down The Graphics Pipeline" 171 // by Jim Blinn, 1996, Morgan Kaufmann Publishers. 172 } 173 } 174 } 175}