Week 6 Tutorial Solutions

Question 1: Winding Order and Culling

Consider the following code for drawing a pyramid.

Which way are the faces pointing? If you drew this in OpenGL with back face culling turned on, what would you see?

        // the base
        gl.glBegin(GL2.GL_POLYGON);
        {
            gl.glVertex3d(1, 1, 0);
            gl.glVertex3d(-1, 1, 0);
            gl.glVertex3d(-1,-1, 0);
            gl.glVertex3d(1, -1, 0);
        }
        gl.glEnd();        

        // the sides
        gl.glBegin(GL2.GL_POLYGON);
        {
            gl.glVertex3d(0, 0, 2);
            gl.glVertex3d(1, 1, 0);
            gl.glVertex3d(-1, 1, 0);
        }
        gl.glEnd();        

        gl.glBegin(GL2.GL_POLYGON);
        {
            gl.glVertex3d(0, 0, 2);
            gl.glVertex3d(-1, -1, 0);
            gl.glVertex3d(-1, 1, 0);
        }
        gl.glEnd();        

        gl.glBegin(GL2.GL_POLYGON);
        {
            gl.glVertex3d(0, 0, 2);
            gl.glVertex3d(-1, -1, 0);
            gl.glVertex3d(1, -1, 0);
        }
        gl.glEnd();        

        gl.glBegin(GL2.GL_POLYGON);
        {
            gl.glVertex3d(0, 0, 2);
            gl.glVertex3d(1, -1, 0);
            gl.glVertex3d(1, 1, 0);
        }
        gl.glEnd();        

i) The base is pointing inwards.

ii) The first side is pointing outwards

iii) The second side is pointing inwards.

iv) The third side is pointing outwards.

v) The fourth side is pointing outwards.

The image below shows view facing the second face (which is invisible). You can see the first and second triangle faces (pointing outwards) and the base (pointing inwards).

If you look at the image from behind everything disappears.

Question 2: Depth buffer and transparency

Use bilinear interpolation to work out the pixel depths for the triangle below, given the coordinates and pseudo-depth values for the vertices as stated. Calculate depth values to two decimal places.

Interpolated depths:

Show the result of copying the triangle into the depth buffer that already has the rectangle below in it

Image drawn with depth buffer:

Note that by default depth buffer values range from 0 for near to 1 for far. And also by default each fragment must have a depth LESS_THAN the pseudodepth in the buffer otherwise it is not drawn.

Suppose the green rectangle is transparent (with alpha = 0.25) and rgb values of (0.3,0.6,0.15) and the triangle is opaque (with alpha value = 1) and the rgb values of the triangle are (0.7,0,0.9). What does the resulting image look like in this case with standard alpha blending? What are the rgb values of the different pixels?

The rectangle is drawn first so it gets blended with the white background. The calculations would be

dest(rgb) = 0.25 (0.3,0.6,0.15) + 0.75(1,1,1) = (0.825,0.9,0.7875) 

When the triangle gets drawn, the parts that are in front of the rectangle just get drawn over the top. No blending occurs as the triangle is opaque.

Suppose the rectangle is opaque( with alpha 1) and the triangle is transparent (with alpha = 0.25). What does the resulting image look like in this case? What are the rgb values of the different pixels?

The rectangle is drawn first and is opaque so no blending occurs with the white background. The triangle is transparent, so the arts that are in front of the rectangle would be blended with the rectangle. The parts behind the rectangle would not be drawn and the parts covering the background would be blended with the background white.

For the pixels blended with the rectangle we would get
dest(rgb) = 0.25(0.7,0,0.9)  + 0.75(0.3,0.6,0.15) =  (0.4,0.45,0.3375)

For the pixels blended with the background we would get
dest(rgb) = 0.25(0.7,0,0.9)  + 0.75(1,1,1) =  (0.925,0.75,0.975)  

Question 3: BSP trees

Consider the dungeon map below:

Assuming each wall is a single polygon, and assigning normals as you see fit, build a BSP tree for this map. There are many possible trees, depending on the order in which you choose polygons. What is the smallest tree you can find?

