/* PMDModel::getBone: find bone data by name */ PMDBone *PMDModel::getBone(const char *name) { PMDBone *match = (PMDBone *) m_name2bone.findNearest(name); if (match && MMDFiles_strequal(match->getName(), name) == true) return match; else return NULL; }
/* MotionManager::startMotionSub: initialize a motion */ void MotionManager::startMotionSub(VMD * vmd, MotionPlayer * m) { btVector3 offset; PMDBone *centerBone; btTransform tr; btVector3 pos; btVector3 centerPos; btVector3 rootOffset; /* initialize and setup motion controller */ m->mc.setup(m_pmd, vmd); /* reset values */ m->mc.reset(); /* base motion does treat the bones with single motion frame at 0th frame as the same as normal bones */ m->mc.setIgnoreSingleMotion(m->ignoreStatic); /* reset work area */ m->vmd = vmd; m->active = true; m->endingBoneBlend = 0.0f; m->endingFaceBlend = 0.0f; /* when motion is changed, speed acceleration is turned off */ m->accelerationStatusFlag = ACCELERATION_STATUS_CONSTANT; /* set model offset */ if (m->enableSmooth) { offset.setZero(); if (m->mc.hasCenter() && m->enableRePos) { /* when the started motion has center motion, the center position of the model will be moved to the current position */ /* The current global position of the center bone will become the new offset of the root bone, and the local center position will be reset */ centerBone = m_pmd->getCenterBone(); /* calculate relative origin of center bone from model root bone */ tr = m_pmd->getRootBone()->getTransform()->inverse(); pos = tr * centerBone->getTransform()->getOrigin(); /* get the translation vector */ centerBone->getOriginPosition(¢erPos); offset = pos - centerPos; offset.setY(0.0f); /* Y axis should be set to zero to place model on ground */ /* save the current pos/rot for smooth motion changing, resetting center location */ m->mc.setOverrideFirst(&offset); /* add the offset to the root bone */ m_pmd->getRootBone()->getOffset(&rootOffset); rootOffset += offset; m_pmd->getRootBone()->setOffset(&rootOffset); m_pmd->getRootBone()->update(); } else { /* save the current pos/rot for smooth motion changing */ m->mc.setOverrideFirst(NULL) ; } } }
/* PMDObject::updateModelRootRotation: update model rotation of root bone */ bool PMDObject::updateModelRootRotation(float fps) { btQuaternion tmpRot; PMDBone *b; bool ret = false; btQuaternion r; float diff; float maxStep; if (m_isEnable == false) return false; m_isRotating = false; /* get root bone */ b = m_pmd.getRootBone(); /* target rotation is m_offsetRot */ /* turn rotation of root bone closer to m_offsetRot */ b->getCurrentRotation(&r); if (m_offsetRot != r) { /* difference calculation */ r = r - m_offsetRot; diff = r.length(); if (diff > PMDOBJECT_MINSPINDIFF) { if (m_spinSpeed >= 0.0f && fps != 0.0f) { /* max turn speed */ maxStep = MMDFILES_RAD(m_spinSpeed) / fps; if (diff > maxStep) { b->getCurrentRotation(&tmpRot); tmpRot = tmpRot.slerp(m_offsetRot, maxStep / diff); b->setCurrentRotation(&tmpRot); m_isRotating = true; } else { b->setCurrentRotation(&m_offsetRot); ret = true; } } else { /* current * 0.95 + target * 0.05 */ b->getCurrentRotation(&tmpRot); tmpRot = tmpRot.slerp(m_offsetRot, 1.0f - PMDOBJECT_SPINSPEEDRATE); b->setCurrentRotation(&tmpRot); m_isRotating = true; } } else { /* set target offset directory if small difference */ b->setCurrentRotation(&m_offsetRot); ret = true; } b->update(); } return ret; }
/* PMDObject::updateModel: update model position of root bone */ bool PMDObject::updateModelRootOffset(float fps) { bool ret = false; PMDBone *b; btVector3 pos, pos2; float diff; float maxStep; if (m_isEnable == false) return false; /* get root bone */ b = m_pmd.getRootBone(); /* target position is m_offsetPos */ /* move offset of root bone closer to m_offsetPos */ b->getOffset(&pos); m_isMoving = false; if (m_offsetPos != pos) { /* if there is difference then update */ diff = pos.distance(m_offsetPos); if (diff > PMDOBJECT_MINMOVEDIFF) { if (m_moveSpeed >= 0.0f && fps != 0.0f) { /* max speed */ maxStep = m_moveSpeed / fps; if (diff > maxStep) { pos2 = pos.lerp(m_offsetPos, maxStep / diff); m_isMoving = true; } else { pos2 = m_offsetPos; ret = true; } } else { /* current * 0.9 + target * 0.1 */ pos2 = pos.lerp(m_offsetPos, 1.0f - PMDOBJECT_MOVESPEEDRATE); m_isMoving = true; } } else { /* set target offset directory if small difference */ pos2 = m_offsetPos; ret = true; } m_pmd.getRootBone()->setOffset(&pos2); m_pmd.getRootBone()->update(); } return ret; }
/* PMDObject::updateRootBone: update root bone if assigned to a base bone */ void PMDObject::updateRootBone() { btVector3 pos; btVector3 posAbs; PMDBone *b; btTransform tr; if (!m_baseBone) return; /* relative position */ pos = m_offsetPos; /* if absolute flag is true, fix relative position from root bone */ posAbs = m_offsetPos + m_origBasePos - m_baseBone->getTransform()->getOrigin(); if (m_absPosFlag[0]) pos.setX(posAbs.x()); if (m_absPosFlag[1]) pos.setY(posAbs.y()); if (m_absPosFlag[2]) pos.setZ(posAbs.z()); /* set root bone */ b = m_pmd.getRootBone(); b->setCurrentPosition(&pos); b->setCurrentRotation(&m_offsetRot); b->update(); /* update transform for base position */ tr = (*m_baseBone->getTransform()) * (*b->getTransform()); b->setTransform(&tr); }