diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d3f8a0..7516e55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,7 @@ add_subdirectory(src/sceneloader) add_subdirectory(audio/gui) add_subdirectory(tests) add_subdirectory(lua-scripts) +add_subdirectory(morph) # add the source files as usual add_executable(0_Bootstrap Bootstrap.cpp) @@ -332,6 +333,22 @@ list(APPEND EDITED_BLEND_TARGETS ${CMAKE_BINARY_DIR}/assets/blender/edited-norma list(APPEND CHARACTER_GLBS ${CMAKE_BINARY_DIR}/characters/${EDITED_BLEND}/normal-${EDITED_BLEND}.glb) endforeach() +add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/characters/shapes/male/chibi/vroid-normal-male-chibi.glb +DEPENDS ${CMAKE_BINARY_DIR}/assets/blender/characters/shapes/male/chibi/vroid-normal-male-chibi.glb +COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/assets/blender/characters/shapes/male/chibi/vroid-normal-male-chibi.glb + ${CMAKE_BINARY_DIR}/characters/shapes/male/chibi/vroid-normal-male-chibi.glb) +add_custom_target(morph ALL DEPENDS MorphTargetsResearch ${CMAKE_BINARY_DIR}/characters/shapes/male/chibi/vroid-normal-male-chibi.glb) + +set(COPY_BLENDS edited-shape-test-male.blend) +foreach (COPY_BLEND_FILE ${COPY_BLENDS}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/assets/blender/${COPY_BLEND_FILE} + DEPENDS ${CMAKE_SOURCE_DIR}/assets/blender/${COPY_BLEND_FILE} + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_SOURCE_DIR}/assets/blender/${COPY_BLEND_FILE} + ${CMAKE_BINARY_DIR}/assets/blender/${COPY_BLEND_FILE}) + list(APPEND EDITED_BLEND_TARGETS ${CMAKE_BINARY_DIR}/assets/blender/${COPY_BLEND_FILE}) +endforeach() + add_custom_target(edited-blends ALL DEPENDS ${EDITED_BLEND_TARGETS}) add_custom_command( diff --git a/assets/blender/edited-normal-female.blend b/assets/blender/edited-normal-female.blend index 1dc5dfe..7a707f0 100644 --- a/assets/blender/edited-normal-female.blend +++ b/assets/blender/edited-normal-female.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0011c2f09089497cd7ab75535e4bcf0bd04f729de36efe118cc50e3d233b7463 -size 16951489 +oid sha256:1f60c4577edc6a71d2af6e1f07099a4a63cafcc2fb2ecb2557c04a2cfe1834b7 +size 17003087 diff --git a/assets/blender/edited-normal-male.blend b/assets/blender/edited-normal-male.blend index e6758f4..0bf9f95 100644 --- a/assets/blender/edited-normal-male.blend +++ b/assets/blender/edited-normal-male.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:98e8b9e8af77703eca5e2ee483e8a6e12ac62c59223754cf7383cd99e1300771 -size 12965958 +oid sha256:bbebb7cddd3cbe0d3511b5a11de75ee3ec7c004cb42212e8df883f25f0e405ab +size 13010776 diff --git a/assets/blender/edited-shape-test-male.blend b/assets/blender/edited-shape-test-male.blend new file mode 100644 index 0000000..9c2fd1d --- /dev/null +++ b/assets/blender/edited-shape-test-male.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:88ee6f04ae3c19e1e3c128caafae86c08032ece391732efbeedcee663956a903 +size 10310071 diff --git a/assets/blender/scripts/export_models.py b/assets/blender/scripts/export_models.py index fb67458..bd2fa4f 100644 --- a/assets/blender/scripts/export_models.py +++ b/assets/blender/scripts/export_models.py @@ -9,7 +9,7 @@ from mathutils import Vector, Matrix from math import radians, pi sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) -from settings import ExportMappingFemale, ExportMappingMale, ExportMappingMaleBabyShape, ExportMappingMaleEdited, ExportMappingFemaleEdited +from settings import ExportMappingFemale, ExportMappingMale, ExportMappingMaleBabyShape, ExportMappingMaleEdited, ExportMappingFemaleEdited, ExportMappingMaleTestShapeEdited basepath = os.getcwd() def check_bone(bname): @@ -179,7 +179,7 @@ def extra_linear(angle, offset): ret += offt return ret -for mapping in [ExportMappingFemale(), ExportMappingMale(), ExportMappingMaleBabyShape(), ExportMappingMaleEdited(), ExportMappingFemaleEdited()]: +for mapping in [ExportMappingFemale(), ExportMappingMale(), ExportMappingMaleBabyShape(), ExportMappingMaleEdited(), ExportMappingFemaleEdited(), ExportMappingMaleTestShapeEdited()]: if not os.path.exists(mapping.blend_path): print("Skipping mapping: " + mapping.blend_path) continue diff --git a/assets/blender/scripts/settings.py b/assets/blender/scripts/settings.py index 6ab3e01..aede80d 100644 --- a/assets/blender/scripts/settings.py +++ b/assets/blender/scripts/settings.py @@ -110,3 +110,17 @@ class ExportMappingMaleBabyShape: for fobj in self.objs: self.files.append({"name": fobj}) +class ExportMappingMaleTestShapeEdited: + blend_path = "assets/blender/" + "edited-shape-test-male.blend" + gltf_path = "characters/shapes/male/edited-shape-test-male.gltf" + ogre_scene = "characters/shapes/male/chibi/vroid-normal-male-chibi.scene" + inner_path = "Object" + objs = ["male", "Body"] + armature_name = "male" + outfile = "tmp-male-chibi.blend" + default_action = 'default' + def __init__(self): + self.files = [] + for fobj in self.objs: + self.files.append({"name": fobj}) + diff --git a/assets/blender/vehicles/boat-big.blend b/assets/blender/vehicles/boat-big.blend new file mode 100644 index 0000000..90a7604 --- /dev/null +++ b/assets/blender/vehicles/boat-big.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff559da43b9e80e50d7193b9635a683768678c45c1313f5e05183e56e3de0fd8 +size 549955 diff --git a/assets/blender/vehicles/boat.blend b/assets/blender/vehicles/boat.blend index 90a7604..6f6cfc4 100644 --- a/assets/blender/vehicles/boat.blend +++ b/assets/blender/vehicles/boat.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff559da43b9e80e50d7193b9635a683768678c45c1313f5e05183e56e3de0fd8 -size 549955 +oid sha256:33d176f38c29464ae86b769452cee751ee0b565f22ee190aa2c135ba0232ea6a +size 514500 diff --git a/lua-scripts/data.lua b/lua-scripts/data.lua index 6a5544b..19644f1 100644 --- a/lua-scripts/data.lua +++ b/lua-scripts/data.lua @@ -228,7 +228,7 @@ function StartGameQuest() quest.activate = function(this) print('activate...') local mc_is_free = function() - this.boat_id = ecs_vehicle_set("raft", 0, 0, -10, 1.75) + this.boat_id = ecs_vehicle_set("boat", 0, 0, -10, 1.75) this.npc_id = ecs_npc_set("normal-female.glb", 0, 2, -10, 1.75) this.boat = true -- ecs_set_slot(this.boat_id, this.npc_id, "captain_seat") diff --git a/morph/CMakeLists.txt b/morph/CMakeLists.txt new file mode 100644 index 0000000..4f53d75 --- /dev/null +++ b/morph/CMakeLists.txt @@ -0,0 +1,9 @@ +project(morph) +add_executable(MorphTargetsResearch MorphTargetsResearch.cpp) +target_link_libraries(MorphTargetsResearch OgreBites OgreBullet OgrePaging ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY} ${ASSIMP_LIBRARIES} + -Wl,--as-needed + ) +if(OGRE_STATIC) +target_link_options(MorphTargetsResearch PRIVATE -static-libstdc++ -static-libgcc) +endif() +add_dependencies(MorphTargetsResearch stage_files import_vrm) \ No newline at end of file diff --git a/morph/MorphTargetsResearch.cpp b/morph/MorphTargetsResearch.cpp new file mode 100644 index 0000000..c99db2d --- /dev/null +++ b/morph/MorphTargetsResearch.cpp @@ -0,0 +1,641 @@ +#include +#include +#include + +class App; + +static void getSubmeshNormals(const Ogre::Mesh *mesh, + const Ogre::SubMesh *submesh, + std::vector &normals) +{ + int j; + float *pReal; + int vertex_count = 0; + if (submesh->useSharedVertices) + vertex_count += mesh->sharedVertexData->vertexCount; + else + vertex_count += submesh->vertexData->vertexCount; + Ogre::HardwareVertexBufferSharedPtr vbuf; + Ogre::VertexData *vertex_data = submesh->useSharedVertices ? + mesh->sharedVertexData : + submesh->vertexData; + const Ogre::VertexElement *normalsElem = + vertex_data->vertexDeclaration->findElementBySemantic( + Ogre::VES_NORMAL); + if (!normalsElem) + return; + OgreAssert(normals.size() == 0 || normals.size() == vertex_count, + "bad vertex count"); + normals.resize(vertex_count); + vbuf = vertex_data->vertexBufferBinding->getBuffer( + normalsElem->getSource()); + unsigned char *vertex = static_cast( + vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); + for (j = 0; j < vertex_data->vertexCount; + ++j, vertex += vbuf->getVertexSize()) { + normalsElem->baseVertexPointerToElement(vertex, &pReal); + normals[j] = Ogre::Vector3(pReal[0], pReal[1], pReal[2]); + } + vbuf->unlock(); +} +static void getSubmeshUVs(const Ogre::Mesh *mesh, const Ogre::SubMesh *submesh, + std::vector &uvs, int index) +{ + int j; + float *pReal; + Ogre::HardwareVertexBufferSharedPtr vbuf; + Ogre::VertexData *vertex_data = submesh->useSharedVertices ? + mesh->sharedVertexData : + submesh->vertexData; + const Ogre::VertexElement *uvElem = + vertex_data->vertexDeclaration->findElementBySemantic( + Ogre::VES_TEXTURE_COORDINATES, index); + int vertex_count = 0; + if (submesh->useSharedVertices) + vertex_count += mesh->sharedVertexData->vertexCount; + else + vertex_count += submesh->vertexData->vertexCount; + if (!uvElem) + return; + OgreAssert(uvs.size() == 0 || uvs.size() == vertex_count, + "bad vertex count"); + uvs.resize(vertex_count); + vbuf = vertex_data->vertexBufferBinding->getBuffer(uvElem->getSource()); + unsigned char *uv = static_cast( + vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); + for (j = 0; j < vertex_data->vertexCount; ++j) { + uvElem->baseVertexPointerToElement(uv, &pReal); + uvs[j] = Ogre::Vector2(pReal[0], pReal[1]); + uv += vbuf->getVertexSize(); + } + vbuf->unlock(); +} +static void getSubmeshVertices(const Ogre::Mesh *mesh, + const Ogre::SubMesh *submesh, + std::vector &vertices) +{ + int j; + float *pReal; + int vertex_count = 0; + if (submesh->useSharedVertices) + vertex_count += mesh->sharedVertexData->vertexCount; + else + vertex_count += submesh->vertexData->vertexCount; + Ogre::HardwareVertexBufferSharedPtr vbuf; + Ogre::VertexData *vertex_data = submesh->useSharedVertices ? + mesh->sharedVertexData : + submesh->vertexData; + const Ogre::VertexElement *posElem = + vertex_data->vertexDeclaration->findElementBySemantic( + Ogre::VES_POSITION); + if (!posElem) + return; + OgreAssert(vertices.size() == 0 || vertices.size() == vertex_count, + "bad vertex count"); + vertices.resize(vertex_count); + vbuf = vertex_data->vertexBufferBinding->getBuffer( + posElem->getSource()); + unsigned char *vertex = static_cast( + vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); + for (j = 0; j < vertex_data->vertexCount; + ++j, vertex += vbuf->getVertexSize()) { + posElem->baseVertexPointerToElement(vertex, &pReal); + vertices[j] = Ogre::Vector3(pReal[0], pReal[1], pReal[2]); + } + vbuf->unlock(); +} +static void getSubmeshIndices(const Ogre::Mesh *mesh, + const Ogre::SubMesh *submesh, + std::vector &indices) +{ + int index_count = 0; + index_count += submesh->indexData->indexCount; + int index_offset = 0; + indices.resize(index_count); + Ogre::IndexData *index_data = submesh->indexData; + size_t numTris = index_data->indexCount / 3; + Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer; + + bool use32bitindexes = + (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT); + + unsigned long *pLong = static_cast( + ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); + unsigned short *pShort = reinterpret_cast(pLong); + + size_t offset = 0; + + if (use32bitindexes) { + for (size_t k = 0; k < numTris * 3; ++k) { + indices[index_offset++] = + pLong[k] + static_cast(offset); + } + } else { + for (size_t k = 0; k < numTris * 3; ++k) { + indices[index_offset++] = + static_cast(pShort[k]) + + static_cast(offset); + } + } + + ibuf->unlock(); +} +struct SubMeshInformation { + Ogre::String materialName; + bool sharedVertices; + std::vector vertices; + std::vector normals; + std::vector uvs; + std::vector uv2s; + std::vector indices; + Ogre::SubMesh::LODFaceList lodFaceList; + Ogre::Mesh::VertexBoneAssignmentList boneList; + void createSubmesh(Ogre::Mesh *mesh) + { + int i; + Ogre::SubMesh *out = mesh->createSubMesh(); + out->useSharedVertices = false; + out->vertexData = new Ogre::VertexData(); + size_t currOffset = 0; + Ogre::VertexDeclaration *vertexDecl = + out->vertexData->vertexDeclaration; + vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, + Ogre::VES_POSITION); + currOffset += + Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); + vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, + Ogre::VES_NORMAL); + currOffset += + Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); + vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT2, + Ogre::VES_TEXTURE_COORDINATES, 0); + currOffset += + Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + out->vertexData->vertexCount = vertices.size(); + Ogre::HardwareVertexBufferSharedPtr vbuf = + Ogre::HardwareBufferManager::getSingleton() + .createVertexBuffer( + vertexDecl->getVertexSize(0), + out->vertexData->vertexCount, + Ogre::HardwareBuffer:: + HBU_STATIC_WRITE_ONLY, // only GPU side + false); + Ogre::VertexBufferBinding *binding = + out->vertexData->vertexBufferBinding; + binding->setBinding(0, vbuf); + float *pvertex = static_cast( + vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD)); + out->indexData->indexCount = indices.size(); + out->indexData->indexBuffer = + Ogre::HardwareBufferManager::getSingleton().createIndexBuffer( + vertices.size() < 32768 ? + Ogre::HardwareIndexBuffer::IT_16BIT : + Ogre::HardwareIndexBuffer::IT_32BIT, + out->indexData->indexCount, + Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, + false); + OgreAssert(normals.size() == vertices.size(), "bad normals"); + for (i = 0; i < vertices.size(); i++) { + *pvertex++ = vertices[i].x; + *pvertex++ = vertices[i].y; + *pvertex++ = vertices[i].z; + if (normals.size() > 0) { + *pvertex++ = normals[i].x; + *pvertex++ = normals[i].y; + *pvertex++ = normals[i].z; + } else { + *pvertex++ = 0.0f; + *pvertex++ = 1.0f; + *pvertex++ = 0.0f; + } + if (uvs.size() > 0) { + *pvertex++ = uvs[i].x; + *pvertex++ = uvs[i].y; + } else { + *pvertex++ = 0.0f; + *pvertex++ = 1.0f; + } + } + vbuf->unlock(); + Ogre::HardwareIndexBufferSharedPtr ibuf = + out->indexData->indexBuffer; + if (vertices.size() < 32768) { + unsigned short *pindices = + static_cast(ibuf->lock( + Ogre::HardwareBuffer::HBL_DISCARD)); + for (i = 0; i < indices.size(); i++) + *pindices++ = (unsigned short)indices[i]; + ibuf->unlock(); + } else { + unsigned long *pindices = static_cast( + ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD)); + for (i = 0; i < indices.size(); i++) + *pindices++ = indices[i]; + ibuf->unlock(); + } + out->clearBoneAssignments(); + auto vbass_it = boneList.begin(); + while (vbass_it != boneList.end()) { + out->addBoneAssignment(vbass_it->second); + vbass_it++; + } + out->setMaterialName(materialName); + } +}; + +static void getSubMeshInformation(const Ogre::Mesh *mesh, + const Ogre::SubMesh *submesh, + struct SubMeshInformation *info) +{ + info->materialName = submesh->getMaterialName(); + info->sharedVertices = submesh->useSharedVertices; + info->lodFaceList = submesh->mLodFaceList; + info->boneList = submesh->getBoneAssignments(); + getSubmeshIndices(mesh, submesh, info->indices); + getSubmeshVertices(mesh, submesh, info->vertices); + getSubmeshNormals(mesh, submesh, info->normals); + getSubmeshUVs(mesh, submesh, info->uvs, 0); + getSubmeshUVs(mesh, submesh, info->uv2s, 1); +} + +struct MeshInformation { + struct MeshMorphTarget { + Ogre::SkeletonPtr skelp; + struct DataChange { + int index; + int submesh; + Ogre::Vector3 vertex; + Ogre::Vector3 normal; + }; + std::vector vertices; + float weight; + }; + std::map targets; + std::vector submesh; + Ogre::SkeletonPtr skelp; + Ogre::String skelName; + MeshInformation(Ogre::Mesh *prototype) + { + int i; + skelName = prototype->getSkeletonName(); + skelp = Ogre::SkeletonManager::getSingleton().getByName( + prototype->getSkeletonName(), "Characters"); + OgreAssert(skelp, "Could not load skeleton " + + prototype->getSkeletonName()); + submesh.resize(prototype->getNumSubMeshes()); + for (i = 0; i < submesh.size(); i++) { + getSubMeshInformation(prototype, + prototype->getSubMesh(i), + &submesh[i]); + std::cout << i << " " << "mesh material name: " + << submesh[i].materialName << std::endl; + std::cout << i << " " + << "shared: " << submesh[i].sharedVertices + << std::endl; + std::cout << i << " " << "vertex_count: " + << submesh[i].vertices.size() << std::endl; + std::cout << i << " " << "index_count: " + << submesh[i].indices.size() << std::endl; + } + } + Ogre::MeshPtr create(const Ogre::String &meshName) + { + int j; + Ogre::MeshPtr baseMesh = + Ogre::MeshManager::getSingleton().createManual( + meshName, Ogre::ResourceGroupManager:: + DEFAULT_RESOURCE_GROUP_NAME); + applyMorphTargets(); + for (j = 0; j < submesh.size(); j++) + submesh[j].createSubmesh(baseMesh.get()); + //define a extreme boundary values + Ogre::Real max_x = -1e+8; + Ogre::Real min_x = 1e+8; + Ogre::Real max_y = -1e+8; + Ogre::Real min_y = 1e+8; + Ogre::Real max_z = -1e+8; + Ogre::Real min_z = +1e+8; + // Setting bounding box + Ogre::Mesh::SubMeshList mlist = baseMesh->getSubMeshes(); + for (j = 0; j < mlist.size(); j++) { + Ogre::SubMesh *in = mlist[j]; + Ogre::VertexData *vertex_data = in->vertexData; + const Ogre::VertexElement *posElem = + vertex_data->vertexDeclaration + ->findElementBySemantic( + Ogre::VES_POSITION); + Ogre::HardwareVertexBufferSharedPtr hwvb = + in->vertexData->vertexBufferBinding->getBuffer( + posElem->getSource()); + unsigned char *hbuff = + static_cast(hwvb->lock( + Ogre::HardwareBuffer::HBL_READ_ONLY)); + Ogre::Real *pValue; + Ogre::Real value; + + for (size_t idx = 0; idx < vertex_data->vertexCount; + ++idx, hbuff += hwvb->getVertexSize()) { + posElem->baseVertexPointerToElement(hbuff, + &pValue); + value = (*pValue++); + if (value > max_x) + max_x = value; + if (value < min_x) + min_x = value; + value = (*pValue++); + + if (value > max_y) + max_y = value; + if (value < min_y) + min_y = value; + value = (*pValue++); + + if (value > max_z) + max_z = value; + if (value < min_z) + min_z = value; + } + hwvb->unlock(); + } + baseMesh->setSkeletonName(skelName); + baseMesh->_setBounds(Ogre::AxisAlignedBox(min_x, min_y, min_z, + max_x, max_y, max_z)); + return baseMesh; + } + void createTarget(const Ogre::String &targetName, + const Ogre::Mesh *target) + { + MeshMorphTarget mtarget; + int i, j, k, l; + std::vector targetInfo; + mtarget.skelp = Ogre::SkeletonManager::getSingleton().getByName( + target->getSkeletonName(), "Characters"); + targetInfo.resize(target->getNumSubMeshes()); + for (i = 0; i < target->getNumSubMeshes(); i++) { + getSubMeshInformation(target, target->getSubMesh(i), + &targetInfo[i]); + } + std::vector vertices; + std::vector normals; + std::vector uvs; + std::vector uv_submeshes; + std::vector uv_indices; + std::vector change_uvs; + std::vector changes; + for (i = 0; i < targetInfo.size(); i++) { + const std::vector &puv = + targetInfo[i].uvs; + const std::vector &pvertices = + targetInfo[i].vertices; + const std::vector &pnormals = + targetInfo[i].normals; + for (j = 0; j < pvertices.size(); j++) { + MeshMorphTarget::DataChange dc; + dc.index = -1; + dc.submesh = -1; + change_uvs.push_back(puv[j]); + dc.normal = pnormals[j]; + dc.vertex = pvertices[j]; + changes.push_back(dc); + } + } + for (i = 0; i < submesh.size(); i++) { + int submesh_id = i; + for (j = 0; j < submesh[i].vertices.size(); j++) { + int index_id = j; + const Ogre::Vector2 &xuv = submesh[i].uvs[j]; + uvs.push_back(xuv); + uv_submeshes.push_back(submesh_id); + uv_indices.push_back(index_id); + } + } + for (i = 0; i < changes.size(); i++) { + float l = 1.0f; + int sub = -1, index = -1; + for (j = 0; j < uvs.size(); j++) { + float xl = + change_uvs[i].squaredDistance(uvs[j]); + if (xl < l) { + l = xl; + sub = uv_submeshes[j]; + index = uv_indices[j]; + } + } + OgreAssert(sub >= 0 && index >= 0, "Indexing error"); + if (l < 0.000000005f) { + changes[i].submesh = sub; + changes[i].index = index; + } + } + mtarget.vertices = changes; + + mtarget.weight = 0.0f; + targets[targetName] = mtarget; + } + void setTargetWeight(const Ogre::String &targetName, float weight) + { + if (targets.find(targetName) == targets.end()) + return; + targets[targetName].weight = weight; + } + void applyMorphTargets() + { + auto it = targets.begin(); + float sum = 0.0f; + while (it != targets.end()) { + sum += it->second.weight; + it++; + } + if (sum > 1.0f) { + it = targets.begin(); + while (it != targets.end()) { + it->second.weight = it->second.weight / sum; + it++; + } + } + it = targets.begin(); + while (it != targets.end()) { + if (it->second.weight > 0.001f) { + int i; + for (i = 0; i < it->second.vertices.size(); + i++) { + int sub_id = + it->second.vertices[i].submesh; + int index_id = + it->second.vertices[i].index; + if (sub_id < 0 || index_id < 0) + continue; + Ogre::Vector3 orig_vertex = + submesh[sub_id] + .vertices[index_id]; + Ogre::Vector3 new_vertex = + it->second.vertices[i].vertex; + Ogre::Vector3 vertex_update = + Ogre::Math::lerp( + orig_vertex, new_vertex, + it->second.weight); + Ogre::Vector3 orig_normal = + submesh[sub_id] + .normals[index_id]; + Ogre::Vector3 new_normal = + it->second.vertices[i].normal; + Ogre::Vector3 normal_update = + Ogre::Math::lerp( + orig_normal, new_normal, + it->second.weight); + submesh[sub_id].vertices[index_id] = + vertex_update; + submesh[sub_id].normals[index_id] = + normal_update; + } + } + it++; + } + } +}; + +struct SimpleListener : public OgreBites::InputListener { + App *mApp; + SimpleListener(App *app) + : mApp(app) + { + } + void frameRendered(const Ogre::FrameEvent &evt) override; +}; + +class App : public OgreBites::ApplicationContext { +public: + App() + : OgreBites::ApplicationContext("MorphTargetsResearch") + { + } + void locateResources() override + { + Ogre::ResourceGroupManager::getSingleton().createResourceGroup( + "Characters", true); + Ogre::ResourceGroupManager::getSingleton().addResourceLocation( + "./characters", "FileSystem", "Characters", true, true); + Ogre::ResourceGroupManager::getSingleton().addResourceLocation( + "../characters", "FileSystem", "Characters", true, + true); + OgreBites::ApplicationContext::locateResources(); + } + void loadResources() override + { + } + void meshProcessing() + { + int i; + //code to test and create entity based off of sub-meshes + + //vector of meshes + std::vector m_Meshes; + + //define meshes + Ogre::MeshPtr base = Ogre::MeshManager::getSingleton().load( + "male/normal-male.glb", "Characters"); + m_Meshes.push_back(base); + Ogre::MeshPtr shape = Ogre::MeshManager::getSingleton().load( + "shapes/male/edited-shape-test-male.glb", "Characters"); + OgreAssert(shape, "no shape"); + MeshInformation meshinfo(base.get()); + std::string m_ModelId = "MergedMesh"; + meshinfo.createTarget("shape", shape.get()); + meshinfo.setTargetWeight("shape", 1.0f); + Ogre::MeshPtr m_BaseMesh = meshinfo.create(m_ModelId); + Ogre::Entity *ent = + mScnMgr->createEntity("entName", m_BaseMesh->getName()); + // ent->setMaterialName("TestMat"); + + //code here is temporary and only ment as a test for the modelers + //Entity* testEntity = mSceneMgr->createEntity("cc", source->getName()); + //testEntity->setMaterialName("TestMat"); + Ogre::SceneNode *thisSceneNode = + mScnMgr->getRootSceneNode()->createChildSceneNode(); + // thisSceneNode->setPosition(100, 100, 100); + thisSceneNode->attachObject(ent); + mIdle = ent->getAnimationState("idle"); + mIdle->setEnabled(true); + mIdle->setLoop(true); + mIdle->setWeight(1.0f); + } + + void setup() override + { + OgreBites::ApplicationContext::setup(); + Ogre::Root *root = getRoot(); + Ogre::SceneManager *scnMgr = root->createSceneManager(); + Ogre::RTShader::ShaderGenerator *shadergen = + Ogre::RTShader::ShaderGenerator::getSingletonPtr(); + shadergen->addSceneManager(scnMgr); + // also need to tell where we are + mScnMgr.reset(scnMgr); + mCameraNode.reset( + mScnMgr->getRootSceneNode()->createChildSceneNode()); + mCameraNode->setPosition(0, 2, 3); + mCameraNode->lookAt(Ogre::Vector3(0, 1, -1), + Ogre::Node::TS_PARENT); + + Ogre::Light *light = mScnMgr->createLight("MainLight"); + Ogre::SceneNode *lightNode = + mScnMgr->getRootSceneNode()->createChildSceneNode(); + // lightNode->setPosition(0, 10, 15); + lightNode->setDirection( + Ogre::Vector3(0.55, -0.3, 0.75).normalisedCopy()); + lightNode->attachObject(light); + light->setType(Ogre::Light::LT_DIRECTIONAL); + light->setDiffuseColour(Ogre::ColourValue::White); + light->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4)); + + mScnMgr->setAmbientLight( + Ogre::ColourValue(0.5f, 0.5f, 0.5f, 1.0f)); + + // create the camera + Ogre::Camera *cam = mScnMgr->createCamera("normal_camera"); + cam->setNearClipDistance(0.1f); // specific to this sample + cam->setAutoAspectRatio(true); + mCameraNode->attachObject(cam); + mCamera.reset(cam); + + // and tell it to render into the main window + getRenderWindow()->addViewport(cam); + meshProcessing(); +#if 0 + Ogre::Entity *ent_base = + mScnMgr->createEntity("male/normal-male.glb"); + Ogre::Entity *ent_shape = mScnMgr->createEntity( + "shapes/male/chibi/vroid-normal-male-chibi.glb"); + Ogre::SceneNode *characterNode = + mScnMgr->getRootSceneNode()->createChildSceneNode("ch"); + characterNode->attachObject(ent_base); +#endif + addInputListener(OGRE_NEW SimpleListener(this)); + } + void animationTime(float time) + { + mIdle->addTime(time); + } + +private: + std::unique_ptr mCameraNode; + std::unique_ptr mCamera; + std::unique_ptr mScnMgr; + Ogre::AnimationState *mIdle; +}; + +int main(int argc, char *argv[]) +{ + App ctx; + ctx.initApp(); + ctx.setWindowGrab(true); + + ctx.getRoot()->startRendering(); + ctx.setWindowGrab(false); + ctx.closeApp(); + return 0; +} + +void SimpleListener::frameRendered(const Ogre::FrameEvent &evt) +{ + mApp->animationTime(evt.timeSinceLastFrame); +} diff --git a/src/gamedata/BoatModule.cpp b/src/gamedata/BoatModule.cpp index 2c7b150..6010fc9 100644 --- a/src/gamedata/BoatModule.cpp +++ b/src/gamedata/BoatModule.cpp @@ -89,7 +89,7 @@ BoatModule::BoatModule(flecs::world &ecs) ECS::get() .mWorld->addRigidBody( 0, boat.mEnt, - Ogre::Bullet::CT_BOX, + Ogre::Bullet::CT_HULL, nullptr, 2, 0x7fffffff); b2e.entities[body.body] = e; std::vector slots = diff --git a/src/gamedata/CharacterAnimationModule.cpp b/src/gamedata/CharacterAnimationModule.cpp index 17fbc52..ccf9cec 100644 --- a/src/gamedata/CharacterAnimationModule.cpp +++ b/src/gamedata/CharacterAnimationModule.cpp @@ -203,17 +203,40 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs) Ogre::Quaternion rot = ch.mBodyNode->getOrientation(); Ogre::Vector3 pos = ch.mBodyNode->getPosition(); Ogre::Vector3 boneMotion = ch.mBoneMotion; - v.velocity = Ogre::Math::lerp( - v.velocity, rot * boneMotion / eng.delta, - 0.99f); + v.velocity = Ogre::Vector3::ZERO; + float safeDelta = + Ogre::Math::Clamp(eng.delta, 0.001f, 0.99f); +#if 0 + if (!e.has()) { + v.velocity = Ogre::Math::lerp( + v.velocity, + rot * boneMotion / safeDelta, 0.99f); + } else { + // v.velocity = rot * boneMotion / safeDelta; + v.velocity = Ogre::Math::lerp( + v.velocity, + rot * boneMotion / safeDelta, 0.99f); + } +#endif + v.velocity = rot * boneMotion / safeDelta; if (!e.has() && !e.has()) { if (eng.startupDelay <= 0.0f) v.velocity += v.gvelocity; - v.velocity.y = Ogre::Math::Clamp( - v.velocity.y, -10.5f, 1000000.0f); + v.velocity.y = Ogre::Math::Clamp(v.velocity.y, + -10.5f, 10.0f); } + // if (v.velocity.squaredLength() > 1.4f * 1.4f) + // v.velocity = v.velocity.normalisedCopy() * 1.4f; // ch.mBoneMotion = Ogre::Vector3::ZERO; + // safety + // std::cout << "velocity: " << v.velocity << std::endl; + v.velocity.x = + Ogre::Math::Clamp(v.velocity.x, -16.0f, 16.0f); + v.velocity.z = + Ogre::Math::Clamp(v.velocity.z, -16.0f, 16.0f); + v.velocity.y = + Ogre::Math::Clamp(v.velocity.y, -10.5f, 10.0f); }); ecs.system("HandleSwimming") @@ -258,6 +281,12 @@ CharacterAnimationModule::CharacterAnimationModule(flecs::world &ecs) if (body.mController) { Ogre::Vector3 rotMotion = v.velocity * eng.delta; + rotMotion.x = Ogre::Math::Clamp( + rotMotion.x, -0.04f, 0.04f); + rotMotion.y = Ogre::Math::Clamp( + rotMotion.y, -0.025f, 0.1f); + rotMotion.z = Ogre::Math::Clamp( + rotMotion.z, -0.04f, 0.04f); btVector3 currentPosition = body.mGhostObject ->getWorldTransform() diff --git a/src/gamedata/CharacterAnimationModule.h b/src/gamedata/CharacterAnimationModule.h index 185fc7a..435f4b6 100644 --- a/src/gamedata/CharacterAnimationModule.h +++ b/src/gamedata/CharacterAnimationModule.h @@ -165,76 +165,6 @@ struct Animation { kf->setRotation(Ogre::Quaternion::IDENTITY); } mRootTrack->setListener(mListener); -#if 0 - OgreAssert(mHipsTrack, "no hips track"); - OgreAssert(mRootTrack, "no Root track"); -#endif -#if 0 - if (mRootTrack) { - Ogre::Vector3 delta = Ogre::Vector3::ZERO; - Ogre::Vector3 motion = Ogre::Vector3::ZERO; - for (j = 0; j < mRootTrack->getNumKeyFrames(); j++) { - Ogre::Vector3 trans = - mRootTrack->getNodeKeyFrame(j) - ->getTranslate(); - if (j == 0) - delta = trans; - else - delta = trans - motion; - mRootTrack->getNodeKeyFrame(j)->setTranslate( - delta); - motion = trans; - } - } -#endif -#if 0 - if (!mMetaRootTrack) { - Ogre::Bone *bone = nullptr; - OgreAssert(skeleton->hasBone("MetaRoot"), - "no bone MetaRoot"); - if (skeleton->hasBone("MetaRoot")) - bone = skeleton->getBone("MetaRoot"); -#if 0 - else - bone = skeleton->createBone("MetaRoot"); -#endif - bone->setPosition(Ogre::Vector3::ZERO); - bone->setOrientation(Ogre::Quaternion::IDENTITY); - std::vector< - std::pair > > - keyframes; - for (j = 0; j < mRootTrack->getNumKeyFrames(); j++) { - Ogre::TransformKeyFrame *kf = - mRootTrack->getNodeKeyFrame(j); - const Ogre::Vector3 &pt = kf->getTranslate(); - const Ogre::Quaternion &rt = kf->getRotation(); - float tp = kf->getTime(); - keyframes.push_back({ tp, { pt, rt } }); -#if 0 - new_kf->setTranslate(pt); - new_kf->setTranslate(kf->getTranslate()); - new_kf->setRotation(kf->getRotation()); -#endif - kf->setTranslate(Ogre::Vector3::ZERO); - kf->setRotation(Ogre::Quaternion::IDENTITY); - } - mMetaRootTrack = mSkelAnimation->createNodeTrack( - bone->getHandle()); - OgreAssert(mMetaRootTrack, - "failed to create node track"); - for (j = 0; j < keyframes.size(); j++) { - Ogre::TransformKeyFrame *new_kf = - mMetaRootTrack->createNodeKeyFrame( - keyframes[j].first); - new_kf->setTranslate(keyframes[j].second.first); - new_kf->setRotation(keyframes[j].second.second); - } - } -#if 0 - mRootTrack = track; -#endif -#endif } Ogre::String getName() {