📄 t3dlib5.cpp
字号:
0, -beta, 0, 0,
alpha, beta, 1, 0,
0, 0, 0, 1);
} // end Build_Perspective_To_Screen_4D_MATRIX4X4()
//////////////////////////////////////////////////////////
void Build_Perspective_To_Screen_MATRIX4X4(CAM4DV1_PTR cam, MATRIX4X4_PTR m)
{
// this function builds up a perspective to screen transformation
// matrix, the function assumes that you want to perform the
// transform in 2D/3D coordinates, that is, you have already converted
// the perspective coordinates from homogenous 4D to 3D before applying
// this matrix, additionally
// the point of this matrix to to scale and translate the perspective
// coordinates to screen coordinates, thus the matrix is built up
// assuming that the perspective coordinates are in normalized form for
// a 2x2 viewplane, that is, x: -1 to 1, y:-1 to 1
// the only difference between this function and the version that
// assumes the coordinates are still in homogenous format is the
// last column doesn't force w=z, in fact the z, and w results
// are irrelevent since we assume that BEFORE this matrix is applied
// all points are already converted from 4D->3D
float alpha = (0.5*cam->viewport_width-0.5);
float beta = (0.5*cam->viewport_height-0.5);
Mat_Init_4X4(m, alpha, 0, 0, 0,
0, -beta, 0, 0,
alpha, beta, 1, 0,
0, 0, 0, 1);
} // end Build_Perspective_To_Screen_MATRIX4X4()
///////////////////////////////////////////////////////////
void Build_Camera_To_Screen_MATRIX4X4(CAM4DV1_PTR cam, MATRIX4X4_PTR m)
{
// this function creates a single matrix that performs the
// entire camera->perspective->screen transform, the only
// important thing is that the camera must be created with
// a viewplane specified to be the size of the viewport
// furthermore, after this transform is applied the the vertex
// must be converted from 4D homogeneous to 3D, technically
// the z is irrelevant since the data would be used for the
// screen, but still the division by w is needed no matter
// what
float alpha = (0.5*cam->viewport_width-0.5);
float beta = (0.5*cam->viewport_height-0.5);
Mat_Init_4X4(m, cam->view_dist, 0, 0, 0,
0, -cam->view_dist, 0, 0,
alpha, beta, 1, 1,
0, 0, 0, 0);
} // end Build_Camera_To_Screen_MATRIX4X4()
///////////////////////////////////////////////////////////
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 trans
// array by the sent matrix
// what coordinates should be transformed?
switch(coord_select)
{
case TRANSFORM_LOCAL_ONLY:
{
// transform each local/model vertex of the object mesh in place
for (int vertex=0; vertex < obj->num_vertices; vertex++)
{
POINT4D presult; // hold result of each transformation
// transform point
Mat_Mul_VECTOR4D_4X4(&obj->vlist_local[vertex], mt, &presult);
// store result back
VECTOR4D_COPY(&obj->vlist_local[vertex], &presult);
} // end for index
} break;
case TRANSFORM_TRANS_ONLY:
{
// transform each "transformed" vertex of the object mesh in place
// remember, the idea of the vlist_trans[] array is to accumulate
// transformations
for (int vertex=0; vertex < obj->num_vertices; vertex++)
{
POINT4D presult; // hold result of each transformation
// transform point
Mat_Mul_VECTOR4D_4X4(&obj->vlist_trans[vertex], mt, &presult);
// store result back
VECTOR4D_COPY(&obj->vlist_trans[vertex], &presult);
} // end for index
} break;
case TRANSFORM_LOCAL_TO_TRANS:
{
// transform each local/model vertex of the object mesh and store result
// in "transformed" vertex list
for (int vertex=0; vertex < obj->num_vertices; vertex++)
{
POINT4D presult; // hold result of each transformation
// transform point
Mat_Mul_VECTOR4D_4X4(&obj->vlist_local[vertex], mt, &obj->vlist_trans[vertex]);
} // end for index
} break;
default: break;
} // end switch
// finally, test if transform should be applied to orientation basis
// hopefully this is a rotation, otherwise the basis will get corrupted
if (transform_basis)
{
// now rotate orientation basis for object
VECTOR4D vresult; // use to rotate each orientation vector axis
// rotate ux of basis
Mat_Mul_VECTOR4D_4X4(&obj->ux, mt, &vresult);
VECTOR4D_COPY(&obj->ux, &vresult);
// rotate uy of basis
Mat_Mul_VECTOR4D_4X4(&obj->uy, mt, &vresult);
VECTOR4D_COPY(&obj->uy, &vresult);
// rotate uz of basis
Mat_Mul_VECTOR4D_4X4(&obj->uz, mt, &vresult);
VECTOR4D_COPY(&obj->uz, &vresult);
} // end if
} // end Transform_OBJECT4DV1
///////////////////////////////////////////////////////////
void Rotate_XYZ_OBJECT4DV1(OBJECT4DV1_PTR obj, // object to rotate
float theta_x, // euler angles
float theta_y,
float theta_z)
{
// this function rotates and object parallel to the
// XYZ axes in that order or a subset thereof, without
// matrices (at least externally sent)
// modifies the object's local vertex list
// additionally it rotates the unit directional vectors
// that track the objects orientation, also note that each
// time this function is called it calls the rotation generation
// function, this is wastefull if a number of object are being rotated
// by the same matrix, therefore, if that's the case, then generate the
// rotation matrix, store it, and call the general Transform_OBJECT4DV1()
// with the matrix
MATRIX4X4 mrot; // used to store generated rotation matrix
// generate rotation matrix, no way to avoid rotation with a matrix
// too much math to do manually!
Build_XYZ_Rotation_MATRIX4X4(theta_x, theta_y, theta_z, &mrot);
// now simply rotate each point of the mesh in local/model coordinates
for (int vertex=0; vertex < obj->num_vertices; vertex++)
{
POINT4D presult; // hold result of each transformation
// transform point
Mat_Mul_VECTOR4D_4X4(&obj->vlist_local[vertex], &mrot, &presult);
// store result back
VECTOR4D_COPY(&obj->vlist_local[vertex], &presult);
} // end for index
// now rotate orientation basis for object
VECTOR4D vresult; // use to rotate each orientation vector axis
// rotate ux of basis
Mat_Mul_VECTOR4D_4X4(&obj->ux, &mrot, &vresult);
VECTOR4D_COPY(&obj->ux, &vresult);
// rotate uy of basis
Mat_Mul_VECTOR4D_4X4(&obj->uy, &mrot, &vresult);
VECTOR4D_COPY(&obj->uy, &vresult);
// rotate uz of basis
Mat_Mul_VECTOR4D_4X4(&obj->uz, &mrot, &vresult);
VECTOR4D_COPY(&obj->uz, &vresult);
} // end Rotate_XYZ_OBJECT4DV1
////////////////////////////////////////////////////////////
void Model_To_World_OBJECT4DV1(OBJECT4DV1_PTR obj, int coord_select)
{
// NOTE: Not matrix based
// this function converts the local model coordinates of the
// sent object into world coordinates, the results are stored
// in the transformed vertex list (vlist_trans) within the object
// interate thru vertex list and transform all the model/local
// coords to world coords by translating the vertex list by
// the amount world_pos and storing the results in vlist_trans[]
if (coord_select == TRANSFORM_LOCAL_TO_TRANS)
{
for (int vertex=0; vertex < obj->num_vertices; vertex++)
{
// translate vertex
VECTOR4D_Add(&obj->vlist_local[vertex], &obj->world_pos, &obj->vlist_trans[vertex]);
} // end for vertex
} // end if local
else
{ // TRANSFORM_TRANS_ONLY
for (int vertex=0; vertex < obj->num_vertices; vertex++)
{
// translate vertex
VECTOR4D_Add(&obj->vlist_trans[vertex], &obj->world_pos, &obj->vlist_trans[vertex]);
} // end for vertex
} // end else trans
} // end Model_To_World_OBJECT4DV1
////////////////////////////////////////////////////////////
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!
// step 1: transform the center of the object's bounding
// sphere into camera space
POINT4D sphere_pos; // hold result of transforming center of bounding sphere
// transform point
Mat_Mul_VECTOR4D_4X4(&obj->world_pos, &cam->mcam, &sphere_pos);
// step 2: based on culling flags remove the object
if (cull_flags & CULL_OBJECT_Z_PLANE)
{
// cull only based on z clipping planes
// test far plane
if ( ((sphere_pos.z - obj->max_radius) > cam->far_clip_z) ||
((sphere_pos.z + obj->max_radius) < cam->near_clip_z) )
{
SET_BIT(obj->state, OBJECT4DV1_STATE_CULLED);
return(1);
} // end if
} // end if
if (cull_flags & CULL_OBJECT_X_PLANE)
{
// cull only based on x clipping planes
// we could use plane equations, but simple similar triangles
// is easier since this is really a 2D problem
// if the view volume is 90 degrees the the problem is trivial
// buts lets assume its not
// test the the right and left clipping planes against the leftmost and rightmost
// points of the bounding sphere
float z_test = (0.5)*cam->viewplane_width*sphere_pos.z/cam->view_dist;
if ( ((sphere_pos.x-obj->max_radius) > z_test) || // right side
((sphere_pos.x+obj->max_radius) < -z_test) ) // left side, note sign change
{
SET_BIT(obj->state, OBJECT4DV1_STATE_CULLED);
return(1);
} // end if
} // end if
if (cull_flags & CULL_OBJECT_Y_PLANE)
{
// cull only based on y clipping planes
// we could use plane equations, but simple similar triangles
// is easier since this is really a 2D problem
// if the view volume is 90 degrees the the problem is trivial
// buts lets assume its not
// test the the top and bottom clipping planes against the bottommost and topmost
// points of the bounding sphere
float z_test = (0.5)*cam->viewplane_height*sphere_pos.z/cam->view_dist;
if ( ((sphere_pos.y-obj->max_radius) > z_test) || // top side
((sphere_pos.y+obj->max_radius) < -z_test) ) // bottom side, note sign change
{
SET_BIT(obj->state, OBJECT4DV1_STATE_CULLED);
return(1);
} // end if
} // end if
// return failure to cull
return(0);
} // end Cull_OBJECT4DV1
////////////////////////////////////////////////////////////
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 vertex
// data in vlist_trans along with the camera position (only)
// note that only the backface state is set in each polygon
// test if the object is culled
if (obj->state & OBJECT4DV1_STATE_CULLED)
return;
// process each poly in mesh
for (int poly=0; poly < obj->num_polys; poly++)
{
// acquire polygon
POLY4DV1_PTR curr_poly = &obj->plist[poly];
// is this polygon valid?
// test this polygon if and only if it's not clipped, not culled,
// active, and visible and not 2 sided. Note we test for backface in the event that
// a previous call might have already determined this, so why work
// harder!
if (!(curr_poly->state & POLY4DV1_STATE_ACTIVE) ||
(curr_poly->state & POLY4DV1_STATE_CLIPPED ) ||
(curr_poly->attr & POLY4DV1_ATTR_2SIDED) ||
(curr_poly->state & POLY4DV1_STATE_BACKFACE) )
continue; // move onto next poly
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -