Showing the changes to libraries/render-utils/src/Model.cpp (1 of 5 files). Show all
Unified · Split
| @@ -96,9 +96,6 @@ Model::Model(RigPointer rig, QObject* parent, SpatiallyNestable* spatiallyNestab · 95 unmodified lines | |||
| 96 | _isVisible(true), | 96 | _isVisible(true), |
| 97 | _blendNumber(0), | 97 | _blendNumber(0), |
| 98 | _appliedBlendNumber(0), | 98 | _appliedBlendNumber(0), |
| 99 | _calculatedMeshPartBoxesValid(false), | ||
| 100 | _calculatedMeshBoxesValid(false), | ||
| 101 | _calculatedMeshTrianglesValid(false), | ||
| 102 | _isWireframe(false), | 99 | _isWireframe(false), |
| 103 | _rig(rig) | 100 | _rig(rig) |
| 104 | { | 101 | { |
| @@ -360,19 +357,14 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 255 unmodified lines | |||
| 360 | // we can use the AABox's ray intersection by mapping our origin and direction into the model frame | 357 | // we can use the AABox's ray intersection by mapping our origin and direction into the model frame |
| 361 | // and testing intersection there. | 358 | // and testing intersection there. |
| 362 | if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face, surfaceNormal)) { | 359 | if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face, surfaceNormal)) { |
| 363 | float bestDistance = std::numeric_limits<float>::max(); | 360 | QMutexLocker locker(&_mutex); |
| 364 | 361 | ||
| 365 | float distanceToSubMesh; | 362 | float bestDistance = std::numeric_limits<float>::max(); |
| 366 | BoxFace subMeshFace; | ||
| 367 | glm::vec3 subMeshSurfaceNormal; | ||
| 368 | int subMeshIndex = 0; | 363 | int subMeshIndex = 0; |
| 369 | |||
| 370 | const FBXGeometry& geometry = getFBXGeometry(); | 364 | const FBXGeometry& geometry = getFBXGeometry(); |
| 371 | 365 | ||
| 372 | // If we hit the models box, then consider the submeshes... | 366 | if (!_triangleSetsValid) { |
| 373 | _mutex.lock(); | 367 | calculateTriangleSets(); |
| 374 | if (!_calculatedMeshBoxesValid || (pickAgainstTriangles && !_calculatedMeshTrianglesValid)) { | ||
| 375 | recalculateMeshBoxes(pickAgainstTriangles); | ||
| 376 | } | 368 | } |
| 377 | 369 | ||
| 378 | glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset); | 370 | glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset); |
| @@ -382,50 +374,26 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g · 3 unmodified lines | |||
| 382 | glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f)); | 374 | glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f)); |
| 383 | glm::vec3 meshFrameDirection = glm::vec3(worldToMeshMatrix * glm::vec4(direction, 0.0f)); | 375 | glm::vec3 meshFrameDirection = glm::vec3(worldToMeshMatrix * glm::vec4(direction, 0.0f)); |
| 384 | 376 | ||
| 385 | 377 | for (const auto& triangleSet : _modelSpaceMeshTriangleSets) { | |
| 386 | for (const auto& subMeshBox : _calculatedMeshBoxes) { | 378 | float triangleSetDistance = 0.0f; |
| 387 | bool intersectedSubMesh = false; | 379 | BoxFace triangleSetFace; |
| 388 | float subMeshDistance = std::numeric_limits<float>::max(); | 380 | glm::vec3 triangleSetNormal; |
| 389 | 381 | if (triangleSet.findRayIntersection(meshFrameOrigin, meshFrameDirection, triangleSetDistance, triangleSetFace, triangleSetNormal, pickAgainstTriangles)) { | |
| 390 | if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace, subMeshSurfaceNormal)) { | 382 | |
| 391 | if (distanceToSubMesh < bestDistance) { | 383 | glm::vec3 meshIntersectionPoint = meshFrameOrigin + (meshFrameDirection * triangleSetDistance); |
| 392 | if (pickAgainstTriangles) { | 384 | glm::vec3 worldIntersectionPoint = glm::vec3(meshToWorldMatrix * glm::vec4(meshIntersectionPoint, 1.0f)); |
| 393 | 385 | float worldDistance = glm::distance(origin, worldIntersectionPoint); | |
| 394 | float subMeshDistance = 0.0f; | 386 | |
| 395 | glm::vec3 subMeshNormal; | 387 | if (worldDistance < bestDistance) { |
| 396 | const auto& meshTriangleSet = _modelSpaceMeshTriangleSets[subMeshIndex]; | 388 | bestDistance = worldDistance; |
| 397 | bool intersectedMesh = meshTriangleSet.findRayIntersection(meshFrameOrigin, meshFrameDirection, subMeshDistance, subMeshNormal); | 389 | intersectedSomething = true; |
| 398 | 390 | face = triangleSetFace; | |
| 399 | if (intersectedMesh) { | 391 | surfaceNormal = glm::vec3(meshToWorldMatrix * glm::vec4(triangleSetNormal, 0.0f)); |
| 400 | glm::vec3 meshIntersectionPoint = meshFrameOrigin + (meshFrameDirection * subMeshDistance); | 392 | extraInfo = geometry.getModelNameOfMesh(subMeshIndex); |
| 401 | glm::vec3 worldIntersectionPoint = glm::vec3(meshToWorldMatrix * glm::vec4(meshIntersectionPoint, 1.0f)); | ||
| 402 | float worldDistance = glm::distance(origin, worldIntersectionPoint); | ||
| 403 | |||
| 404 | if (worldDistance < bestDistance) { | ||
| 405 | bestDistance = subMeshDistance; | ||
| 406 | intersectedSomething = true; | ||
| 407 | face = subMeshFace; | ||
| 408 | surfaceNormal = glm::vec3(meshToWorldMatrix * glm::vec4(subMeshNormal, 0.0f)); | ||
| 409 | extraInfo = geometry.getModelNameOfMesh(subMeshIndex); | ||
| 410 | } | ||
| 411 | } | ||
| 412 | } else { | ||
| 413 | // this is the non-triangle picking case... | ||
| 414 | bestDistance = distanceToSubMesh; | ||
| 415 | intersectedSomething = true; | ||
| 416 | face = subMeshFace; | ||
| 417 | surfaceNormal = subMeshSurfaceNormal; | ||
| 418 | extraInfo = geometry.getModelNameOfMesh(subMeshIndex); | ||
| 419 | |||
| 420 | intersectedSubMesh = true; | ||
| 421 | } | ||
| 422 | } | 393 | } |
| 423 | } | 394 | } |
| 424 | |||
| 425 | |||
| 426 | subMeshIndex++; | 395 | subMeshIndex++; |
| 427 | } | 396 | } |
| 428 | _mutex.unlock(); | ||
| 429 | 397 | ||
| 430 | if (intersectedSomething) { | 398 | if (intersectedSomething) { |
| 431 | distance = bestDistance; | 399 | distance = bestDistance; |
| @@ -461,183 +429,98 @@ bool Model::convexHullContains(glm::vec3 point) { · 29 unmodified lines | |||
| 461 | // we can use the AABox's contains() by mapping our point into the model frame | 429 | // we can use the AABox's contains() by mapping our point into the model frame |
| 462 | // and testing there. | 430 | // and testing there. |
| 463 | if (modelFrameBox.contains(modelFramePoint)){ | 431 | if (modelFrameBox.contains(modelFramePoint)){ |
| 464 | _mutex.lock(); | 432 | QMutexLocker locker(&_mutex); |
| 465 | if (!_calculatedMeshTrianglesValid) { | 433 | |
| 466 | recalculateMeshBoxes(true); | 434 | if (!_triangleSetsValid) { |
| 435 | calculateTriangleSets(); | ||
| 467 | } | 436 | } |
| 468 | 437 | ||
| 469 | // If we are inside the models box, then consider the submeshes... | 438 | // If we are inside the models box, then consider the submeshes... |
| 470 | int subMeshIndex = 0; | 439 | glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset); |
| 471 | foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { | 440 | glm::mat4 meshToWorldMatrix = meshToModelMatrix * glm::translate(_translation) * glm::mat4_cast(_rotation); |
| 472 | if (subMeshBox.contains(point)) { | 441 | glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix); |
| 473 | 442 | glm::vec3 meshFramePoint = glm::vec3(worldToMeshMatrix * glm::vec4(point, 1.0f)); | |
| 474 | glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset); | ||
| 475 | glm::mat4 meshToWorldMatrix = meshToModelMatrix * glm::translate(_translation) * glm::mat4_cast(_rotation); | ||
| 476 | glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix); | ||
| 477 | |||
| 478 | glm::vec3 meshFramePoint = glm::vec3(worldToMeshMatrix * glm::vec4(point, 1.0f)); | ||
| 479 | 443 | ||
| 480 | if (_modelSpaceMeshTriangleSets[subMeshIndex].convexHullContains(meshFramePoint)) { | 444 | for (const auto& triangleSet : _modelSpaceMeshTriangleSets) { |
| 445 | const AABox& box = triangleSet.getBounds(); | ||
| 446 | if (box.contains(meshFramePoint)) { | ||
| 447 | if (triangleSet.convexHullContains(meshFramePoint)) { | ||
| 481 | // It's inside this mesh, return true. | 448 | // It's inside this mesh, return true. |
| 482 | _mutex.unlock(); | ||
| 483 | return true; | 449 | return true; |
| 484 | } | 450 | } |
| 485 | } | 451 | } |
| 486 | subMeshIndex++; | ||
| 487 | } | 452 | } |
| 488 | _mutex.unlock(); | 453 | |
| 454 | |||
| 489 | } | 455 | } |
| 490 | // It wasn't in any mesh, return false. | 456 | // It wasn't in any mesh, return false. |
| 491 | return false; | 457 | return false; |
| 492 | } | 458 | } |
| 493 | 459 | ||
| 494 | // TODO: we seem to call this too often when things haven't actually changed... look into optimizing this | 460 | void Model::calculateTriangleSets() { |
| 495 | // Any script might trigger findRayIntersectionAgainstSubMeshes (and maybe convexHullContains), so these | ||
| 496 | // can occur multiple times. In addition, rendering does it's own ray picking in order to decide which | ||
| 497 | // entity-scripts to call. I think it would be best to do the picking once-per-frame (in cpu, or gpu if possible) | ||
| 498 | // and then the calls use the most recent such result. | ||
| 499 | void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { | ||
| 500 | PROFILE_RANGE(render, __FUNCTION__); | 461 | PROFILE_RANGE(render, __FUNCTION__); |
| 501 | bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; | ||
| 502 | 462 | ||
| 503 | if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded || (!_calculatedMeshPartBoxesValid && pickAgainstTriangles) ) { | 463 | const FBXGeometry& geometry = getFBXGeometry(); |
| 464 | int numberOfMeshes = geometry.meshes.size(); | ||
| 504 | 465 | ||
| 505 | if (pickAgainstTriangles) { | 466 | _triangleSetsValid = true; |
| 506 | qDebug() << "RECALCULATING triangles!"; | 467 | _modelSpaceMeshTriangleSets.clear(); |
| 507 | } else { | 468 | _modelSpaceMeshTriangleSets.resize(numberOfMeshes); |
| 508 | qDebug() << "RECALCULATING boxes!"; | ||
| 509 | } | ||
| 510 | 469 | ||
| 511 | const FBXGeometry& geometry = getFBXGeometry(); | 470 | for (int i = 0; i < numberOfMeshes; i++) { |
| 512 | int numberOfMeshes = geometry.meshes.size(); | 471 | const FBXMesh& mesh = geometry.meshes.at(i); |
| 513 | _calculatedMeshBoxes.resize(numberOfMeshes); | ||
| 514 | _calculatedMeshPartBoxes.clear(); | ||
| 515 | |||
| 516 | _modelSpaceMeshTriangleSets.clear(); | ||
| 517 | _modelSpaceMeshTriangleSets.resize(numberOfMeshes); | ||
| 518 | |||
| 519 | for (int i = 0; i < numberOfMeshes; i++) { | ||
| 520 | const FBXMesh& mesh = geometry.meshes.at(i); | ||
| 521 | Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents, _translation, _rotation); | ||
| 522 | |||
| 523 | _calculatedMeshBoxes[i] = AABox(scaledMeshExtents); | ||
| 524 | |||
| 525 | if (pickAgainstTriangles) { | ||
| 526 | |||
| 527 | for (int j = 0; j < mesh.parts.size(); j++) { | ||
| 528 | const FBXMeshPart& part = mesh.parts.at(j); | ||
| 529 | |||
| 530 | bool atLeastOnePointInBounds = false; | ||
| 531 | AABox thisPartBounds; | ||
| 532 | |||
| 533 | const int INDICES_PER_TRIANGLE = 3; | ||
| 534 | const int INDICES_PER_QUAD = 4; | ||
| 535 | |||
| 536 | if (part.quadIndices.size() > 0) { | ||
| 537 | int numberOfQuads = part.quadIndices.size() / INDICES_PER_QUAD; | ||
| 538 | int vIndex = 0; | ||
| 539 | for (int q = 0; q < numberOfQuads; q++) { | ||
| 540 | int i0 = part.quadIndices[vIndex++]; | ||
| 541 | int i1 = part.quadIndices[vIndex++]; | ||
| 542 | int i2 = part.quadIndices[vIndex++]; | ||
| 543 | int i3 = part.quadIndices[vIndex++]; | ||
| 544 | |||
| 545 | glm::vec3 mv0 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i0], 1.0f)); | ||
| 546 | glm::vec3 mv1 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i1], 1.0f)); | ||
| 547 | glm::vec3 mv2 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f)); | ||
| 548 | glm::vec3 mv3 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i3], 1.0f)); | ||
| 549 | |||
| 550 | // track the mesh parts in model space | ||
| 551 | if (!atLeastOnePointInBounds) { | ||
| 552 | thisPartBounds.setBox(mv0, 0.0f); | ||
| 553 | atLeastOnePointInBounds = true; | ||
| 554 | } else { | ||
| 555 | thisPartBounds += mv0; | ||
| 556 | } | ||
| 557 | thisPartBounds += mv1; | ||
| 558 | thisPartBounds += mv2; | ||
| 559 | thisPartBounds += mv3; | ||
| 560 | |||
| 561 | // let's also track the model space version... (eventually using only this!) | ||
| 562 | // these points will be transformed by the FST's offset, which includes the | ||
| 563 | // scaling, rotation, and translation specified by the FST/FBX, this can't change | ||
| 564 | // at runtime, so we can safely store these in our TriangleSet | ||
| 565 | { | ||
| 566 | glm::vec3 v0 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i0], 1.0f)); | ||
| 567 | glm::vec3 v1 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i1], 1.0f)); | ||
| 568 | glm::vec3 v2 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i2], 1.0f)); | ||
| 569 | glm::vec3 v3 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i3], 1.0f)); | ||
| 570 | |||
| 571 | Triangle tri1 = { v0, v1, v3 }; | ||
| 572 | Triangle tri2 = { v1, v2, v3 }; | ||
| 573 | _modelSpaceMeshTriangleSets[i].insertTriangle(tri1); | ||
| 574 | _modelSpaceMeshTriangleSets[i].insertTriangle(tri2); | ||
| 575 | } | ||
| 576 | |||
| 577 | } | ||
| 578 | } | ||
| 579 | 472 | ||
| 580 | if (part.triangleIndices.size() > 0) { | 473 | for (int j = 0; j < mesh.parts.size(); j++) { |
| 581 | int numberOfTris = part.triangleIndices.size() / INDICES_PER_TRIANGLE; | 474 | const FBXMeshPart& part = mesh.parts.at(j); |
| 582 | int vIndex = 0; | 475 | |
| 583 | for (int t = 0; t < numberOfTris; t++) { | 476 | const int INDICES_PER_TRIANGLE = 3; |
| 584 | int i0 = part.triangleIndices[vIndex++]; | 477 | const int INDICES_PER_QUAD = 4; |
| 585 | int i1 = part.triangleIndices[vIndex++]; | 478 | |
| 586 | int i2 = part.triangleIndices[vIndex++]; | 479 | if (part.quadIndices.size() > 0) { |
| 587 | 480 | int numberOfQuads = part.quadIndices.size() / INDICES_PER_QUAD; | |
| 588 | glm::vec3 mv0 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i0], 1.0f)); | 481 | int vIndex = 0; |
| 589 | glm::vec3 mv1 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i1], 1.0f)); | 482 | for (int q = 0; q < numberOfQuads; q++) { |
| 590 | glm::vec3 mv2 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f)); | 483 | int i0 = part.quadIndices[vIndex++]; |
| 591 | 484 | int i1 = part.quadIndices[vIndex++]; | |
| 592 | // track the mesh parts in model space | 485 | int i2 = part.quadIndices[vIndex++]; |
| 593 | if (!atLeastOnePointInBounds) { | 486 | int i3 = part.quadIndices[vIndex++]; |
| 594 | thisPartBounds.setBox(mv0, 0.0f); | 487 | |
| 595 | atLeastOnePointInBounds = true; | 488 | // track the model space version... these points will be transformed by the FST's offset, |
| 596 | } else { | 489 | // which includes the scaling, rotation, and translation specified by the FST/FBX, |
| 597 | thisPartBounds += mv0; | 490 | // this can't change at runtime, so we can safely store these in our TriangleSet |
| 598 | } | 491 | glm::vec3 v0 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i0], 1.0f)); |
| 599 | thisPartBounds += mv1; | 492 | glm::vec3 v1 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i1], 1.0f)); |
| 600 | thisPartBounds += mv2; | 493 | glm::vec3 v2 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i2], 1.0f)); |
| 601 | 494 | glm::vec3 v3 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i3], 1.0f)); | |
| 602 | // let's also track the model space version... (eventually using only this!) | 495 | |
| 603 | // these points will be transformed by the FST's offset, which includes the | 496 | Triangle tri1 = { v0, v1, v3 }; |
| 604 | // scaling, rotation, and translation specified by the FST/FBX, this can't change | 497 | Triangle tri2 = { v1, v2, v3 }; |
| 605 | // at runtime, so we can safely store these in our TriangleSet | 498 | _modelSpaceMeshTriangleSets[i].insertTriangle(tri1); |
| 606 | { | 499 | _modelSpaceMeshTriangleSets[i].insertTriangle(tri2); |
| 607 | glm::vec3 v0 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i0], 1.0f)); | ||
| 608 | glm::vec3 v1 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i1], 1.0f)); | ||
| 609 | glm::vec3 v2 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i2], 1.0f)); | ||
| 610 | |||
| 611 | Triangle tri = { v0, v1, v2 }; | ||
| 612 | _modelSpaceMeshTriangleSets[i].insertTriangle(tri); | ||
| 613 | } | ||
| 614 | |||
| 615 | } | ||
| 616 | } | ||
| 617 | _calculatedMeshPartBoxes[QPair<int,int>(i, j)] = thisPartBounds; | ||
| 618 | } | 500 | } |
| 619 | _calculatedMeshPartBoxesValid = true; | ||
| 620 | } | 501 | } |
| 621 | } | ||
| 622 | _calculatedMeshBoxesValid = true; | ||
| 623 | _calculatedMeshTrianglesValid = pickAgainstTriangles; | ||
| 624 | } | ||
| 625 | } | ||
| 626 | 502 | ||
| 627 | void Model::renderSetup(RenderArgs* args) { | 503 | if (part.triangleIndices.size() > 0) { |
| 628 | // set up dilated textures on first render after load/simulate | 504 | int numberOfTris = part.triangleIndices.size() / INDICES_PER_TRIANGLE; |
| 629 | const FBXGeometry& geometry = getFBXGeometry(); | 505 | int vIndex = 0; |
| 630 | if (_dilatedTextures.isEmpty()) { | 506 | for (int t = 0; t < numberOfTris; t++) { |
| 631 | foreach (const FBXMesh& mesh, geometry.meshes) { | 507 | int i0 = part.triangleIndices[vIndex++]; |
| 632 | QVector<QSharedPointer<Texture> > dilated; | 508 | int i1 = part.triangleIndices[vIndex++]; |
| 633 | dilated.resize(mesh.parts.size()); | 509 | int i2 = part.triangleIndices[vIndex++]; |
| 634 | _dilatedTextures.append(dilated); | 510 | |
| 511 | // track the model space version... these points will be transformed by the FST's offset, | ||
| 512 | // which includes the scaling, rotation, and translation specified by the FST/FBX, | ||
| 513 | // this can't change at runtime, so we can safely store these in our TriangleSet | ||
| 514 | glm::vec3 v0 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i0], 1.0f)); | ||
| 515 | glm::vec3 v1 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i1], 1.0f)); | ||
| 516 | glm::vec3 v2 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i2], 1.0f)); | ||
| 517 | |||
| 518 | Triangle tri = { v0, v1, v2 }; | ||
| 519 | _modelSpaceMeshTriangleSets[i].insertTriangle(tri); | ||
| 520 | } | ||
| 521 | } | ||
| 635 | } | 522 | } |
| 636 | } | 523 | } |
| 637 | |||
| 638 | if (!_addedToScene && isLoaded()) { | ||
| 639 | createRenderItemSet(); | ||
| 640 | } | ||
| 641 | } | 524 | } |
| 642 | 525 | ||
| 643 | void Model::setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scene) { | 526 | void Model::setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scene) { |
| @@ -752,7 +635,15 @@ void Model::removeFromScene(std::shared_ptr<render::Scene> scene, render::Pendin · 108 unmodified lines | |||
| 752 | void Model::renderDebugMeshBoxes(gpu::Batch& batch) { | 635 | void Model::renderDebugMeshBoxes(gpu::Batch& batch) { |
| 753 | int colorNdx = 0; | 636 | int colorNdx = 0; |
| 754 | _mutex.lock(); | 637 | _mutex.lock(); |
| 755 | foreach(AABox box, _calculatedMeshBoxes) { | 638 | |
| 639 | glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset); | ||
| 640 | glm::mat4 meshToWorldMatrix = meshToModelMatrix * glm::translate(_translation) * glm::mat4_cast(_rotation); | ||
| 641 | Transform meshToWorld(meshToWorldMatrix); | ||
| 642 | batch.setModelTransform(meshToWorld); | ||
| 643 | |||
| 644 | for(const auto& triangleSet : _modelSpaceMeshTriangleSets) { | ||
| 645 | auto box = triangleSet.getBounds(); | ||
| 646 | |||
| 756 | if (_debugMeshBoxesID == GeometryCache::UNKNOWN_ID) { | 647 | if (_debugMeshBoxesID == GeometryCache::UNKNOWN_ID) { |
| 757 | _debugMeshBoxesID = DependencyManager::get<GeometryCache>()->allocateID(); | 648 | _debugMeshBoxesID = DependencyManager::get<GeometryCache>()->allocateID(); |
| 758 | } | 649 | } |
| @@ -784,8 +675,8 @@ void Model::renderDebugMeshBoxes(gpu::Batch& batch) { · 25 unmodified lines | |||
| 784 | points << blf << tlf; | 675 | points << blf << tlf; |
| 785 | 676 | ||
| 786 | glm::vec4 color[] = { | 677 | glm::vec4 color[] = { |
| 787 | { 1.0f, 0.0f, 0.0f, 1.0f }, // red | ||
| 788 | { 0.0f, 1.0f, 0.0f, 1.0f }, // green | 678 | { 0.0f, 1.0f, 0.0f, 1.0f }, // green |
| 679 | { 1.0f, 0.0f, 0.0f, 1.0f }, // red | ||
| 789 | { 0.0f, 0.0f, 1.0f, 1.0f }, // blue | 680 | { 0.0f, 0.0f, 1.0f, 1.0f }, // blue |
| 790 | { 1.0f, 0.0f, 1.0f, 1.0f }, // purple | 681 | { 1.0f, 0.0f, 1.0f, 1.0f }, // purple |
| 791 | { 1.0f, 1.0f, 0.0f, 1.0f }, // yellow | 682 | { 1.0f, 1.0f, 0.0f, 1.0f }, // yellow |
| @@ -843,37 +734,6 @@ Extents Model::getUnscaledMeshExtents() const { · 51 unmodified lines | |||
| 843 | return scaledExtents; | 734 | return scaledExtents; |
| 844 | } | 735 | } |
| 845 | 736 | ||
| 846 | Extents Model::calculateScaledOffsetExtents(const Extents& extents, | ||
| 847 | glm::vec3 modelPosition, glm::quat modelOrientation) const { | ||
| 848 | // we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix | ||
| 849 | glm::vec3 minimum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f)); | ||
| 850 | glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f)); | ||
| 851 | |||
| 852 | Extents scaledOffsetExtents = { ((minimum + _offset) * _scale), | ||
| 853 | ((maximum + _offset) * _scale) }; | ||
| 854 | |||
| 855 | Extents rotatedExtents = scaledOffsetExtents.getRotated(modelOrientation); | ||
| 856 | |||
| 857 | Extents translatedExtents = { rotatedExtents.minimum + modelPosition, | ||
| 858 | rotatedExtents.maximum + modelPosition }; | ||
| 859 | |||
| 860 | return translatedExtents; | ||
| 861 | } | ||
| 862 | |||
| 863 | /// Returns the world space equivalent of some box in model space. | ||
| 864 | AABox Model::calculateScaledOffsetAABox(const AABox& box, glm::vec3 modelPosition, glm::quat modelOrientation) const { | ||
| 865 | return AABox(calculateScaledOffsetExtents(Extents(box), modelPosition, modelOrientation)); | ||
| 866 | } | ||
| 867 | |||
| 868 | glm::vec3 Model::calculateScaledOffsetPoint(const glm::vec3& point) const { | ||
| 869 | // we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix | ||
| 870 | glm::vec3 offsetPoint = glm::vec3(getFBXGeometry().offset * glm::vec4(point, 1.0f)); | ||
| 871 | glm::vec3 scaledPoint = ((offsetPoint + _offset) * _scale); | ||
| 872 | glm::vec3 rotatedPoint = _rotation * scaledPoint; | ||
| 873 | glm::vec3 translatedPoint = rotatedPoint + _translation; | ||
| 874 | return translatedPoint; | ||
| 875 | } | ||
| 876 | |||
| 877 | void Model::clearJointState(int index) { | 737 | void Model::clearJointState(int index) { |
| 878 | _rig->clearJointState(index); | 738 | _rig->clearJointState(index); |
| 879 | } | 739 | } |
| @@ -1159,8 +1019,11 @@ void Model::simulate(float deltaTime, bool fullUpdate) { · 279 unmodified lines | |||
| 1159 | // they really only become invalid if something about the transform to world space has changed. This is | 1019 | // they really only become invalid if something about the transform to world space has changed. This is |
| 1160 | // not too bad at this point, because it doesn't impact rendering. However it does slow down ray picking | 1020 | // not too bad at this point, because it doesn't impact rendering. However it does slow down ray picking |
| 1161 | // because ray picking needs valid boxes to work | 1021 | // because ray picking needs valid boxes to work |
| 1162 | _calculatedMeshBoxesValid = false; | 1022 | //_calculatedMeshBoxesValid = false; |
| 1163 | _calculatedMeshTrianglesValid = false; | 1023 | //_calculatedMeshTrianglesValid = false; |
| 1024 | |||
| 1025 | // FIXME -- if the model URL changes, then we need to recalculate the triangle sets??!!!! | ||
| 1026 | |||
| 1164 | onInvalidate(); | 1027 | onInvalidate(); |
| 1165 | 1028 | ||
| 1166 | // check for scale to fit | 1029 | // check for scale to fit |