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

📄 nvcomplexmesh.cpp

📁 游戏编程精华02-含有几十个游戏编程例子
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/*********************************************************************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 + -