Professional Documents
Culture Documents
GPU Programming
EE 4702-1
Take-Home Pre-Final Examination
Due: 30 November 2018 at 16:30
Work on this exam alone. Regular class resources, such as notes, papers,
solutions, documentation, and code, can be used to find solutions. In
addition outside OpenGL references and tutorials, other programming
resources, and mathematical references can be consulted. Do not try
to seek out references that specifically answer any question here. Do
not discuss this exam with classmates or anyone else, except questions
or concerns about problems should be directed to Dr. Koppelman.
Good Luck!
Problem 1: [33 pts] Appearing on the next page is the fragment shader code taken from the solution to
Homework 3, in which a texture is applied to the triangular spiral in such a way that it looks like the texture
image was cut into strips and glued together.
(a) Modify the shader code so that the text is rotated by 90◦ , as shown in the screenshot above. The text
aspect ratio must be consistent along segments. As with the homework, the text must be readable without
skipped or repeated sections. Do not assume or make any changes to the host code. In particular, the
fragment shader should work with the same primitives as emitted for the Homework 3 code.
(b) Modify the shader code so that red lines are drawn separating the lines of text.
It is okay to try out your solution on the Homework 3 package, but put the solution in this exam. That is,
the solution will not be collected by the TA-bot.
See the Homework 3 solution for detailed comments explaining the shader code.
2
Modify shader so text rotated 90◦ .
Text aspect ratio and size must be consistent on all segments and there must be no gaps or skipped
sections.
void fs_main_hw03() {
float line_num = floor(tex_coord.x);
vec2 tc = vec2( tex_coord.x, ( line_num + tex_coord.y ) * tex_ht );
vec4 color =
gl_FrontFacing ? gl_FrontMaterial.diffuse : gl_BackMaterial.diffuse;
3
Problem 2: [34 pts] Recall that the true sphere code covered in class emits a square (two triangles) for
each sphere to be rendered. The square is chosen so that it perfectly frames the sphere as seen by the viewer.
The square is perfect in the sense that if it were made any smaller parts of the sphere would not be visible.
But it is still wasteful because the sphere is not visible in the corners of the square and so those fragment
shader invocations are wasted.
(a) Modify the true-sphere geometry shader below so that it emits a 2s-sided polygon rather than a square.
Show the code for computing the polygon coordinates, do not use the assumed functions from the next
problem. Note that when s = 2 the code should emit a bounding square, which is what the original code
does.
4
Modify code to emit 2s-sided bounding polygon. Take advantage of the fact that 2s is an even number.
void gs_main() {
vertex_id = In[0].vertex_id;
mat4 mvp = trans_proj * gl_ModelViewMatrix;
vec4 pos_rad = sphere_pos_rad[vertex_id];
vec3 ctr_o = pos_rad.xyz;
float r = pos_rad.w;
vec3 e_o = vec3(gl_ModelViewMatrixInverse*vec4(0,0,0,1)); // Eye location in object space.
// Compute center of the limb, lmb_o. (The limb is the sphere outline.)
float sin_theta = r / ec_len;
float a = r * sin_theta;
vec3 lmb_o = ctr_o - a * ne;
// Emit a bounding square for the limb. --- Solution should start here.
for ( int i = -1; i < 2; i += 2 ) for ( int j = -1; j < 2; j += 2 ) {
vertex_o = lmb_o + ax * i + ay * j;
gl_Position = mvp * vec4(vertex_o,1);
EmitVertex(); }
EndPrimitive();
5
(b) Let tf denote the execution time of 1 invocation of the true-sphere fragment shader when the sphere
covers the fragment, and let tn denote the execution time of 1 invocation when the sphere does not cover the
fragment. Assume that tf > tn . Let tg0 + stg1 denote the execution time of one invocation of the true-sphere
geometry shader that emits a 2s-sided polygon.
In general, emitting a polygon with more sides reduces the work performed by the fragment shader but
increases the work done by the geometry shader, improving overall performance. But there will be a point
at which increasing s reduces performance.
Using the symbols defined above plus other information, find an expression for the time needed to render a
sphere. The other information is needed to compute a sphere rendering time using the timings above. Of
course, no credit will be given if that other information is the execution time. Also determine the value of s
that will minimize the total time used by the geometry and fragment shaders for rendering a sphere. When
computing the s that minimizes time it is okay to apply simplifications based on s being large. (Otherwise
a closed-form solution can’t easily be found.) Hint: Yes, the solution requires calculus.
Show an expression for the time needed to render a sphere using a 2s-sided bounding polygon in terms of
tf , etc., and the other information.
Find an expression for s that will minimize time in terms of tf , etc., and the other information.
6
Problem 3: [33 pts] The screenshot below is based on the code from Homework 4. The code is in lenses
mode, meaning that the sphere is visible only at certain points. Unlike Homework 4, the lenses are much
further apart from each other, and therefore much less of the sphere is visible. If the code in the Homework
4 solution were used then most invocations of the fragment shader would be wasted because they end up
discarding the fragment.
There would be much less waste if a separate primitive were emitted for each lens, rather than one primitive
for the entire sphere.
Suppose that each sphere has the same number of lenses, call that number h, and refer to the lenses as
lens 0, lens 1, etc. Assume that a library of functions is available for computing positions for each lens.
Among these is a function lens_get_ctr_o(i,sphere_info) which returns the object-space coordinates of
the center of lens i. Variable sphere_info holds the value of the sphere center, radius, and orientation.
Assume that sphere_info has already been prepared. You may assume that related functions exist such as
lens_get_ctr_e(i,sphere_info) for eye-space coordinates. Also convenient for this problem is function
lens_get_bb_o(i,j,n,sphere_info) which returns the object-space coordinates of point j of an n-sided
bounding polygon for lens i. The bounding polygon is like the bounding square used in the true-sphere
code: it tightly fits around the lens as seen by the viewer (or equivalently, when projected on to the frame
buffer). The points wrap around the lens in a clockwise direction with increasing j.
Show changes needed to the geometry and fragment shaders on the following pages to render the lenses
efficiently for cases in which h is relatively small, say on the order of 10.
7
Problem 3, continued:
(a) Appearing below is a shortened version of the geometry shader from the Homework 4 solution. The
comments have been removed, but feel free to look at comments in the posted solution. Modify the geometry
shader below so that it emits a primitive for each lens and provides information needed by the fragment
shader (see next problem). Use the functions described above to find coordinates of bounding polygons for
the lenses.
};
void gs_main() {
vertex_id = In[0].vertex_id;
vec4 pos_rad = sphere_pos_rad[vertex_id];
vec3 ctr_o = pos_rad.xyz;
float r = pos_rad.w;
Sphere_Info sphere_info = make_sphere_info(pos_rad,sphere_rot[vertex_id]);
// Compute center of the limb, lmb_o, the circle formed by the most
// distant visible parts of the sphere surface.
8
float sin_theta = r / ec_len;
float a = r * sin_theta;
vec3 lmb_o = ctr_o - a * ne;
9
(b) Appearing below is the fragment shader from the Homework 4 solution. The comments have been
removed for brevity, feel free to look at the full Homework 4 solution. Show the changes needed to the
fragment shader. The shader should be substantially simpler.
The fragment shader should render lenses only, not full spheres.
Simplify based on the fact that geometry shader is providing lens information.
void fs_main()
{
vec4 pos_rad = sphere_pos_rad[vertex_id];
vec3 ctr_o = pos_rad.xyz;
float rsq = pos_rad.w * pos_rad.w;
vec3 e_o = gl_ModelViewMatrixInverse[3].xyz;
vec3 ef = vertex_o - e_o; // Eye to fragment.
vec3 ce = e_o-ctr_o;
float qfa = dot(ef,ef), qfb = 2 * dot(ef,ce), qfc = dot(ce,ce) - rsq;
float discr = qfb*qfb - 4 * qfa * qfc;
if ( solid ) break;
10
const float hole_radius = 0.5 * hole_frac * radians_per_hole_eq;
11