diff --git a/code/AssetLib/Assbin/AssbinLoader.cpp b/code/AssetLib/Assbin/AssbinLoader.cpp index f7b35636c7..04e4738b0e 100644 --- a/code/AssetLib/Assbin/AssbinLoader.cpp +++ b/code/AssetLib/Assbin/AssbinLoader.cpp @@ -700,6 +700,7 @@ void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, I stream->Seek(128, aiOrigin_CUR); // options stream->Seek(64, aiOrigin_CUR); // padding + /* if (compressed) { uLongf uncompressedSize = Read(stream); uLongf compressedSize = static_cast(stream->FileSize() - stream->Tell()); @@ -725,8 +726,9 @@ void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, I delete[] uncompressedData; delete[] compressedData; } else { + */ ReadBinaryScene(stream, pScene); - } + //} pIOHandler->Close(stream); } diff --git a/code/AssetLib/MMD/MMDImporter.cpp b/code/AssetLib/MMD/MMDImporter.cpp index 97b04f4eb4..fc478af778 100644 --- a/code/AssetLib/MMD/MMDImporter.cpp +++ b/code/AssetLib/MMD/MMDImporter.cpp @@ -51,8 +51,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include #include #include #include @@ -68,6 +70,15 @@ static const aiImporterDesc desc = { "MMD Importer", 0, "pmx" }; +namespace { + struct membuf : std::streambuf + { + membuf(char* begin, char* end) { + this->setg(begin, begin, end); + } + }; +} + namespace Assimp { using namespace std; @@ -167,6 +178,85 @@ void MMDImporter::CreateDataFromImport(const pmx::PmxModel *pModel, indexStart += indexCount; } + { + int morphTotal = 0; + for (int morphNo = 0; morphNo < pModel->morph_count; morphNo++) { + const auto& morph = pModel->morphs[morphNo]; + if (morph.morph_type != pmx::MorphType::Vertex) { + continue; + } + if (morph.morph_name.length() <= 0) { + continue; + } + morphTotal++; + } + + int indexStart = 0; + int indexNext = 0; + for (unsigned int i = 0; i < pScene->mNumMeshes; i++) { + const unsigned int indexCount = pModel->materials[i].index_count; + indexStart = indexNext; + indexNext += indexCount; + + auto* aim = pScene->mMeshes[i]; + if (aim->mNumAnimMeshes == 0) { + aim->mNumAnimMeshes = (unsigned int)morphTotal; + aim->mAnimMeshes = new aiAnimMesh * [aim->mNumAnimMeshes]; + } + + int currentMorph = 0; + for (int morphNo = 0; morphNo < pModel->morph_count; morphNo++) { + + const auto& morph = pModel->morphs[morphNo]; + if (morph.morph_type != pmx::MorphType::Vertex) { + continue; + } + if (morph.morph_name.length() <= 0) { + continue; + } + + int c = currentMorph; + currentMorph++; + + aim->mAnimMeshes[c] = Assimp::aiCreateAnimMesh(aim); + aiAnimMesh& aiAnimMesh = *(aim->mAnimMeshes[c]); + for (unsigned int v = 0; v < aiAnimMesh.mNumVertices; ++v) { + //aiAnimMesh.mVertices[v] = aim->mVertices[v]; + aiAnimMesh.mVertices[v].Set(0, 0, 0); + } + + //vrm + aiAnimMesh.mName = morph.morph_name; + + if (morph.vertex_offsets.get() != nullptr) { + for (int vertexId = 0; vertexId < morph.offset_count; vertexId++) { + const auto& ver = morph.vertex_offsets[vertexId]; + const int targetIndex = ver.vertex_index; + + int bFoundCount = false; + for (unsigned int uu = 0; uu < indexCount; ++uu) { + if (pModel->indices[indexStart + uu] == targetIndex) { + ++bFoundCount; + //break; + if (uu < aiAnimMesh.mNumVertices) { + aiAnimMesh.mVertices[uu].Set( + -morph.vertex_offsets[vertexId].position_offset[0], + morph.vertex_offsets[vertexId].position_offset[1], + -morph.vertex_offsets[vertexId].position_offset[2]); + } + } + } + if (bFoundCount == 0) { + continue; + } + + aiAnimMesh.mWeight = 1.f; + } + } + } + } + } // morph end + // create node hierarchy for bone position std::unique_ptr ppNode(new aiNode *[pModel->bone_count]); for (auto i = 0; i < pModel->bone_count; i++) { @@ -178,6 +268,11 @@ void MMDImporter::CreateDataFromImport(const pmx::PmxModel *pModel, if (bone.parent_index < 0) { pScene->mRootNode->addChildren(1, ppNode.get() + i); + aiVector3D v3 = aiVector3D( + bone.position[0], + bone.position[1], + bone.position[2]); + aiMatrix4x4::Translation(v3, ppNode[i]->mTransformation); } else { ppNode[bone.parent_index]->addChildren(1, ppNode.get() + i); @@ -326,7 +421,11 @@ aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel, aiMaterial *MMDImporter::CreateMaterial(const pmx::PmxMaterial *pMat, const pmx::PmxModel *pModel) { aiMaterial *mat = new aiMaterial(); - aiString name(pMat->material_english_name); + //aiString name(pMat->material_english_name); + aiString name(pMat->material_name); + if (pMat->material_name.size() == 0) { + name = pMat->material_english_name; + } mat->AddProperty(&name, AI_MATKEY_NAME); aiColor3D diffuse(pMat->diffuse[0], pMat->diffuse[1], pMat->diffuse[2]); diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 3becc4d9b5..26f9bc6333 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -92,6 +92,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # define ai_assert #endif +#include "assimp/vrm/vrmmeta.h" + #if _MSC_VER > 1500 || (defined __GNUC___) # define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP #else @@ -803,6 +805,8 @@ struct MaterialIOR { //! The material appearance of a primitive. struct Material : public Object { + std::string shaderName; + //PBR metallic roughness properties PbrMetallicRoughness pbrMetallicRoughness; @@ -862,6 +866,7 @@ struct Mesh : public Object { Ref material; struct Target { + std::string name; AccessorList position, normal, tangent; }; std::vector targets; @@ -1062,6 +1067,25 @@ class LazyDict : public LazyDictBase { inline T &operator[](size_t i) { return *mObjs[i]; } }; + +struct GLTF2VRMMetadata +{ + VRM::VRMMetadata* vrmdata; + + std::map materialShaderName; + + void Read(Document& doc, Asset& r); + + GLTF2VRMMetadata() : vrmdata(nullptr) {} + + ~GLTF2VRMMetadata() { + if (vrmdata) delete vrmdata; + vrmdata = nullptr; + } +}; + + + struct AssetMetadata { std::string copyright; //!< A copyright message suitable for display to credit the content creator. std::string generator; //!< Tool that generated this glTF model.Useful for debugging. @@ -1140,6 +1164,9 @@ class Asset { AssetMetadata asset; Value *extras; + GLTF2VRMMetadata vrmdata; + + // Dictionaries for each type of object LazyDict accessors; diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index db47915d64..47231ea0b4 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -1101,6 +1101,9 @@ inline void Image::Read(Value &obj, Asset &r) { throw DeadlyImportError("GLTF2: ", getContextForErrorMessages(id, name), " should have either a URI of a bufferView and mimetype"); } } + if (Value* v = FindMember(obj, "name")) { + uri = v->GetString(); + } } inline uint8_t *Image::StealData() { @@ -1235,6 +1238,11 @@ inline void Material::Read(Value &material, Asset &r) { ReadMember(material, "alphaMode", this->alphaMode); ReadMember(material, "alphaCutoff", this->alphaCutoff); + ReadMember(material, "shader", this->shaderName); + if (Value* v = FindMember(material, "shader")) { + this->shaderName = *v->GetString(); + } + if (Value *extensions = FindObject(material, "extensions")) { if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) { if (Value *curPbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) { @@ -1486,6 +1494,19 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) { } (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint()); } + if (Value* v1 = FindMember(target, "extra")) { + if (Value* v2 = FindMember(*v1, "name")) { + prim.targets[i].name = v2->GetString(); + } + } + } + } + // ex name + if (Value* ex = FindObject(primitive, "extras")) { + if (Value* t = FindArray(*ex, "targetNames")) { + for (uint32_t j = 0; j < t->Size(); ++j) { + prim.targets[j].name = (*t)[j].GetString(); + } } } } @@ -1605,12 +1626,28 @@ inline void Node::Read(Value &obj, Asset &r) { Value *curMesh = FindUInt(obj, "mesh"); if (nullptr != curMesh) { - unsigned int numMeshes = 1; + //unsigned int numMeshes = 1; + + unsigned int cc = (*curMesh).GetUint(); + // cache meshes + for (unsigned int i = 0; i < cc; ++i) { + Ref tmp = r.meshes.Retrieve(i); + (void)tmp; + //do not delete! + } + Ref meshRef = r.meshes.Retrieve(cc); + + if (this->meshes.size() == 0) { + if (meshRef) this->meshes.push_back(meshRef); + } + + /* this->meshes.reserve(numMeshes); Ref meshRef = r.meshes.Retrieve((*curMesh).GetUint()); if (meshRef) { this->meshes.push_back(meshRef); } + */ } // Do not retrieve a skin here, just take a reference, to avoid infinite recursion @@ -1676,6 +1713,386 @@ inline void Skin::Read(Value &obj, Asset &r) { } } +//vrm +//static std::vector shapeBlend = { +// "Neutral","A","I","U","E","O","Blink","Joy","Angry","Sorrow","Fun","LookUp","LookDown","LookLeft","LookRight","Blink_L","Blink_R", +//}; + +static std::vector humanBoneNameList = { + "hips", + "leftUpperLeg","rightUpperLeg","leftLowerLeg","rightLowerLeg", + "leftFoot","rightFoot", + "spine","chest","neck","head", + "leftShoulder","rightShoulder","leftUpperArm","rightUpperArm", + "leftLowerArm","rightLowerArm","leftHand","rightHand","leftToes","rightToes", + "leftEye","rightEye","jaw", + "leftThumbProximal","leftThumbIntermediate","leftThumbDistal","leftIndexProximal", + "leftIndexIntermediate","leftIndexDistal","leftMiddleProximal","leftMiddleIntermediate", + "leftMiddleDistal","leftRingProximal","leftRingIntermediate","leftRingDistal","leftLittleProximal","leftLittleIntermediate","leftLittleDistal", + "rightThumbProximal","rightThumbIntermediate","rightThumbDistal","rightIndexProximal", + "rightIndexIntermediate","rightIndexDistal","rightMiddleProximal","rightMiddleIntermediate", + "rightMiddleDistal","rightRingProximal","rightRingIntermediate","rightRingDistal","rightLittleProximal", + "rightLittleIntermediate","rightLittleDistal","upperChest", +}; + +static std::string getNodeNameFromMesh(std::string meshName, Asset& r) { + + for (unsigned int i = 0; i < r.nodes.Size(); ++i) { + Ref node = r.nodes.Retrieve(i); + for (auto& mm : node->meshes) { + if (mm->name == meshName) { + return node->name; + } + } + } + return ""; +} + +inline void GLTF2VRMMetadata::Read(Document& doc, Asset& r) +{ + + auto FindObjectLocal = [](Value& val, const char* memberId/*, const char* context=nullptr, const char* extraContext = nullptr*/) { + Value* ret = nullptr; + if (!val.IsObject()) { + return ret; + } + Value::MemberIterator it = val.FindMember(memberId); + if (it == val.MemberEnd()) { + return ret; + } + if (!it->value.IsObject()) { + //throwUnexpectedTypeError("object", memberId, context, extraContext); + } + return &it->value; + }; + + auto FindArrayLocal = [](Value& val, const char* memberId/*, const char* context, const char* extraContext = nullptr*/) { + Value* ret = nullptr; + if (!val.IsObject()) { + return ret; + } + Value::MemberIterator it = val.FindMember(memberId); + if (it == val.MemberEnd()) { + return ret; + } + if (!it->value.IsArray()) { + //throwUnexpectedTypeError("array", memberId, context, extraContext); + } + return &it->value; + }; + + + vrmdata = new VRM::VRMMetadata(); + + Value* ext = FindObject(doc, "extensions"); + if (ext == nullptr) { + return; + } + Value* vrm = FindObjectLocal(*ext, "VRM"); + if (vrm == nullptr) { + return; + } + + if (Value* sec = FindObjectLocal(*vrm, "secondaryAnimation")) { + if (Value* nodeArray = FindArrayLocal(*sec, "boneGroups")) { + vrmdata->springNum = nodeArray->Size(); + vrmdata->springs = new VRM::VRMSpring[vrmdata->springNum]; + for (unsigned int i = 0; i < nodeArray->Size(); ++i) { + VRM::VRMSpring& s = vrmdata->springs[i]; + // warning! stiffiness in VRM <- stiffness in member + if (Value* v = FindMember((*nodeArray)[i], "stiffiness")) { + s.stiffness = v->GetFloat(); + } + if (Value* v = FindMember((*nodeArray)[i], "gravityPower")) { + s.gravityPower = v->GetFloat(); + } + if (Value* v = FindObjectLocal((*nodeArray)[i], "gravityDir")) { + s.gravityDir[0] = FindMember(*v, "x")->GetFloat(); + s.gravityDir[1] = FindMember(*v, "y")->GetFloat(); + s.gravityDir[2] = FindMember(*v, "z")->GetFloat(); + } + + if (Value* v = FindMember((*nodeArray)[i], "dragForce")) { + s.dragForce = v->GetFloat(); + } + if (Value* v = FindMember((*nodeArray)[i], "hitRadius")) { + s.hitRadius = v->GetFloat(); + } + if (Value* v = FindArrayLocal((*nodeArray)[i], "bones")) { + s.boneNum = v->Size(); + s.bones = new int[s.boneNum]; + s.bones_name = new aiString[s.boneNum]; + for (unsigned int i2 = 0; i2 < v->Size(); ++i2) { + int j = (*v)[i2].GetInt(); + s.bones[i2] = j; + Ref chn = r.nodes.Retrieve(s.bones[i2]); + s.bones_name[i2] = chn->name; + } + } + if (Value* v = FindMember((*nodeArray)[i], "colliderGroups")) { + s.colliderGourpNum = v->Size(); + s.colliderGroups = new int[s.colliderGourpNum]; + for (unsigned int i2 = 0; i2 < v->Size(); ++i2) { + int j = (*v)[i2].GetInt(); + s.colliderGroups[i2] = j; + } + } + } + } + if (Value* nodeArray = FindArrayLocal(*sec, "colliderGroups")) { + vrmdata->colliderGroupNum = nodeArray->Size(); + vrmdata->colliderGroups = new VRM::VRMColliderGroup[vrmdata->colliderGroupNum]; + for (unsigned int i = 0; i < nodeArray->Size(); ++i) { + VRM::VRMColliderGroup& g = vrmdata->colliderGroups[i]; + g.node = FindMember((*nodeArray)[i], "node")->GetInt(); + + Ref chn = r.nodes.Retrieve(g.node); + g.node_name = chn->name; + //g.node_name = r.nodes[g.node].Name; + + if (Value* cArray = FindArrayLocal((*nodeArray)[i], "colliders")) { + g.colliderNum = cArray->Size(); + g.colliders = new VRM::VRMCollider[g.colliderNum]; + for (unsigned int ic = 0; ic < cArray->Size(); ++ic) { + VRM::VRMCollider& c = g.colliders[ic]; + if (Value* v = FindObjectLocal((*cArray)[ic], "offset")) { + c.offset[0] = FindMember((*v), "x")->GetFloat(); + c.offset[1] = FindMember((*v), "y")->GetFloat(); + c.offset[2] = FindMember((*v), "z")->GetFloat(); + } + c.radius = FindMember((*cArray)[ic], "radius")->GetFloat(); + //g.colliders.push_back(c); + } + } + } + } + } + + if (Value* mp = FindArrayLocal(*vrm, "materialProperties")) { + vrmdata->materialNum = mp->Size(); + vrmdata->material = new VRM::VRMMaterial[vrmdata->materialNum]; + memset(vrmdata->material, 0, sizeof(VRM::VRMMaterial) * vrmdata->materialNum); + + for (uint32_t m = 0; m < mp->Size(); ++m) { + std::string name, shaderName; + if (Value* v = FindMember((*mp)[m], "name")) { + name = v->GetString(); + } + if (Value* v = FindMember((*mp)[m], "shader")) { + shaderName = v->GetString(); + } + materialShaderName.insert(std::make_pair(name, shaderName)); + + auto& mat = vrmdata->material[m]; + auto& pro_f = mat.floatProperties; + auto& pro_v = mat.vectorProperties; + auto& pro_t = mat.textureProperties; + mat.name = name; + mat.shaderName = shaderName; + + { + // scalar + struct TT { + std::string key; + float& value; + }; + TT table[] = { + {"_Cutoff", pro_f._Cutoff}, + {"_BumpScale", pro_f._BumpScale}, + {"_ReceiveShadowRate", pro_f._ReceiveShadowRate}, + {"_ShadeShift", pro_f._ShadeShift}, + {"_ShadeToony", pro_f._ShadeToony}, + {"_LightColorAttenuation", pro_f._LightColorAttenuation}, + {"_IndirectLightIntensity", pro_f._IndirectLightIntensity}, + {"_RimLightingMix", pro_f._RimLightingMix}, + {"_RimFresnelPower", pro_f._RimFresnelPower}, + {"_RimLift", pro_f._RimLift}, + {"_OutlineWidth", pro_f._OutlineWidth}, + {"_OutlineScaledMaxDistance", pro_f._OutlineScaledMaxDistance}, + {"_OutlineLightingMix", pro_f._OutlineLightingMix}, + {"_UvAnimScrollX", pro_f._UvAnimScrollX}, + {"_UvAnimScrollY", pro_f._UvAnimScrollY}, + {"_UvAnimRotation", pro_f._UvAnimRotation}, + {"_MToonVersion", pro_f._MToonVersion}, + {"_DebugMode", pro_f._DebugMode}, + {"_BlendMode", pro_f._BlendMode}, + {"_OutlineWidthMode", pro_f._OutlineWidthMode}, + {"_OutlineColorMode", pro_f._OutlineColorMode}, + {"_CullMode", pro_f._CullMode}, + {"_OutlineCullMode", pro_f._OutlineCullMode}, + {"_SrcBlend", pro_f._SrcBlend}, + {"_DstBlend", pro_f._DstBlend}, + {"_ZWrite", pro_f._ZWrite}, + }; + if (Value* p = FindObjectLocal((*mp)[m], "floatProperties")) { + for (auto& t : table) { + ReadMember(*p, t.key.c_str(), t.value); + } + } + } + { + // vector + struct TT { + std::string key; + vec4& value; + }; + TT table[] = { + {"_Color", pro_v._Color}, + {"_ShadeColor", pro_v._ShadeColor}, + {"_MainTex", pro_v._MainTex}, + {"_ShadeTexture", pro_v._ShadeTexture}, + {"_BumpMap", pro_v._BumpMap}, + {"_ReceiveShadowTexture", pro_v._ReceiveShadowTexture}, + {"_ShadingGradeTexture", pro_v._ShadingGradeTexture}, + {"_RimColor", pro_v._RimColor}, + {"_RimTexture", pro_v._RimTexture}, + {"_SphereAdd", pro_v._SphereAdd}, + {"_EmissionColor", pro_v._EmissionColor}, + {"_EmissionMap", pro_v._EmissionMap}, + {"_OutlineWidthTexture", pro_v._OutlineWidthTexture}, + {"_OutlineColor", pro_v._OutlineColor}, + {"_UvAnimMaskTexture", pro_v._UvAnimMaskTexture}, + }; + if (Value* p = FindObjectLocal((*mp)[m], "vectorProperties")) { + for (auto& t : table) { + ReadMember(*p, t.key.c_str(), t.value); + } + } + } + { + // texture index + struct TT { + std::string key; + int& value; + }; + TT table[] = { + {"_MainTex", pro_t._MainTex}, + {"_ShadeTexture", pro_t._ShadeTexture}, + {"_BumpMap", pro_t._BumpMap}, + {"_ReceiveShadowTexture",pro_t._ReceiveShadowTexture}, + {"_ShadingGradeTexture", pro_t._ShadingGradeTexture}, + {"_RimTexture", pro_t._RimTexture}, + {"_SphereAdd", pro_t._SphereAdd}, + {"_EmissionMap", pro_t._EmissionMap}, + {"_OutlineWidthTexture", pro_t._OutlineWidthTexture}, + {"_UvAnimMaskTexture", pro_t._UvAnimMaskTexture}, + }; + if (Value* p = FindObjectLocal((*mp)[m], "textureProperties")) { + for (auto& t : table) { + if (ReadMember(*p, t.key.c_str(), t.value)) { + } else { + t.value = -1; + } + } + } + } + } + } + if (1) { + if (Value* meta = FindObjectLocal(*vrm, "meta")) { + std::string target[] = { + "version","author","contactInformation","reference", + "title", "texture", + "allowedUserName", + "violentUssageName","sexualUssageName","commercialUssageName", + "otherPermissionUrl","licenseName","otherLicenseUrl" + }; + auto& lic = vrmdata->license; + lic.licensePairNum = VRM::LIC_max; + lic.licensePair = new VRM::VRMLicensePair[lic.licensePairNum]; + int min = sizeof(target) / sizeof(target[0]); + min = (min < VRM::LIC_max) ? min : VRM::LIC_max; + for (int i = 0; i < min; ++i) { + if (Value* v = FindMember(*meta, target[i].c_str())) { + lic.licensePair[i].Key = target[i]; + + if (i == VRM::LIC_texture) { + lic.licensePair[i].Value = std::to_string(v->GetInt()); + } else { + lic.licensePair[i].Value = v->GetString(); + } + } + } + lic.licensePair[VRM::LIC_futter].Key = "vrm4u_futter"; + lic.licensePair[VRM::LIC_futter].Value = "vrm4u_futter"; + } + } + + if (Value* human = FindObjectLocal(*vrm, "humanoid")) { + if (Value* hb = FindArrayLocal(*human, "humanBones")) { + for (uint32_t b = 0; b < hb->Size(); ++b) { + std::string s; + ReadMember((*hb)[b], "bone", s); + + for (auto a : humanBoneNameList) { + if (a != s) { + continue; + } + vrmdata->humanoidBone[b].humanBoneName = s.c_str(); + + int i; + ReadMember((*hb)[b], "node", i); + vrmdata->humanoidBone[b].nodeName = r.nodes.Retrieve(i)->name; + break; + } + } + } + } + + if (Value* blendMaster = FindObjectLocal(*vrm, "blendShapeMaster")) { + if (Value* bsg = FindArrayLocal(*blendMaster, "blendShapeGroups")) { + + vrmdata->blensShapeGroupNum = bsg->Size(); + vrmdata->blensShapeGourp = new VRM::VRMBlendShapeGroup[vrmdata->blensShapeGroupNum]; + for (uint32_t iBsg = 0; iBsg < bsg->Size(); ++iBsg) { + std::string s; + ReadMember((*bsg)[iBsg], "name", s); + + //for (auto a : shapeBlend) { + { + //if (a != s) { + // continue; + //} + auto& shapeGroup = vrmdata->blensShapeGourp[iBsg]; + shapeGroup.groupName = s.c_str(); + + Value* binds = FindArrayLocal((*bsg)[iBsg], "binds"); + + shapeGroup.bindNum = binds->Size(); + shapeGroup.bind = new VRM::VRMBlendShapeBind[shapeGroup.bindNum]; + + for (int iBind = 0; iBind < shapeGroup.bindNum; ++iBind) { + auto& bi = shapeGroup.bind[iBind]; + + ReadMember((*binds)[iBind], "mesh", bi.meshID); + ReadMember((*binds)[iBind], "index", bi.shapeIndex); + ReadMember((*binds)[iBind], "weight", bi.weight); + + Ref mp = r.meshes.Retrieve(bi.meshID); + int offset = 0; + for (int tmp = 0; tmp < bi.meshID; ++tmp) { + Ref mp2 = r.meshes.Retrieve(tmp); + offset += (int)(mp2->primitives.size()) - 1; + } + + bi.meshID += offset; + bi.meshName = mp->name; + + bi.nodeName = getNodeNameFromMesh(bi.meshName.C_Str(), r).c_str(); + + + bi.blendShapeName = mp->primitives[0].targets[bi.shapeIndex].name; + + } + } + } + } + } +} +//vrm + + + inline void Animation::Read(Value &obj, Asset &r) { Value *curSamplers = FindArray(obj, "samplers"); if (nullptr != curSamplers) { @@ -1936,12 +2353,52 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) sceneIndex = curScene->GetUint(); } + { + //if (Value* skinsArray = FindArray(doc, "skins")) { + // skins.Retrieve(0); + // } + } + if (Value* im = FindArray(doc, "images")) { + for (unsigned int m = 0; m < im->Size(); ++m) { + images.Retrieve(m); + } + } + + if (Value* nodeArray = FindArray(doc, "nodes")) { + for (unsigned int i = 0; i < nodeArray->Size(); ++i) { + nodes.Retrieve(i); + } + } + if (Value* nodeArray = FindArray(doc, "accessors")) { + for (unsigned int i = 0; i < nodeArray->Size(); ++i) { + accessors.Retrieve(i); + } + } + if (Value* nodeArray = FindArray(doc, "skins")) { + for (unsigned int i = 0; i < nodeArray->Size(); ++i) { + skins.Retrieve(i); + } + } + + { + if (Value* animMeshesArray = FindArray(doc, "animations")) { + animations.Retrieve(0); + } + } + + if (Value *scenesArray = FindArray(doc, "scenes")) { if (sceneIndex < scenesArray->Size()) { this->scene = scenes.Retrieve(sceneIndex); } } + if (Value* materialsArray = FindArray(doc, "materials")) { + for (unsigned int i = 0; i < materialsArray->Size(); ++i) { + this->materials.Retrieve(i); + } + } + if (Value *skinsArray = FindArray(doc, "skins")) { for (unsigned int i = 0; i < skinsArray->Size(); ++i) { skins.Retrieve(i); @@ -1958,6 +2415,17 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) for (size_t i = 0; i < mDicts.size(); ++i) { mDicts[i]->DetachFromDocument(); } + + // call last!! + { + { + for (unsigned int i = 0; i < nodes.Size(); ++i) { + printf("%s\n", nodes[i].name.c_str()); + printf("%s\n", nodes[i].id.c_str()); + } + } + vrmdata.Read(doc, *this); + } } inline bool Asset::CanRead(const std::string &pFile, bool isBinary) { diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 947edc8d51..8b06e93822 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -66,6 +66,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +//vrm +void VRM_ReleaseVRMMeta(void *p) { + VRM::VRMMetadata* meta = reinterpret_cast(p); + if (meta) { + delete meta; + meta = nullptr; + } +} +//vrm + using namespace Assimp; using namespace glTF2; using namespace glTFCommon; @@ -92,7 +102,7 @@ static const aiImporterDesc desc = { 0, 0, 0, - "gltf glb" + "gltf glb vrm" }; glTF2Importer::glTF2Importer() : @@ -111,15 +121,14 @@ const aiImporterDesc *glTF2Importer::GetInfo() const { bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const { const std::string extension = GetExtension(filename); - if (!checkSig && (extension != "gltf") && (extension != "glb")) { + if (!checkSig && (extension != "gltf") && (extension != "glb") && (extension != "vrm")) { return false; } if (pIOHandler) { glTF2::Asset asset(pIOHandler); - return asset.CanRead(filename, extension == "glb"); + return asset.CanRead(filename, extension == "glb" || extension == "vrm"); } - return false; } @@ -357,6 +366,9 @@ static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, M aimat->AddProperty(&ior.ior, 1, AI_MATKEY_REFRACTI); } + //vrm + aimat->mShaderName = mat.shaderName; + return aimat; } catch (...) { delete aimat; @@ -375,7 +387,10 @@ void glTF2Importer::ImportMaterials(Asset &r) { mScene->mMaterials[numImportedMaterials] = ImportMaterial(mEmbeddedTexIdxs, r, defaultMaterial); for (unsigned int i = 0; i < numImportedMaterials; ++i) { - mScene->mMaterials[i] = ImportMaterial(mEmbeddedTexIdxs, r, r.materials[i]); + //mScene->mMaterials[i] = ImportMaterial(mEmbeddedTexIdxs, r, r.materials[i]); + glTF2::Ref ref = r.materials.Retrieve(i); + mScene->mMaterials[i] = ImportMaterial(mEmbeddedTexIdxs, r, *ref); + mScene->mMaterials[i]->mShaderName = r.vrmdata.materialShaderName[mScene->mMaterials[i]->GetName().C_Str()]; } } @@ -579,6 +594,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { aiAnimMesh &aiAnimMesh = *(aim->mAnimMeshes[i]); Mesh::Primitive::Target &target = targets[i]; + //vrm + aiAnimMesh.mName = target.name; + if (needPositions) { if (target.position[0]->count != aim->mNumVertices) { ASSIMP_LOG_WARN("Positions of target ", i, " in mesh \"", mesh.name, "\" does not match the vertex count"); @@ -586,7 +604,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { aiVector3D *positionDiff = nullptr; target.position[0]->ExtractData(positionDiff); for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { - aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId]; + aiAnimMesh.mVertices[vertexId] = positionDiff[vertexId]; } delete[] positionDiff; } @@ -598,7 +616,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { aiVector3D *normalDiff = nullptr; target.normal[0]->ExtractData(normalDiff); for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { - aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId]; + aiAnimMesh.mNormals[vertexId] = normalDiff[vertexId]; } delete[] normalDiff; } @@ -617,7 +635,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { target.tangent[0]->ExtractData(tangentDiff); for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) { - tangent[vertexId].xyz += tangentDiff[vertexId]; + tangent[vertexId].xyz = tangentDiff[vertexId]; aiAnimMesh.mTangents[vertexId] = tangent[vertexId].xyz; aiAnimMesh.mBitangents[vertexId] = (aiAnimMesh.mNormals[vertexId] ^ tangent[vertexId].xyz) * tangent[vertexId].w; } @@ -817,6 +835,15 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { } else { aim->mMaterialIndex = mScene->mNumMaterials - 1; } + + for (unsigned int i = 0; i < r.materials.Size(); ++i) { + glTF2::Ref m2 = r.materials.Retrieve(i); + + if (m2.GetIndex() == prim.material.GetIndex()) { + aim->mMaterialIndex = i; + break; + } + } } } @@ -1211,7 +1238,7 @@ void glTF2Importer::ImportNodes(glTF2::Asset &r) { if (numRootNodes == 1) { // a single root node: use it mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]); } else if (numRootNodes > 1) { // more than one root node: create a fake root - aiNode *root = mScene->mRootNode = new aiNode("ROOT"); + aiNode *root = mScene->mRootNode = new aiNode("__ROOT"); root->mChildren = new aiNode *[numRootNodes]; std::fill(root->mChildren, root->mChildren + numRootNodes, nullptr); @@ -1561,6 +1588,8 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) { aiTexture *tex = mScene->mTextures[idx] = new aiTexture(); + tex->mFilename = img.uri; + size_t length = img.GetDataLength(); void *data = img.StealData(); @@ -1624,7 +1653,8 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO // read the asset file glTF2::Asset asset(pIOHandler, static_cast(mSchemaDocumentProvider)); - asset.Load(pFile, GetExtension(pFile) == "glb"); + //asset.Load(pFile, GetExtension(pFile) == "glb"); + asset.Load(pFile, GetExtension(pFile) == "glb" || GetExtension(pFile) == "vrm"); if (asset.scene) { pScene->mName = asset.scene->name; } @@ -1642,6 +1672,36 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO ImportAnimations(asset); + { + this->mScene->mVRMMeta = asset.vrmdata.vrmdata->CreateClone(); + auto m = static_cast(mScene->mVRMMeta); + + for (int i = 0; i < m->materialNum; ++i) { + auto& a = m->material[i].textureProperties; + + struct TT { + int& value; + }; + TT table[] = { + {a._MainTex}, + {a._ShadeTexture}, + {a._BumpMap}, + {a._ReceiveShadowTexture}, + {a._ShadingGradeTexture}, + {a._RimTexture}, + {a._SphereAdd}, + {a._EmissionMap}, + {a._OutlineWidthTexture}, + {a._UvAnimMaskTexture}, + }; + + for (auto& t : table) { + if (t.value < 0) continue; + t.value = mEmbeddedTexIdxs[t.value]; + } + } + } + ImportCommonMetadata(asset); if (pScene->mNumMeshes == 0) { diff --git a/code/Common/Version.cpp b/code/Common/Version.cpp index 808c3598d1..5d12fc0c5e 100644 --- a/code/Common/Version.cpp +++ b/code/Common/Version.cpp @@ -138,6 +138,7 @@ ASSIMP_API aiScene::aiScene() : mName(), mNumSkeletons(0), mSkeletons(nullptr), + mVRMMeta(nullptr), mPrivate(new Assimp::ScenePrivateData()) { // empty } @@ -186,5 +187,14 @@ ASSIMP_API aiScene::~aiScene() { delete[] mSkeletons; + mMetaData = nullptr; + if (mVRMMeta) { + extern void VRM_ReleaseVRMMeta(void* p); + VRM_ReleaseVRMMeta(mVRMMeta); + + mVRMMeta = nullptr; + } + + delete static_cast(mPrivate); } diff --git a/code/PostProcessing/ConvertToLHProcess.cpp b/code/PostProcessing/ConvertToLHProcess.cpp index 359c5a284c..4bf02fa6c7 100644 --- a/code/PostProcessing/ConvertToLHProcess.cpp +++ b/code/PostProcessing/ConvertToLHProcess.cpp @@ -167,6 +167,7 @@ void MakeLeftHandedProcess::ProcessMesh(aiMesh *pMesh) { // mirror anim meshes positions, normals and stuff along the Z axis for (size_t m = 0; m < pMesh->mNumAnimMeshes; ++m) { + if (pMesh->mAnimMeshes[m]->mVertices == nullptr) break; for (size_t a = 0; a < pMesh->mAnimMeshes[m]->mNumVertices; ++a) { pMesh->mAnimMeshes[m]->mVertices[a].z *= -1.0f; if (pMesh->mAnimMeshes[m]->HasNormals()) { diff --git a/include/assimp/material.h b/include/assimp/material.h index 0052888d11..2074cbe866 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -933,6 +933,8 @@ struct aiMaterial /** Storage allocated */ unsigned int mNumAllocated; + + C_STRUCT aiString mShaderName; }; // Go back to extern "C" again diff --git a/include/assimp/scene.h b/include/assimp/scene.h index f6dfd82b06..b16adacb3c 100644 --- a/include/assimp/scene.h +++ b/include/assimp/scene.h @@ -352,6 +352,8 @@ struct aiScene */ C_STRUCT aiSkeleton **mSkeletons; + void* mVRMMeta; + #ifdef __cplusplus //! Default constructor - set everything to 0/nullptr diff --git a/include/assimp/vrm/vrmmeta.h b/include/assimp/vrm/vrmmeta.h new file mode 100644 index 0000000000..8b42ff2093 --- /dev/null +++ b/include/assimp/vrm/vrmmeta.h @@ -0,0 +1,322 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#pragma pack(1) + +#ifdef __cplusplus +extern "C" { +#endif + + namespace VRM { + typedef float(vec3)[3]; + typedef float(vec4)[4]; + + struct ASSIMP_API VRMBlendShapeBind { + aiString blendShapeName; + aiString nodeName; + aiString meshName; + int meshID=0; + int shapeIndex=0; + int weight=100; + }; + + struct ASSIMP_API VRMBlendShapeGroup { + aiString groupName; + + int bindNum=0; + VRMBlendShapeBind *bind = nullptr; + + ~VRMBlendShapeGroup() { + delete[] bind; + } + + void CopyFrom(const VRMBlendShapeGroup &src){ + groupName = src.groupName; + + bindNum = src.bindNum; + bind = new VRMBlendShapeBind[bindNum]; + for (int i=0; ilicense.CopyFrom(license); + + p->springNum = springNum; + p->springs = new VRMSpring[springNum]; + for (int i=0;isprings[i].CopyFrom(springs[i]); + } + + p->colliderGroupNum = colliderGroupNum; + p->colliderGroups = new VRMColliderGroup[colliderGroupNum]; + for (int i=0; icolliderGroups[i].CopyFrom(colliderGroups[i]); + } + + for (int i=0; ihumanoidBone[i] = humanoidBone[i]; + } + + p->blensShapeGroupNum = blensShapeGroupNum; + p->blensShapeGourp = new VRMBlendShapeGroup[blensShapeGroupNum]; + for (int i = 0; i < blensShapeGroupNum; ++i) { + p->blensShapeGourp[i].CopyFrom(blensShapeGourp[i]); + } + + + p->materialNum = materialNum; + p->material = new VRMMaterial[materialNum]; + for (int i = 0; i < materialNum; ++i) { + p->material[i].CopyFrom(material[i]); + } + + + return p; + } + + }; + + void ReleaseVRMMeta(VRMMetadata *&meta); + } + +#ifdef __cplusplus +} +#endif + +#pragma pack() +