提交 d392865a 编写于 作者: K Kai Ninomiya

Merge branch 'master' into mesh_compression_open3dgc

上级 44e84083
......@@ -35,7 +35,7 @@ using namespace std;
namespace GLTF
{
void GLTFAccessor::_generateID() {
this->_ID = GLTFUtils::generateIDForType("accessor");
this->_ID = GLTFUtils::generateIDForType(kAccessor.c_str());
}
GLTFAccessor::GLTFAccessor(shared_ptr<GLTFProfile> profile, const std::string& componentType, const std::string& type):
......
......@@ -86,58 +86,8 @@ namespace GLTF
}
bool writeCompressedMesh(shared_ptr <GLTFMesh> mesh, GLTFAsset* asset) {
GLTFOutputStream* compressionOutputStream = asset->createOutputStreamIfNeeded(kCompressionOutputStream).get();
shared_ptr <JSONObject> floatAttributeIndexMapping(new JSONObject());
unsigned compressedBufferStart = (unsigned int)compressionOutputStream->length();
encodeOpen3DGCMesh(mesh, floatAttributeIndexMapping, asset);
typedef std::map<std::string , shared_ptr<GLTF::GLTFBuffer> > IDToBufferDef;
IDToBufferDef IDToBuffer;
shared_ptr <MeshAttributeVector> allMeshAttributes = mesh->meshAttributes();
int vertexCount;
unsigned int indicesCount, allIndicesCount = 0;
GLTF::JSONValueVector primitives = mesh->getPrimitives()->values();
unsigned int primitivesCount = (unsigned int)primitives.size();
for (unsigned int i = 0 ; i < primitivesCount ; i++) {
shared_ptr<GLTF::GLTFPrimitive> primitive = static_pointer_cast<GLTFPrimitive>(primitives[i]);
shared_ptr <GLTF::GLTFAccessor> uniqueIndices = primitive->getIndices();
/*
Convert the indices to unsigned short and write the blob
*/
indicesCount = (unsigned int)uniqueIndices->getCount();
if (indicesCount > 0) {
allIndicesCount += indicesCount;
//FIXME: this is assuming triangles
unsigned int trianglesCount = asset->convertionResults()->getUnsignedInt32("trianglesCount");
trianglesCount += indicesCount / 3;
asset->convertionResults()->setUnsignedInt32("trianglesCount", trianglesCount);
size_t indicesLength = sizeof(unsigned short) * indicesCount;
uniqueIndices->setByteOffset(compressedBufferStart);
compressedBufferStart += (unsigned int)indicesLength; //we simulate how will be the uncompressed data here, so this is the length in short *on purpose*
}
}
shared_ptr<GLTFAccessor> positionAttribute = mesh->getMeshAttribute(GLTF::POSITION, 0);
vertexCount = (unsigned int)positionAttribute->getCount();
unsigned int totalVerticesCount = asset->convertionResults()->getUnsignedInt32("verticesCount");
totalVerticesCount += vertexCount;
asset->convertionResults()->setUnsignedInt32("verticesCount", totalVerticesCount);
for (unsigned int j = 0 ; j < allMeshAttributes->size() ; j++) {
shared_ptr <GLTFAccessor> meshAttribute = (*allMeshAttributes)[j];
shared_ptr <GLTFBufferView> bufferView = meshAttribute->getBufferView();
shared_ptr <GLTFBuffer> buffer = bufferView->getBuffer();
if (!bufferView.get()) { return false; }
if (!IDToBuffer[bufferView->getBuffer()->getID()].get()) {
meshAttribute->exposeMinMax();
meshAttribute->setByteOffset(compressedBufferStart);
compressedBufferStart += (unsigned int)buffer->getByteLength();
IDToBuffer[bufferView->getBuffer()->getID()] = buffer;
}
}
// Encode the mesh into the output stream
encodeOpen3DGCMesh(mesh, asset);
return true;
}
......@@ -432,7 +382,10 @@ namespace GLTF
this->_root = shared_ptr <GLTF::JSONObject> (new GLTF::JSONObject());
this->_root->createObjectIfNeeded(kNodes);
this->_writer->initWithPath(this->getOutputFilePath().c_str());
if (!this->_writer->initWithPath(this->getOutputFilePath().c_str())) {
printf("fatal error: could not open file for writing\n");
exit(EXIT_FAILURE);
}
}
//FIXME:legacy
......@@ -852,7 +805,6 @@ namespace GLTF
}
shared_ptr<GLTFOutputStream> rawOutputStream = this->createOutputStreamIfNeeded(this->getSharedBufferId());
shared_ptr<GLTFOutputStream> compressionOutputStream = this->createOutputStreamIfNeeded(kCompressionOutputStream);
shared_ptr <GLTF::JSONObject> animations = this->_root->createObjectIfNeeded("animations");
std::vector <std::string> animationsUIDs = animations->getAllKeys();
......@@ -893,6 +845,7 @@ namespace GLTF
shared_ptr <GLTF::JSONObject> meshes = this->_root->createObjectIfNeeded(kMeshes);
shared_ptr <GLTF::JSONObject> accessors = this->_root->createObjectIfNeeded(kAccessors);
shared_ptr <GLTF::JSONObject> bufferViews = this->_root->createObjectIfNeeded(kBufferViews);
std::vector <std::string> meshesUIDs = meshes->getAllKeys();
......@@ -975,37 +928,45 @@ namespace GLTF
this->addValueEvaluator(std::make_shared<GLTFCleanupEvaluator>());
this->launchModifiers();
size_t verticesLength;
size_t indicesLength;
size_t animationLength = rawOutputStream->length();
size_t compressionLength = 0;
size_t previousLength = animationLength;
std::vector<bool> meshCompressibleMap;
//save all meshes as compressed
for (size_t i = 0 ; i < meshesUIDs.size() ; i++) {
shared_ptr<GLTFMesh> mesh = static_pointer_cast<GLTFMesh>(meshes->getObject(meshesUIDs[i]));
bool compressMesh = (CONFIG_STRING(this, "compressionType") == "Open3DGC") && canEncodeOpen3DGCMesh(mesh,this->_profile);
if (compressMesh)
bool compressMesh = (CONFIG_STRING(this, "compressionType") == "Open3DGC") && canEncodeOpen3DGCMesh(mesh, this->_profile);
meshCompressibleMap.push_back(compressMesh);
if (compressMesh) {
writeCompressedMesh(mesh, this);
}
}
size_t compressionLength = compressionOutputStream->length();
shared_ptr <GLTFBuffer> compressionBuffer(new GLTFBuffer(compressionOutputStream->id(), compressionLength));
compressionLength = rawOutputStream->length() - previousLength;
previousLength = rawOutputStream->length();
//save all indices
for (size_t i = 0 ; i < meshesUIDs.size() ; i++) {
shared_ptr<GLTFMesh> mesh = static_pointer_cast<GLTFMesh>(meshes->getObject(meshesUIDs[i]));
bool compressMesh = (CONFIG_STRING(this, "compressionType") == "Open3DGC") && canEncodeOpen3DGCMesh(mesh,this->_profile);
if (!compressMesh)
if (!meshCompressibleMap[i]) {
writeMeshIndices(mesh, previousLength, this);
}
}
indicesLength = rawOutputStream->length() - previousLength;
previousLength = rawOutputStream->length();
//add padding for https://github.com/KhronosGroup/glTF/issues/167
//it is known that the other buffers are all FLOAT, so as a minimal fix we just have to align indices (that are short) on FLOAT when writting them.
size_t rem = indicesLength % 4;
if (rem) {
char pad[3];
char pad[3] = {0};
size_t paddingForAlignement = 4 - rem;
rawOutputStream->write(pad, paddingForAlignement);
indicesLength += paddingForAlignement;
......@@ -1015,32 +976,28 @@ namespace GLTF
//save all mesh attributes
for (size_t i = 0 ; i < meshesUIDs.size() ; i++) {
shared_ptr<GLTFMesh> mesh = static_pointer_cast<GLTFMesh>(meshes->getObject(meshesUIDs[i]));
bool compressMesh = (CONFIG_STRING(this, "compressionType") == "Open3DGC") && canEncodeOpen3DGCMesh(mesh,this->_profile);
if (!compressMesh)
if (!meshCompressibleMap[i]) {
writeMeshAttributes(mesh, previousLength, this);
}
}
verticesLength = rawOutputStream->length() - previousLength;
previousLength = rawOutputStream->length();
shared_ptr <GLTFBuffer> sharedBuffer(new GLTFBuffer(this->getSharedBufferId(), verticesLength + indicesLength + animationLength));
shared_ptr <GLTFBuffer> sharedBuffer(new GLTFBuffer(this->getSharedBufferId(), verticesLength + indicesLength + animationLength + compressionLength));
//---
shared_ptr <GLTFBufferView> genericBufferView(new GLTFBufferView(sharedBuffer, 0, animationLength));
shared_ptr <GLTFBufferView> indicesBufferView(new GLTFBufferView(sharedBuffer, animationLength, indicesLength));
shared_ptr <GLTFBufferView> verticesBufferView(new GLTFBufferView(sharedBuffer, indicesLength + animationLength, verticesLength));
shared_ptr <GLTFBufferView> compressionBufferView(new GLTFBufferView(compressionBuffer, 0, compressionLength));
shared_ptr <GLTFBufferView> verticesBufferView(new GLTFBufferView(sharedBuffer, animationLength + indicesLength, verticesLength));
// ----
for (size_t i = 0 ; i < meshesUIDs.size() ; i++) {
shared_ptr<GLTFMesh> mesh = static_pointer_cast<GLTFMesh>(meshes->getObject(meshesUIDs[i]));
bool compressMesh = meshCompressibleMap[i];
GLTF::JSONValueVector primitives = mesh->getPrimitives()->values();
bool isCompressed = false;
if (mesh->contains(kExtensions)) {
isCompressed = mesh->getExtensions()->contains("Open3DGC-compression");
}
//serialize attributes
vector <GLTF::Semantic> allSemantics = mesh->allSemantics();
for (size_t k = 0 ; k < allSemantics.size() ; k++) {
......@@ -1050,29 +1007,30 @@ namespace GLTF
for (size_t j = 0 ; j < attributesCount ; j++) {
shared_ptr <GLTF::GLTFAccessor> meshAttribute = mesh->getMeshAttribute(semantic, j);
meshAttribute->setBufferView(isCompressed ? compressionBufferView : verticesBufferView);
if (compressMesh) {
auto bv = meshAttribute->getBufferView();
bufferViews->setValue(bv->getID(), bv);
} else {
meshAttribute->setBufferView(verticesBufferView);
}
accessors->setValue(meshAttribute->getID(), meshAttribute);
}
}
//serialize indices
unsigned int primitivesCount = (unsigned int)primitives.size();
for (size_t k = 0 ; k < primitivesCount ; k++) {
shared_ptr<GLTF::GLTFPrimitive> primitive = static_pointer_cast<GLTFPrimitive>(primitives[k]);
shared_ptr <GLTF::GLTFAccessor> uniqueIndices = primitive->getIndices();
GLTFBufferView *bufferView = isCompressed ? (GLTFBufferView*)compressionBufferView.get() : (GLTFBufferView*)indicesBufferView.get();
uniqueIndices->setString(kBufferView, bufferView->getID());
accessors->setValue(uniqueIndices->getID(), uniqueIndices);
}
//set the compression buffer view
if (mesh->contains(kExtensions)) {
shared_ptr<JSONObject> compressionData = static_pointer_cast<JSONObject>(mesh->valueForKeyPath("extensions.Open3DGC-compression.compressedData"));
if (compressionData) {
compressionData->setString(kBufferView, compressionBufferView->getID());
if (compressMesh) {
auto bv = uniqueIndices->getBufferView();
bufferViews->setValue(bv->getID(), bv);
} else {
GLTFBufferView *bufferView = indicesBufferView.get();
uniqueIndices->setString(kBufferView, bufferView->getID());
}
accessors->setValue(uniqueIndices->getID(), uniqueIndices);
}
}
......@@ -1118,10 +1076,8 @@ namespace GLTF
for (size_t i = 0 ; i <parameterKeys.size() ; i++) {
std::string parameterUID = parameters->getString(parameterKeys[i]);
shared_ptr <JSONObject> parameterObject = accessors->getObject(parameterUID);
// TODO: fix animation compression?
shared_ptr <JSONObject> compressedData = static_pointer_cast<JSONObject>(parameterObject->valueForKeyPath("extensions.Open3DGC-compression.compressedData"));
if (compressedData) {
compressedData->setString(kBufferView, compressionBufferView->getID());
}
parameterObject->setString(kBufferView, genericBufferView->getID());
}
}
......@@ -1142,32 +1098,18 @@ namespace GLTF
buffersObject->setValue(this->getSharedBufferId(), sharedBuffer);
}
if (compressionBuffer->getByteLength() > 0) {
std::string compressedBufferID = compressionOutputStream->id();
buffersObject->setValue(compressedBufferID, compressionBuffer);
if (CONFIG_BOOL(this, "embedResources") == false) {
COLLADABU::URI uri(compressionOutputStream->outputPath());
compressionBuffer->setString(kURI, COLLADABU::URI::uriEncode(uri.getPathFile()));
} else {
compressionBuffer->setString(kURI, COLLADABU::URI::uriEncode(compressionOutputStream->outputPath()));
}
if (converterConfig()->config()->getString("compressionMode") == "ascii")
compressionBuffer->setString(kType, "text");
else
compressionBuffer->setString(kType, "arraybuffer");
}
//FIXME: below is an acceptable short-cut since in this converter we will always create one buffer view for vertices and one for indices.
//Fabrice: Other pipeline tools should be built on top of the format & manipulate the buffers and end up with a buffer / bufferViews layout that matches the need of a given application for performance. For instance we might want to concatenate a set of geometry together that come from different file and call that a "level" for a game.
shared_ptr <JSONObject> bufferViews = this->_root->createObjectIfNeeded(kBufferViews);
bufferViews->setValue(indicesBufferView->getID(), indicesBufferView);
bufferViews->setValue(verticesBufferView->getID(), verticesBufferView);
if ((animationLength > 0) || (compressionLength > 0)) {
bufferViews->setValue(genericBufferView->getID(), genericBufferView);
if (indicesLength > 0) {
bufferViews->setValue(indicesBufferView->getID(), indicesBufferView);
}
if (verticesLength > 0) {
bufferViews->setValue(verticesBufferView->getID(), verticesBufferView);
}
if (compressionLength > 0) {
bufferViews->setValue(compressionBufferView->getID(), compressionBufferView);
// TODO: fix animation compression?
if (animationLength > 0) {
bufferViews->setValue(genericBufferView->getID(), genericBufferView);
}
indicesBufferView->setUnsignedInt32(kTarget, this->_profile->getGLenumForString("ELEMENT_ARRAY_BUFFER"));
......@@ -1176,16 +1118,13 @@ namespace GLTF
this->_performValuesEvaluation();
rawOutputStream->close();
if (compressionLength == 0) {
this->closeOutputStream(kCompressionOutputStream, true);
}
if (sharedBuffer->getByteLength() == 0)
rawOutputStream->remove();
this->convertionResults()->setUnsignedInt32(kGeometry, (unsigned int)this->getGeometryByteLength());
this->convertionResults()->setUnsignedInt32(kAnimation, (unsigned int)this->getAnimationByteLength());
this->convertionResults()->setUnsignedInt32(kScene, (int) (verticesLength + indicesLength + animationLength + compressionLength) );
this->convertionResults()->setUnsignedInt32(kScene, (unsigned int) (verticesLength + indicesLength + animationLength + compressionLength));
this->log("[geometry] %d bytes\n", (int)this->getGeometryByteLength());
this->log("[animations] %d bytes\n", (int)this->getAnimationByteLength());
......
......@@ -19,14 +19,10 @@ namespace GLTF
virtual ~GLTFAssetValueEvaluator() {};
};
#define CONFIG_BOOL(asset,X) (asset->converterConfig()->config()->getBool(X))
#define CONFIG_STRING(asset, X) (asset->converterConfig()->config()->getString(X))
#define CONFIG_DOUBLE(asset, X) (asset->converterConfig()->config()->getDouble(X))
#define CONFIG_INT32(asset, X) (asset->converterConfig()->config()->getInt32(X))
#define CONFIG_UINT32(asset, X) (asset->converterConfig()->config()->getUInt32(X))
const std::string kRawOutputStream = "rawOutputStream";
const std::string kCompressionOutputStream = "compression";
#define CONFIG_BOOL(asset, X) ((asset)->converterConfig()->config()->getBool(X))
#define CONFIG_STRING(asset, X) ((asset)->converterConfig()->config()->getString(X))
#define CONFIG_DOUBLE(asset, X) ((asset)->converterConfig()->config()->getDouble(X))
#define CONFIG_INT32(asset, X) ((asset)->converterConfig()->config()->getInt32(X))
class GLTFAnimationFlattener;
......@@ -200,4 +196,4 @@ namespace GLTF
std::string uniqueIdWithType(std::string type, const COLLADAFW::UniqueId& uniqueId);
}
#endif
\ No newline at end of file
#endif
......@@ -55,7 +55,7 @@ namespace GLTF
_data((unsigned char*)data),
_ownData(ownData) {
this->setUnsignedInt32(kByteLength, (unsigned int)byteLength);
this->_ID = GLTFUtils::generateIDForType("buffer");
this->_ID = GLTFUtils::generateIDForType(kBuffer.c_str());
}
GLTFBuffer::GLTFBuffer(std::string ID,void *data, size_t byteLength, bool ownData): JSONObject(),
......@@ -106,7 +106,8 @@ namespace GLTF
this->setByteOffset(byteOffset);
}
GLTFBufferView::GLTFBufferView(std::string ID, shared_ptr <GLTF::GLTFBuffer> buffer, size_t byteOffset, size_t byteLength) : JSONObject() {
GLTFBufferView::GLTFBufferView(std::string ID, shared_ptr <GLTF::GLTFBuffer> buffer, size_t byteOffset, size_t byteLength)
: JSONObject(), _ID(ID) {
this->_setBuffer(buffer);
this->setByteLength(byteLength);
this->setByteOffset(byteOffset);
......
......@@ -79,6 +79,7 @@ namespace GLTF
quantization->setUnsignedInt32("TEXCOORD", 10);
quantization->setUnsignedInt32("COLOR", 10);
quantization->setUnsignedInt32("WEIGHT", 8);
quantization->setUnsignedInt32("JOINT", 10);
quantization->setUnsignedInt32("TIME", 10);
shared_ptr<JSONObject> prediction(new JSONObject());
......
......@@ -39,7 +39,7 @@ namespace GLTF
GLTFMesh::GLTFMesh() : JSONObject() , _subMeshes(nullptr) {
this->_subMeshes = nullptr;
this->_remapTableForPositions = nullptr;
this->_ID = GLTFUtils::generateIDForType("mesh");
this->_ID = GLTFUtils::generateIDForType(kMesh.c_str());
}
GLTFMesh::~GLTFMesh() {
......
......@@ -66,7 +66,9 @@ const std::string kProfile = "profile";
const std::string kVersion = "version";
const std::string kAsset = "asset";
const std::string kNodes = "nodes";
const std::string kMesh = "mesh";
const std::string kMeshes = "meshes";
const std::string kAccessor = "accessor";
const std::string kAccessors = "accessors";
const std::string kTarget = "target";
const std::string kGeometry = "geometry";
......@@ -88,6 +90,11 @@ const std::string kSemantic = "semantic";
const std::string kJointName = "jointName";
const std::string kJointNames = "jointNames";
const std::string kDoubleSided = "doubleSided";
const std::string kExtensionOpen3DGC = "mesh_compression_open3dgc";
const std::string kDecompressedView = "decompressedView";
const std::string kDecompressedViews = "decompressedViews";
const std::string kDecompressedByteLength = "decompressedByteLength";
const std::string kCompressionMode = "mode";
const std::string MODELVIEW = "MODELVIEW";
const std::string MODELVIEWINVERSETRANSPOSE = "MODELVIEWINVERSETRANSPOSE";
......
......@@ -188,7 +188,7 @@ namespace GLTF
inputLength = vertexData.getLength(indexOfSet);
} else {
// for unpatched version of OpenCOLLADA we need this work-around.
id = GLTF::GLTFUtils::generateIDForType("buffer").c_str();
id = GLTF::GLTFUtils::generateIDForType(kBufferView.c_str()).c_str();
componentsPerElement = 3; //only normal and positions should reach this code
inputLength = vertexData.getLength(0);
}
......
......@@ -28,9 +28,7 @@ namespace GLTF
{
bool canEncodeOpen3DGCMesh(std::shared_ptr <GLTFMesh> mesh, std::shared_ptr <GLTFProfile> profile);
void encodeOpen3DGCMesh(std::shared_ptr <GLTFMesh> mesh,
std::shared_ptr<JSONObject> floatAttributeIndexMapping,
GLTFAsset* asset);
void encodeOpen3DGCMesh(std::shared_ptr <GLTFMesh> mesh, GLTFAsset* asset);
void encodeDynamicVector(float *buffer, const std::string &path, size_t componentsCount, size_t count, GLTFAsset& asset);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册