1

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>
yongnan
  • 405
  • 7
  • 20
  • If there is some way to modify the TrackballControls.js so that it will support the trackball control object, it will be much helpful. – yongnan Apr 22 '14 at 15:12
  • Are you getting console errors? Try one of the rotation functions in `Object3D.js`. – WestLangley Apr 22 '14 at 17:54
  • @WestLangley Thank you! What do you mean to put in Object3D.js should I modify the Object3D.js? The first program is right. But when you rotate 180 degree, the rotation will upside down with the wrong orientation. – yongnan Apr 22 '14 at 19:03
  • 1. No, do not modify `Object3D.js`. 2. Be sure to use the most recent version of three.js, r.66. 3. `cube.rotation` is an Euler vector. Euler vectors do not have a method `.setRotationFromMatrix()`. 4. Look at the rotation methods in `Object3D.js` and see if one of them is what you are looking for. 5. Please do not say "It does not work". I do not know what that means. You have to specify _exactly_ what is not working for you. – WestLangley Apr 22 '14 at 19:33
  • Thanks, I will have a try – yongnan Apr 22 '14 at 19:49
  • Thanks @yongnan I found your solution helped in my understanding of something similar I was attempting. I've modified the above example code to work more like how I'm using it. I've put the code on [GitHub](https://github.com/defmech/Three.js-Object-Rotation-with-Quaternion) if you want to check it out. The code rotates the object as expected except occasionally it seem to flip when doing long drags. Maybe someone can see something wrong? – defmech May 23 '14 at 12:11
  • @defmech I find you code use a start point to remember the start point. And then use the mouse position when moving to calculate a trackball position. I think, we just need to know the startPoint EndPoint and project to them the virtual ball and then calculate the quatertion for object rotation. I found my trackball will still move(static rotation) when the mouse is down but we do not move the mouse. This seems a problem, I find you solved this problem, How you solved this, and What's my problem about the static rotation? thank you! http://younyzhu.github.io/Trackball/objectTrackball.html – yongnan May 29 '14 at 14:21
  • My code only rotates the cube by the amount of movement between mouse move events. Yours seems to keep adding rotation until the mouse button is lifted. – defmech May 30 '14 at 17:26

3 Answers3

4

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/

defmech
  • 1,307
  • 2
  • 9
  • 14
  • I've updated it with momentum so if you spin it fast when you let go of the mouse it slows down rather than stopping. – defmech May 30 '14 at 16:54
1

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>
yongnan
  • 405
  • 7
  • 20
0

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

user2143479
  • 89
  • 1
  • 6
  • Could you expand this answer a bit, showing an example of how you might use this library to solve the problem in the question? We are okay with recommending your own library, as long as you do it judiciously and explain how it actually solves the problem. (Answers that are essentially just a link to an externally-hosted library cause problems in the long run, when links inevitably rot.) – Cody Gray - on strike Aug 30 '17 at 19:25