Added: shape2obj project to convert NeL .shape to standard .obj file format
This commit is contained in:
parent
9cd35a8a5d
commit
4d8cde70b2
1 changed files with 668 additions and 0 deletions
668
code/nel/tools/3d/shape2obj/main.cpp
Normal file
668
code/nel/tools/3d/shape2obj/main.cpp
Normal file
|
@ -0,0 +1,668 @@
|
|||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <nel/misc/file.h>
|
||||
#include <nel/3d/mesh.h>
|
||||
#include <nel/3d/mesh_mrm.h>
|
||||
#include <nel/3d/mesh_mrm_skinned.h>
|
||||
#include <nel/3d/scene.h>
|
||||
#include <nel/3d/register_3d.h>
|
||||
#include <nel/misc/app_context.h>
|
||||
#include <nel/misc/o_xml.h>
|
||||
#include <nel/misc/i_xml.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace NLMISC;
|
||||
using namespace NL3D;
|
||||
using namespace std;
|
||||
|
||||
struct CVertex
|
||||
{
|
||||
CVector vertex;
|
||||
CVector normal;
|
||||
CUV uv;
|
||||
};
|
||||
|
||||
bool operator == (const CVertex &v1, const CVertex &v2)
|
||||
{
|
||||
return (v1.vertex == v2.vertex) && (v1.normal == v2.normal) && (v1.uv == v2.uv);
|
||||
}
|
||||
|
||||
bool operator < (const CVertex &v1, const CVertex &v2)
|
||||
{
|
||||
return (v1.vertex < v2.vertex);
|
||||
}
|
||||
|
||||
const CIndexBuffer *getRdrPassPrimitiveBlock(const CMeshMRMGeom *mesh, uint lodId, uint renderPass)
|
||||
{
|
||||
return &(mesh->getRdrPassPrimitiveBlock(lodId, renderPass));
|
||||
}
|
||||
|
||||
// ***************************************************************************
|
||||
|
||||
const CIndexBuffer *getRdrPassPrimitiveBlock(const CMeshMRMSkinnedGeom *mesh, uint lodId, uint renderPass)
|
||||
{
|
||||
static CIndexBuffer block;
|
||||
mesh->getRdrPassPrimitiveBlock(lodId, renderPass, block);
|
||||
return █
|
||||
}
|
||||
|
||||
// ***************************************************************************
|
||||
|
||||
bool ProcessMeshMRMSkinned(const std::string &filename, IShape *shapeMesh);
|
||||
bool ProcessMeshMRM(const std::string &filename, IShape *shapeMesh);
|
||||
bool ProcessMesh(const std::string &filename, IShape *shapeMesh);
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
cout << "Syntax : shape2obj <NeL .shape file>" << endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!NLMISC::INelContext::isContextInitialised()) new NLMISC::CApplicationContext();
|
||||
|
||||
registerSerial3d();
|
||||
CScene::registerBasics();
|
||||
|
||||
IShape *shapeMesh = NULL;
|
||||
|
||||
CIFile ifile;
|
||||
|
||||
// Sream a shape
|
||||
CShapeStream streamShape;
|
||||
|
||||
string filename = argv[1];
|
||||
|
||||
if (!ifile.open(filename)) return 1;
|
||||
|
||||
try
|
||||
{
|
||||
// Stream it
|
||||
streamShape.serial(ifile);
|
||||
|
||||
// Add the shape
|
||||
shapeMesh = streamShape.getShapePointer();
|
||||
}
|
||||
catch (Exception& e)
|
||||
{
|
||||
cout << "Error : " << e.what() << endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ProcessMeshMRMSkinned(filename, shapeMesh)) return 0;
|
||||
if (ProcessMeshMRM(filename, shapeMesh)) return 0;
|
||||
if (ProcessMesh(filename, shapeMesh)) return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ProcessMeshMRMSkinned(const std::string &filename, IShape *shapeMesh)
|
||||
{
|
||||
CMeshMRMSkinned *mesh = dynamic_cast<CMeshMRMSkinned*>(shapeMesh);
|
||||
|
||||
if (!mesh) return false;
|
||||
|
||||
COFile ofile;
|
||||
|
||||
CMeshMRMSkinnedGeom* meshIn = (CMeshMRMSkinnedGeom*)&mesh->getMeshGeom();
|
||||
|
||||
std::vector<CMesh::CSkinWeight> skinWeights;
|
||||
meshIn->getSkinWeights(skinWeights);
|
||||
CVertexBuffer vertexBuffer;
|
||||
meshIn->getVertexBuffer(vertexBuffer);
|
||||
|
||||
CVertexBufferRead vba;
|
||||
vertexBuffer.lock (vba);
|
||||
uint i, j;
|
||||
|
||||
// **** Select the Lod.
|
||||
uint numLods= meshIn->getNbLod();
|
||||
|
||||
// get the max tris displayed
|
||||
float numMeshFacesMin= (float)meshIn->getLevelDetail().MinFaceUsed;
|
||||
float numMeshFacesMax= (float)meshIn->getLevelDetail().MaxFaceUsed;
|
||||
// find the lod
|
||||
sint lodId = numLods-1;
|
||||
|
||||
// **** First, for the best lod indicate what vertex is used or not. Also index geomorphs to know what real vertex is used
|
||||
vector<sint> vertexUsed;
|
||||
// -1 means "not used"
|
||||
vertexUsed.resize(skinWeights.size(), -1);
|
||||
// Parse all triangles.
|
||||
for(i=0;i<meshIn->getNbRdrPass(lodId); ++i)
|
||||
{
|
||||
const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
|
||||
CIndexBufferRead iba;
|
||||
pb->lock (iba);
|
||||
if (iba.getFormat() == CIndexBuffer::Indices32)
|
||||
{
|
||||
const uint32 *triPtr= (const uint32 *) iba.getPtr();
|
||||
for(j=0;j<pb->getNumIndexes(); ++j)
|
||||
{
|
||||
uint idx= *triPtr;
|
||||
// Flag the vertex with its own index => used.
|
||||
vertexUsed[idx]= idx;
|
||||
triPtr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint16 *triPtr= (const uint16 *) iba.getPtr();
|
||||
for(j=0;j<pb->getNumIndexes(); ++j)
|
||||
{
|
||||
uint idx= *triPtr;
|
||||
// Flag the vertex with its own index => used.
|
||||
vertexUsed[idx]= idx;
|
||||
triPtr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Special for Geomorphs: must take The End target vertex.
|
||||
const std::vector<CMRMWedgeGeom> &geomorphs= meshIn->getGeomorphs(lodId);
|
||||
for(i=0;i<geomorphs.size(); ++i)
|
||||
{
|
||||
uint trueIdx= geomorphs[i].End;
|
||||
// map to the Geomorph Target.
|
||||
vertexUsed[i]= trueIdx;
|
||||
// mark also the real vertex used as used.
|
||||
vertexUsed[trueIdx]= trueIdx;
|
||||
}
|
||||
|
||||
|
||||
// **** For all vertices used (not geomorphs), compute vertex Skins.
|
||||
vector<CVertex> shadowVertices;
|
||||
vector<sint> vertexToVSkin;
|
||||
vertexToVSkin.resize(vertexUsed.size());
|
||||
shadowVertices.reserve(vertexUsed.size());
|
||||
// use a map to remove duplicates (because of UV/normal discontinuities before!!)
|
||||
map<CVertex, uint> shadowVertexMap;
|
||||
uint numMerged= 0;
|
||||
// Skip Geomorphs.
|
||||
for(i=geomorphs.size();i<vertexUsed.size(); ++i)
|
||||
{
|
||||
// If this vertex is used.
|
||||
if(vertexUsed[i]!=-1)
|
||||
{
|
||||
// Build the vertex
|
||||
CVertex shadowVert;
|
||||
CUV uv;
|
||||
shadowVert.vertex = *(CVector*)vba.getVertexCoordPointer(i);
|
||||
shadowVert.normal = *(CVector*)vba.getNormalCoordPointer(i);
|
||||
shadowVert.uv = *(CUV*)vba.getTexCoordPointer(i);
|
||||
/*
|
||||
// Select the best Matrix.
|
||||
CMesh::CSkinWeight sw= skinWeights[i];
|
||||
float maxW= 0;
|
||||
uint matId= 0;
|
||||
for(j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
|
||||
{
|
||||
// if no more matrix influenced, stop
|
||||
if(sw.Weights[j]==0)
|
||||
break;
|
||||
if(sw.Weights[j]>maxW)
|
||||
{
|
||||
matId= sw.MatrixId[j];
|
||||
maxW= sw.Weights[j];
|
||||
}
|
||||
}
|
||||
// shadowVert.MatrixId= matId;
|
||||
*/
|
||||
// If dont find the shadowVertex in the map.
|
||||
map<CVertex, uint>::iterator it= shadowVertexMap.find(shadowVert);
|
||||
if(it==shadowVertexMap.end())
|
||||
{
|
||||
// Append
|
||||
uint index= shadowVertices.size();
|
||||
vertexToVSkin[i]= index;
|
||||
shadowVertices.push_back(shadowVert);
|
||||
shadowVertexMap.insert(make_pair(shadowVert, index));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ok, map.
|
||||
vertexToVSkin[i]= it->second;
|
||||
numMerged++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ofstream ofs(string(filename + ".obj").c_str());
|
||||
|
||||
for(size_t y = 0; y < shadowVertices.size(); ++y)
|
||||
{
|
||||
CVector v = shadowVertices[y].vertex;
|
||||
CVector vn = shadowVertices[y].normal;
|
||||
CUV vt = shadowVertices[y].uv;
|
||||
|
||||
ofs << "v " << v.x << " " << v.y << " " << v.z << endl;
|
||||
ofs << "vn " << vn.x << " " << vn.y << " " << vn.z << endl;
|
||||
ofs << "vt " << vt.U << " " << vt.V << endl;
|
||||
}
|
||||
|
||||
// **** Get All Faces
|
||||
// Final List Of Triangles that match the bone.
|
||||
vector<uint32> shadowTriangles;
|
||||
shadowTriangles.reserve(1000);
|
||||
// Parse all input tri of the mesh.
|
||||
for(i=0; i<meshIn->getNbRdrPass(lodId); ++i)
|
||||
{
|
||||
ofs << "g pass" << i << endl;
|
||||
|
||||
const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
|
||||
CIndexBufferRead iba;
|
||||
pb->lock (iba);
|
||||
if (iba.getFormat() == CIndexBuffer::Indices32)
|
||||
{
|
||||
const uint32 *triPtr= (const uint32 *) iba.getPtr();
|
||||
|
||||
for(j=0; j<pb->getNumIndexes(); ++j)
|
||||
{
|
||||
uint idx= *triPtr;
|
||||
// Get the real Vertex (ie not the geomporhed one).
|
||||
idx= vertexUsed[idx];
|
||||
// Get the ShadowVertex associated
|
||||
idx= vertexToVSkin[idx];
|
||||
|
||||
shadowTriangles.push_back(idx);
|
||||
triPtr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint16 *triPtr= (const uint16 *) iba.getPtr();
|
||||
for(j=0; j<pb->getNumIndexes(); ++j)
|
||||
{
|
||||
uint idx= *triPtr;
|
||||
// Get the real Vertex (ie not the geomporhed one).
|
||||
idx= vertexUsed[idx];
|
||||
// Get the ShadowVertex associated
|
||||
idx= vertexToVSkin[idx];
|
||||
|
||||
shadowTriangles.push_back(idx);
|
||||
triPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t pass = 0; pass<shadowTriangles.size(); pass += 3)
|
||||
{
|
||||
ofs << "f " << shadowTriangles[pass]+1 << "/" << shadowTriangles[pass]+1 << "/" << shadowTriangles[pass]+1 << " ";
|
||||
ofs << shadowTriangles[pass+1]+1 << "/" << shadowTriangles[pass+1]+1 << "/" << shadowTriangles[pass+1]+1 << " ";
|
||||
ofs << shadowTriangles[pass+2]+1 << "/" << shadowTriangles[pass+2]+1 << "/" << shadowTriangles[pass+2]+1 << endl;
|
||||
}
|
||||
|
||||
shadowTriangles.clear();
|
||||
}
|
||||
|
||||
ofs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcessMeshMRM(const std::string &filename, IShape *shapeMesh)
|
||||
{
|
||||
CMeshMRM *mesh = dynamic_cast<CMeshMRM*>(shapeMesh);
|
||||
|
||||
if (!mesh) return false;
|
||||
|
||||
COFile ofile;
|
||||
|
||||
CMeshMRMGeom* meshIn = (CMeshMRMGeom*)&mesh->getMeshGeom();
|
||||
|
||||
std::vector<CMesh::CSkinWeight> skinWeights = meshIn->getSkinWeights();
|
||||
CVertexBuffer vertexBuffer = meshIn->getVertexBuffer();
|
||||
|
||||
CVertexBufferRead vba;
|
||||
vertexBuffer.lock (vba);
|
||||
uint i, j;
|
||||
|
||||
// **** Select the Lod.
|
||||
uint numLods= meshIn->getNbLod();
|
||||
|
||||
// get the max tris displayed
|
||||
float numMeshFacesMin= (float)meshIn->getLevelDetail().MinFaceUsed;
|
||||
float numMeshFacesMax= (float)meshIn->getLevelDetail().MaxFaceUsed;
|
||||
// find the lod
|
||||
sint lodId = numLods-1;
|
||||
|
||||
// **** First, for the best lod indicate what vertex is used or not. Also index geomorphs to know what real vertex is used
|
||||
vector<sint> vertexUsed;
|
||||
// -1 means "not used"
|
||||
vertexUsed.resize(skinWeights.size(), -1);
|
||||
// Parse all triangles.
|
||||
for(i=0;i<meshIn->getNbRdrPass(lodId); ++i)
|
||||
{
|
||||
const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
|
||||
CIndexBufferRead iba;
|
||||
pb->lock (iba);
|
||||
if (iba.getFormat() == CIndexBuffer::Indices32)
|
||||
{
|
||||
const uint32 *triPtr= (const uint32 *) iba.getPtr();
|
||||
for(j=0;j<pb->getNumIndexes(); ++j)
|
||||
{
|
||||
uint idx= *triPtr;
|
||||
// Flag the vertex with its own index => used.
|
||||
vertexUsed[idx]= idx;
|
||||
triPtr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint16 *triPtr= (const uint16 *) iba.getPtr();
|
||||
for(j=0;j<pb->getNumIndexes(); ++j)
|
||||
{
|
||||
uint idx= *triPtr;
|
||||
// Flag the vertex with its own index => used.
|
||||
vertexUsed[idx]= idx;
|
||||
triPtr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Special for Geomorphs: must take The End target vertex.
|
||||
const std::vector<CMRMWedgeGeom> &geomorphs= meshIn->getGeomorphs(lodId);
|
||||
for(i=0;i<geomorphs.size(); ++i)
|
||||
{
|
||||
uint trueIdx= geomorphs[i].End;
|
||||
// map to the Geomorph Target.
|
||||
vertexUsed[i]= trueIdx;
|
||||
// mark also the real vertex used as used.
|
||||
vertexUsed[trueIdx]= trueIdx;
|
||||
}
|
||||
|
||||
|
||||
// **** For all vertices used (not geomorphs), compute vertex Skins.
|
||||
vector<CVertex> shadowVertices;
|
||||
vector<sint> vertexToVSkin;
|
||||
vertexToVSkin.resize(vertexUsed.size());
|
||||
shadowVertices.reserve(vertexUsed.size());
|
||||
// use a map to remove duplicates (because of UV/normal discontinuities before!!)
|
||||
map<CVertex, uint> shadowVertexMap;
|
||||
uint numMerged= 0;
|
||||
// Skip Geomorphs.
|
||||
for(i=geomorphs.size();i<vertexUsed.size(); ++i)
|
||||
{
|
||||
// If this vertex is used.
|
||||
if(vertexUsed[i]!=-1)
|
||||
{
|
||||
// Build the vertex
|
||||
CVertex shadowVert;
|
||||
CUV uv;
|
||||
shadowVert.vertex = *(CVector*)vba.getVertexCoordPointer(i);
|
||||
shadowVert.normal = *(CVector*)vba.getNormalCoordPointer(i);
|
||||
shadowVert.uv = *(CUV*)vba.getTexCoordPointer(i);
|
||||
/*
|
||||
// Select the best Matrix.
|
||||
CMesh::CSkinWeight sw= skinWeights[i];
|
||||
float maxW= 0;
|
||||
uint matId= 0;
|
||||
for(j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
|
||||
{
|
||||
// if no more matrix influenced, stop
|
||||
if(sw.Weights[j]==0)
|
||||
break;
|
||||
if(sw.Weights[j]>maxW)
|
||||
{
|
||||
matId= sw.MatrixId[j];
|
||||
maxW= sw.Weights[j];
|
||||
}
|
||||
}
|
||||
// shadowVert.MatrixId= matId;
|
||||
*/
|
||||
// If dont find the shadowVertex in the map.
|
||||
map<CVertex, uint>::iterator it= shadowVertexMap.find(shadowVert);
|
||||
if(it==shadowVertexMap.end())
|
||||
{
|
||||
// Append
|
||||
uint index= shadowVertices.size();
|
||||
vertexToVSkin[i]= index;
|
||||
shadowVertices.push_back(shadowVert);
|
||||
shadowVertexMap.insert(make_pair(shadowVert, index));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ok, map.
|
||||
vertexToVSkin[i]= it->second;
|
||||
numMerged++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ofstream ofs(string(filename + ".obj").c_str());
|
||||
|
||||
for(size_t y = 0; y < shadowVertices.size(); ++y)
|
||||
{
|
||||
CVector v = shadowVertices[y].vertex;
|
||||
CVector vn = shadowVertices[y].normal;
|
||||
CUV vt = shadowVertices[y].uv;
|
||||
|
||||
ofs << "v " << v.x << " " << v.y << " " << v.z << endl;
|
||||
ofs << "vn " << vn.x << " " << vn.y << " " << vn.z << endl;
|
||||
ofs << "vt " << vt.U << " " << vt.V << endl;
|
||||
}
|
||||
|
||||
// **** Get All Faces
|
||||
// Final List Of Triangles that match the bone.
|
||||
vector<uint32> shadowTriangles;
|
||||
shadowTriangles.reserve(1000);
|
||||
// Parse all input tri of the mesh.
|
||||
for(i=0; i<meshIn->getNbRdrPass(lodId); ++i)
|
||||
{
|
||||
ofs << "g pass" << i << endl;
|
||||
|
||||
const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
|
||||
CIndexBufferRead iba;
|
||||
pb->lock (iba);
|
||||
if (iba.getFormat() == CIndexBuffer::Indices32)
|
||||
{
|
||||
const uint32 *triPtr= (const uint32 *) iba.getPtr();
|
||||
|
||||
for(j=0; j<pb->getNumIndexes(); ++j)
|
||||
{
|
||||
uint idx= *triPtr;
|
||||
// Get the real Vertex (ie not the geomporhed one).
|
||||
idx= vertexUsed[idx];
|
||||
// Get the ShadowVertex associated
|
||||
idx= vertexToVSkin[idx];
|
||||
|
||||
shadowTriangles.push_back(idx);
|
||||
triPtr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint16 *triPtr= (const uint16 *) iba.getPtr();
|
||||
for(j=0; j<pb->getNumIndexes(); ++j)
|
||||
{
|
||||
uint idx= *triPtr;
|
||||
// Get the real Vertex (ie not the geomporhed one).
|
||||
idx= vertexUsed[idx];
|
||||
// Get the ShadowVertex associated
|
||||
idx= vertexToVSkin[idx];
|
||||
|
||||
shadowTriangles.push_back(idx);
|
||||
triPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t pass = 0; pass<shadowTriangles.size(); pass += 3)
|
||||
{
|
||||
ofs << "f " << shadowTriangles[pass]+1 << "/" << shadowTriangles[pass]+1 << "/" << shadowTriangles[pass]+1 << " ";
|
||||
ofs << shadowTriangles[pass+1]+1 << "/" << shadowTriangles[pass+1]+1 << "/" << shadowTriangles[pass+1]+1 << " ";
|
||||
ofs << shadowTriangles[pass+2]+1 << "/" << shadowTriangles[pass+2]+1 << "/" << shadowTriangles[pass+2]+1 << endl;
|
||||
}
|
||||
|
||||
shadowTriangles.clear();
|
||||
}
|
||||
|
||||
ofs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcessMesh(const std::string &filename, IShape *shapeMesh)
|
||||
{
|
||||
CMesh *mesh = dynamic_cast<CMesh*>(shapeMesh);
|
||||
|
||||
if (!mesh) return false;
|
||||
|
||||
COFile ofile;
|
||||
|
||||
CMeshGeom* meshIn = (CMeshGeom*)&mesh->getMeshGeom();
|
||||
|
||||
CVertexBuffer vertexBuffer = meshIn->getVertexBuffer();
|
||||
|
||||
// CVertexBufferRead vba;
|
||||
// vertexBuffer.lock (vba);
|
||||
|
||||
uint i = vertexBuffer.getNumVertices();
|
||||
|
||||
std::vector<NLMISC::CVector> vertices;
|
||||
meshIn->retrieveVertices(vertices);
|
||||
|
||||
std::vector<uint32> indices;
|
||||
meshIn->retrieveTriangles(indices);
|
||||
|
||||
|
||||
// **** For all vertices used (not geomorphs), compute vertex Skins.
|
||||
vector<CVertex> shadowVertices;
|
||||
vector<sint> vertexToVSkin;
|
||||
vertexToVSkin.resize(indices.size());
|
||||
shadowVertices.reserve(indices.size());
|
||||
// use a map to remove duplicates (because of UV/normal discontinuities before!!)
|
||||
map<CVertex, uint> shadowVertexMap;
|
||||
uint numMerged= 0;
|
||||
// Skip Geomorphs.
|
||||
for(i=0;i<indices.size(); ++i)
|
||||
{
|
||||
// Build the vertex
|
||||
CVertex shadowVert;
|
||||
CUV uv;
|
||||
shadowVert.vertex = *(CVector*)vba.getVertexCoordPointer(i);
|
||||
shadowVert.normal = *(CVector*)vba.getNormalCoordPointer(i);
|
||||
shadowVert.uv = *(CUV*)vba.getTexCoordPointer(i);
|
||||
|
||||
// Select the best Matrix.
|
||||
CMesh::CSkinWeight sw= skinWeights[i];
|
||||
float maxW= 0;
|
||||
uint matId= 0;
|
||||
for(j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
|
||||
{
|
||||
// if no more matrix influenced, stop
|
||||
if(sw.Weights[j]==0)
|
||||
break;
|
||||
if(sw.Weights[j]>maxW)
|
||||
{
|
||||
matId= sw.MatrixId[j];
|
||||
maxW= sw.Weights[j];
|
||||
}
|
||||
}
|
||||
|
||||
// If dont find the shadowVertex in the map.
|
||||
map<CVertex, uint>::iterator it= shadowVertexMap.find(shadowVert);
|
||||
if(it==shadowVertexMap.end())
|
||||
{
|
||||
// Append
|
||||
uint index= shadowVertices.size();
|
||||
vertexToVSkin[i]= index;
|
||||
shadowVertices.push_back(shadowVert);
|
||||
shadowVertexMap.insert(make_pair(shadowVert, index));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ok, map.
|
||||
vertexToVSkin[i]= it->second;
|
||||
numMerged++;
|
||||
}
|
||||
}
|
||||
|
||||
ofstream ofs(string(filename + ".obj").c_str());
|
||||
|
||||
for(size_t y = 0; y < shadowVertices.size(); ++y)
|
||||
{
|
||||
CVector v = shadowVertices[y].vertex;
|
||||
CVector vn = shadowVertices[y].normal;
|
||||
CUV vt = shadowVertices[y].uv;
|
||||
|
||||
ofs << "v " << v.x << " " << v.y << " " << v.z << endl;
|
||||
ofs << "vn " << vn.x << " " << vn.y << " " << vn.z << endl;
|
||||
ofs << "vt " << vt.U << " " << vt.V << endl;
|
||||
}
|
||||
|
||||
// **** Get All Faces
|
||||
// Final List Of Triangles that match the bone.
|
||||
vector<uint32> shadowTriangles;
|
||||
shadowTriangles.reserve(1000);
|
||||
// Parse all input tri of the mesh.
|
||||
for(i=0; i<meshIn->getNbRdrPass(lodId); ++i)
|
||||
{
|
||||
ofs << "g pass" << i << endl;
|
||||
|
||||
const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
|
||||
CIndexBufferRead iba;
|
||||
pb->lock (iba);
|
||||
if (iba.getFormat() == CIndexBuffer::Indices32)
|
||||
{
|
||||
const uint32 *triPtr= (const uint32 *) iba.getPtr();
|
||||
|
||||
for(j=0; j<pb->getNumIndexes(); ++j)
|
||||
{
|
||||
uint idx= *triPtr;
|
||||
// Get the real Vertex (ie not the geomporhed one).
|
||||
idx= vertexUsed[idx];
|
||||
// Get the ShadowVertex associated
|
||||
idx= vertexToVSkin[idx];
|
||||
|
||||
shadowTriangles.push_back(idx);
|
||||
triPtr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint16 *triPtr= (const uint16 *) iba.getPtr();
|
||||
for(j=0; j<pb->getNumIndexes(); ++j)
|
||||
{
|
||||
uint idx= *triPtr;
|
||||
// Get the real Vertex (ie not the geomporhed one).
|
||||
idx= vertexUsed[idx];
|
||||
// Get the ShadowVertex associated
|
||||
idx= vertexToVSkin[idx];
|
||||
|
||||
shadowTriangles.push_back(idx);
|
||||
triPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t pass = 0; pass<shadowTriangles.size(); pass += 3)
|
||||
{
|
||||
ofs << "f " << shadowTriangles[pass]+1 << "/" << shadowTriangles[pass]+1 << "/" << shadowTriangles[pass]+1 << " ";
|
||||
ofs << shadowTriangles[pass+1]+1 << "/" << shadowTriangles[pass+1]+1 << "/" << shadowTriangles[pass+1]+1 << " ";
|
||||
ofs << shadowTriangles[pass+2]+1 << "/" << shadowTriangles[pass+2]+1 << "/" << shadowTriangles[pass+2]+1 << endl;
|
||||
}
|
||||
|
||||
shadowTriangles.clear();
|
||||
}
|
||||
|
||||
ofs.close();
|
||||
|
||||
return true;
|
||||
}
|
Loading…
Reference in a new issue