CS 457/557 -- Winter Quarter 2024

Project #7B

100 Points

Due: March 8

This project is an alternative to the Geometry Shader Project #7 for those who do not have access to a system that can handle Geometry Shaders. All others must do the Geometry Shader Project #7.

You may not use glman for this project.

Twisting


This page was last updated: March 4, 2024


Introduction

Un-twisted Twisted about Y

The goal of this project is to twist an OBJ-defined object.

What is twisting anyway? "Twisting" is a rotation about an axis where the angle of rotation is proportional to the distance away from the origin along that axis. Half the object is getting a positive twist while the other half is getting a negative twist. (See the video for an example.) Think of what it is like to twist a dishrag.

  1. The object needs to have per-fragment lighting. Feel free to hardcode numbers for Ka, Kd, Ks, and Shininess.
  2. The object also needs to have some sort of "hatching" linework applied procedurally in the fragment shader. (The point of the hatching is to make it easier to see the twisting.) It might be best to key off of s or t, but x, y, or z in model coordinates might work too. The hatching only has to be in one direction. (In the images above, I was experimenting with doing it in two directions. You don't have to do that.) You might re-look at the Stripes, Rings, and Dots noteset.

Requirements:

  1. Read in an OBJ file. The choice of object is up to you. Use your LoadObjFile( ) function to read it in.

  2. Be sure the OBJ file has surface normals (vn) so that you can light it.

  3. The twisting can occur about the X, Y, or Z axis, you can pick. Different objects look better twisted in different directions. You have rotate functions below for all three directions.

  4. You need to animate the twisting. This can be done with keytiming or by using the Time variable (see below).

  5. The hatching must be stripe-ish. Ellipses do not count as "hatching".

Turn-in:

Use the Teach system to turn in your:

  1. .cpp file
  2. A one-page PDF with a title, your name, your email address, a nice screen shot from your program, and the link to the video demonstrating that your project does what the requirements ask for. Narrate your video so that you can tell us what it is doing.

Timing Your Scene Animation

  1. You can use Keytime animation, or,
  2. You can set a constant called something like MS_PER_CYCLE that specifies the number of milliseconds per animation cycle. Then, in your Idle Function, query the number of milliseconds since your program started and turn that into a floating point number between 0. and 1. that indicates how far through the animation cycle you are. So, in Animate( ), you might say:
    
    #define MS_PER_CYCLE	10000
    . . .
    int ms = glutGet( GLUT_ELAPSED_TIME );
    ms %= MS_PER_CYCLE;
    Time = (float)ms / (float)MS_PER_CYCLE;		// [0.,1.)
    

Then, in Display( ), convert whatever you did into an amount of twisting to apply and send that over to your vertex shader as a uniform variable.

Setting up the Object Display List:

In InitGraphics( ):

glGenLists( 1, &MyObjectList );
glNewList( MyObjectList, GL_COMPILE );
	LoadObjFile( (char *)"dino.obj" );
glEndList( );

In Display( ):


float twist = ?????;
Pattern.Use( );
Pattern.SetUniformVariable( "uTwist", twist );
glCallList( MyObjectList );
Pattern.UnUse;

How to do the Rotations:


vec3
RotateX( vec3 xyz, float radians )
{
	float c = cos(radians);
	float s = sin(radians);
	vec3 newxyz = xyz;
	newxyz.yz = vec2(
		dot( xyz.yz, vec2( c,-s) ),
		dot( xyz.yz, vec2( s, c) )
	);
	return newxyz;
}

vec3
RotateY( vec3 xyz, float radians )
{
	float c = cos(radians);
	float s = sin(radians);
	vec3 newxyz = xyz;
	newxyz.xz =vec2(
		dot( xyz.xz, vec2( c,s) ),
		dot( xyz.xz, vec2(-s,c) )
	);
	return newxyz;
}

vec3
RotateZ( vec3 xyz, float radians )
{
	float c = cos(radians);
	float s = sin(radians);
	vec3 newxyz = xyz;
	newxyz.xy = vec2(
		dot( xyz.xy, vec2( c,-s) ),
		dot( xyz.xy, vec2( s, c) )
	);
	return newxyz;
}

Suggestions for Hatching:

Get ideas from the Stripes, Rings, and Dots noteset. Some of this might help you. (or not...)


in vec2  vST;
in vec3  vMC;

float
SmoothPulse( float left, float right,   float value, float tol )
{
	float t =	smoothstep( left-tol,  left+tol,  value )  -
			smoothstep( right-tol, right+tol, value );
	return t;
}


// in main( ):
	float numin? = int( ??? / ??? );
	float ?c = numin?*??? + ???/2.;
	float tp = SmoothPulse( ???, ???, ???, ??? );

	vec3 myColor = mix( ???, ???, tp );
	vec3 mySpecularColor = vec3( 1.0, 1.0, 1.0 );
	. . .

Extra Credit (+5 points)

Add a ChromaDepth feature that colors the scene by eye coordinate depth: red in the front, Blue in the back, and Green in the middle. Include an option which turns the use of ChromaDepth on and off.

I have glasses which will use the ChromaDepth colors to make your scene look really 3D, although you (and we) will know if it is working without having the glasses. Please do not touch the plastic lenses on the glasses. Human fingerprints are nearly impossible to get off them.

uRedDepth and uBlueDepth are meant to be the Z depths in eye coordinates at which the ChromaDepth color interpolation starts and ends. You can make these variable, or you can hardcode them if you find good values for them.


// in the vertex shader:
out float	vZ;
. . .
	vZ = -ECposition.z;


// in the fragment shader:
in float                vZ;
. . .
vec3
Rainbow( float t )
{
        t = clamp( t, 0., 1. );         // 0.00 is red, 0.33 is green, 0.67 is blue

        float r = 1.;
        float g = 0.0;
        float b = 1.  -  6. * ( t - (5./6.) );

        if( t <= (5./6.) )
        {
                r = 6. * ( t - (4./6.) );
                g = 0.;
                b = 1.;
        }

        if( t <= (4./6.) )
        {
                r = 0.;
                g = 1.  -  6. * ( t - (3./6.) );
                b = 1.;
        }

        if( t <= (3./6.) )
        {
                r = 0.;
                g = 1.;
                b = 6. * ( t - (2./6.) );
        }

        if( t <= (2./6.) )
        {
                r = 1.  -  6. * ( t - (1./6.) );
                g = 1.;
                b = 0.;
        }

        if( t <= (1./6.) )
        {
                r = 1.;
                g = 6. * t;
        }

        return vec3( r, g, b );
}

. . .

        vec3 myColor = ?????
        vec3 mySpecularColor = vec3( 1.0, 1.0, 1.0 );

        if( uUseChromaDepth )
        {
                float t = (2./3.) * ( abs(vZ) - uRedDepth ) / ( uBlueDepth - uRedDepth );
                t = clamp( t, 0., 2./3. );
                myColor = Rainbow( t );
        }

If you want to see more ChromaDepth examples, click here.

Grading:

Item Points
Using an OBJ file 10
Correct per-fragment lighting (we look for the bright spot) 20
Some sort of stripe-ish hatching done procedurally (not a texture, not ellipses) 30
Some sort of twisting of the object 10
Animation of the twisting 30
Extra Credit 5
Potential Total 105