📄 nvcomplexmesh.cpp
字号:
/*********************************************************************NVMH2****
Copyright (C) 1999, 2000 NVIDIA Corporation
This file is provided without support, instruction, or implied warranty of any
kind. NVIDIA makes no guarantee of its fitness for a particular purpose and is
not liable under any circumstances for any damages or loss whatsoever arising
from the use or inability to use this file or items derived from it.
Comments:
******************************************************************************/
#include "nvcomplexmesh.h"
#include "nvresourcemanager.h"
#include "nvtextureresource.h"
#include "nvrenderstyleresource.h"
#include <algorithm>
using namespace std;
namespace nv_objects
{
NVComplexMesh::NVComplexMesh()
: m_dwNumVertices(0),
m_dwStride(0),
m_pVB(NULL),
m_pBoneNames(NULL),
m_pBoneTransforms(NULL),
m_pBoneCombinations(NULL),
m_pBoneMatrices(NULL),
m_dwNumBones(0),
m_dwNumBoneCombinations(0),
m_dwDesiredPaletteSize(10),
m_dwFVF(0)
{
}
NVComplexMesh::~NVComplexMesh()
{
Release();
}
void NVComplexMesh::Release()
{
// Remove the vertex data associated with this mesh
tVertexDataMap::iterator itrVertex = m_VertexData.begin();
while(itrVertex != m_VertexData.end())
{
NVVertexData* pVertexData = itrVertex->second;
SAFE_DELETE(pVertexData);
itrVertex++;
}
m_dwNumVertices = 0;
tIndexBufferArray::iterator itrIndices = m_IndexBuffers.begin();
while (itrIndices != m_IndexBuffers.end())
{
SAFE_RELEASE(*itrIndices);
itrIndices++;
}
m_IndexBuffers.clear();
SAFE_RELEASE(m_pVB);
SAFE_RELEASE(m_pBoneNames);
SAFE_RELEASE(m_pBoneTransforms);
SAFE_RELEASE(m_pBoneCombinations);
m_dwNumBoneCombinations = 0;
m_dwNumBones = 0;
SAFE_DELETE_ARRAY(m_pBoneMatrices);
}
bool NVComplexMesh::FlipNormals()
{
NVVertexData* pNormalData = FindVertexData(NVVERT_NORMAL);
if (!pNormalData)
return false;
D3DXVECTOR3* pData = GetDataPointer<D3DXVECTOR3, D3DDATATYPE_FLOAT3>(pNormalData);
for (DWORD i = 0; i < pNormalData->size(); i++)
{
pData[i] = -pData[i];
}
return true;
}
bool NVComplexMesh::GenerateNormals()
{
DWORD i;
NVVertexData* pPositionData = FindVertexData(NVVERT_POSITION);
NVVertexData* pNormalData = FindVertexData(NVVERT_NORMAL);
if (!pPositionData || !pNormalData ||
(pPositionData->GetDataType() != D3DDATATYPE_FLOAT3) ||
(pNormalData->GetDataType() != D3DDATATYPE_FLOAT3))
{
return false;
}
D3DXVECTOR3* pPosition = GetDataPointer<D3DXVECTOR3, D3DDATATYPE_FLOAT3>(pPositionData);
D3DXVECTOR3* pNormal = GetDataPointer<D3DXVECTOR3, D3DDATATYPE_FLOAT3>(pNormalData);
tIndexArray::iterator itrIndices;
D3DXVECTOR3 norm;
// Clear the normals
for (i = 0; i < pNormalData->size(); i++)
{
pNormal[i] = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
}
// Generate normals
itrIndices = m_Indices.begin();
while (itrIndices != m_Indices.end())
{
D3DXVECTOR3 vec1 = pPosition[*(itrIndices + 0)] - pPosition[*(itrIndices + 1)];
D3DXVECTOR3 vec2 = pPosition[*(itrIndices + 0)] - pPosition[*(itrIndices + 2)];
D3DXVec3Cross(&norm, &vec1, &vec2);
pNormal[*(itrIndices + 0)] += norm;
pNormal[*(itrIndices + 1)] += norm;
pNormal[*(itrIndices + 2)] += norm;
itrIndices += 3;
}
// Normalize
for (i = 0; i < pNormalData->size(); i++)
{
float Length;
Length = D3DXVec3Length(&pNormal[i]);
pNormal[i] /= Length;
}
return true;
}
bool NVComplexMesh::NormalizeNormals()
{
NVVertexData* pNormalData = FindVertexData(NVVERT_NORMAL);
if (!pNormalData || (pNormalData->GetDataType() != D3DDATATYPE_FLOAT3))
{
return false;
}
D3DXVECTOR3* pNormal = GetDataPointer<D3DXVECTOR3, D3DDATATYPE_FLOAT3>(pNormalData);
// Normalize
for (DWORD i = 0; i < pNormalData->size(); i++)
{
float Length;
Length = D3DXVec3Length(&pNormal[i]);
pNormal[i] /= Length;
}
return true;
}
bool NVComplexMesh::GenerateBasis(DWORD dwTexture, DWORD dwOption)
{
DWORD i, j;
float epsilon = 1.0e-5f;
float x,y,z,dist;
NVVertexData* pPositionData = FindVertexData(NVVERT_POSITION);
NVVertexData* pNormalData = FindVertexData(NVVERT_NORMAL);
NVVertexData* pTextureData;
NVVertexData* pSBasisData;
NVVertexData* pTBasisData;
NVVertexData* pSxTBasisData;
// Find the texture data
pTextureData = FindVertexData(NVVERT_TEXTURE0 + dwTexture);
// Find the basis vectors if available
pSBasisData = FindVertexData(NVVERT_SBASIS0 + dwTexture);
pTBasisData = FindVertexData(NVVERT_TBASIS0 + dwTexture);
pSxTBasisData = FindVertexData(NVVERT_SxTBASIS0 + dwTexture);
if (!pPositionData || !pTextureData || !pSBasisData || !pTBasisData ||
(pPositionData->GetDataType() != D3DDATATYPE_FLOAT3) ||
(pTextureData->GetDataType() != D3DDATATYPE_FLOAT2) ||
(pSBasisData->GetDataType() != D3DDATATYPE_FLOAT3) ||
(pTBasisData->GetDataType() != D3DDATATYPE_FLOAT3))
{
return false;
}
if (pSxTBasisData && !pNormalData)
{
// Need normal stream if generating SxTBasis.
return false;
}
D3DXVECTOR3* pPosition = GetDataPointer<D3DXVECTOR3, D3DDATATYPE_FLOAT3>(pPositionData);
D3DXVECTOR2* pTexture = GetDataPointer<D3DXVECTOR2, D3DDATATYPE_FLOAT2>(pTextureData);
D3DXVECTOR3* pNormal = GetDataPointer<D3DXVECTOR3, D3DDATATYPE_FLOAT3>(pNormalData);
D3DXVECTOR3* pSBasis = GetDataPointer<D3DXVECTOR3, D3DDATATYPE_FLOAT3>(pSBasisData);
D3DXVECTOR3* pTBasis = GetDataPointer<D3DXVECTOR3, D3DDATATYPE_FLOAT3>(pTBasisData);
// Pick up SxT if needed
D3DXVECTOR3* pSxTBasis = NULL;
if (pSxTBasisData)
{
pSxTBasis = GetDataPointer<D3DXVECTOR3, D3DDATATYPE_FLOAT3>(pSxTBasisData);
}
tIndexArray::iterator itrIndices;
// Clear the basis vectors
for (i = 0; i < m_dwNumVertices; i++)
{
pSBasis[i] = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
pTBasis[i] = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
}
// Walk through the triangle list and calculate gradiants for each triangle.
// Sum the results into the S and T components.
itrIndices = m_Indices.begin();
while (itrIndices != m_Indices.end())
{
DWORD TriIndex[3];
D3DXVECTOR3 du, dv;
D3DXVECTOR3 edge01;
D3DXVECTOR3 edge02;
D3DXVECTOR3 cp;
TriIndex[0] = *(itrIndices + 0);
TriIndex[1] = *(itrIndices + 1);
TriIndex[2] = *(itrIndices + 2);
itrIndices += 3;
NVASSERT((TriIndex[0] < m_dwNumVertices) && (TriIndex[1] < m_dwNumVertices) && (TriIndex[2] < m_dwNumVertices), "Index exceeds vertex count");
// Position locations
D3DXVECTOR3& v0 = pPosition[TriIndex[0]];
D3DXVECTOR3& v1 = pPosition[TriIndex[1]];
D3DXVECTOR3& v2 = pPosition[TriIndex[2]];
// Texture locations
D3DXVECTOR2& t0 = pTexture[TriIndex[0]];
D3DXVECTOR2& t1 = pTexture[TriIndex[1]];
D3DXVECTOR2& t2 = pTexture[TriIndex[2]];
// Basis locations
D3DXVECTOR3& sb0 = pSBasis[TriIndex[0]];
D3DXVECTOR3& tb0 = pTBasis[TriIndex[0]];
D3DXVECTOR3& sb1 = pSBasis[TriIndex[1]];
D3DXVECTOR3& tb1 = pTBasis[TriIndex[1]];
D3DXVECTOR3& sb2 = pSBasis[TriIndex[2]];
D3DXVECTOR3& tb2 = pTBasis[TriIndex[2]];
// x, s, t
edge01 = D3DXVECTOR3( v1.x - v0.x, t1.x - t0.x, t1.y - t0.y );
edge02 = D3DXVECTOR3( v2.x - v0.x, t2.x - t0.x, t2.y - t0.y );
D3DXVec3Cross(&cp, &edge01, &edge02);
if ( fabs(cp.x) > SMALL_FLOAT )
{
sb0.x += -cp.y / cp.x;
tb0.x += -cp.z / cp.x;
sb1.x += -cp.y / cp.x;
tb1.x += -cp.z / cp.x;
sb2.x += -cp.y / cp.x;
tb2.x += -cp.z / cp.x;
}
// y, s, t
edge01 = D3DXVECTOR3( v1.y - v0.y, t1.x - t0.x, t1.y - t0.y );
edge02 = D3DXVECTOR3( v2.y - v0.y, t2.x - t0.x, t2.y - t0.y );
D3DXVec3Cross(&cp, &edge01, &edge02);
if ( fabs(cp.x) > SMALL_FLOAT )
{
sb0.y += -cp.y / cp.x;
tb0.y += -cp.z / cp.x;
sb1.y += -cp.y / cp.x;
tb1.y += -cp.z / cp.x;
sb2.y += -cp.y / cp.x;
tb2.y += -cp.z / cp.x;
}
// z, s, t
edge01 = D3DXVECTOR3( v1.z - v0.z, t1.x - t0.x, t1.y - t0.y );
edge02 = D3DXVECTOR3( v2.z - v0.z, t2.x - t0.x, t2.y - t0.y );
D3DXVec3Cross(&cp, &edge01, &edge02);
if ( fabs(cp.x) > SMALL_FLOAT )
{
sb0.z += -cp.y / cp.x;
tb0.z += -cp.z / cp.x;
sb1.z += -cp.y / cp.x;
tb1.z += -cp.z / cp.x;
sb2.z += -cp.y / cp.x;
tb2.z += -cp.z / cp.x;
}
}
if (dwOption & MeshOption_SmoothBasis)
{
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Before normalizing the S, T vectors we have to
// find degenerate vertices to average the basis
// for points which share position but not UV
// coordinate (ie lathed objects with a seam where
// vertices are duplicated).
// If we were to search for these degenerate points after
// normalizing the S & T, the averaging of these normalized
// (pre-averaged) vectors would not be correct over the
// seam, and a discontinuity might appear.
// duplicate_index is array of indices to bins.
typedef vector< vector<DWORD> > tindexmap;
tindexmap duplicate_index;
duplicate_index.resize(m_dwNumVertices);
// Need to search the mesh for vertices with the same spatial coordinate
// These are vertices duplicated for lathed/wrapped objects to make a
// 2nd set of texture coordinates at the point in order to avoid bad
// texture wrapping
// In short: For each vertex, find any other vertices that share it's
// position. "Average" the tangent space basis calculated above for
// these duplicate vertices. This is not rigorous, but works well
// to fix up authored models. ** Models should not have T juntions! **
// Check each vert with every other. There's no reason to check
// j with i after doing i with j, so start j from i ( so we test
// 1 with 2 but never 2 with 1 again).
// This is a model pre-processing step and only done once. For large
// models, compute this off-line if you have to and store the resultant
// data.
// The whole thing could be made much more efficient (linked list, etc)
for( i=0; i < m_dwNumVertices; i++ )
{
for(j=i+1; j < m_dwNumVertices; j++ )
{
x = pPosition[i].x - pPosition[j].x;
y = pPosition[i].y - pPosition[j].y;
z = pPosition[i].z - pPosition[j].z;
dist = x*x + y*y + z*z;
if( dist < epsilon )
{
// if i matches j and k, just record into i. j will be
// half full as it will only match k, but this is
// taken care of when i is processed.
duplicate_index[i].push_back(j);
}
}
}
// Now average the tangent spaces & write the new result to
// each duplicated vertex
D3DXVECTOR3 S_temp, T_temp, SxT_temp, N_temp;
for( i = 0; i < m_dwNumVertices; i++ )
{
if(!duplicate_index[i].empty())
{
// FDebug("Averaging vert prop at %d for %d vertices\n", i, duplicate_count[i]);
// If there are more than 5 vertices sharing this point then
// the point is probably some kind of lathe axis node. No need to
// process it here
// Set accumulator to value for vertex in question
S_temp = pSBasis[i];
T_temp = pTBasis[i];
N_temp = pNormal[i];
if (pSxTBasis)
SxT_temp = pSxTBasis[i];
// add in basis vectors for all other vertices which
// have the same positon (found above)
for(j=0; j < duplicate_index[i].size(); j++ )
{
S_temp = S_temp + pSBasis[duplicate_index[i][j]];
T_temp = T_temp + pTBasis[duplicate_index[i][j]];
N_temp = N_temp + pNormal[duplicate_index[i][j]];
if (pSxTBasis)
{
SxT_temp = SxT_temp + pSxTBasis[duplicate_index[i][j]];
}
}
// Normalize the basis vectors
// Note that SxT might not be perpendicular to S and T
// anymore. Not absolutely necessary to re-do the
// cross product.
// Write the average basis to the first vertex for which
// the duplicates were found
D3DXVec3Normalize( & S_temp, & S_temp );
D3DXVec3Normalize( & T_temp, & T_temp );
D3DXVec3Normalize( & N_temp, & N_temp );
pSBasis[i] = S_temp;
pTBasis[i] = T_temp;
if (pSxTBasis)
{
D3DXVec3Normalize( & SxT_temp, & SxT_temp );
pSxTBasis[i] = SxT_temp;
}
if(dwOption & MeshOption_UnifyNormals)
pNormal[i] = N_temp;
// Now write to all later vertices with the same position
for(j=0; j < duplicate_index[i].size(); j++ )
{
// Set the vertices in the same position to
// the average basis.
pSBasis[duplicate_index[i][j]] = S_temp;
pTBasis[duplicate_index[i][j]] = T_temp;
if (pSxTBasis)
{
pSxTBasis[duplicate_index[i][j]] = SxT_temp;
}
if(dwOption & MeshOption_UnifyNormals)
pNormal[duplicate_index[i][j]] = N_temp;
// Kill the duplicate index lists of all vertices of
// higher index which overlap this one. This is so
// higher index vertices do not average a smaller
// subset of bases.
// Arrays are de-allocated later
duplicate_index[duplicate_index[i][j]].clear();
}
}
}
}
// Calculate the SxT vector
for(i = 0; i < m_dwNumVertices; i++)
{
// Normalize the S, T vectors
D3DXVec3Normalize(&pSBasis[i], &pSBasis[i]);
D3DXVec3Normalize(&pTBasis[i], &pTBasis[i]);
if (pSxTBasis)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -