question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Feature request: ObjectControls

See original GitHub issue
Feature request

OrbitControls were originally created to rotate a camera around a point in a scene: Screen Shot 2020-01-28 at 3 32 16 PM https://threejs.org/examples/#misc_controls_orbit

TransformControls were originally created for rotating individual objects within a scene: Screen Shot 2020-01-28 at 3 32 26 PM https://threejs.org/examples/#misc_controls_transform

However in most examples and in web apps, we seem to be using OrbitControls to rotate objects? e.g. https://threejs.org/examples/#webgl_materials_normalmap_object_space https://threejs.org/examples/#webgl_clipping_intersection https://threejs.org/examples/#webgl_clipping_stencil https://threejs.org/examples/#webgl_decals etc…

This usage creates confusion when you actually do want to rotate an object (and control the camera separately). In my case I needed the user to spin a globe, while the camera pans to a certain viewing angle.

Neither OrbitControls or TransformControls fully support the actual needed functionality needed for object spinning:

  • OrbitControls locks your camera.lookAt to controls.target, and is spinning the camera not the object, which also spins the scenes.
  • TransformControls correctly spins the object, but doesn’t support damping / free spinning / hiding the gizmo gui.

So with that in mind, could we add an example for ObjectControls?

The controls implementation of Autodesk Forge viewer is probably a good benchmark: https://forge-rcdb.autodesk.io/configurator?id=5904729b0007f5ead5b1196d

Some ideal features:

  • Selecting an object
  • Rotate object
  • Lock axis
  • Free spin in any direction
  • Damping to slowly spin to a stop

Here is my attempt at a potential solution by using TransformControls as a reference:

index.html

control = new ObjectControls(camera, renderer.domElement);
control.enableDamping = true;
control.freeMode = true;
control.setMode('rotate');
control.showX = false;
control.showY = false;
control.showZ = false;

ObjectControls.js line 69

// Set to true to enable damping (inertia)
// If damping is enabled, you must call controls.update() in your animation loop
defineProperty( "enableDamping", false );
defineProperty( "dampingFactor", 0.05 );
defineProperty( "freeMode", false );
defineProperty( "rotateSpeed", 1.0 );

line 128:

var rotateStart = new Vector2();
var rotateEnd = new Vector2();
var rotateDelta = new Vector2();

line 255:

this.pointerHover = function ( pointer ) {
  if ( this.object === undefined || this.dragging === true || ( pointer.button !== undefined && pointer.button !== 0 ) ) return;
  if (this.freeMode === true) {
    this.axis = 'XYZE';
    return;
  }
  ray.setFromCamera( pointer, this.camera );
  var intersect = ray.intersectObjects( _gizmo.picker[ this.mode ].children, true )[ 0 ] || false;
  if ( intersect ) {
    this.axis = intersect.object.name;
  } else {
    this.axis = null;
  }
};

line 523: var ROTATION_SPEED = 2 / worldPosition.distanceTo( _tempVector.setFromMatrixPosition( this.camera.matrixWorld ) );

line 724:

this.update = function () {
  if (this.dragging === false && scope.enableDamping && (Math.abs(rotateDelta.x) > 0.01 || Math.abs(rotateDelta.y) > 0.01)) {
    quaternionStart.copy( this.object.quaternion );
    offset = new Vector3(
      rotateDelta.x * 5,
      - rotateDelta.y * 5,
      0
    );
    rotateDelta.x *= 1 - scope.dampingFactor;
    rotateDelta.y *= 1 - scope.dampingFactor;
    var ROTATION_SPEED = .1 / worldPosition.distanceTo( _tempVector.setFromMatrixPosition( this.camera.matrixWorld ) );
    rotationAxis.copy( offset ).cross( eye ).normalize();
    rotationAngle = offset.dot( _tempVector.copy( rotationAxis ).cross( this.eye ) ) * ROTATION_SPEED;
    rotationAxis.applyQuaternion( parentQuaternionInv );
    this.object.quaternion.copy( _tempQuaternion.setFromAxisAngle( rotationAxis, rotationAngle ) );
    this.object.quaternion.multiply( quaternionStart ).normalize();
  }
};

line 644:

function onPointerDown( event ) {
  if ( ! scope.enabled ) return;
  rotateStart.set( event.clientX, event.clientY );
  document.addEventListener( "mousemove", onPointerMove, false );
  scope.pointerHover( getPointer( event ) );
  scope.pointerDown( getPointer( event ) );
}
function onPointerMove( event ) {
  if ( ! scope.enabled ) return;
  rotateEnd.set( event.clientX, event.clientY );
  rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
  scope.pointerMove( getPointer( event ) );
  rotateStart.copy( rotateEnd );
}

line 1178:

if (this.freeMode === true) {
  this.gizmo[ "translate" ].visible = false;
  this.gizmo[ "rotate" ].visible = false;
  this.gizmo[ "scale" ].visible = false;

  this.helper[ "translate" ].visible = false;
  this.helper[ "rotate" ].visible = false;
  this.helper[ "scale" ].visible = false;
} else {
  this.gizmo[ "translate" ].visible = this.mode === "translate";
  this.gizmo[ "rotate" ].visible = this.mode === "rotate";
  this.gizmo[ "scale" ].visible = this.mode === "scale";

  this.helper[ "translate" ].visible = this.mode === "translate";
  this.helper[ "rotate" ].visible = this.mode === "rotate";
  this.helper[ "scale" ].visible = this.mode === "scale";
}

Live example:

Three.js version
  • Dev
  • r112
Browser
  • All of them
  • Chrome
  • Firefox
  • Internet Explorer
OS
  • All of them
  • Windows
  • macOS
  • Linux
  • Android
  • iOS
Hardware Requirements (graphics card, VR Device, …)

None

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:3
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

9reactions
Mugen87commented, Mar 14, 2021

For all users who are looking for a solution, there is now SpinControls.

Since this project is already maintained at GitHub, it’s not required to add the controls to the three.js repository. Please post feature requests or bugs at the above repo.

1reaction
systemsincodecommented, Jul 13, 2020

This would be awesome to see as I agree this is a pretty common set of use cases imho…

Read more comments on GitHub >

github_iconTop Results From Across the Web

Feature Requests: Hot (424 ideas) – Horizon Worlds
Hierarchy list on world build menu. A visual list where you can see and select objects and gizmo blocks from the build menu....
Read more >
Eos Family Feature Requests - ETC - Community
Proposing the ability to turn on/off Automark on a list-by-list basis rather than globally. For example: Main list wants to be manually marked,...
Read more >
[feature request] Rotation of the objects and more generic ...
One workaround I can offer is to rotate a control in a drawing app and then import it as an image. Another possibility...
Read more >
Feature requests - Marlin Firmware
We keep track of feature requests in the Marlin Issue Queue. Open tagged feature requests ... A Github account is required to submit...
Read more >
Forms: Instance Controls inside of History/Audit Trail/Task View
Feature Request : Forms: Instance Controls inside of History/Audit Trail/Task View ... to save an administrator from scrolling to find Retry-able objects ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found