//----------------------------------------------------------------------- void Entity::_updateRenderQueue(RenderQueue* queue) { SubEntityList* subEntList; // Check we're not using a manual LOD if (mMeshLodIndex > 0 && mMesh->isLodManual()) { // Use alternate subentities assert((mMeshLodIndex-1) < mLodSubEntityList.size() && "No LOD SubEntityList - did you build the manual LODs after creating the entity?"); // index - 1 as we skip index 0 (original lod) subEntList = mLodSubEntityList[mMeshLodIndex - 1]; } else { subEntList = &mSubEntityList; } // Add each SubEntity to the queue SubEntityList::iterator i, iend; iend = subEntList->end(); for (i = subEntList->begin(); i != iend; ++i) { queue->addRenderable(*i, mRenderQueueID, RENDERABLE_DEFAULT_PRIORITY); } // Since we know we're going to be rendered, take this opportunity to // cache bone matrices & apply world matrix to them if (mMesh->hasSkeleton()) { cacheBoneMatrices(); //--- pass this point, we are sure that the transformation matrix of each bone and tagPoint have been updated // 挂到骨头上的子物体 ChildObjectList::iterator child_itr = mChildObjectList.begin(); ChildObjectList::iterator child_itr_end = mChildObjectList.end(); for( ; child_itr != child_itr_end; child_itr++) { (*child_itr).second->_updateRenderQueue(queue); } } // HACK to display bones // This won't work if the entity is not centered at the origin // TODO work out a way to allow bones to be rendered when Entity not centered if (mDisplaySkeleton && mMesh->hasSkeleton()) { Skeleton* pSkel = mMesh->getSkeleton(); int numBones = pSkel->getNumBones(); for (int b = 0; b < numBones; ++b) { Bone* bone = pSkel->getBone(b); queue->addRenderable(bone, mRenderQueueID); } } }
void SkeletonTool::drawSkeleton(const Skeleton &skeleton, int row) { bool buildingSkeleton = m_mode.getValue() == BUILD_SKELETON; bool ikEnabled = m_mode.getValue() == INVERSE_KINEMATICS; TXsheet *xsh = getXsheet(); std::vector<int> showBoneIndex; int i; for (i = 0; i < skeleton.getBoneCount(); i++) { Skeleton::Bone *bone = skeleton.getBone(i); TStageObjectId id = bone->getStageObject()->getId(); bool canShow = canShowBone(bone, xsh, row); if (!canShow) continue; showBoneIndex.push_back(i); } bool changingParent = dynamic_cast<ParentChangeTool *>(m_dragTool) != 0; TStageObjectId currentObjectId = TTool::getApplication()->getCurrentObject()->getObjectId(); std::string currentHandle = xsh->getStageObject(currentObjectId)->getHandle(); for (i = 0; i < (int)showBoneIndex.size(); i++) { Skeleton::Bone *bone = skeleton.getBone(showBoneIndex[i]); TStageObjectId id = bone->getStageObject()->getId(); bool isCurrent = id == currentObjectId; if (isCurrent && buildingSkeleton && m_parentProbeEnabled) { if (!m_magicLinks.empty()) { drawBone(bone->getCenter(), m_magicLinks[0].m_h1.m_pos, false); } drawBone(bone->getCenter(), m_parentProbe, true); } else if (ikEnabled) { if (bone->getParent()) drawIKBone(bone->getCenter(), bone->getParent()->getCenter()); } else if (bone->getParent() || isCurrent) { double pixelSize = getPixelSize(); TPointD a = bone->getCenter(); TPointD b, pm; if (bone->getParent()) { b = bone->getParent()->getCenter(); pm = (a + b) * 0.5; } else { pm = b = a + TPointD(0, 60) * pixelSize; } bool boneIsVisible = false; if (buildingSkeleton) { boneIsVisible = true; if (bone->isSelected()) drawBone(a, b, true); else if (!m_showOnlyActiveSkeleton.getValue()) drawBone(a, b, false); else boneIsVisible = false; } if (boneIsVisible && isCurrent) { // draw change parent gadget double r = pixelSize * 5; if (isPicking()) { // int code = TD_ResetParent + bone->getStageObject()->getId().getIndex(); glPushName(TD_ChangeParent); tglDrawDisk(pm, r); glPopName(); } else { if (m_device == TD_ChangeParent) { glColor4d(0.47 * alpha, 0.6 * alpha, 0.65 * alpha, alpha); r *= 1.5; } else glColor4d(0.37 * alpha, 0.5 * alpha, 0.55 * alpha, alpha); glRectd(pm.x - r, pm.y - r, pm.x + r, pm.y + r); glColor3d(0, 0, 0); tglDrawRect(pm.x - r, pm.y - r, pm.x + r, pm.y + r); } } } } for (i = 0; i < (int)showBoneIndex.size(); i++) { Skeleton::Bone *bone = skeleton.getBone(showBoneIndex[i]); if (!m_showOnlyActiveSkeleton.getValue() || bone->isSelected()) drawJoint(bone->getCenter(), currentObjectId == bone->getStageObject()->getId() && currentHandle.find("H") != 0); } }
void SkeletonTool::togglePinnedStatus(int columnIndex, int frame, bool shiftPressed) { Skeleton skeleton; buildSkeleton(skeleton, columnIndex); if (!skeleton.getRootBone() || !skeleton.getRootBone()->getStageObject()) return; Skeleton::Bone *bone = skeleton.getBoneByColumnIndex(columnIndex); assert(bone); if (!bone) return; TogglePinnedStatusUndo *undo = new TogglePinnedStatusUndo(this, frame); for (int i = 0; i < skeleton.getBoneCount(); i++) { TStageObject *obj = skeleton.getBone(i)->getStageObject(); if (obj) { undo->addBoneId(obj->getId()); obj->setKeyframeWithoutUndo(frame); } } getApplication()->getCurrentXsheet()->notifyXsheetChanged(); getApplication()->getCurrentObject()->notifyObjectIdChanged(false); undo->setOldTemp(m_temporaryPinnedColumns); bool isTemporaryPinned = m_temporaryPinnedColumns.count(columnIndex) > 0; if (shiftPressed || isTemporaryPinned) { if (isTemporaryPinned) m_temporaryPinnedColumns.erase(columnIndex); else m_temporaryPinnedColumns.insert(columnIndex); } else { TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet(); TAffine placement = xsh->getPlacement(bone->getStageObject()->getId(), frame); TStageObjectId rootId = skeleton.getRootBone()->getStageObject()->getId(); TAffine rootPlacement = xsh->getPlacement(rootId, frame); int pinnedStatus = bone->getPinnedStatus(); if (pinnedStatus != Skeleton::Bone::PINNED) { int oldPinned = -1; for (int i = 0; i < skeleton.getBoneCount(); i++) { TStageObject *obj = skeleton.getBone(i)->getStageObject(); if (obj->getPinnedRangeSet()->isPinned(frame)) { oldPinned = i; break; } } int lastFrame = 1000000; if (oldPinned >= 0) { assert(skeleton.getBone(oldPinned) != bone); TStageObject *obj = skeleton.getBone(oldPinned)->getStageObject(); const TPinnedRangeSet::Range *range = obj->getPinnedRangeSet()->getRange(frame); assert(range && range->first <= frame && frame <= range->second); lastFrame = range->second; TPinnedRangeSet *rangeSet = obj->getPinnedRangeSet(); rangeSet->removeRange(frame, range->second); obj->invalidate(); undo->setOldRange(oldPinned, frame, range->second, rangeSet->getPlacement()); } else { for (int i = 0; i < skeleton.getBoneCount(); i++) { TStageObject *obj = skeleton.getBone(i)->getStageObject(); const TPinnedRangeSet::Range *range = obj->getPinnedRangeSet()->getNextRange(frame); if (range) { assert(range->first > frame); if (range->first - 1 < lastFrame) lastFrame = range->first - 1; } } } TStageObject *obj = bone->getStageObject(); TPinnedRangeSet *rangeSet = obj->getPinnedRangeSet(); rangeSet->setRange(frame, lastFrame); if (frame == 0) { // this code should be moved elsewhere, possibly in the stageobject implementation // the idea is to remove the normal TStageObject *rootObj = skeleton.getRootBone()->getStageObject(); rootObj->setStatus(TStageObject::XY); placement = rootObj->getPlacement(0).inv() * placement; rootObj->setStatus(TStageObject::IK); rangeSet->setPlacement(placement); rootObj->invalidate(); } undo->setNewRange(bone->getColumnIndex(), frame, lastFrame, rangeSet->getPlacement()); } } undo->setNewTemp(m_temporaryPinnedColumns); TUndoManager::manager()->add(undo); }
void SkeletonTool::draw() { // parent object reference system //glColor3d(1,0,0); //tglDrawRect(0,0,100,100); if (m_label != "") ToolUtils::drawBalloon(m_labelPos, m_label, TPixel32::Red, TPoint(20, -20), false); bool ikEnabled = m_mode.getValue() == INVERSE_KINEMATICS; assert(glGetError() == GL_NO_ERROR); // l'xsheet, oggetto (e relativo placement), frame corrente TTool::Application *app = TTool::getApplication(); TXsheet *xsh = getXsheet(); assert(xsh); TStageObjectId objId = app->getCurrentObject()->getObjectId(); // se l'oggetto corrente non e' una colonna non disegno nulla if (!objId.isColumn()) return; TStageObject *pegbar = xsh->getStageObject(objId); int col = objId.getIndex(); int frame = app->getCurrentFrame()->getFrame(); if (m_currentFrame != frame) m_temporaryPinnedColumns.clear(); TAffine aff = getMatrix(); // puo' suggere che il placement degeneri (es.: c'e' uno h-scale = 0%) if (fabs(aff.det()) < 0.00001) return; // m_unit = getPixelSize() * sqrt(fabs(aff.det())); if (!ikEnabled) drawLevelBoundingBox(frame, col); glPushMatrix(); tglMultMatrix(aff.inv()); // camera stand reference system //glColor3d(0,1,0); //tglDrawRect(0,0,100,100); bool changingParent = dynamic_cast<ParentChangeTool *>(m_dragTool) != 0; // !changingParent && if (m_mode.getValue() == BUILD_SKELETON && !xsh->getStageObjectParent(objId).isColumn()) { if (!changingParent) drawHooks(); } Skeleton skeleton; buildSkeleton(skeleton, col); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); drawSkeleton(skeleton, frame); glDisable(GL_BLEND); TXshCell cell = xsh->getCell(frame, objId.getIndex()); Skeleton::Bone *rootBone = skeleton.getRootBone(); for (int i = 0; i < skeleton.getBoneCount(); i++) { Skeleton::Bone *bone = skeleton.getBone(i); TStageObjectId currentId = bone->getStageObject()->getId(); bool isCurrent = (currentId == objId); TPointD pos = bone->getCenter(); if (isCurrent && m_mode.getValue() != BUILD_SKELETON) { drawDrawingBrowser(cell, pos); } bool isActiveChain = bone->isSelected(); glColor3d(0, 1, 0); if (ikEnabled) { drawIKJoint(bone); } else { TPointD pos = bone->getCenter(); if (isCurrent && m_mode.getValue() == ANIMATE) { drawMainGadget(pos); } } } m_currentFrame = frame; if (m_dragTool) m_dragTool->draw(); glPopMatrix(); }
void Skeleton::fitToTargetSkeleton(const Skeleton &target) { // find root bone int rootId = -1; for(unsigned int i = 0; i < mBones.size(); ++i) { if(mBones[i].parent == -1) { rootId = i; break; } } // is a root in the skeleton if(rootId == -1) { LOG("no root bone found"); return; } // check for consistency if(mBones.size() != target.getNumBones()) { LOG("skeletons does not match"); return; } // init stack with root std::vector<int> ndStack(0); ndStack.push_back(rootId); // level pt int sp = 0; while((unsigned int)sp < ndStack.size()) { Bone& cur = mBones[ndStack[sp]]; for(unsigned int j = 0; j < cur.children.size(); ++j) { ndStack.push_back(cur.children[j]); } sp++; } // apply all rotations according stack order for(unsigned int k = 0; k < ndStack.size(); ++k) { // get current bone unsigned int l = ndStack[k]; Bone& _tB = mBones[l]; // transform rotation from other bone Bone _oB; target.getBone(l, _oB); _tB.R = _oB.R; // offset is the fathers end position if(_tB.parent > -1 && (unsigned int)_tB.parent < mBones.size()) { Bone& _pP = mBones[_tB.parent]; _tB.t = _pP.t + _pP.R.col(1) * _pP.length; } else { // LOG("no t correction for bone " << l); } mJoints[_tB.j0] = _tB.t; mJoints[_tB.j1] = _tB.t + _tB.R.col(1) * _tB.length; } }
bool FileSystem::loadModelAndSkeletonDae(const char *path, Model &m, Skeleton &s) { size_t pos; std::string line, armatureName; std::ifstream fileStream(path); std::vector<bool> closed; glm::mat4 bindShapeMatrix; std::vector<float> v, n, t, w; std::vector<glm::mat4> bindPoses; std::vector<std::vector<int> > weightJoints, weightWeights, indices; std::vector<std::string> polylistMaterials; std::vector<int> vcount; if (fileStream.is_open()) { getline(fileStream, line); while (line.find("<library_geometries>") == std::string::npos && fileStream.good()) { getline(fileStream, line); } while (line.find("<mesh>") == std::string::npos && fileStream.good()) { getline(fileStream, line); } //load model while (fileStream.good()) { getline(fileStream, line); size_t pos; if ((pos = line.find("<source id=")) != std::string::npos) { std::string id = line; getline(fileStream, line); std::string::iterator begIt = line.begin() + (pos = line.find_first_of(">")) + 1; std::string::iterator endIt = line.begin() + line.find_first_of("<", pos + 1); if ((pos = id.find("-positions")) != std::string::npos) { v.reserve(atoi(line.substr((pos = line.find("count=\"")) + 7, line.find_first_of("\"", pos + 1) - (pos + 1)).c_str())); split(begIt, endIt, ' ', v); } else if ((pos = id.find("-normals")) != std::string::npos) { n.reserve(atoi(line.substr((pos = line.find("count=\"")) + 7, line.find_first_of("\"", pos + 1) - (pos + 1)).c_str())); split(begIt, endIt, ' ', n); } else if ((pos = id.find("-map")) != std::string::npos) { t.reserve(atoi(line.substr((pos = line.find("count=\"")) + 7, line.find_first_of("\"", pos + 1) - (pos + 1)).c_str())); split(begIt, endIt, ' ', t); } } else if ((pos = line.find("<polylist")) != std::string::npos) { polylistMaterials.push_back(line.substr((pos = line.find("material=\"") + 10), line.find("-material\"", pos + 1) - pos)); indices.push_back(std::vector<int>()); indices.back().reserve(atoi(line.substr((pos = line.find("count=\"")) + 7, line.find_first_of("\"", pos + 1) - (pos + 1)).c_str())); while (line.find("<p>") == std::string::npos && fileStream.good()) { getline(fileStream, line); } std::string::iterator begIt = line.begin() + (pos = line.find_first_of(">")) + 1; std::string::iterator endIt = line.begin() + line.find_first_of("<", pos + 1); split(begIt, endIt, ' ', indices.back()); } else if ((pos = line.find("</mesh>")) != std::string::npos) { break; } } while (line.find("<library_controllers>") == std::string::npos && fileStream.good()) { getline(fileStream, line); } while (line.find("</library_controllers>") == std::string::npos && fileStream.good()) { if (line.find("<controller id") != std::string::npos) { if ((pos = line.find("-skin\"")) != std::string::npos) { pos = line.find("name="); armatureName = line.substr((pos = line.find_first_of("\"", pos)) + 1, line.find_first_of("\"", pos + 1) - (pos + 1)); break; } } getline(fileStream, line); } while (line.find("<bind_shape_matrix>") == std::string::npos && fileStream.good()) { getline(fileStream, line); } { std::string::iterator begIt = line.begin() + (pos = line.find_first_of(">")) + 1; std::string::iterator endIt = line.begin() + line.find_first_of("<", pos + 1); std::vector<float> matrixValues; split(begIt, endIt, ' ', matrixValues); for (unsigned int i = 0; i < 16; i++) bindShapeMatrix[i / 4][i % 4] = matrixValues[i]; bindShapeMatrix = glm::transpose(bindShapeMatrix); } //load vertex weights while (fileStream.good()) { getline(fileStream, line); if ((pos = line.find("<source id=")) != std::string::npos) { getline(fileStream, line); std::string::iterator begIt = line.begin() + (pos = line.find_first_of(">")) + 1; std::string::iterator endIt = line.begin() + line.find_first_of("<", pos + 1); if ((pos = line.find("-bind_poses-array")) != std::string::npos) { std::vector<float> matrixValues; matrixValues.reserve(atoi(line.substr((pos = line.find("count=\"")) + 7, line.find_first_of("\"", pos + 1) - (pos + 1)).c_str())); split(begIt, endIt, ' ', matrixValues); for (unsigned int i = 0; i < matrixValues.size(); i++) { glm::mat4 m; for (int j = 0; j < 16; j++) { m[j / 4][j % 4] = matrixValues[i]; i++; } i--; bindPoses.push_back(m); } } else if ((pos = line.find("-weights-array")) != std::string::npos) { w.reserve(atoi(line.substr((pos = line.find("count=\"")) + 7, line.find_first_of("\"", pos + 1) - (pos + 1)).c_str())); split(begIt, endIt, ' ', w); } } else if (line.find("<vertex_weights") != std::string::npos) break; } int weightsCount = atoi(line.substr((pos = line.find("count=\"")) + 7, line.find_first_of("\"", pos + 1) - (pos + 1)).c_str()); while (line.find("<vcount>") == std::string::npos && fileStream.good()) { getline(fileStream, line); } std::string::iterator begIt = line.begin() + (pos = line.find_first_of(">")) + 1; std::string::iterator endIt = line.begin() + line.find_first_of("<", pos + 1); vcount.reserve(weightsCount); split(begIt, endIt, ' ', vcount); while (line.find("<v>") == std::string::npos && fileStream.good()) { getline(fileStream, line); } begIt = line.begin() + (pos = line.find_first_of(">")) + 1; endIt = line.begin() + line.find_first_of("<", pos + 1); std::vector<int> weights; weights.reserve(weightsCount); split(begIt, endIt, ' ', weights); int k = 0; weightJoints.reserve(vcount.size()); weightWeights.reserve(vcount.size()); for (unsigned int i = 0; i < vcount.size(); i++) { weightJoints.push_back(std::vector<int>()); weightJoints.back().reserve(vcount[i]); weightWeights.push_back(std::vector<int>()); weightWeights.back().reserve(vcount[i]); for (int j = 0; j < vcount[i]; j++) { weightJoints[i].push_back(weights[k]); k++; weightWeights[i].push_back(weights[k]); k++; } } while (line.find("<library_visual_scenes>") == std::string::npos && fileStream.good()) { getline(fileStream, line); } while (line.find("node id=\"" + armatureName + "\"") == std::string::npos && fileStream.good()) { getline(fileStream, line); } getline(fileStream, line); { std::string::iterator begIt = line.begin() + (pos = line.find_first_of(">")) + 1; std::string::iterator endIt = line.begin() + line.find_first_of("<", pos + 1); std::vector<float> mat; mat.reserve(16); split(begIt, endIt, ' ', mat); glm::mat4 m; for (unsigned int i = 0; i < 16; i++) m[i / 4][i % 4] = mat[i]; s.setRootTransformMatrix(glm::transpose(m)); } s.setBonesNumber(bindPoses.size()); //load skeleton while (fileStream.good()) { getline(fileStream, line); if (line.find("</node>") != std::string::npos) { int last = findLastOpen(closed); if (last < 0) break; closed[last] = true;; } else if ((pos = line.find("<node id=")) != std::string::npos) { int parent = findLastOpen(closed); std::string name = line.substr((pos = line.find_first_of("\"")) + 1, line.find_first_of("\"", pos + 1) - (pos + 1)); getline(fileStream, line); std::string::iterator begIt = line.begin() + (pos = line.find_first_of(">")) + 1; std::string::iterator endIt = line.begin() + line.find_first_of("<", pos + 1); std::vector<float> mat; mat.reserve(16); split(begIt, endIt, ' ', mat); glm::mat4 m; for (unsigned int i = 0; i < 16; i++) m[i / 4][i % 4] = mat[i]; s.addBone(glm::transpose(m), findLastOpen(closed)); closed.push_back(false); } } if (!fileStream.good()) { std::cout << "File is in incorrect format " << path << std::endl; return false; } //add inverse bind pose matrices for (unsigned int i = 0; i < bindPoses.size(); i++) { s.getBone(i)->inverseBindMatrix = glm::transpose(bindPoses[i]) * bindShapeMatrix; } s.fixScale(); //sort weights std::vector<std::vector<float> > wSorted; std::vector<std::vector<int> > jSorted; wSorted.reserve(weightJoints.size()); jSorted.reserve(weightJoints.size()); for (unsigned int i = 0; i < weightJoints.size(); i++) { wSorted.push_back(std::vector<float>()); wSorted.back().reserve(weightJoints[i].size()); jSorted.push_back(std::vector<int>()); jSorted.back().reserve(weightJoints[i].size()); for (unsigned int j = 0; j < weightJoints[i].size(); j++) { if (j == 0) { wSorted[i].push_back(w[weightWeights[i][j]]); jSorted[i].push_back(weightJoints[i][j]); } else { for (unsigned int k = 0; k < wSorted[i].size(); k++) { if (w[weightWeights[i][j]] > wSorted[i][k]) { wSorted[i].insert(wSorted[i].begin() + k, w[weightWeights[i][j]]); jSorted[i].insert(jSorted[i].begin() + k, weightJoints[i][j]); break; } if (k == wSorted[i].size() - 1) { wSorted[i].push_back(w[weightWeights[i][j]]); jSorted[i].push_back(weightJoints[i][j]); break; } } } } } for (unsigned int i = 0; i < wSorted.size(); i++) { if (wSorted[i].size() > 4) { for (unsigned int j = wSorted[i].size() - 1; j > 3; j--) { for (int k = 0; k < 4; k++) wSorted[i][k] += wSorted[i][j] * 0.25f; wSorted[i].erase(wSorted[i].begin() + j); jSorted[i].erase(jSorted[i].begin() + j); } } } //push in faces for (unsigned int k = 0; k < indices.size(); k++) { WeightedMesh mesh; mesh.reserve(indices[k].size()); for (unsigned int i = 0; i < indices[k].size(); i += 3) { glm::vec3 vertex, normal; glm::vec2 texCoord; glm::vec4 weights; glm::ivec4 joints; vertex.x = v[indices[k][i] * 3]; vertex.y = v[indices[k][i] * 3 + 1]; vertex.z = v[indices[k][i] * 3 + 2]; weights = glm::vec4(0.0f); joints = glm::ivec4(0); for (unsigned int j = 0; j < wSorted[indices[k][i]].size(); j++) { weights[j] = wSorted[indices[k][i]][j]; joints[j] = jSorted[indices[k][i]][j]; } normal.x = n[indices[k][i + 1] * 3]; normal.y = n[indices[k][i + 1] * 3 + 1]; normal.z = n[indices[k][i + 1] * 3 + 2]; if (t.size() > 0) { texCoord.x = t[indices[k][i + 2] * 2]; texCoord.y = 1.0f - t[indices[k][i + 2] * 2 + 1]; //OpenGL coords } else texCoord = glm::vec2(0.0f); mesh.addVertex(vertex, normal, texCoord, weights, joints); } std::shared_ptr<Material> mat(new Material); Texture tex; if (!loadTexture(std::string("resource/").append(polylistMaterials[k].append("_D.png")).c_str(), tex)) { if (!loadTexture("resource/white_D.png", tex)) return false; } mat->setDifTex(tex); mesh.addMaterial(mat); m.addMesh(std::make_shared<WeightedMesh>(mesh)); } fileStream.close(); return true; } std::cout << "Unable to open file " << path << std::endl; return false; }