Rotate Sphere x Axis Based on Mouse Position in three.js - javascript

I have a sphere with an earth texture on it using three.js. Although the earth rotates on the y axis on it's own (horizontally), I'm not sure how to rotate the sphere on its vertical x axis based on the mouse position. The earth should show the north pole when the mouse is positioned at the top of the browser window, and the south pole when the mouse is positioned at the bottom of the screen. It should rotate to show the earth between the poles based on the vertical mouse position as the mouse moves vertically within the browser window.
How can this type of rotation be accomplished?
This code sets up the three.js scene, but the math for the rotation is not quite correct:
<html>
<head>
<title>Earth Rotation</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var geometry = new THREE.SphereGeometry(1, 100, 100);
var material = new THREE.MeshPhongMaterial();
var earthMesh = new THREE.Mesh(geometry, material);
material.map = THREE.ImageUtils.loadTexture('images/earth.jpg');
var light = new THREE.AmbientLight( 0xcccccc );
scene.add(light);
scene.add(earthMesh);
camera.position.z = 1.5;
document.addEventListener('mousemove', function(event){
if(event.clientY < window.innerHeight / 2) {
earthMesh.rotation.x = ((window.innerHeight / 2) - (event.clientY * .0001));
} else if(event.clientY > window.innerHeight / 2) {
earthMesh.rotation.x = ((window.innerHeight / 2) + (event.clientY * .0001));
}
}, false)
var animate = function () {
requestAnimationFrame( animate );
earthMesh.rotation.y -= 0.0005;
renderer.render( scene, camera );
};
animate();
</script>
</body>
</html>

Possibly, you can achieve the same thing, using THREE.OrbtiControls() with some modifications.
Just an option with moving the camera over the rotating globe.
r96
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 10;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var globe = new THREE.Mesh(new THREE.SphereGeometry(4, 32, 16), new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load("https://c1.staticflickr.com/3/2521/3884071286_edb50f8137_b.jpg")
}));
scene.add(globe);
window.addEventListener("mousemove", onMouseMove, false);
function onMouseMove(event) {
camera.position.setFromSphericalCoords(10, Math.PI * -event.clientY / window.innerHeight, 0);
camera.lookAt(globe.position);
}
render();
function render() {
requestAnimationFrame(render);
globe.rotation.y -= 0.005;
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>

Related

How to make a parallax effect using Three.js

I want to make a parallax effect on mouse move using three.js.
Basically I want to generate bunch of clouds to canvas and want them to move on x axis when mouse is moved.
So I have already tried to add clouds to the scene as images. How could I link mouse move even to these clouds? Or should I add clouds to the scene differently?
How I added clouds:
var imgCloud = new THREE.MeshBasicMaterial({
map:THREE.ImageUtils.loadTexture('img/cloud.jpg')
});
imgCloud.map.needsUpdate = true;
// Cloud
var cloud = new THREE.Mesh(new THREE.PlaneGeometry(200, 200), imgCloud);
cloud.overdraw = true;
scene.add(cloud);
You need to add an event listener to the window to get the mouse position. Then you can use that to modify the position of all clouds individually or just the position of the scene.
window.addEventListener('mousemove', onMouseMove, false);
function onMouseMove(event) {
scene.position.x = (event.clientX - window.innerWidth / 2);
}
You can simply catch the mouse position and then move the camera along an axis relative to the new mouse position.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 150;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Add cloud
for (let i = 0; i <= 200; i++) {
const geometry = new THREE.SphereGeometry(5, 32, 32);
const material = new THREE.MeshBasicMaterial({ color: 0x3399ff, transparent: true, opacity: 0.8});
const sphere = new THREE.Mesh(geometry, material);
sphere.position.x += Math.round(Math.random() * 500) - 250;
sphere.position.y += Math.round(Math.random() * 500) - 250;
sphere.position.z += Math.round(Math.random() * 200);
scene.add(sphere);
}
// Control
var mouseTolerance = 0.1;
document.onmousemove = function (e) {
var centerX = window.innerWidth * 0.5;
var centerY = window.innerHeight * 0.5;
camera.position.x = (e.clientX - centerX) * mouseTolerance;
camera.position.y = (e.clientY - centerY) * mouseTolerance;
};
//Render loop
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
render();
body{
margin: 0;
overflow: hidden;
height: 400px;
width: 600px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.min.js"></script>
The mouse position can be obtained withdocument.onmousemove as usual. Camera can be repositioned with camera.position.[axis]. You can play with different axes and see how it looks. Note that some objects must be closer to the camera than others otherwise it will not look like Parallax

Set 3d cube rotation origin

I have a simple 3d cube (BoxGeometry of 100, 100, 100) and I am trying to rotate it. If we call all 100x100x100 a tile - when I rotate it I can see it's overlapping the below tile.
(by changing color, now I totally understand the behaviour).
tl.to(this.cube4.rotation, 0.5, {z: -45* Math.PI/180});
[
What if I want to rotate it based on an anchor point of right bottom? So instead of overflowing inside the below tile, it will overflow that portion to above tile.
So it will look like the green example and not the red example:
The red example here is achieved by
tl.to(this.cube4.rotation, 0.5, {z: -45* Math.PI/180});
tl.to(this.cube4.position, 0.5, {x: 50 }, 0.5);
I am very new to three.js so if any terminology is wrong, please warn me
Add the ("red") cube to a THREE.Group, in that way that the rotation axis (the edge) is in the origin of the group. This means the cube has to be shifted by the half side length.
If you rotate the group object, then the cube (which is inside the group) will rotate around the edge and not around its center.
e.g.
var bbox = new THREE.Box3().setFromObject(cube);
cube.position.set(bbox.min.x, bbox.max.y, 0);
var pivot = new THREE.Group();
pivot.add(cube);
scene.add(pivot);
See also the answer to How to center a group of objects?, which uses this solution to rotate a group of objects.
(function onLoad() {
var camera, scene, renderer, orbitControls, pivot;
var rot = 0.02;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 100);
camera.position.set(4, 1, 2);
//camera.lookAt( -1, 0, 0 );
loader = new THREE.TextureLoader();
loader.setCrossOrigin("");
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
scene.add(camera);
window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
orbitControls = new THREE.OrbitControls(camera, container);
var ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.set(1,2,-1.5);
scene.add( directionalLight );
addGridHelper();
createModel();
}
function createModel() {
var material = new THREE.MeshPhongMaterial({color:'#80f080'});
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var cube1 = new THREE.Mesh(geometry, material);
cube1.position.set(0,-0.5,-0.5);
var cube2 = new THREE.Mesh(geometry, material);
cube2.position.set(0,0.5,-0.5);
var cube3 = new THREE.Mesh(geometry, material);
cube3.position.set(0,-0.5,0.5);
var material2 = new THREE.MeshPhongMaterial({color:'#f08080'});
var cube4 = new THREE.Mesh(geometry, material2);
var bbox = new THREE.Box3().setFromObject(cube4);
cube4.position.set(bbox.min.x, bbox.max.y, 0);
pivot = new THREE.Group();
pivot.add(cube4);
pivot.position.set(-bbox.min.x, 0.5-bbox.max.y, 0.5);
scene.add(cube1);
scene.add(cube2);
scene.add(cube3);
scene.add(pivot);
}
function addGridHelper() {
var helper = new THREE.GridHelper(100, 100);
helper.material.opacity = 0.25;
helper.material.transparent = true;
scene.add(helper);
var axis = new THREE.AxesHelper(1000);
scene.add(axis);
}
function animate() {
requestAnimationFrame(animate);
orbitControls.update();
pivot.rotation.z += rot;
if (pivot.rotation.z > 0.0 || pivot.rotation.z < -Math.PI/2) rot *= -1;
render();
}
function render() {
renderer.render(scene, camera);
}
})();
<!--script src="https://threejs.org/build/three.js"></!--script-->
<script src="https://rawcdn.githack.com/mrdoob/three.js/r124/build/three.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r124/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.js"></script>
<div id="container"></div>
From the first image, it appears that the pivot of your red tile is at its center.
For the rotation you want, you would ideally change the pivot to the lower right of the cube. This is impossible without modifying the geometry of the cube.
BUT a simple trick is to create an empty node at that pivot point, parent your cube to that empty, and apply your rotation to the empty. (Don't forget to remove your translation, you don't need it anymore)
Here is some pseudo code, assuming your red box is centered at (0,0,0) and has a width and height of 100:
// create an empty node at desired rotation pivot
var empty = new Object3D or group
empty.position = (50, -50, 0)
// parent your cube to the empty
var cube = your box
empty.add(cube)
// you may need to change the local position of your cube to bring it back to its global position of (0,0,0)
cube.position = (-50, 50, 0)
rotate empty by 45°
I think you can get the bounds of the rotated object like this:
bounds = new THREE.Box3().setFromObject( theRedObject )
Then reposition the object.y based on its bounds.min.y
let scene, camera, controls, ambient, point, loader, renderer, container, stats;
const targetRotation = 0;
const targetRotationOnMouseDown = 0;
const mouseX = 0;
const mouseXOnMouseDown = 0;
const windowHalfX = window.innerWidth / 2;
const windowHalfY = window.innerHeight / 2;
init();
animate();
var box, b1, b2, b3;
function init() {
// Create a scene which will hold all our meshes to be rendered
scene = new THREE.Scene();
// Create and position a camera
camera = new THREE.PerspectiveCamera(
60, // Field of view
window.innerWidth / window.innerHeight, // Aspect ratio
/*window.innerWidth / -8,
window.innerWidth / 8,
window.innerHeight / 8,
window.innerHeight / -8,
*/
0.1, // Near clipping pane
1000 // Far clipping pane
);
scene.add(camera)
// Reposition the camera
camera.position.set(0, 5, 10);
// Point the camera at a given coordinate
camera.lookAt(new THREE.Vector3(0, 0, 0));
// Add orbit control
controls = new THREE.OrbitControls(camera);
controls.target.set(0, -0.5, 0);
controls.update();
// Add an ambient lights
ambient = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(ambient);
// Add a point light that will cast shadows
point = new THREE.PointLight(0xffffff, 1);
point.position.set(25, 50, 25);
point.castShadow = true;
point.shadow.mapSize.width = 1024;
point.shadow.mapSize.height = 1024;
scene.add(point);
group = new THREE.Group();
group.position.y = 0;
scene.add(group);
rotationAnchor = new THREE.Object3D()
group.add(rotationAnchor);
box = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshStandardMaterial({
color: 'grey'
}))
b1 = box.clone();
b2 = box.clone();
b3 = box.clone();
b3.material = b3.material.clone()
b3.material.color.set('red')
group.add(box);
group.add(b1);
b1.position.y += 1
group.add(b2);
b2.position.z += 1
rotationAnchor.add(b3);
rotationAnchor.position.set(0.5, 0.5, 1.5)
b3.position.set(-.5, -.5, -.5)
// Create a renderer
renderer = new THREE.WebGLRenderer({
antialias: true
});
// Set size
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Set color
renderer.setClearColor(0xf8a5c2);
renderer.gammaOutput = true;
// Enable shadow mapping
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Append to the document
container = document.createElement("div");
document.body.appendChild(container);
document.body.appendChild(renderer.domElement);
// Add resize listener
window.addEventListener("resize", onWindowResize, false);
// Enable FPS stats
stats = new Stats();
container.appendChild(stats.dom);
var gui = new dat.GUI({
height: 5 * 32 - 1
});
let params = {
'test': 4,
'bevelThickness': 1,
'bevelSize': 1.5,
'bevelSegments': 3
}
gui.add(params, 'test', 0, 10).onChange(val => {
test = val
})
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
rotationAnchor.rotation.z = (Math.cos(performance.now() * 0.001) * Math.PI * 0.25) + (Math.PI * 1.25)
requestAnimationFrame(animate);
// Re-render scene
renderer.render(scene, camera);
// Update stats
stats.update();
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.2/dat.gui.min.js"></script>

Zoom in to the object based on mouse pointer

Here I'm trying to zoom in the object(say cube) based on the on mouse pointer position. Here I googled and got a idea that it can be achieved in D3 JS and also it can achieved by capturing the mouse pointer 3D point and passing it in the mouse wheel function.
Here's the fiddle https://jsfiddle.net/fpt9hswo/
var scene, renderer, camera;
var cube;
var controls;
var containerWidth = window.innerWidth,
containerHeight = window.innerHeight;
init();
animate();
function init() {
configureRenderer();
scene = new THREE.Scene();
configureCube();
configureCamera();
configureLight();
configureControls();
fitAll();
}
function configureRenderer() {
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(containerWidth, containerHeight);
document.body.appendChild(renderer.domElement);
}
function configureCube() {
var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
var cubeMaterial = new THREE.MeshLambertMaterial({
color: 0xff0000
});
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(50, 0, 0);
scene.add(cube);
}
function configureCamera() {
camera = new THREE.PerspectiveCamera(45, containerWidth / containerHeight, 1, 1000);
camera.position.set(0, 160, 400);
camera.lookAt(scene);
}
function configureLight() {
pointLight = new THREE.PointLight(0xffffff, 1.0, 100000);
pointLight.position.set(0, 300, 200);
scene.add(pointLight);
}
function configureControls() {
controls = new THREE.TrackballControls(camera, renderer.domElement);
// configuration of controls
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5.0;
controls.panSpeed = 2.0;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0;
}
function fitAll() {
// Calculate bounding box of the whole scene
var boundingBoxOfNode = new THREE.Box3().setFromObject(scene),
centerOfGravity = boundingBoxOfNode.getCenter();
/************* CAMERA *************************/
camera.position.addVectors(camera.position, centerOfGravity);
camera.lookAt(centerOfGravity);
//new camera positions will be set here
//Eg: camera.position.set(newCamera.x,newCamera.y,newCamera.z);
//Similarly new camera rotation and quaternion coordinates will be set
//Eg: camera.rotation.set(newCamera.rotatex,newCamera.rotatey,newCamera.rotatez);
//Eg: camera.quaternion.set(newCamera.qw,newCamera.qx,newCamera.qy,newCamera.qz);
/************* CONTROLS *************************/
controls.target.set(centerOfGravity.x, centerOfGravity.y, centerOfGravity.z);
//new controls.target values will be set here
//Eg: controls.target.set(newCamera.targetx,newCamera.targety,newCamera.targetz);
}
function animate() {
controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
Thanks in advance
To do what you want you've to implement your own mouse wheel event and you've to disable the default zoom of THREE.TrackballControls:
controls = new THREE.TrackballControls(camera, renderer.domElement);
//...
controls.zoomSpeed = 0.0;
Add a wheel event:
e.g.
renderer.domElement.addEventListener("wheel", event => {
const delta = event.deltaY;
// [...]
}
Zooming in perspective projection can be achieved, by shifting the camera position in the depth of the world.
If you want to zoom to a point, this can be achieved by moving the camera along a ray, from the camera position through the cursor (mouse) position and to move the target position in parallel.
A point on the ray from the camera to the cursor in normalized device space can be found with ease. In normalized device space all coordinates are in range [-1, 1] and all points with the same x and y coordinate are at the same ray. If the z coordinate is -1, the the point is on the near plane and if z is 1 then the point is on the far plane.
e.g. NDC point on the far plane and on a ray through the cursor:
let x = 2 * event.clientX / window.innerWidth - 1;
let y = 1 - 2 * event.clientY / window.innerHeight;
let cursorpos = new THREE.Vector3(x, y, 1);
This point in normalized device space can be transformed to a point in world space, by THREE.Vector3.unproject(). The parameter to the function has to be the THREE.Camera which defines the view and projection:
cursorpos.unproject(camera);
The direction for the movement of the camera is the normalized direction from the camera position to the cursor position in world space:
let dir = new THREE.Vector3().copy(cursorpos).sub(camera.position).normalize();
Calculate the movement dependent on the direction and the mouse wheel delta and update the camera and THREE.TrackballControls:
let shift = new THREE.Vector3().copy(dir).multiplyScalar(delta * 0.1);
camera.position.add(shift);
controls.position0.add(shift);
controls.target.add(shift);
See the example, where I applied the suggestions to the code of the question:
var scene, renderer, camera;
var cube;
var controls;
var containerWidth = window.innerWidth,
containerHeight = window.innerHeight;
init();
animate();
function init() {
configureRenderer();
scene = new THREE.Scene();
configureCube();
configureCamera();
configureLight();
configureControls();
}
function configureRenderer() {
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(containerWidth, containerHeight);
document.body.appendChild(renderer.domElement);
window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
if (controls)
controls.handleResize();
}
renderer.domElement.addEventListener("wheel", event => {
const delta = event.deltaY;
let x = 2 * event.clientX / window.innerWidth - 1;
let y = 1 - 2 * event.clientY / window.innerHeight;
let cursorpos = new THREE.Vector3(x, y, 1);
cursorpos.unproject(camera);
let dir = new THREE.Vector3().copy(cursorpos).sub(camera.position).normalize();
let shift = new THREE.Vector3().copy(dir).multiplyScalar(delta * 0.1);
camera.position.add(shift);
controls.position0.add(shift);
controls.target.add(shift);
});
}
function configureCube() {
var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
var cubeMaterial = new THREE.MeshLambertMaterial({
color: 0xff0000
});
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(50, 0, 0);
scene.add(cube);
}
function configureCamera() {
camera = new THREE.PerspectiveCamera(45, containerWidth / containerHeight, 1, 1000);
camera.position.set(0, 160, 400);
camera.lookAt(scene);
}
function configureLight() {
pointLight = new THREE.PointLight(0xffffff, 1.0, 100000);
pointLight.position.set(0, 300, 200);
scene.add(pointLight);
}
function configureControls() {
controls = new THREE.TrackballControls(camera, renderer.domElement);
// configuration of controls
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 0.0;
controls.panSpeed = 2.0;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0;
}
function animate() {
controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>

how i rotate cube on button click in three.js?

here is my code...cube is a perfect but i want rotate on button click.
eg..when i click front button then cube will be show front side same as other button
I did a lot of research but i did not find any solution
please anyone can help me..
var scene, camera, renderer, cube;
init();
//drag();
function init() {
// renderer
var container = document.getElementById("container");
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor ('#fff', 1);
container.appendChild(renderer.domElement);
// camera
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.x = 50;
camera.position.y = 50;
camera.position.z = 800;
//cube
var geometry = new THREE.BoxBufferGeometry(250, 350, 100,1,1,1);
var cubeMaterial = new THREE.MeshLambertMaterial({color:"red"});
cube = new THREE.Mesh(geometry, cubeMaterial);
//cube.doubleSided = true;
cube.rotation.x = Math.PI / 1.5;
cube.rotation.y = Math.PI / 1;
// scene
scene = new THREE.Scene();
scene.add(cube);
// add subtle ambient lighting
var ambientLight = new THREE.AmbientLight(0x888888);
scene.add(ambientLight);
// directional lighting
var directionalLight = new THREE.DirectionalLight(0x666666);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
function render() {
renderer.render(scene, camera);
//requestAnimFrame(render);
requestAnimationFrame(render);
}
render();
}
body {
margin: 0px;
}
#container {
width: 100%;
height: 100%;
}
<script src="https://rawgit.com/mrdoob/three.js/r86/build/three.min.js"></script>
<div id="container"></div>
You already have code which does some rotation:
cube.rotation.x = Math.PI / 1.5;
cube.rotation.y = Math.PI / 1;
Make yourself a set of functions which rotate the object to the desired angles and call them on buttons' clicks.

Three JS Level Horizon Camera

I've dug around everywhere looking for a solution to this. It seems that on OrbitControls and TrackballControlls the camera wont stay horizontal! As you move around with TrackballControlls the scene starts to roll. OrbitControlls dragging from left to right only rolls the scene. I'd like to be able to use the TrackballControls but keep the camera level with the horizon when moving around the center of the scene. Is this possible?
My code:
// SETUP GLOBAL VARIABLES
var camera, controls, scene, renderer;
// PLANET PHYSICAL LOCATIONS
var sun, mercPL, venPL, earthPL, marsPL, jupPL, satPL, urPL, nepPL;
// TIME, AND SCALARS
var now, scalar, planetScalar;
init();
animate();
function init() {
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
var container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 100000 );
camera.position.z = 200;
controls = new THREE.OrbitControls( camera, renderer.domElement );
//controls.addEventListener( 'change', render ); // add this only if there is no animation loop (requestAnimationFrame)
controls.enableDamping = true;
controls.dampingFactor = 0.8;
controls.enableZoom = true;
// ADD THE SUN PHYSICAL LOCATION
var geometry = new THREE.SphereGeometry(5, 30, 30, 0, Math.PI * 2, 0, Math.PI * 2);
var material = new THREE.MeshBasicMaterial({color: "Yellow"});
sun = new THREE.Mesh(geometry, material);
scene.add(sun);
var segmentCount = 32,
radius = 80,
geometry = new THREE.Geometry(),
material = new THREE.LineBasicMaterial({ color: 0xFFFFFF });
for (var i = 0; i <= segmentCount; i++) {
var theta = (i / segmentCount) * Math.PI * 2;
geometry.vertices.push(
new THREE.Vector3(
Math.cos(theta) * radius,
Math.sin(theta) * radius,
0));
}
scene.add(new THREE.Line(geometry, material));
var segmentCount2 = 32,
radius2 = 120,
geometry2 = new THREE.Geometry(),
material2 = new THREE.LineBasicMaterial({ color: 0xFFFFFF });
for (var i = 0; i <= segmentCount2; i++) {
var theta = (i / segmentCount2) * Math.PI * 2;
geometry2.vertices.push(
new THREE.Vector3(
Math.cos(theta) * radius2,
Math.sin(theta) * radius2,
0));
}
scene.add(new THREE.Line(geometry2, material2));
//
window.addEventListener( 'resize', onWindowResize, false );
//
render();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
render(); // MUST BE HERE FOR ANIMATION
}
function render() {
renderer.render( scene, camera );
}
Thanks!
Perhaps this can help you ( all the options are commented in the orbit library)
Level Horizon:
controls.minPolarAngle = Math.PI / 2;
controls.maxPolarAngle = Math.PI / 2;
Focus of Orbit:
controls.target = (cube.position);
Result: (Note: My mouse controls are inverted (Orbit Right / Pan Left) )
Three.js Lock Orbit Controls
Edit: After reviewing your comments code, I think this is what you want:
Three.js Orbit Controls pt 2.
The gist is that :
a) you need to provide the camera with an up vector:
camera.up.set( 0, 0, 1 );
And
b) Target the sun with the camera:
camera.lookAt(sun.position);
You can still play with the damping, and lock the angles ( there are also vertical constraints if you need them) and speed up down the yaw, but I hope this gets you closer.

Categories