diff --git a/examples/editModels.js b/examples/editModels.js index 30d1e4edf4..1db6901e23 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -40,6 +40,8 @@ var modelURLs = [ var toolBar; +var jointList = MyAvatar.getJointNames(); + function isLocked(properties) { // special case to lock the ground plane model in hq. if (location.hostname == "hq.highfidelity.io" && @@ -81,10 +83,13 @@ function controller(wichSide) { this.grabbing = false; this.modelID = { isKnownID: false }; + this.modelURL = ""; this.oldModelRotation; this.oldModelPosition; this.oldModelRadius; + this.jointsIntersectingFromStart = []; + this.laser = Overlays.addOverlay("line3d", { position: { x: 0, y: 0, z: 0 }, end: { x: 0, y: 0, z: 0 }, @@ -134,16 +139,65 @@ function controller(wichSide) { this.grabbing = true; this.modelID = modelID; + this.modelURL = properties.modelURL; this.oldModelPosition = properties.position; this.oldModelRotation = properties.modelRotation; this.oldModelRadius = properties.radius; + + this.jointsIntersectingFromStart = []; + for (var i = 0; i < jointList.length; i++) { + var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); + if (distance < this.oldModelRadius) { + this.jointsIntersectingFromStart.push(i); + } + } } } this.release = function () { + if (this.grabbing) { + if (jointList.length <= 0) { + jointList = MyAvatar.getJointNames(); + } + + var closestJointIndex = -1; + var closestJointDistance = 10; + for (var i = 0; i < jointList.length; i++) { + var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); + if (distance < closestJointDistance) { + closestJointDistance = distance; + closestJointIndex = i; + } + } + + print("closestJoint: " + jointList[closestJointIndex]); + print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelRadius + ")"); + + if (closestJointDistance < this.oldModelRadius) { + + if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1) { + // Do nothing + } else { + print("Attaching to " + jointList[closestJointIndex]); + var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); + var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); + + var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition); + attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); + var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); + + MyAvatar.attach(this.modelURL, jointList[closestJointIndex], + attachmentOffset, attachmentRotation, 2.0 * this.oldModelRadius, + true, false); + Models.deleteModel(this.modelID); + } + } + } + this.grabbing = false; this.modelID.isKnownID = false; + this.jointsIntersectingFromStart = []; } this.checkTrigger = function () { @@ -251,11 +305,6 @@ function controller(wichSide) { position: newPosition, modelRotation: newRotation }); -// print("Moving " + this.modelID.id); -// Vec3.print("Old Position: ", this.oldModelPosition); -// Vec3.print("Sav Position: ", newPosition); -// Quat.print("Old Rotation: ", this.oldModelRotation); -// Quat.print("New Rotation: ", newRotation); this.oldModelRotation = newRotation; this.oldModelPosition = newPosition; @@ -410,8 +459,6 @@ function checkController(deltaTime) { moveOverlays(); } - - function initToolBar() { toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); // New Model diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 14bea50bb0..22df8604e1 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -28,8 +28,10 @@ var NEW_VOXEL_SIZE = 1.0; var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0; var PIXELS_PER_EXTRUDE_VOXEL = 16; var WHEEL_PIXELS_PER_SCALE_CHANGE = 100; -var MAX_VOXEL_SCALE = 16.0; -var MIN_VOXEL_SCALE = 1.0 / Math.pow(2.0, 8.0); +var MAX_VOXEL_SCALE_POWER = 4; +var MIN_VOXEL_SCALE_POWER = -8; +var MAX_VOXEL_SCALE = Math.pow(2.0, MAX_VOXEL_SCALE_POWER); +var MIN_VOXEL_SCALE = Math.pow(2.0, MIN_VOXEL_SCALE_POWER); var WHITE_COLOR = { red: 255, green: 255, blue: 255 }; var MAX_PASTE_VOXEL_SCALE = 256; @@ -330,6 +332,13 @@ function ScaleSelector() { visible: false }); this.setScale = function(scale) { + if (scale > MAX_VOXEL_SCALE) { + scale = MAX_VOXEL_SCALE; + } + if (scale < MIN_VOXEL_SCALE) { + scale = MIN_VOXEL_SCALE; + } + this.scale = scale; this.power = Math.floor(Math.log(scale) / Math.log(2)); rescaleImport(); @@ -391,12 +400,9 @@ function ScaleSelector() { this.incrementScale = function() { copyScale = false; - if (this.power < 13) { + if (this.power < MAX_VOXEL_SCALE_POWER) { ++this.power; this.scale *= 2.0; - if (this.scale > MAX_VOXEL_SCALE) { - this.scale = MAX_VOXEL_SCALE; - } this.update(); rescaleImport(); resizeVoxelSound.play(voxelSizePlus); @@ -405,7 +411,7 @@ function ScaleSelector() { this.decrementScale = function() { copyScale = false; - if (-4 < this.power) { + if (MIN_VOXEL_SCALE_POWER < this.power) { --this.power; this.scale /= 2.0; this.update(); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 306dc0194e..870d5b1a53 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -378,10 +378,10 @@ void Avatar::simulateAttachments(float deltaTime) { model->setLODDistance(getLODDistance()); } if (_skeletonModel.getJointPosition(jointIndex, jointPosition) && - _skeletonModel.getJointRotation(jointIndex, jointRotation)) { + _skeletonModel.getJointCombinedRotation(jointIndex, jointRotation)) { model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale); model->setRotation(jointRotation * attachment.rotation); - model->setScale(_skeletonModel.getScale() * attachment.scale); + model->setScaleToFit(true, _scale * attachment.scale); model->simulate(deltaTime); } } @@ -705,6 +705,54 @@ QStringList Avatar::getJointNames() const { return _skeletonModel.isActive() ? _skeletonModel.getGeometry()->getFBXGeometry().getJointNames() : QStringList(); } +glm::vec3 Avatar::getJointPosition(int index) const { + if (QThread::currentThread() != thread()) { + glm::vec3 position; + QMetaObject::invokeMethod(const_cast(this), "getJointPosition", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::vec3, position), Q_ARG(const int, index)); + return position; + } + glm::vec3 position; + _skeletonModel.getJointPosition(index, position); + return position; +} + +glm::vec3 Avatar::getJointPosition(const QString& name) const { + if (QThread::currentThread() != thread()) { + glm::vec3 position; + QMetaObject::invokeMethod(const_cast(this), "getJointPosition", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::vec3, position), Q_ARG(const QString&, name)); + return position; + } + glm::vec3 position; + _skeletonModel.getJointPosition(getJointIndex(name), position); + return position; +} + +glm::quat Avatar::getJointCombinedRotation(int index) const { + if (QThread::currentThread() != thread()) { + glm::quat rotation; + QMetaObject::invokeMethod(const_cast(this), "getJointCombinedRotation", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::quat, rotation), Q_ARG(const int, index)); + return rotation; + } + glm::quat rotation; + _skeletonModel.getJointCombinedRotation(index, rotation); + return rotation; +} + +glm::quat Avatar::getJointCombinedRotation(const QString& name) const { + if (QThread::currentThread() != thread()) { + glm::quat rotation; + QMetaObject::invokeMethod(const_cast(this), "getJointCombinedRotation", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::quat, rotation), Q_ARG(const QString&, name)); + return rotation; + } + glm::quat rotation; + _skeletonModel.getJointCombinedRotation(getJointIndex(name), rotation); + return rotation; +} + void Avatar::setFaceModelURL(const QUrl& faceModelURL) { AvatarData::setFaceModelURL(faceModelURL); const QUrl DEFAULT_FACE_MODEL_URL = QUrl::fromLocalFile(Application::resourcesPath() + "meshes/defaultAvatar_head.fst"); @@ -734,6 +782,8 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { // update the urls for (int i = 0; i < attachmentData.size(); i++) { + _attachmentModels[i]->setSnapModelToCenter(true); + _attachmentModels[i]->setScaleToFit(true, _scale * _attachmentData.at(i).scale); _attachmentModels[i]->setURL(attachmentData.at(i).modelURL); } } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index db13656546..f928881068 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -152,7 +152,12 @@ public: quint32 getCollisionGroups() const { return _collisionGroups; } virtual void setCollisionGroups(quint32 collisionGroups) { _collisionGroups = (collisionGroups & VALID_COLLISION_GROUPS); } - + + Q_INVOKABLE glm::vec3 getJointPosition(int index) const; + Q_INVOKABLE glm::vec3 getJointPosition(const QString& name) const; + Q_INVOKABLE glm::quat getJointCombinedRotation(int index) const; + Q_INVOKABLE glm::quat getJointCombinedRotation(const QString& name) const; + public slots: void updateCollisionGroups(); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 1a857ff811..ee774c183a 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -634,8 +634,16 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind) return false; } rotation = _jointStates[jointIndex]._combinedRotation * - (fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation : - _geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation); + (fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation : + _geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation); + return true; +} + +bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const { + if (jointIndex == -1 || _jointStates.isEmpty()) { + return false; + } + rotation = _jointStates[jointIndex]._combinedRotation; return true; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index b8a5de5902..af00c15168 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -144,6 +144,7 @@ public: bool getJointPosition(int jointIndex, glm::vec3& position) const; bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const; + bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; QStringList getJointNames() const;