/* Init character given serialized skeleton information */ void SBDebuggerUtility::initCharacter(const std::string& name, const std::string& skelName) { if (name == "") { LOG("Character has no name - will not be created."); return; } SmartBody::SBCharacter* sbCharacter = SmartBody::SBScene::getScene()->createCharacter(name, ""); if (!sbCharacter) { LOG("Problem creating character %s, will not be created in remote session...", name.c_str()); return; } SmartBody::SBSkeleton* sbSkeleton = SmartBody::SBScene::getScene()->getSkeleton(skelName); if (!sbSkeleton) { LOG("Problem creating skeleton %s, character %s will not be created in remote session...", name.c_str(), skelName.c_str()); return; } SmartBody::SBSkeleton* copySbSkeleton = new SmartBody::SBSkeleton(sbSkeleton); if (!copySbSkeleton) { LOG("Problem creating copy of skeleton %s, character %s will not be created in remote session...", name.c_str(), skelName.c_str()); return; } sbCharacter->setSkeleton(copySbSkeleton); }
void ResourceWindow::updateCharacter( Fl_Tree_Item* tree, SmartBody::SBCharacter* character ) { SmartBody::SBCharacter* sbcharacter = dynamic_cast<SmartBody::SBCharacter*>(character); Fl_Tree_Item* item = resourceTree->add(tree,character->getName().c_str()); item->user_data((void*) addSpecialName(character->getName())); resourceTree->sortorder(FL_TREE_SORT_NONE); Fl_Tree_Item* skeletonFolder = resourceTree->add(item,"skeleton"); skeletonFolder->user_data((void*) _reverseSpecialNames["skeleton"]); SmartBody::SBSkeleton* sbSk = sbcharacter->getSkeleton(); if (sbSk) { Fl_Tree_Item* charSkItem = resourceTree->add(skeletonFolder, sbSk->getName().c_str()); } Fl_Tree_Item* controllerFolder = resourceTree->add(item,"controllers"); controllerFolder->user_data((void*) _reverseSpecialNames["controller"]); controllerFolder->close(); // add controllers MeControllerTreeRoot* ctTree = character->ct_tree_p ; if( ctTree ) { int n = ctTree->count_controllers(); for (int c = 0; c < n; c++) { //LOG( "%s", ctTree->controller(c)->name() ); Fl_Tree_Item* ctrlItem = resourceTree->add(controllerFolder,ctTree->controller(c)->getName().c_str()); // ctrlItem->user_data((void*)ITEM_CONTROLLER); } } /* // add gesture map Fl_Tree_Item* gestureFolder = resourceTree->add(item,"gestures"); gestureFolder->user_data((void*)-1); gestureFolder->close(); // add individual gesture mappings SmartBody::SBScene* scene = SmartBody::SBScene::getScene(); SBGestureMap* gestureMap = scene->getGestureMapManager()->getGestureMap(sbcharacter->getName()); if (gestureMap) { std::string lexeme; std::string type; std::string hand; std::string style; std::string posture; gestureMap->getGestureByInfo(lexeme, type, hand, style, posture); Fl_Tree_Item* gestureItem = resourceTree->add(gestureFolder, lexeme.c_str()); gestureItem->user_data((void*)ITEM_GESTUREMAP); } */ // add NVBG Fl_Tree_Item* nvbgItem = resourceTree->add(item, "minibrain"); nvbgItem->user_data((void*) _reverseSpecialNames["minibrain"]); SmartBody::Nvbg* nvbg = character->getNvbg(); if (nvbg) { nvbgItem = resourceTree->add(item, nvbg->getName().c_str()); } }
SBAPI bool SBM_GetCharacter( SBMHANDLE sbmHandle, const char * name, SBM_CharacterFrameDataMarshalFriendly * character ) { if ( !SBM_HandleExists( sbmHandle ) ) { LOG("SBM_GetCharcter : Handle %d does not exist", sbmHandle); return false; } SmartBody::SBScene * scene = SmartBody::SBScene::getScene(); SmartBody::SBCharacter * sbcharacter = scene->getCharacter(name); const SBM_CharacterFrameDataMarshalFriendly & data = sbcharacter->GetFrameDataMarshalFriendly(); if (character->m_numJoints == 0 || character->m_numJoints != data.m_numJoints) { SBM_ReleaseCharacterJoints(character); character->m_numJoints = data.m_numJoints; character->jname = new char * [ character->m_numJoints ]; character->jx = new float [ character->m_numJoints ]; character->jy = new float [ character->m_numJoints ]; character->jz = new float [ character->m_numJoints ]; character->jrw = new float [ character->m_numJoints ]; character->jrx = new float [ character->m_numJoints ]; character->jry = new float [ character->m_numJoints ]; character->jrz = new float [ character->m_numJoints ]; for ( int i = 0; i < character->m_numJoints; i++ ) { character->jname[ i ] = new char[ strlen(data.jname[ i ]) + 1 ]; strcpy( character->jname[ i ], data.jname[ i ] ); } } character->x = data.x; character->y = data.y; character->z = data.z; character->rw = data.rw; character->rx = data.rx; character->ry = data.ry; character->rz = data.rz; memcpy(character->jx, data.jx, data.m_numJoints * sizeof(float)); memcpy(character->jy, data.jy, data.m_numJoints * sizeof(float)); memcpy(character->jz, data.jz, data.m_numJoints * sizeof(float)); memcpy(character->jrw, data.jrw, data.m_numJoints * sizeof(float)); memcpy(character->jrx, data.jrx, data.m_numJoints * sizeof(float)); memcpy(character->jry, data.jry, data.m_numJoints * sizeof(float)); memcpy(character->jrz, data.jrz, data.m_numJoints * sizeof(float)); return true; }
void SBDebuggerUtility::initCharacterFaceDefinition(const std::string& characterName, const std::string& faceDefName, const std::string& message) { SmartBody::SBScene* sbScene = SmartBody::SBScene::getScene(); SmartBody::SBCharacter* sbCharacter = sbScene->getCharacter(characterName); if (!sbCharacter) return; SmartBody::SBFaceDefinition* faceDef = sbScene->getFaceDefinition(faceDefName); if (!faceDef) return; sbCharacter->setFaceDefinition(faceDef); }
int main_sb( int argc, char** argv ) { osg::ArgumentParser arguments( &argc, argv ); SmartBody::SBScene* scene = SmartBody::SBScene::getScene(); scene->setMediaPath( "./smartbody/" ); // data/ scene->addAssetPath( "motion", "ChrBrad" ); scene->addAssetPath( "mesh", "mesh"); scene->addAssetPath( "script", "scripts"); scene->loadAssets(); int numMotions = scene->getNumMotions(); std::cout << "Loaded motions: " << numMotions << std::endl; SmartBody::SBCharacter* character = scene->createCharacter( "mycharacter", "" ); SmartBody::SBSkeleton* skeleton = scene->createSkeleton( "ChrBrad.sk" ); character->setSkeleton( skeleton ); character->createStandardControllers(); SmartBody::SBSimulationManager* sim = scene->getSimulationManager(); sim->setupTimer(); osg::ref_ptr<osg::Group> root = new osg::Group; osgViewer::Viewer viewer; viewer.setCameraManipulator( new osgGA::TrackballManipulator ); viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) ); viewer.addEventHandler( new osgViewer::StatsHandler ); viewer.addEventHandler( new osgViewer::WindowSizeHandler ); viewer.setSceneData( root.get() ); viewer.setUpViewOnSingleScreen( 1 ); std::string ret = scene->getBmlProcessor()->execBML( "mycharacter", "<body posture=\"ChrBrad@Idle01\"/>" ); sim->start(); while ( !viewer.done() ) { scene->update(); int numCharacters = scene->getNumCharacters(); if (numCharacters == 0) return true; sim->updateTimer(); viewer.frame(); } sim->stop(); return 0; }
void SBDebuggerUtility::updateCharacter(const std::string& cName, const std::string& jName, float& posX, float& posY, float& posZ, float& rotX, float& rotY, float& rotZ, float& rotW) { SmartBody::SBCharacter* sbCharacter = SmartBody::SBScene::getScene()->getCharacter(cName); if (!sbCharacter) return; SmartBody::SBJoint* sbJoint = sbCharacter->getSkeleton()->getJointByName(jName); if (sbJoint) { sbJoint->pos()->value(0, (float)posX); sbJoint->pos()->value(1, (float)posY); sbJoint->pos()->value(2, (float)posZ); SrQuat q = SrQuat((float)rotW, (float)rotX, (float)rotY, (float)rotZ); SrQuat newq = sbJoint->getPrerotation().inverse()*q; sbJoint->quat()->value(newq); } }
void MiniBrain::update(SBCharacter* character, double time, double dt) { if (minibrainCounter < 300) { minibrainCounter ++; return; } SrVec myVelocity; SrVec myPosition; float mySpeed = 0.0f; SrVec myFacing(0, 0, 1); // determine the facing vector SkJoint* base = character->getSkeleton()->search_joint("base"); if (base) { SkJointQuat* jointQuat = base->quat(); const SrQuat& quat = jointQuat->orientation(); SrVec zfacing(0, 0, 1); myFacing = zfacing * quat; } const std::vector<std::string>& pawns = SmartBody::SBScene::getScene()->getPawnNames(); for (std::vector<std::string>::const_iterator pawnIter = pawns.begin(); pawnIter != pawns.end(); pawnIter++) { SBPawn* pawn = SmartBody::SBScene::getScene()->getPawn((*pawnIter)); // determine the velocity of the object std::map<std::string, ObjectData>::iterator piter = _data.find(pawn->getName()); if (piter != _data.end()) { ObjectData& data = (*piter).second; // get the last position SrVec& lastPosition = data.position; // get the current position SmartBody::SBCharacter* curCharacter = dynamic_cast<SmartBody::SBCharacter*>(pawn); SrVec curPosition; if (curCharacter) { curPosition = curCharacter->getPosition(); data.isAnimate = true; } else { float x, y, z, h, p, r; pawn->get_world_offset(x, y, z, h, p, r); curPosition.x = x; curPosition.y = y; curPosition.z = z; data.isAnimate = false; } data.velocity = (curPosition - data.position) / (float) dt; if ((int)data.cachePositions.size() > _cacheLimit) data.cachePositions.pop_front(); data.cachePositions.push_back(curPosition); SrVec temp; for ( std::list<SrVec>::iterator iter = data.cachePositions.begin(); iter != data.cachePositions.end(); iter++) { temp += (*iter); } data.position = temp / float(data.cachePositions.size()); //data.position = curPosition; if (curCharacter && curCharacter == character) { myVelocity = data.velocity; myPosition = data.position; mySpeed = myVelocity.len(); } } else { // seed the object data with position, no velocity ObjectData data; // get the current position SmartBody::SBCharacter* curCharacter = dynamic_cast<SmartBody::SBCharacter*>(pawn); SrVec curPosition; if (curCharacter) { curPosition = curCharacter->getPosition(); } else { float x, y, z, h, p, r; pawn->get_world_offset(x, y, z, h, p, r); curPosition.x = x; curPosition.y = y; curPosition.z = z; } data.velocity = SrVec(); data.position = curPosition; if ((int)data.cachePositions.size() > _cacheLimit) data.cachePositions.pop_front(); data.cachePositions.push_back(curPosition); data.startGazeTime = -1; _data.insert(std::pair<std::string, ObjectData>(pawn->getName(), data)); } } std::string fastestObject = ""; float fastest = -1; ObjectData* fastestData = NULL; for (std::map<std::string, ObjectData>::iterator piter = _data.begin(); piter != _data.end(); piter++) { std::string pawnName = (*piter).first; if (pawnName == character->getName()) continue; // calculate the relative positon and relative velocity ObjectData& data = (*piter).second; data.relativePosition = myPosition - data.position; data.relativeVelocity = myVelocity - data.velocity; float size = data.relativeVelocity.len(); // ignore objects that aren't moving faster than you are if (size <= mySpeed) continue; if (size > fastest) { // ignore activity that is happening behind the character SrVec diffVec = data.position - myPosition; float result = dot(myFacing, diffVec); if (result < 0.0f) continue; fastestObject = pawnName; fastest = size; fastestData = &data; } } Nvbg* nvbg = character->getNvbg(); if (nvbg) // if an NVBG instance is running, send this information there { for (std::map<std::string, ObjectData>::iterator piter = _data.begin(); piter != _data.end(); piter++) { const std::string& pawnName = (*piter).first; ObjectData& data = (*piter).second; nvbg->objectEvent(character->getName(), pawnName, data.isAnimate, myPosition, myVelocity, data.position, data.velocity, data.relativePosition, data.relativeVelocity); } } else // simple functionality - look at things that move quickly { // now look at the fastest thing moving that exceeds a threshold float characterHeight = character->getHeight(); if (fastest > characterHeight / 10.0) { SbmPawn* gazeTarget = SmartBody::SBScene::getScene()->getPawn(fastestObject); if (!gazeTarget) return; // make sure that we aren't already gazing at this object MeCtScheduler2* gazeSchedule = character->gaze_sched_p; if (!gazeSchedule) return; MeCtScheduler2::VecOfTrack tracks = gazeSchedule->tracks(); for (size_t t = 0; t < tracks.size(); t++) { MeController* controller = tracks[t]->animation_ct(); MeCtGaze* gaze = dynamic_cast<MeCtGaze*>(controller); if (gaze) { float x, y, z; SkJoint* joint = gaze->get_target_joint(x, y, z); if (joint && joint->skeleton() == gazeTarget->getSkeleton()) { // update the time fastestData->startGazeTime = time; return; } } } std::stringstream strstr; strstr << "bml char " << character->getName() << " <gaze target=\"" << fastestObject << "\" sbm:joint-range=\"EYES NECK\"/>" << std::endl; fastestData->startGazeTime = time; SmartBody::SBScene::getScene()->getCommandManager()->execute((char*) strstr.str().c_str()); return; } // if we are staring at nothing, fade out any gazes for objects that have been 'uninteresting' for more than 2 seconds for (std::map<std::string, ObjectData>::iterator piter = _data.begin(); piter != _data.end(); piter++) { ObjectData& data = (*piter).second; if (data.startGazeTime > 0 && (time - data.startGazeTime) > 2.0 + float(rand() % 100) * .01f) { std::stringstream strstr; strstr << "char " << character->getName() << " gazefade out .5" << std::endl; data.startGazeTime = -1; SmartBody::SBScene::getScene()->getCommandManager()->execute((char*) strstr.str().c_str()); std::stringstream strstr2; strstr2 << "char " << character->getName() << " prune" << std::endl; SmartBody::SBScene::getScene()->getCommandManager()->execute_later((char*) strstr2.str().c_str(), 3 + float(rand() % 100) * .01f); } } } }
bool OgreSmartBody::frameRenderingQueued(const Ogre::FrameEvent& evt) { if(mWindow->isClosed()) return false; //Need to capture/update each device mKeyboard->capture(); mMouse->capture(); if(mKeyboard->isKeyDown(OIS::KC_ESCAPE)) return false; // smartbody if (!m_pScene) return true; SmartBody::SBSimulationManager* sim = m_pScene->getSimulationManager(); sim->setTime((Ogre::Root::getSingleton().getTimer()->getMilliseconds() / 1000.0f) - mStartTime); m_pScene->update(); int numCharacters = m_pScene->getNumCharacters(); if (numCharacters == 0) return true; const std::vector<std::string>& characterNames = m_pScene->getCharacterNames(); for (size_t n = 0; n < characterNames.size(); n++) { SmartBody::SBCharacter* character = m_pScene->getCharacter(characterNames[n]); if (!this->getSceneManager()->hasEntity(characterNames[n])) continue; Ogre::Entity* entity = this->getSceneManager()->getEntity(characterNames[n]); Ogre::Skeleton* meshSkel = entity->getSkeleton(); Ogre::Node* node = entity->getParentNode(); SrVec pos = character->getPosition(); SrQuat ori = character->getOrientation(); //std::cout << ori.w << ori.x << " " << ori.y << " " << ori.z << std::endl; node->setPosition(pos.x, pos.y, pos.z); node->setOrientation(ori.w, ori.x, ori.y, ori.z); // Update joints SmartBody::SBSkeleton* sbSkel = character->getSkeleton(); int numJoints = sbSkel->getNumJoints(); for (int j = 0; j < numJoints; j++) { SmartBody::SBJoint* joint = sbSkel->getJoint(j); try { SrQuat orientation = joint->quat()->value(); Ogre::Vector3 posDelta(joint->getPosition().x, joint->getPosition().y, joint->getPosition().z); Ogre::Quaternion quatDelta(orientation.w, orientation.x, orientation.y, orientation.z); Ogre::Bone* bone = meshSkel->getBone(joint->getName()); if (!bone) continue; bone->setPosition(bone->getInitialPosition() + posDelta); bone->setOrientation(quatDelta); } catch (Ogre::ItemIdentityException& ex) { // Should not happen as we filtered using m_mValidBones } } } return true; }
BML::BehaviorRequestPtr BML::parse_bml_states( DOMElement* elem, const std::string& unique_id, BehaviorSyncPoints& behav_syncs, bool required, BmlRequestPtr request, SmartBody::SBScene* scene ) { // local Id std::string localId; const XMLCh* attrID = elem->getAttribute(BMLDefs::ATTR_ID); xml_utils::xml_translate(&localId, attrID); // get character std::string characterName = request->actor->getName(); SmartBody::SBCharacter* character = SmartBody::SBScene::getScene()->getCharacter(characterName); if (character == NULL) { LOG("parse_bml_states ERR: cannot find character with name %s.", characterName.c_str()); return BehaviorRequestPtr(); } MeCtParamAnimation* paramCt = character->param_animation_ct; std::string layer = xml_parse_string(BMLDefs::ATTR_LAYER, elem); if (layer == "1") paramCt = character->param_animation_ct; if (layer == "2") paramCt = character->param_animation_ct_layer1; if (layer == "3") paramCt = character->param_animation_ct_layer2; if (!paramCt) { LOG("No parameterized animation controller present for character %s.", character->getName().c_str()); return BehaviorRequestPtr(); } // get state std::string stateName = xml_parse_string(BMLDefs::ATTR_NAME, elem); if (stateName == "") { LOG("parse_bml_states ERR: expecting a state name."); return BehaviorRequestPtr(); } PABlend* state = SmartBody::SBScene::getScene()->getBlendManager()->getBlend(stateName); if (!state) { LOG("parse_bml_states WARNING: Can't find state name %s, will schedule PseudoIdle state under schedule mode", stateName.c_str()); } // get parameters std::string mode = xml_parse_string(BMLDefs::ATTR_MODE, elem); if (mode == "") mode = "schedule"; std::string xString = xml_parse_string(BMLDefs::ATTR_X, elem); std::string yString = xml_parse_string(BMLDefs::ATTR_Y, elem); std::string zString = xml_parse_string(BMLDefs::ATTR_Z, elem); // get weights from parameters std::vector<double> weights; if (state) { weights.resize(state->getNumMotions()); } if (weights.size() > 0) weights[0] = 1.0f; double x = 0; double y = 0; double z = 0; if ((xString != "" || yString != "" || zString != "") && state) { x = atof(xString.c_str()); y = atof(yString.c_str()); z = atof(zString.c_str()); int parameterType = state->getType(); if (parameterType == 0) state->getWeightsFromParameters(x, weights); if (parameterType == 1) state->getWeightsFromParameters(x, y, weights); if (parameterType == 2) state->getWeightsFromParameters(x, y, z, weights); } // wrap mode ScheduleType scType; std::string wrap = xml_parse_string(BMLDefs::ATTR_WRAPMODE, elem); if (wrap == "") wrap = "Loop"; boost::algorithm::to_lower(wrap); scType.wrap = PABlendData::Loop; if (wrap == "once") scType.wrap = PABlendData::Once; if (wrap == "clamp") scType.wrap = PABlendData::Clamp; // schedule mode std::string schedule = xml_parse_string(BMLDefs::ATTR_SCHEDULEMODE, elem); if (schedule == "") schedule = "Queued"; boost::algorithm::to_lower(schedule); scType.schedule = PABlendData::Queued; if (schedule == "now") scType.schedule = PABlendData::Now; // blend mode std::string blend = xml_parse_string(BMLDefs::ATTR_BLENDMODE, elem); if (blend == "") blend = "Overwrite"; boost::algorithm::to_lower(blend); scType.blend =PABlendData::Overwrite; if (blend == "additive") scType.blend = PABlendData::Additive; // partial joint name std::string joint = xml_parse_string(BMLDefs::ATTR_PARTIALJOINT, elem); if (joint == "") joint = "null"; // take time offset0 scType.jName = joint; scType.timeOffset = xml_parse_double(BMLDefs::ATTR_START, elem); scType.stateTimeOffset = xml_parse_double(BMLDefs::ATTR_OFFSET, elem, 0.0); scType.stateTimeTrim = xml_parse_double(BMLDefs::ATTR_TRIM, elem, 0.0); scType.transitionLen = xml_parse_double(BMLDefs::ATTR_TRANSITION_LENGTH, elem, -1.0); scType.playSpeed = xml_parse_double(BMLDefs::ATTR_SPEED, elem, 1.0); scType.duration = xml_parse_double(BMLDefs::ATTR_DURATION, elem, -1.0); std::string directPlayStr = xml_parse_string(BMLDefs::ATTR_DIRECTPLAY, elem, "false"); scType.directPlay = false; if (directPlayStr == "true") scType.directPlay = true; SmartBody::SBAnimationBlend0D* ZeroDState = dynamic_cast<SmartBody::SBAnimationBlend0D*>(state); if (!ZeroDState) // don't use state offset unless it is a 0-D state { scType.stateTimeOffset = 0.0; scType.stateTimeTrim = 0.0; } // schedule a state if (mode == "schedule") { if (state) //character->param_animation_ct->schedule(state, x, y, z, wrapMode, scheduleMode, blendMode, joint, timeOffset, stateStartOffset, stateEndTrim, transitionLen, directPlay); //character->param_animation_ct->schedule(state, weights, scType); paramCt->schedule(state, weights, scType); else //character->param_animation_ct->schedule(state, weights, scType); paramCt->schedule(state, weights, scType); } // update parameter if (mode == "update") { // character->param_animation_ct->updateWeights(weights); paramCt->updateWeights(weights); paramCt->getCurrentPABlendData()->wrapMode = scType.wrap; } return BehaviorRequestPtr( new EventRequest(unique_id, localId, "", "", behav_syncs, "")); }
void PAAutoFootStepsEditor::confirmEditting(Fl_Widget* widget, void* data) { PAAutoFootStepsEditor* footStepEditor = (PAAutoFootStepsEditor*) data; PABlend* currentState = footStepEditor->stateEditor->getCurrentState(); if (!currentState) { LOG("PAAutoFootStepsEditor::confirmEditting WARNING: please select a state!"); return; } // take down previous correspondence points first footStepEditor->stateEditor->previousKeys.clear(); footStepEditor->stateEditor->previousKeys.resize(currentState->getNumMotions()); for (int i = 0; i < currentState->getNumMotions(); i++) { footStepEditor->stateEditor->previousKeys[i].resize(currentState->getNumKeys()); footStepEditor->stateEditor->previousKeys[i] = currentState->keys[i]; } // auto foot steps algorithm float floorHeight = (float)atof(footStepEditor->inputFloorHeight->value()); float heightThresh = (float)atof(footStepEditor->inputHeightThreshold->value()); float speedThresh = (float)atof(footStepEditor->inputSpeedThreshold->value()); int speedWindow = atoi(footStepEditor->inputSpeedDetectWindow->value()); int stepsPerJoint = atoi(footStepEditor->inputStepsPerJoint->value()); if (stepsPerJoint < 1) stepsPerJoint = 1; int checkDebugInfoVal = footStepEditor->checkDebugInfo->value(); if (checkDebugInfoVal == 0) footStepEditor->isPrintDebugInfo = false; if (checkDebugInfoVal == 1) footStepEditor->isPrintDebugInfo = true; const std::vector<std::string>& selectedMotions = footStepEditor->stateEditor->getSelectedMotions(); SmartBody::SBCharacter* curCharacter = footStepEditor->stateEditor->paWindow->getCurrentCharacter(); std::vector<std::string> selectedJoints; for (int i = 0; i < footStepEditor->browserJoint->size(); i++) { if (footStepEditor->browserJoint->selected(i+1)) { selectedJoints.push_back(footStepEditor->browserJoint->text(i + 1)); } } if (selectedJoints.size() == 0) { fl_alert("Please select at least one joint."); return; } std::stringstream finalMessage; std::vector<std::string> motionsNeedManualAdjusting; finalMessage << "Current State: " << currentState->stateName << "\n"; bool isConvergent = true; for (size_t m = 0; m < selectedMotions.size(); m++) { // shared std::vector<double> possibleTiming; // divided std::vector<std::vector<double> > vecOutMeans; vecOutMeans.resize(selectedJoints.size()); std::vector<std::vector<double> > vecTiming; vecTiming.resize(selectedJoints.size()); SmartBody::SBMotion* motion = SmartBody::SBScene::getScene()->getMotion(selectedMotions[m]); if (!motion) continue; #if 1 // feng : I tried to refactor the footstep detection into a API function in SBMotion. // Still contains too many parameters to be used as an API. But would clean it up more and see if we can come up with // a version that can also detect the number of steps as the input. If this is interfering with the editor, set this back to 0. std::vector<double> outMeans; int maxNumSteps = footStepEditor->stateEditor->getCurrentState()->getNumKeys(); if (!footStepEditor->isProcessAll) { stepsPerJoint = maxNumSteps / selectedJoints.size(); } else { maxNumSteps = stepsPerJoint * selectedJoints.size(); } // std::vector<FootStepRecord> footSteps; // motion->autoFootPlantDetection(curCharacter->getSkeleton(),selectedJoints,floorHeight, heightThresh,speedThresh,footSteps); // // for (int i=0;i<footSteps.size();i++) // { // FootStepRecord& record = footSteps[i]; // LOG("Footstep joint = %s, start frame = %f, end frame = %f",record.jointName.c_str(), record.startTime, record.endTime); // } isConvergent = motion->autoFootStepDetection(outMeans, stepsPerJoint, maxNumSteps, curCharacter->getSkeleton(), selectedJoints, floorHeight, heightThresh, speedThresh, speedWindow, footStepEditor->isPrintDebugInfo); #else motion->connect(curCharacter->getSkeleton()); for(int f = 0; f < motion->getNumFrames(); f++) { motion->apply_frame(f); motion->connected_skeleton()->update_global_matrices(); for (size_t jointId = 0; jointId < selectedJoints.size(); jointId ++) { std::string jointName = selectedJoints[jointId]; SBJoint* joint = curCharacter->getSkeleton()->getJointByName(jointName); if (!joint) continue; // get height const SrMat& gMat = joint->gmat(); SrVec gPos = SrVec(gMat.get(12), gMat.get(13), gMat.get(14)); // get speed int startFrame = f - speedWindow / 2; int endFrame = f + speedWindow / 2; float startTime = startFrame * (float)motion->getFrameRate(); float endTime = endFrame * (float)motion->getFrameRate(); float speed = motion->getJointSpeed(joint, startTime, endTime); // print info if (footStepEditor->isPrintDebugInfo) LOG("motion %s at time %f-> speed is %f, height is %f, joint is %s", motion->getName().c_str(), f * motion->getFrameRate(), speed, gPos.y, jointName.c_str()); // filter for height if (gPos.y < floorHeight || gPos.y > (floorHeight + heightThresh)) continue; // filter speed if (speed <= speedThresh) { vecTiming[jointId].push_back(f * (float)motion->getFrameRate()); possibleTiming.push_back(f * (float)motion->getFrameRate()); } } } // K means algorithm according to desired number of steps std::vector<double> outMeans; int maxNumSteps = footStepEditor->stateEditor->getCurrentState()->getNumKeys(); if (!footStepEditor->isProcessAll) { stepsPerJoint = maxNumSteps / selectedJoints.size(); } else { maxNumSteps = stepsPerJoint * selectedJoints.size(); } /* int numSteps = footStepEditor->stateEditor->getCurrentState()->getNumKeys(); isConvergent = footStepEditor->kMeansClustering1D(numSteps, possibleTiming, outMeans); */ for (size_t jointId = 0; jointId < selectedJoints.size(); jointId++) { if (jointId == (selectedJoints.size() - 1) && !footStepEditor->isProcessAll) { int mod = footStepEditor->stateEditor->getCurrentState()->getNumKeys() % selectedJoints.size(); stepsPerJoint += mod; } bool retBoolean = footStepEditor->kMeansClustering1D(stepsPerJoint, vecTiming[jointId], vecOutMeans[jointId]); if (!retBoolean) { isConvergent = false; break; } } if (isConvergent) { outMeans.clear(); for (size_t joinId = 0; joinId < selectedJoints.size(); joinId++) { for (size_t meanId = 0; meanId < vecOutMeans[joinId].size(); meanId++) outMeans.push_back(vecOutMeans[joinId][meanId]); } std::sort(outMeans.begin(), outMeans.end()); } #endif // apply it to corresponding points // also appending starting and ending corresponding points int motionIndex = currentState->getMotionId(selectedMotions[m]); if (isConvergent) { std::stringstream ss; ss << "[" << motion->getName() << "]detected "; for (size_t i = 0; i < outMeans.size(); i++) ss << outMeans[i] << " "; LOG("%s", ss.str().c_str()); finalMessage << ss.str() << "\n"; currentState->keys[motionIndex].clear(); if (footStepEditor->isProcessAll) currentState->keys[motionIndex].push_back(0); for (size_t i = 0; i < outMeans.size(); i++) currentState->keys[motionIndex].push_back(outMeans[i]); if (footStepEditor->isProcessAll) currentState->keys[motionIndex].push_back(motion->getDuration()); } else { motionsNeedManualAdjusting.push_back(motion->getName()); std::stringstream ss; ss << "[" << motion->getName() << "]NOT detected(evenly distrubted): "; int actualNum = maxNumSteps; currentState->keys[motionIndex].clear(); if (footStepEditor->isProcessAll) actualNum += 2; for (int i = 0; i < actualNum; i++) { double step = motion->getDuration() / double(actualNum - 1); currentState->keys[motionIndex].push_back(step * i); ss << step * i << " "; } LOG("%s", ss.str().c_str()); finalMessage << ss.str() << "\n"; } motion->disconnect(); } // print out final message finalMessage << "\n\n=======Summary=======\n"; for (size_t m = 0; m < motionsNeedManualAdjusting.size(); m++) { finalMessage << motionsNeedManualAdjusting[m] << " may need manual adjusting\n"; } fl_message("%s", finalMessage.str().c_str()); // refresh state editor footStepEditor->stateEditor->buttonUndoAutoFootSteps->activate(); footStepEditor->stateEditor->refresh(); footStepEditor->hide(); }
PAAutoFootStepsEditor::PAAutoFootStepsEditor(PABlendEditor* editor, int x, int y, int w, int h) : Fl_Window(x, y, w, h) { set_modal(); stateEditor = editor; xDis = 10; yDis = 10; int csx = xDis; int csy = yDis; isPrintDebugInfo = false; this->label("Auto Footsteps Editor"); this->begin(); inputFloorHeight = new Fl_Input(xDis + csx + 100, yDis, 10 * xDis, 2 * yDis, "FloorHeight"); inputFloorHeight->value("0"); inputHeightThreshold = new Fl_Input(xDis + csx + 100, 4 * yDis, 10 * xDis, 2 * yDis, "HeightThreshold"); std::stringstream inputHeightSS; inputHeightSS << 0.15f / SmartBody::SBScene::getScene()->getScale(); inputHeightThreshold->value(inputHeightSS.str().c_str()); inputSpeedThreshold = new Fl_Input(xDis + csx + 100, 7 * yDis, 10 * xDis, 2 * yDis, "SpeedThreshold"); std::stringstream inputSpeedSS; inputSpeedSS << 0.4f / SmartBody::SBScene::getScene()->getScale(); inputSpeedThreshold->value(inputSpeedSS.str().c_str()); inputSpeedDetectWindow = new Fl_Input(xDis + csx + 100, 10 * yDis, 10 * xDis, 2 * yDis, "SpeedDetectWindow"); inputSpeedDetectWindow->value("3"); inputSpeedDetectWindow->deactivate(); browserJoint = new Fl_Multi_Browser(xDis + csx + 100, 13 * yDis, 28 * xDis, 20 * yDis, "Joint"); SmartBody::SBCharacter* character = stateEditor->paWindow->getCurrentCharacter(); if (character) { const std::vector<std::string>& charJNames = character->getSkeleton()->getJointNames(); for (size_t i = 0; i < charJNames.size(); i++) browserJoint->add(charJNames[i].c_str()); } inputStepsPerJoint = new Fl_Input(xDis + csx + 100, 36 * yDis, 10 * xDis, 2 * yDis, "StepsPerJoint"); PABlend* curState = stateEditor->getCurrentState(); std::vector<std::string> selectedMotions = stateEditor->getSelectedMotions(); if (selectedMotions.size() == curState->getNumMotions()) inputStepsPerJoint->activate(); else inputStepsPerJoint->deactivate(); int stepsPerJoint = 2; std::stringstream ss; ss << stepsPerJoint; inputStepsPerJoint->value(ss.str().c_str()); browserSelectedMotions = new Fl_Browser(xDis + csx + 100, 39 * yDis, 28 * xDis, 10 * yDis, "SelectedMotions"); browserSelectedMotions->deactivate(); refreshSelectedMotions(); checkDebugInfo = new Fl_Check_Button(xDis + csx + 100, 51 * yDis, 10 * xDis, 2 * yDis, "DumpDetailInformation"); buttonConfirm = new Fl_Button(xDis + csx, 55 * yDis, 10 * xDis, 2 * yDis, "Apply"); buttonConfirm->callback(confirmEditting, this); buttonCancel = new Fl_Button(xDis + csx + 120, 55 * yDis, 10 * xDis, 2 * yDis, "Leave"); buttonCancel->callback(cancelEditting, this); this->end(); }