mirror of
https://github.com/bulletphysics/bullet3
synced 2025-01-19 05:20:06 +00:00
753 lines
23 KiB
C++
753 lines
23 KiB
C++
/*
|
|
Bullet Collision Detection and Physics Library http://bulletphysics.org
|
|
This file is Copyright (c) 2014 Google Inc.
|
|
|
|
This software is provided 'as-is', without any express or implied warranty.
|
|
In no event will the authors be held liable for any damages arising from the use of this software.
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it freely,
|
|
subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
//original author: Erwin Coumans
|
|
*/
|
|
|
|
|
|
#include "LoadMeshFromCollada.h"
|
|
#include <stdio.h> //fopen
|
|
#include "Bullet3Common/b3AlignedObjectArray.h"
|
|
#include <string>
|
|
#include "../../ThirdPartyLibs/tinyxml2/tinyxml2.h"
|
|
using namespace tinyxml2;
|
|
|
|
#include "Bullet3Common/b3FileUtils.h"
|
|
#include "LinearMath/btHashMap.h"
|
|
#include <assert.h>
|
|
#include "btMatrix4x4.h"
|
|
|
|
|
|
#define MAX_VISUAL_SHAPES 512
|
|
|
|
|
|
struct VertexSource
|
|
{
|
|
std::string m_positionArrayId;
|
|
std::string m_normalArrayId;
|
|
};
|
|
|
|
struct TokenFloatArray
|
|
{
|
|
btAlignedObjectArray<float>& m_values;
|
|
TokenFloatArray(btAlignedObjectArray<float>& floatArray)
|
|
:m_values(floatArray) {
|
|
}
|
|
inline void add(const char* token)
|
|
{
|
|
float v = atof(token);
|
|
m_values.push_back(v);
|
|
}
|
|
};
|
|
struct TokenIntArray
|
|
{
|
|
btAlignedObjectArray<int>& m_values;
|
|
TokenIntArray(btAlignedObjectArray<int>& intArray)
|
|
:m_values(intArray) {
|
|
}
|
|
inline void add(const char* token)
|
|
{
|
|
float v = atoi(token);
|
|
m_values.push_back(v);
|
|
}
|
|
};
|
|
|
|
template <typename AddToken>
|
|
void tokenize(const std::string& str, AddToken& tokenAdder, const std::string& delimiters = " ")
|
|
{
|
|
std::string::size_type pos, lastPos = 0;
|
|
while(true)
|
|
{
|
|
pos = str.find_first_of(delimiters, lastPos);
|
|
if(pos == std::string::npos)
|
|
{
|
|
pos = str.length();
|
|
if(pos != lastPos)
|
|
{
|
|
tokenAdder.add(str.data()+lastPos);
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if(pos != lastPos)
|
|
{
|
|
tokenAdder.add(str.data()+lastPos);
|
|
}
|
|
}
|
|
lastPos = pos + 1;
|
|
}
|
|
}
|
|
|
|
|
|
void readFloatArray(XMLElement* source, btAlignedObjectArray<float>& floatArray, int& componentStride)
|
|
{
|
|
int numVals, stride;
|
|
XMLElement* array = source->FirstChildElement("float_array");
|
|
if(array)
|
|
{
|
|
componentStride = 1;
|
|
if (source->FirstChildElement("technique_common")->FirstChildElement("accessor")->QueryIntAttribute("stride", &stride)!= XML_NO_ATTRIBUTE)
|
|
{
|
|
componentStride = stride;
|
|
}
|
|
array->QueryIntAttribute("count", &numVals);
|
|
TokenFloatArray adder(floatArray);
|
|
floatArray.reserve(numVals);
|
|
tokenize(array->GetText(),adder);
|
|
assert(floatArray.size() == numVals);
|
|
}
|
|
}
|
|
|
|
btVector3 getVector3FromXmlText(const char* text)
|
|
{
|
|
btVector3 vec(0,0,0);
|
|
btAlignedObjectArray<float> floatArray;
|
|
TokenFloatArray adder(floatArray);
|
|
floatArray.reserve(3);
|
|
tokenize(text,adder);
|
|
assert(floatArray.size() == 3);
|
|
if (floatArray.size()==3)
|
|
{
|
|
vec.setValue(floatArray[0],floatArray[1],floatArray[2]);
|
|
}
|
|
return vec;
|
|
}
|
|
|
|
btVector4 getVector4FromXmlText(const char* text)
|
|
{
|
|
btVector4 vec(0,0,0,0);
|
|
btAlignedObjectArray<float> floatArray;
|
|
TokenFloatArray adder(floatArray);
|
|
floatArray.reserve(4);
|
|
tokenize(text,adder);
|
|
assert(floatArray.size() == 4);
|
|
if (floatArray.size()==4)
|
|
{
|
|
vec.setValue(floatArray[0],floatArray[1],floatArray[2],floatArray[3]);
|
|
}
|
|
return vec;
|
|
}
|
|
|
|
|
|
void readLibraryGeometries(XMLDocument& doc, btAlignedObjectArray<GLInstanceGraphicsShape>& visualShapes, btHashMap<btHashString,int>& name2Shape, float extraScaling)
|
|
{
|
|
btHashMap<btHashString,XMLElement* > allSources;
|
|
btHashMap<btHashString,VertexSource> vertexSources;
|
|
for(XMLElement* geometry = doc.RootElement()->FirstChildElement("library_geometries")->FirstChildElement("geometry");
|
|
geometry != NULL; geometry = geometry->NextSiblingElement("geometry"))
|
|
{
|
|
btAlignedObjectArray<btVector3> vertexPositions;
|
|
btAlignedObjectArray<btVector3> vertexNormals;
|
|
btAlignedObjectArray<int> indices;
|
|
|
|
const char* geometryName = geometry->Attribute("id");
|
|
for (XMLElement* mesh = geometry->FirstChildElement("mesh");(mesh != NULL); mesh = mesh->NextSiblingElement("mesh"))
|
|
{
|
|
XMLElement* vertices2 = mesh->FirstChildElement("vertices");
|
|
|
|
for (XMLElement* source = mesh->FirstChildElement("source");source != NULL;source = source->NextSiblingElement("source"))
|
|
{
|
|
const char* srcId= source->Attribute("id");
|
|
// printf("source id=%s\n",srcId);
|
|
allSources.insert(srcId,source);
|
|
}
|
|
const char* vertexId = vertices2->Attribute("id");
|
|
//printf("vertices id=%s\n",vertexId);
|
|
VertexSource vs;
|
|
for(XMLElement* input = vertices2->FirstChildElement("input");input != NULL;input = input->NextSiblingElement("input"))
|
|
{
|
|
const char* sem = input->Attribute("semantic");
|
|
std::string semName(sem);
|
|
// printf("sem=%s\n",sem);
|
|
// const char* src = input->Attribute("source");
|
|
// printf("src=%s\n",src);
|
|
const char* srcIdRef = input->Attribute("source");
|
|
std::string source_name;
|
|
source_name = std::string(srcIdRef);
|
|
source_name = source_name.erase(0, 1);
|
|
if (semName=="POSITION")
|
|
{
|
|
vs.m_positionArrayId = source_name;
|
|
}
|
|
if (semName=="NORMAL")
|
|
{
|
|
vs.m_normalArrayId = source_name;
|
|
}
|
|
}
|
|
vertexSources.insert(vertexId,vs);
|
|
|
|
for (XMLElement* primitive = mesh->FirstChildElement("triangles"); primitive; primitive = primitive->NextSiblingElement("triangles"))
|
|
{
|
|
std::string positionSourceName;
|
|
std::string normalSourceName;
|
|
int primitiveCount;
|
|
primitive->QueryIntAttribute("count", &primitiveCount);
|
|
int indexStride=1;
|
|
int posOffset = 0;
|
|
int normalOffset = 0;
|
|
int numIndices = 0;
|
|
{
|
|
|
|
for (XMLElement* input = primitive->FirstChildElement("input");input != NULL;input = input->NextSiblingElement("input"))
|
|
{
|
|
const char* sem = input->Attribute("semantic");
|
|
std::string semName(sem);
|
|
int offset = atoi(input->Attribute("offset"));
|
|
if ((offset+1)>indexStride)
|
|
indexStride=offset+1;
|
|
//printf("sem=%s\n",sem);
|
|
// const char* src = input->Attribute("source");
|
|
|
|
//printf("src=%s\n",src);
|
|
const char* srcIdRef = input->Attribute("source");
|
|
std::string source_name;
|
|
source_name = std::string(srcIdRef);
|
|
source_name = source_name.erase(0, 1);
|
|
|
|
if (semName=="VERTEX")
|
|
{
|
|
//now we have POSITION and possibly NORMAL too, using same index array (<p>)
|
|
VertexSource* vs = vertexSources[source_name.c_str()];
|
|
if (vs->m_positionArrayId.length())
|
|
{
|
|
positionSourceName = vs->m_positionArrayId;
|
|
posOffset = offset;
|
|
}
|
|
if (vs->m_normalArrayId.length())
|
|
{
|
|
normalSourceName = vs->m_normalArrayId;
|
|
normalOffset = offset;
|
|
}
|
|
}
|
|
if (semName=="NORMAL")
|
|
{
|
|
btAssert(normalSourceName.length()==0);
|
|
normalSourceName = source_name;
|
|
normalOffset = offset;
|
|
}
|
|
}
|
|
numIndices = primitiveCount * 3;
|
|
}
|
|
btAlignedObjectArray<float> positionFloatArray;
|
|
int posStride=1;
|
|
XMLElement** sourcePtr = allSources[positionSourceName.c_str()];
|
|
if (sourcePtr)
|
|
{
|
|
readFloatArray(*sourcePtr,positionFloatArray, posStride);
|
|
}
|
|
btAlignedObjectArray<float> normalFloatArray;
|
|
int normalStride=1;
|
|
sourcePtr = allSources[normalSourceName.c_str()];
|
|
if (sourcePtr)
|
|
{
|
|
readFloatArray(*sourcePtr,normalFloatArray,normalStride);
|
|
}
|
|
btAlignedObjectArray<int> curIndices;
|
|
curIndices.reserve(numIndices*indexStride);
|
|
TokenIntArray adder(curIndices);
|
|
tokenize(primitive->FirstChildElement("p")->GetText(),adder);
|
|
assert(curIndices.size() == numIndices*indexStride);
|
|
int indexOffset = vertexPositions.size();
|
|
|
|
for(int index=0; index<numIndices; index++)
|
|
{
|
|
int posIndex = curIndices[index*indexStride+posOffset];
|
|
int normalIndex = curIndices[index*indexStride+normalOffset];
|
|
vertexPositions.push_back(btVector3(extraScaling*positionFloatArray[posIndex*3+0],
|
|
extraScaling*positionFloatArray[posIndex*3+1],
|
|
extraScaling*positionFloatArray[posIndex*3+2]));
|
|
|
|
if (normalFloatArray.size() && (normalFloatArray.size()>normalIndex))
|
|
{
|
|
vertexNormals.push_back(btVector3(normalFloatArray[normalIndex*3+0],
|
|
normalFloatArray[normalIndex*3+1],
|
|
normalFloatArray[normalIndex*3+2]));
|
|
} else
|
|
{
|
|
//add a dummy normal of length zero, so it is easy to detect that it is an invalid normal
|
|
vertexNormals.push_back(btVector3(0,0,0));
|
|
}
|
|
}
|
|
int curNumIndices = indices.size();
|
|
indices.resize(curNumIndices+numIndices);
|
|
for(int index=0; index<numIndices; index++)
|
|
{
|
|
indices[curNumIndices+index] = index+indexOffset;
|
|
}
|
|
}//if(primitive != NULL)
|
|
}//for each mesh
|
|
|
|
int shapeIndex = visualShapes.size();
|
|
if (shapeIndex<MAX_VISUAL_SHAPES)
|
|
{
|
|
GLInstanceGraphicsShape& visualShape = visualShapes.expand();
|
|
{
|
|
visualShape.m_vertices = new b3AlignedObjectArray<GLInstanceVertex>;
|
|
visualShape.m_indices = new b3AlignedObjectArray<int>;
|
|
int indexBase = 0;
|
|
|
|
btAssert(vertexNormals.size()==vertexPositions.size());
|
|
for (int v=0;v<vertexPositions.size();v++)
|
|
{
|
|
GLInstanceVertex vtx;
|
|
vtx.xyzw[0] = vertexPositions[v].x();
|
|
vtx.xyzw[1] = vertexPositions[v].y();
|
|
vtx.xyzw[2] = vertexPositions[v].z();
|
|
vtx.xyzw[3] = 1.f;
|
|
vtx.normal[0] = vertexNormals[v].x();
|
|
vtx.normal[1] = vertexNormals[v].y();
|
|
vtx.normal[2] = vertexNormals[v].z();
|
|
vtx.uv[0] = 0.5f;
|
|
vtx.uv[1] = 0.5f;
|
|
visualShape.m_vertices->push_back(vtx);
|
|
}
|
|
|
|
for (int index=0;index<indices.size();index++)
|
|
{
|
|
visualShape.m_indices->push_back(indices[index]+indexBase);
|
|
}
|
|
|
|
|
|
//b3Printf(" index_count =%dand vertexPositions.size=%d\n",indices.size(), vertexPositions.size());
|
|
indexBase=visualShape.m_vertices->size();
|
|
visualShape.m_numIndices = visualShape.m_indices->size();
|
|
visualShape.m_numvertices = visualShape.m_vertices->size();
|
|
}
|
|
//b3Printf("geometry name=%s\n",geometryName);
|
|
name2Shape.insert(geometryName,shapeIndex);
|
|
} else
|
|
{
|
|
b3Warning("DAE exceeds number of visual shapes (%d/%d)",shapeIndex, MAX_VISUAL_SHAPES);
|
|
}
|
|
|
|
}//for each geometry
|
|
}
|
|
|
|
void readNodeHierarchy(XMLElement* node,btHashMap<btHashString,int>& name2Shape, btAlignedObjectArray<ColladaGraphicsInstance>& visualShapeInstances, const btMatrix4x4& parentTransMat)
|
|
{
|
|
|
|
|
|
btMatrix4x4 nodeTrans;
|
|
nodeTrans.setIdentity();
|
|
|
|
///todo(erwincoumans) we probably have to read the elements 'translate', 'scale', 'rotate' and 'matrix' in-order and accumulate them...
|
|
{
|
|
for (XMLElement* transElem = node->FirstChildElement("matrix");transElem;transElem=node->NextSiblingElement("matrix"))
|
|
{
|
|
if (transElem->GetText())
|
|
{
|
|
btAlignedObjectArray<float> floatArray;
|
|
TokenFloatArray adder(floatArray);
|
|
tokenize(transElem->GetText(),adder);
|
|
if (floatArray.size()==16)
|
|
{
|
|
btMatrix4x4 t(floatArray[0],floatArray[1],floatArray[2],floatArray[3],
|
|
floatArray[4],floatArray[5],floatArray[6],floatArray[7],
|
|
floatArray[8],floatArray[9],floatArray[10],floatArray[11],
|
|
floatArray[12],floatArray[13],floatArray[14],floatArray[15]);
|
|
|
|
nodeTrans = nodeTrans*t;
|
|
} else
|
|
{
|
|
b3Warning("Error: expected 16 elements in a <matrix> element, skipping\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
for (XMLElement* transElem = node->FirstChildElement("translate");transElem;transElem=node->NextSiblingElement("translate"))
|
|
{
|
|
if (transElem->GetText())
|
|
{
|
|
btVector3 pos = getVector3FromXmlText(transElem->GetText());
|
|
//nodePos+= unitScaling*parentScaling*pos;
|
|
btMatrix4x4 t;
|
|
t.setPureTranslation(pos);
|
|
nodeTrans = nodeTrans*t;
|
|
|
|
}
|
|
}
|
|
}
|
|
{
|
|
for(XMLElement* scaleElem = node->FirstChildElement("scale");
|
|
scaleElem!= NULL; scaleElem= node->NextSiblingElement("scale"))
|
|
{
|
|
if (scaleElem->GetText())
|
|
{
|
|
btVector3 scaling = getVector3FromXmlText(scaleElem->GetText());
|
|
btMatrix4x4 t;
|
|
t.setPureScaling(scaling);
|
|
nodeTrans = nodeTrans*t;
|
|
}
|
|
}
|
|
}
|
|
{
|
|
for(XMLElement* rotateElem = node->FirstChildElement("rotate");
|
|
rotateElem!= NULL; rotateElem= node->NextSiblingElement("rotate"))
|
|
{
|
|
if (rotateElem->GetText())
|
|
{
|
|
//accumulate orientation
|
|
btVector4 rotate = getVector4FromXmlText(rotateElem->GetText());
|
|
btQuaternion orn(btVector3(rotate),btRadians(rotate[3]));//COLLADA DAE rotate is in degrees, convert to radians
|
|
btMatrix4x4 t;
|
|
t.setPureRotation(orn);
|
|
nodeTrans = nodeTrans*t;
|
|
}
|
|
}
|
|
}
|
|
|
|
nodeTrans = parentTransMat*nodeTrans;
|
|
|
|
for (XMLElement* instanceGeom = node->FirstChildElement("instance_geometry");
|
|
instanceGeom!=0;
|
|
instanceGeom=instanceGeom->NextSiblingElement("instance_geometry"))
|
|
{
|
|
const char* geomUrl = instanceGeom->Attribute("url");
|
|
//printf("node referring to geom %s\n", geomUrl);
|
|
geomUrl++;
|
|
int* shapeIndexPtr = name2Shape[geomUrl];
|
|
if (shapeIndexPtr)
|
|
{
|
|
// int index = *shapeIndexPtr;
|
|
//printf("found geom with index %d\n", *shapeIndexPtr);
|
|
ColladaGraphicsInstance& instance = visualShapeInstances.expand();
|
|
instance.m_shapeIndex = *shapeIndexPtr;
|
|
instance.m_worldTransform = nodeTrans;
|
|
} else
|
|
{
|
|
b3Warning("geom not found\n");
|
|
}
|
|
}
|
|
|
|
for(XMLElement* childNode = node->FirstChildElement("node");
|
|
childNode!= NULL; childNode = childNode->NextSiblingElement("node"))
|
|
{
|
|
readNodeHierarchy(childNode,name2Shape,visualShapeInstances, nodeTrans);
|
|
}
|
|
}
|
|
void readVisualSceneInstanceGeometries(XMLDocument& doc, btHashMap<btHashString,int>& name2Shape, btAlignedObjectArray<ColladaGraphicsInstance>& visualShapeInstances)
|
|
{
|
|
btHashMap<btHashString,XMLElement* > allVisualScenes;
|
|
|
|
XMLElement* libVisualScenes = doc.RootElement()->FirstChildElement("library_visual_scenes");
|
|
if (libVisualScenes==0)
|
|
return;
|
|
|
|
{
|
|
for(XMLElement* scene = libVisualScenes->FirstChildElement("visual_scene");
|
|
scene != NULL; scene = scene->NextSiblingElement("visual_scene"))
|
|
{
|
|
const char* sceneName = scene->Attribute("id");
|
|
allVisualScenes.insert(sceneName,scene);
|
|
}
|
|
}
|
|
|
|
XMLElement* scene = 0;
|
|
{
|
|
XMLElement* scenes = doc.RootElement()->FirstChildElement("scene");
|
|
if (scenes)
|
|
{
|
|
XMLElement* instanceSceneReference = scenes->FirstChildElement("instance_visual_scene");
|
|
if (instanceSceneReference)
|
|
{
|
|
const char* instanceSceneUrl = instanceSceneReference->Attribute("url");
|
|
XMLElement** sceneInstancePtr = allVisualScenes[instanceSceneUrl+1];//skip #
|
|
if (sceneInstancePtr)
|
|
{
|
|
scene = *sceneInstancePtr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (scene)
|
|
{
|
|
for(XMLElement* node = scene->FirstChildElement("node");
|
|
node != NULL; node = node->NextSiblingElement("node"))
|
|
{
|
|
btMatrix4x4 identity;
|
|
identity.setIdentity();
|
|
btVector3 identScaling(1,1,1);
|
|
readNodeHierarchy(node,name2Shape,visualShapeInstances, identity);
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void getUnitMeterScalingAndUpAxisTransform(XMLDocument& doc, btTransform& tr, float& unitMeterScaling, int clientUpAxis)
|
|
{
|
|
///todo(erwincoumans) those up-axis transformations have been quickly coded without rigorous testing
|
|
|
|
XMLElement* unitMeter = doc.RootElement()->FirstChildElement("asset")->FirstChildElement("unit");
|
|
if (unitMeter)
|
|
{
|
|
const char* meterText = unitMeter->Attribute("meter");
|
|
//printf("meterText=%s\n", meterText);
|
|
unitMeterScaling = atof(meterText);
|
|
}
|
|
|
|
XMLElement* upAxisElem = doc.RootElement()->FirstChildElement("asset")->FirstChildElement("up_axis");
|
|
if (upAxisElem)
|
|
{
|
|
switch (clientUpAxis)
|
|
{
|
|
|
|
case 1:
|
|
{
|
|
std::string upAxisTxt = upAxisElem->GetText();
|
|
if (upAxisTxt == "X_UP")
|
|
{
|
|
btQuaternion x2y(btVector3(0,0,1),SIMD_HALF_PI);
|
|
tr.setRotation(x2y);
|
|
}
|
|
if (upAxisTxt == "Y_UP")
|
|
{
|
|
//assume Y_UP for now, to be compatible with assimp?
|
|
//client and COLLADA are both Z_UP so no transform needed (identity)
|
|
}
|
|
if (upAxisTxt == "Z_UP")
|
|
{
|
|
btQuaternion z2y(btVector3(1,0,0),-SIMD_HALF_PI);
|
|
tr.setRotation(z2y);
|
|
}
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
std::string upAxisTxt = upAxisElem->GetText();
|
|
if (upAxisTxt == "X_UP")
|
|
{
|
|
btQuaternion x2z(btVector3(0,1,0),-SIMD_HALF_PI);
|
|
tr.setRotation(x2z);
|
|
}
|
|
if (upAxisTxt == "Y_UP")
|
|
{
|
|
btQuaternion y2z(btVector3(1,0,0),SIMD_HALF_PI);
|
|
tr.setRotation(y2z);
|
|
}
|
|
if (upAxisTxt == "Z_UP")
|
|
{
|
|
//client and COLLADA are both Z_UP so no transform needed (identity)
|
|
}
|
|
break;
|
|
}
|
|
case 0:
|
|
default:
|
|
{
|
|
//we don't support X or other up axis
|
|
btAssert(0);
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
void LoadMeshFromCollada(const char* relativeFileName, btAlignedObjectArray<GLInstanceGraphicsShape>& visualShapes, btAlignedObjectArray<ColladaGraphicsInstance>& visualShapeInstances, btTransform& upAxisTransform, float& unitMeterScaling,int clientUpAxis)
|
|
{
|
|
|
|
// GLInstanceGraphicsShape* instance = 0;
|
|
|
|
//usually COLLADA files don't have that many visual geometries/shapes
|
|
visualShapes.reserve(MAX_VISUAL_SHAPES);
|
|
|
|
float extraScaling = 1;//0.01;
|
|
btHashMap<btHashString, int> name2ShapeIndex;
|
|
b3FileUtils f;
|
|
char filename[1024];
|
|
if (!f.findFile(relativeFileName,filename,1024))
|
|
{
|
|
b3Warning("File not found: %s\n", filename);
|
|
return;
|
|
}
|
|
|
|
XMLDocument doc;
|
|
if (!doc.LoadFile(filename))
|
|
return;
|
|
|
|
//We need units to be in meter, so apply a scaling using the asset/units meter
|
|
unitMeterScaling=1;
|
|
upAxisTransform.setIdentity();
|
|
|
|
//Also we can optionally compensate all transforms using the asset/up_axis as well as unit meter scaling
|
|
getUnitMeterScalingAndUpAxisTransform(doc, upAxisTransform, unitMeterScaling,clientUpAxis);
|
|
|
|
btMatrix4x4 ident;
|
|
ident.setIdentity();
|
|
|
|
readLibraryGeometries(doc, visualShapes, name2ShapeIndex, extraScaling);
|
|
|
|
readVisualSceneInstanceGeometries(doc, name2ShapeIndex, visualShapeInstances);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef COMPARE_WITH_ASSIMP
|
|
|
|
#include <assimp/Importer.hpp>
|
|
#include <assimp/mesh.h>
|
|
#include <assimp/postprocess.h>
|
|
#include <assimp/scene.h>
|
|
|
|
|
|
# include "assimp/ColladaLoader.h"
|
|
//# include "STLLoader.h"
|
|
# include "assimp/SortByPTypeProcess.h"
|
|
# include "assimp/LimitBoneWeightsProcess.h"
|
|
# include "assimp/TriangulateProcess.h"
|
|
# include "assimp/JoinVerticesProcess.h"
|
|
# include "assimp/RemoveVCProcess.h"
|
|
|
|
|
|
namespace Assimp {
|
|
// ------------------------------------------------------------------------------------------------
|
|
void GetImporterInstanceList(std::vector< BaseImporter* >& out)
|
|
{
|
|
out.push_back( new ColladaLoader());
|
|
}
|
|
// ------------------------------------------------------------------------------------------------
|
|
void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
|
|
{
|
|
out.push_back( new SortByPTypeProcess());
|
|
out.push_back( new LimitBoneWeightsProcess());
|
|
out.push_back( new TriangulateProcess());
|
|
out.push_back( new JoinVerticesProcess());
|
|
//out.push_back( new RemoveVCProcess());
|
|
}
|
|
|
|
}
|
|
|
|
static void addMeshParts(const aiScene* scene, const aiNode* node, GLInstanceGraphicsShape* outverts, const aiMatrix4x4& parentTr)
|
|
{
|
|
aiMatrix4x4 const& nodeTrans(node->mTransformation);
|
|
|
|
aiMatrix4x4 trans;
|
|
trans = parentTr * nodeTrans;
|
|
|
|
for (size_t i = 0; i < node->mNumMeshes; ++i)
|
|
{
|
|
aiMesh const* mesh = scene->mMeshes[node->mMeshes[i]];
|
|
size_t num_vertices = mesh->mNumVertices;
|
|
if (mesh->mPrimitiveTypes==aiPrimitiveType_TRIANGLE)
|
|
{
|
|
int curVertexBase = outverts->m_vertices->size();
|
|
|
|
for (int v=0;v<mesh->mNumVertices;v++)
|
|
{
|
|
GLInstanceVertex vtx;
|
|
aiVector3D vWorld = trans*mesh->mVertices[v];
|
|
vtx.xyzw[0] = vWorld.x;
|
|
vtx.xyzw[1] = vWorld.y;
|
|
vtx.xyzw[2] = vWorld.z;
|
|
vtx.xyzw[3] = 1;
|
|
if (mesh->HasNormals())
|
|
{
|
|
vtx.normal[0] = mesh->mNormals[v].x;
|
|
vtx.normal[1] = mesh->mNormals[v].y;
|
|
vtx.normal[2] = mesh->mNormals[v].z;
|
|
} else
|
|
{
|
|
vtx.normal[0] = 0;
|
|
vtx.normal[1] = 0;
|
|
vtx.normal[2] = 1;
|
|
}
|
|
if (mesh->HasTextureCoords(0))
|
|
{
|
|
vtx.uv[0] = mesh->mTextureCoords[0][v].x;
|
|
vtx.uv[1] = mesh->mTextureCoords[0][v].y;
|
|
} else
|
|
{
|
|
vtx.uv[0]=0.5f;
|
|
vtx.uv[1]=0.5f;
|
|
}
|
|
outverts->m_vertices->push_back(vtx);
|
|
}
|
|
for (int f=0;f<mesh->mNumFaces;f++)
|
|
{
|
|
b3Assert(mesh->mFaces[f].mNumIndices == 3);
|
|
int i0 = mesh->mFaces[f].mIndices[0];
|
|
int i1 = mesh->mFaces[f].mIndices[1];
|
|
int i2 = mesh->mFaces[f].mIndices[2];
|
|
outverts->m_indices->push_back(i0+curVertexBase);
|
|
outverts->m_indices->push_back(i1+curVertexBase);
|
|
outverts->m_indices->push_back(i2+curVertexBase);
|
|
}
|
|
}
|
|
}
|
|
for (size_t i=0 ; i<node->mNumChildren ; ++i) {
|
|
addMeshParts(scene,node->mChildren[i], outverts, trans);
|
|
}
|
|
}
|
|
|
|
|
|
void LoadMeshFromColladaAssimp(const char* relativeFileName, btAlignedObjectArray<GLInstanceGraphicsShape>& visualShapes, btAlignedObjectArray<ColladaGraphicsInstance>& visualShapeInstances,btTransform& upAxisTrans, float& unitMeterScaling)
|
|
{
|
|
upAxisTrans.setIdentity();
|
|
unitMeterScaling=1;
|
|
|
|
GLInstanceGraphicsShape* shape = 0;
|
|
|
|
|
|
FILE* file = fopen(relativeFileName,"rb");
|
|
if (file)
|
|
{
|
|
int size=0;
|
|
if (fseek(file, 0, SEEK_END) || (size = ftell(file)) == EOF || fseek(file, 0, SEEK_SET))
|
|
{
|
|
b3Warning("Error: Cannot access file to determine size of %s\n", relativeFileName);
|
|
} else
|
|
{
|
|
if (size)
|
|
{
|
|
//printf("Open DAE file of %d bytes\n",size);
|
|
|
|
Assimp::Importer importer;
|
|
//importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, aiComponent_NORMALS | aiComponent_COLORS);
|
|
importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT);
|
|
// importer.SetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 1);
|
|
aiScene const* scene = importer.ReadFile(relativeFileName,
|
|
aiProcess_JoinIdenticalVertices |
|
|
//aiProcess_RemoveComponent |
|
|
aiProcess_SortByPType |
|
|
aiProcess_Triangulate);
|
|
if (scene)
|
|
{
|
|
shape = &visualShapes.expand();
|
|
shape->m_scaling[0] = 1;
|
|
shape->m_scaling[1] = 1;
|
|
shape->m_scaling[2] = 1;
|
|
shape->m_scaling[3] = 1;
|
|
int index = 0;
|
|
shape->m_indices = new b3AlignedObjectArray<int>();
|
|
shape->m_vertices = new b3AlignedObjectArray<GLInstanceVertex>();
|
|
|
|
aiMatrix4x4 ident;
|
|
addMeshParts(scene, scene->mRootNode, shape, ident);
|
|
shape->m_numIndices = shape->m_indices->size();
|
|
shape->m_numvertices = shape->m_vertices->size();
|
|
ColladaGraphicsInstance& instance = visualShapeInstances.expand();
|
|
instance.m_shapeIndex = visualShapes.size()-1;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif //COMPARE_WITH_ASSIMP
|