This commit is contained in:
Andrzej Kapolka 2014-05-27 17:26:56 -07:00
commit 9796334160
7 changed files with 231 additions and 142 deletions

View file

@ -188,7 +188,7 @@ function controller(wichSide) {
var X = Vec3.sum(A, Vec3.multiply(B, x)); var X = Vec3.sum(A, Vec3.multiply(B, x));
var d = Vec3.length(Vec3.subtract(P, X)); var d = Vec3.length(Vec3.subtract(P, X));
if (d < properties.radius && 0 < x && x < LASER_LENGTH_FACTOR) { if (0 < x && x < LASER_LENGTH_FACTOR) {
return { valid: true, x: x, y: y, z: z }; return { valid: true, x: x, y: y, z: z };
} }
return { valid: false }; return { valid: false };
@ -293,39 +293,43 @@ function controller(wichSide) {
if (this.pressing) { if (this.pressing) {
Vec3.print("Looking at: ", this.palmPosition); Vec3.print("Looking at: ", this.palmPosition);
var foundModels = Models.findModels(this.palmPosition, LASER_LENGTH_FACTOR); var pickRay = { origin: this.palmPosition,
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) };
var foundIntersection = Models.findRayIntersection(pickRay);
for (var i = 0; i < foundModels.length; i++) { if(!foundIntersection.accurate) {
return;
if (!foundModels[i].isKnownID) { }
var identify = Models.identifyModel(foundModels[i]); var foundModel = foundIntersection.modelID;
if (!identify.isKnownID) {
print("Unknown ID " + identify.id + "(update loop)"); if (!foundModel.isKnownID) {
return; var identify = Models.identifyModel(foundModel);
} if (!identify.isKnownID) {
foundModels[i] = identify; print("Unknown ID " + identify.id + " (update loop " + foundModel.id + ")");
continue;
} }
foundModel = identify;
var properties = Models.getModelProperties(foundModels[i]); }
print("foundModels["+i+"].modelURL=" + properties.modelURL);
var properties = Models.getModelProperties(foundModel);
if (isLocked(properties)) { print("foundModel.modelURL=" + properties.modelURL);
print("Model locked " + properties.id);
} else { if (isLocked(properties)) {
print("Checking properties: " + properties.id + " " + properties.isKnownID); print("Model locked " + properties.id);
var check = this.checkModel(properties); } else {
if (check.valid) { print("Checking properties: " + properties.id + " " + properties.isKnownID);
this.grab(foundModels[i], properties); var check = this.checkModel(properties);
this.x = check.x; if (check.valid) {
this.y = check.y; this.grab(foundModel, properties);
this.z = check.z; this.x = check.x;
return; this.y = check.y;
} this.z = check.z;
return;
} }
} }
} }
} }
this.cleanup = function () { this.cleanup = function () {
Overlays.deleteOverlay(this.laser); Overlays.deleteOverlay(this.laser);
Overlays.deleteOverlay(this.ball); Overlays.deleteOverlay(this.ball);
@ -478,93 +482,97 @@ function mousePressEvent(event) {
} else { } else {
var pickRay = Camera.computePickRay(event.x, event.y); var pickRay = Camera.computePickRay(event.x, event.y);
Vec3.print("[Mouse] Looking at: ", pickRay.origin); Vec3.print("[Mouse] Looking at: ", pickRay.origin);
var foundModels = Models.findModels(pickRay.origin, LASER_LENGTH_FACTOR); var foundIntersection = Models.findRayIntersection(pickRay);
var closest = -1.0;
for (var i = 0; i < foundModels.length; i++) { if(!foundIntersection.accurate) {
if (!foundModels[i].isKnownID) { return;
var identify = Models.identifyModel(foundModels[i]); }
if (!identify.isKnownID) { var foundModel = foundIntersection.modelID;
print("Unknown ID " + identify.id + "(update loop)");
continue; if (!foundModel.isKnownID) {
} var identify = Models.identifyModel(foundModel);
foundModels[i] = identify; if (!identify.isKnownID) {
} print("Unknown ID " + identify.id + " (update loop " + foundModel.id + ")");
continue;
var properties = Models.getModelProperties(foundModels[i]);
if (isLocked(properties)) {
print("Model locked " + properties.id);
} else {
print("Checking properties: " + properties.id + " " + properties.isKnownID);
// P P - Model
// /| A - Palm
// / | d B - unit vector toward tip
// / | X - base of the perpendicular line
// A---X----->B d - distance fom axis
// x x - distance from A
//
// |X-A| = (P-A).B
// X == A + ((P-A).B)B
// d = |P-X|
var A = pickRay.origin;
var B = Vec3.normalize(pickRay.direction);
var P = properties.position;
var x = Vec3.dot(Vec3.subtract(P, A), B);
var X = Vec3.sum(A, Vec3.multiply(B, x));
var d = Vec3.length(Vec3.subtract(P, X));
if (d < properties.radius && 0 < x && x < LASER_LENGTH_FACTOR) {
if (closest < 0.0) {
closest = x;
}
if (x <= closest) {
modelSelected = true;
selectedModelID = foundModels[i];
selectedModelProperties = properties;
orientation = MyAvatar.orientation;
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
}
}
} }
foundModel = identify;
} }
if (modelSelected) { var properties = Models.getModelProperties(foundModel);
selectedModelProperties.oldRadius = selectedModelProperties.radius; if (isLocked(properties)) {
selectedModelProperties.oldPosition = { print("Model locked " + properties.id);
x: selectedModelProperties.position.x, } else {
y: selectedModelProperties.position.y, print("Checking properties: " + properties.id + " " + properties.isKnownID);
z: selectedModelProperties.position.z, // P P - Model
}; // /| A - Palm
selectedModelProperties.oldRotation = { // / | d B - unit vector toward tip
x: selectedModelProperties.modelRotation.x, // / | X - base of the perpendicular line
y: selectedModelProperties.modelRotation.y, // A---X----->B d - distance fom axis
z: selectedModelProperties.modelRotation.z, // x x - distance from A
w: selectedModelProperties.modelRotation.w, //
}; // |X-A| = (P-A).B
// X == A + ((P-A).B)B
// d = |P-X|
selectedModelProperties.glowLevel = 0.1; var A = pickRay.origin;
Models.editModel(selectedModelID, { glowLevel: selectedModelProperties.glowLevel}); var B = Vec3.normalize(pickRay.direction);
var P = properties.position;
print("Clicked on " + selectedModelID.id + " " + modelSelected); var x = Vec3.dot(Vec3.subtract(P, A), B);
var X = Vec3.sum(A, Vec3.multiply(B, x));
var d = Vec3.length(Vec3.subtract(P, X));
if (0 < x && x < LASER_LENGTH_FACTOR) {
modelSelected = true;
selectedModelID = foundModel;
selectedModelProperties = properties;
orientation = MyAvatar.orientation;
intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation));
}
} }
} }
if (modelSelected) {
selectedModelProperties.oldRadius = selectedModelProperties.radius;
selectedModelProperties.oldPosition = {
x: selectedModelProperties.position.x,
y: selectedModelProperties.position.y,
z: selectedModelProperties.position.z,
};
selectedModelProperties.oldRotation = {
x: selectedModelProperties.modelRotation.x,
y: selectedModelProperties.modelRotation.y,
z: selectedModelProperties.modelRotation.z,
w: selectedModelProperties.modelRotation.w,
};
selectedModelProperties.glowLevel = 0.0;
print("Clicked on " + selectedModelID.id + " " + modelSelected);
}
} }
Controller.mouseReleaseEvent.connect(function() { var glowedModelID = { id: -1, isKnownID: false };
if (modelSelected) {
Models.editModel(selectedModelID, { glowLevel: 0.0 });
modelSelected = false;
}
});
var oldModifier = 0; var oldModifier = 0;
var modifier = 0; var modifier = 0;
var wasShifted = false; var wasShifted = false;
function mouseMoveEvent(event) { function mouseMoveEvent(event) {
var pickRay = Camera.computePickRay(event.x, event.y);
if (!modelSelected) { if (!modelSelected) {
var modelIntersection = Models.findRayIntersection(pickRay);
if (modelIntersection.accurate) {
if(glowedModelID.isKnownID && glowedModelID.id != modelIntersection.modelID.id) {
Models.editModel(glowedModelID, { glowLevel: 0.0 });
glowedModelID.id = -1;
glowedModelID.isKnownID = false;
}
if (modelIntersection.modelID.isKnownID) {
Models.editModel(modelIntersection.modelID, { glowLevel: 0.25 });
glowedModelID = modelIntersection.modelID;
}
}
return; return;
} }
@ -579,8 +587,7 @@ function mouseMoveEvent(event) {
} else { } else {
modifier = 0; modifier = 0;
} }
pickRay = Camera.computePickRay(event.x, event.y);
var pickRay = Camera.computePickRay(event.x, event.y);
if (wasShifted != event.isShifted || modifier != oldModifier) { if (wasShifted != event.isShifted || modifier != oldModifier) {
selectedModelProperties.oldRadius = selectedModelProperties.radius; selectedModelProperties.oldRadius = selectedModelProperties.radius;
@ -653,6 +660,15 @@ function mouseMoveEvent(event) {
Models.editModel(selectedModelID, selectedModelProperties); Models.editModel(selectedModelID, selectedModelProperties);
} }
function mouseReleaseEvent(event) {
modelSelected = false;
glowedModelID.id = -1;
glowedModelID.isKnownID = false;
}
function setupModelMenus() { function setupModelMenus() {
// add our menuitems // add our menuitems
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" });
@ -677,6 +693,7 @@ Script.scriptEnding.connect(scriptEnding);
Script.update.connect(checkController); Script.update.connect(checkController);
Controller.mousePressEvent.connect(mousePressEvent); Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseMoveEvent.connect(mouseMoveEvent); Controller.mouseMoveEvent.connect(mouseMoveEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
setupModelMenus(); setupModelMenus();
Menu.menuItemEvent.connect(function(menuItem){ Menu.menuItemEvent.connect(function(menuItem){

View file

@ -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();

View file

@ -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;

View file

@ -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)))))));
}

View file

@ -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

View file

@ -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

View file

@ -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);