What is the method for consistently rotating the object regardless of the camera's orientation?

I am trying to rotate an object along the world axis while considering the direction of the camera, so that the rotation remains consistent even when the camera changes direction.

The current code allows me to rotate a sphere along the world axis. However, when the camera rotates, the sphere's rotation does not take into account the camera's direction. How can I incorporate the camera's direction when rotating the sphere?

const viewport = { width: window.innerWidth, height: window.innerHeight };

// Setting up the scene
let canvas, renderer, camera, scene, controls;

{
  renderer = new THREE.WebGLRenderer();
  renderer.setSize(viewport.width, viewport.height);
  renderer.setPixelRatio(window.devicePixelRatio);
  canvas = renderer.domElement;
  document.body.appendChild(canvas);
  document.body.style.margin = '0px';
}

{
  const fov = 45;
  const aspect = viewport.width / viewport.height;
  const near = 1;
  const far = 100;
  camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.lookAt(0, 0, 0);
  camera.position.z = 10;
}

{
  scene = new THREE.Scene();
}

{
  controls = new THREE.OrbitControls(camera, canvas);
  controls.enableDamping = false;
  controls.enableZoom = true;
  controls.enableRotate = false;
  controls.enablePan = false;
  controls.autoRotate = true;
}

// Adding objects to the scene
let axesHelper, light, light1, light2, sphere, texture;

{
  axesHelper = new THREE.AxesHelper(10);
  scene.add(axesHelper);
}

{
  light = new THREE.HemisphereLight(0xffffff, 0x000000);
  light1 = new THREE.PointLight(0xffffff);
  light1.position.set(10, 0, 0);
  light2 = new THREE.PointLight(0xffffff);
  light2.position.set(-10, 0, 0);
  scene.add(light);
  scene.add(light1);
  scene.add(light2);
}

{
  texture = new THREE.TextureLoader().load('https://threejs.org/manual/examples/resources/images/wall.jpg');
  const geometry = new THREE.SphereBufferGeometry(5, 32, 16);
  const material = new THREE.MeshPhongMaterial({ color: 0xff0000, map: texture });
  sphere = new THREE.Mesh(geometry, material);
  scene.add(sphere);
}

// Function for sphere rotation
const prevCoords = new THREE.Vector2();
const deltaCoords = new THREE.Vector2();
function handleEvent(event) {
  const isFirst = event.type === 'mousedown';
  const isLast = event.type === 'mouseup';
  if(isFirst) {
    this.moving = true;
    prevCoords.set(event.clientX, event.clientY);
  }
  else if(isLast) {
    this.moving = false;
  }
  else if(!this.moving) {
    return;
  }
  deltaCoords.set(event.clientX - prevCoords.x, event.clientY - prevCoords.y);
  rotateSphere();
  prevCoords.set(event.clientX, event.clientY);
}
const vector = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
let axis, angle;
function rotateSphere() {
  sphere.rotateOnWorldAxis(new THREE.Vector3(1, 0, 0), deltaCoords.y * 0.001);
  sphere.rotateOnWorldAxis(new THREE.Vector3(0, 1, 0), deltaCoords.x * 0.001);
}
window.addEventListener('mousedown', handleEvent);
window.addEventListener('mousemove', handleEvent);
window.addEventListener('mouseup', handleEvent);

// Rendering the scene
function loop(time) {
  controls.update();
  renderer.render(scene, camera);
  window.requestAnimationFrame(loop);
}
window.requestAnimationFrame(loop);
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

I have managed to obtain the camera direction using:

camera.getWorldDirection(vector);

However, I'm unsure of how to utilize this direction vector to adjust the axis change when the camera's direction changes.

Answer №1

I am unsure of my exact goal at this point. It appears that the rotation needs to be around the x-axis in view space rather than world space. Utilize the camera object and .localToWorld method to convert a vector from world space to view space:

let xAxis = camera.localToWorld(new THREE.Vector4(1, 0, 0, 0));
sphere.rotateOnWorldAxis(xAxis, deltaCoords.y * 0.001);

const viewport = { width: window.innerWidth, height: window.innerHeight };

// Setting up the scene
let canvas, renderer, camera, scene, controls;

