Showing the changes to libraries/render-utils/src/Model.cpp (1 of 19 files). Show all
Unified · Split
| @@ -60,7 +60,7 @@ static int weakNetworkGeometryPointerTypeId = qRegisterMetaType<QWeakPointer<Net · 59 unmodified lines | ||
| 60 | 60 | static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >(); |
| 61 | 61 | float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; |
| 62 | 62 | |
| 63 | −Model::Model(QObject* parent, RigPointer rig) : | |
| 63 | +Model::Model(RigPointer rig, QObject* parent) : | |
| 64 | 64 | QObject(parent), |
| 65 | 65 | _scale(1.0f, 1.0f, 1.0f), |
| 66 | 66 | _scaleToFit(false), |
| @@ -87,7 +87,7 @@ Model::Model(QObject* parent, RigPointer rig) : · 20 unmodified lines | ||
| 87 | 87 | if (_viewState) { |
| 88 | 88 | moveToThread(_viewState->getMainThread()); |
| 89 | 89 | } |
| 90 | − | |
| 90 | + | |
| 91 | 91 | setSnapModelToRegistrationPoint(true, glm::vec3(0.5f)); |
| 92 | 92 | } |
| 93 | 93 | |
| @@ -252,22 +252,9 @@ QVector<JointState> Model::createJointStates(const FBXGeometry& geometry) { · 158 unmodified lines | ||
| 252 | 252 | }; |
| 253 | 253 | |
| 254 | 254 | void Model::initJointTransforms() { |
| 255 | − // compute model transforms | |
| 256 | − int numStates = _jointStates.size(); | |
| 257 | − for (int i = 0; i < numStates; ++i) { | |
| 258 | − JointState& state = _jointStates[i]; | |
| 259 | − const FBXJoint& joint = state.getFBXJoint(); | |
| 260 | − int parentIndex = joint.parentIndex; | |
| 261 | − if (parentIndex == -1) { | |
| 262 | − const FBXGeometry& geometry = _geometry->getFBXGeometry(); | |
| 263 | − // NOTE: in practice geometry.offset has a non-unity scale (rather than a translation) | |
| 264 | − glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; | |
| 265 | − state.initTransform(parentTransform); | |
| 266 | − } else { | |
| 267 | − const JointState& parentState = _jointStates.at(parentIndex); | |
| 268 | − state.initTransform(parentState.getTransform()); | |
| 269 | − } | |
| 270 | − } | |
| 255 | + const FBXGeometry& geometry = _geometry->getFBXGeometry(); | |
| 256 | + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; | |
| 257 | + _rig->initJointTransforms(parentTransform); | |
| 271 | 258 | } |
| 272 | 259 | |
| 273 | 260 | void Model::init() { |
| @@ -396,14 +383,8 @@ void Model::init() { · 122 unmodified lines | ||
| 396 | 383 | } |
| 397 | 384 | |
| 398 | 385 | void Model::reset() { |
| 399 | − if (_jointStates.isEmpty()) { | |
| 400 | − return; | |
| 401 | − } | |
| 402 | 386 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); |
| 403 | − for (int i = 0; i < _jointStates.size(); i++) { | |
| 404 | − _jointStates[i].setRotationInConstrainedFrame(geometry.joints.at(i).rotation, 0.0f); | |
| 405 | − } | |
| 406 | − | |
| 387 | + _rig->reset(geometry.joints); | |
| 407 | 388 | _meshGroupsKnown = false; |
| 408 | 389 | _readyWhenAdded = false; // in case any of our users are using scenes |
| 409 | 390 | invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid |
| @@ -436,28 +417,30 @@ bool Model::updateGeometry() { · 26 unmodified lines | ||
| 436 | 417 | |
| 437 | 418 | const FBXGeometry& newGeometry = geometry->getFBXGeometry(); |
| 438 | 419 | QVector<JointState> newJointStates = createJointStates(newGeometry); |
| 439 | − if (! _jointStates.isEmpty()) { | |
| 420 | + | |
| 421 | + if (! _rig->jointStatesEmpty()) { | |
| 440 | 422 | // copy the existing joint states |
| 441 | 423 | const FBXGeometry& oldGeometry = _geometry->getFBXGeometry(); |
| 442 | 424 | for (QHash<QString, int>::const_iterator it = oldGeometry.jointIndices.constBegin(); |
| 443 | − it != oldGeometry.jointIndices.constEnd(); it++) { | |
| 425 | + it != oldGeometry.jointIndices.constEnd(); it++) { | |
| 444 | 426 | int oldIndex = it.value() - 1; |
| 445 | 427 | int newIndex = newGeometry.getJointIndex(it.key()); |
| 446 | 428 | if (newIndex != -1) { |
| 447 | − newJointStates[newIndex].copyState(_jointStates[oldIndex]); | |
| 429 | + newJointStates[newIndex].copyState(_rig->getJointState(oldIndex)); | |
| 448 | 430 | } |
| 449 | 431 | } |
| 450 | − } | |
| 432 | + } | |
| 433 | + | |
| 451 | 434 | deleteGeometry(); |
| 452 | 435 | _dilatedTextures.clear(); |
| 453 | 436 | setGeometry(geometry); |
| 454 | − | |
| 437 | + | |
| 455 | 438 | _meshGroupsKnown = false; |
| 456 | 439 | _readyWhenAdded = false; // in case any of our users are using scenes |
| 457 | 440 | invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid |
| 458 | 441 | initJointStates(newJointStates); |
| 459 | 442 | needToRebuild = true; |
| 460 | − } else if (_jointStates.isEmpty()) { | |
| 443 | + } else if (_rig->jointStatesEmpty()) { | |
| 461 | 444 | const FBXGeometry& fbxGeometry = geometry->getFBXGeometry(); |
| 462 | 445 | if (fbxGeometry.joints.size() > 0) { |
| 463 | 446 | initJointStates(createJointStates(fbxGeometry)); |
| @@ -493,22 +476,9 @@ bool Model::updateGeometry() { · 29 unmodified lines | ||
| 493 | 476 | |
| 494 | 477 | // virtual |
| 495 | 478 | void Model::initJointStates(QVector<JointState> states) { |
| 496 | − _jointStates = states; | |
| 497 | − initJointTransforms(); | |
| 498 | − | |
| 499 | − int numStates = _jointStates.size(); | |
| 500 | − float radius = 0.0f; | |
| 501 | − for (int i = 0; i < numStates; ++i) { | |
| 502 | − float distance = glm::length(_jointStates[i].getPosition()); | |
| 503 | − if (distance > radius) { | |
| 504 | − radius = distance; | |
| 505 | − } | |
| 506 | − _jointStates[i].buildConstraint(); | |
| 507 | − } | |
| 508 | − for (int i = 0; i < _jointStates.size(); i++) { | |
| 509 | − _jointStates[i].slaveVisibleTransform(); | |
| 510 | − } | |
| 511 | − _boundingRadius = radius; | |
| 479 | + const FBXGeometry& geometry = _geometry->getFBXGeometry(); | |
| 480 | + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; | |
| 481 | + _boundingRadius = _rig->initJointStates(states, parentTransform); | |
| 512 | 482 | } |
| 513 | 483 | |
| 514 | 484 | bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, |
| @@ -1070,51 +1040,24 @@ glm::vec3 Model::calculateScaledOffsetPoint(const glm::vec3& point) const { · 555 unmodified lines | ||
| 1070 | 1040 | return translatedPoint; |
| 1071 | 1041 | } |
| 1072 | 1042 | |
| 1073 | − | |
| 1074 | 1043 | bool Model::getJointState(int index, glm::quat& rotation) const { |
| 1075 | − if (index == -1 || index >= _jointStates.size()) { | |
| 1076 | − return false; | |
| 1077 | − } | |
| 1078 | − const JointState& state = _jointStates.at(index); | |
| 1079 | − rotation = state.getRotationInConstrainedFrame(); | |
| 1080 | − return !state.rotationIsDefault(rotation); | |
| 1044 | + return _rig->getJointStateRotation(index, rotation); | |
| 1081 | 1045 | } |
| 1082 | 1046 | |
| 1083 | 1047 | bool Model::getVisibleJointState(int index, glm::quat& rotation) const { |
| 1084 | − if (index == -1 || index >= _jointStates.size()) { | |
| 1085 | − return false; | |
| 1086 | − } | |
| 1087 | − const JointState& state = _jointStates.at(index); | |
| 1088 | − rotation = state.getVisibleRotationInConstrainedFrame(); | |
| 1089 | − return !state.rotationIsDefault(rotation); | |
| 1048 | + return _rig->getVisibleJointState(index, rotation); | |
| 1090 | 1049 | } |
| 1091 | 1050 | |
| 1092 | 1051 | void Model::clearJointState(int index) { |
| 1093 | − if (index != -1 && index < _jointStates.size()) { | |
| 1094 | − JointState& state = _jointStates[index]; | |
| 1095 | − state.setRotationInConstrainedFrame(glm::quat(), 0.0f); | |
| 1096 | − } | |
| 1052 | + _rig->clearJointState(index); | |
| 1097 | 1053 | } |
| 1098 | 1054 | |
| 1099 | 1055 | void Model::clearJointAnimationPriority(int index) { |
| 1100 | − if (_rig) { | |
| 1101 | − _rig->clearJointAnimationPriority(index); | |
| 1102 | − } else { | |
| 1103 | − if (index != -1 && index < _jointStates.size()) { | |
| 1104 | − _jointStates[index]._animationPriority = 0.0f; | |
| 1105 | − } | |
| 1106 | − } | |
| 1056 | + _rig->clearJointAnimationPriority(index); | |
| 1107 | 1057 | } |
| 1108 | 1058 | |
| 1109 | 1059 | void Model::setJointState(int index, bool valid, const glm::quat& rotation, float priority) { |
| 1110 | − if (index != -1 && index < _jointStates.size()) { | |
| 1111 | − JointState& state = _jointStates[index]; | |
| 1112 | − if (valid) { | |
| 1113 | − state.setRotationInConstrainedFrame(rotation, priority); | |
| 1114 | − } else { | |
| 1115 | − state.restoreRotation(1.0f, priority); | |
| 1116 | − } | |
| 1117 | − } | |
| 1060 | + _rig->setJointState(index, valid, rotation, priority); | |
| 1118 | 1061 | } |
| 1119 | 1062 | |
| 1120 | 1063 | int Model::getParentJointIndex(int jointIndex) const { |
| @@ -1189,62 +1132,31 @@ void Model::setCollisionModelURL(const QUrl& url) { · 68 unmodified lines | ||
| 1189 | 1132 | } |
| 1190 | 1133 | |
| 1191 | 1134 | bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const { |
| 1192 | − if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | |
| 1193 | − return false; | |
| 1194 | − } | |
| 1195 | − // position is in world-frame | |
| 1196 | − position = _translation + _rotation * _jointStates[jointIndex].getPosition(); | |
| 1197 | − return true; | |
| 1135 | + return _rig->getJointPositionInWorldFrame(jointIndex, position, _translation, _rotation); | |
| 1198 | 1136 | } |
| 1199 | 1137 | |
| 1200 | 1138 | bool Model::getJointPosition(int jointIndex, glm::vec3& position) const { |
| 1201 | − if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | |
| 1202 | − return false; | |
| 1203 | − } | |
| 1204 | − // position is in model-frame | |
| 1205 | − position = extractTranslation(_jointStates[jointIndex].getTransform()); | |
| 1206 | − return true; | |
| 1139 | + return _rig->getJointPosition(jointIndex, position); | |
| 1207 | 1140 | } |
| 1208 | 1141 | |
| 1209 | 1142 | bool Model::getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const { |
| 1210 | − if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | |
| 1211 | − return false; | |
| 1212 | − } | |
| 1213 | − rotation = _rotation * _jointStates[jointIndex].getRotation(); | |
| 1214 | − return true; | |
| 1143 | + return _rig->getJointRotationInWorldFrame(jointIndex, rotation, _rotation); | |
| 1215 | 1144 | } |
| 1216 | 1145 | |
| 1217 | 1146 | bool Model::getJointRotation(int jointIndex, glm::quat& rotation) const { |
| 1218 | − if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | |
| 1219 | − return false; | |
| 1220 | − } | |
| 1221 | − rotation = _jointStates[jointIndex].getRotation(); | |
| 1222 | − return true; | |
| 1147 | + return _rig->getJointRotation(jointIndex, rotation); | |
| 1223 | 1148 | } |
| 1224 | 1149 | |
| 1225 | 1150 | bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const { |
| 1226 | − if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | |
| 1227 | − return false; | |
| 1228 | − } | |
| 1229 | − rotation = _rotation * _jointStates[jointIndex].getRotation(); | |
| 1230 | − return true; | |
| 1151 | + return _rig->getJointCombinedRotation(jointIndex, rotation, _rotation); | |
| 1231 | 1152 | } |
| 1232 | 1153 | |
| 1233 | 1154 | bool Model::getVisibleJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const { |
| 1234 | − if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | |
| 1235 | − return false; | |
| 1236 | − } | |
| 1237 | − // position is in world-frame | |
| 1238 | − position = _translation + _rotation * _jointStates[jointIndex].getVisiblePosition(); | |
| 1239 | − return true; | |
| 1155 | + return _rig->getVisibleJointPositionInWorldFrame(jointIndex, position, _translation, _rotation); | |
| 1240 | 1156 | } |
| 1241 | 1157 | |
| 1242 | 1158 | bool Model::getVisibleJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const { |
| 1243 | − if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | |
| 1244 | − return false; | |
| 1245 | − } | |
| 1246 | − rotation = _rotation * _jointStates[jointIndex].getVisibleRotation(); | |
| 1247 | − return true; | |
| 1159 | + return _rig->getVisibleJointRotationInWorldFrame(jointIndex, rotation, _rotation); | |
| 1248 | 1160 | } |
| 1249 | 1161 | |
| 1250 | 1162 | QStringList Model::getJointNames() const { |
| @@ -1438,12 +1350,14 @@ void Model::updateClusterMatrices() { · 187 unmodified lines | ||
| 1438 | 1350 | if (_showTrueJointTransforms) { |
| 1439 | 1351 | for (int j = 0; j < mesh.clusters.size(); j++) { |
| 1440 | 1352 | const FBXCluster& cluster = mesh.clusters.at(j); |
| 1441 | − state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getTransform() * cluster.inverseBindMatrix; | |
| 1353 | + state.clusterMatrices[j] = | |
| 1354 | + modelToWorld * _rig->getJointTransform(cluster.jointIndex) * cluster.inverseBindMatrix; | |
| 1442 | 1355 | } |
| 1443 | 1356 | } else { |
| 1444 | 1357 | for (int j = 0; j < mesh.clusters.size(); j++) { |
| 1445 | 1358 | const FBXCluster& cluster = mesh.clusters.at(j); |
| 1446 | − state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getVisibleTransform() * cluster.inverseBindMatrix; | |
| 1359 | + state.clusterMatrices[j] = | |
| 1360 | + modelToWorld * _rig->getJointVisibleTransform(cluster.jointIndex) * cluster.inverseBindMatrix; | |
| 1447 | 1361 | } |
| 1448 | 1362 | } |
| 1449 | 1363 | } |
| @@ -1457,16 +1371,12 @@ void Model::simulateInternal(float deltaTime) { · 7 unmodified lines | ||
| 1457 | 1371 | handle->simulate(deltaTime); |
| 1458 | 1372 | } |
| 1459 | 1373 | |
| 1460 | − for (int i = 0; i < _jointStates.size(); i++) { | |
| 1461 | − updateJointState(i); | |
| 1462 | − } | |
| 1463 | − for (int i = 0; i < _jointStates.size(); i++) { | |
| 1464 | − _jointStates[i].resetTransformChanged(); | |
| 1465 | − } | |
| 1374 | + const FBXGeometry& geometry = _geometry->getFBXGeometry(); | |
| 1375 | + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; | |
| 1376 | + _rig->simulateInternal(parentTransform); | |
| 1466 | 1377 | |
| 1467 | 1378 | _shapesAreDirty = !_shapes.isEmpty(); |
| 1468 | 1379 | |
| 1469 | − const FBXGeometry& geometry = _geometry->getFBXGeometry(); | |
| 1470 | 1380 | glm::mat4 modelToWorld = glm::mat4_cast(_rotation); |
| 1471 | 1381 | for (int i = 0; i < _meshStates.size(); i++) { |
| 1472 | 1382 | MeshState& state = _meshStates[i]; |
| @@ -1474,12 +1384,14 @@ void Model::simulateInternal(float deltaTime) { · 1 unmodified line | ||
| 1474 | 1384 | if (_showTrueJointTransforms) { |
| 1475 | 1385 | for (int j = 0; j < mesh.clusters.size(); j++) { |
| 1476 | 1386 | const FBXCluster& cluster = mesh.clusters.at(j); |
| 1477 | − state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getTransform() * cluster.inverseBindMatrix; | |
| 1387 | + state.clusterMatrices[j] = | |
| 1388 | + modelToWorld * _rig->getJointTransform(cluster.jointIndex) * cluster.inverseBindMatrix; | |
| 1478 | 1389 | } |
| 1479 | 1390 | } else { |
| 1480 | 1391 | for (int j = 0; j < mesh.clusters.size(); j++) { |
| 1481 | 1392 | const FBXCluster& cluster = mesh.clusters.at(j); |
| 1482 | − state.clusterMatrices[j] = modelToWorld * _jointStates[cluster.jointIndex].getVisibleTransform() * cluster.inverseBindMatrix; | |
| 1393 | + state.clusterMatrices[j] = | |
| 1394 | + modelToWorld * _rig->getJointVisibleTransform(cluster.jointIndex) * cluster.inverseBindMatrix; | |
| 1483 | 1395 | } |
| 1484 | 1396 | } |
| 1485 | 1397 | } |
| @@ -1492,261 +1404,42 @@ void Model::simulateInternal(float deltaTime) { · 6 unmodified lines | ||
| 1492 | 1404 | } |
| 1493 | 1405 | |
| 1494 | 1406 | void Model::updateJointState(int index) { |
| 1495 | − JointState& state = _jointStates[index]; | |
| 1496 | − const FBXJoint& joint = state.getFBXJoint(); | |
| 1497 | − | |
| 1498 | − // compute model transforms | |
| 1499 | − int parentIndex = joint.parentIndex; | |
| 1500 | − if (parentIndex == -1) { | |
| 1501 | − const FBXGeometry& geometry = _geometry->getFBXGeometry(); | |
| 1502 | − glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; | |
| 1503 | − state.computeTransform(parentTransform); | |
| 1504 | − } else { | |
| 1505 | − // guard against out-of-bounds access to _jointStates | |
| 1506 | − if (joint.parentIndex >= 0 && joint.parentIndex < _jointStates.size()) { | |
| 1507 | − const JointState& parentState = _jointStates.at(parentIndex); | |
| 1508 | − state.computeTransform(parentState.getTransform(), parentState.getTransformChanged()); | |
| 1509 | − } | |
| 1510 | − } | |
| 1511 | −} | |
| 1512 | − | |
| 1513 | −void Model::updateVisibleJointStates() { | |
| 1514 | − if (_showTrueJointTransforms) { | |
| 1515 | − // no need to update visible transforms | |
| 1516 | − return; | |
| 1517 | − } | |
| 1518 | − for (int i = 0; i < _jointStates.size(); i++) { | |
| 1519 | − _jointStates[i].slaveVisibleTransform(); | |
| 1520 | − } | |
| 1407 | + const FBXGeometry& geometry = _geometry->getFBXGeometry(); | |
| 1408 | + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; | |
| 1409 | + _rig->updateJointState(index, parentTransform); | |
| 1521 | 1410 | } |
| 1522 | 1411 | |
| 1523 | 1412 | bool Model::setJointPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, bool useRotation, |
| 1524 | − int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority) { | |
| 1525 | − if (jointIndex == -1 || _jointStates.isEmpty()) { | |
| 1526 | − return false; | |
| 1527 | − } | |
| 1413 | + int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority) { | |
| 1528 | 1414 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); |
| 1529 | 1415 | const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage; |
| 1530 | − if (freeLineage.isEmpty()) { | |
| 1531 | − return false; | |
| 1532 | − } | |
| 1533 | − if (lastFreeIndex == -1) { | |
| 1534 | − lastFreeIndex = freeLineage.last(); | |
| 1535 | − } | |
| 1536 | − | |
| 1537 | − // this is a cyclic coordinate descent algorithm: see | |
| 1538 | − // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d | |
| 1539 | − const int ITERATION_COUNT = 1; | |
| 1540 | − glm::vec3 worldAlignment = alignment; | |
| 1541 | − for (int i = 0; i < ITERATION_COUNT; i++) { | |
| 1542 | − // first, try to rotate the end effector as close as possible to the target rotation, if any | |
| 1543 | − glm::quat endRotation; | |
| 1544 | − if (useRotation) { | |
| 1545 | − JointState& state = _jointStates[jointIndex]; | |
| 1546 | − | |
| 1547 | − state.setRotationInBindFrame(rotation, priority); | |
| 1548 | − endRotation = state.getRotationInBindFrame(); | |
| 1549 | − } | |
| 1550 | − | |
| 1551 | − // then, we go from the joint upwards, rotating the end as close as possible to the target | |
| 1552 | − glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].getTransform()); | |
| 1553 | − for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { | |
| 1554 | − int index = freeLineage.at(j); | |
| 1555 | − JointState& state = _jointStates[index]; | |
| 1556 | − const FBXJoint& joint = state.getFBXJoint(); | |
| 1557 | − if (!(joint.isFree || allIntermediatesFree)) { | |
| 1558 | − continue; | |
| 1559 | − } | |
| 1560 | − glm::vec3 jointPosition = extractTranslation(state.getTransform()); | |
| 1561 | − glm::vec3 jointVector = endPosition - jointPosition; | |
| 1562 | − glm::quat oldCombinedRotation = state.getRotation(); | |
| 1563 | − glm::quat combinedDelta; | |
| 1564 | − float combinedWeight; | |
| 1565 | − if (useRotation) { | |
| 1566 | − combinedDelta = safeMix(rotation * glm::inverse(endRotation), | |
| 1567 | − rotationBetween(jointVector, position - jointPosition), 0.5f); | |
| 1568 | − combinedWeight = 2.0f; | |
| 1569 | − | |
| 1570 | − } else { | |
| 1571 | − combinedDelta = rotationBetween(jointVector, position - jointPosition); | |
| 1572 | − combinedWeight = 1.0f; | |
| 1573 | − } | |
| 1574 | − if (alignment != glm::vec3() && j > 1) { | |
| 1575 | − jointVector = endPosition - jointPosition; | |
| 1576 | − glm::vec3 positionSum; | |
| 1577 | − for (int k = j - 1; k > 0; k--) { | |
| 1578 | − int index = freeLineage.at(k); | |
| 1579 | − updateJointState(index); | |
| 1580 | − positionSum += extractTranslation(_jointStates.at(index).getTransform()); | |
| 1581 | − } | |
| 1582 | − glm::vec3 projectedCenterOfMass = glm::cross(jointVector, | |
| 1583 | − glm::cross(positionSum / (j - 1.0f) - jointPosition, jointVector)); | |
| 1584 | − glm::vec3 projectedAlignment = glm::cross(jointVector, glm::cross(worldAlignment, jointVector)); | |
| 1585 | − const float LENGTH_EPSILON = 0.001f; | |
| 1586 | − if (glm::length(projectedCenterOfMass) > LENGTH_EPSILON && glm::length(projectedAlignment) > LENGTH_EPSILON) { | |
| 1587 | − combinedDelta = safeMix(combinedDelta, rotationBetween(projectedCenterOfMass, projectedAlignment), | |
| 1588 | − 1.0f / (combinedWeight + 1.0f)); | |
| 1589 | − } | |
| 1590 | − } | |
| 1591 | − state.applyRotationDelta(combinedDelta, true, priority); | |
| 1592 | − glm::quat actualDelta = state.getRotation() * glm::inverse(oldCombinedRotation); | |
| 1593 | − endPosition = actualDelta * jointVector + jointPosition; | |
| 1594 | − if (useRotation) { | |
| 1595 | − endRotation = actualDelta * endRotation; | |
| 1596 | − } | |
| 1597 | − } | |
| 1598 | − } | |
| 1599 | − | |
| 1600 | − // now update the joint states from the top | |
| 1601 | − for (int j = freeLineage.size() - 1; j >= 0; j--) { | |
| 1602 | − updateJointState(freeLineage.at(j)); | |
| 1416 | + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; | |
| 1417 | + if (_rig->setJointPosition(jointIndex, position, rotation, useRotation, | |
| 1418 | + lastFreeIndex, allIntermediatesFree, alignment, priority, freeLineage, parentTransform)) { | |
| 1419 | + _shapesAreDirty = !_shapes.isEmpty(); | |
| 1420 | + return true; | |
| 1603 | 1421 | } |
| 1604 | − _shapesAreDirty = !_shapes.isEmpty(); | |
| 1605 | − | |
| 1606 | − return true; | |
| 1422 | + return false; | |
| 1607 | 1423 | } |
| 1608 | 1424 | |
| 1609 | 1425 | void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::quat& targetRotation, float priority) { |
| 1610 | − // NOTE: targetRotation is from bind- to model-frame | |
| 1611 | − | |
| 1612 | − if (endIndex == -1 || _jointStates.isEmpty()) { | |
| 1613 | − return; | |
| 1614 | − } | |
| 1615 | − | |
| 1616 | 1426 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); |
| 1617 | 1427 | const QVector<int>& freeLineage = geometry.joints.at(endIndex).freeLineage; |
| 1618 | − if (freeLineage.isEmpty()) { | |
| 1619 | − return; | |
| 1620 | − } | |
| 1621 | − int numFree = freeLineage.size(); | |
| 1622 | − | |
| 1623 | − // store and remember topmost parent transform | |
| 1624 | − glm::mat4 topParentTransform; | |
| 1625 | − { | |
| 1626 | − int index = freeLineage.last(); | |
| 1627 | − const JointState& state = _jointStates.at(index); | |
| 1628 | − const FBXJoint& joint = state.getFBXJoint(); | |
| 1629 | − int parentIndex = joint.parentIndex; | |
| 1630 | − if (parentIndex == -1) { | |
| 1631 | − const FBXGeometry& geometry = _geometry->getFBXGeometry(); | |
| 1632 | − topParentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; | |
| 1633 | − } else { | |
| 1634 | − topParentTransform = _jointStates[parentIndex].getTransform(); | |
| 1635 | − } | |
| 1636 | − } | |
| 1637 | − | |
| 1638 | − // this is a cyclic coordinate descent algorithm: see | |
| 1639 | − // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d | |
| 1640 | − | |
| 1641 | − // keep track of the position of the end-effector | |
| 1642 | − JointState& endState = _jointStates[endIndex]; | |
| 1643 | − glm::vec3 endPosition = endState.getPosition(); | |
| 1644 | − float distanceToGo = glm::distance(targetPosition, endPosition); | |
| 1645 | − | |
| 1646 | − const int MAX_ITERATION_COUNT = 2; | |
| 1647 | − const float ACCEPTABLE_IK_ERROR = 0.005f; // 5mm | |
| 1648 | − int numIterations = 0; | |
| 1649 | − do { | |
| 1650 | − ++numIterations; | |
| 1651 | − // moving up, rotate each free joint to get endPosition closer to target | |
| 1652 | − for (int j = 1; j < numFree; j++) { | |
| 1653 | − int nextIndex = freeLineage.at(j); | |
| 1654 | − JointState& nextState = _jointStates[nextIndex]; | |
| 1655 | − FBXJoint nextJoint = nextState.getFBXJoint(); | |
| 1656 | − if (! nextJoint.isFree) { | |
| 1657 | − continue; | |
| 1658 | − } | |
| 1659 | − | |
| 1660 | − glm::vec3 pivot = nextState.getPosition(); | |
| 1661 | − glm::vec3 leverArm = endPosition - pivot; | |
| 1662 | − float leverLength = glm::length(leverArm); | |
| 1663 | − if (leverLength < EPSILON) { | |
| 1664 | − continue; | |
| 1665 | − } | |
| 1666 | − glm::quat deltaRotation = rotationBetween(leverArm, targetPosition - pivot); | |
| 1667 | − | |
| 1668 | − // We want to mix the shortest rotation with one that will pull the system down with gravity | |
| 1669 | − // so that limbs don't float unrealistically. To do this we compute a simplified center of mass | |
| 1670 | − // where each joint has unit mass and we don't bother averaging it because we only need direction. | |
| 1671 | − if (j > 1) { | |
| 1672 | − | |
| 1673 | − glm::vec3 centerOfMass(0.0f); | |
| 1674 | − for (int k = 0; k < j; ++k) { | |
| 1675 | − int massIndex = freeLineage.at(k); | |
| 1676 | − centerOfMass += _jointStates[massIndex].getPosition() - pivot; | |
| 1677 | − } | |
| 1678 | − // the gravitational effect is a rotation that tends to align the two cross products | |
| 1679 | − const glm::vec3 worldAlignment = glm::vec3(0.0f, -1.0f, 0.0f); | |
| 1680 | − glm::quat gravityDelta = rotationBetween(glm::cross(centerOfMass, leverArm), | |
| 1681 | − glm::cross(worldAlignment, leverArm)); | |
| 1682 | − | |
| 1683 | − float gravityAngle = glm::angle(gravityDelta); | |
| 1684 | − const float MIN_GRAVITY_ANGLE = 0.1f; | |
| 1685 | − float mixFactor = 0.5f; | |
| 1686 | − if (gravityAngle < MIN_GRAVITY_ANGLE) { | |
| 1687 | − // the final rotation is a mix of the two | |
| 1688 | − mixFactor = 0.5f * gravityAngle / MIN_GRAVITY_ANGLE; | |
| 1689 | − } | |
| 1690 | − deltaRotation = safeMix(deltaRotation, gravityDelta, mixFactor); | |
| 1691 | − } | |
| 1692 | − | |
| 1693 | − // Apply the rotation, but use mixRotationDelta() which blends a bit of the default pose | |
| 1694 | − // in the process. This provides stability to the IK solution for most models. | |
| 1695 | − glm::quat oldNextRotation = nextState.getRotation(); | |
| 1696 | − float mixFactor = 0.03f; | |
| 1697 | − nextState.mixRotationDelta(deltaRotation, mixFactor, priority); | |
| 1698 | − | |
| 1699 | − // measure the result of the rotation which may have been modified by | |
| 1700 | − // blending and constraints | |
| 1701 | − glm::quat actualDelta = nextState.getRotation() * glm::inverse(oldNextRotation); | |
| 1702 | − endPosition = pivot + actualDelta * leverArm; | |
| 1703 | − } | |
| 1704 | − | |
| 1705 | − // recompute transforms from the top down | |
| 1706 | − glm::mat4 parentTransform = topParentTransform; | |
| 1707 | − for (int j = numFree - 1; j >= 0; --j) { | |
| 1708 | − JointState& freeState = _jointStates[freeLineage.at(j)]; | |
| 1709 | − freeState.computeTransform(parentTransform); | |
| 1710 | − parentTransform = freeState.getTransform(); | |
| 1711 | − } | |
| 1712 | − | |
| 1713 | − // measure our success | |
| 1714 | − endPosition = endState.getPosition(); | |
| 1715 | − distanceToGo = glm::distance(targetPosition, endPosition); | |
| 1716 | − } while (numIterations < MAX_ITERATION_COUNT && distanceToGo < ACCEPTABLE_IK_ERROR); | |
| 1717 | − | |
| 1718 | − // set final rotation of the end joint | |
| 1719 | − endState.setRotationInBindFrame(targetRotation, priority, true); | |
| 1720 | − | |
| 1428 | + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; | |
| 1429 | + _rig->inverseKinematics(endIndex, targetPosition, targetRotation, priority, freeLineage, parentTransform); | |
| 1721 | 1430 | _shapesAreDirty = !_shapes.isEmpty(); |
| 1722 | 1431 | } |
| 1723 | 1432 | |
| 1724 | 1433 | bool Model::restoreJointPosition(int jointIndex, float fraction, float priority) { |
| 1725 | − if (jointIndex == -1 || _jointStates.isEmpty()) { | |
| 1726 | − return false; | |
| 1727 | − } | |
| 1728 | 1434 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); |
| 1729 | 1435 | const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage; |
| 1730 | − | |
| 1731 | − foreach (int index, freeLineage) { | |
| 1732 | − JointState& state = _jointStates[index]; | |
| 1733 | − state.restoreRotation(fraction, priority); | |
| 1734 | − } | |
| 1735 | − return true; | |
| 1436 | + return _rig->restoreJointPosition(jointIndex, fraction, priority, freeLineage); | |
| 1736 | 1437 | } |
| 1737 | 1438 | |
| 1738 | 1439 | float Model::getLimbLength(int jointIndex) const { |
| 1739 | − if (jointIndex == -1 || _jointStates.isEmpty()) { | |
| 1740 | − return 0.0f; | |
| 1741 | − } | |
| 1742 | 1440 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); |
| 1743 | 1441 | const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage; |
| 1744 | − float length = 0.0f; | |
| 1745 | − float lengthScale = (_scale.x + _scale.y + _scale.z) / 3.0f; | |
| 1746 | − for (int i = freeLineage.size() - 2; i >= 0; i--) { | |
| 1747 | − length += geometry.joints.at(freeLineage.at(i)).distanceToParent * lengthScale; | |
| 1748 | − } | |
| 1749 | − return length; | |
| 1442 | + return _rig->getLimbLength(jointIndex, freeLineage, _scale, geometry.joints); | |
| 1750 | 1443 | } |
| 1751 | 1444 | |
| 1752 | 1445 | void Model::renderJointCollisionShapes(float alpha) { |
| @@ -1816,7 +1509,7 @@ void Model::applyNextGeometry() { · 63 unmodified lines | ||
| 1816 | 1509 | |
| 1817 | 1510 | void Model::deleteGeometry() { |
| 1818 | 1511 | _blendedVertexBuffers.clear(); |
| 1819 | − _jointStates.clear(); | |
| 1512 | + _rig->clearJointStates(); | |
| 1820 | 1513 | _meshStates.clear(); |
| 1821 | 1514 | clearShapes(); |
| 1822 | 1515 | |
| @@ -1945,7 +1638,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran · 122 unmodified lines | ||
| 1945 | 1638 | args, locations); |
| 1946 | 1639 | |
| 1947 | 1640 | { |
| 1948 | − updateVisibleJointStates(); | |
| 1641 | + if (!_showTrueJointTransforms) { | |
| 1642 | + _rig->updateVisibleJointStates(); | |
| 1643 | + } // else no need to update visible transforms | |
| 1949 | 1644 | } |
| 1950 | 1645 | |
| 1951 | 1646 | // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown |