Javascript threejs multi scene and mouse event - three.js

I am using Threejs for container cargo loading interactive program. Since my cargo loading plan is layer by layer for one container. So I want to divide the browser into multiple scenes. Each scene represents one layer. Every layer has its own arrangement of cargo boxes and operator could make some adjustment. And all cargo boxes are cubic type of shape.
My codes are based on example, webgl_interactive_cubes_ortho.html (r82), and I does not so many cubes in the example so I modify the code example a little bit.
The example codes works but only has one scene with Viewport. Since I want to divide browser vertically, so I begin to divide the height into 2 scenes. Then even I just devided Viewport into 2, see Render method in the script, Then I could not catch object selected in mouse down event.
What I believe is because of mouse click and 3D scene transform calculation. Anyway, in my case, I just want to select the object and drag and drop. Anyone could help me to make the object selected and can make drag and drop?
/1/
//var height = renderer.domElement.height/2; //only want to divide into two layers
/2/
var container, stats;
var camera, scene, scene2, raycaster, renderer;
var cameras =[];
var mouse = new THREE.Vector2(), INTERSECTED,SELECTED;
var radius = 500, theta = 0;
var offset = new THREE.Vector3();
var frustumSize = 1000;
var cubesL0=[], cubesL1=[];
var plane = new THREE.Plane();
var intersection = new THREE.Vector3();
var scenes =[];
var aspect = window.innerWidth / window.innerHeight;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'three.js webgl - interactive cubes';
container.appendChild( info );
camera = new THREE.OrthographicCamera( frustumSize * aspect / - 2, frustumSize * aspect / 2, frustumSize /2 , frustumSize / -2, 1, 1000 );
scene = new THREE.Scene();
scene2 = new THREE.Scene();
var geometry = new THREE.BoxBufferGeometry( 150, 150, 150 );
for ( var i = 0; i < 2; i ++ ) {
var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0x000fff } ) );
if(i==0){
object.position.x = - 100;
object.position.y = - 100;
object.position.z = - 100;
}else{
object.position.x = 200;
object.position.y = -359;
object.position.z = -50;
}
scene.add( object );
scenes.push(scene);
cubesL0.push(object);
}
raycaster = new THREE.Raycaster();
renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.sortObjects = false;
container.appendChild(renderer.domElement);
stats = new Stats();
container.appendChild( stats.dom );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
var aspect = window.innerWidth / window.innerHeight;
camera.left = - frustumSize * aspect / 2;
camera.right = frustumSize * aspect / 2;
camera.top = frustumSize / 2;
camera.bottom = - frustumSize / 2;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = (- ( event.clientY / window.innerHeight) * 2 + 1);
console.log("mouse x:"+mouse.x+", mouse y:"+mouse.y);
raycaster.setFromCamera( mouse, camera );
if ( SELECTED ) {
if ( raycaster.ray.intersectPlane( plane, intersection ) ) {
SELECTED.position.copy( intersection.sub( offset ) );
}
return;
}
var intersects = raycaster.intersectObjects( cubesL0 );
if ( intersects.length > 0 ) {
console.log(" there is object going to move");
if ( INTERSECTED != intersects[ 0 ].object ) {
if ( INTERSECTED ) INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
plane.setFromNormalAndCoplanarPoint(
camera.getWorldDirection( plane.normal ),
INTERSECTED.position );
}
container.style.cursor = 'pointer';
} else {
if ( INTERSECTED ) INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
INTERSECTED = null;
container.style.cursor = 'auto';
}
}
function onDocumentMouseDown( event ) {
event.preventDefault();
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( cubesL0 );
var getTarget = true;
if ( intersects.length > 0 ) {
SELECTED = intersects[ 0 ].object;
if ( raycaster.ray.intersectPlane( plane, intersection ) ) {
offset.copy( intersection ).sub( SELECTED.position );
}
container.style.cursor = 'move';
}
}
function onDocumentMouseUp( event ) {
event.preventDefault();
console.log(" in mouse up event ");
if ( INTERSECTED ) {
SELECTED = null;
}
container.style.cursor = 'auto';
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
var width = renderer.domElement.width;
var height = renderer.domElement.height;
//var height = renderer.domElement.height/2; //only want to divide into two layers
var left = 0;
var bottom = 0;
renderer.setViewport( left, bottom, width, height );
renderer.setScissor( left, bottom, width, height );
renderer.render( scene, camera );
}
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - interactive cubes</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/libs/stats.min.js"></script>
</body>
</html>

Related

Javascript threejs 3D draw solid cubic with border

I follow threejs example, webgl_interactive_draggablecubes.html. My project is to use Threejs to make a container loading plan. So I want to make solid cubic with a border. something we could see with/without border difference.
,
I could use multi-material, but then my drag and drop is broken. The code snippet in creating Geometry3 is commented.
My question is: how to make solid cubic with border and at the same time could be drag and drop?
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - draggable cubes</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="js/three.js"></script>
<script src="js/TrackballControls.js"></script>
<script src="js/stats.min.js"></script>
<script>
var container, stats;
var camera, controls, scene, renderer;
var cubes = [];
var plane = new THREE.Plane();
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2(),
offset = new THREE.Vector3(),
intersection = new THREE.Vector3(),
INTERSECTED, SELECTED;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 10;
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
scene = new THREE.Scene();
scene.add( new THREE.AmbientLight( 0x505050 ) );
var geometry = new THREE.BoxGeometry( 2, 5, 7);
var hex = 0xff0000;
for ( var i = 0; i < geometry.faces.length; i++ ) {
geometry.faces[ i ].color.setHex( hex );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5,wireframe:true } );
var cube = new THREE.Mesh( geometry, material );
cubes.push( cube );
var geometry2 = new THREE.BoxGeometry(2,4, 5);
var hex2 = 0x009fff;
for ( var i = 0; i < geometry2.faces.length; i++ ) {
geometry2.faces[ i ].color.setHex( hex2 );
}
var material2 = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5,wireframe:true } );
var cube2 = new THREE.Mesh( geometry2, material2 );
cubes.push( cube2 );
var geometry3 = new THREE.BoxGeometry(1,3,4);
var hex3 = 0x0f0ff0;
for ( var i = 0; i < geometry3.faces.length; i++ ) {
geometry3.faces[ i ].color.setHex( hex3 );
}
/* var darkMaterial3= new THREE.MeshBasicMaterial( { color: 0xffffcc } );
var wireframeMaterial3= new THREE.MeshBasicMaterial( { color: 0x0f0000, wireframe: true, transparent: false } );
var multiMaterial3= [ darkMaterial3, wireframeMaterial3 ];
var cube3 = THREE.SceneUtils.createMultiMaterialObject(geometry3,multiMaterial3);*/
var material3 = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5,wireframe:true } );
var cube3 = new THREE.Mesh( geometry3, material3 );
cubes.push( cube3 );
scene.add(cube);
scene.add(cube2);
scene.add(cube3);
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setClearColor( 0xf0f0f0 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.sortObjects = false;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
container.appendChild( renderer.domElement );
stats = new Stats();
container.appendChild( stats.dom );
renderer.domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
renderer.domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
renderer.domElement.addEventListener( 'mouseup', onDocumentMouseUp, false );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
if ( SELECTED ) {
if ( raycaster.ray.intersectPlane( plane, intersection ) ) {
SELECTED.position.copy( intersection.sub( offset ) );
}
return;
}
var intersects = raycaster.intersectObjects( cubes );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if ( INTERSECTED ) INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
plane.setFromNormalAndCoplanarPoint(
camera.getWorldDirection( plane.normal ),
INTERSECTED.position );
}
container.style.cursor = 'pointer';
} else {
if ( INTERSECTED ) INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
INTERSECTED = null;
container.style.cursor = 'auto';
}
}
function onDocumentMouseDown( event ) {
event.preventDefault();
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( cubes );
if ( intersects.length > 0 ) {
controls.enabled = false;
SELECTED = intersects[ 0 ].object;
if ( raycaster.ray.intersectPlane( plane, intersection ) ) {
offset.copy( intersection ).sub( SELECTED.position );
}
container.style.cursor = 'move';
}
}
function onDocumentMouseUp( event ) {
event.preventDefault();
controls.enabled = true;
if ( INTERSECTED ) {
SELECTED = null;
}
container.style.cursor = 'auto';
}
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
controls.update();
renderer.render( scene, camera );
}
</script>
</body>
</html>
Add a WireframeGeometry or EdgesGeometry as a child of each draggable object.
scene.add( object );
objects.push( object );
// wireframe
var geo = new THREE.EdgesGeometry( object.geometry );
var mat = new THREE.LineBasicMaterial( { color: 0x000000 } );
var wireframe = new THREE.LineSegments( geo, mat );
object.add( wireframe );
Also see this related answer.
three.js r.144
I suggest using EdgesHelper
this.scene.add(image3D);
edges = new THREE.EdgesHelper(image3D, 0x808080);
edges.material.linewidth = 3;
this.scene.add(edges);
Example:

Three.js - Collision by raycasting with a rotated origin mesh

Hello I try to control a mesh, he can turn and moove relative to its rotation by mesh.translate.
But for collisions, i cant find how to raycast relative to its rotation.
If the origin mesh is not rotated or if I moove it with mesh.position.x++, it works. But rotated and with translateX(1), it's not ok.
Thank you for your attention.
Here is my function only for right side (+X) :
function coll(b1,b2){
var hit = false;
var dist = (width/2);
var matrix = new THREE.Matrix4();
matrix.extractRotation( b1.matrix );
var origin = new THREE.Vector3(b1.position.x,b1.position.y,b1.position.z);
var direction = new THREE.Vector3( 1, 0, 0 );
direction = matrix.multiplyVector3( direction );
var ray = new THREE.Raycaster(origin, direction,0,dist);
var collisionResult = ray.intersectObject(b2);
if(collisionResult!=0){
hit = true; b1.translateX( -1 );
}else{
hit = false;
}//if
return hit;
}//coll()
And this is the entire code just in case :
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - geometry - cube</title>
<meta charset="utf-8">
<style>
body {
margin: 0px;
background-color: #000000;
overflow: hidden;
color: white;
}
</style>
</head>
<body>
<script src="../build/three.min.js"></script>
<script>
var camera, scene, renderer;
var width = 100;
var mesh, mesh2;
var key = {left:false};
function keyDown(e){
if (e.keyCode == 39) { key.right = true; }
}//keyPress()
window.addEventListener("keydown", keyDown);
function keyUp(e){
if (e.keyCode == 39) { key.right = false; }
}//keyPress()
window.addEventListener("keyup", keyUp);
function moove(m){
if (key.right){
m.translateX( 1 );
//m.position.x++;
}//if
if (key.left){
m.translateX( -1 );
}//if
}//moove()
function coll(b1,b2){
var hit = false;
var dist = (width/2);
var matrix = new THREE.Matrix4();
matrix.extractRotation( b1.matrix );
var origin = new THREE.Vector3(b1.position.x,b1.position.y,b1.position.z);
var direction = new THREE.Vector3( 1, 0, 0 );
direction = matrix.multiplyVector3( direction );
var ray = new THREE.Raycaster(origin, direction,0,dist);
var collisionResult = ray.intersectObject(b2);
if(collisionResult!=0){
hit = true; b1.translateX( -1 );
}else{
hit = false;
}//if
return hit;
}//coll()
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
//
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 400;
scene = new THREE.Scene();
var geometry = new THREE.BoxGeometry( width, 10, 10);
mesh = new THREE.Mesh( geometry);
scene.add( mesh );
mesh.position.x = -100;
mesh.position.y = -20;
mesh.rotation.z = 1;
geometry = new THREE.BoxGeometry( width, 100, 100);
mesh2 = new THREE.Mesh( geometry);
scene.add( mesh2 );
window.addEventListener( 'resize', onWindowResize, false );
}//init()
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}//resize()
function animate() {
requestAnimationFrame( animate );
coll(mesh,mesh2);
moove(mesh);
renderer.render( scene, camera );
}//animate()
</script>
</body>
</html>
I also tried with quaternion but its still the same result :
direction.applyQuaternion( b1.quaternion );
I have a collision with mesh.position.x++ so maybe translateX does something wrong ?
It is ok now. This collision works good finally.

How to rotate object in three.js(r66) not use trackball which is control the camera

