📄 nvcomplexmesh.cpp
字号:
{
D3DXVECTOR3 NormalizedNormal;
// Get the cross of the S and T vectors
D3DXVec3Cross(&pSxTBasis[i], &pSBasis[i], &pTBasis[i]);
D3DXVec3Normalize(&pSxTBasis[i], &pSxTBasis[i]);
// Need a normalized normal
D3DXVec3Normalize(&NormalizedNormal, &pNormal[i]);
// v coordinates go in opposite direction from the texture v increase in xyz
pTBasis[i] = -pTBasis[i];
// Get the direction of the SxT vector
if (D3DXVec3Dot(&pSxTBasis[i], &NormalizedNormal) < 0.0f)
{
pSxTBasis[i] = -pSxTBasis[i];
}
}
}
return true;
}
bool NVComplexMesh::CreateFromXFile(LPDIRECT3DDEVICE8 pDevice, const char* fileName)
{
HRESULT hr;
LPD3DXBUFFER pMaterials = NULL;
LPD3DXMESH tempMesh = NULL;
LPD3DXMESH tempMeshOpt = NULL;
DWORD dwNumMaterials;
LPDIRECT3DVERTEXBUFFER8 pVB = NULL;
LPDIRECT3DINDEXBUFFER8 pIB = NULL;
Release();
// If there's a path to this file, jump to this directory to ensure correct loading of textures, etc.
m_strDirectory = fileName;
std::string::size_type Pos = m_strDirectory.find_last_of("\\", m_strDirectory.size());
if (Pos != m_strDirectory.npos)
{
m_strDirectory = m_strDirectory.substr(0, Pos);
}
else
{
m_strDirectory = ".";
}
// Load the mesh into system memory
hr = D3DXLoadMeshFromX(const_cast<char*>(fileName), D3DXMESH_SYSTEMMEM, pDevice, NULL, (ID3DXBuffer**)&pMaterials, &dwNumMaterials, &tempMesh);
if (FAILED(hr))
return false;
// Sort the attributes.
hr = tempMesh->Optimize(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL, &tempMeshOpt);
if (FAILED(hr))
return false;
hr = tempMeshOpt->GetVertexBuffer(&pVB);
if (FAILED(hr))
{
SAFE_RELEASE(m_pBoneNames);
SAFE_RELEASE(m_pBoneTransforms);
return false;
}
hr = tempMeshOpt->GetIndexBuffer(&pIB);
if (FAILED(hr))
{
SAFE_RELEASE(pVB);
SAFE_RELEASE(m_pBoneNames);
SAFE_RELEASE(m_pBoneTransforms);
return false;
}
bool bSuccess = CreateFromXFileData(pDevice, pVB, pIB, pMaterials, dwNumMaterials, tempMeshOpt);
SAFE_RELEASE(pMaterials);
SAFE_RELEASE(tempMesh);
SAFE_RELEASE(tempMeshOpt);
SAFE_RELEASE(pIB);
SAFE_RELEASE(pVB);
return bSuccess;
}
bool NVComplexMesh::CreateFromXof(LPDIRECT3DDEVICE8 pDevice, LPDIRECTXFILEDATA pxofobjCur)
{
HRESULT hr;
LPD3DXSKINMESH tempSkinMesh = NULL;
LPD3DXMESH tempMesh = NULL;
LPD3DXMESH tempMeshOpt = NULL;
LPD3DXBUFFER pMaterials = NULL;
LPD3DXBUFFER pAdjacency = NULL;
DWORD dwNumMaterials;
LPDIRECT3DVERTEXBUFFER8 pVB = NULL;
LPDIRECT3DINDEXBUFFER8 pIB = NULL;
Release();
std::string strPathSize;
DWORD dwPathSize = GetCurrentDirectory(0, &m_strDirectory[0]);
m_strDirectory.resize(dwPathSize);
GetCurrentDirectory(dwPathSize, &m_strDirectory[0]);
// Remove the 0 off the string so we can sew in more data
std::string::size_type Pos = m_strDirectory.find_last_of('\0', m_strDirectory.size());
if (Pos != m_strDirectory.npos)
{
m_strDirectory = m_strDirectory.substr(0, Pos);
}
hr = D3DXLoadSkinMeshFromXof(pxofobjCur, D3DXMESH_SYSTEMMEM, pDevice, &pAdjacency, (ID3DXBuffer**)&pMaterials, &dwNumMaterials,
&m_pBoneNames, &m_pBoneTransforms, &tempSkinMesh);
if (FAILED(hr))
return false;
m_dwNumBones = tempSkinMesh->GetNumBones();
if (m_dwNumBones != 0)
{
DWORD dwMaxFaceInfluences;
DWORD dwNumFaces;
DWORD dwNumBoneCombinations;
m_dwBonePaletteSize = m_dwDesiredPaletteSize;
tempSkinMesh->GetMaxFaceInfluences(&dwMaxFaceInfluences);
dwNumFaces = tempSkinMesh->GetNumFaces();
// 12 entry palette guarantees that any triangle (4 independent influences per vertex of a tri)
// can be handled
dwMaxFaceInfluences = min(dwMaxFaceInfluences, 12);
// Expand the palette to fit if we have to
if (m_dwBonePaletteSize < dwMaxFaceInfluences)
m_dwBonePaletteSize = dwMaxFaceInfluences;
// PaletteSize is the min of the requested palette size or the number of bones (if there are less bones)
m_dwBonePaletteSize = min(m_dwBonePaletteSize, m_dwNumBones);
m_pBoneMatrices = new const D3DXMATRIX*[m_dwNumBones];
hr = tempSkinMesh->ConvertToIndexedBlendedMesh(D3DXMESH_SYSTEMMEM, (DWORD*)pAdjacency->GetBufferPointer(), m_dwBonePaletteSize, NULL,
&dwNumBoneCombinations, &m_pBoneCombinations, &tempMesh);
if (FAILED(hr))
return false;
SAFE_RELEASE(tempSkinMesh);
}
else
{
// Discard the skinning part
tempSkinMesh->GetOriginalMesh(&tempMesh);
SAFE_RELEASE(tempSkinMesh);
}
// Sort the attributes.
hr = tempMesh->Optimize(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL, &tempMeshOpt);
if (FAILED(hr))
return false;
hr = tempMeshOpt->GetVertexBuffer(&pVB);
if (FAILED(hr))
{
SAFE_RELEASE(m_pBoneNames);
SAFE_RELEASE(m_pBoneTransforms);
return false;
}
hr = tempMeshOpt->GetIndexBuffer(&pIB);
if (FAILED(hr))
{
SAFE_RELEASE(pVB);
SAFE_RELEASE(m_pBoneNames);
SAFE_RELEASE(m_pBoneTransforms);
return false;
}
bool bSuccess = CreateFromXFileData(pDevice, pVB, pIB, pMaterials, dwNumMaterials, tempMeshOpt);
if (!bSuccess)
{
SAFE_RELEASE(m_pBoneNames);
SAFE_RELEASE(m_pBoneTransforms);
SAFE_DELETE_ARRAY(m_pBoneMatrices);
}
SAFE_RELEASE(pMaterials);
SAFE_RELEASE(tempMesh);
SAFE_RELEASE(tempMeshOpt);
SAFE_RELEASE(pIB);
SAFE_RELEASE(pVB);
return bSuccess;
}
bool NVComplexMesh::CreateFromXFileData(LPDIRECT3DDEVICE8 pDevice, LPDIRECT3DVERTEXBUFFER8 pVB, LPDIRECT3DINDEXBUFFER8 pIB, LPD3DXBUFFER pMaterials, DWORD dwNumMaterials, LPD3DXMESH pMesh)
{
DWORD i;
DWORD dwNumAttributes;
D3DXATTRIBUTERANGE* pAttributes;
D3DVERTEXBUFFER_DESC vbdesc;
D3DINDEXBUFFER_DESC ibdesc;
DWORD dwTexCount;
HRESULT hr;
hr = pMesh->GetAttributeTable(NULL, &dwNumAttributes);
if (FAILED(hr))
return false;
pAttributes = (D3DXATTRIBUTERANGE*)HeapAlloc(GetProcessHeap(), 0, dwNumAttributes * sizeof(D3DXATTRIBUTERANGE));
hr = pMesh->GetAttributeTable(pAttributes, &dwNumAttributes);
pIB->GetDesc(&ibdesc);
pVB->GetDesc(&vbdesc);
LPD3DXBONECOMBINATION pBoneComb = NULL;
if (m_pBoneCombinations)
pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(m_pBoneCombinations->GetBufferPointer());
typedef std::map<DWORD, NVResourceRef> tMapMaterialToResource;
tMapMaterialToResource MaterialToResource;
// First store the material data
for (i = 0; i < dwNumAttributes; i++)
{
NVComplexMeshSection Attrib;
NVMaterialResource* pMaterial;
DWORD dwMaterialAttrib;
NVResourceRef Material;
// The material either matches the attribute, or it is in referred to in the bone combination buffer.
if (pBoneComb)
{
dwMaterialAttrib = pBoneComb[i].AttribId;
}
else
{
dwMaterialAttrib = i;
}
tMapMaterialToResource::const_iterator itrMaterial = MaterialToResource.find(dwMaterialAttrib);
if (itrMaterial != MaterialToResource.end())
{
Material = itrMaterial->second;
pMaterial = NVMaterialResource::GetMaterialResourcePtr(Material.GetPointer());
}
else
{
pMaterial = new NVMaterialResource;
Material = NVRESOURCEMANAGER.AddResource(pMaterial);
MaterialToResource.insert(tMapMaterialToResource::value_type(dwMaterialAttrib, Material));
// Create dummy material if there are none in the mesh
if (!pMaterials)
{
// Create named constants for this mesh
pMaterial->AddValue("diffuse", NVValue(NVV_VECTOR4, D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f)));
pMaterial->AddValue("power", NVValue(NVV_VECTOR4, D3DXVECTOR4(0.0f, 0.0f, 0.0f, 50.0f)));
}
else
{
NVASSERT(pMaterials->GetBufferSize() >= (dwNumMaterials * sizeof(D3DXMATERIAL)), "Materials buffer is too small");
D3DXMATERIAL* pMat = (D3DXMATERIAL*)pMaterials->GetBufferPointer();
// Create named constants for this mesh
pMaterial->AddValue("diffuse", NVValue(NVV_VECTOR4, &pMat[i].MatD3D.Diffuse));
pMaterial->AddValue("ambient", NVValue(NVV_VECTOR4, &pMat[i].MatD3D.Ambient));
pMaterial->AddValue("emissive", NVValue(NVV_VECTOR4, &pMat[i].MatD3D.Emissive));
// Only add specular if there's a specular power
if (pMat[i].MatD3D.Power != 0.0f)
{
pMaterial->AddValue("power", NVValue(NVV_VECTOR4, D3DXVECTOR4(0.0f, 0.0f, 0.0f, pMat[i].MatD3D.Power)));
pMaterial->AddValue("specular", NVValue(NVV_VECTOR4, &pMat[i].MatD3D.Specular));
}
if (pMat[i].pTextureFilename)
{
string strFilePath = m_strDirectory + "\\" + pMat[i].pTextureFilename;
HANDLE hFile = CreateFile(strFilePath.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
// Try without the appended directory
strFilePath = pMat[i].pTextureFilename;
hFile = CreateFile(strFilePath.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
}
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
// Add this texture to the resource manager
NVTextureFileResource* pTexture = new NVTextureFileResource(pDevice, strFilePath);
pMaterial->AddValue("basemap", NVValue(NVV_RESOURCE, &NVRESOURCEMANAGER.AddResource(pTexture)));
}
}
}
}
Attrib.m_dwAttribId = pAttributes[i].AttribId;
Attrib.m_TriType = NVComplexMeshSection::IndexedTriangleList;
Attrib.m_dwIndexStart = pAttributes[i].FaceStart * 3;
Attrib.m_dwIndexCount = pAttributes[i].FaceCount * 3;
Attrib.m_dwVertexStart = pAttributes[i].VertexStart;
Attrib.m_dwVertexCount = pAttributes[i].VertexCount;
Attrib.m_Material = Material;
m_Sections.push_back(Attrib);
}
// Copy the vertex data
BYTE* pVertex;
hr = pVB->Lock(0, vbdesc.Size,(BYTE**)&pVertex, 0);
DWORD dwTextures = ((vbdesc.FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT);
DWORD dwStride = D3DXGetFVFVertexSize(vbdesc.FVF);
// Create array pointers. May be setup depending on contents of mesh
D3DXVECTOR3* pPosition = NULL;
D3DXVECTOR3* pNormal = NULL;
D3DXVECTOR4* pDiffuse = NULL;
D3DXVECTOR4* pSpecular = NULL;
vector<D3DXVECTOR2*> Textures;
vector<D3DXVECTOR4*> BoneIndices;
vector<D3DXVECTOR4*> BoneWeights;
NVVertexData* pData = NULL;
SetNumVertices(vbdesc.Size / dwStride);
m_dwNumWeights = 0;
DWORD dwNumBoneQuadruples = 0;
if (m_pBoneTransforms)
{
if ((vbdesc.FVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ)
{
switch(vbdesc.FVF & D3DFVF_POSITION_MASK)
{
case D3DFVF_XYZB1:
m_dwNumWeights = 1;
break;
case D3DFVF_XYZB2:
m_dwNumWeights = 2;
break;
case D3DFVF_XYZB3:
m_dwNumWeights = 3;
break;
case D3DFVF_XYZB4:
m_dwNumWeights = 4;
break;
case D3DFVF_XYZB5:
m_dwNumWeights = 5;
break;
default:
NVASSERT(0, "ERROR: Num weights not known");
break;
}
dwNumBoneQuadruples = (m_dwNumWeights + 3) / 4;
}
else
{
m_dwNumWeights = 1;
dwNumBoneQuadruples = 1;
}
}
// Create vertex data in the pass for the geometry we found in the mesh
if (vbdesc.FVF & D3DFVF_XYZ || m_pBoneTransforms)
{
pData = AddVertexData(NVVERT_POSITION, D3DDATATYPE_FLOAT3);
pPosition = GetDataPointer<D3DXVECTOR3, D3DDATATYPE_FLOAT3>(pData);
for (i = 0; i < dwNumBoneQuadruples; i++)
{
pData = AddVertexData(NVVERT_BONEINDICES0 + i, D3DDATATYPE_FLOAT4);
BoneIndices.push_back(GetDataPointer<D3DXVECTOR4, D3DDATATYPE_FLOAT4>(pData));
pData = AddVertexData(NVVERT_BONEWEIGHTS0 + i, D3DDATATYPE_FLOAT4);
BoneWeights.push_back(GetDataPointer<D3DXVECTOR4, D3DDATATYPE_FLOAT4>(pData));
}
}
// Normal
if (vbdesc.FVF & D3DFVF_NORMAL)
{
pData = AddVertexData(NVVERT_NORMAL, D3DDATATYPE_FLOAT3);
pNormal = GetDataPointer<D3DXVECTOR3, D3DDATATYPE_FLOAT3>(pData);
}
// Diffuse
if (vbdesc.FVF & D3DFVF_DIFFUSE)
{
pData = AddVertexData(NVVERT_DIFFUSE, D3DDATATYPE_FLOAT4);
pDiffuse = GetDataPointer<D3DXVECTOR4, D3DDATATYPE_FLOAT4>(pData);
}
// Specular
if (vbdesc.FVF & D3DFVF_SPECULAR)
{
pData = AddVertexData(NVVERT_SPECULAR, D3DDATATYPE_FLOAT4);
pSpecular = GetDataPointer<D3DXVECTOR4, D3DDATATYPE_FLOAT4>(pData);
}
// Up to 8 texture coordinates
for (dwTexCount = 0; dwTexCount < dwTextures; dwTexCount++)
{
pData = AddVertexData(NVVERT_TEXTURE0 + dwTexCount, D3DDATATYPE_FLOAT2);
Textures.push_back(GetDataPointer<D3DXVECTOR2, D3DDATATYPE_FLOAT2>(pData));
}
for (i = 0; i < (vbdesc.Size / dwStride); i++)
{
BYTE* pVert = pVertex;
if (m_dwNumWeights == 0)
{
// Position
if (vbdesc.FVF & D3DFVF_XYZ)
{
pPosition[i] = (*(D3DXVECTOR3*)pVert);
pVert += sizeof(D3DXVECTOR3);
}
}
else
{
DWORD dwWeightCount;
DWORD dwIndexCount;
DWORD dwQuadCount;
pPosition[i] = (*(D3DXVECTOR3*)pVert);
pVert += sizeof(D3DXVECTOR3);
// Add the weights. We retrieve the list of floats and pack them
// into vec4's. The last weight is 1 - totalweights
float ftotalweight = 0.0f;
dwQuadCount = 0;
dwWeightCount = 0;
BoneWeights[dwQuadCount][i] = D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f);
while (1)
{
float fweight;
bool bLastWeight = false;
if (dwWeightCount == (m_dwNumWeights - 1))
{
fweight = 1.0f - ftotalweight;
bLastWeight = true;
}
else
{
fweight = (*(float*)pVert);
pVert += sizeof(float);
ftotalweight += fweight;
}
if ((dwWeightCount & 0x3) == 0)
{
BoneWeights[dwQuadCount][i].x = fweight;
}
else if ((dwWeightCount & 0x3) == 1)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -