所有的3D效果,都是基于数学的支撑,以下是3DUI中用到的数学基础:
#pragma once //======================================================================== // Geometry.h : Collection of code for 3D math and 3D shapes //======================================================================== //======================================================================== // Content References in Game Coding Complete 3rd Edition // // class Vec3 // class Vec4 // class Mat4x4 // class Quaternion // class Plane // class Frustum // const float GCC_PI = 3.14159265358979f; const float GCC_2PI = 2 * GCC_PI; //////////////////////////////////////////////////// // // Utility classes for vectors and matrices // //////////////////////////////////////////////////// typedef D3DXVECTOR2 Vec2; //////////////////////////////////////////////////// // // Vec3 Description // // //////////////////////////////////////////////////// typedef struct D3DXVECTOR3 { float x; float y; float z; } D3DXVECTOR3, *LPD3DXVECTOR3; class Vec3 : public D3DXVECTOR3 { public: inline float Length() { return D3DXVec3Length(this); } // 法线向量 inline Vec3 *Normalize() { return static_cast<Vec3 *>(D3DXVec3Normalize(this, this)); } // 两个向量的点乘 和 两个向量的叉乘 inline float Dot(const Vec3 &b) { return D3DXVec3Dot(this, &b); } inline Vec3 Cross(const Vec3 &b) const; Vec3(D3DXVECTOR3 &v3) { x = v3.x; y = v3.y; z = v3.z; } Vec3() : D3DXVECTOR3() { x = 0; y = 0; z = 0; } Vec3(const float _x, const float _y, const float _z) { x=_x; y=_y; z=_z; } Vec3(const double _x, const double _y, const double _z) { x = (float)_x; y = (float)_y; z = (float)_z; } inline Vec3(const class Vec4 &v4); }; inline Vec3 Vec3::Cross(const Vec3 &b) const { Vec3 out; D3DXVec3Cross(&out, this, &b); return out; } //////////////////////////////////////////////////// // // Vec4 Description // // //////////////////////////////////////////////////// typedef struct D3DXVECTOR4 { float x; float y; float z; float w; } D3DXVECTOR4, *LPD3DXVECTOR4; class Vec4 : public D3DXVECTOR4 { public: inline float Length() { return D3DXVec4Length(this); } inline Vec4 *Normalize() { return static_cast<Vec4 *>(D3DXVec4Normalize(this, this)); } // If you want the cross product, use Vec3::Cross inline float Dot(const Vec4 &b) { return D3DXVec4Dot(this, &b); } Vec4(D3DXVECTOR4 &v4) { x = v4.x; y = v4.y; z = v4.z; w = v4.w; } Vec4() : D3DXVECTOR4() { } Vec4(const float _x, const float _y, const float _z, const float _w) { x=_x; y=_y; z=_z; w=_w; } Vec4(const Vec3 &v3) { x = v3.x; y = v3.y; z = v3.z; w = 1.0f; } }; inline Vec3::Vec3(const Vec4 &v4) { x = v4.x; y = v4.y; z = v4.z; } extern Vec3 g_Up; extern Vec3 g_Right; extern Vec3 g_Forward; extern Vec4 g_Up4; extern Vec4 g_Right4; extern Vec4 g_Forward4; //////////////////////////////////////////////////// // // Vec3List Description // Vec4List Description // // An STL list of Vectors // //////////////////////////////////////////////////// typedef std::list<Vec3> Vec3List; typedef std::list<Vec4> Vec4List; //////////////////////////////////////////////////// // // Quaternion Description // // //////////////////////////////////////////////////// typedef struct D3DXQUATERNION { float x; float y; float z; float w; } D3DXQUATERNION, *LPD3DXQUATER class Quaternion : public D3DXQUATERNION { public: // Modifiers void Normalize() { D3DXQuaternionNormalize(this, this); }; void Slerp(const Quaternion &begin, const Quaternion &end, float cooef) { // performs spherical linear interpolation between begin & end // NOTE: set cooef between 0.0f-1.0f D3DXQuaternionSlerp(this, &begin, &end, cooef); } // Accessors void GetAxisAngle(Vec3 &axis, float &angle) const { D3DXQuaternionToAxisAngle(this, &axis, &angle); } // Initializers void Build(const class Mat4x4 &mat); void BuildRotYawPitchRoll( const float yawRadians, const float pitchRadians, const float rollRadians) { D3DXQuaternionRotationYawPitchRoll(this, yawRadians, pitchRadians, rollRadians); } void BuildAxisAngle(const Vec3 &axis, const float radians) { D3DXQuaternionRotationAxis(this, &axis, radians); } Quaternion(D3DXQUATERNION &q) : D3DXQUATERNION(q) { } Quaternion() { } static const Quaternion g_Identity; }; inline Quaternion operator * (const Quaternion &a, const Quaternion &b) { // for rotations, this is exactly like concatenating // matrices - the new quat represents rot A followed by rot B. Quaternion out; D3DXQuaternionMultiply(&out, &a, &b); return out; } //////////////////////////////////////////////////// // // Mat4x4 Description // // //////////////////////////////////////////////////// typedef struct D3DXMATRIX { float _ij; } D3DXMATRIX, *LPD3DXMATRIX; class Mat4x4 : public D3DXMATRIX { public: // Modifiers inline void SetPosition(Vec3 const &pos); inline void SetPosition(Vec4 const &pos); inline void SetScale(Vec3 const &scale); // Accessors and Calculation Methods inline Vec3 GetPosition() const; inline Vec3 GetDirection() const; inline Vec3 GetUp() const; inline Vec3 GetRight() const; inline Vec3 GetYawPitchRoll() const; inline Vec3 GetScale() const; inline Vec4 Xform(Vec4 &v) const; inline Vec3 Xform(Vec3 &v) const; inline Mat4x4 Inverse() const; Mat4x4(D3DXMATRIX &mat) { memcpy(&m, &mat.m, sizeof(mat.m)); } Mat4x4() : D3DXMATRIX() { } static const Mat4x4 g_Identity; // Initialization methods inline void BuildTranslation(const Vec3 &pos); inline void BuildTranslation(const float x, const float y, const float z ); inline void BuildRotationX(const float radians) { D3DXMatrixRotationX(this, radians); } inline void BuildRotationY(const float radians) { D3DXMatrixRotationY(this, radians); } inline void BuildRotationZ(const float radians) { D3DXMatrixRotationZ(this, radians); } inline void BuildYawPitchRoll(const float yawRadians, const float pitchRadians, const float rollRadians) { D3DXMatrixRotationYawPitchRoll(this, yawRadians, pitchRadians, rollRadians); } inline void BuildRotationQuat(const Quaternion &q) { D3DXMatrixRotationQuaternion(this, &q); } inline void BuildRotationLookAt(const Vec3 &eye, const Vec3 &at, const Vec3 &up) { D3DXMatrixLookAtRH(this, &eye, &at, &up); } inline void BuildScale(const float x, const float y, const float z ); }; inline void Mat4x4::SetPosition(Vec3 const &pos) { m[3][0] = pos.x; m[3][1] = pos.y; m[3][2] = pos.z; m[3][3] = 1.0f; } inline void Mat4x4::SetPosition(Vec4 const &pos) { m[3][0] = pos.x; m[3][1] = pos.y; m[3][2] = pos.z; m[3][3] = pos.w; } inline void Mat4x4::SetScale(Vec3 const &scale) { m[1][1] = scale.x; m[2][2] = scale.y; m[3][3] = scale.z; } inline Vec3 Mat4x4::GetPosition() const { return Vec3(m[3][0], m[3][1], m[3][2]); } inline Vec3 Mat4x4::GetDirection() const { // Note - the following code can be used to double check the vector construction above. Mat4x4 justRot = *this; justRot.SetPosition(Vec3(0.f,0.f,0.f)); Vec3 forward = justRot.Xform(g_Forward); return forward; } inline Vec3 Mat4x4::GetRight() const { // Note - the following code can be used to double check the vector construction above. Mat4x4 justRot = *this; justRot.SetPosition(Vec3(0.f,0.f,0.f)); Vec3 right = justRot.Xform(g_Right); return right; } inline Vec3 Mat4x4::GetUp() const { // Note - the following code can be used to double check the vector construction above. Mat4x4 justRot = *this; justRot.SetPosition(Vec3(0.f,0.f,0.f)); Vec3 up = justRot.Xform(g_Up); return up; } inline Vec3 Mat4x4::GetYawPitchRoll() const { float yaw, pitch, roll; pitch = asin(-_32); double threshold = 0.001; // Hardcoded constant - burn him, he's a witch double test = cos(pitch); if(test > threshold) { roll = atan2(_12, _22); yaw = atan2(_31, _33); } else { roll = atan2(-_21, _11); yaw = 0.0; } return (Vec3(yaw, pitch, roll)); } inline Vec3 Mat4x4::GetScale() const { return Vec3(m[0][0], m[1][1], m[2][2]); } inline Vec4 Mat4x4::Xform(Vec4 &v) const { Vec4 temp; D3DXVec4Transform(&temp, &v, this); return temp; } inline Vec3 Mat4x4::Xform(Vec3 &v) const { Vec4 temp(v); Vec4 out; D3DXVec4Transform(&out, &temp, this); return Vec3(out.x, out.y, out.z); } inline Mat4x4 Mat4x4::Inverse() const { Mat4x4 out; D3DXMatrixInverse(&out, NULL, this); return out; } inline void Mat4x4::BuildTranslation(const Vec3 &pos) { *this = Mat4x4::g_Identity; m[3][0] = pos.x; m[3][1] = pos.y; m[3][2] = pos.z; } inline void Mat4x4::BuildTranslation(const float x, const float y, const float z ) { *this = Mat4x4::g_Identity; m[3][0] = x; m[3][1] = y; m[3][2] = z; } inline void Mat4x4::BuildScale(const float x, const float y, const float z ) { *this = Mat4x4::g_Identity; m[1][1] = x; m[2][2] = y; m[3][3] = z; } inline Mat4x4 operator * (const Mat4x4 &a, const Mat4x4 &b) { Mat4x4 out; D3DXMatrixMultiply(&out, &a, &b); return out; } inline void Quaternion::Build(const Mat4x4 &mat) { D3DXQuaternionRotationMatrix(this, &mat); } //////////////////////////////////////////////////// // // D3D9 Vertex Type Definitions // // TRANSFORMED_VERTEX Description // UNTRANSFORMED_VERTEX Description // UNTRANSFORMED_LIT_VERTEX Description // D3D9Vertex_UnlitColored Description // D3D9Vertex_ColoredTextured Description // D3D9Vertex_Colored Description // // Note: There's been a slight change from the book in this code. // Instead of #define D3DFVF_BlahBlah they are static constants; // find them at the top of Geometry.cpp // // See Game Coding Complete, 3rd Edition, Chapter 13, page 440-444 //////////////////////////////////////////////////// // A structure for our custom vertex type. We added texture coordinates struct D3D9Vertex_Colored { D3DXVECTOR3 position; // The position D3DCOLOR color; // The color static const DWORD FVF; }; // A structure for our custom vertex type. We added texture coordinates struct D3D9Vertex_ColoredTextured { D3DXVECTOR3 position; // The position D3DCOLOR color; // The color float tu, tv; // The texture coordinates static const DWORD FVF; }; struct D3D9Vertex_UnlitColored { D3DXVECTOR3 position; // The position in 3D space D3DXVECTOR3 normal; // The normal vector (must be 1.0 units in length) D3DCOLOR diffuse; // The diffuse color D3DCOLOR specular; // The specular color static const DWORD FVF; }; struct D3D9Vertex_UnlitTextured { D3DXVECTOR3 position; D3DXVECTOR3 normal; float tu, tv; static const DWORD FVF; }; struct D3D11_SimpleVertex { Vec3 Pos; Vec3 Normal; }; struct D3D11Vertex_UnlitTextured { Vec3 Pos; Vec3 Normal; Vec2 Uv; }; // Create our vertex input layout const D3D11_INPUT_ELEMENT_DESC D3D11VertexLayout_UnlitTextured[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_float, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_float, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_float, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; struct D3D11Vertex_UnlitTexturedColored { Vec3 Pos; Vec3 Normal; Vec3 Diffuse; Vec2 Uv; }; // Create our vertex input layout const D3D11_INPUT_ELEMENT_DESC D3D11VertexLayout_UnlitTexturedColored[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_float, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_float, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32_float, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_float, 0, 36, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; struct D3D11Vertex_PositionColored { Vec3 Pos; Vec3 Diffuse; }; const D3D11_INPUT_ELEMENT_DESC D3D11VertexLayout_PositionColored[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_float, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32_float, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; const D3D11_INPUT_ELEMENT_DESC D3D11VertexLayout_Position[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_float, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; //////////////////////////////////////////////////// // // TriangleIterator Definition - added post press // // Allows a variety of different vertex buffers to be iterated as // a series of triangles. // //////////////////////////////////////////////////// class TriangleIterator { protected: Vec3 *m_Triangles; unsigned int m_Size; public: TriangleIterator() { m_Triangles=0; m_Size=0; } virtual ~TriangleIterator() { SAFE_DELETE_ARRAY(m_Triangles); } bool InitializeStrippedMesh(LPDIRECT3DVERTEXBUFFER9 pVerts, int stride, int strips, int *triCountList ); virtual unsigned int VGetSize() { return m_Size; } virtual void *VGet(unsigned int i); }; //////////////////////////////////////////////////// // // Plane Definition // //////////////////////////////////////////////////// class Plane : public D3DXPLANE { public: inline void Normalize(); // normal faces away from you if you send in verts in counter clockwise order.... inline void Init(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2); bool Inside(const Vec3 &point, const float radius) const; bool Inside(const Vec3 &point) const; }; inline void Plane::Normalize() { float mag; mag = sqrt(a * a + b * b + c * c); a = a / mag; b = b / mag; c = c / mag; d = d / mag; } inline void Plane::Init(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2) { D3DXPlaneFromPoints(this, &p0, &p1, &p2); Normalize(); } //////////////////////////////////////////////////// // // Frustum Definition // //////////////////////////////////////////////////// class Frustum { public: enum Side { Near, Far, Top, Right, Bottom, Left, NumPlanes }; Plane m_Planes[NumPlanes]; // planes of the frusum in camera space Vec3 m_NearClip[4]; // verts of the near clip plane in camera space Vec3 m_FarClip[4]; // verts of the far clip plane in camera space float m_Fov; // field of view in radians float m_Aspect; // aspect ratio - width divided by height float m_Near; // near clipping distance float m_Far; // far clipping distance public: Frustum(); bool Inside(const Vec3 &point) const; bool Inside(const Vec3 &point, const float radius) const; const Plane &Get(Side side) { return m_Planes[side]; } void SetFOV(float fov) { m_Fov=fov; Init(m_Fov, m_Aspect, m_Near, m_Far); } void SetAspect(float aspect) { m_Aspect=aspect; Init(m_Fov, m_Aspect, m_Near, m_Far); } void SetNear(float nearClip) { m_Near=nearClip; Init(m_Fov, m_Aspect, m_Near, m_Far); } void SetFar(float farClip) { m_Far=farClip; Init(m_Fov, m_Aspect, m_Near, m_Far); } void Init(const float fov, const float aspect, const float near, const float far); void Render(); }; inline Vec3 CalcVelocity(Vec3 const &pos0, Vec3 const &pos1, float time) { // CalcVelocity - Chapter 15, page 526 return (pos1 - pos0) / time; } inline Vec3 CalcAcceleration(Vec3 const &vel0, Vec3 const &vel1, float time) { // CalcVelocity - Chapter 15, page 526 return (vel1 - vel0) / time; } inline void HandleAccel(Vec3 &pos, Vec3 &vel, Vec3 &accel, float time) { // CalcVelocity - Chapter 15, page 526 vel += accel * time; pos += vel * time; } // converts Barycentric coordinates to world coordinates // inputs are the 3 verts of the triangle, and the u,v barycentric coordinates extern Vec3 BarycentricToVec3(Vec3 v0, Vec3 v1, Vec3 v2, float u, float v); extern bool IntersectTriangle( const Vec3& orig, const Vec3& dir, Vec3& v0, Vec3& v1, Vec3& v2, float* t, float* u, float* v );
//======================================================================== // Geometry.cpp : Collection of code for 3D math and 3D shapes //======================================================================== #include "GameCodeStd.h" #include "Geometry.h" //======================================================================== // // Note - FVFs are part of the fixed function pipeline, and were described in // Game Coding Complete, 3rd Edition. // // Our custom FVF, which describes our custom vertex structure // These were #define'd in the book - now they are static constants. // const DWORD D3D9Vertex_UnlitColored::FVF = (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_SPECULAR); const DWORD D3D9Vertex_ColoredTextured::FVF = (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1); const DWORD D3D9Vertex_Colored::FVF = (D3DFVF_XYZ|D3DFVF_DIFFUSE); const DWORD D3D9Vertex_UnlitTextured::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; const Mat4x4 Mat4x4::g_Identity(D3DXMATRIX(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)); const Quaternion Quaternion::g_Identity(D3DXQUATERNION(0,0,0,1)); bool Plane::Inside(const Vec3 &point) const { // Inside the plane is defined as the direction the normal is facing float result = D3DXPlaneDotCoord(this, &point); return (result >= 0.0f); } bool Plane::Inside(const Vec3 &point, const float radius) const { float fDistance; // calculate our distances to each of the planes // find the distance to this plane fDistance = D3DXPlaneDotCoord(this, &point); // if this distance is < -radius, we are outside return (fDistance >= -radius); } // // Frustum::Frustum - // Frustum::Frustum() { m_Fov = GCC_PI/4.0f; // default field of view is 90 degrees m_Aspect = 1.0f; // default aspect ratio is 1:1 m_Near = 1.0f; // default near clip plane is 1m away from the camera m_Far = 1000.0f; // default near clip plane is 100m away from the camera } // // Frustum::Inside // bool Frustum::Inside(const Vec3 &point) const { for (int i=0; i<NumPlanes; ++i) { if (!m_Planes[i].Inside(point)) return false; } return true; } // // Frustum::Inside // bool Frustum::Inside(const Vec3 &point, const float radius) const { for(int i = 0; i < NumPlanes; ++i) { if (!m_Planes[i].Inside(point, radius)) return false; } // otherwise we are fully in view return(true); } // // Frustum::Init // void Frustum::Init(const float fov, const float aspect, const float nearClip, const float farClip) { m_Fov = fov; m_Aspect = aspect; m_Near = nearClip; m_Far = farClip; float tanFovOver2 = (float)tan(m_Fov/2.0f); Vec3 nearRight = (m_Near * tanFovOver2) * m_Aspect * g_Right; Vec3 farRight = (m_Far * tanFovOver2) * m_Aspect * g_Right; Vec3 nearUp = (m_Near * tanFovOver2 ) * g_Up; Vec3 farUp = (m_Far * tanFovOver2) * g_Up; // points start in the upper right and go around clockwise m_NearClip[0] = (m_Near * g_Forward) - nearRight + nearUp; m_NearClip[1] = (m_Near * g_Forward) + nearRight + nearUp; m_NearClip[2] = (m_Near * g_Forward) + nearRight - nearUp; m_NearClip[3] = (m_Near * g_Forward) - nearRight - nearUp; m_FarClip[0] = (m_Far * g_Forward) - farRight + farUp; m_FarClip[1] = (m_Far * g_Forward) + farRight + farUp; m_FarClip[2] = (m_Far * g_Forward) + farRight - farUp; m_FarClip[3] = (m_Far * g_Forward) - farRight - farUp; // now we have all eight points. Time to construct 6 planes. // the normals point away from you if you use counter clockwise verts. Vec3 origin(0.0f, 0.0f, 0.0f); m_Planes[Near].Init(m_NearClip[2], m_NearClip[1], m_NearClip[0]); m_Planes[Far].Init(m_FarClip[0], m_FarClip[1], m_FarClip[2]); m_Planes[Right].Init(m_FarClip[2], m_FarClip[1], origin); m_Planes[Top].Init(m_FarClip[1], m_FarClip[0], origin); m_Planes[Left].Init(m_FarClip[0], m_FarClip[3], origin); m_Planes[Bottom].Init(m_FarClip[3], m_FarClip[2], origin); } // // Frustum::Render // void Frustum::Render() { D3D9Vertex_Colored verts[24]; for (int i=0; i<8; ++i) { verts[i].color = g_White; } for (int i=0; i<8; ++i) { verts[i+8].color = g_Red; } for (int i=0; i<8; ++i) { verts[i+16].color = g_Blue; } // Draw the near clip plane verts[0].position = m_NearClip[0]; verts[1].position = m_NearClip[1]; verts[2].position = m_NearClip[1]; verts[3].position = m_NearClip[2]; verts[4].position = m_NearClip[2]; verts[5].position = m_NearClip[3]; verts[6].position = m_NearClip[3]; verts[7].position = m_NearClip[0]; // Draw the far clip plane verts[8].position = m_FarClip[0]; verts[9].position = m_FarClip[1]; verts[10].position = m_FarClip[1]; verts[11].position = m_FarClip[2]; verts[12].position = m_FarClip[2]; verts[13].position = m_FarClip[3]; verts[14].position = m_FarClip[3]; verts[15].position = m_FarClip[0]; // Draw the edges between the near and far clip plane verts[16].position = m_NearClip[0]; verts[17].position = m_FarClip[0]; verts[18].position = m_NearClip[1]; verts[19].position = m_FarClip[1]; verts[20].position = m_NearClip[2]; verts[21].position = m_FarClip[2]; verts[22].position = m_NearClip[3]; verts[23].position = m_FarClip[3]; DWORD oldLightMode; DXUTGetD3D9Device()->GetRenderState( D3DRS_LIGHTING, &oldLightMode ); DXUTGetD3D9Device()->SetRenderState( D3DRS_LIGHTING, FALSE ); DXUTGetD3D9Device()->SetFVF( D3D9Vertex_Colored::FVF ); DXUTGetD3D9Device()->DrawPrimitiveUP( D3DPT_LINELIST, 12, verts, sizeof(D3D9Vertex_Colored) ); DXUTGetD3D9Device()->SetRenderState( D3DRS_LIGHTING, oldLightMode ); } Vec3 BarycentricToVec3(Vec3 v0, Vec3 v1, Vec3 v2, float u, float v) { //V1 + U(V2 - V1) + V(V3 - V1). Vec3 result = v0 + u * (v1 - v0) + v * (v2 - v0); return result; } //-------------------------------------------------------------------------------------- // Given a ray origin (orig) and direction (dir), and three vertices of a triangle, this // function returns TRUE and the interpolated texture coordinates if the ray intersects // the triangle //-------------------------------------------------------------------------------------- bool IntersectTriangle( const Vec3& orig, const Vec3& dir, Vec3& v0, Vec3& v1, Vec3& v2, FLOAT* t, FLOAT* u, FLOAT* v ) { // Find vectors for two edges sharing vert0 Vec3 edge1 = v1 - v0; Vec3 edge2 = v2 - v0; // Begin calculating determinant - also used to calculate U parameter Vec3 pvec; D3DXVec3Cross( &pvec, &dir, &edge2 ); // If determinant is near zero, ray lies in plane of triangle FLOAT det = D3DXVec3Dot( &edge1, &pvec ); Vec3 tvec; if( det > 0 ) { tvec = orig - v0; } else { tvec = v0 - orig; det = -det; } if( det < 0.0001f ) return FALSE; // Calculate U parameter and test bounds *u = D3DXVec3Dot( &tvec, &pvec ); if( *u < 0.0f || *u > det ) return FALSE; // Prepare to test V parameter Vec3 qvec; D3DXVec3Cross( &qvec, &tvec, &edge1 ); // Calculate V parameter and test bounds *v = D3DXVec3Dot( &dir, &qvec ); if( *v < 0.0f || *u + *v > det ) return FALSE; // Calculate t, scale parameters, ray intersects triangle *t = D3DXVec3Dot( &edge2, &qvec ); FLOAT fInvDet = 1.0f / det; *t *= fInvDet; *u *= fInvDet; *v *= fInvDet; return TRUE; } bool TriangleIterator::InitializeStrippedMesh(LPDIRECT3DVERTEXBUFFER9 pVerts, int stride, int strips, int *triCountList ) { char *pVertices = NULL; if( FAILED( pVerts->Lock( 0, 0, (void**)&pVertices, 0 ) ) ) return false; for (int i=0; i<strips; ++i) { m_Size += triCountList[i]; } m_Triangles = GCC_NEW Vec3[m_Size * 3]; int src = 0; int dest = 0; for (int strip=0; strip<strips; ++strip ) { int vertsInStrip = triCountList[strip]+2; GCC_ASSERT(vertsInStrip); m_Triangles[dest] = *((Vec3*)&pVertices[stride * src]); m_Triangles[dest+1] = *((Vec3*)&pVertices[stride * (src+1)]); m_Triangles[dest+2] = *((Vec3*)&pVertices[stride * (src+2)]); dest+=3; src+=3; for (int tri=1; tri<triCountList[strip]; ++tri) { // for every extra vertex in the triangle strip, you have to grab // the two previous verts in the dest list, reverse them, and copy them // forward. This will give you a triangle with the same winding m_Triangles[dest] = m_Triangles[dest-1]; m_Triangles[dest+1] = m_Triangles[dest-2]; m_Triangles[dest+2] = *((Vec3*)&pVertices[stride * (++src)]); dest+=3; } } GCC_ASSERT(dest==m_Size*3); pVerts->Unlock(); return true; } void *TriangleIterator::VGet(unsigned int i) { GCC_ASSERT(i<m_Size); return &m_Triangles[i*3]; }下面一篇是基于Direct X 实现的渲染封装~~