When rotating an Object, I think there are two ways[focus on rotate the object, not use camera]:
1.rotate the object directly in render(), just like(canvas_geometry_cube.html)
cube.rotation.y += ( targetRotationY - cube.rotation.y ) * 0.05;
cube.rotation.x += ( targetRotationY - cube.rotation.x ) * 0.05;
However, here has a problem, when you rotate in some angle, it not works.
with the code:
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js canvas - geometry - cube</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="../build/three.min.js"></script>
<script src="js/libs/stats.min.js"></script>
<script>
var container, stats;
var camera, scene, renderer;
var cube, plane;
var targetRotationX = 0;
var targetRotationOnMouseDownX = 0;
var targetRotationY = 0;
var targetRotationOnMouseDownY = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var mouseY = 0;
var mouseYOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'Drag to spin the cube';
container.appendChild( info );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 150;
camera.position.z = 500;
scene = new THREE.Scene();
// Cube
var geometry = new THREE.CubeGeometry( 200, 200, 200 );
for ( var i = 0; i < geometry.faces.length; i += 2 ) {
var hex = Math.random() * 0xffffff;
geometry.faces[ i ].color.setHex( hex );
geometry.faces[ i + 1 ].color.setHex( hex );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5 } );
cube = new THREE.Mesh( geometry, material );
cube.position.y = 150;
scene.add( cube );
// Plane
var geometry = new THREE.PlaneGeometry( 200, 200 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xe0e0e0, overdraw: 0.5 } );
plane = new THREE.Mesh( geometry, material );
scene.add( plane );
renderer = new THREE.CanvasRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function onDocumentMouseDown( event ) {
event.preventDefault();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDownX = targetRotationX;
mouseYOnMouseDown = event.clientY - windowHalfY;
targetRotationOnMouseDownY = targetRotationY;
}
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
targetRotationX = targetRotationOnMouseDownX + ( mouseX - mouseXOnMouseDown ) * 0.02;
mouseY = event.clientY - windowHalfY;
targetRotationY = targetRotationOnMouseDownY + ( mouseY - mouseYOnMouseDown ) * 0.02;
}
function onDocumentMouseUp( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentMouseOut( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentTouchStart( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
targetRotationOnMouseDownX = targetRotationX;
mouseYOnMouseDown = event.touches[ 0 ].pageY - windowHalfY;
targetRotationOnMouseDownY = targetRotationY;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotationX = targetRotationOnMouseDownX + ( mouseX - mouseXOnMouseDown ) * 0.05;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
targetRotationY = targetRotationOnMouseDownY + ( mouseY - mouseYOnMouseDown ) * 0.05;
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
cube.rotation.x += ( targetRotationY - cube.rotation.x ) * 0.05;
cube.rotation.y += ( targetRotationX - cube.rotation.y ) * 0.05;
renderer.render( scene, camera );
}
</script>
</body>
</html>
2.So I try another way, to save the rotation Matrix about the mouse move(refer to the links in https://github.com/mrdoob/three.js/issues/1230).
var newRotationMatrix = new THREE.Matrix4();
newRotationMatrix.identity();
var axisy = new THREE.Vector3(0,1,0);
var axisx = new THREE.Vector3(1,0,0);
var deltaX = newX - lastMouseX;
newRotationMatrix.makeRotationAxis(axisy.normalize(), THREE.Math.degToRad(deltaX / 10));
rotationMatrix.multiply(newRotationMatrix);
var deltaY = newY - lastMouseY;
newRotationMatrix.makeRotationAxis(axisx.normalize(), THREE.Math.degToRad(deltaY / 10));
rotationMatrix.multiply(newRotationMatrix);
and when in the render() I use:
cube.rotation.setRotationFromMatrix(rotationMatrix);
But it does not work.
Can you help me, thank you!
With the whole code:
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js canvas - geometry - cube</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="../build/three.min.js"></script>
<script src="js/libs/stats.min.js"></script>
<script>
var container, stats;
var camera, scene, renderer;
var cube, plane;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
var mouseDown = false;
var lastMouseX = null;
var lastMouseY = null;
var rotationMatrix = new THREE.Matrix4();
rotationMatrix.identity();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'Drag to spin the cube';
container.appendChild( info );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 150;
camera.position.z = 500;
scene = new THREE.Scene();
// Cube
var geometry = new THREE.CubeGeometry( 200, 200, 200 );
for ( var i = 0; i < geometry.faces.length; i += 2 ) {
var hex = Math.random() * 0xffffff;
geometry.faces[ i ].color.setHex( hex );
geometry.faces[ i + 1 ].color.setHex( hex );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5 } );
cube = new THREE.Mesh( geometry, material );
cube.position.y = 150;
scene.add( cube );
// Plane
var geometry = new THREE.PlaneGeometry( 800, 800 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xe0e0e0, overdraw: 0.5 } );
plane = new THREE.Mesh( geometry, material );
plane.position.y = -150;
scene.add( plane );
renderer = new THREE.WebGLRenderer();
//renderer.setClearColor( 0xf0f0f0 );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseUp(event) {
mouseDown = false;
}
function onDocumentMouseDown( event ) {
mouseDown = true;
lastMouseX = event.clientX;
lastMouseY = event.clientY;
}
function onDocumentMouseMove( event ) {
if(!mouseDown)
{
return;
}
var newX = event.clientX;
var newY = event.clientY;
var newRotationMatrix = new THREE.Matrix4();
newRotationMatrix.identity();
var axisy = new THREE.Vector3(0,1,0);
var axisx = new THREE.Vector3(1,0,0);
var deltaX = newX - lastMouseX;
newRotationMatrix.makeRotationAxis(axisy.normalize(), THREE.Math.degToRad(deltaX / 10));
rotationMatrix.multiply(newRotationMatrix);
var deltaY = newY - lastMouseY;
newRotationMatrix.makeRotationAxis(axisx.normalize(), THREE.Math.degToRad(deltaY / 10));
rotationMatrix.multiply(newRotationMatrix);
lastMouseX = newX;
lastMouseY = newY;
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
cube.rotation.setRotationFromMatrix(rotationMatrix);
renderer.render( scene, camera );
}
</script>
</body>
</html>
Rotation solved
Sorry for my poor english.
Object could set rotation from quaternion. So First I get the quaternion from the mouse move.(trackball modify from the control trackball) And then apply to the object.
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js canvas - geometry - cube</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="../build/three.min.js"></script>
<script src="js/libs/stats.min.js"></script>
<script>
var container, stats;
var camera, scene, renderer;
var cube, plane;
var mouseDown = false;
var rotateStartP = new THREE.Vector3(0,0,1);
var rotateEndP = new THREE.Vector3(0,0,1);
var lastPosX;
var lastPosY;
var targetRotationY = 0;
var targetRotationX = 0;
var quater;
//var rotateQuaternion = new THREE.Quaternion();
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'Drag to spin the cube';
container.appendChild( info );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 150;
camera.position.z = 500;
scene = new THREE.Scene();
// Cube
var geometry = new THREE.CubeGeometry( 200, 200, 200 );
for ( var i = 0; i < geometry.faces.length; i += 2 ) {
var hex = Math.random() * 0xffffff;
geometry.faces[ i ].color.setHex( hex );
geometry.faces[ i + 1 ].color.setHex( hex );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5 } );
cube = new THREE.Mesh( geometry, material );
cube.position.y = 150;
scene.add( cube );
// Plane
var geometry = new THREE.PlaneGeometry( 200, 200 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xe0e0e0, overdraw: 0.5 } );
plane = new THREE.Mesh( geometry, material );
scene.add( plane );
renderer = new THREE.CanvasRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function onDocumentMouseDown( event ) {
event.preventDefault();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseDown = true;
rotateStartP = projectOnTrackball(event.clientX, event.clientY);
}
function onDocumentMouseMove( event ) {
if(!mouseDown)
{
return;
}
rotateEndP = projectOnTrackball(event.clientX, event.clientY);
}
function getMouseOnScreen( pageX, pageY) {
return new THREE.Vector2.set(pageX / window.innerWidth ,pageY / window.innerHeight);
}
function projectOnTrackball(pageX, pageY) // The screen coordinate[(0,0)on the left-top] convert to the
//trackball coordinate [(0,0) on the center of the page]
{
var mouseOnBall = new THREE.Vector3();
mouseOnBall.set(
( pageX - window.innerWidth * 0.5 ) / (window.innerWidth * .5),
( window.innerHeight * 0.5 - pageY ) / ( window.innerHeight * .5),
0.0
);
var length = mouseOnBall.length();
if (length > 1.0) {
mouseOnBall.normalize();
}
else {
mouseOnBall.z = Math.sqrt(1.0 - length * length);
}
return mouseOnBall;
}
function rotateMatrix(rotateStart, rotateEnd)
{
var axis = new THREE.Vector3(),
quaternion = new THREE.Quaternion();
var angle = Math.acos( rotateStart.dot( rotateEnd ) / rotateStart.length() / rotateEnd.length() );
if ( angle )
{
axis.crossVectors( rotateStart, rotateEnd ).normalize();
angle *= 0.01; //Here we could define rotate speed
quaternion.setFromAxisAngle( axis, angle );
}
return quaternion;
}
function onDocumentMouseUp( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
mouseDown = false;
rotateStartP = rotateEndP;
}
function onDocumentMouseOut( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentTouchStart( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
/*
mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
targetRotationOnMouseDownX = targetRotationX;
mouseYOnMouseDown = event.touches[ 0 ].pageY - windowHalfY;
targetRotationOnMouseDownY = targetRotationY; */
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
/*
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotationX = targetRotationOnMouseDownX + ( mouseX - mouseXOnMouseDown ) * 0.05;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
targetRotationY = targetRotationOnMouseDownY + ( mouseY - mouseYOnMouseDown ) * 0.05; */
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
//if(rotateStartP != rotateEndP) {
//rotateQuaternion = rotateMatrix(rotateStartP, rotateEndP);
//quater=cube.quaternion;
//quater.multiplyQuaternions(rotateQuaternion, quater);
//quater.multiply(rotateQuaternion);
//quater.normalize();
var rotateQuaternion = rotateMatrix(rotateStartP, rotateEndP);
quater=cube.quaternion;
quater.multiplyQuaternions(rotateQuaternion,quater);
quater.normalize();
cube.setRotationFromQuaternion(quater);
// }
renderer.render( scene, camera );
}
</script>
</body>
</html>
I've taken the code from #yongnan and modified it to work as I would have expected the cube to rotate while dragging. You can download the code here: https://github.com/defmech/Three.js-Object-Rotation-with-Quaternion
Example here: http://projects.defmech.com/ThreeJSObjectRotationWithQuaternion/
Add the answer, so that, it would help for the other people who has the similar problem
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js canvas - geometry - cube</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="../build/three.min.js"></script>
<script src="js/libs/stats.min.js"></script>
<script>
var container, stats;
var camera, scene, renderer;
var cube, plane;
var mouseDown = false;
var rotateStartP = new THREE.Vector3(0,0,1);
var rotateEndP = new THREE.Vector3(0,0,1);
var lastPosX;
var lastPosY;
var targetRotationY = 0;
var targetRotationX = 0;
var quater;
//var rotateQuaternion = new THREE.Quaternion();
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'Drag to spin the cube';
container.appendChild( info );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 150;
camera.position.z = 500;
scene = new THREE.Scene();
// Cube
var geometry = new THREE.CubeGeometry( 200, 200, 200 );
for ( var i = 0; i < geometry.faces.length; i += 2 ) {
var hex = Math.random() * 0xffffff;
geometry.faces[ i ].color.setHex( hex );
geometry.faces[ i + 1 ].color.setHex( hex );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5 } );
cube = new THREE.Mesh( geometry, material );
cube.position.y = 150;
scene.add( cube );
// Plane
var geometry = new THREE.PlaneGeometry( 200, 200 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xe0e0e0, overdraw: 0.5 } );
plane = new THREE.Mesh( geometry, material );
scene.add( plane );
renderer = new THREE.CanvasRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function onDocumentMouseDown( event ) {
event.preventDefault();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseDown = true;
rotateStartP = projectOnTrackball(event.clientX, event.clientY);
}
function onDocumentMouseMove( event ) {
if(!mouseDown)
{
return;
}
rotateEndP = projectOnTrackball(event.clientX, event.clientY);
}
function getMouseOnScreen( pageX, pageY) {
return new THREE.Vector2.set(pageX / window.innerWidth ,pageY / window.innerHeight);
}
function projectOnTrackball(pageX, pageY) // The screen coordinate[(0,0)on the left-top] convert to the
//trackball coordinate [(0,0) on the center of the page]
{
var mouseOnBall = new THREE.Vector3();
mouseOnBall.set(
( pageX - window.innerWidth * 0.5 ) / (window.innerWidth * .5),
( window.innerHeight * 0.5 - pageY ) / ( window.innerHeight * .5),
0.0
);
var length = mouseOnBall.length();
if (length > 1.0) {
mouseOnBall.normalize();
}
else {
mouseOnBall.z = Math.sqrt(1.0 - length * length);
}
return mouseOnBall;
}
function rotateMatrix(rotateStart, rotateEnd)
{
var axis = new THREE.Vector3(),
quaternion = new THREE.Quaternion();
var angle = Math.acos( rotateStart.dot( rotateEnd ) / rotateStart.length() / rotateEnd.length() );
if ( angle )
{
axis.crossVectors( rotateStart, rotateEnd ).normalize();
angle *= 0.01; //Here we could define rotate speed
quaternion.setFromAxisAngle( axis, angle );
}
return quaternion;
}
function onDocumentMouseUp( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
mouseDown = false;
rotateStartP = rotateEndP;
}
function onDocumentMouseOut( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentTouchStart( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
/*
mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
targetRotationOnMouseDownX = targetRotationX;
mouseYOnMouseDown = event.touches[ 0 ].pageY - windowHalfY;
targetRotationOnMouseDownY = targetRotationY; */
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
/*
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotationX = targetRotationOnMouseDownX + ( mouseX - mouseXOnMouseDown ) * 0.05;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
targetRotationY = targetRotationOnMouseDownY + ( mouseY - mouseYOnMouseDown ) * 0.05; */
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
//if(rotateStartP != rotateEndP) {
//rotateQuaternion = rotateMatrix(rotateStartP, rotateEndP);
//quater=cube.quaternion;
//quater.multiplyQuaternions(rotateQuaternion, quater);
//quater.multiply(rotateQuaternion);
//quater.normalize();
var rotateQuaternion = rotateMatrix(rotateStartP, rotateEndP);
quater=cube.quaternion;
quater.multiplyQuaternions(rotateQuaternion,quater);
quater.normalize();
cube.setRotationFromQuaternion(quater);
// }
renderer.render( scene, camera );
}
</script>
</body>
</html>
I realise this is an old post - but for people happening on it & just in case anyone is interested: I've put together a first version of a drag controller which enables drag rotation about 3 axes, with the axis of rotation specified by the mouse pointer rather than the center of the object.
It works with touch, and should behave the same irrespective of camera position/object position. I've also had it working alongside OrbitControls.js, so that the whole scene rotates/translates if blank canvas is clicked on.
You can read more about it and get the code here: https://virtual.blue/point-drag-controls

How to control the data.gui.js that do not affect the object(Three.js r66)

I write a trackball to control the object rotation, everything goes fine. However, when I add the gui component to the program, and when I put the mouse to change the gui, the object is moving. Because my trackball project the screen coordinate to the virtual ball, when my mouse is on the gui component, it is still in the screen, and it makes the object move. How to avoid that? I try t find the reason about the trackball three.js has, and do not find the a result. Why his trackball do not affact the gui object?
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js canvas - geometry - cube</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="../build/three.min.js"></script>
<script src="js/libs/dat.gui.min.js"></script>
<script src="js/libs/stats.min.js"></script>
<script>
var container, stats;
var camera, scene, renderer;
var cube, plane;
var mouseDown = false;
var rotateStartP = new THREE.Vector3(0,0,1);
var rotateEndP = new THREE.Vector3(0,0,1);
var lastPosX;
var lastPosY;
var targetRotationY = 0;
var targetRotationX = 0;
var quater;
//var rotateQuaternion = new THREE.Quaternion();
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'Drag to spin the cube';
container.appendChild( info );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 150;
camera.position.z = 500;
scene = new THREE.Scene();
// Cube
var geometry = new THREE.CubeGeometry( 200, 200, 200 );
for ( var i = 0; i < geometry.faces.length; i += 2 ) {
var hex = Math.random() * 0xffffff;
geometry.faces[ i ].color.setHex( hex );
geometry.faces[ i + 1 ].color.setHex( hex );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5 } );
cube = new THREE.Mesh( geometry, material );
cube.position.y = 150;
scene.add( cube );
// Plane
var geometry = new THREE.PlaneGeometry( 200, 200 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xe0e0e0, overdraw: 0.5 } );
plane = new THREE.Mesh( geometry, material );
scene.add( plane );
renderer = new THREE.CanvasRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//GUI
var controls = new function () {
this.xx = false;
this.yy = 512;
this.onChange = function () {
}
};
var gui = new dat.GUI();
gui.add(controls, 'xx').onChange(controls.onChange);
gui.add(controls, 'yy', 1, 10).step(1).onChange(controls.onChange);
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function onDocumentMouseDown( event ) {
event.preventDefault();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseDown = true;
rotateStartP = projectOnTrackball(event.clientX, event.clientY);
}
function onDocumentMouseMove( event ) {
if(!mouseDown)
{
return;
}
rotateEndP = projectOnTrackball(event.clientX, event.clientY);
}
function getMouseOnScreen( pageX, pageY) {
return new THREE.Vector2.set(pageX / window.innerWidth ,pageY / window.innerHeight);
}
function projectOnTrackball(pageX, pageY) // The screen coordinate[(0,0)on the left-top] convert to the
//trackball coordinate [(0,0) on the center of the page]
{
var mouseOnBall = new THREE.Vector3();
mouseOnBall.set(
( pageX - window.innerWidth * 0.5 ) / (window.innerWidth * .5),
( window.innerHeight * 0.5 - pageY ) / ( window.innerHeight * .5),
0.0
);
var length = mouseOnBall.length();
if (length > 1.0) {
mouseOnBall.normalize();
}
else {
mouseOnBall.z = Math.sqrt(1.0 - length * length);
}
return mouseOnBall;
}
function rotateMatrix(rotateStart, rotateEnd)
{
var axis = new THREE.Vector3(),
quaternion = new THREE.Quaternion();
var angle = Math.acos( rotateStart.dot( rotateEnd ) / rotateStart.length() / rotateEnd.length() );
if ( angle )
{
axis.crossVectors( rotateStart, rotateEnd ).normalize();
angle *= 0.01; //Here we could define rotate speed
quaternion.setFromAxisAngle( axis, angle );
}
return quaternion;
}
function onDocumentMouseUp( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
mouseDown = false;
rotateStartP = rotateEndP;
}
function onDocumentMouseOut( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentTouchStart( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
/*
mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
targetRotationOnMouseDownX = targetRotationX;
mouseYOnMouseDown = event.touches[ 0 ].pageY - windowHalfY;
targetRotationOnMouseDownY = targetRotationY; */
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
/*
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotationX = targetRotationOnMouseDownX + ( mouseX - mouseXOnMouseDown ) * 0.05;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
targetRotationY = targetRotationOnMouseDownY + ( mouseY - mouseYOnMouseDown ) * 0.05; */
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
//if(rotateStartP != rotateEndP) {
//rotateQuaternion = rotateMatrix(rotateStartP, rotateEndP);
//quater=cube.quaternion;
//quater.multiplyQuaternions(rotateQuaternion, quater);
//quater.multiply(rotateQuaternion);
//quater.normalize();
var rotateQuaternion = rotateMatrix(rotateStartP, rotateEndP);
quater=cube.quaternion;
quater.multiplyQuaternions(rotateQuaternion,quater);
quater.normalize();
cube.setRotationFromQuaternion(quater);
// }
renderer.render( scene, camera );
}
</script>
</body>
</html>
Change my code to ObjectTrackball.js
The code is as follows:
TrackballControls = function ( object, domElement ) {
var _this = this;
_this.quater = object.quaternion;
_this.object = object;
_this.domElement = ( domElement !== undefined ) ? domElement : document;
_this.zoomValue = 0;
_this.mouseDown = true;
_this.rotateStartP = new THREE.Vector3();
_this.rotateEndP = new THREE.Vector3();
// events
var changeEvent = { type: 'change' };
// methods
this.handleEvent = function ( event ) {
if ( typeof this[ event.type ] == 'function' ) {
this[ event.type ]( event );
}
};
this.update = function () {
var rotateQuaternion = rotateMatrix(_this.rotateStartP, _this.rotateEndP);
_this.quater = _this.object.quaternion;
_this.quater.multiplyQuaternions(rotateQuaternion,_this.quater);
_this.quater.normalize();
_this.object.setRotationFromQuaternion(_this.quater);
_this.object.position.z += _this.zoomValue;
_this.zoomValue = 0;
};
function mousedown( event ) {
event.preventDefault();
_this.mouseDown = true;
_this.rotateStartP = projectOnTrackball(event.clientX, event.clientY);
document.addEventListener( 'mousemove', mousemove, false );
document.addEventListener( 'mouseup', mouseup, false );
}
function getMouseOnScreen( pageX, pageY) {
return new THREE.Vector2.set(pageX / window.innerWidth ,pageY / window.innerHeight);
}
function projectOnTrackball(pageX, pageY) // The screen coordinate[(0,0)on the left-top] convert to the
//trackball coordinate [(0,0) on the center of the page]
{
var mouseOnBall = new THREE.Vector3();
mouseOnBall.set(
( pageX - window.innerWidth * 0.5 ) / (window.innerWidth * .5),
( window.innerHeight * 0.5 - pageY ) / ( window.innerHeight * .5),
0.0
);
var length = mouseOnBall.length();
if (length > 1.0) {
mouseOnBall.normalize();
}
else {
mouseOnBall.z = Math.sqrt(1.0 - length * length);
}
return mouseOnBall;
}
function rotateMatrix(rotateStart, rotateEnd)
{
var axis = new THREE.Vector3(),
quaternion = new THREE.Quaternion();
var angle = Math.acos( rotateStart.dot( rotateEnd ) / rotateStart.length() / rotateEnd.length() );
if ( angle )
{
axis.crossVectors( rotateStart, rotateEnd ).normalize();
angle *= 0.01; //Here we could define rotate speed
quaternion.setFromAxisAngle( axis, angle );
}
return quaternion;
}
function mousemove( event ) {
if(!_this.mouseDown)
{
return;
}
_this.rotateEndP = projectOnTrackball(event.clientX, event.clientY);
}
function mouseup( event ) {
_this.mouseDown = false;
_this.rotateStartP = _this.rotateEndP;
document.removeEventListener( 'mousemove', mousemove );
document.removeEventListener( 'mouseup', mouseup );
}
function mousewheel( event ) {
event.preventDefault();
event.stopPropagation();
var delta = 0;
if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
delta = event.wheelDelta / 40;
} else if ( event.detail ) { // Firefox
delta = - event.detail / 3;
}
_this.zoomValue += delta;
}
this.domElement.addEventListener( 'mousedown', mousedown, false );
this.domElement.addEventListener( 'mousewheel', mousewheel, false );
this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox
};
TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
Code of The Object control application (Three.js r66)
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js canvas - geometry - cube</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="../build/three.min.js"></script>
<script src="js/libs/dat.gui.min.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="js/controls/ObjectTrackballControl.js"></script>
<script>
var container, stats;
var camera, scene, renderer;
var cube, plane;
var control;
var mouseDown = false;
var rotateStartP = new THREE.Vector3(0,0,1);
var rotateEndP = new THREE.Vector3(0,0,1);
var lastPosX;
var lastPosY;
var targetRotationY = 0;
var targetRotationX = 0;
var quater;
//var rotateQuaternion = new THREE.Quaternion();
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'Drag to spin the cube';
container.appendChild( info );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 150;
camera.position.z = 500;
scene = new THREE.Scene();
// Cube
var geometry = new THREE.CubeGeometry( 200, 200, 200 );
for ( var i = 0; i < geometry.faces.length; i += 2 ) {
var hex = Math.random() * 0xffffff;
geometry.faces[ i ].color.setHex( hex );
geometry.faces[ i + 1 ].color.setHex( hex );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5 } );
cube = new THREE.Mesh( geometry, material );
cube.position.y = 150;
scene.add( cube );
control = new TrackballControls(cube);
// Plane
var geometry = new THREE.PlaneGeometry( 200, 200 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xe0e0e0, overdraw: 0.5 } );
plane = new THREE.Mesh( geometry, material );
scene.add( plane );
renderer = new THREE.CanvasRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//GUI
var controls = new function () {
this.xx = false;
this.yy = 512;
this.onChange = function () {
}
};
var gui = new dat.GUI();
gui.add(controls, 'xx').onChange(controls.onChange);
gui.add(controls, 'yy', 1, 10).step(1).onChange(controls.onChange);
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
control.update();
renderer.render( scene, camera );
}
</script>
</body>
</html>

three.js - identify point on tube circumference and rotate from that point

Below is my code for the scene of tube geometry. I've loaded 200 co-ordinates as JSON data from external file.
<!DOCTYPE html>
<html lang="en">
<head>
<title>3d Model using HTML5 and three.js</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
#info {
color:#000;
position: absolute;
top: 0px; width: 100%;
padding: 5px;
}
</style>
</head>
<body>
<div id="info">
WASD-move, RF-up/down, QE-roll, mouse-look around, mouse left/right click- zoom-in/out
</div>
<script src="three.min.js" type="text/javascript"></script>
<script src="Curve.js" type="text/javascript"></script>
<script src="Stats.js" type="text/javascript"></script>
<script src="Detector.js" type="text/javascript"></script>
<script src="path.js" type="text/javascript"></script>
<script>
// variables
var container, stats;
var camera, scene, renderer, controls;
var text, plane, tube, tubeMesh, parent;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0, mouseY = 0; var radius = 6371;
var mouseXOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var clock = new THREE.Clock();
function plotPath()
{
var obj = getPath();
var segments = 60;
var closed = false;
var debug = true;
var radiusSegments = 12;
var tube;
var points = [];
var x=0,y=0,z=0;
var extrudePath;
for(var i=0; i<obj.path.length; i++)
{
console.log(obj.path[i].point);
points.push(obj.path[i].point);
}
extrudePath = new THREE.SplineCurve3(points);
tube = new THREE.TubeGeometry(extrudePath, segments, 2, radiusSegments, closed, debug);
tubeMesh = new THREE.Mesh(tube ,new THREE.MeshBasicMaterial({
color: 0x000000, side: THREE.DoubleSide,
opacity: 0.5, transparent: true, wireframe: true}));
if ( tube.debug ) tubeMesh.add( tube.debug );
scene.add( tubeMesh );
}
init();
animate();
function init(){
// container
container = document.createElement( 'div' );
document.body.appendChild( container );
// scene
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 );
// renderer
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setClearColor( scene.fog.color, 1 );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
// camera
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
// light
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 1, 1, 1 );
scene.add( light );
light = new THREE.DirectionalLight( 0x002288 );
light.position.set( -1, -1, -1 );
scene.add( light );
light = new THREE.AmbientLight( 0x555555 );
scene.add( light );
// CONTROLS
controls = new THREE.RollControls( camera );
controls.movementSpeed = 50;
controls.lookSpeed = 3;
controls.constrainVertical = [ -0.5, 0.5 ];
// Grid
geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3( - 500, 0, 0 ) );
geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ) );
for ( var i = 0; i <= 20; i ++ ) {
line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
line.position.z = ( i * 50 ) - 500;
scene.add( line );
line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
line.position.x = ( i * 50 ) - 500;
line.rotation.y = 90 * Math.PI / 180;
scene.add( line );
}
// projector
projector = new THREE.Projector();
plotPath();
// stats
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
stats.domElement.style.zIndex = 100;
container.appendChild( stats.domElement );
// events
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
update();
}
function update(){
controls.update(clock.getDelta());
stats.update();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>
How can I identify a point on tube circumference and how to rotate a tube from that point ?
OrbitControls, for example, has a property target which is both the center of rotation and the camera look-at position.
controls = new THREE.OrbitControls( camera );
You can change the center of rotation of the camera using picking.
function onDocumentMouseDown( event ) {
event.preventDefault();
var vector = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1,
0.5 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
var intersects = ray.intersectObjects( objects );
if ( intersects.length > 0 ) {
controls.target.copy( intersects[0].point );
}
}
EDIT: Here is an updated fiddle: http://jsfiddle.net/eVkgs/30/
three.js r.65

Resources