750 likes | 812 Views
This module covers local to world object transformation, 3D engine data structures, and polygon rendering techniques for a 3D pipeline. Learn about 3D object creation, polygon rasterization, and PLX file loading functions.
E N D
3D Wireframe Rendering CIS 488/588 Bruce R. Maxim UM-Dearborn
Local to World Object Transformation void Model_To_World_RENDERLIST4DV1 (RENDERLIST4DV1_PTR rend_list, POINT4D_PTR world_pos, int coord_select) // NOTE: Not matrix based // this function converts the local model coordinates of the // sent render list into world coordinates, the results are // stored in the transformed vertex list (tvlist) within the // renderlist // iterate thru vertex list and transform all the // model/local coords to world coords by translating the // vertex list bythe amount world_pos and storing the // results in tvlist[] is this polygon valid?
3D Engine • Based on three data structures introduced in the previous chapter • Polygon structure based on a vertex list (POLY4DV1_TYP) • Self-contained polygon structure (POLYF4DV1_TYP) • Object structure containing polygons (OBJECT4DV1_TYP)
Master Polygon List - 1 typedef struct RENDERLIST4DV1_TYP { int state; // state of renderlist ??? int attr; // attributes of renderlist ??? // the render list is an array of pointers each pointing to // a self contained "renderable" polygon face POLYF4DV1 POLYF4DV1_PTR poly_ptrs[RENDERLIST4DV1_MAX_POLYS]; // additionally to cut down on allocatation, de-allocation // of polygons each frame, here's where the actual polygon // faces will be stored POLYF4DV1 poly_data[RENDERLIST4DV1_MAX_POLYS]; int num_polys; // number of polys in render list } RENDERLIST4DV1, *RENDERLIST4DV1_PTR;
Master Polygon List - 2 • The state and attr fields are used to track the list state and attributes • The arrays poly_ptrs[ ] and polydata[ ] make up what is called an indirection list (the pointers are sorted not the data) they are called index vertex buffers in Direct3D • This is defined in the new software modules T3DLIB5 (.H and .CPP)
Creating/Loading Objects • Perform local-world transformation • Object removal (optional) • Back-face removal (optional) • Perform world-camera transformation • 3D Clipping (optional) • Perform camera-perspective projection • Perform perspective-screen transformation • Rasterize polygons
PLX File Loader • LaMothe has modified the PLG descriptor to create a PLX file • Bit d15 d0 CSSD RRRR GGGG BBBBB C = RGB/indexed color flag SS = define shading mode D = double-sided flag RRRR GGGG BBBB = bits for RGB mode GGGGBBBB = 8bit color index
PLX Functions - 1 char *Get_Line_PLG(char *buffer, int maxlength, FILE *fp); // this little helper function simply read past // comments and blank lines in a PLG file and always // returns full lines with something on them or NULL // if the file is empty
PLX Functions - 2 int Load_OBJECT4DV1_PLG(OBJECT4DV1_PTR obj, // object pointer char *filename, // plg filename VECTOR4D_PTR scale, // initial scaling factors VECTOR4D_PTR pos, // initial position VECTOR4D_PTR r // initial rotations // this function loads a plg object in off disk, additionally // it allows the caller to scale, position, and rotate the object // to save extra calls later for non-dynamic objects • Note this function basically recognizes white space and comments delineated by #
How it works • First line of file controls number of vertices and polygons to read in • The vertex list is read and inserted in the OBJECT4DV1 object • Polygons are inserted with their flags and color models which are translated to POLY_ATTR flags • Also computes average and maximum radius for collection detection and removal
Using the function OBJECT4Dv1 obj; // object storage VECTOR4D scale = {1,1,1,1}, // no scaling pos = {0,0,0,1}, // pos (0,0,0) in world rot = {0,0,0,1}; // no rotation // load object Load_OBJECT4DV1_PLG(&obj,”cube.plg”,&scale,&pos,&rot);
Building 3D Pipeline • You may need to keep a copy of the original vertex data for a later pipeline phase • In POLYF4DV1, vlist[3] contains the orginal triangle vertices and tvlist[3] contains the transformed vertices • In OBJHECT4DV1, vlist_local[ ] contains the array of original local vertices and vlist_trans[ ] contains the array of transformed vertices • You would also want to transform the entire list of polygons at once
Transforming List void Transform_RENDERLIST4DV1 (RENDERLIST4DV1_PTR rend_list, // render list to // transform MATRIX4X4_PTR mt, // transformation matrix int coord_select) // selects coords to transform // 0 = local only // 1 = use transformed vlist and overwrite // 2 = transform local vlist and overwrite // transformed storage // this function simply transforms all of the polygons // vertices in the local or trans array of the render // list by the sent matrix
Transforming One Object void Transform_OBJECT4DV1 (OBJECT4DV1_PTR obj, // object to transform MATRIX4X4_PTR mt, // transformation matrix int coord_select, // selects coords to // transform int transform_basis) // flags if vector // orientation should // be transformed too // this function simply transforms all of the vertices // in the local or transarray by the sent matrix
Local to World Object Transformation void Model_To_World_RENDERLIST4DV1 (RENDERLIST4DV1_PTR rend_list, POINT4D_PTR world_pos, int coord_select) // NOTE: Not matrix based // this function converts the local model coordinates of the // sent render list into world coordinates, the results are // stored in the transformed vertex list (tvlist) within the // renderlist // iterate thru vertex list and transform all the // model/local coords to world coords by translating the // vertex list bythe amount world_pos and storing the // results in tvlist[] is this polygon valid?
Camera Model - 1 typedef struct CAM4DV1_TYP { int state; // state of camera int attr; // camera attributes POINT4D pos; // world position used by both camera models VECTOR4D dir; // angles or look at direction of camera for // simple euler camera models, elevation and // heading foruvn model VECTOR4D u; // extra vectors to track camera orientation VECTOR4D v; // for more complex UVN camera model VECTOR4D n; VECTOR4D target; // look at target float view_dist; // focal length float fov; // field of view for horiz & vert axes
Camera Model - 2 // 3d clipping planes // if view volume is NOT 90 degree then general 3d clipping // must be employed float near_clip_z; // near z=constant clipping plane float far_clip_z; // far z=constant clipping plane PLANE3D rt_clip_plane; // the right clipping plane PLANE3D lt_clip_plane; // the left clipping plane PLANE3D tp_clip_plane; // the top clipping plane PLANE3D bt_clip_plane; // the bottom clipping plane float viewplane_width; // width and height of view plane // to project onto
Camera Model - 3 float viewplane_height; // usually 2x2 for normalized // projection or the exact same // size as the viewport or screen // remember screen and viewport are synonomous float viewport_width; // size of screen/viewport float viewport_height; float viewport_center_x; // center of view port // (final image destination) float viewport_center_y; float aspect_ratio;
Camera Model - 4 // these matrices are not necessarily needed based on the // method oftransformation, for example, a manual // perspective or screen transformand or a concatenated // perspective/screen, however, having these matrices give // us more flexibility MATRIX4X4 mcam; // storage for the world to camera MATRIX4X4 mper; // storage for the camera to perspective MATRIX4X4 mscr; // storage for the perspective to screen } CAM4DV1, *CAM4DV1_PTR;
Differences Between Euler and UNV Camera • Euler camera defined by position and rotation angles that make up its orientation • In the UNV camera adds the look at the target and uses vectors U, N, V n – similar to z-axis always points toward target v – “up vector” similar to y-axis (starts as <0,1,0> once u is computed becomes v = n x u) u – “right vector” computed as u = n x v
UVN Matrix Muvn • Transforming XYZ system to UNV p’ = p(x,y,z) * Muvn = (p • u, p • v, p • n) | ux vx nx 0 | [xy z 1] * | uy vy ny 0 | | uz vz nz 0 | | 0 0 0 1 |
Camera Positioning Tuvn = Tcam-1 * Muvn = | 1 0 0 0 | | ux vx nx 0 | | 0 1 0 0 | * | uy vy ny 0 | = | 0 0 1 0 | | uz vz nz 0 | | -cam_x –cam_y –cam_z 1 | | 0 0 0 1 | | ux vx nx 0 | | uy vy ny 0 | | uz vz nz 0 | |-(cam_pos • u) -(cam_pos • u) -(cam_pos • u) 1 |
Finding u, v, n • n = <target position-view reference point> • v = <0, 1, 0> • u = (v x n) • v = (n x u) • (Optional) Normalize u,v,n by dividing each vector by its length (if not already done)
Spherical UNV Setup • Assume camera is sitting at p(,,) P = target vector = length of P = elevation angle = heading angle r = length of projection of P on the x-z plane x = - r * sin() y = * cos() z = r * cos() • x,y,z are for rhs and require transformation x = -y y = z z = x
Initializing Camera void Init_CAM4DV1 (CAM4DV1_PTR cam, // the camera object int cam_attr, // attributes POINT4D_PTR cam_pos, // initial camera position VECTOR4D_PTR cam_dir, // initial camera angles POINT4D_PTR cam_target, // UVN target float near_clip_z, // near and far clipping planes float far_clip_z, float fov, // field of view in degrees float viewport_width, // size of final screen viewport float viewport_height) // this function initializes the camera object cam, the // functiondoesn't do a lot of error checking or sanity // checking since I want to allow you to create projections // as you wish
Initializing Euler Camera void Init_CAM4DV1 (&cam, // the camera object CAM_MODEL_EULER, // attributes &cam_pos, // initial camera position &cam_dir, // initial camera angles NULL, // for Euler 50.0, // near and far clipping planes 500.0, 90.0, // field of view in degrees 400, // size of final screen viewport 400)
Initializing UNV Camera void Init_CAM4DV1 (&cam, // the camera object CAM_MODEL_UNV, // attributes &cam_pos, // initial camera position &cam_dir, // initial camera angles &cam_target, // initial target for UNV 50.0, // near and far clipping planes 500.0, 90.0, // field of view in degrees 640, // size of final screen viewport 480)
Position CameraEuler void Build_CAM4DV1_Matrix_Euler (CAM4DV1_PTR cam, int cam_rot_seq) // this creates a camera matrix based on Euler angles // and stores it in the sent camera object // we need to create a transformation matrix that looks like: // Mcam = mt(-1) * my(-1) * mx(-1) * mz(-1) // that is the inverse of the camera translation matrix // mutilplied by the inverses of yxz, in that order, however, // the order of the rotation matrices is really up to you, so // we aren't going to force any order, thus its programmable // based on the value of cam_rot_seq which can be any value // CAM_ROT_SEQ_XYZ where XYZ can be in any order, YXZ, ZXY, // etc.
Position CameraUNV void Build_CAM4DV1_Matrix_UVN(CAM4DV1_PTR cam, int mode) // this creates a camera matrix based on a look at vector n, // look up vector v, and a look right (or left) u and stores // it in the sent camera object, all values are extracted out // of the camera object itself and mode selects how uvn is // computed // UVN_MODE_SIMPLE - low level simple model, use the target // and view reference point // UVN_MODE_SPHERICAL - spherical mode, the x,y components // will be used as the elevation and // heading of the view vector // respectively along with the view // reference point as the position // as usual
World-Camera Transform • If you want the YXZ ordering Twc = T-1cam * R-1camy * R-1camx R-1camz • If you want the ZYX ordering Twc = T-1cam * R-1camz * R-1camy R-1camx • Functions to build Euler and UNV cameras exist so functions to apply the transformations to objects and render lists are all that are needed
World-CameraObject void World_To_Camera_OBJECT4DV1 (OBJECT4DV1_PTR obj, CAM4DV1_PTR cam) // NOTE: this is a matrix based function // this function transforms the world coordinates of an object // into camera coordinates, based on the sent camera matrix // but it totally disregards the polygons themselves, // it only works on the vertices in the vlist_trans[] list // assumes the object has already been transformed to world // coordinates and the result is in vlist_trans[]
World-CameraRender List void World_To_Camera_RENDERLIST4DV1 (RENDERLIST4DV1_PTR rend_list, CAM4DV1_PTR cam) // NOTE: this is a matrix based function // this function transforms each polygon in the global render // listto camera coordinates based on the sent camera // transform matrixyou would use this function instead of the // object based functionif you decided earlier in the // pipeline to turn each object into a list of polygons and // then add them to the global render listthe conversion of // an object into polygons probably would havehappened after // object culling, local transforms, local to worldand // backface culling, so the minimum number of polygons from // each object are in the list, note that the function assumes // that at LEAST the local to world transform has been called // and the polygon data is in the transformed list tvlist of // the POLYF4DV1 object
Object Culling • Removing unnecessary objects so that they won’t be processed during entire 3D pipeline • Culling can be performed in world space or camera space • LaMothe prefers to cull in camera space by transforming the object center and using a bounding sphere to determine inclusion or exclusion based on the object radius
Object Culling int Cull_OBJECT4DV1 (OBJECT4DV1_PTR obj, // object to cull CAM4DV1_PTR cam, // camera to cull relative to int cull_flags) // clipping planes to consider // NOTE: is matrix based // this function culls an entire object from the viewing // frustrum by using the sent camera information and object // the cull_flags determine what axes culling should take // place x, y, z or all which is controlled by ORing the flags // together if the object is culled its state is modified // thats all this function assumes that both the camera and // the object are valid!
Resetting Flags void Reset_OBJECT4DV1(OBJECT4DV1_PTR obj) // this function resets the sent object and redies it // for future transformations, basically just resets // the culled, clipped andbackface flags, but here's // where you would add stuff to ready any object for // the pipeline
Back-face Removal • Process of removing polygons that are facing away from the viewport • Test is performed on every polygon of the object in the render list (can remove 50% of one sided polygons before performing the world-to-camera transform) • The angle between the viewport direction vector and the surface normal is computed, if angle > 90 or n • l <= 0 then object not visible
Back-face RemovalObject void Remove_Backfaces_OBJECT4DV1 (OBJECT4DV1_PTR obj, CAM4DV1_PTR cam) // NOTE: this is not a matrix based function // this function removes the backfaces from an object's // polygon mesh, the function does this based on the // vertexdata in vlist_trans along with the camera // position (only) // note: // that only the backface state is set in each polygon // tests to see if the object is already culled
Back-face RemovalRender List void Remove_Backfaces_RENDERLIST4DV1 (RENDERLIST4DV1_PTR rend_list, CAM4DV1_PTR cam) // NOTE: this is not a matrix based function // this function removes the backfaces from polygon // listthe function does this based on the polygon // list datatvlist along with camera position (only) // note: // that only the backface state is set in each polygon
Camera-to-Perspective • Basic transform is xper = viewing_distance * x_world/z_world yper = viewing_distance * aspect_ratio * y_world/z_world • Two approaches: manual or matrix • However, can’t divide by z using matrices without first doing 4D homogeneous to 3Dconversions • This makes the matrix version slow in software, but hardware may provide some acceleration for the matrix version
Perspective TransformObjects void Camera_To_Perspective_OBJECT4DV1 (OBJECT4DV1_PTR obj, CAM4DV1_PTR cam) // NOTE: this is not a matrix based function // this function transforms the camera coordinates of an // objectinto perspective coordinates, based on the sent // camera object, but it totally disregards the polygons // themselves,it only works on the vertices in the // vlist_trans[] list assumes the object has already been // transformed to cameracoordinates // finally this function is really for experimental reasons // onlyyou would probably never let an object stay intact // this far downthe pipeline, since it's probably that // there's only a single polygonthat is visible! But this // function has to transform the whole mesh!
Matrix Version • To implement a matrix version we would need to use the following call sequence MATRIX4X4 mper; Build_Camera_To_Perspective_Matrix4X4(&cam, &mper); Transform_OBJECT4DV1 (&obj, &mper, TRANSFORM_TRANS_ONLY); Convert_From_Homogeneous4D_OBJECT4DV1 (&obj);
Build Camera Perspective void Build_Camera_To_Perspective_MATRIX4X4 (CAM4DV1_PTR cam, MATRIX4X4_PTR m) // function builds up camera to perspective transformation // matrix, in most cases camera would have a 2x2 normalized // view plane with a 90 degree FOV, since the point of the // having this matrix must be to also have a perspective to // screen (viewport) matrix that scales the normalized // coordinates, also the matrix assumes that you are working // in 4D homogenous coordinates and at some point there will // be a 4D->3D conversion, it might be immediately after this // transform is applied to vertices, or after the perspective // to screen transform
Conversion From 4D void Convert_From_Homogeneous4D_OBJECT4DV1 (OBJECT4DV1_PTR obj) // this function converts all vertices in the // transformedvertex list from 4D homogeneous // coordinates to normal 3D coordinatesby dividing // each x,y,z component by w
Perspective TransformRender Lists void Camera_To_Perspective_RENDERLIST4DV1 (RENDERLIST4DV1_PTR rend_list, CAM4DV1_PTR cam) // NOTE: this is not a matrix based function // this function transforms each polygon in the global render // listinto perspective coordinates, based on the sent camera // object, ou would use this function instead of the object // based function if you decided earlier in the pipeline to // turn each object into a list of polygons and then add them // to the global render list // transform each polygon in the render list into camera // coordinatesassumes the render list has already been // transformed to world coordinates and the result is in // tvlist[] of each polygon object
Matrix Version • To implement a matrix version we would need to use the following call sequence MATRIX4X4 mper; Build_Camera_To_Perspective_Matrix4X4(&cam, &mper); Transform_RENDERLIST4DV1 (&rend_list, &mper, TRANSFORM_TRANS_ONLY); Convert_From_Homogeneous4D_RENDERLIST4DV1 (&rend_list);