Skip to content

Commit

Permalink
Add pointer to sphere mapping dropdown selecter
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Elliott committed Dec 24, 2020
1 parent d5f0b4f commit 513f621
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 26 deletions.
11 changes: 7 additions & 4 deletions CameraSpinControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* @author alteredq / http://alteredqualia.com/
* @author WestLangley / http://github.com/WestLangley
* @author erich666 / http://erichaines.com
* @author Paul Elliott / http://vizworkshop.com
*/

// Hack of OrbitControls.js to use SpinControls.js for rotation.
Expand Down Expand Up @@ -150,8 +151,10 @@ CameraSpinControls = function ( camera, domElement ) {
lastPosition.copy( scope.object.position );
lastQuaternion.copy( scope.object.quaternion );
zoomChanged = false;

scope.spinControl.resetInputAfterCameraMovement(); // Don't let camera movement to ratchet mouse movement over sphere across frames

// Don't let camera movement cause mouse to move over sphere across frames
// thus we avoid rotating when panning or dollying
scope.spinControl.resetInputAfterCameraMovement();

return true;

Expand Down Expand Up @@ -824,9 +827,9 @@ CameraSpinControls = function ( camera, domElement ) {
window.addEventListener( 'keydown', onKeyDown, false );

scope.spinControl = new SpinControls( this.targetObj, 1, camera, this.domElement );
// FIXME Camera movement moves point on sphere bug.
scope.spinControl.rotateSensitivity *= -1; // Negated it to pull camera around sphere as if sphere is fixed.
// scope.spinControl.rotateAlgorithm = scope.spinControl.POINTER_SPHERE_MAPPING.HOLROYD; // Only Holroyd works well for camera movement at the moment
scope.spinControl.rotateAlgorithm = scope.spinControl.POINTER_SPHERE_MAPPING.SHOEMAKE; // Only Holroyd works well for camera movement at the moment
//FIXME CameraSpinControls jumps when moving off/on sphere with Shoemake mapping

scope.domElement.addEventListener( 'touchend', onTouchEnd, true );
scope.domElement.addEventListener( 'touchmove', onTouchMove, false );
Expand Down
25 changes: 11 additions & 14 deletions SpinControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,49 +246,46 @@ var SpinControls = function ( object, trackBallRadius, camera, domElement ) {
objToPointer.subVectors(ndc, objToPointer);

// Scale by object screen size. TODO simplify if Orthographic camera.
objEdgePos.setFromMatrixPosition(_this.object.matrixWorld); // objEdgePos is aspirational on this line
objEdgePos.setFromMatrixPosition(_this.object.matrixWorld); // objEdgePos is still aspirational on this line
var offset = new THREE.Vector3().set(_this.trackballRadius, 0, 0);
// rotate to point at screen center. TODO Investigate
// TODO Investigate rotating offset to point towards screen center for consitant screen space size.
// objPos.z = 0;
// if(objPos.lengthSq() > 0) {
// offset.applyAxisAngle(point.set(0, 0, -1), offset.angleTo(objPos));
// }
offset.applyQuaternion(cameraRot.setFromRotationMatrix(_this.camera.matrixWorld));
objEdgePos.add(offset);
objEdgePos.project( _this.camera ); // position in ndc/screen
objEdgePos.project(_this.camera); // position in ndc/screen
objEdgePos.z = 0;
objPos.z = 0;
var objRadiusNDC = objEdgePos.distanceTo(objPos);

objToPointer.x = objToPointer.x * (1 / objRadiusNDC);
objToPointer.y = objToPointer.y * (1 / objRadiusNDC);
objToPointer.x /= objRadiusNDC;
objToPointer.y /= objRadiusNDC;
if(_this.camera.aspect) { // Perspective camera probably
objToPointer.y /= _this.camera.aspect;
}

// Pointer mapping code below derived from https://mimosa-pudica.net/3d-rotation/
if( _this.rotateAlgorithm == _this.POINTER_SPHERE_MAPPING.HOLROYD ) {
if( _this.rotateAlgorithm === _this.POINTER_SPHERE_MAPPING.HOLROYD ) {
var t = objToPointer.lengthSq();
if (t < 0.5) {
point.set(objToPointer.x, objToPointer.y, Math.sqrt(1.0 - t));
}
else {
} else {
point.set(objToPointer.x, objToPointer.y, 1.0 / (2.0 * Math.sqrt(t)));
point.normalize();
}
}
else if( _this.rotateAlgorithm == _this.POINTER_SPHERE_MAPPING.SHOEMAKE ) {
//FIXME CameraSpinControls jumps when moving off/on sphere with Shoemake mapping
else if( _this.rotateAlgorithm === _this.POINTER_SPHERE_MAPPING.SHOEMAKE ) {
var t = objToPointer.lengthSq();
if (t < 1.0) {
point.set(objToPointer.x, objToPointer.y, Math.sqrt(1.0 - t));
}
else {
} else {
objToPointer.normalize();
point.set(objToPointer.x, objToPointer.y, 0.0);
}
}
else if( _this.rotateAlgorithm == _this.POINTER_SPHERE_MAPPING.HOLROYD ) {
else if( _this.rotateAlgorithm === _this.POINTER_SPHERE_MAPPING.AZIMUTHAL ) {
var t = (Math.PI / 2.0) * objToPointer.length();
var sined = t < Number.EPSILON ? 1.0 : Math.sin(t) / t;
objToPointer.multiplyScalar((Math.PI / 2.0) * sined);
Expand Down Expand Up @@ -391,7 +388,7 @@ var SpinControls = function ( object, trackBallRadius, camera, domElement ) {
_angularVelocity.set( 0, 0, 0 );
_isPointerDown = true;
_isTouchDown = true;
_this.applyVelocity(); //Todo Should not be needed here
_this.applyVelocity(); //TODO Should not be needed here

}

Expand Down
1 change: 1 addition & 0 deletions example_simple.html
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
scene.add( group );

spinControl = new SpinControls( group, radius, camera, renderer.domElement );
//spinControl.rotateAlgorithm = spinControl.POINTER_SPHERE_MAPPING.SHOEMAKE // options

window.addEventListener( 'resize', onWindowResize, false );

Expand Down
58 changes: 50 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,40 @@
padding: 15px;
z-index:100;
box-sizing: border-box;
pointer-events: none;
pointer-events: none;
}

#mapping {
pointer-events: auto;
}

</style>
</head>
<body>

<div id="info">
Spin Controls<br /> Left click or touch spheres to spin them as if touching a trackball.
<br /> Elsewhere: Orbit camera - Left click / 1 finger | Dolly - Right click / 2 fingers | Zoom - Mouse wheel / pinch
<p><strong>Spin Controls</strong> Left click or touch spheres to spin them as if touching a trackball.</p>
<p>Elsewhere: Orbit camera - Left click / 1 finger | Dolly - Right click / 2 fingers | Zoom - Mouse wheel / pinch</p>
<p>
Pointer to trackball sphere mapping method:
<select name="spin-mapping" id="mapping">
<option value="holroyd">Holroyd</option>
<option value="shoemake">Shoemake</option>
<option value="azimuthal">Azimuthal</option>
</select>
</p>
</div>

<script src="three.min.js"></script>
<script src="SpinControls.js"></script>
<script src="CameraSpinControls.js"></script> <!-- After SpinControls please -->
<script src="CameraSpinControls.js"></script> <!-- CameraSpinControls after SpinControls please -->

<script>
var camera, scene, renderer,
smallSpinner, bigSpinner, spinControlBig, spinControlSmall,
controls, cameraUI, isTouched;
controls, cameraUI, isTouched, spinners, mapperSelector;
init();
animate(0);
animate( 0 );

function init() {

Expand Down Expand Up @@ -164,7 +176,7 @@

if ( event.button === 0 ) {

pickControlToEnable( getPointerInNdc( event.pageX, event.pageY ) );
pickControlToEnable( getPointerInNdc( event.pageX, event.pageY ) );

} else { //if not left click then move camera

Expand Down Expand Up @@ -192,6 +204,11 @@
controls.enabled = false;

}

spinners = [spinControlSmall, spinControlBig, controls.spinControl];

mapperSelector = document.getElementById('mapping')
mapperSelector.addEventListener("change", onSpinMapping);

window.addEventListener( 'resize', onWindowResize, false );

Expand Down Expand Up @@ -244,7 +261,7 @@

}

function animate(timeStamp) {
function animate(timeStamp) {

requestAnimationFrame( animate );
spinControlSmall.update();
Expand Down Expand Up @@ -326,6 +343,31 @@

}

function onSpinMapping() {

var mappingMode = mapperSelector.options[mapperSelector.selectedIndex].value;
var newMode;
if( mappingMode === 'holroyd' ) {

newMode = spinControlBig.POINTER_SPHERE_MAPPING.HOLROYD;

} else if( mappingMode === 'shoemake' ) {

newMode = spinControlBig.POINTER_SPHERE_MAPPING.SHOEMAKE;

} else if( mappingMode === 'azimuthal' ) {

newMode = spinControlBig.POINTER_SPHERE_MAPPING.AZIMUTHAL;

}

spinners.forEach((spinner) => {

spinner.rotateAlgorithm = newMode;

})
}

</script>

</body>
Expand Down

0 comments on commit 513f621

Please sign in to comment.