block the movement along z axis in three js - javascript

I'm creating a game level page using three js. Here I used mapcontrols for user control. In this when I click and drag any part of the screen, the object gets translated (as per my wish). But when I move along the Z axis, the objects move along z-axis which I need to block.
I just want to make the scene like a horizontal carousel in normal html (literally)
I tried some properties of OrbitControls which is given in threejs docs.
https://threejs.org/docs/index.html#examples/en/controls/OrbitControls
Here is the code I tried
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
var mapControls = new THREE.MapControls( camera, renderer.domElement );
mapControls.enableDamping = true;
mapControls.enableRotate = false;
mapControls.enableZoom = false;

To create a carousel-like experience, you don't need orbit controls, you only need to move the camera while looking at your object is advancing through the carousel, like the typical platform games.
I have created this fiddle with an example with an sphere moving along the x axis and the camera following it.
and the relevant code is basically on the render method:
function render() {
requestAnimationFrame(render);
mesh.position.x -= 0.1;
camera.lookAt(mesh.position);
camera.position.x -= 0.1;
renderer.render(scene, camera);
}
If you want to still playing with OrbitControls and fix the axes, you need to play with minPolarAngle and maxPolarAngle, that will block vertical axis if you set the same value for both.
controls.maxPolarAngle = Math.PI / 2;
controls.minPolarAngle = Math.PI / 2;
but that gives no perspective at all, so I would use:
controls.maxPolarAngle = Math.PI / 2.2;
controls.minPolarAngle = Math.PI / 2.2;
Then you have to play with the horizontal perspective, for that you need to set minAzimuthAngle and maxAzimuthAngle between -2 PI and +2 PI...:
controls.minAzimuthAngle = -Math.PI * 1.1;
controls.maxAzimuthAngle = Math.PI * 1.1;
This will slightly turn your camera angle:
Then, using only OrbitControls you will need to move the rest of the objects in the scene, so instead of moving the sphere, you will need to move conceptually the "floor".
If this solution solves your question, please mark the answer as answer accepted, in that way it will also help other users to know it was the right solution.

Related

not able to understand scene position importance

I am trying to write some sample code of three.js where i have a plane and i want that plane to rotate around.
This is my camera:
var camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(50, 50, 60);
camera.lookAt(scene.position);
and this is my plane:
var planeGeometry = new THREE.PlaneGeometry(70, 30, 1, 1);
var planeMaterial = new THREE.MeshBasicMaterial({ color: green });
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -0.5 * Math.PI;
scene.add(plane);
i have other code too but this is my render and animationframe code:
renderScene();
function cameraUpdate() {
camera.position.x = cameraRadius * Math.cos(step);
camera.position.z = cameraRadius * Math.sin(step);
camera.lookAt(scene.position);
}
function renderScene() {
//make update to position, rotation of objects in the scene
step += 0.05;
cameraUpdate();
requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
My question is that inside cameraUpdate function if dont put
camera.lookAt(scene.position);
the rotation become very wierd and when i put this inside cameraUpdate, i get rotation of the plane in own axis which is desired !!!
My question is
what does scene.position mean
Why do i need to make camera lookat at every animation frame? i dont understand how its value get changed when camera is rotated
Thank you in advance !!!
If you want the plane to rotate on its own, you should just use plane.rotation.y += 0.1 on each frame, or something simple like that. What you’re doing instead is that you’re making the camera move around in circles around the plane. Think of it as walking in a circle around a coffee table. If you keep your head looking forward, you won’t see the table as you walk past it. That’s what camera.lookAt() fixes. It makes the camera look at a point in space. You can read about it in the docs.
scene.position is by default at (0, 0, 0) so it’s just another way of telling the camera to look at the center of the scene.

Three.js - Scaling a plane to full screen

I am adding a plane to the scene like this:
// Camera
this.three.camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 60);
// Plane
const planeGeometry = new THREE.PlaneBufferGeometry(1,1,this.options.planeSegments,this.options.planeSegments);
const planeMat = new THREE.ShaderMaterial( ... )
this.three.plane = new THREE.Mesh(planeGeometry,planeMat);
this.three.scene.add(this.three.plane);
Pretty basic. I am than trying to find out how I have to move the plane in the Z axis for it to fill the browser-viewport. For that,
// See attachment "solving for this" is closeZ
const closeZ = 0.5 / Math.tan((this.three.camera.fov/2.0) * Math.PI / 180.0);
this.uniforms.uZMax = new THREE.Uniform(this.three.camera.position.z - closeZ);
So now I know in my shader how much I can add to Z to make the plane fill the viewport. Vertex Shader looks like this:
uniform float uZMax;
void main() {
vec3 pos = (position.xy, uZMax);
gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1 );
}
This actually zoom the plane to fill the viewport, but in Y-Axis, not in X-Axis.
I would like to discover why my math is referring to the Y-Axis and how I need to transform it, so the plane will fill the viewport width instead of it's height?
Edit:
I'm trying to achieve something like this https://tympanus.net/Tutorials/GridToFullscreenAnimations/index4.html - But in the given example they're just scaling the x- and y-pixels to fill the screen and therefore no actual 3d - and therefore again no lighting is going on.
I want to actually move the plane towards the camera using different z-values so I can calculate surface normals to then again calculate lighting in the fragment shader by how aligned the normal is with the light direction - like it's done in raymarching.
You can easily achieve such a fullscreen effect by using the following setup:
const camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
const geometry = new THREE.PlaneBufferGeometry( 2, 2 );
When creating a mesh with this geometry and a custom shader material, the orthographic camera will ensure the intended fullscreen effect. This approach is used in all post-processing example where the entire viewport has to be filled with a single quad.
I figured it out, and as suspected it has to do with the aspect ratio passed to the camera. For anyone looking for a solution after me, here is how it works:
I wrongly assumed that the field-of-value for the camera is the same in all directions. But the FOV is referring to the Y-Axis FOV, so we have to convert the camera-fov to the x-axis also:
function getXFOV() {
// Convert angle to radiant
const FOV = this.three.camera.fov;
let yFovRadiant = FOV * Math.PI/180;
// Calculate X-FOV Radiant
let xFovRadiant = 2 * Math.atan( Math.tan(yFovRadiant/2) * (window.innerWidth / window.innerHeight));
// Convert back to angle
let xFovAngle = xFovRadiant * 180/Math.PI;
return xFovAngle;
}
And then we simply use that angle in in the closeZ-calculation instead of the camera's fov. Now it snaps to the window-width.
const closeZ = 0.5 / Math.tan((this.getXFOV()) * Math.PI / 180.0);
this.uniforms.uZMax = new THREE.Uniform(this.three.camera.position.z - closeZ);

