I am trying to rotate the camera around to X-axis of the scene.
At this point my code is like this:
rotation += 0.05;
camera.position.y = Math.sin(rotation) * 500;
camera.position.z = Math.cos(rotation) * 500;
This makes the camera move around but during the rotation something weird happens and either the camera flips, or it skips some part of the imaginary circle it's following.
You have only provided a snippet of code, so I have to make some assumptions about what you are doing.
This code:
rotation += 0.05;
camera.position.x = 0;
camera.position.y = Math.sin(rotation) * 500;
camera.position.z = Math.cos(rotation) * 500;
camera.lookAt( scene.position ); // the origin
will cause the "flipping" you refer to because the camera is trying to remain "right side up", and it will quickly change orientation as it passes over the "north pole."
If you offset the camera's x-coordinate like so,
camera.position.x = 200;
the camera behavior will appear more natural to you.
Three.js tries to keep the camera facing up. When you pass 0 along the z-axis, it'll "fix" the camera's rotation. You can just check and reset the camera's angle manually.
camera.lookAt( scene.position ); // the origin
if (camera.position.z < 0) {
camera.rotation.z = 0;
}
I'm sure this is not the best solution, but if anyone else runs across this question while playing with three.js (like I just did), it'll give one step further.
This works for me, I hope it helps.
Rotating around X-Axis:
var x_axis = new THREE.Vector3( 1, 0, 0 );
var quaternion = new THREE.Quaternion;
camera.position.applyQuaternion(quaternion.setFromAxisAngle(x_axis, rotation_speed));
camera.up.applyQuaternion(quaternion.setFromAxisAngle(x_axis, rotation_speed));
Rotating around Y-Axis:
var y_axis = new THREE.Vector3( 0, 1, 0 );
camera.position.applyQuaternion(quaternion.setFromAxisAngle(y_axis, angle));
Rotating around Z-Axis:
var z_axis = new THREE.Vector3( 0, 0, 1 );
camera.up.applyQuaternion(quaternion.setFromAxisAngle(z_axis, angle));
I wanted to move my camera to a new location while having the camera look at a particular object, and this is what I came up with [make sure to load tween.js]:
/**
* Helper to move camera
* #param loc Vec3 - where to move the camera; has x, y, z attrs
* #param lookAt Vec3 - where the camera should look; has x, y, z attrs
* #param duration int - duration of transition in ms
**/
function flyTo(loc, lookAt, duration) {
// Use initial camera quaternion as the slerp starting point
var startQuaternion = camera.quaternion.clone();
// Use dummy camera focused on target as the slerp ending point
var dummyCamera = camera.clone();
dummyCamera.position.set(loc.x, loc.y, loc.z);
// set the dummy camera quaternion
var rotObjectMatrix = new THREE.Matrix4();
rotObjectMatrix.makeRotationFromQuaternion(startQuaternion);
dummyCamera.quaternion.setFromRotationMatrix(rotObjectMatrix);
dummyCamera.up.set(camera)
console.log(camera.quaternion, dummyCamera.quaternion);
// create dummy controls to avoid mutating main controls
var dummyControls = new THREE.TrackballControls(dummyCamera);
dummyControls.target.set(loc.x, loc.y, loc.z);
dummyControls.update();
// Animate between the start and end quaternions
new TWEEN.Tween(camera.position)
.to(loc, duration)
.onUpdate(function(timestamp) {
// Slerp the camera quaternion for smooth transition.
// `timestamp` is the eased time value from the tween.
THREE.Quaternion.slerp(startQuaternion, dummyCamera.quaternion, camera.quaternion, timestamp);
camera.lookAt(lookAt);
})
.onComplete(function() {
controls.target = new THREE.Vector3(scene.children[1].position-0.001);
camera.lookAt(lookAt);
}).start();
}
Example usage:
var pos = {
x: -4.3,
y: 1.7,
z: 7.3,
};
var lookAt = scene.children[1].position;
flyTo(pos, lookAt, 60000);
Then in your update()/render() function, call TWEEN.update();
Full example
Related
How can a cesium camera be moved around an object in circular path?
Assuming you want something similar to helicopter circles... It can be done by 'lookAt' at every clock tick.
let heading = 0; //or any starting angle in radians
let rotation = -1; //counter-clockwise; +1 would be clockwise
let centre = new Cesium.Cartesian3.fromDegrees(longitude, latitude);
let elevation = 100; // 100 meters
let pitch = -0.7854; //looking down at 45 degrees
const SMOOTHNESS = 600; //it would make one full circle in roughly 600 frames
viewer.clock.onTick.addEventListener(() => {
heading += rotation * Math.PI / SMOOTHNESS;
viewer.camera.lookAt(centre, new Cesium.HeadingPitchRange(heading, pitch, elevation));
});
I'm using BabylonJS to make a little game.
I'm using this code to build a camera :
this.cam = new BABYLON.FreeCamera("playerCamera", new BABYLON.Vector3(x, y, z), s);
this.cam.checkCollisions = true;
this.cam.applyGravity = false;
this.cam.keysUp = [90]; // Z
this.cam.keysDown = [83]; // S
this.cam.keysLeft = [81]; // Q
this.cam.keysRight = [68]; // D
this.cam.speed = v;
this.cam.ellipsoid = new BABYLON.Vector3(1, h, 1);
this.cam.angularSensibility = a;
And it works, i have a camera, i can move around ect ...
But my problem is here : by default they are a smooth animation when a move and when i change the orientation of the camera.
Let me explain : When i move with my arrow keys (aproximately 20 pixels to the left) it will go to 25 pixels (20 pixels + 5 smooths pixels).
I don't want it :/ Do you know how o disable it ? (To move and change orientation of the camera).
This is due to the inertia defined in the free camera.
To remove this "smooth" movements, simply disable inertia:
this.cam.inertia = 0;
I'm trying to make a camera rotation and zoom around a point.
I don't want to use THREE.TrackBallControls because as i see, it only modify the fov when zooming, it is not what i want.
I'm using this simple equation : http://en.wikipedia.org/wiki/Sphere#Equations_in. To compute a point on the sphere, this point will be the position of the camera.
In three.js
var point = new THREE.Vector3(
radius * Math.cos(theta) * Math.sin(phi),
radius * Math.sin(theta) * Math.sin(phi),
radius * Math.cos(phi)
);
point.add(center);
To manipulate it, i use :
left mouse, for rotation : x coord === theta and y coord === phi
middle mouse, for zooming : zoom in/out === radius
It doesn't work well, especially for 'phi' rotation, maybe because it's define between 0 and PI.
Maybe there is a better solution using Quaternion.Slerp ?
edit :
My camera :
aspectRatio = container.offsetWidth / container.offsetHeight;
camera = new THREE.OrthographicCamera( -aspectRatio * viewSize / 2, aspectRatio * viewSize / 2, viewSize / 2, -viewSize / 2, -10, 10 );
camera.position.x = 0.004;
camera.position.y = 0.004;
camera.position.z = 0.004;
camera.lookAt(new THREE.Vector3(0, 0, 0))
scene.add(camera);
My OrbitControls :
controls = new THREE.OrbitControls ( camera );
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.keyPanSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
when using left mouse (rotation) the camera.position change.
when using middle mouse (zoom) the camera.position is still the same.
check made in the render function :
function render() {
// update camera controls
controls.update();
console.log(camera.position);
// actually render the scene
renderer.render( scene, camera );
}
EDIT: Solved the issue, see my own answer
Recently I've been working on a 3D world editor that will be using picking to raise or lower terrain. I'm using camera unprojection and ray casting to find the world position of the mouse screen coordinates.
However, it seems like the ray is on the wrong axis. As I remember, the ray that is supposed to come out of unproject should be coming straight from the camera.
Here's an example of what it currently looks like.
My question is, why is the ray over the Y-axis when it's supposed to be over the Z-axis?
XMFLOAT3 D3D11Camera::Unproject(const float& px, const float& py, const float& pz)
{
const XMFLOAT2& res = D3D11RenderSettings::Instance()->resolution();
XMVECTOR coords = XMVector3Unproject(XMVectorSet(px, res.y - py, pz, 0.0f), 0.0f, 0.0f, res.x, res.y, near_plane_, far_plane_, projection_, view_, XMMatrixIdentity());
XMFLOAT3 to_ret;
XMStoreFloat3(&to_ret, coords);
return to_ret;
}
This is the unprojection code..
And this is how I'm using it
projectRay: function()
{
var p = Mouse.position(MousePosition.Relative);
p.x = (p.x + RenderSettings.resolution().w / 2);
p.y = (p.y + RenderSettings.resolution().h / 2);
var unprojA = this._camera.unproject(p.x, p.y, 0);
var unprojB = this._camera.unproject(p.x, p.y, 1);
var dir = Vector3D.normalise(Vector3D.sub(unprojB, unprojA));
var ray = Ray.construct(unprojA, dir);
var p1 = ray.origin;
var p2 = Vector3D.add(ray.origin, Vector3D.mul(ray.direction, 1000));
RenderTargets.ui.drawLine(p1.x, p1.y, p1.z, 1, 0, 0, p2.x, p2.y, p2.z, 1, 0, 0);
return ray;
}
Cheers!
Stupidity aside, I'm working with both an inverted Y-axis coordinate system and a default -- non inverted -- one. It seemed like it was a ray oriented vertically, but in fact it was a ray that was oriented in the direction of '/' while it was supposed to be oriented like '\'. Multiplying the Y component of the result by -1 solved the issue.
I want to change the paper(objects base) size of Raphael to fit the window resizing. [ using Firefox_13.0, Raphael_2.1.0, WindowsXP ]
If it is available, I would like to fit full-screen-mode.
==================================================
(steps)
I created the paper : paper = Raphael(0, 50, 800, 600); // initial width and height are 800 and 600.
I placed objects on the paper.
The window size of browser is checked by windowW = window.innerWidth and winnowH = window.innerHeight (on Firefox).
Scaling value is calculated by sv = windowW/800;
And scaling the paper by paper.scale(sv, sv);
==================================================
(the script)
window.onload = function () {
paper = Raphael(0, 50, 800, 600);
var background = paper.rect(0, 0, 800, 600).attr({fill:'#669999'});
// placing the objects
var circle = ...;
var rect = ...;
var ellipse = ...;
winowW = window.innerWidth;
winowH = window.innerHeight;
sv = winowW/800.
paper.scale(sv, sv);
}
==================================================
(result)
Though circle.scale(sv), rect.scale(sv, sv) and ellipse.scale(sv, sv) are valid, paper.scale(sv, sv) and background.scale(sv, sv) are not.
Why this case is happen ? I can get the window size by window.onresize = function() {...} on real-time. If there are better methods, please tell me.
Thanks,
I've succeeded by following two points:
1) "paper" itself is not manipulative object. I think we should look it as billboard.
2) use st = paper.set() and put the objects(circle, rect, ...) in it. And use st.scale(sv, sv, 0, 0);
* third and fourth parameter (0, 0) are very impotent.
(caution)
Serial resizing operation is not good for the function "scale()". Because each of resizing coefficient is piled as the
power of a number. So when one have done 1.1 times resizing operation 5 times, the scale will be 1.1^5.
Use setViewBox()
It should do the work
http://raphaeljs.com/reference.html#Paper.setViewBox