Merge branch 'master' into issue_3678

This commit is contained in:
Kim Kulling
2021-04-03 10:27:07 +02:00
committed by GitHub
29 changed files with 1471 additions and 73 deletions

View File

@@ -444,7 +444,7 @@ void Discreet3DSExporter::WriteMeshes() {
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
writer.PutU2(count);
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
const aiVector3D &v = trafo * mesh.mVertices[i];
const aiVector3D &v = mesh.mVertices[i];
writer.PutF4(v.x);
writer.PutF4(v.y);
writer.PutF4(v.z);
@@ -506,11 +506,16 @@ void Discreet3DSExporter::WriteMeshes() {
// Transformation matrix by which the mesh vertices have been pre-transformed with.
{
ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRMATRIX);
for (unsigned int r = 0; r < 4; ++r) {
// Store rotation 3x3 matrix row wise
for (unsigned int r = 0; r < 3; ++r) {
for (unsigned int c = 0; c < 3; ++c) {
writer.PutF4(trafo[r][c]);
}
}
// Store translation sub vector column wise
for (unsigned int r = 0; r < 3; ++r) {
writer.PutF4(trafo[r][3]);
}
}
}
}

View File

@@ -981,9 +981,9 @@ void Discreet3DSImporter::ParseMeshChunk() {
mMesh.mMat.a3 = stream->GetF4();
mMesh.mMat.b3 = stream->GetF4();
mMesh.mMat.c3 = stream->GetF4();
mMesh.mMat.a4 = stream->GetF4();
mMesh.mMat.b4 = stream->GetF4();
mMesh.mMat.c4 = stream->GetF4();
mMesh.mMat.d1 = stream->GetF4();
mMesh.mMat.d2 = stream->GetF4();
mMesh.mMat.d3 = stream->GetF4();
} break;
case Discreet3DS::CHUNK_MAPLIST: {

View File

@@ -116,7 +116,7 @@ public:
Mask = 0xf,
};
inline const uint8_t GetType() const { return (flags & Mask); }
inline uint8_t GetType() const { return (flags & Mask); }
};
// Represents an AC3D object

View File

@@ -812,6 +812,18 @@ void FBXExporter::WriteDefinitions ()
// Geometry / FbxMesh
// <~~ aiMesh
count = mScene->mNumMeshes;
// Blendshapes are considered Geometry
int32_t bsDeformerCount=0;
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
aiMesh* m = mScene->mMeshes[mi];
if (m->mNumAnimMeshes > 0) {
count+=m->mNumAnimMeshes;
bsDeformerCount+=m->mNumAnimMeshes; // One deformer per blendshape
bsDeformerCount++; // Plus one master blendshape deformer
}
}
if (count) {
n = FBX::Node("ObjectType", "Geometry");
n.AddChild("Count", count);
@@ -978,7 +990,7 @@ void FBXExporter::WriteDefinitions ()
}
// Deformer
count = int32_t(count_deformers(mScene));
count = int32_t(count_deformers(mScene))+bsDeformerCount;
if (count) {
n = FBX::Node("ObjectType", "Deformer");
n.AddChild("Count", count);
@@ -1363,6 +1375,7 @@ void FBXExporter::WriteObjects ()
n.End(outstream, binary, indent, true);
}
// aiMaterial
material_uids.clear();
for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
@@ -1697,6 +1710,100 @@ void FBXExporter::WriteObjects ()
}
}
// Blendshapes, if any
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
const aiMesh* m = mScene->mMeshes[mi];
if (m->mNumAnimMeshes == 0) {
continue;
}
// make a deformer for this mesh
int64_t deformer_uid = generate_uid();
FBX::Node dnode("Deformer");
dnode.AddProperties(deformer_uid, m->mName.data + FBX::SEPARATOR + "Blendshapes", "BlendShape");
dnode.AddChild("Version", int32_t(101));
dnode.Dump(outstream, binary, indent);
// connect it
connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]);
std::vector<int32_t> vertex_indices = vVertexIndice[mi];
for (unsigned int am = 0; am < m->mNumAnimMeshes; ++am) {
aiAnimMesh *pAnimMesh = m->mAnimMeshes[am];
std::string blendshape_name = pAnimMesh->mName.data;
// start the node record
FBX::Node bsnode("Geometry");
int64_t blendshape_uid = generate_uid();
mesh_uids.push_back(blendshape_uid);
bsnode.AddProperty(blendshape_uid);
bsnode.AddProperty(blendshape_name + FBX::SEPARATOR + "Blendshape");
bsnode.AddProperty("Shape");
bsnode.AddChild("Version", int32_t(100));
bsnode.Begin(outstream, binary, indent);
bsnode.DumpProperties(outstream, binary, indent);
bsnode.EndProperties(outstream, binary, indent);
bsnode.BeginChildren(outstream, binary, indent);
indent++;
if (pAnimMesh->HasPositions()) {
std::vector<int32_t>shape_indices;
std::vector<double>pPositionDiff;
std::vector<double>pNormalDiff;
for (unsigned int vt = 0; vt < vertex_indices.size(); ++vt) {
aiVector3D pDiff = (pAnimMesh->mVertices[vertex_indices[vt]] - m->mVertices[vertex_indices[vt]]);
if(pDiff.Length()>1e-8){
shape_indices.push_back(vertex_indices[vt]);
pPositionDiff.push_back(pDiff[0]);
pPositionDiff.push_back(pDiff[1]);
pPositionDiff.push_back(pDiff[2]);
if (pAnimMesh->HasNormals()) {
aiVector3D nDiff = (pAnimMesh->mNormals[vertex_indices[vt]] - m->mNormals[vertex_indices[vt]]);
pNormalDiff.push_back(nDiff[0]);
pNormalDiff.push_back(nDiff[1]);
pNormalDiff.push_back(nDiff[2]);
}
}
}
FBX::Node::WritePropertyNode(
"Indexes", shape_indices, outstream, binary, indent
);
FBX::Node::WritePropertyNode(
"Vertices", pPositionDiff, outstream, binary, indent
);
if (pNormalDiff.size()>0) {
FBX::Node::WritePropertyNode(
"Normals", pNormalDiff, outstream, binary, indent
);
}
}
indent--;
bsnode.End(outstream, binary, indent, true);
// Add blendshape Channel Deformer
FBX::Node sdnode("Deformer");
const int64_t blendchannel_uid = generate_uid();
sdnode.AddProperties(
blendchannel_uid, blendshape_name + FBX::SEPARATOR + "SubDeformer", "BlendShapeChannel"
);
sdnode.AddChild("Version", int32_t(100));
sdnode.AddChild("DeformPercent", int32_t(100));
FBX::Node p("Properties70");
p.AddP70numberA("DeformPercent", 100.);
sdnode.AddChild(p);
// TODO: Normally just one weight per channel, adding stub for later development
std::vector<float>fFullWeights;
fFullWeights.push_back(0.);
sdnode.AddChild("FullWeights", fFullWeights);
sdnode.Dump(outstream, binary, indent);
connections.emplace_back("C", "OO", blendchannel_uid, deformer_uid);
connections.emplace_back("C", "OO", blendshape_uid, blendchannel_uid);
}
}
// bones.
//
// output structure:

View File

@@ -302,6 +302,10 @@ void StepExporter::WriteFile()
dv23.Normalize();
dv31.Normalize();
dv13.Normalize();
aiVector3D dvY = dv12;
aiVector3D dvX = dvY ^ dv13;
dvX.Normalize();
int pid1 = uniqueVerts.find(v1)->second;
int pid2 = uniqueVerts.find(v2)->second;
@@ -337,8 +341,8 @@ void StepExporter::WriteFile()
mOutput << "#" << sid+9 << "=PLANE('',#" << sid+10 << ")" << endstr;
mOutput << "#" << sid+10 << "=AXIS2_PLACEMENT_3D('',#" << pid1 << ", #" << sid+11 << ",#" << sid+12 << ")" << endstr;
mOutput << "#" << sid+11 << "=DIRECTION('',(" << dv12.x << "," << dv12.y << "," << dv12.z << "))" << endstr;
mOutput << "#" << sid+12 << "=DIRECTION('',(" << dv13.x << "," << dv13.y << "," << dv13.z << "))" << endstr;
mOutput << "#" << sid + 11 << "=DIRECTION('',(" << dvX.x << "," << dvX.y << "," << dvX.z << "))" << endstr;
mOutput << "#" << sid + 12 << "=DIRECTION('',(" << dvY.x << "," << dvY.y << "," << dvY.z << "))" << endstr;
mOutput << "#" << sid+13 << "=FACE_BOUND('',#" << sid+14 << ",.T.)" << endstr;
mOutput << "#" << sid+14 << "=EDGE_LOOP('',(#" << sid+15 << ",#" << sid+16 << ",#" << sid+17 << "))" << endstr;

View File

@@ -370,6 +370,13 @@ struct Object {
//! Maps special IDs to another ID, where needed. Subclasses may override it (statically)
static const char *TranslateId(Asset & /*r*/, const char *id) { return id; }
inline Value *FindString(Value &val, const char *id);
inline Value *FindNumber(Value &val, const char *id);
inline Value *FindUInt(Value &val, const char *id);
inline Value *FindArray(Value &val, const char *id);
inline Value *FindObject(Value &val, const char *id);
inline Value *FindExtension(Value &val, const char *extensionId);
};
//
@@ -780,6 +787,11 @@ struct Material : public Object {
Material() { SetDefaults(); }
void Read(Value &obj, Asset &r);
void SetDefaults();
inline void SetTextureProperties(Asset &r, Value *prop, TextureInfo &out);
inline void ReadTextureProperty(Asset &r, Value &vals, const char *propName, TextureInfo &out);
inline void ReadTextureProperty(Asset &r, Value &vals, const char *propName, NormalTextureInfo &out);
inline void ReadTextureProperty(Asset &r, Value &vals, const char *propName, OcclusionTextureInfo &out);
};
//! A set of primitives to be rendered. A node can contain one or more meshes. A node's transform places the mesh in the scene.

View File

@@ -180,41 +180,133 @@ inline Value *FindMember(Value &val, const char *id) {
return (it != val.MemberEnd()) ? &it->value : nullptr;
}
inline Value *FindString(Value &val, const char *id) {
Value::MemberIterator it = val.FindMember(id);
return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : nullptr;
template<int N>
inline void throwUnexpectedTypeError(const char (&expectedTypeName)[N], const char* memberId, const char* context, const char* extraContext) {
std::string fullContext = context;
if (extraContext && (strlen(extraContext) > 0))
{
fullContext = fullContext + " (" + extraContext + ")";
}
throw DeadlyImportError("Member \"", memberId, "\" was not of type \"", expectedTypeName, "\" when reading ", fullContext);
}
inline Value *FindNumber(Value &val, const char *id) {
Value::MemberIterator it = val.FindMember(id);
return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : nullptr;
// Look-up functions with type checks. Context and extra context help the user identify the problem if there's an error.
inline Value *FindStringInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) {
Value::MemberIterator it = val.FindMember(memberId);
if (it == val.MemberEnd()) {
return nullptr;
}
if (!it->value.IsString()) {
throwUnexpectedTypeError("string", memberId, context, extraContext);
}
return &it->value;
}
inline Value *FindUInt(Value &val, const char *id) {
Value::MemberIterator it = val.FindMember(id);
return (it != val.MemberEnd() && it->value.IsUint()) ? &it->value : nullptr;
inline Value *FindNumberInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) {
Value::MemberIterator it = val.FindMember(memberId);
if (it == val.MemberEnd()) {
return nullptr;
}
if (!it->value.IsNumber()) {
throwUnexpectedTypeError("number", memberId, context, extraContext);
}
return &it->value;
}
inline Value *FindArray(Value &val, const char *id) {
Value::MemberIterator it = val.FindMember(id);
return (it != val.MemberEnd() && it->value.IsArray()) ? &it->value : nullptr;
inline Value *FindUIntInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) {
Value::MemberIterator it = val.FindMember(memberId);
if (it == val.MemberEnd()) {
return nullptr;
}
if (!it->value.IsUint()) {
throwUnexpectedTypeError("uint", memberId, context, extraContext);
}
return &it->value;
}
inline Value *FindObject(Value &val, const char *id) {
Value::MemberIterator it = val.FindMember(id);
return (it != val.MemberEnd() && it->value.IsObject()) ? &it->value : nullptr;
inline Value *FindArrayInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) {
Value::MemberIterator it = val.FindMember(memberId);
if (it == val.MemberEnd()) {
return nullptr;
}
if (!it->value.IsArray()) {
throwUnexpectedTypeError("array", memberId, context, extraContext);
}
return &it->value;
}
inline Value *FindExtension(Value &val, const char *extensionId) {
if (Value *extensionList = FindObject(val, "extensions")) {
if (Value *extension = FindObject(*extensionList, extensionId)) {
inline Value *FindObjectInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) {
Value::MemberIterator it = val.FindMember(memberId);
if (it == val.MemberEnd()) {
return nullptr;
}
if (!it->value.IsObject()) {
throwUnexpectedTypeError("object", memberId, context, extraContext);
}
return &it->value;
}
inline Value *FindExtensionInContext(Value &val, const char *extensionId, const char* context, const char* extraContext = nullptr) {
if (Value *extensionList = FindObjectInContext(val, "extensions", context, extraContext)) {
if (Value *extension = FindObjectInContext(*extensionList, extensionId, context, extraContext)) {
return extension;
}
}
return nullptr;
}
// Overloads when the value is the document.
inline Value *FindString(Document &doc, const char *memberId) {
return FindStringInContext(doc, memberId, "the document");
}
inline Value *FindNumber(Document &doc, const char *memberId) {
return FindNumberInContext(doc, memberId, "the document");
}
inline Value *FindUInt(Document &doc, const char *memberId) {
return FindUIntInContext(doc, memberId, "the document");
}
inline Value *FindArray(Document &val, const char *memberId) {
return FindArrayInContext(val, memberId, "the document");
}
inline Value *FindObject(Document &doc, const char *memberId) {
return FindObjectInContext(doc, memberId, "the document");
}
inline Value *FindExtension(Value &val, const char *extensionId) {
return FindExtensionInContext(val, extensionId, "the document");
}
} // namespace
inline Value *Object::FindString(Value &val, const char *memberId) {
return FindStringInContext(val, memberId, id.c_str(), name.c_str());
}
inline Value *Object::FindNumber(Value &val, const char *memberId) {
return FindNumberInContext(val, memberId, id.c_str(), name.c_str());
}
inline Value *Object::FindUInt(Value &val, const char *memberId) {
return FindUIntInContext(val, memberId, id.c_str(), name.c_str());
}
inline Value *Object::FindArray(Value &val, const char *memberId) {
return FindArrayInContext(val, memberId, id.c_str(), name.c_str());
}
inline Value *Object::FindObject(Value &val, const char *memberId) {
return FindObjectInContext(val, memberId, id.c_str(), name.c_str());
}
inline Value *Object::FindExtension(Value &val, const char *extensionId) {
return FindExtensionInContext(val, extensionId, id.c_str(), name.c_str());
}
#ifdef ASSIMP_ENABLE_DRACO
template <typename T>
@@ -349,17 +441,20 @@ inline LazyDict<T>::~LazyDict() {
template <class T>
inline void LazyDict<T>::AttachToDocument(Document &doc) {
Value *container = nullptr;
const char* context = nullptr;
if (mExtId) {
if (Value *exts = FindObject(doc, "extensions")) {
container = FindObject(*exts, mExtId);
container = FindObjectInContext(*exts, mExtId, "extensions");
context = mExtId;
}
} else {
container = &doc;
context = "the document";
}
if (container) {
mDict = FindArray(*container, mDictId);
mDict = FindArrayInContext(*container, mDictId, context);
}
}
@@ -383,6 +478,7 @@ unsigned int LazyDict<T>::Remove(const char *id) {
mAsset.mUsedIds[id] = false;
mObjsById.erase(id);
mObjsByOIndex.erase(index);
delete mObjs[index];
mObjs.erase(mObjs.begin() + index);
//update index of object in mObjs;
@@ -788,7 +884,14 @@ inline void Accessor::Read(Value &obj, Asset &r) {
byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
count = MemberOrDefault(obj, "count", size_t(0));
{
const Value* countValue = FindUInt(obj, "count");
if (!countValue || countValue->GetInt() < 1)
{
throw DeadlyImportError("A strictly positive count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
}
count = countValue->GetUint();
}
const char *typestr;
type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
@@ -1107,8 +1210,7 @@ inline void Texture::Read(Value &obj, Asset &r) {
}
}
namespace {
inline void SetTextureProperties(Asset &r, Value *prop, TextureInfo &out) {
void Material::SetTextureProperties(Asset &r, Value *prop, TextureInfo &out) {
if (r.extensionsUsed.KHR_texture_transform) {
if (Value *pKHR_texture_transform = FindExtension(*prop, "KHR_texture_transform")) {
out.textureTransformSupported = true;
@@ -1134,8 +1236,8 @@ inline void SetTextureProperties(Asset &r, Value *prop, TextureInfo &out) {
}
}
if (Value *index = FindUInt(*prop, "index")) {
out.texture = r.textures.Retrieve(index->GetUint());
if (Value *indexProp = FindUInt(*prop, "index")) {
out.texture = r.textures.Retrieve(indexProp->GetUint());
}
if (Value *texcoord = FindUInt(*prop, "texCoord")) {
@@ -1143,13 +1245,13 @@ inline void SetTextureProperties(Asset &r, Value *prop, TextureInfo &out) {
}
}
inline void ReadTextureProperty(Asset &r, Value &vals, const char *propName, TextureInfo &out) {
inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, TextureInfo &out) {
if (Value *prop = FindMember(vals, propName)) {
SetTextureProperties(r, prop, out);
}
}
inline void ReadTextureProperty(Asset &r, Value &vals, const char *propName, NormalTextureInfo &out) {
inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, NormalTextureInfo &out) {
if (Value *prop = FindMember(vals, propName)) {
SetTextureProperties(r, prop, out);
@@ -1159,7 +1261,7 @@ inline void ReadTextureProperty(Asset &r, Value &vals, const char *propName, Nor
}
}
inline void ReadTextureProperty(Asset &r, Value &vals, const char *propName, OcclusionTextureInfo &out) {
inline void Material::ReadTextureProperty(Asset &r, Value &vals, const char *propName, OcclusionTextureInfo &out) {
if (Value *prop = FindMember(vals, propName)) {
SetTextureProperties(r, prop, out);
@@ -1168,7 +1270,6 @@ inline void ReadTextureProperty(Asset &r, Value &vals, const char *propName, Occ
}
}
}
} // namespace
inline void Material::Read(Value &material, Asset &r) {
SetDefaults();
@@ -1762,17 +1863,10 @@ inline void AssetMetadata::Read(Document &doc) {
ReadMember(*obj, "copyright", copyright);
ReadMember(*obj, "generator", generator);
if (Value *versionString = FindString(*obj, "version")) {
if (Value *versionString = FindStringInContext(*obj, "version", "\"asset\"")) {
version = versionString->GetString();
} else if (Value *versionNumber = FindNumber(*obj, "version")) {
char buf[4];
ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble());
version = buf;
}
Value *curProfile = FindObject(*obj, "profile");
Value *curProfile = FindObjectInContext(*obj, "profile", "\"asset\"");
if (nullptr != curProfile) {
ReadMember(*curProfile, "api", this->profile.api);
ReadMember(*curProfile, "version", this->profile.version);

View File

@@ -110,19 +110,18 @@ namespace glTF2 {
if (a.bufferView) {
obj.AddMember("bufferView", a.bufferView->index, w.mAl);
obj.AddMember("byteOffset", (unsigned int)a.byteOffset, w.mAl);
Value vTmpMax, vTmpMin;
if (a.componentType == ComponentType_FLOAT) {
obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl);
obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl);
} else {
obj.AddMember("max", MakeValueCast<int64_t>(vTmpMax, a.max, w.mAl), w.mAl);
obj.AddMember("min", MakeValueCast<int64_t>(vTmpMin, a.min, w.mAl), w.mAl);
}
}
obj.AddMember("componentType", int(a.componentType), w.mAl);
obj.AddMember("count", (unsigned int)a.count, w.mAl);
obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
Value vTmpMax, vTmpMin;
if (a.componentType == ComponentType_FLOAT) {
obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl);
obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl);
} else {
obj.AddMember("max", MakeValueCast<int64_t>(vTmpMax, a.max, w.mAl), w.mAl);
obj.AddMember("min", MakeValueCast<int64_t>(vTmpMin, a.min, w.mAl), w.mAl);
}
if (a.sparse) {
Value sparseValue;
@@ -887,6 +886,7 @@ namespace glTF2 {
if (d.mObjs.empty()) return;
Value* container = &mDoc;
const char* context = "Document";
if (d.mExtId) {
Value* exts = FindObject(mDoc, "extensions");
@@ -895,17 +895,18 @@ namespace glTF2 {
exts = FindObject(mDoc, "extensions");
}
container = FindObject(*exts, d.mExtId);
container = FindObjectInContext(*exts, d.mExtId, "extensions");
if (nullptr != container) {
exts->AddMember(StringRef(d.mExtId), Value().SetObject().Move(), mDoc.GetAllocator());
container = FindObject(*exts, d.mExtId);
container = FindObjectInContext(*exts, d.mExtId, "extensions");
context = d.mExtId;
}
}
Value *dict = FindArray(*container, d.mDictId);
Value *dict = FindArrayInContext(*container, d.mDictId, context);
if (nullptr == dict) {
container->AddMember(StringRef(d.mDictId), Value().SetArray().Move(), mDoc.GetAllocator());
dict = FindArray(*container, d.mDictId);
dict = FindArrayInContext(*container, d.mDictId, context);
if (nullptr == dict) {
return;
}

View File

@@ -122,7 +122,7 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
const aiFace& face = mesh->mFaces[fidx];
if (face.mNumIndices < 3) continue; // triangles and polygons only, please
unsigned int small = face.mNumIndices, large = small;
unsigned int smallV = face.mNumIndices, large = smallV;
bool zero = false, one = false, round_to_zero = false;
// Check whether this face lies on a UV seam. We can just guess,
@@ -133,7 +133,7 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
{
if (out[face.mIndices[n]].x < LOWER_LIMIT)
{
small = n;
smallV = n;
// If we have a U value very close to 0 we can't
// round the others to 0, too.
@@ -151,7 +151,7 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
one = true;
}
}
if (small != face.mNumIndices && large != face.mNumIndices)
if (smallV != face.mNumIndices && large != face.mNumIndices)
{
for (unsigned int n = 0; n < face.mNumIndices;++n)
{