Reputation: 419
I'm trying to pivot a piece of a headphone set. It's capable of doing such in my model (in Maya).. but I can't seem to figure it out in threejs.
I know I can rotate my objects X Y and Z by doing something like this:
object.rotateX(THREE.Math.degToRad(degreeX));
object.rotateY(THREE.Math.degToRad(degreeY));
object.rotateZ(THREE.Math.degToRad(degreeZ));
But how do I keep the pivot point stationary while the rests rotates/moves? So in my example, I'd want the ear piece to be able to move left and right based off of the black-ish screw you see in my picture.
Upvotes: 2
Views: 462
Reputation:
Parent your model to another THREE.Object3D
but to make it easy use the SceneUtils.attach
function.
Example:
Click then drag, each time you click the pivot object will be moved to that location and then the model (the cube) will be attached to the pivot by calling THREE.SceneUtils.attach(model, scene, pivot)
. When you let off the mouse the model is detached using THREE.SceneUtils.detach(model, pivot, scene)
.
'use strict';
/* global THREE */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas: canvas});
const fov = 45;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 100;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
// make the camera look down
camera.position.set(0, 10, 0);
camera.up.set(0, 0, -1);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
scene.add(new THREE.GridHelper(40, 40));
let model;
{
const cubeSize = 3;
const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
const cubeMat = new THREE.MeshBasicMaterial({color: 'red'});
model = new THREE.Mesh(cubeGeo, cubeMat);
model.position.set(.5, .5, .5);
scene.add(model);
}
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
}
render();
let rotate = false;
const startPos = {x:0, y:0};
const raycaster = new THREE.Raycaster();
const pivot = new THREE.Object3D();
scene.add(pivot);
pivot.add(new THREE.AxesHelper(.5));
function setPivotPoint(e) {
startPos.x = e.clientX;
startPos.y = e.clientY;
const normalizedPosition = {
x: e.clientX / canvas.clientWidth * 2 - 1,
y: e.clientY / canvas.clientHeight * -2 + 1,
};
// this part is NOT important to the answer. The question
// is how to rotate from some point. This code is picking
// a point. Which point to pick was not part of the question
// but to demo the solution it's important to pick a point
// put the pivot where the mouse was clicked
raycaster.setFromCamera(normalizedPosition, camera);
const intersection = raycaster.intersectObjects(scene.children)[0];
if (intersection) {
if (rotate) {
removeFromPivot();
}
pivot.position.copy(intersection.point);
pivot.rotation.set(0,0,0);
pivot.updateMatrixWorld();
rotate = true;
// this the important part. We're making the cube
// a child of 'pivot' without it moving in world space
THREE.SceneUtils.attach(model, scene, pivot);
render();
}
}
function rotatePivot(e) {
e.preventDefault();
if (rotate) {
const dx = e.clientX - startPos.x;
const dy = e.clientY - startPos.y;
const maxDelta = Math.abs(dx) > Math.abs(dy) ? dx : dy;
pivot.rotation.y = maxDelta * 0.01;
render();
}
}
function removeFromPivot() {
if (rotate) {
rotate = false;
THREE.SceneUtils.detach(model, pivot, scene);
window.removeEventListener('mousemove', rotatePivot);
window.removeEventListener('mouseup', removeFromPivot);
}
}
canvas.addEventListener('mousedown', (e) => {
e.preventDefault();
setPivotPoint(e);
if (rotate) {
window.addEventListener('mousemove', rotatePivot);
window.addEventListener('mouseup', removeFromPivot);
}
});
}
main();
html, body {
margin: 0;
height: 100%;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r98/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r98/js/utils/SceneUtils.js"></script>
Upvotes: 2
Reputation: 28472
You could nest your headphones Mesh inside another THREE.Group
, reposition the headphones inside this group so the pivot is in the desired position, then rotate the parent.
// You take your headphones and nest them inside a Group
var headphones = new THREE.Mesh(geom, material);
var parent = new THREE.Group();
parent.add(headphones);
// Then you move your headphones to the desired pivot position
headphones.position.set(-5, 0.1, 0);
// Parent is going to rotate around it origin
parent.rotateX(THREE.Math.degToRad(degreeX));
Note that if you want the pivot to be at (5, -0.1, 0)
, you should move headphones in the opposite direction: (-5, 0.1, 0)
.
Upvotes: 2