📄 wmltrimesh.cpp
字号:
// Magic Software, Inc.
// http://www.magic-software.com
// http://www.wild-magic.com
// Copyright (c) 2003. All Rights Reserved
//
// The Wild Magic Library (WML) source code is supplied under the terms of
// the license agreement http://www.magic-software.com/License/WildMagic.pdf
// and may not be copied or disclosed except in accordance with the terms of
// that agreement.
#include "WmlRenderer.h"
#include "WmlTriMesh.h"
using namespace Wml;
using namespace std;
WmlImplementRTTI(TriMesh,Geometry);
WmlImplementStream(TriMesh);
//----------------------------------------------------------------------------
TriMesh::TriMesh (int iVertexQuantity, Vector3f* akVertex, Vector3f* akNormal,
ColorRGB* akColor, Vector2f* akTexture, int iTriangleQuantity,
int* aiConnect, Vector2f* akTexture1, Vector2f* akTexture2,
Vector2f* akTexture3, Vector2f* akTextureBump,
VertexShader* pkVertexShader, PixelShader* pkPixelShader)
:
Geometry(iVertexQuantity,akVertex,akNormal,akColor,akTexture,akTexture1,
akTexture2,akTexture3,akTextureBump, pkVertexShader, pkPixelShader)
{
m_iTriangleQuantity = iTriangleQuantity;
m_aiConnect = aiConnect;
}
//----------------------------------------------------------------------------
TriMesh::TriMesh ()
{
m_iTriangleQuantity = 0;
m_aiConnect = NULL;
}
//----------------------------------------------------------------------------
TriMesh::~TriMesh ()
{
delete[] m_aiConnect;
}
//----------------------------------------------------------------------------
void TriMesh::Reconstruct (int iVertexQuantity, int iTriangleQuantity)
{
Geometry::Reconstruct(iVertexQuantity);
m_iTriangleQuantity = iTriangleQuantity;
delete[] m_aiConnect;
if ( m_iTriangleQuantity > 0 )
m_aiConnect = new int[3*m_iTriangleQuantity];
}
//----------------------------------------------------------------------------
void TriMesh::Reconstruct (int iVertexQuantity, Vector3f* akVertex,
Vector3f* akNormal, ColorRGB* akColor, Vector2f* akTexture,
int iTriangleQuantity, int* aiConnect, Vector2f* akTexture1,
Vector2f* akTexture2, Vector2f* akTexture3, Vector2f* akTextureBump)
{
Geometry::Reconstruct(iVertexQuantity,akVertex,akNormal,akColor,
akTexture,akTexture1,akTexture2,akTexture3,akTextureBump);
if ( m_aiConnect != aiConnect )
{
delete[] m_aiConnect;
m_aiConnect = aiConnect;
}
m_iTriangleQuantity = iTriangleQuantity;
}
//----------------------------------------------------------------------------
void TriMesh::GetTriangle (int i, int& riV0, int& riV1, int& riV2) const
{
assert( i < m_iTriangleQuantity );
int iBase = 3*i;
riV0 = m_aiConnect[iBase++];
riV1 = m_aiConnect[iBase++];
riV2 = m_aiConnect[iBase];
}
//----------------------------------------------------------------------------
void TriMesh::GetTriangle (int i, Vector3f& rkV0, Vector3f& rkV1,
Vector3f& rkV2) const
{
assert( i < m_iTriangleQuantity );
int iBase = 3*i;
rkV0 = m_akVertex[m_aiConnect[iBase++]];
rkV1 = m_akVertex[m_aiConnect[iBase++]];
rkV2 = m_akVertex[m_aiConnect[iBase]];
}
//----------------------------------------------------------------------------
void TriMesh::UpdateModelNormals ()
{
// Calculate normals from vertices by weighted averages of facet planes
// that contain the vertices. TO DO. Replace by algorithm that computes
// axis of minimum cone containing the normals.
if ( !m_akNormal )
m_akNormal = new Vector3f[m_iVertexQuantity];
memset(m_akNormal,0,m_iVertexQuantity*sizeof(Vector3f));
int* aiConnect = m_aiConnect;
int i;
for (i = 0; i < m_iTriangleQuantity; i++)
{
// get vertex indices
int iV0 = *aiConnect++;
int iV1 = *aiConnect++;
int iV2 = *aiConnect++;
// get vertices
Vector3f& rkV0 = m_akVertex[iV0];
Vector3f& rkV1 = m_akVertex[iV1];
Vector3f& rkV2 = m_akVertex[iV2];
// compute the normal (length provides the weighted sum)
Vector3f kEdge1 = rkV1 - rkV0;
Vector3f kEdge2 = rkV2 - rkV0;
Vector3f kNormal = kEdge1.Cross(kEdge2);
m_akNormal[iV0] += kNormal;
m_akNormal[iV1] += kNormal;
m_akNormal[iV2] += kNormal;
}
for (i = 0; i < m_iVertexQuantity; i++)
m_akNormal[i].Normalize();
}
//----------------------------------------------------------------------------
void TriMesh::Draw (Renderer& rkRenderer)
{
Geometry::Draw(rkRenderer);
rkRenderer.Draw(*this);
}
//----------------------------------------------------------------------------
TriMesh::PickRecord::PickRecord (TriMesh* pkObject, float fRayT,
int iTriangle, float fBary0, float fBary1, float fBary2)
:
Geometry::PickRecord(pkObject,fRayT)
{
m_iTriangle = iTriangle;
m_fBary0 = fBary0;
m_fBary1 = fBary1;
m_fBary2 = fBary2;
}
//----------------------------------------------------------------------------
void TriMesh::DoPick (const Vector3f& rkOrigin, const Vector3f& rkDirection,
PickArray& rkResults)
{
if ( m_kWorldBound.TestIntersection(rkOrigin,rkDirection) )
{
// convert the ray to model-space coordinates
Vector3f kDiff = rkOrigin - m_kWorldTranslate;
float fInvScale = 1.0f/m_fWorldScale;
Vector3f kMOrigin = fInvScale*(kDiff*m_kWorldRotate);
Vector3f kMDirection = fInvScale*(rkDirection*m_kWorldRotate);
// compute intersections with the model-space triangles
int* aiConnect = m_aiConnect;
for (int i = 0; i < m_iTriangleQuantity; i++)
{
int iV0 = *aiConnect++;
int iV1 = *aiConnect++;
int iV2 = *aiConnect++;
float fBary0, fBary1, fBary2, fRayT;
if ( GetRayTriangleIntersection(kMOrigin,kMDirection,
m_akVertex[iV0],m_akVertex[iV1],m_akVertex[iV2],fBary0,
fBary1,fBary2,fRayT) )
{
rkResults.push_back(new PickRecord(this,fRayT,i,fBary0,fBary1,
fBary2));
}
}
}
}
//----------------------------------------------------------------------------
bool TriMesh::GetRayTriangleIntersection (const Vector3f& rkModelOrigin,
const Vector3f& rkModelDirection, const Vector3f& rkV0,
const Vector3f& rkV1, const Vector3f& rkV2, float& rfBary0,
float& rfBary1, float& rfBary2, float& rfRayT)
{
// compute the offset origin, edges, and normal
Vector3f kDiff = rkModelOrigin - rkV0;
Vector3f kEdge1 = rkV1 - rkV0;
Vector3f kEdge2 = rkV2 - rkV0;
Vector3f kNormal = kEdge1.Cross(kEdge2);
// Solve Q + t*D = s1*E1 + s2*E2 (Q = kDiff, D = kMDirection,
// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
// |Dot(D,N)|*s1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
// |Dot(D,N)|*s2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
// |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
const float fEpsilon = 1e-06f;
float fDdN = rkModelDirection.Dot(kNormal);
float fSign;
if ( fDdN > fEpsilon )
{
fSign = 1.0f;
}
else if ( fDdN < -fEpsilon )
{
fSign = -1.0f;
fDdN = -fDdN;
}
else
{
// Ray and triangle are parallel, call it a "no intersection"
// even if the ray does intersect.
return false;
}
float fDdQxE2 = fSign*rkModelDirection.Dot(kDiff.Cross(kEdge2));
if ( fDdQxE2 >= 0.0f )
{
float fDdE1xQ = fSign*rkModelDirection.Dot(kEdge1.Cross(kDiff));
if ( fDdE1xQ >= 0.0f )
{
if ( fDdQxE2 + fDdE1xQ <= fDdN )
{
// line intersects triangle, check if ray does
float fQdN = -fSign*kDiff.Dot(kNormal);
if ( fQdN >= 0.0f )
{
// ray intersects triangle
float fInv = 1.0f/fDdN;
rfBary1 = fDdQxE2*fInv;
rfBary2 = fDdE1xQ*fInv;
rfBary0 = 1.0f - rfBary1 - rfBary2;
rfRayT = fQdN*fInv;
return true;
}
// else: t < 0, no intersection
}
// else: s1+s2 > 1, no intersection
}
// else: s2 < 0, no intersection
}
// else: s1 < 0, no intersection
return false;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// streaming
//----------------------------------------------------------------------------
Object* TriMesh::Factory (Stream& rkStream)
{
TriMesh* pkObject = new TriMesh;
Stream::Link* pkLink = new Stream::Link(pkObject);
pkObject->Load(rkStream,pkLink);
return pkObject;
}
//----------------------------------------------------------------------------
void TriMesh::Load (Stream& rkStream, Stream::Link* pkLink)
{
Geometry::Load(rkStream,pkLink);
// native data
StreamRead(rkStream,m_iTriangleQuantity);
int iQuantity = 3*m_iTriangleQuantity;
m_aiConnect = new int[iQuantity];
StreamRead(rkStream,m_aiConnect,iQuantity);
}
//----------------------------------------------------------------------------
void TriMesh::Link (Stream& rkStream, Stream::Link* pkLink)
{
Geometry::Link(rkStream,pkLink);
}
//----------------------------------------------------------------------------
bool TriMesh::Register (Stream& rkStream)
{
return Geometry::Register(rkStream);
}
//----------------------------------------------------------------------------
void TriMesh::Save (Stream& rkStream)
{
Geometry::Save(rkStream);
// native data
StreamWrite(rkStream,m_iTriangleQuantity);
StreamWrite(rkStream,m_aiConnect,3*m_iTriangleQuantity);
}
//----------------------------------------------------------------------------
StringTree* TriMesh::SaveStrings ()
{
StringTree* pkTree = new StringTree(2,0,2,0);
// strings
pkTree->SetString(0,MakeString(&ms_kRTTI,GetName()));
pkTree->SetString(1,MakeString("triangle quantity =",
m_iTriangleQuantity));
// children
pkTree->SetChild(0,Geometry::SaveStrings());
StringTree* pkTriTree = new StringTree(m_iTriangleQuantity+1,0,0,0);
pkTriTree->SetString(0,MakeString("triangles"));
int* piConnect = m_aiConnect;
char acDummy[64];
for (int i = 0; i < m_iTriangleQuantity; i++)
{
int iI0 = *piConnect++;
int iI1 = *piConnect++;
int iI2 = *piConnect++;
sprintf(acDummy,"<%5d,%5d,%5d>",iI0,iI1,iI2);
pkTriTree->SetString(i+1,MakeString(acDummy));
}
pkTree->SetChild(1,pkTriTree);
return pkTree;
}
//----------------------------------------------------------------------------
int TriMesh::GetMemoryUsed () const
{
int iBaseSize = sizeof(TriMesh) - sizeof(Geometry);
int iDynaSize = 3*m_iTriangleQuantity*sizeof(int);
int iTotalSize = iBaseSize + iDynaSize + Geometry::GetMemoryUsed();
return iTotalSize;
}
//----------------------------------------------------------------------------
int TriMesh::GetDiskUsed () const
{
return Geometry::GetDiskUsed() +
sizeof(m_iTriangleQuantity) +
3*m_iTriangleQuantity*sizeof(m_aiConnect[0]);
}
//----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -