Is it possible to adjust the center of rotation in THREE.js TrackballControls so that it is not located at the center of the canvas

I'm currently using TrackballControls within THREE.js. The issue I am facing is that the center of rotation always remains in the center of the canvas. Is there a way to adjust this and move the center of rotation upwards? Here are my failed attempts:

  1. Attempting to move the scene up (scene.translateY(1)) - unfortunately, the center of rotation remains in the center of the canvas

  2. Trying to move the camera up (camera.position.y = 1) - although I seem to be looking "up", the center of rotation is still fixed at the center of the canvas

  3. Modifying the controls target (controls.target.y = 1) - this caused the entire scene to rotate so that the target was back in the center of the canvas.

window.addEventListener("DOMContentLoaded", function () {
var scene, camera, renderer, controls, sphere, red, blue, black;

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 3;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
  color: 0xff0000
});
sphere1 = new THREE.Mesh(geometry, material);
scene.add(sphere1);

geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
  color: 0x00ff00
});
sphere2 = new THREE.Mesh(geometry, material);
scene.add(sphere2);
sphere2.position.x = 1;

geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
  color: 0x0000ff
});
sphere3 = new THREE.Mesh(geometry, material);
scene.add(sphere3);
sphere3.position.y = 1;

controls = new THREE.TrackballControls(camera, renderer.domElement);

function loop() {
  controls.update();
  renderer.render(scene, camera);
  requestAnimationFrame(loop);
}

// camera.position.y = 1;
// controls.target.y = 1;
// scene.position.y = 1;

loop();

})
canvas {
  box-sizing: border-box;
  border: 1px solid red;
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}
<script src="https://rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.js"></script>

I'm aiming to achieve rotation around the red sphere with the sphere positioned in the upper third of the canvas instead of the center.

Answer №1

Explaining your situation involves some complex mathematical concepts because the camera always maintains focus on the target, resulting in it being centered at all times. Simply rotating the camera to adjust its viewing angle downwards is not straightforward with the TrackballControls method as it rotates around the z-axis, making it challenging to determine the orientation of "down."

One potential solution could involve altering the viewport of the renderer using renderer.setViewport(). By manipulating the scene's dimensions within the specified parameters, you have more control over its positioning. In the example below, I render the scene twice - once occupying the entire screen and the second time only 200px in height, as demonstrated by this code snippet:

// First render takes up the full screen
renderer.setViewport(0, 0, window.innerWidth, window.innerHeight);
renderer.render(scene, camera);

// Second render is only 100px tall
renderer.setViewport(0, 0, 100 * ratio, 100);
renderer.render(scene, camera);

If this method aligns with your requirements, ensure to set renderer.autoClear = false; to prevent canvas clearing during each render() invocation.

window.addEventListener("DOMContentLoaded", function () {
var scene, camera, renderer, controls, sphere, red, blue, black;

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 3;
renderer = new THREE.WebGLRenderer();
renderer.autoClear = false;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
color: 0xff0000
});
sphere1 = new THREE.Mesh(geometry, material);
scene.add(sphere1);

geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
sphere2 = new THREE.Mesh(geometry, material);
scene.add(sphere2);
sphere2.position.x = 1;

geometry = new THREE.SphereGeometry(0.1);
material = new THREE.MeshBasicMaterial({
color: 0x0000ff
});
sphere3 = new THREE.Mesh(geometry, material);
scene.add(sphere3);
sphere3.position.y = 1;

controls = new THREE.TrackballControls(camera, renderer.domElement);

var ratio = window.innerWidth / window.innerHeight;
function loop() {
controls.update();

// First render takes up the full screen
renderer.setViewport(0, 0, window.innerWidth, window.innerHeight);
renderer.render(scene, camera);

// Second render is only 100px tall
renderer.setViewport(0, 0, 100 * ratio, 100);
renderer.render(scene, camera);
requestAnimationFrame(loop);
}

// camera.position.y = 1;
// controls.target.y = 1;
// scene.position.y = 1;