{
    renderer = new THREE.WebGLRenderer();
    renderer.setSize(viewport.width, viewport.height);
    renderer.setPixelRatio(window.devicePixelRatio);
    canvas = renderer.domElement;
    document.body.appendChild(canvas);
    document.body.style.margin = '0px';
}

{
    const fov = 45;
    const aspect = viewport.width / viewport.height;
    const near = 1;
    const far = 100;
    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
    camera.lookAt(0, 0, 0);
    camera.position.z = 10;
}

{
    scene = new THREE.Scene();
}

{
    controls = new THREE.OrbitControls(camera, canvas);
    controls.enableDamping = false;
    controls.enableZoom = true;
    controls.enableRotate = false;
    controls.enablePan = false;
    controls.autoRotate = true;
}

// Adding objects to the scene
let axesHelper, light, light1, light2, sphere, texture;

{
    axesHelper = new THREE.AxesHelper(10);
    scene.add(axesHelper);
}

{
    light = new THREE.HemisphereLight(0xffffff, 0x000000);
    light1 = new THREE.PointLight(0xffffff);
    light1.position.set(10, 0, 0);
    light2 = new THREE.PointLight(0xffffff);
    light2.position.set(-10, 0, 0);
    scene.add(light);
    scene.add(light1);
    scene.add(light2);
}

{
    texture = new THREE.TextureLoader().load('https://threejs.org/manual/examples/resources/images/wall.jpg');
    const geometry = new THREE.SphereBufferGeometry(5, 32, 16);
    const material = new THREE.MeshPhongMaterial({ color: 0xff0000, map: texture });
    sphere = new THREE.Mesh(geometry, material);
    scene.add(sphere);
}

// Handling sphere rotation
const prevCoords = new THREE.Vector2();
const deltaCoords = new THREE.Vector2();
function handleEvent(event) {
    const isFirst = event.type === 'mousedown';
    const isLast = event.type === 'mouseup';
    if (isFirst) {
        this.moving = true;
        prevCoords.set(event.clientX, event.clientY);
    }
    else if (isLast) {
        this.moving = false;
    }
    else if (!this.moving) {
        return;
    }
    deltaCoords.set(event.clientX - prevCoords.x, event.clientY - prevCoords.y);
    rotateSphere();
    prevCoords.set(event.clientX, event.clientY);
}
const vector = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
let axis, angle;
function rotateSphere() {
    // camera.getWorldDirection(vector);
    // quaternion.setFromAxisAngle(vector, deltaCoords.x * 0.01);
    // sphere.quaternion.premultiply(quaternion);

    let xAxis = camera.localToWorld(new THREE.Vector4(1, 0, 0, 0));
    sphere.rotateOnWorldAxis(xAxis, deltaCoords.y * 0.001);
    sphere.rotateOnWorldAxis(new THREE.Vector3(0, 1, 0), deltaCoords.x * 0.001);
}
window.addEventListener('mousedown', handleEvent);
window.addEventListener('mousemove', handleEvent);
window.addEventListener('mouseup', handleEvent);

// Rendering the scene
function loop(time) {
    controls.update();
    renderer.render(scene, camera);
    window.requestAnimationFrame(loop);
}
window.requestAnimationFrame(loop);
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using CanvasTexture to apply as a texture map on a 3D .obj model that has been

