Showing the changes to libraries/render-utils/src/Model.cpp (1 of 8 files). Show all
Unified · Split
| @@ -353,31 +353,27 @@ void Model::initJointStates() { · 352 unmodified lines | |||
| 353 | bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, | 353 | bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, |
| 354 | BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, | 354 | BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, |
| 355 | bool pickAgainstTriangles, bool allowBackface) { | 355 | bool pickAgainstTriangles, bool allowBackface) { |
| 356 | |||
| 357 | bool intersectedSomething = false; | 356 | bool intersectedSomething = false; |
| 358 | 357 | ||
| 359 | // if we aren't active, we can't ray pick yet... | 358 | // if we aren't active, we can't pick yet... |
| 360 | if (!isActive()) { | 359 | if (!isActive()) { |
| 361 | return intersectedSomething; | 360 | return intersectedSomething; |
| 362 | } | 361 | } |
| 363 | 362 | ||
| 364 | // extents is the entity relative, scaled, centered extents of the entity | 363 | // extents is the entity relative, scaled, centered extents of the entity |
| 365 | glm::vec3 position = _translation; | 364 | glm::mat4 modelToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation); |
| 366 | glm::mat4 rotation = glm::mat4_cast(_rotation); | ||
| 367 | glm::mat4 translation = glm::translate(position); | ||
| 368 | glm::mat4 modelToWorldMatrix = translation * rotation; | ||
| 369 | glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); | 365 | glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); |
| 370 | 366 | ||
| 371 | Extents modelExtents = getMeshExtents(); // NOTE: unrotated | 367 | Extents modelExtents = getMeshExtents(); // NOTE: unrotated |
| 372 | 368 | ||
| 373 | glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; | 369 | glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; |
| 374 | glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the ray picking in the model frame of reference | 370 | glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the picking in the model frame of reference |
| 375 | AABox modelFrameBox(corner, dimensions); | 371 | AABox modelFrameBox(corner, dimensions); |
| 376 | 372 | ||
| 377 | glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); | 373 | glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); |
| 378 | glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 0.0f)); | 374 | glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 0.0f)); |
| 379 | 375 | ||
| 380 | // we can use the AABox's ray intersection by mapping our origin and direction into the model frame | 376 | // we can use the AABox's intersection by mapping our origin and direction into the model frame |
| 381 | // and testing intersection there. | 377 | // and testing intersection there. |
| 382 | if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face, surfaceNormal)) { | 378 | if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face, surfaceNormal)) { |
| 383 | QMutexLocker locker(&_mutex); | 379 | QMutexLocker locker(&_mutex); |
| @@ -395,7 +391,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 11 unmodified lines | |||
| 395 | } | 391 | } |
| 396 | 392 | ||
| 397 | glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset); | 393 | glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset); |
| 398 | glm::mat4 meshToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation) * meshToModelMatrix; | 394 | glm::mat4 meshToWorldMatrix = modelToWorldMatrix * meshToModelMatrix; |
| 399 | glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix); | 395 | glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix); |
| 400 | 396 | ||
| 401 | glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f)); | 397 | glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f)); |
| @@ -405,11 +401,10 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 3 unmodified lines | |||
| 405 | for (auto& meshTriangleSets : _modelSpaceMeshTriangleSets) { | 401 | for (auto& meshTriangleSets : _modelSpaceMeshTriangleSets) { |
| 406 | int partIndex = 0; | 402 | int partIndex = 0; |
| 407 | for (auto &partTriangleSet : meshTriangleSets) { | 403 | for (auto &partTriangleSet : meshTriangleSets) { |
| 408 | float triangleSetDistance = 0.0f; | 404 | float triangleSetDistance; |
| 409 | BoxFace triangleSetFace; | 405 | BoxFace triangleSetFace; |
| 410 | Triangle triangleSetTriangle; | 406 | Triangle triangleSetTriangle; |
| 411 | if (partTriangleSet.findRayIntersection(meshFrameOrigin, meshFrameDirection, triangleSetDistance, triangleSetFace, triangleSetTriangle, pickAgainstTriangles, allowBackface)) { | 407 | if (partTriangleSet.findRayIntersection(meshFrameOrigin, meshFrameDirection, triangleSetDistance, triangleSetFace, triangleSetTriangle, pickAgainstTriangles, allowBackface)) { |
| 412 | |||
| 413 | glm::vec3 meshIntersectionPoint = meshFrameOrigin + (meshFrameDirection * triangleSetDistance); | 408 | glm::vec3 meshIntersectionPoint = meshFrameOrigin + (meshFrameDirection * triangleSetDistance); |
| 414 | glm::vec3 worldIntersectionPoint = glm::vec3(meshToWorldMatrix * glm::vec4(meshIntersectionPoint, 1.0f)); | 409 | glm::vec3 worldIntersectionPoint = glm::vec3(meshToWorldMatrix * glm::vec4(meshIntersectionPoint, 1.0f)); |
| 415 | float worldDistance = glm::distance(origin, worldIntersectionPoint); | 410 | float worldDistance = glm::distance(origin, worldIntersectionPoint); |
| @@ -457,6 +452,111 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 41 unmodified lines | |||
| 457 | return intersectedSomething; | 452 | return intersectedSomething; |
| 458 | } | 453 | } |
| 459 | 454 | ||
| 455 | bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, | ||
| 456 | float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, | ||
| 457 | bool pickAgainstTriangles, bool allowBackface) { | ||
| 458 | bool intersectedSomething = false; | ||
| 459 | |||
| 460 | // if we aren't active, we can't pick yet... | ||
| 461 | if (!isActive()) { | ||
| 462 | return intersectedSomething; | ||
| 463 | } | ||
| 464 | |||
| 465 | // extents is the entity relative, scaled, centered extents of the entity | ||
| 466 | glm::mat4 modelToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation); | ||
| 467 | glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); | ||
| 468 | |||
| 469 | Extents modelExtents = getMeshExtents(); // NOTE: unrotated | ||
| 470 | |||
| 471 | glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; | ||
| 472 | glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the picking in the model frame of reference | ||
| 473 | AABox modelFrameBox(corner, dimensions); | ||
| 474 | |||
| 475 | glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); | ||
| 476 | glm::vec3 modelFrameVelocity = glm::vec3(worldToModelMatrix * glm::vec4(velocity, 0.0f)); | ||
| 477 | glm::vec3 modelFrameAcceleration = glm::vec3(worldToModelMatrix * glm::vec4(acceleration, 0.0f)); | ||
| 478 | |||
| 479 | // we can use the AABox's intersection by mapping our origin and direction into the model frame | ||
| 480 | // and testing intersection there. | ||
| 481 | if (modelFrameBox.findParabolaIntersection(modelFrameOrigin, modelFrameVelocity, modelFrameAcceleration, parabolicDistance, face, surfaceNormal)) { | ||
| 482 | QMutexLocker locker(&_mutex); | ||
| 483 | |||
| 484 | float bestDistance = FLT_MAX; | ||
| 485 | Triangle bestModelTriangle; | ||
| 486 | Triangle bestWorldTriangle; | ||
| 487 | int bestSubMeshIndex = 0; | ||
| 488 | |||
| 489 | int subMeshIndex = 0; | ||
| 490 | const FBXGeometry& geometry = getFBXGeometry(); | ||
| 491 | |||
| 492 | if (!_triangleSetsValid) { | ||
| 493 | calculateTriangleSets(geometry); | ||
| 494 | } | ||
| 495 | |||
| 496 | glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset); | ||
| 497 | glm::mat4 meshToWorldMatrix = modelToWorldMatrix * meshToModelMatrix; | ||
| 498 | glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix); | ||
| 499 | |||
| 500 | glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f)); | ||
| 501 | glm::vec3 meshFrameVelocity = glm::vec3(worldToMeshMatrix * glm::vec4(velocity, 0.0f)); | ||
| 502 | glm::vec3 meshFrameAcceleration = glm::vec3(worldToMeshMatrix * glm::vec4(acceleration, 0.0f)); | ||
| 503 | |||
| 504 | int shapeID = 0; | ||
| 505 | for (auto& meshTriangleSets : _modelSpaceMeshTriangleSets) { | ||
| 506 | int partIndex = 0; | ||
| 507 | for (auto &partTriangleSet : meshTriangleSets) { | ||
| 508 | float triangleSetDistance; | ||
| 509 | BoxFace triangleSetFace; | ||
| 510 | Triangle triangleSetTriangle; | ||
| 511 | if (partTriangleSet.findParabolaIntersection(meshFrameOrigin, meshFrameVelocity, meshFrameAcceleration, | ||
| 512 | triangleSetDistance, triangleSetFace, triangleSetTriangle, pickAgainstTriangles, allowBackface)) { | ||
| 513 | if (triangleSetDistance < bestDistance) { | ||
| 514 | bestDistance = triangleSetDistance; | ||
| 515 | intersectedSomething = true; | ||
| 516 | face = triangleSetFace; | ||
| 517 | bestModelTriangle = triangleSetTriangle; | ||
| 518 | bestWorldTriangle = triangleSetTriangle * meshToWorldMatrix; | ||
| 519 | glm::vec3 worldIntersectionPoint = meshFrameOrigin + meshFrameVelocity * triangleSetDistance + | ||
| 520 | 0.5f * meshFrameAcceleration * triangleSetDistance * triangleSetDistance; | ||
| 521 | glm::vec3 meshIntersectionPoint = origin + velocity * triangleSetDistance + | ||
| 522 | 0.5f * acceleration * triangleSetDistance * triangleSetDistance; | ||
| 523 | extraInfo["worldIntersectionPoint"] = vec3toVariant(worldIntersectionPoint); | ||
| 524 | extraInfo["meshIntersectionPoint"] = vec3toVariant(meshIntersectionPoint); | ||
| 525 | extraInfo["partIndex"] = partIndex; | ||
| 526 | extraInfo["shapeID"] = shapeID; | ||
| 527 | bestSubMeshIndex = subMeshIndex; | ||
| 528 | } | ||
| 529 | } | ||
| 530 | partIndex++; | ||
| 531 | shapeID++; | ||
| 532 | } | ||
| 533 | subMeshIndex++; | ||
| 534 | } | ||
| 535 | |||
| 536 | if (intersectedSomething) { | ||
| 537 | parabolicDistance = bestDistance; | ||
| 538 | surfaceNormal = bestWorldTriangle.getNormal(); | ||
| 539 | if (pickAgainstTriangles) { | ||
| 540 | extraInfo["subMeshIndex"] = bestSubMeshIndex; | ||
| 541 | extraInfo["subMeshName"] = geometry.getModelNameOfMesh(bestSubMeshIndex); | ||
| 542 | extraInfo["subMeshTriangleWorld"] = QVariantMap{ | ||
| 543 | { "v0", vec3toVariant(bestWorldTriangle.v0) }, | ||
| 544 | { "v1", vec3toVariant(bestWorldTriangle.v1) }, | ||
| 545 | { "v2", vec3toVariant(bestWorldTriangle.v2) }, | ||
| 546 | }; | ||
| 547 | extraInfo["subMeshNormal"] = vec3toVariant(bestModelTriangle.getNormal()); | ||
| 548 | extraInfo["subMeshTriangle"] = QVariantMap{ | ||
| 549 | { "v0", vec3toVariant(bestModelTriangle.v0) }, | ||
| 550 | { "v1", vec3toVariant(bestModelTriangle.v1) }, | ||
| 551 | { "v2", vec3toVariant(bestModelTriangle.v2) }, | ||
| 552 | }; | ||
| 553 | } | ||
| 554 | } | ||
| 555 | } | ||
| 556 | |||
| 557 | return intersectedSomething; | ||
| 558 | } | ||
| 559 | |||
| 460 | bool Model::convexHullContains(glm::vec3 point) { | 560 | bool Model::convexHullContains(glm::vec3 point) { |
| 461 | // if we aren't active, we can't compute that yet... | 561 | // if we aren't active, we can't compute that yet... |
| 462 | if (!isActive()) { | 562 | if (!isActive()) { |
| @@ -594,7 +694,7 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe · 131 unmodified lines | |||
| 594 | } | 694 | } |
| 595 | scene->enqueueTransaction(transaction); | 695 | scene->enqueueTransaction(transaction); |
| 596 | } | 696 | } |
| 597 | // update triangles for ray picking | 697 | // update triangles for picking |
| 598 | { | 698 | { |
| 599 | FBXGeometry geometry; | 699 | FBXGeometry geometry; |
| 600 | for (const auto& newMesh : meshes) { | 700 | for (const auto& newMesh : meshes) { |