HW2: Wireframe rendering using 'Processing'
Summary
You need to create a program to implement wireframe rendering of a scene specified via a text file. You will implement this using the 'Processing' platform. See 'Description' below for details.
Due date
Nov. 10 '08, by midnight (late Mon. night).
No extensions. Also, there is a penalty of 5% for each day you're late.
Score
10% of the total (HW1, Midterm, HW2, HW3 and Final are worth 10%, 15%, 10%, 30% and 35% respectively). 20% (of the 10%) extra credit is also
available - see below.
How to submit
Please use Blackboard to submit your work. For this homework, all you need to submit is a single Processing source file, with a '.pde' extension (eg. 'Scott_HW2.pde') and a README file that explains how to run your program (esp. important if you are
implementing extra-credit code). If you are not familiar with how to submit via Blackboard, please see a TA/Grader and learn how. Email submissions will NOT be accepted.
Platforms
PC/Mac/Linux.
Description
Your program needs to read an input 'scene' file [which specifies mesh(es) and their object->world transforms, camera information and output window size], and draw a 'wireframe' version of the scene. As you may recall, a wireframe mesh shows the outlines (not fills) of polygons comprising the mesh.
The scene file format that your program needs to read in ("parse") is as follows (see lecture slides for explanations of the camera spec. etc.]:
xres yres
px py pz ux uy uz vx vy vz nx ny nz
near far top bottom left right
r g b rx ry rz sx sy sz tx ty tz meshname.sff
... [more 'r g b rx ry rz sx sy sz tx ty tz meshname.sff' entries]
As you can see from the above, the scene specification is pretty simple:
- the first line contains xres,yres of the output window
- the second line contains the camera specification (location, orientation). Note - in the corresponding lecture slide, the
camera location (px,py,pz) is refered to as the position vector 'r'.
- the third line specifies the six view volume limits for perspective projection
- from the fourth line on, there are one or more entries that specify the object(s) [meshes] in the scene. 'r g b' specifies the mesh color. rx, ry and rz specify rotation angles, in degrees, about the X, Y and Z axes respectively (and are applied in that order: X, Y, then Z). sx, sy and sz specify scaling. tx, ty and tz specify translation. Finally, meshname.sff indicates the polymesh object undergoing the transformations just mentioned. There can be more meshes in the scene, specified using additional lines similar to the one just described. These .sff meshes are separate, independent files on disk.
Notes:
- the rotation angles rx ry and rz are (already) in radians, suitable for use with sin() and cos(). In other words, no need to do a deg-to-rad conversion on them.
- an sff vertex will always undergo transformations in this fixed order: rx -> ry -> rz -> s -> t -> cam -> NDC -> raster
- you need to write your own code (eg. a small function) to multiply a point by a matrix, ie. to do: pNew = pOld*xformMat, where pOld is a 'current' 4D homogenous coordinate, xformMat is a 4x4 matrix, one of rx/ry/rz/s/t/cam/NDC, and pNew is the transformed result. You are not to use the builtin matrix class (PMatrix3D) or add-on libraries' matrix calls.
- be sure to divide the NDC coordinates' 'x' and 'y' values by 'w' (the fourth coordinate, which usually will NOT be 1) after the perspective (NDC) transformation and before converting to integer raster values. In other words, do something like 'x = x/w; y = y/w' before using 'x' and 'y' to derive 2D integer raster (pixel) coordinates suitable for line drawing.
The only thing left is to describe a .sff ("simple file format") mesh. Here is how an octahedron (made of 8 tris) is represented in .sff:
8
3
1 0 0
0 0 1
0 1 0
3
0 1 0
0 0 1
-1 0 0
3
-1 0 0
0 0 1
0 -1 0
3
0 -1 0
0 0 1
1 0 0
3
1 0 0
0 1 0
0 0 -1
3
0 1 0
-1 0 0
0 0 -1
3
-1 0 0
0 -1 0
0 0 -1
3
0 -1 0
1 0 0
0 0 -1
The very first value (8, in the above example) indicates how many polys are in the mesh. Following that is data for each of those polys. For each poly, a vertex (or equivalently, edge) count comes first, followed by x,y,z position data for each of those vertices (or edges). Note the indentations for the vertex count and vertex data! Using 'b' for blank space, here is how the above
data is laid out:
8
b3
bbb1 0 0
bbb0 0 1
bbb0 1 0
...
...
The leading blank spaces do matter if you are using Processing's split() call to tokenize each line.
Platforms
PC/Mac/Linux.
Description
Your program needs to read an input 'scene' file [which specifies mesh(es) and their object->world transforms, camera information and output window size], and draw a 'wireframe' version of the scene. As you may recall, a wireframe mesh shows the outlines (not fills) of polygons comprising the mesh.
The scene file format that your program needs to read in ("parse") is as follows (see lecture slides for explanations of the camera spec. etc.]:
xres yres
px py pz ux uy uz vx vy vz nx ny nz
near far top bottom left right
r g b rx ry rz sx sy sz tx ty tz meshname.sff
... [more 'r g b rx ry rz sx sy sz tx ty tz meshname.sff' entries]
As you can see from the above, the scene specification is pretty simple:
- the first line contains xres,yres of the output window
- the second line contains the camera specification (location, orientation). Note - in the corresponding lecture slide, the
camera location (px,py,pz) is refered to as the position vector 'r'.
- the third line specifies the six view volume limits for perspective projection
- from the fourth line on, there are one or more entries that specify the object(s) [meshes] in the scene. 'r g b' specifies the mesh color. rx, ry and rz specify rotation angles, in degrees, about the X, Y and Z axes respectively (and are applied in that order: X, Y, then Z). sx, sy and sz specify scaling. tx, ty and tz specify translation. Finally, meshname.sff indicates the polymesh object undergoing the transformations just mentioned. There can be more meshes in the scene, specified using additional lines similar to the one just described. These .sff meshes are separate, independent files on disk.
Notes:
- the rotation angles rx ry and rz are (already) in radians, suitable for use with sin() and cos(). In other words, no need to do a deg-to-rad conversion on them.
- an sff vertex will always undergo transformations in this fixed order: rx -> ry -> rz -> s -> t -> cam -> NDC -> raster
- you need to write your own code (eg. a small function) to multiply a point by a matrix, ie. to do: pNew = pOld*xformMat, where pOld is a 'current' 4D homogenous coordinate, xformMat is a 4x4 matrix, one of rx/ry/rz/s/t/cam/NDC, and pNew is the transformed result. You are not to use the builtin matrix class (PMatrix3D) or add-on libraries' matrix calls.
- be sure to divide the NDC coordinates' 'x' and 'y' values by 'w' (the fourth coordinate, which usually will NOT be 1) after the perspective (NDC) transformation and before converting to integer raster values. In other words, do something like 'x = x/w; y = y/w' before using 'x' and 'y' to derive 2D integer raster (pixel) coordinates suitable for line drawing.
The only thing left is to describe a .sff ("simple file format") mesh. Here is how an octahedron (made of 8 tris) is represented in .sff:
8
3
1 0 0
0 0 1
0 1 0
3
0 1 0
0 0 1
-1 0 0
3
-1 0 0
0 0 1
0 -1 0
3
0 -1 0
0 0 1
1 0 0
3
1 0 0
0 1 0
0 0 -1
3
0 1 0
-1 0 0
0 0 -1
3
-1 0 0
0 -1 0
0 0 -1
3
0 -1 0
1 0 0
0 0 -1
The very first value (8, in the above example) indicates how many polys are in the mesh. Following that is data for each of those polys. For each poly, a vertex (or equivalently, edge) count comes first, followed by x,y,z position data for each of those vertices (or edges). Note the indentations for the vertex count and vertex data! Using 'b' for blank space, here is how the above
data is laid out:
8
b3
bbb1 0 0
bbb0 0 1
bbb0 1 0
...
...
The leading blank spaces do matter if you are using Processing's split() call to tokenize each line.
xres yres px py pz ux uy uz vx vy vz nx ny nz near far top bottom left right r g b rx ry rz sx sy sz tx ty tz meshname.sff ... [more 'r g b rx ry rz sx sy sz tx ty tz meshname.sff' entries]As you can see from the above, the scene specification is pretty simple:
- the first line contains xres,yres of the output window
- the second line contains the camera specification (location, orientation). Note - in the corresponding lecture slide, the camera location (px,py,pz) is refered to as the position vector 'r'.
- the third line specifies the six view volume limits for perspective projection
- from the fourth line on, there are one or more entries that specify the object(s) [meshes] in the scene. 'r g b' specifies the mesh color. rx, ry and rz specify rotation angles, in degrees, about the X, Y and Z axes respectively (and are applied in that order: X, Y, then Z). sx, sy and sz specify scaling. tx, ty and tz specify translation. Finally, meshname.sff indicates the polymesh object undergoing the transformations just mentioned. There can be more meshes in the scene, specified using additional lines similar to the one just described. These .sff meshes are separate, independent files on disk.
- the rotation angles rx ry and rz are (already) in radians, suitable for use with sin() and cos(). In other words, no need to do a deg-to-rad conversion on them.
- an sff vertex will always undergo transformations in this fixed order: rx -> ry -> rz -> s -> t -> cam -> NDC -> raster
- you need to write your own code (eg. a small function) to multiply a point by a matrix, ie. to do: pNew = pOld*xformMat, where pOld is a 'current' 4D homogenous coordinate, xformMat is a 4x4 matrix, one of rx/ry/rz/s/t/cam/NDC, and pNew is the transformed result. You are not to use the builtin matrix class (PMatrix3D) or add-on libraries' matrix calls.
- be sure to divide the NDC coordinates' 'x' and 'y' values by 'w' (the fourth coordinate, which usually will NOT be 1) after the perspective (NDC) transformation and before converting to integer raster values. In other words, do something like 'x = x/w; y = y/w' before using 'x' and 'y' to derive 2D integer raster (pixel) coordinates suitable for line drawing.
8 3 1 0 0 0 0 1 0 1 0 3 0 1 0 0 0 1 -1 0 0 3 -1 0 0 0 0 1 0 -1 0 3 0 -1 0 0 0 1 1 0 0 3 1 0 0 0 1 0 0 0 -1 3 0 1 0 -1 0 0 0 0 -1 3 -1 0 0 0 -1 0 0 0 -1 3 0 -1 0 1 0 0 0 0 -1The very first value (8, in the above example) indicates how many polys are in the mesh. Following that is data for each of those polys. For each poly, a vertex (or equivalently, edge) count comes first, followed by x,y,z position data for each of those vertices (or edges). Note the indentations for the vertex count and vertex data! Using 'b' for blank space, here is how the above data is laid out:
8 b3 bbb1 0 0 bbb0 0 1 bbb0 1 0 ... ...The leading blank spaces do matter if you are using Processing's split() call to tokenize each line.
Here are some sample .sff meshes.
At the heart of it, your program will typically contain these three nested loops:
for each mesh in the scene
for each polygon in the mesh
for each edge (pair of vertices) of the polygon
draw a digital line after transforming pairs of vertices (xfms are O -> W -> C -> NDC -> S, see 'Notes' above)
To draw lines you can use either your own line-drawing code from HW1, or the built-in line() call. Remember to flip (mirror) the 'y' values since Processing's (0,0) lies at the top-left corner of the output window instead of bottom-left. Also, if your lines don't show up and they should, do 'strokeWidth(1);' to explicitly set line width.
That's it.. HAVE FUN!
Sample input/output
Here are two simple inputs and outputs:Scene file, eg. 'scene.txt':
600 600 0 0 5 1 0 0 0 1 0 0 0 1 1 10 1 -1 -1 1 128 128 128 2.5 0.5 0 1. 1. 1. -.15 0.1 0 cutcube.sffResult:
Another scene file:
600 600 0.5 1 2 1 0 0 0 1 0 0 0 1 1 10 1 -1 -1 1 128 60 255 0 0.1 0 .1 .1 .1 0. 1.27 0 teapot_faceted.sff 128 128 128 0 1.57 0 1. 1. 1. 0. 0.5 0 endtable.sffOutput: