所有的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 实现的渲染封装~~