loop();

})
canvas {
box-sizing: border-box;
border: 1px solid red;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
<script src="https://rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.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

Mastering the utilization of the Data object in VueJS with Decorators can be tricky. One common error message you might encounter is, "Class method 'data' expected 'this' to be used."

Error > The class method 'data' should use 'this' but it is not. I encountered this issue and believed I fixed it as shown below: TypeScript Unexpected token, A constructor, method, accessor or property was expected <script lang ...

Add one string to an existing array

I have a component named ContactUpdater that appears in a dialog window. This component is responsible for displaying the injected object and executing a PUT operation on that injected object. The code for the component is shown below: HTML <form [for ...

I'm having trouble with my bootstrap dropdown and I've exhausted all of my options trying to fix it based on my current understanding

My dropdown menu is not working despite adding all necessary Bootstrap CDN and files along with the jQuery script. Even with the table being handled by JavaScript, the button does not respond when clicked repeatedly. I suspect the issue lies within the han ...

What are some superior methods for determining the validity of a control in JavaScript?

Is there a way to determine the validity of a control in JavaScript within Asp.Net using a client-side API? Specifically, I am looking for a function that can check if a control is valid based on attached validators. For example, if a textbox has 2 validat ...

The transfer of information through HTTP

I have been exploring the inner workings of HTTP servers and clients to better understand how data is transmitted. Despite reading numerous articles on the topic, I still have some lingering questions that remain unanswered. I would like to walk through th ...

Updating content with Ajax in Laravel

Hey, I'm currently facing an issue with my update functionality. Below is the blade code snippet: <div class="form-group floating-label" id="role_colaboration1"> <select name="{{$role}}[]" id="role" class="form-control"> ...

Enhance Odoo Conversations (mail)

I've been attempting to customize the Odoo discussions, but have hit a roadblock. Here is my goal: https://i.sstatic.net/1lJnc.png I am adding messages using the "New Message" button to an Odoo module (in class mro.order). The messages are appearing ...

Positioning a designated div directly above a designated spot on the canvas

I'm grappling with a challenge in my game where the canvas handles most of the animation, but the timer for the game resides outside the canvas in a separate div. I've been struggling to center the timer around the same focal point as the squares ...

I have the ability to see HTTP-only cookies within my web browser

So, I always believed that httpOnly cookies could only be accessed during a http request. But the other day, while inspecting Firefox dev tools, I noticed that I could actually view the cookies' values. Is this standard behavior? ...

Targeting lightgallery.js on dynamically added elements in Javascript: The solution to dynamically add elements to

I am facing a challenge in targeting dynamically added elements to make them work with lightgallery.js. Take a look at the example below: <div id="animated-thumbs" class="page-divs-middle"> <!-- STATIC EXAMPLE --> ...

Endless loop in XMLHttpRequest()

I am trying to use Ajax in the code snippet below to continuously retrieve a PHP query result until it reaches "6". The code seems to be functioning correctly, but once the result is "6", the script does not stop running. Instead, my CPU fan starts making ...

Is it Unwise to Depend on Props within the useReducer Hook?

Within my App() component, I utilize props named data. This particular component relies on a useReducer hook to manage its state. The reducer function is responsible for determining when to display or hide specific data based on the state. Additionally, it ...

Tips for saving a JavaScript function in JSON format

Looking to store a JS object in Local Storage for future reference, but struggling to convert it to a string. Here’s the code: JSON.stringify({ x: 10, y: function (input) { return input; } }) As a result, I get: "{"x":10}" Any su ...

Is the performance of `fillRect` hindered when painting on a 3D model?

Currently, I am in the process of developing a painting-type application using three.js/canvas. My goal is to enable users to paint directly onto a 3D model, updating the UV map accordingly. https://i.sstatic.net/DfMvB.png While I have achieved the desi ...

How to toggle two classes simultaneously using JQuery

Check out this code snippet: http://jsfiddle.net/celiostat/NCPv9/ Utilizing the 2 jQuery plugin allows for the following changes to be made: - The background color of the div can be set to gray. - The text color can be changed to red. The issue arises wh ...

What are the steps to integrate HJSON with Jest in a create-react-app development environment?

Currently, I am utilizing HJSON within a create-react-app project (view answer here). However, Jest does not utilize the same webpack configuration, resulting in a failed import of HJSON - for instance, import options from '../assets/options.hjson&ap ...

"Error encountered: 'require' is not defined in the bundled JS file for

Recently, I decided to try my hand at Django and ReactJS. While attempting to compile a simple JSX code to JS, I followed this tutorial: . However, I encountered an error that prevented it from working. I then resorted to using npm run dev to compile the c ...

Guide to setting up a Node, Express, Connect-Auth, and Backbone application architecture for server-side development

As someone who primarily works on the client-side, I have recently ventured into the realm of server-side JavaScript. My initial plan for my first Node.js application involves a server-side setup that primarily serves an empty shell along with a plethora o ...

Easily validate the contenteditable attribute of <td> element

I am currently working on a table that displays data from a MYSQL database. Whenever a user makes changes to an element in the table, I want the database to be updated using AJAX. Below is my JavaScript code for sending data in an editable row. function s ...

Transferring an array to PHP using AJAX

In this coding scenario, I initialize my array: let myArray = []; Within a loop, elements are added to the array as follows: myArray.push($(this).data('id')); // Example: [1, 2, 3, 4] Subsequently, I transmit this data to PHP using AJAX throu ...