THREE.js can not rotate object - three.js

I am attempting to rotate an object I uploaded along its y axis. The object uploads and the material is applied. I have used the same code to rotate a sphere but it does not seem to work with a custom object. If I un-comment the line at the bottom that is supposed to handle the actual rotation, the image no longer shows up as if there is an error.
Web GL Test
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
<script src="js/three.min.js"></script>
<script src="js/OBJLoader.js"></script>
<script type="text/javascript">
var container, stats;
var camera, scene, renderer;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 200;
camera.position.z = 150;
scene = new THREE.Scene();
var loader = new THREE.OBJLoader();
loader.addEventListener( 'load', function ( event ) {
var object = event.content;
var geom = new THREE.SphereGeometry( 100, 50, 50 );
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = texture;
}
} );
object.position.y = 150;
scene.add( object );
});
loader.load( 'Head.obj' );
var texture = THREE.ImageUtils.loadTexture('face.gif');
texture.needsUpdate = true;
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.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;
targetRotationOnMouseDown = targetRotation;
}
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 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;
targetRotationOnMouseDown = targetRotation;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
//object.rotation.y += ( targetRotation - object.rotation.y ) * 0.05;
renderer.render( scene, camera );
}
</script>
</body>

The problem is that you use the variable "object" in the animate function before it is initialized. Also the variable "object" has a scope limited to the callback function of the loader.
You might want to read something about javascript variable scope.
http://www.mredkj.com/tutorials/reference_js_intro_ex.html
To solve your problem you might to change a few things.
1) Make the variable "object" global
// Make object a global variable
var camera, scene, renderer, object;
2) Do not call the animate function before the object is initialized
init();
//animate();
3) Do not use "var" inside callback function of the loader
var loader = new THREE.OBJLoader();
loader.addEventListener( 'load', function ( event ) {
//var object = event.content;
object = event.content;
var geom = new THREE.SphereGeometry( 100, 50, 50 );
4) Call "animate" after "object" is initialized
object.position.y = 150;
scene.add( object );
// Call animate after object is loaded and added to the scene
animate();
5) Good luck ;)

Related

Three.js - DOMException: "The operation is insecure." - most likely cross domain issue

I have implemented a three.js viewer for my panoramic pictures a couple of years ago and now that I'm moving my site to another location, I have an issue with Three.js not willing to load anymore.
Error message in the console:
DOMException: "The operation is insecure."
Here is the html part I'm using:
<div class="article-pano-gallery" style="display:table">
<img onclick="init('https://images.laurentwillen.be/sites/21/2017/05/photo-panoramique-360-Catane.jpg')" class="article-gallery-image pano-image" data-srcset="https://images.laurentwillen.be/sites/21/2017/05/photo-panoramique-360-Catane.jpg" src="https://images.laurentwillen.be/sites/21/2017/05/photo-panoramique-360-Catane-150x150.jpg" width="150" height="150">
</div>
And for the JS part:
<script async src="https://ajax.googleapis.com/ajax/libs/threejs/r84/three.min.js"></script>
<script>
var camera, scene, renderer;
var isUserInteracting = false,
onMouseDownMouseX = 0, onMouseDownMouseY = 0,
lon = 0, onMouseDownLon = 0,
lat = 0, onMouseDownLat = 0,
phi = 0, theta = 0;
function init(full_image)
{
var container, mesh;
container = document.getElementById( 'background-section' );
document.getElementById( 'background-section') .style.display='block';
document.getElementById( 'pano-loading-section') .style.display='block';
document.getElementById( 'close') .style.display='block';
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
camera.target = new THREE.Vector3( 0, 0, 0 );
scene = new THREE.Scene();
var geometry = new THREE.SphereBufferGeometry( 500, 60, 40 );
// invert the geometry on the x-axis so that all of the faces point inward
geometry.scale( - 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( {
map: new THREE.TextureLoader().load( full_image )
} );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth*0.95, window.innerHeight*0.95 );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousedown', onPointerStart, false );
document.addEventListener( 'mousemove', onPointerMove, false );
document.addEventListener( 'mouseup', onPointerUp, false );
document.addEventListener( 'wheel', onDocumentMouseWheel, false );
document.addEventListener( 'touchstart', onPointerStart, false );
document.addEventListener( 'touchmove', onPointerMove, false );
document.addEventListener( 'touchend', onPointerUp, false );
document.addEventListener( 'dragover', function ( event )
{
event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
}, false );
document.addEventListener( 'dragenter', function ()
{
document.body.style.opacity = 0.5;
}, false );
document.addEventListener( 'dragleave', function ()
{
document.body.style.opacity = 1;
}, false );
document.addEventListener( 'drop', function ( event )
{
event.preventDefault();
var reader = new FileReader();
reader.addEventListener( 'load', function ( event ) {
material.map.image.src = event.target.result;
material.map.needsUpdate = true;
}, false );
reader.readAsDataURL( event.dataTransfer.files[ 0 ] );
document.body.style.opacity = 1;
}, false );
//
window.addEventListener( 'resize', onWindowResize, false );
document.getElementById( 'pano-loading-section') .style.display='none';
animate();
}
function onWindowResize()
{
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth*0.95, window.innerHeight*0.95 );
}
function onPointerStart( event )
{
isUserInteracting = true;
var clientX = event.clientX || event.touches[ 0 ].clientX;
var clientY = event.clientY || event.touches[ 0 ].clientY;
onMouseDownMouseX = clientX;
onMouseDownMouseY = clientY;
onMouseDownLon = lon;
onMouseDownLat = lat;
}
function onPointerMove( event )
{
if ( isUserInteracting === true )
{
var clientX = event.clientX || event.touches[ 0 ].clientX;
var clientY = event.clientY || event.touches[ 0 ].clientY;
lon = ( onMouseDownMouseX - clientX ) * 0.1 + onMouseDownLon;
lat = ( clientY - onMouseDownMouseY ) * 0.1 + onMouseDownLat;
}
}
function onPointerUp()
{
isUserInteracting = false;
}
function onDocumentMouseWheel( event )
{
var fov = camera.fov + event.deltaY * 0.05;
camera.fov = THREE.Math.clamp( fov, 10, 75 );
camera.updateProjectionMatrix();
}
function animate()
{
requestAnimationFrame( animate );
update();
}
function update()
{
if ( isUserInteracting === false )
{
lon += 0.1;
}
lat = Math.max( - 85, Math.min( 85, lat ) );
phi = THREE.Math.degToRad( 90 - lat );
theta = THREE.Math.degToRad( lon );
camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );
camera.target.y = 500 * Math.cos( phi );
camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta );
camera.lookAt( camera.target );
/*
// distortion
camera.position.copy( camera.target ).negate();
*/
renderer.render( scene, camera );
}
</script>
I was using the same script on another domain for images and it was working well but now that I have moved, it doesn't work anymore.
I suppose it has something to do with cross domain but I don't see where exactly. I have tried a local version of the JS file and it's the same issue.
The error in the JS occurs on line 121. Here is the full text as requested below:
DOMException: "The operation is insecure." three.js:121:396
texImage2D https://wp.laurentwillen.be/js/three.js:121
n https://wp.laurentwillen.be/js/three.js:97
setTexture2D https://wp.laurentwillen.be/js/three.js:181
hf https://wp.laurentwillen.be/js/three.js:7
upload https://wp.laurentwillen.be/js/three.js:343
G https://wp.laurentwillen.be/js/three.js:147
renderBufferDirect https://wp.laurentwillen.be/js/three.js:165
n https://wp.laurentwillen.be/js/three.js:134
render https://wp.laurentwillen.be/js/three.js:180
update https://wp.laurentwillen.be/circuits/circuit-italie/catane/?bb:1679
animate https://wp.laurentwillen.be/circuits/circuit-italie/catane/?bb:1659
Thanks
This is definitely a CORS issue. I recommend you get yourself acquainted with how modern browsers handle cross-domain requests.
My best guess is that your images.laurentwillen.be server isn't configured to allow delivering assets to other domains. This is a safety feature so other people don't steal your bandwidth (you probably wouldn't want 1000s of sites freeloading by using images hosted on your server).
There are 2 solutions to this problem:
Host the images in the same domain where they're being requested.
Figure out how to let your server allow delivery of images to the domain where you're using them. The way to achieve this depends on the type of server you're running and you'll have to do some digging to figure out how to configure it, so solution 1 would be easiest.

Javascript threejs multi scene and mouse event

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>

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, OBJLoader -> Uncaught ReferenceError: object is not defined

My code below.
When I uncomment
object.rotation.y += ( targetRotation - object.rotation.y ) * 0.05; from render() or animate() function I get "Uncaught ReferenceError: object is not defined " error.
I tried anything, my animate() function is even in loader callback, I tried changing three.js to older version (currently using r59), hoped var object = event.content; might solve it, no effect.
I want to add "click and move your mouse to rotate model" usability, I have no problems with that when its cube.
but it just won't work with my *obj.
Help? =)
var scene, camera, renderer, loader, ambient, directionalLight;
var windowHalfX = 300;
var windowHalfY = 145;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
init();
function init() {
container = document.createElement( 'div' );
document.getElementById("3dbox").appendChild(container);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, 600 / 290, 0.1, 1000 );
//camera.position.set( -15, 10, 15 );
renderer = new THREE.WebGLRenderer();
renderer.setSize( 600, 290 );
container.appendChild( renderer.domElement );
// MODEL
var loader = new THREE.OBJMTLLoader();
loader.addEventListener( 'load', function ( event ) {
var object = event.content;
scene.add( object );
animate();
});
loader.load( '<?php bloginfo('template_directory'); ?>/obj/female02.obj', '<?php bloginfo('template_directory'); ?>/obj/female02.mtl' );
camera.position.z = 100;
camera.position.y = 10;
ambient = new THREE.AmbientLight( 0x101030 );
scene.add( ambient );
directionalLight = new THREE.DirectionalLight( 0xffeedd );
directionalLight.position.set( 0, 0, 1 );
scene.add( directionalLight );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
}
function render() {
//object.rotation.y += ( targetRotation - object.rotation.y ) * 0.05;
renderer.render(scene, camera);
}
function animate() {
//object.rotation.y += ( targetRotation - object.rotation.y ) * 0.05;
requestAnimationFrame( animate );
render();
}
function onDocumentMouseDown( event ) {
event.preventDefault();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 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;
targetRotationOnMouseDown = targetRotation;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
}
}
It is because "object" is a local variable in your callback function. Decare it globally:
var object;
Then in your callback,
object = event.content;
three.js r.59

Resources