History

cleanup use of triangleSet for picking

ZappoMan committed 9 years ago

Commit 87bcced1 parent 32add665 files · +138 −276Browse files

Showing the changes to libraries/render-utils/src/Model.cpp (1 of 5 files). Show all

Unified · Split

libraries/render-utils/src/Model.cpp+103−240
@@ -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 frame357 // 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 frame429 // 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 this460void 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.
499void 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 space485 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 the496 Triangle tri1 = { v0, v1, v3 };
604 // scaling, rotation, and translation specified by the FST/FBX, this can't change497 Triangle tri2 = { v1, v2, v3 };
605 // at runtime, so we can safely store these in our TriangleSet498 _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
627void Model::renderSetup(RenderArgs* args) {503 if (part.triangleIndices.size() > 0) {
628 // set up dilated textures on first render after load/simulate504 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
643void Model::setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scene) {526void 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
752void Model::renderDebugMeshBoxes(gpu::Batch& batch) {635void 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 }, // green678 { 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 }, // blue680 { 0.0f, 0.0f, 1.0f, 1.0f }, // blue
790 { 1.0f, 0.0f, 1.0f, 1.0f }, // purple681 { 1.0f, 0.0f, 1.0f, 1.0f }, // purple
791 { 1.0f, 1.0f, 0.0f, 1.0f }, // yellow682 { 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
846Extents 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.
864AABox Model::calculateScaledOffsetAABox(const AABox& box, glm::vec3 modelPosition, glm::quat modelOrientation) const {
865 return AABox(calculateScaledOffsetExtents(Extents(box), modelPosition, modelOrientation));
866}
867
868glm::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
877void Model::clearJointState(int index) {737void 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 is1019 // 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 picking1020 // 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 work1021 // 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 fit1029 // check for scale to fit