mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 06:44:06 +02:00
cleanup use of triangleSet for picking
This commit is contained in:
parent
32add6635d
commit
87bcced409
5 changed files with 134 additions and 272 deletions
|
@ -418,6 +418,12 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
// Enqueue updates for the next frame
|
||||
if (_model) {
|
||||
|
||||
#if 1 //def WANT_EXTRA_RENDER_DEBUGGING
|
||||
// debugging...
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
_model->renderDebugMeshBoxes(batch);
|
||||
#endif
|
||||
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
|
||||
// FIXME: this seems like it could be optimized if we tracked our last known visible state in
|
||||
|
|
|
@ -96,9 +96,6 @@ Model::Model(RigPointer rig, QObject* parent, SpatiallyNestable* spatiallyNestab
|
|||
_isVisible(true),
|
||||
_blendNumber(0),
|
||||
_appliedBlendNumber(0),
|
||||
_calculatedMeshPartBoxesValid(false),
|
||||
_calculatedMeshBoxesValid(false),
|
||||
_calculatedMeshTrianglesValid(false),
|
||||
_isWireframe(false),
|
||||
_rig(rig)
|
||||
{
|
||||
|
@ -360,19 +357,14 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
// we can use the AABox's ray intersection by mapping our origin and direction into the model frame
|
||||
// and testing intersection there.
|
||||
if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face, surfaceNormal)) {
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
float bestDistance = std::numeric_limits<float>::max();
|
||||
|
||||
float distanceToSubMesh;
|
||||
BoxFace subMeshFace;
|
||||
glm::vec3 subMeshSurfaceNormal;
|
||||
int subMeshIndex = 0;
|
||||
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
|
||||
// If we hit the models box, then consider the submeshes...
|
||||
_mutex.lock();
|
||||
if (!_calculatedMeshBoxesValid || (pickAgainstTriangles && !_calculatedMeshTrianglesValid)) {
|
||||
recalculateMeshBoxes(pickAgainstTriangles);
|
||||
if (!_triangleSetsValid) {
|
||||
calculateTriangleSets();
|
||||
}
|
||||
|
||||
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
|
||||
|
@ -382,50 +374,26 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 meshFrameDirection = glm::vec3(worldToMeshMatrix * glm::vec4(direction, 0.0f));
|
||||
|
||||
for (const auto& triangleSet : _modelSpaceMeshTriangleSets) {
|
||||
float triangleSetDistance = 0.0f;
|
||||
BoxFace triangleSetFace;
|
||||
glm::vec3 triangleSetNormal;
|
||||
if (triangleSet.findRayIntersection(meshFrameOrigin, meshFrameDirection, triangleSetDistance, triangleSetFace, triangleSetNormal, pickAgainstTriangles)) {
|
||||
|
||||
for (const auto& subMeshBox : _calculatedMeshBoxes) {
|
||||
bool intersectedSubMesh = false;
|
||||
float subMeshDistance = std::numeric_limits<float>::max();
|
||||
glm::vec3 meshIntersectionPoint = meshFrameOrigin + (meshFrameDirection * triangleSetDistance);
|
||||
glm::vec3 worldIntersectionPoint = glm::vec3(meshToWorldMatrix * glm::vec4(meshIntersectionPoint, 1.0f));
|
||||
float worldDistance = glm::distance(origin, worldIntersectionPoint);
|
||||
|
||||
if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace, subMeshSurfaceNormal)) {
|
||||
if (distanceToSubMesh < bestDistance) {
|
||||
if (pickAgainstTriangles) {
|
||||
|
||||
float subMeshDistance = 0.0f;
|
||||
glm::vec3 subMeshNormal;
|
||||
const auto& meshTriangleSet = _modelSpaceMeshTriangleSets[subMeshIndex];
|
||||
bool intersectedMesh = meshTriangleSet.findRayIntersection(meshFrameOrigin, meshFrameDirection, subMeshDistance, subMeshNormal);
|
||||
|
||||
if (intersectedMesh) {
|
||||
glm::vec3 meshIntersectionPoint = meshFrameOrigin + (meshFrameDirection * subMeshDistance);
|
||||
glm::vec3 worldIntersectionPoint = glm::vec3(meshToWorldMatrix * glm::vec4(meshIntersectionPoint, 1.0f));
|
||||
float worldDistance = glm::distance(origin, worldIntersectionPoint);
|
||||
|
||||
if (worldDistance < bestDistance) {
|
||||
bestDistance = subMeshDistance;
|
||||
intersectedSomething = true;
|
||||
face = subMeshFace;
|
||||
surfaceNormal = glm::vec3(meshToWorldMatrix * glm::vec4(subMeshNormal, 0.0f));
|
||||
extraInfo = geometry.getModelNameOfMesh(subMeshIndex);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// this is the non-triangle picking case...
|
||||
bestDistance = distanceToSubMesh;
|
||||
intersectedSomething = true;
|
||||
face = subMeshFace;
|
||||
surfaceNormal = subMeshSurfaceNormal;
|
||||
extraInfo = geometry.getModelNameOfMesh(subMeshIndex);
|
||||
|
||||
intersectedSubMesh = true;
|
||||
}
|
||||
if (worldDistance < bestDistance) {
|
||||
bestDistance = worldDistance;
|
||||
intersectedSomething = true;
|
||||
face = triangleSetFace;
|
||||
surfaceNormal = glm::vec3(meshToWorldMatrix * glm::vec4(triangleSetNormal, 0.0f));
|
||||
extraInfo = geometry.getModelNameOfMesh(subMeshIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
subMeshIndex++;
|
||||
}
|
||||
_mutex.unlock();
|
||||
|
||||
if (intersectedSomething) {
|
||||
distance = bestDistance;
|
||||
|
@ -461,182 +429,97 @@ bool Model::convexHullContains(glm::vec3 point) {
|
|||
// we can use the AABox's contains() by mapping our point into the model frame
|
||||
// and testing there.
|
||||
if (modelFrameBox.contains(modelFramePoint)){
|
||||
_mutex.lock();
|
||||
if (!_calculatedMeshTrianglesValid) {
|
||||
recalculateMeshBoxes(true);
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
if (!_triangleSetsValid) {
|
||||
calculateTriangleSets();
|
||||
}
|
||||
|
||||
// If we are inside the models box, then consider the submeshes...
|
||||
int subMeshIndex = 0;
|
||||
foreach(const AABox& subMeshBox, _calculatedMeshBoxes) {
|
||||
if (subMeshBox.contains(point)) {
|
||||
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
|
||||
glm::mat4 meshToWorldMatrix = meshToModelMatrix * glm::translate(_translation) * glm::mat4_cast(_rotation);
|
||||
glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix);
|
||||
glm::vec3 meshFramePoint = glm::vec3(worldToMeshMatrix * glm::vec4(point, 1.0f));
|
||||
|
||||
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
|
||||
glm::mat4 meshToWorldMatrix = meshToModelMatrix * glm::translate(_translation) * glm::mat4_cast(_rotation);
|
||||
glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix);
|
||||
|
||||
glm::vec3 meshFramePoint = glm::vec3(worldToMeshMatrix * glm::vec4(point, 1.0f));
|
||||
|
||||
if (_modelSpaceMeshTriangleSets[subMeshIndex].convexHullContains(meshFramePoint)) {
|
||||
for (const auto& triangleSet : _modelSpaceMeshTriangleSets) {
|
||||
const AABox& box = triangleSet.getBounds();
|
||||
if (box.contains(meshFramePoint)) {
|
||||
if (triangleSet.convexHullContains(meshFramePoint)) {
|
||||
// It's inside this mesh, return true.
|
||||
_mutex.unlock();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
subMeshIndex++;
|
||||
}
|
||||
_mutex.unlock();
|
||||
|
||||
|
||||
}
|
||||
// It wasn't in any mesh, return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: we seem to call this too often when things haven't actually changed... look into optimizing this
|
||||
// Any script might trigger findRayIntersectionAgainstSubMeshes (and maybe convexHullContains), so these
|
||||
// can occur multiple times. In addition, rendering does it's own ray picking in order to decide which
|
||||
// entity-scripts to call. I think it would be best to do the picking once-per-frame (in cpu, or gpu if possible)
|
||||
// and then the calls use the most recent such result.
|
||||
void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
||||
void Model::calculateTriangleSets() {
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid;
|
||||
|
||||
if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded || (!_calculatedMeshPartBoxesValid && pickAgainstTriangles) ) {
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
int numberOfMeshes = geometry.meshes.size();
|
||||
|
||||
if (pickAgainstTriangles) {
|
||||
qDebug() << "RECALCULATING triangles!";
|
||||
} else {
|
||||
qDebug() << "RECALCULATING boxes!";
|
||||
}
|
||||
_triangleSetsValid = true;
|
||||
_modelSpaceMeshTriangleSets.clear();
|
||||
_modelSpaceMeshTriangleSets.resize(numberOfMeshes);
|
||||
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
int numberOfMeshes = geometry.meshes.size();
|
||||
_calculatedMeshBoxes.resize(numberOfMeshes);
|
||||
_calculatedMeshPartBoxes.clear();
|
||||
for (int i = 0; i < numberOfMeshes; i++) {
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
|
||||
_modelSpaceMeshTriangleSets.clear();
|
||||
_modelSpaceMeshTriangleSets.resize(numberOfMeshes);
|
||||
for (int j = 0; j < mesh.parts.size(); j++) {
|
||||
const FBXMeshPart& part = mesh.parts.at(j);
|
||||
|
||||
for (int i = 0; i < numberOfMeshes; i++) {
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents, _translation, _rotation);
|
||||
const int INDICES_PER_TRIANGLE = 3;
|
||||
const int INDICES_PER_QUAD = 4;
|
||||
|
||||
_calculatedMeshBoxes[i] = AABox(scaledMeshExtents);
|
||||
if (part.quadIndices.size() > 0) {
|
||||
int numberOfQuads = part.quadIndices.size() / INDICES_PER_QUAD;
|
||||
int vIndex = 0;
|
||||
for (int q = 0; q < numberOfQuads; q++) {
|
||||
int i0 = part.quadIndices[vIndex++];
|
||||
int i1 = part.quadIndices[vIndex++];
|
||||
int i2 = part.quadIndices[vIndex++];
|
||||
int i3 = part.quadIndices[vIndex++];
|
||||
|
||||
if (pickAgainstTriangles) {
|
||||
// track the model space version... these points will be transformed by the FST's offset,
|
||||
// which includes the scaling, rotation, and translation specified by the FST/FBX,
|
||||
// this can't change at runtime, so we can safely store these in our TriangleSet
|
||||
glm::vec3 v0 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i0], 1.0f));
|
||||
glm::vec3 v1 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i1], 1.0f));
|
||||
glm::vec3 v2 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i2], 1.0f));
|
||||
glm::vec3 v3 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i3], 1.0f));
|
||||
|
||||
for (int j = 0; j < mesh.parts.size(); j++) {
|
||||
const FBXMeshPart& part = mesh.parts.at(j);
|
||||
|
||||
bool atLeastOnePointInBounds = false;
|
||||
AABox thisPartBounds;
|
||||
|
||||
const int INDICES_PER_TRIANGLE = 3;
|
||||
const int INDICES_PER_QUAD = 4;
|
||||
|
||||
if (part.quadIndices.size() > 0) {
|
||||
int numberOfQuads = part.quadIndices.size() / INDICES_PER_QUAD;
|
||||
int vIndex = 0;
|
||||
for (int q = 0; q < numberOfQuads; q++) {
|
||||
int i0 = part.quadIndices[vIndex++];
|
||||
int i1 = part.quadIndices[vIndex++];
|
||||
int i2 = part.quadIndices[vIndex++];
|
||||
int i3 = part.quadIndices[vIndex++];
|
||||
|
||||
glm::vec3 mv0 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i0], 1.0f));
|
||||
glm::vec3 mv1 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i1], 1.0f));
|
||||
glm::vec3 mv2 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f));
|
||||
glm::vec3 mv3 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i3], 1.0f));
|
||||
|
||||
// track the mesh parts in model space
|
||||
if (!atLeastOnePointInBounds) {
|
||||
thisPartBounds.setBox(mv0, 0.0f);
|
||||
atLeastOnePointInBounds = true;
|
||||
} else {
|
||||
thisPartBounds += mv0;
|
||||
}
|
||||
thisPartBounds += mv1;
|
||||
thisPartBounds += mv2;
|
||||
thisPartBounds += mv3;
|
||||
|
||||
// let's also track the model space version... (eventually using only this!)
|
||||
// these points will be transformed by the FST's offset, which includes the
|
||||
// scaling, rotation, and translation specified by the FST/FBX, this can't change
|
||||
// at runtime, so we can safely store these in our TriangleSet
|
||||
{
|
||||
glm::vec3 v0 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i0], 1.0f));
|
||||
glm::vec3 v1 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i1], 1.0f));
|
||||
glm::vec3 v2 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i2], 1.0f));
|
||||
glm::vec3 v3 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i3], 1.0f));
|
||||
|
||||
Triangle tri1 = { v0, v1, v3 };
|
||||
Triangle tri2 = { v1, v2, v3 };
|
||||
_modelSpaceMeshTriangleSets[i].insertTriangle(tri1);
|
||||
_modelSpaceMeshTriangleSets[i].insertTriangle(tri2);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (part.triangleIndices.size() > 0) {
|
||||
int numberOfTris = part.triangleIndices.size() / INDICES_PER_TRIANGLE;
|
||||
int vIndex = 0;
|
||||
for (int t = 0; t < numberOfTris; t++) {
|
||||
int i0 = part.triangleIndices[vIndex++];
|
||||
int i1 = part.triangleIndices[vIndex++];
|
||||
int i2 = part.triangleIndices[vIndex++];
|
||||
|
||||
glm::vec3 mv0 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i0], 1.0f));
|
||||
glm::vec3 mv1 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i1], 1.0f));
|
||||
glm::vec3 mv2 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f));
|
||||
|
||||
// track the mesh parts in model space
|
||||
if (!atLeastOnePointInBounds) {
|
||||
thisPartBounds.setBox(mv0, 0.0f);
|
||||
atLeastOnePointInBounds = true;
|
||||
} else {
|
||||
thisPartBounds += mv0;
|
||||
}
|
||||
thisPartBounds += mv1;
|
||||
thisPartBounds += mv2;
|
||||
|
||||
// let's also track the model space version... (eventually using only this!)
|
||||
// these points will be transformed by the FST's offset, which includes the
|
||||
// scaling, rotation, and translation specified by the FST/FBX, this can't change
|
||||
// at runtime, so we can safely store these in our TriangleSet
|
||||
{
|
||||
glm::vec3 v0 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i0], 1.0f));
|
||||
glm::vec3 v1 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i1], 1.0f));
|
||||
glm::vec3 v2 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i2], 1.0f));
|
||||
|
||||
Triangle tri = { v0, v1, v2 };
|
||||
_modelSpaceMeshTriangleSets[i].insertTriangle(tri);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
_calculatedMeshPartBoxes[QPair<int,int>(i, j)] = thisPartBounds;
|
||||
Triangle tri1 = { v0, v1, v3 };
|
||||
Triangle tri2 = { v1, v2, v3 };
|
||||
_modelSpaceMeshTriangleSets[i].insertTriangle(tri1);
|
||||
_modelSpaceMeshTriangleSets[i].insertTriangle(tri2);
|
||||
}
|
||||
}
|
||||
|
||||
if (part.triangleIndices.size() > 0) {
|
||||
int numberOfTris = part.triangleIndices.size() / INDICES_PER_TRIANGLE;
|
||||
int vIndex = 0;
|
||||
for (int t = 0; t < numberOfTris; t++) {
|
||||
int i0 = part.triangleIndices[vIndex++];
|
||||
int i1 = part.triangleIndices[vIndex++];
|
||||
int i2 = part.triangleIndices[vIndex++];
|
||||
|
||||
// track the model space version... these points will be transformed by the FST's offset,
|
||||
// which includes the scaling, rotation, and translation specified by the FST/FBX,
|
||||
// this can't change at runtime, so we can safely store these in our TriangleSet
|
||||
glm::vec3 v0 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i0], 1.0f));
|
||||
glm::vec3 v1 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i1], 1.0f));
|
||||
glm::vec3 v2 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i2], 1.0f));
|
||||
|
||||
Triangle tri = { v0, v1, v2 };
|
||||
_modelSpaceMeshTriangleSets[i].insertTriangle(tri);
|
||||
}
|
||||
_calculatedMeshPartBoxesValid = true;
|
||||
}
|
||||
}
|
||||
_calculatedMeshBoxesValid = true;
|
||||
_calculatedMeshTrianglesValid = pickAgainstTriangles;
|
||||
}
|
||||
}
|
||||
|
||||
void Model::renderSetup(RenderArgs* args) {
|
||||
// set up dilated textures on first render after load/simulate
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
if (_dilatedTextures.isEmpty()) {
|
||||
foreach (const FBXMesh& mesh, geometry.meshes) {
|
||||
QVector<QSharedPointer<Texture> > dilated;
|
||||
dilated.resize(mesh.parts.size());
|
||||
_dilatedTextures.append(dilated);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_addedToScene && isLoaded()) {
|
||||
createRenderItemSet();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -752,7 +635,15 @@ void Model::removeFromScene(std::shared_ptr<render::Scene> scene, render::Pendin
|
|||
void Model::renderDebugMeshBoxes(gpu::Batch& batch) {
|
||||
int colorNdx = 0;
|
||||
_mutex.lock();
|
||||
foreach(AABox box, _calculatedMeshBoxes) {
|
||||
|
||||
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
|
||||
glm::mat4 meshToWorldMatrix = meshToModelMatrix * glm::translate(_translation) * glm::mat4_cast(_rotation);
|
||||
Transform meshToWorld(meshToWorldMatrix);
|
||||
batch.setModelTransform(meshToWorld);
|
||||
|
||||
for(const auto& triangleSet : _modelSpaceMeshTriangleSets) {
|
||||
auto box = triangleSet.getBounds();
|
||||
|
||||
if (_debugMeshBoxesID == GeometryCache::UNKNOWN_ID) {
|
||||
_debugMeshBoxesID = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
@ -784,8 +675,8 @@ void Model::renderDebugMeshBoxes(gpu::Batch& batch) {
|
|||
points << blf << tlf;
|
||||
|
||||
glm::vec4 color[] = {
|
||||
{ 1.0f, 0.0f, 0.0f, 1.0f }, // red
|
||||
{ 0.0f, 1.0f, 0.0f, 1.0f }, // green
|
||||
{ 1.0f, 0.0f, 0.0f, 1.0f }, // red
|
||||
{ 0.0f, 0.0f, 1.0f, 1.0f }, // blue
|
||||
{ 1.0f, 0.0f, 1.0f, 1.0f }, // purple
|
||||
{ 1.0f, 1.0f, 0.0f, 1.0f }, // yellow
|
||||
|
@ -843,37 +734,6 @@ Extents Model::getUnscaledMeshExtents() const {
|
|||
return scaledExtents;
|
||||
}
|
||||
|
||||
Extents Model::calculateScaledOffsetExtents(const Extents& extents,
|
||||
glm::vec3 modelPosition, glm::quat modelOrientation) const {
|
||||
// we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix
|
||||
glm::vec3 minimum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));
|
||||
glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));
|
||||
|
||||
Extents scaledOffsetExtents = { ((minimum + _offset) * _scale),
|
||||
((maximum + _offset) * _scale) };
|
||||
|
||||
Extents rotatedExtents = scaledOffsetExtents.getRotated(modelOrientation);
|
||||
|
||||
Extents translatedExtents = { rotatedExtents.minimum + modelPosition,
|
||||
rotatedExtents.maximum + modelPosition };
|
||||
|
||||
return translatedExtents;
|
||||
}
|
||||
|
||||
/// Returns the world space equivalent of some box in model space.
|
||||
AABox Model::calculateScaledOffsetAABox(const AABox& box, glm::vec3 modelPosition, glm::quat modelOrientation) const {
|
||||
return AABox(calculateScaledOffsetExtents(Extents(box), modelPosition, modelOrientation));
|
||||
}
|
||||
|
||||
glm::vec3 Model::calculateScaledOffsetPoint(const glm::vec3& point) const {
|
||||
// we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix
|
||||
glm::vec3 offsetPoint = glm::vec3(getFBXGeometry().offset * glm::vec4(point, 1.0f));
|
||||
glm::vec3 scaledPoint = ((offsetPoint + _offset) * _scale);
|
||||
glm::vec3 rotatedPoint = _rotation * scaledPoint;
|
||||
glm::vec3 translatedPoint = rotatedPoint + _translation;
|
||||
return translatedPoint;
|
||||
}
|
||||
|
||||
void Model::clearJointState(int index) {
|
||||
_rig->clearJointState(index);
|
||||
}
|
||||
|
@ -1159,8 +1019,11 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
|
|||
// they really only become invalid if something about the transform to world space has changed. This is
|
||||
// not too bad at this point, because it doesn't impact rendering. However it does slow down ray picking
|
||||
// because ray picking needs valid boxes to work
|
||||
_calculatedMeshBoxesValid = false;
|
||||
_calculatedMeshTrianglesValid = false;
|
||||
//_calculatedMeshBoxesValid = false;
|
||||
//_calculatedMeshTrianglesValid = false;
|
||||
|
||||
// FIXME -- if the model URL changes, then we need to recalculate the triangle sets??!!!!
|
||||
|
||||
onInvalidate();
|
||||
|
||||
// check for scale to fit
|
||||
|
|
|
@ -96,7 +96,6 @@ public:
|
|||
render::PendingChanges& pendingChanges,
|
||||
render::Item::Status::Getters& statusGetters);
|
||||
void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
void renderSetup(RenderArgs* args);
|
||||
bool isRenderable() const;
|
||||
|
||||
bool isVisible() const { return _isVisible; }
|
||||
|
@ -251,6 +250,9 @@ public:
|
|||
uint32_t getGeometryCounter() const { return _deleteGeometryCounter; }
|
||||
const QMap<render::ItemID, render::PayloadPointer>& getRenderItems() const { return _modelMeshRenderItems; }
|
||||
|
||||
void renderDebugMeshBoxes(gpu::Batch& batch);
|
||||
|
||||
|
||||
public slots:
|
||||
void loadURLFinished(bool success);
|
||||
|
||||
|
@ -267,15 +269,6 @@ protected:
|
|||
/// Returns the unscaled extents of the model's mesh
|
||||
Extents getUnscaledMeshExtents() const;
|
||||
|
||||
/// Returns the scaled equivalent of some extents in model space.
|
||||
Extents calculateScaledOffsetExtents(const Extents& extents, glm::vec3 modelPosition, glm::quat modelOrientation) const;
|
||||
|
||||
/// Returns the world space equivalent of some box in model space.
|
||||
AABox calculateScaledOffsetAABox(const AABox& box, glm::vec3 modelPosition, glm::quat modelOrientation) const;
|
||||
|
||||
/// Returns the scaled equivalent of a point in model space.
|
||||
glm::vec3 calculateScaledOffsetPoint(const glm::vec3& point) const;
|
||||
|
||||
/// Clear the joint states
|
||||
void clearJointState(int index);
|
||||
|
||||
|
@ -332,14 +325,13 @@ protected:
|
|||
|
||||
/// Allow sub classes to force invalidating the bboxes
|
||||
void invalidCalculatedMeshBoxes() {
|
||||
_calculatedMeshBoxesValid = false;
|
||||
_calculatedMeshPartBoxesValid = false;
|
||||
_calculatedMeshTrianglesValid = false;
|
||||
_triangleSetsValid = false;
|
||||
}
|
||||
|
||||
// hook for derived classes to be notified when setUrl invalidates the current model.
|
||||
virtual void onInvalidate() {};
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
virtual void deleteGeometry();
|
||||
|
@ -358,17 +350,12 @@ protected:
|
|||
int _blendNumber;
|
||||
int _appliedBlendNumber;
|
||||
|
||||
QHash<QPair<int,int>, AABox> _calculatedMeshPartBoxes; // world coordinate AABoxes for all sub mesh part boxes
|
||||
|
||||
bool _calculatedMeshPartBoxesValid;
|
||||
QVector<AABox> _calculatedMeshBoxes; // world coordinate AABoxes for all sub mesh boxes
|
||||
bool _calculatedMeshBoxesValid;
|
||||
QVector<TriangleSet> _modelSpaceMeshTriangleSets; // model space triangles for all sub meshes
|
||||
|
||||
bool _calculatedMeshTrianglesValid;
|
||||
QMutex _mutex;
|
||||
|
||||
void recalculateMeshBoxes(bool pickAgainstTriangles = false);
|
||||
bool _triangleSetsValid { false };
|
||||
void calculateTriangleSets();
|
||||
QVector<TriangleSet> _modelSpaceMeshTriangleSets; // model space triangles for all sub meshes
|
||||
|
||||
|
||||
void createRenderItemSet();
|
||||
virtual void createVisibleRenderItemSet();
|
||||
|
@ -377,7 +364,6 @@ protected:
|
|||
bool _isWireframe;
|
||||
|
||||
// debug rendering support
|
||||
void renderDebugMeshBoxes(gpu::Batch& batch);
|
||||
int _debugMeshBoxesID = GeometryCache::UNKNOWN_ID;
|
||||
|
||||
|
||||
|
|
|
@ -28,24 +28,31 @@ void TriangleSet::clear() {
|
|||
// Determine of the given ray (origin/direction) in model space intersects with any triangles
|
||||
// in the set. If an intersection occurs, the distance and surface normal will be provided.
|
||||
bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, glm::vec3& surfaceNormal) const {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision) const {
|
||||
|
||||
float bestDistance = std::numeric_limits<float>::max();
|
||||
float thisTriangleDistance;
|
||||
bool intersectedSomething = false;
|
||||
float boxDistance = std::numeric_limits<float>::max();
|
||||
float bestDistance = std::numeric_limits<float>::max();
|
||||
|
||||
for (const auto& triangle : _triangles) {
|
||||
if (findRayTriangleIntersection(origin, direction, triangle, thisTriangleDistance)) {
|
||||
if (thisTriangleDistance < bestDistance) {
|
||||
bestDistance = thisTriangleDistance;
|
||||
intersectedSomething = true;
|
||||
surfaceNormal = triangle.getNormal();
|
||||
distance = bestDistance;
|
||||
//face = subMeshFace;
|
||||
//extraInfo = geometry.getModelNameOfMesh(subMeshIndex);
|
||||
if (_bounds.findRayIntersection(origin, direction, boxDistance, face, surfaceNormal)) {
|
||||
if (precision) {
|
||||
for (const auto& triangle : _triangles) {
|
||||
float thisTriangleDistance;
|
||||
if (findRayTriangleIntersection(origin, direction, triangle, thisTriangleDistance)) {
|
||||
if (thisTriangleDistance < bestDistance) {
|
||||
bestDistance = thisTriangleDistance;
|
||||
intersectedSomething = true;
|
||||
surfaceNormal = triangle.getNormal();
|
||||
distance = bestDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
intersectedSomething = true;
|
||||
distance = boxDistance;
|
||||
}
|
||||
}
|
||||
|
||||
return intersectedSomething;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,10 +22,10 @@ public:
|
|||
// Determine of the given ray (origin/direction) in model space intersects with any triangles
|
||||
// in the set. If an intersection occurs, the distance and surface normal will be provided.
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, glm::vec3& surfaceNormal) const;
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision) const;
|
||||
|
||||
bool convexHullContains(const glm::vec3& point) const; // this point is "inside" all triangles
|
||||
const AABox& getBounds() const;
|
||||
const AABox& getBounds() const { return _bounds; }
|
||||
|
||||
private:
|
||||
QVector<Triangle> _triangles;
|
||||
|
|
Loading…
Reference in a new issue