mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 21:17:01 +02:00
Merge pull request #2931 from ZappoMan/aacube
Support improved Ray picking of models
This commit is contained in:
commit
1348902c4b
6 changed files with 111 additions and 39 deletions
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include <glm/gtx/quaternion.hpp>
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
|
||||||
|
#include <FBXReader.h>
|
||||||
|
|
||||||
#include "InterfaceConfig.h"
|
#include "InterfaceConfig.h"
|
||||||
#include "Menu.h"
|
#include "Menu.h"
|
||||||
#include "ModelTreeRenderer.h"
|
#include "ModelTreeRenderer.h"
|
||||||
|
@ -34,8 +36,13 @@ ModelTreeRenderer::~ModelTreeRenderer() {
|
||||||
|
|
||||||
void ModelTreeRenderer::init() {
|
void ModelTreeRenderer::init() {
|
||||||
OctreeRenderer::init();
|
OctreeRenderer::init();
|
||||||
|
static_cast<ModelTree*>(_tree)->setFBXService(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModelTreeRenderer::setTree(Octree* newTree) {
|
||||||
|
OctreeRenderer::setTree(newTree);
|
||||||
|
static_cast<ModelTree*>(_tree)->setFBXService(this);
|
||||||
|
}
|
||||||
|
|
||||||
void ModelTreeRenderer::update() {
|
void ModelTreeRenderer::update() {
|
||||||
if (_tree) {
|
if (_tree) {
|
||||||
|
@ -48,6 +55,16 @@ void ModelTreeRenderer::render(RenderMode renderMode) {
|
||||||
OctreeRenderer::render(renderMode);
|
OctreeRenderer::render(renderMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FBXGeometry* ModelTreeRenderer::getGeometryForModel(const ModelItem& modelItem) {
|
||||||
|
const FBXGeometry* result = NULL;
|
||||||
|
Model* model = getModel(modelItem);
|
||||||
|
if (model) {
|
||||||
|
result = &model->getGeometry()->getFBXGeometry();
|
||||||
|
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Model* ModelTreeRenderer::getModel(const ModelItem& modelItem) {
|
Model* ModelTreeRenderer::getModel(const ModelItem& modelItem) {
|
||||||
Model* model = NULL;
|
Model* model = NULL;
|
||||||
|
|
||||||
|
@ -73,42 +90,6 @@ Model* ModelTreeRenderer::getModel(const ModelItem& modelItem) {
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
void calculateRotatedExtents(Extents& extents, const glm::quat& rotation) {
|
|
||||||
glm::vec3 bottomLeftNear(extents.minimum.x, extents.minimum.y, extents.minimum.z);
|
|
||||||
glm::vec3 bottomRightNear(extents.maximum.x, extents.minimum.y, extents.minimum.z);
|
|
||||||
glm::vec3 bottomLeftFar(extents.minimum.x, extents.minimum.y, extents.maximum.z);
|
|
||||||
glm::vec3 bottomRightFar(extents.maximum.x, extents.minimum.y, extents.maximum.z);
|
|
||||||
glm::vec3 topLeftNear(extents.minimum.x, extents.maximum.y, extents.minimum.z);
|
|
||||||
glm::vec3 topRightNear(extents.maximum.x, extents.maximum.y, extents.minimum.z);
|
|
||||||
glm::vec3 topLeftFar(extents.minimum.x, extents.maximum.y, extents.maximum.z);
|
|
||||||
glm::vec3 topRightFar(extents.maximum.x, extents.maximum.y, extents.maximum.z);
|
|
||||||
|
|
||||||
glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear;
|
|
||||||
glm::vec3 bottomRightNearRotated = rotation * bottomRightNear;
|
|
||||||
glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar;
|
|
||||||
glm::vec3 bottomRightFarRotated = rotation * bottomRightFar;
|
|
||||||
glm::vec3 topLeftNearRotated = rotation * topLeftNear;
|
|
||||||
glm::vec3 topRightNearRotated = rotation * topRightNear;
|
|
||||||
glm::vec3 topLeftFarRotated = rotation * topLeftFar;
|
|
||||||
glm::vec3 topRightFarRotated = rotation * topRightFar;
|
|
||||||
|
|
||||||
extents.minimum = glm::min(bottomLeftNearRotated,
|
|
||||||
glm::min(bottomRightNearRotated,
|
|
||||||
glm::min(bottomLeftFarRotated,
|
|
||||||
glm::min(bottomRightFarRotated,
|
|
||||||
glm::min(topLeftNearRotated,
|
|
||||||
glm::min(topRightNearRotated,
|
|
||||||
glm::min(topLeftFarRotated,topRightFarRotated)))))));
|
|
||||||
|
|
||||||
extents.maximum = glm::max(bottomLeftNearRotated,
|
|
||||||
glm::max(bottomRightNearRotated,
|
|
||||||
glm::max(bottomLeftFarRotated,
|
|
||||||
glm::max(bottomRightFarRotated,
|
|
||||||
glm::max(topLeftNearRotated,
|
|
||||||
glm::max(topRightNearRotated,
|
|
||||||
glm::max(topLeftFarRotated,topRightFarRotated)))))));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
|
void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
|
||||||
args->_elementsTouched++;
|
args->_elementsTouched++;
|
||||||
// actually render it here...
|
// actually render it here...
|
||||||
|
@ -248,6 +229,7 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isShadowMode && displayModelBounds) {
|
if (!isShadowMode && displayModelBounds) {
|
||||||
|
|
||||||
glm::vec3 unRotatedMinimum = model->getUnscaledMeshExtents().minimum;
|
glm::vec3 unRotatedMinimum = model->getUnscaledMeshExtents().minimum;
|
||||||
glm::vec3 unRotatedMaximum = model->getUnscaledMeshExtents().maximum;
|
glm::vec3 unRotatedMaximum = model->getUnscaledMeshExtents().maximum;
|
||||||
glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum;
|
glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum;
|
||||||
|
@ -285,6 +267,7 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
||||||
glutWireCube(1.0);
|
glutWireCube(1.0);
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include "renderer/Model.h"
|
#include "renderer/Model.h"
|
||||||
|
|
||||||
// Generic client side Octree renderer class.
|
// Generic client side Octree renderer class.
|
||||||
class ModelTreeRenderer : public OctreeRenderer {
|
class ModelTreeRenderer : public OctreeRenderer, public ModelItemFBXService {
|
||||||
public:
|
public:
|
||||||
ModelTreeRenderer();
|
ModelTreeRenderer();
|
||||||
virtual ~ModelTreeRenderer();
|
virtual ~ModelTreeRenderer();
|
||||||
|
@ -38,6 +38,7 @@ public:
|
||||||
virtual void renderElement(OctreeElement* element, RenderArgs* args);
|
virtual void renderElement(OctreeElement* element, RenderArgs* args);
|
||||||
virtual float getSizeScale() const;
|
virtual float getSizeScale() const;
|
||||||
virtual int getBoundaryLevelAdjust() const;
|
virtual int getBoundaryLevelAdjust() const;
|
||||||
|
virtual void setTree(Octree* newTree);
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
|
@ -48,6 +49,8 @@ public:
|
||||||
virtual void init();
|
virtual void init();
|
||||||
virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE);
|
virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE);
|
||||||
|
|
||||||
|
virtual const FBXGeometry* getGeometryForModel(const ModelItem& modelItem);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Model* getModel(const ModelItem& modelItem);
|
Model* getModel(const ModelItem& modelItem);
|
||||||
QMap<uint32_t, Model*> _knownModelsItemModels;
|
QMap<uint32_t, Model*> _knownModelsItemModels;
|
||||||
|
|
|
@ -2052,3 +2052,40 @@ FBXGeometry readSVO(const QByteArray& model) {
|
||||||
|
|
||||||
return geometry;
|
return geometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void calculateRotatedExtents(Extents& extents, const glm::quat& rotation) {
|
||||||
|
glm::vec3 bottomLeftNear(extents.minimum.x, extents.minimum.y, extents.minimum.z);
|
||||||
|
glm::vec3 bottomRightNear(extents.maximum.x, extents.minimum.y, extents.minimum.z);
|
||||||
|
glm::vec3 bottomLeftFar(extents.minimum.x, extents.minimum.y, extents.maximum.z);
|
||||||
|
glm::vec3 bottomRightFar(extents.maximum.x, extents.minimum.y, extents.maximum.z);
|
||||||
|
glm::vec3 topLeftNear(extents.minimum.x, extents.maximum.y, extents.minimum.z);
|
||||||
|
glm::vec3 topRightNear(extents.maximum.x, extents.maximum.y, extents.minimum.z);
|
||||||
|
glm::vec3 topLeftFar(extents.minimum.x, extents.maximum.y, extents.maximum.z);
|
||||||
|
glm::vec3 topRightFar(extents.maximum.x, extents.maximum.y, extents.maximum.z);
|
||||||
|
|
||||||
|
glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear;
|
||||||
|
glm::vec3 bottomRightNearRotated = rotation * bottomRightNear;
|
||||||
|
glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar;
|
||||||
|
glm::vec3 bottomRightFarRotated = rotation * bottomRightFar;
|
||||||
|
glm::vec3 topLeftNearRotated = rotation * topLeftNear;
|
||||||
|
glm::vec3 topRightNearRotated = rotation * topRightNear;
|
||||||
|
glm::vec3 topLeftFarRotated = rotation * topLeftFar;
|
||||||
|
glm::vec3 topRightFarRotated = rotation * topRightFar;
|
||||||
|
|
||||||
|
extents.minimum = glm::min(bottomLeftNearRotated,
|
||||||
|
glm::min(bottomRightNearRotated,
|
||||||
|
glm::min(bottomLeftFarRotated,
|
||||||
|
glm::min(bottomRightFarRotated,
|
||||||
|
glm::min(topLeftNearRotated,
|
||||||
|
glm::min(topRightNearRotated,
|
||||||
|
glm::min(topLeftFarRotated,topRightFarRotated)))))));
|
||||||
|
|
||||||
|
extents.maximum = glm::max(bottomLeftNearRotated,
|
||||||
|
glm::max(bottomRightNearRotated,
|
||||||
|
glm::max(bottomLeftFarRotated,
|
||||||
|
glm::max(bottomRightFarRotated,
|
||||||
|
glm::max(topLeftNearRotated,
|
||||||
|
glm::max(topRightNearRotated,
|
||||||
|
glm::max(topLeftFarRotated,topRightFarRotated)))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,8 @@ public:
|
||||||
bool containsPoint(const glm::vec3& point) const;
|
bool containsPoint(const glm::vec3& point) const;
|
||||||
|
|
||||||
/// \return whether or not the extents are empty
|
/// \return whether or not the extents are empty
|
||||||
bool isEmpty() { return minimum == maximum; }
|
bool isEmpty() const { return minimum == maximum; }
|
||||||
|
bool isValid() const { return !((minimum == glm::vec3(FLT_MAX)) && (maximum == glm::vec3(-FLT_MAX))); }
|
||||||
|
|
||||||
glm::vec3 minimum;
|
glm::vec3 minimum;
|
||||||
glm::vec3 maximum;
|
glm::vec3 maximum;
|
||||||
|
@ -238,4 +239,6 @@ FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping);
|
||||||
/// Reads SVO geometry from the supplied model data.
|
/// Reads SVO geometry from the supplied model data.
|
||||||
FBXGeometry readSVO(const QByteArray& model);
|
FBXGeometry readSVO(const QByteArray& model);
|
||||||
|
|
||||||
|
void calculateRotatedExtents(Extents& extents, const glm::quat& rotation);
|
||||||
|
|
||||||
#endif // hifi_FBXReader_h
|
#endif // hifi_FBXReader_h
|
||||||
|
|
|
@ -20,6 +20,11 @@ public:
|
||||||
virtual void modelCreated(const ModelItem& newModel, const SharedNodePointer& senderNode) = 0;
|
virtual void modelCreated(const ModelItem& newModel, const SharedNodePointer& senderNode) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ModelItemFBXService {
|
||||||
|
public:
|
||||||
|
virtual const FBXGeometry* getGeometryForModel(const ModelItem& modelItem) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class ModelTree : public Octree {
|
class ModelTree : public Octree {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -74,6 +79,11 @@ public:
|
||||||
|
|
||||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||||
void handleAddModelResponse(const QByteArray& packet);
|
void handleAddModelResponse(const QByteArray& packet);
|
||||||
|
|
||||||
|
void setFBXService(ModelItemFBXService* service) { _fbxService = service; }
|
||||||
|
const FBXGeometry* getGeometryForModel(const ModelItem& modelItem) {
|
||||||
|
return _fbxService ? _fbxService->getGeometryForModel(modelItem) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -96,6 +106,7 @@ private:
|
||||||
|
|
||||||
QReadWriteLock _recentlyDeletedModelsLock;
|
QReadWriteLock _recentlyDeletedModelsLock;
|
||||||
QMultiMap<quint64, uint32_t> _recentlyDeletedModelItemIDs;
|
QMultiMap<quint64, uint32_t> _recentlyDeletedModelItemIDs;
|
||||||
|
ModelItemFBXService* _fbxService;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ModelTree_h
|
#endif // hifi_ModelTree_h
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <FBXReader.h>
|
||||||
#include <GeometryUtil.h>
|
#include <GeometryUtil.h>
|
||||||
|
|
||||||
#include "ModelTree.h"
|
#include "ModelTree.h"
|
||||||
|
@ -158,7 +159,41 @@ bool ModelTreeElement::findDetailedRayIntersection(const glm::vec3& origin, cons
|
||||||
|
|
||||||
// if the ray doesn't intersect with our cube, we can stop searching!
|
// if the ray doesn't intersect with our cube, we can stop searching!
|
||||||
if (modelCube.findRayIntersection(origin, direction, localDistance, localFace)) {
|
if (modelCube.findRayIntersection(origin, direction, localDistance, localFace)) {
|
||||||
if (localDistance < distance) {
|
const FBXGeometry* fbxGeometry = _myTree->getGeometryForModel(model);
|
||||||
|
if (fbxGeometry && fbxGeometry->meshExtents.isValid()) {
|
||||||
|
Extents extents = fbxGeometry->meshExtents;
|
||||||
|
|
||||||
|
// NOTE: these extents are model space, so we need to scale and center them accordingly
|
||||||
|
// size is our "target size in world space"
|
||||||
|
// we need to set our model scale so that the extents of the mesh, fit in a cube that size...
|
||||||
|
float maxDimension = glm::distance(extents.maximum, extents.minimum);
|
||||||
|
float scale = model.getSize() / maxDimension;
|
||||||
|
|
||||||
|
glm::vec3 halfDimensions = (extents.maximum - extents.minimum) * 0.5f;
|
||||||
|
glm::vec3 offset = -extents.minimum - halfDimensions;
|
||||||
|
|
||||||
|
extents.minimum += offset;
|
||||||
|
extents.maximum += offset;
|
||||||
|
|
||||||
|
extents.minimum *= scale;
|
||||||
|
extents.maximum *= scale;
|
||||||
|
|
||||||
|
calculateRotatedExtents(extents, model.getModelRotation());
|
||||||
|
|
||||||
|
extents.minimum += model.getPosition();
|
||||||
|
extents.maximum += model.getPosition();
|
||||||
|
|
||||||
|
AABox rotatedExtentsBox(extents.minimum, (extents.maximum - extents.minimum));
|
||||||
|
|
||||||
|
if (rotatedExtentsBox.findRayIntersection(origin, direction, localDistance, localFace)) {
|
||||||
|
if (localDistance < distance) {
|
||||||
|
distance = localDistance;
|
||||||
|
face = localFace;
|
||||||
|
*intersectedObject = (void*)(&model);
|
||||||
|
somethingIntersected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (localDistance < distance) {
|
||||||
distance = localDistance;
|
distance = localDistance;
|
||||||
face = localFace;
|
face = localFace;
|
||||||
*intersectedObject = (void*)(&model);
|
*intersectedObject = (void*)(&model);
|
||||||
|
|
Loading…
Reference in a new issue