If the player is in the position marked, what order should the polygons be drawn so that all hidden surfaces are renderered properly?

The smallest tree is obtained working from the outside in, as shown below. The tree is completely unbalanced but since the traversal algorithm visits every polygon in any case, it doesn't particularly affect affect run time.

With this tree and the player in the position marked, the polygons would be drawn in order 1, 2, 3, 4, 5, 6, 7, 8. In each case the player is in front of the polygon and there are no polygons behind it.

An example of a larger tree would be the following tree where the ordering has resulted in polygons having to be split.

For this tree I would draw them in the following order : 8, 2b, 5b, 6b, 4b, 6f, 7, 1, 2f, 3, 5f, 4f

Question 4: Illumination

Suppose you have modelled a vertex with the following material properties (assume emissive co-efficients are default values of 0).
float amb[]  = {0.0f, 0.0f, 0.1f, 1.0f};
float diff[] = {0.0f, 0.0f, 0.5f, 1.0f};
float spec[] = {1.0f, 1.0f, 1.0f, 1.0f};
float f[] = { 10.0f }; //phong exponent

gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT, amb,0);
gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, diff,0);
gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_SPECULAR, spec,0);
gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_SHININESS, f,0);        	

And a light source with the following properties

float lightAmb[] = { 0.2f, 0.2f, 0.2f, 1.0f };
float lightDifAndSpec[] = { 1, 1, 1, 1 };
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT,  lightAmb,0);
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE,  lightDifAndSpec,0);
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, lightDifAndSpec,0);

float[] globAmb =  {0.1f, 0.1f, 0.1f, 1.0f};
gl.glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globAmb, 0);

//Calculate the camera viewpoint properly instead of using hack.
gl.glLightModeli(GL2.GL_LIGHT_MODEL_LOCAL_VIEWER, GL2.GL_TRUE); 

Assume

Assume these have already been transformed into camera/eye co-ordinates.
  1. Calculate the diffuse component rgb values for the vertex

    For this we need the direction to the lightsource(s) and the normal (m). These should both be normalised. We then need to take their dot product and multiply by the diffuse co-efficients for the material and the lighting.

    s = (0,3,2) - (0,0,-2) = (0,3,4)
    |s| = sqrt(0+9+16) = 5
    s_unit = (0,0.6,0.8)
    
    s_unit.m = (0,0.6,0.8) . (0,0,1) = 0.8
    
    diffuse(r,g,b) = (0,0,0.5*1*0.8) = (0,0,0.4)
    
  2. Calculate the specular component rgb values assuming we are using the blinn-phong specular model.

    For this we need the halfway vector which we need the direction to the lightsource(s) and the direction to the view/camera (v). We already calculated the direction to the light source. Since we are in camera co-ordinates the view/camera is at (0,0,0)

    v = (0,0,0) - (0,0,-2) = (0,0,2)
    |v| = sqrt(4) = 2
    v_unit = (0,0,1)
    h = s_unit +v_unit =  (0,0.6,0.8) + (0,0,1) = (0,0.6,1.8)
    |h| = sqrt(0.36+3.24)
    h_unit = (0,0.32,0.95)
    
    h_unit.m = (0,0.32,0.95).(0,0,1) = 0.95
    pow(0.95,10) = 0.60
    specular(r,g,b) = (1*1*0.6,1*1*0.6,1*1*0.6) = (0.6,0.6,0.6)
    
  3. Calculate the total rgb values for the vertex.
    globalAmbient = (0.1*0,0.1*0,0.1*0.1) = (0,0,0.01)
    ambient = (0.2*0,0.2*0,0.2*0.1) = (0,0,0.02)
    total(r,g,b) = globalAmbient + ambient + diffuse + specular
                 = (0,0,0.01) + (0,0,0.02) + (0,0,0.4) + (0.6,0.6,0.6)
                 = (0.6,0.6,1.03)
    the actual values get clamed to 1 so we would get
    (0.6,0.6,1)