I recently imported a .obj file into my project using the following code: OBJLoader.load('/models/model.obj', m => { let model = m.children[0]; model.material = new THREE.MeshBasicMaterial(); ...

Apologies, there seems to be a problem: TypeError - Unable to access the property 'map' as it is undefined

Just dipping my toes into reactjs by following a tutorial. However, it seems like the tutorial is slightly outdated because I keep encountering this error message: Uncaught TypeError: Cannot read property 'map' of undefined at ContactsList.r ...

Getting into particular fields of an embedded object array using a dynamic variable in Meteor: a step-by-step guide

Users have defined an array of strings with different combinations: pickedStrings = ["A", "B", "G", "L", "Y"]; This can also be: pickedStrings = ["A", "G"] or pickedStrings = ["A", "L", "Y"] or any other mix. More strings may be added in the future. ...

Sequelize associations are not functioning optimally as expected

Trying to display a nested relationship: Cat.hasMany(legs) Leg.belongsTo(cat) Leg.hasOne(paw) paw.hasMany(leg) This is the Cat Model: module.exports = (sequelize, DataTypes) => { const Cat = sequelize.define('Cat', { us ...

removing duplicate items from an array in Vue.js

I created a Pokemon App where users can add Pokemon to their 'pokedex'. The app takes a pokemon object from this.$store.state.pokemon and adds it to this.$store.state.pokedex. However, users can add the same pokemon multiple times to the pokedex, ...

If the browser closes and there is no recipient to receive the data requested by my ajax, what ultimately becomes of that data?

On my website, utilizing vb.net / c# programming, there is javascript ajax code that retrieves data from the database and sends JSON back to the page. If, just before the ajax call is able to receive the JSON, the browser is closed or the page is redirect ...

Running a JavaScript script within MongoDB

Seeking guidance on running a JavaScript file within MongoDB. Here is a snippet of code from my JS file: function loadNames() { print("name"); } My attempt to execute the file from the command prompt: mongo test.js resulted in the following error: ...

Change the order of numbering in ordered lists

I am seeking a way to change the ordering of an ordered list to be in descending order. You can view a live example here. Instead of having the counter span multiple ol elements, I would like the counter to reset after each ol. For the live demo, the des ...

Tips on displaying a modal pop-up at the center of the screen while also keeping its position intact when the screen is resized

I have a modal pop-up that I am displaying in the center of the screen using JavaScript. $('div.openIDPopup').css({ 'height': $(document).height() + 'px', 'width': $(window).width() + 'px', ...

Create a separate child process in Node.js

Is it possible to create a separate process from the current script? I want to execute another script while the original one is still running. This new script should be completely independent of the calling script. ...

Is your Node.js HTTP Request failing to function properly?

I am currently working on creating an HTTP Request function where all requests are directed to the same domain but with different file names. Unfortunately, I am encountering a problem where nothing is being displayed in the console and no data is being r ...

What is the best way to extract data from user input and display it in a table modal?

I need to retrieve all the values from the 'input' fields and display them in a modal table using JavaScript. What is the best way to achieve this? Here is my current script: <script> $(document).ready(function() { ...

A guide on implementing listings in React Native through the use of loops

I am trying to display the data retrieved from an API, but I am encountering an error. // Retrieving the data. componentWillMount() { tokenner() .then(responseJson => { const token = "Bearer " + responseJson.result.token; ...

Maintaining the sequence of a PHP associative array when transferring it to JavaScript via ajax

Below is the code from my PHP file: GetUserArray.php $Users = array('7'=>'samei', '4'=>"chaya", '10'=>'abetterchutia'); echo json_encode($Users); Here is the AJAX request I am using: $.ajax({ ...

The behavior of JavaScript may vary when running in the IE deployment environment compared to running in debugging tools like Visual

UPDATE: After debugging in IE, it seems that the "setSelectionRange" function is not supported. It's strange that it works in Visual Studio but not outside of it. The JavaScript fails at that line when running in IE, which raises the question: how can ...

What is the purpose of the `Bitwise operator |` in the `d3.shuffle` source code and how can it be understood

Learning about the Bitwise operator | can be found in the document here and a helpful video tutorial here. However, understanding the purpose and significance of | may not come easily through basic examples in those resources. In my exploration of the sou ...

Can you provide guidance on transforming a JSON date format like '/Date(1388412591038)/' into a standard date format such as '12-30-2013'?

I have a json that is created on the client side and then sent to the server. However, I am facing an issue with the conversion of the StartDate and EndDate values. Can someone please assist me with this? [ { "GoalTitle": "Achievement Goal", ...

Is it possible to automatically adjust the text color to match the background color?

In my hypothetical scenario, I am part of a group chat where the owner has the ability to change the background color of the chat bubbles. Each user's username appears on top of their respective bubble in one of ten pre-assigned colors. However, not a ...

The Kendo UI Grid's cancel function fails to revert back to the original data

I am facing an issue with a kendo grid that is embedded inside a kendo window template. This grid gets its data from another grid on the main UI, following a model hierarchy of Fund -> Currency -> Allocations. The main UI grid displays the entire dat ...

Various methods for deactivating controls in a CSS class

Is there a way to disable all buttons within a specific class? I have attempted the following code without success: $("input.myClass").attr('disabled', true); This is how I am trying to implement it: <script type="text/javascript> ...