⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 t3dlib5.cpp

📁 3D游戏编程大师技巧第十章的源代码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
                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 + -