Orientation of camera not preserved when switching between camera types in Three.js

All of the code
Hello, I'm having a problem with switching between a perspective camera and an orthographic camera. My goal is to be able to have a switch to easily switch back and forth between the two camera types while preserving the camera's location and orientation. Here's the relevant code (line 98):
let display = gui.addFolder("Display");
display.add(guiOptions.display,"orthographicCamera").name("Orthographic Camera").onChange(function(){
var position=camera.position;
var target=controls.target;
var quaternion=camera.quaternion;
if (guiOptions.display.orthographicCamera){
camera = new THREE.OrthographicCamera(
window.innerWidth / - (zoom / scaleFactor),
window.innerWidth / (zoom / scaleFactor),
window.innerHeight / (zoom / scaleFactor),
window.innerHeight / - (zoom / scaleFactor),
-500, 1000);
}
else{
camera = new THREE.PerspectiveCamera( 115, window.innerWidth / window.innerHeight, 0.000001, 10000 );
}
camera.position.set(position.x,position.y,position.z);
camera.quaternion.set(quaternion._x,quaternion._y,quaternion._z,quaternion._w);
controls=new THREE.TrackballControls(camera,renderer.domElement);
controls.dynamicDampingFactor = .15;
controls.target=target;
});
My problem is that, for some camera rotations, the switch between a perspective camera and an orthographic camera results in a different orientation of the resulting camera. I thought it was a problem with the quaternion attribute, but changing it to its previous value doesn't seem to have any effect.
I can't seem to figure out how to fix this. I'd appreciate any help, thanks ahead of time!
EDIT: I figured it out but I'm doing something right now, so I'll update with my solution later
Do something like:
orthoCamera=orthographic camera instance
orthoControls=document.body.appendChild(renderer.domElement);
orthoControls=new THREE.TrackballControls(orthoCamera,renderer.domElement);
perspectiveCamera=perpsective camera instance
perspectiveControls=new THREE.TrackballControls(perspectiveCamera,renderer.domElement);
...
display.add(guiOptions.display,"orthoCamera").name("Orthographic Camera");
...
function animate() {
requestAnimationFrame(animate);
orthoControls.update();
perspectiveControls.update();
if (guiOptions.display.orthoCamera){
renderer.render(scene, orthoCamera)
}
else{
renderer.render(scene, perspectiveCamera)
}
}
Thus both controls are active at the same time, and switching between camera views is simply a switch between witch camera to render with.

Strange shaking while rotating the camera with Orbit Controls in Three.js

I'm making a model of the Solar System. This is my current metric:
scale = 0.001;
// 1 unit - 1 kilometer
var AU = 149597871 * scale;
This is how i define the camera, renderer and controls:
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1 * scale, 0.1 * AU);
renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
controls = new THREE.OrbitControls(camera, renderer.domElement);
Then i give the user the option to jump between the objects so this is how i set the camera after user selects a planet/moon:
function cameraGoTo() {
for (var i = scene.children.length - 1; i >= 0 ; i--) {
var obj = scene.children[i];
if (obj.name == parameters.selected) {
controls.target = obj.position;
camera.position.copy(obj.position);
camera.position.y += obj.radius * 2;
}
}
}
The problem is that for small planets/moons ( <= 1000 km in radius) camera is shaking while rotating around the object. I have only basic knowledge of computer graphics so i don't know either this is the problem of Orbit Controls or it has something to with renderer itself...so I've tried to set logarithmicDepthBuffer = true but it didn't help. Also trying different scale didn't change anything.
Thank in advance for any help/clues.
EDIT:
Here's the fiddle:
http://jsfiddle.net/twxyz/8kxcdkjj/
You can see that shaking increases with any of the following:
the smaller the object,
the further the object from the point of origin,
What is the cause of this? It clearly seems it has nothing to do with the camera near/far spectrum values but is related to the distance the objects are from the center of the scene.
I've come up with the solution.
My problem was with the floating point precision errors when dealing with objects far from the point of origin. This turns out to be a very known problem and there are various solutions. I've used this one:
http://answers.unity3d.com/questions/54739/any-solution-for-extreamly-large-gameworlds-single.html
What happens is basically instead of moving the camera/player, we transform whole scene relative to the camera/player that is always at the point of origin. In this case, Orbit Controls' target is always point of origin.

How to rotate a THREE.PerspectiveCamera around on object

I am making this program where you can click on an object, zoom to it, then look at it from all angles by holding the right mouse button and dragging. I need the camera to be going around the object, not rotate the object with the camera looking at it. I honestly just have no idea how to math it out!
For testing there is already a game object with an xyz we have selected and are looking at
var g = new GameObject(500, 0, 0);//The game object with xyz
this.selected = g;//set selected to g
//Create and set the camera
this.camera = new THREE.PerspectiveCamera(45, w/h, 1, 10000);
this.camera.position.x = 0;
this.camera.position.y = 0;
this.camera.position.z = 0;
//set camera to look at the object which is 500 away in the x direction
this.camera.lookAt(new THREE.Vector3(this.selected.x, this.selected.y, this.selected.z));
So the radius between the camera and the object is 500 and while selected and rotating, the camera should always be 500 away.
I update the scene here:
Main.prototype.update = function(){
this.renderer.render(this.scene, this.camera);//scene is just some ambient lighting
//what to do when mouse right is held down
if(this.rightMouseDown){
//placeholder functionality, needs to rotate around object based on mouse movements
this.camera.position.x -= 5;
}
}
How do I rotate this camera around g with a radius of 500?!?!
As gaitat mentioned, trackball controls are the best place to start with many configurable parameters to make camera rotation/revolution easy. One enormous potential benefit of this method ( especially for your project ) is avoiding "gimbal lock" which is the source of much frustration when working with rotations. Here's a link that might help you with Trackball controls and Orbitcontrols:
Rotate camera in Three.js with mouse
Another option would be setting camera coordinates yourself in the animation loop which is actually quite simple:
var angle = 0;
var radius = 500;
function animate() {
...
// Use Math.cos and Math.sin to set camera X and Z values based on angle.
camera.position.x = radius * Math.cos( angle );
camera.position.z = radius * Math.sin( angle );
angle += 0.01;
...
}
Another option would be to connect the camera to a pivot object and just rotate the pivot:
var camera_pivot = new THREE.Object3D()
var Y_AXIS = new THREE.Vector3( 0, 1, 0 );
scene.add( camera_pivot );
camera_pivot.add( camera );
camera.position.set( 500, 0, 0 );
camera.lookAt( camera_pivot.position );
...
camera_pivot.rotateOnAxis( Y_AXIS, 0.01 ); // radians
If you pursue this option, be aware that the camera object is in "camera pivot space", and might be more challenging to manipulate further.

Categories

Resources