Export glTF 2
parent
d7cbbaf23e
commit
bb55246c18
|
@ -177,7 +177,7 @@ namespace glTF2
|
|||
struct GLB_Header
|
||||
{
|
||||
uint8_t magic[4]; //!< Magic number: "glTF"
|
||||
uint32_t version; //!< Version number (always 1 as of the last update)
|
||||
uint32_t version; //!< Version number
|
||||
uint32_t length; //!< Total length of the Binary glTF, including header, scene, and body, in bytes
|
||||
uint32_t sceneLength; //!< Length, in bytes, of the glTF scene
|
||||
uint32_t sceneFormat; //!< Specifies the format of the glTF scene (see the SceneFormat enum)
|
||||
|
@ -381,6 +381,7 @@ namespace glTF2
|
|||
//! Base classe for all glTF top-level objects
|
||||
struct Object
|
||||
{
|
||||
int index; //!< The index of this object within its property container
|
||||
std::string id; //!< The globally unique ID used to reference this object
|
||||
std::string name; //!< The user-defined name of this object
|
||||
|
||||
|
@ -952,10 +953,10 @@ namespace glTF2
|
|||
};
|
||||
|
||||
struct AnimChannel {
|
||||
std::string sampler; //!< The ID of one sampler present in the containing animation's samplers property.
|
||||
int sampler; //!< The index of a sampler in the containing animation's samplers property.
|
||||
|
||||
struct AnimTarget {
|
||||
Ref<Node> id; //!< The ID of the node to animate.
|
||||
Ref<Node> node; //!< The node to animate.
|
||||
std::string path; //!< The name of property of the node to animate ("translation", "rotation", or "scale").
|
||||
} target;
|
||||
};
|
||||
|
@ -977,6 +978,20 @@ namespace glTF2
|
|||
|
||||
Animation() {}
|
||||
void Read(Value& obj, Asset& r);
|
||||
|
||||
//! Get accessor given an animation parameter name.
|
||||
Ref<Accessor> GetAccessor(std::string name) {
|
||||
if (name == "TIME") {
|
||||
return Parameters.TIME;
|
||||
} else if (name == "rotation") {
|
||||
return Parameters.rotation;
|
||||
} else if (name == "scale") {
|
||||
return Parameters.scale;
|
||||
} else if (name == "translation") {
|
||||
return Parameters.translation;
|
||||
}
|
||||
return Ref<Accessor>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -1058,7 +1073,7 @@ namespace glTF2
|
|||
std::string version; //!< Specifies the target rendering API (default: "1.0.3")
|
||||
} profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {})
|
||||
|
||||
int version; //!< The glTF format version (should be 1)
|
||||
int version; //!< The glTF format version
|
||||
|
||||
void Read(Document& doc);
|
||||
|
||||
|
|
|
@ -242,6 +242,7 @@ Ref<T> LazyDict<T>::Create(const char* id)
|
|||
}
|
||||
T* inst = new T();
|
||||
inst->id = id;
|
||||
inst->index = mObjs.size();
|
||||
return Add(inst);
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace glTF2 {
|
|||
lst.SetArray();
|
||||
lst.Reserve(unsigned(v.size()), al);
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
lst.PushBack(StringRef(v[i]->id), al);
|
||||
lst.PushBack(v[i]->index, al);
|
||||
}
|
||||
obj.AddMember(StringRef(fieldId), lst, al);
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ namespace glTF2 {
|
|||
|
||||
inline void Write(Value& obj, Accessor& a, AssetWriter& w)
|
||||
{
|
||||
obj.AddMember("bufferView", Value(a.bufferView->id, w.mAl).Move(), w.mAl);
|
||||
obj.AddMember("bufferView", a.bufferView->index, w.mAl);
|
||||
obj.AddMember("byteOffset", a.byteOffset, w.mAl);
|
||||
obj.AddMember("byteStride", a.byteStride, w.mAl);
|
||||
obj.AddMember("componentType", int(a.componentType), w.mAl);
|
||||
|
@ -113,12 +113,13 @@ namespace glTF2 {
|
|||
Value valChannel;
|
||||
valChannel.SetObject();
|
||||
{
|
||||
valChannel.AddMember("sampler", c.sampler, w.mAl);
|
||||
Animation::AnimSampler& s = a.Samplers[c.sampler];
|
||||
valChannel.AddMember("sampler", s.id, w.mAl);
|
||||
|
||||
Value valTarget;
|
||||
valTarget.SetObject();
|
||||
{
|
||||
valTarget.AddMember("id", StringRef(c.target.id->id), w.mAl);
|
||||
valTarget.AddMember("id", StringRef(c.target.node->id), w.mAl);
|
||||
valTarget.AddMember("path", c.target.path, w.mAl);
|
||||
}
|
||||
valChannel.AddMember("target", valTarget, w.mAl);
|
||||
|
@ -127,61 +128,35 @@ namespace glTF2 {
|
|||
}
|
||||
obj.AddMember("channels", channels, w.mAl);
|
||||
|
||||
/****************** Parameters *******************/
|
||||
Value valParameters;
|
||||
valParameters.SetObject();
|
||||
{
|
||||
if (a.Parameters.TIME) {
|
||||
valParameters.AddMember("TIME", StringRef(a.Parameters.TIME->id), w.mAl);
|
||||
}
|
||||
if (a.Parameters.rotation) {
|
||||
valParameters.AddMember("rotation", StringRef(a.Parameters.rotation->id), w.mAl);
|
||||
}
|
||||
if (a.Parameters.scale) {
|
||||
valParameters.AddMember("scale", StringRef(a.Parameters.scale->id), w.mAl);
|
||||
}
|
||||
if (a.Parameters.translation) {
|
||||
valParameters.AddMember("translation", StringRef(a.Parameters.translation->id), w.mAl);
|
||||
}
|
||||
}
|
||||
obj.AddMember("parameters", valParameters, w.mAl);
|
||||
|
||||
/****************** Samplers *******************/
|
||||
Value valSamplers;
|
||||
valSamplers.SetObject();
|
||||
valSamplers.SetArray();
|
||||
|
||||
for (size_t i = 0; i < unsigned(a.Samplers.size()); ++i) {
|
||||
Animation::AnimSampler& s = a.Samplers[i];
|
||||
Value valSampler;
|
||||
valSampler.SetObject();
|
||||
{
|
||||
valSampler.AddMember("input", s.input, w.mAl);
|
||||
Ref<Accessor> inputAccessor = a.GetAccessor(s.input);
|
||||
Ref<Accessor> outputAccessor = a.GetAccessor(s.output);
|
||||
valSampler.AddMember("input", inputAccessor->index, w.mAl);
|
||||
valSampler.AddMember("interpolation", s.interpolation, w.mAl);
|
||||
valSampler.AddMember("output", s.output, w.mAl);
|
||||
valSampler.AddMember("output", outputAccessor->index, w.mAl);
|
||||
}
|
||||
valSamplers.AddMember(StringRef(s.id), valSampler, w.mAl);
|
||||
valSamplers.PushBack(valSampler, w.mAl);
|
||||
}
|
||||
obj.AddMember("samplers", valSamplers, w.mAl);
|
||||
}
|
||||
|
||||
inline void Write(Value& obj, Buffer& b, AssetWriter& w)
|
||||
{
|
||||
const char* type;
|
||||
switch (b.type) {
|
||||
case Buffer::Type_text:
|
||||
type = "text"; break;
|
||||
default:
|
||||
type = "arraybuffer";
|
||||
}
|
||||
|
||||
obj.AddMember("byteLength", static_cast<uint64_t>(b.byteLength), w.mAl);
|
||||
obj.AddMember("type", StringRef(type), w.mAl);
|
||||
obj.AddMember("uri", Value(b.GetURI(), w.mAl).Move(), w.mAl);
|
||||
}
|
||||
|
||||
inline void Write(Value& obj, BufferView& bv, AssetWriter& w)
|
||||
{
|
||||
obj.AddMember("buffer", Value(bv.buffer->id, w.mAl).Move(), w.mAl);
|
||||
obj.AddMember("buffer", bv.buffer->index, w.mAl);
|
||||
obj.AddMember("byteOffset", static_cast<uint64_t>(bv.byteOffset), w.mAl);
|
||||
obj.AddMember("byteLength", static_cast<uint64_t>(bv.byteLength), w.mAl);
|
||||
obj.AddMember("target", int(bv.target), w.mAl);
|
||||
|
@ -200,7 +175,7 @@ namespace glTF2 {
|
|||
exts.SetObject();
|
||||
ext.SetObject();
|
||||
|
||||
ext.AddMember("bufferView", StringRef(img.bufferView->id), w.mAl);
|
||||
ext.AddMember("bufferView", img.bufferView->index, w.mAl);
|
||||
|
||||
if (!img.mimeType.empty())
|
||||
ext.AddMember("mimeType", StringRef(img.mimeType), w.mAl);
|
||||
|
@ -224,9 +199,12 @@ namespace glTF2 {
|
|||
namespace {
|
||||
inline void WriteColorOrTex(Value& obj, TexProperty& prop, const char* propName, MemoryPoolAllocator<>& al)
|
||||
{
|
||||
if (prop.texture)
|
||||
obj.AddMember(StringRef(propName), Value(prop.texture->id, al).Move(), al);
|
||||
else {
|
||||
if (prop.texture) {
|
||||
Value tex;
|
||||
tex.SetObject();
|
||||
tex.AddMember("index", prop.texture->index, al);
|
||||
obj.AddMember(StringRef(propName), tex, al);
|
||||
} else {
|
||||
Value col;
|
||||
obj.AddMember(StringRef(propName), MakeValue(col, prop.color, al), al);
|
||||
}
|
||||
|
@ -238,17 +216,21 @@ namespace glTF2 {
|
|||
Value v;
|
||||
v.SetObject();
|
||||
{
|
||||
WriteColorOrTex(v, m.ambient, "ambient", w.mAl);
|
||||
WriteColorOrTex(v, m.diffuse, "diffuse", w.mAl);
|
||||
WriteColorOrTex(v, m.specular, "specular", w.mAl);
|
||||
WriteColorOrTex(v, m.emission, "emission", w.mAl);
|
||||
WriteColorOrTex(v, m.ambient, m.ambient.texture ? "ambientTexture" : "ambientFactor", w.mAl);
|
||||
WriteColorOrTex(v, m.diffuse, m.diffuse.texture ? "diffuseTexture" : "diffuseFactor", w.mAl);
|
||||
WriteColorOrTex(v, m.specular, m.specular.texture ? "specularTexture" : "specularFactor", w.mAl);
|
||||
WriteColorOrTex(v, m.emission, m.emission.texture ? "emissionTexture" : "emissionFactor", w.mAl);
|
||||
|
||||
if (m.transparent)
|
||||
v.AddMember("transparency", m.transparency, w.mAl);
|
||||
|
||||
v.AddMember("shininess", m.shininess, w.mAl);
|
||||
v.AddMember("shininessFactor", m.shininess, w.mAl);
|
||||
}
|
||||
obj.AddMember("values", v, w.mAl);
|
||||
v.AddMember("type", "commonPhong", w.mAl);
|
||||
Value ext;
|
||||
ext.SetObject();
|
||||
ext.AddMember("KHR_materials_common", v, w.mAl);
|
||||
obj.AddMember("extensions", ext, w.mAl);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -257,13 +239,13 @@ namespace glTF2 {
|
|||
{
|
||||
if (lst.empty()) return;
|
||||
if (lst.size() == 1 && !forceNumber) {
|
||||
attrs.AddMember(StringRef(semantic), Value(lst[0]->id, w.mAl).Move(), w.mAl);
|
||||
attrs.AddMember(StringRef(semantic), lst[0]->index, w.mAl);
|
||||
}
|
||||
else {
|
||||
for (size_t i = 0; i < lst.size(); ++i) {
|
||||
char buffer[32];
|
||||
ai_snprintf(buffer, 32, "%s_%d", semantic, int(i));
|
||||
attrs.AddMember(Value(buffer, w.mAl).Move(), Value(lst[i]->id, w.mAl).Move(), w.mAl);
|
||||
attrs.AddMember(Value(buffer, w.mAl).Move(), lst[i]->index, w.mAl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -337,10 +319,10 @@ namespace glTF2 {
|
|||
prim.AddMember("mode", Value(int(p.mode)).Move(), w.mAl);
|
||||
|
||||
if (p.material)
|
||||
prim.AddMember("material", p.material->id, w.mAl);
|
||||
prim.AddMember("material", p.material->index, w.mAl);
|
||||
|
||||
if (p.indices)
|
||||
prim.AddMember("indices", Value(p.indices->id, w.mAl).Move(), w.mAl);
|
||||
prim.AddMember("indices", p.indices->index, w.mAl);
|
||||
|
||||
Value attrs;
|
||||
attrs.SetObject();
|
||||
|
@ -390,7 +372,7 @@ namespace glTF2 {
|
|||
AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
|
||||
|
||||
if (n.skin) {
|
||||
obj.AddMember("skin", Value(n.skin->id, w.mAl).Move(), w.mAl);
|
||||
obj.AddMember("skin", n.skin->index, w.mAl);
|
||||
}
|
||||
|
||||
if (!n.jointName.empty()) {
|
||||
|
@ -437,9 +419,9 @@ namespace glTF2 {
|
|||
vJointNames.Reserve(unsigned(b.jointNames.size()), w.mAl);
|
||||
|
||||
for (size_t i = 0; i < unsigned(b.jointNames.size()); ++i) {
|
||||
vJointNames.PushBack(StringRef(b.jointNames[i]->jointName), w.mAl);
|
||||
vJointNames.PushBack(b.jointNames[i]->index, w.mAl);
|
||||
}
|
||||
obj.AddMember("jointNames", vJointNames, w.mAl);
|
||||
obj.AddMember("joints", vJointNames, w.mAl);
|
||||
|
||||
if (b.bindShapeMatrix.isPresent) {
|
||||
Value val;
|
||||
|
@ -447,7 +429,7 @@ namespace glTF2 {
|
|||
}
|
||||
|
||||
if (b.inverseBindMatrices) {
|
||||
obj.AddMember("inverseBindMatrices", Value(b.inverseBindMatrices->id, w.mAl).Move(), w.mAl);
|
||||
obj.AddMember("inverseBindMatrices", b.inverseBindMatrices->index, w.mAl);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -460,10 +442,10 @@ namespace glTF2 {
|
|||
inline void Write(Value& obj, Texture& tex, AssetWriter& w)
|
||||
{
|
||||
if (tex.source) {
|
||||
obj.AddMember("source", Value(tex.source->id, w.mAl).Move(), w.mAl);
|
||||
obj.AddMember("source", tex.source->index, w.mAl);
|
||||
}
|
||||
if (tex.sampler) {
|
||||
obj.AddMember("sampler", Value(tex.sampler->id, w.mAl).Move(), w.mAl);
|
||||
obj.AddMember("sampler", tex.sampler->index, w.mAl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -490,7 +472,7 @@ namespace glTF2 {
|
|||
|
||||
// Add the target scene field
|
||||
if (mAsset.scene) {
|
||||
mDoc.AddMember("scene", StringRef(mAsset.scene->id), mAl);
|
||||
mDoc.AddMember("scene", mAsset.scene->index, mAl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -582,7 +564,7 @@ namespace glTF2 {
|
|||
GLB_Header header;
|
||||
memcpy(header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic));
|
||||
|
||||
header.version = 1;
|
||||
header.version = 2;
|
||||
AI_SWAP4(header.version);
|
||||
|
||||
header.length = uint32_t(sizeof(header) + sceneLength + bodyLength);
|
||||
|
@ -624,7 +606,7 @@ namespace glTF2 {
|
|||
if (false)
|
||||
exts.PushBack(StringRef("KHR_binary_glTF"), mAl);
|
||||
|
||||
if (false)
|
||||
// This is used to export common materials with GLTF 2.
|
||||
exts.PushBack(StringRef("KHR_materials_common"), mAl);
|
||||
}
|
||||
|
||||
|
@ -653,9 +635,9 @@ namespace glTF2 {
|
|||
}
|
||||
|
||||
Value* dict;
|
||||
if (!(dict = FindObject(*container, d.mDictId))) {
|
||||
container->AddMember(StringRef(d.mDictId), Value().SetObject().Move(), mDoc.GetAllocator());
|
||||
dict = FindObject(*container, d.mDictId);
|
||||
if (!(dict = FindArray(*container, d.mDictId))) {
|
||||
container->AddMember(StringRef(d.mDictId), Value().SetArray().Move(), mDoc.GetAllocator());
|
||||
dict = FindArray(*container, d.mDictId);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < d.mObjs.size(); ++i) {
|
||||
|
@ -670,7 +652,7 @@ namespace glTF2 {
|
|||
|
||||
Write(obj, *d.mObjs[i], *this);
|
||||
|
||||
dict->AddMember(StringRef(d.mObjs[i]->id), obj, mAl);
|
||||
dict->PushBack(obj, mAl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -434,7 +434,7 @@ void ExportSkin(Asset& mAsset, const aiMesh* aimesh, Ref<Mesh>& meshRef, Ref<Buf
|
|||
// aib->mName =====> skinRef->jointNames
|
||||
// Find the node with id = mName.
|
||||
Ref<Node> nodeRef = mAsset.nodes.Get(aib->mName.C_Str());
|
||||
nodeRef->jointName = nodeRef->id;
|
||||
nodeRef->jointName = nodeRef->name;
|
||||
|
||||
unsigned int jointNamesIndex;
|
||||
bool addJointToJointNames = true;
|
||||
|
@ -744,16 +744,28 @@ void glTF2Exporter::ExportMeshes()
|
|||
skinRef->bindShapeMatrix.isPresent = true;
|
||||
IdentityMatrix4(skinRef->bindShapeMatrix.value);
|
||||
|
||||
// Find node that contains this mesh and add "skeletons" and "skin" attributes to that node.
|
||||
// Find nodes that contain a mesh with bones and add "skeletons" and "skin" attributes to those nodes.
|
||||
Ref<Node> rootNode = mAsset->nodes.Get(unsigned(0));
|
||||
Ref<Node> meshNode;
|
||||
std::string meshID = mAsset->meshes.Get(unsigned(0))->id;
|
||||
for (unsigned int meshIndex = 0; meshIndex < mAsset->meshes.Size(); ++meshIndex) {
|
||||
Ref<Mesh> mesh = mAsset->meshes.Get(meshIndex);
|
||||
bool hasBones = false;
|
||||
for (unsigned int i = 0; i < mesh->primitives.size(); ++i) {
|
||||
if (!mesh->primitives[i].attributes.weight.empty()) {
|
||||
hasBones = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasBones) {
|
||||
continue;
|
||||
}
|
||||
std::string meshID = mesh->id;
|
||||
FindMeshNode(rootNode, meshNode, meshID);
|
||||
|
||||
Ref<Node> rootJoint = FindSkeletonRootJoint(skinRef);
|
||||
meshNode->skeletons.push_back(rootJoint);
|
||||
meshNode->skin = skinRef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -787,9 +799,11 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode* n)
|
|||
*/
|
||||
unsigned int glTF2Exporter::ExportNode(const aiNode* n, Ref<Node>& parent)
|
||||
{
|
||||
Ref<Node> node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node"));
|
||||
std::string name = mAsset->FindUniqueID(n->mName.C_Str(), "node");
|
||||
Ref<Node> node = mAsset->nodes.Create(name);
|
||||
|
||||
node->parent = parent;
|
||||
node->name = name;
|
||||
|
||||
if (!n->mTransformation.IsIdentity()) {
|
||||
node->matrix.isPresent = true;
|
||||
|
@ -826,7 +840,7 @@ void glTF2Exporter::ExportScene()
|
|||
void glTF2Exporter::ExportMetadata()
|
||||
{
|
||||
AssetMetadata& asset = mAsset->asset;
|
||||
asset.version = 1;
|
||||
asset.version = 2;
|
||||
|
||||
char buffer[256];
|
||||
ai_snprintf(buffer, 256, "Open Asset Import Library (assimp v%d.%d.%d)",
|
||||
|
@ -970,12 +984,12 @@ void glTF2Exporter::ExportAnimations()
|
|||
Animation::AnimChannel tmpAnimChannel;
|
||||
Animation::AnimSampler tmpAnimSampler;
|
||||
|
||||
tmpAnimChannel.sampler = name + "_" + channelType;
|
||||
tmpAnimChannel.sampler = animRef->Samplers.size();
|
||||
tmpAnimChannel.target.path = channelType;
|
||||
tmpAnimSampler.output = channelType;
|
||||
tmpAnimSampler.id = name + "_" + channelType;
|
||||
|
||||
tmpAnimChannel.target.id = mAsset->nodes.Get(nodeChannel->mNodeName.C_Str());
|
||||
tmpAnimChannel.target.node = mAsset->nodes.Get(nodeChannel->mNodeName.C_Str());
|
||||
|
||||
tmpAnimSampler.input = "TIME";
|
||||
tmpAnimSampler.interpolation = "LINEAR";
|
||||
|
|
Loading…
Reference in New Issue