I made a 3D scene where I have three groups of models. I have a camera which is looking at one of those groups.
Models in these groups rotate around the group center (Up axis), and models also rotate their own local center (Up axis).
This is similar to XNA Racing Game car selection screen.
Only difference is that I want to be able to rotate my camera to look at another group.
When rotating camera to look at next group I want to rotate it 120 degrees (I have 3 model groups 360/3=120)
NOTE:
- camera is looking at a group from slightly above the group's plane.
for camera:
viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspectRatio, 1f, 1000f);
OK:
I can rotate model around its own axis.
I can rotate group of models left or right around the group center point
(in game screen, closest model to the screen is the one currently selected).
Not OK:
I cannot find correct way to rotate camera around it's own Up axis.
Couple of images to clarify this situation:
It looks to me like you want all your rotations to be about the world up axis rather than the camera's up axis.
here's a possible way to change the view from one group to another. This will rotate at a constant rate. If you want it the rotation to slow a little as it arrives at the desired group, addition code is required. This assumes you know the center position of each group.
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
float rotationRate = 0.01f; //radians per second. set to taste
Vector3 cameraGoal;// the center point of the group that you want the camera to settle on. changes with input.
Vector3 currentLookingDirection = cameraTarget - cameraPosition;//
Vector3 desiredLookingDirection = cameraGoal - cameraPosition;
float angularSeparationFactor = Vector3.Dot(currentLookingDirection, desiredLookingDirection);
if(angularSeparationFactor < 0.98f);//set to taste
{
float directionToRotate = Math.Sign(Vector3.Cross(currentLookingDirection , desiredLookingDirection ).Y);
cameraTarget = Vector3.Transform(cameraTarget - cameraPosition, Matrix.CreateRotationY(rotationRate * elapsed * directionToRotate)) + cameraPosition;
}
else
{
cameraTarget = cameraGoal;
}
view = Matrix.CreatLookAt(cameraPosition, cameraTarget, Vector3.Up);
Related
Even after hours of googling, I can't really get my head around this. Maybe somebody here can help me a bit with this.
I basically want to determine the Y-rotation of an object (that is always in the viewport's center), relative to my camera. Imagine the object standing on the center of a record player/turntable, that slowly rotates around its Y axis, and my camera always facing the center of that object while using OrbitControls to change the cam's position around the object. Imagine the camera not moving, but the turntable turning, one revolution equals this Y rotation to be between 0° and 360°.
For example, this Y rotation would be:
0° when cam's position is [x=0, y=0, z=100], or [x=0, y=100, z=200] (the cam's y position doesn't matter, it always looks down/up to the group's center),
45° when cam's position is [x=100, y=0, z=100] or [x=100, y=200, z=100],
90° when cam's position is [x=100, y=0, z=0] or [x=200, y=100, z=0], etc.
Thing is, both of these can have some pretty random positions & rotations in the world coordinate system, so it's not given that the object's position is [x=0, y=0, z=0].
Any ideas? Thanks a lot!
I'm not sure if I'm being helpful, but perhaps Object3D.getWorldQuaternion and Quaternion.angleTo() might help?
something like :
const cameraQuaternion = new THREE.Quaternion();
camera.getWorldQuaternion(cameraQuaternion);
const targetQuaternion = new THREE.Quaternion();
target.getWorldQuaternion(targetQuaternion);
const delta = cameraQuaternion.angleTo(targetQuaternion);
const euler = new THREE.Euler().setFromQuaternion(delta);
console.log(euler.y / Math.PI * 180);
I have this code in Threejs where I have a cone and a sphere being children to an Object3D named "sphereGroup"
inside my animate function I have the following
sphere.position.x = -4;
cone.position.x= 3 ;
sphereGroup.rotation.y -= 2* angle ;
when this runs I see that the cone and sphere both rotate both around their axis AND the group center. why does this behavior happen ?
see here : http://ahmedfathishaban.herokuapp.com/index.html
I read that the order is always (TRS)parent * (TRS)child
in my case it will minimize to : R(parent) * T(child) => Translate the cone from the group center then rotate the whole group around the group center.
So I understand the cone (or sphere) needs to rotate around the group center, without spinning around its own axis, What Am I missing ?
So I have one point in 3D space, and I have location and rotation of the Camera in 3D space.
So basically there is Vector3 on the object.
Camera Vector3 and Quaternion.
I need to get how to look at that point.
I want to tell user how to move to that point.
Should user direct camera left or right or behind?
One way to do this is to calculate the direction the camera is currently facing as a yaw angle (like a compass heading), and calculate the direction it needs to face in order to be looking at the point.
Subtract one from the other and adjust the result so that it is in the range of -180 to 180 degrees (or -pi to pi radians) and then tell the user to turn left or right based on the sign. If the absolute value is more than 120 degrees (or some configurable value) then tell them it is behind them.
To find the camera's current heading, transform the vector (0, 0, 1) by the quaternion to get the forward vector, then calculate the heading using atan2(forward.z, forward.x).
To calculate the heading required to look at the point, subtract the current camera position from the point to get a desired forward vector and then pass to atan:
Vector3 desired_forward = point - camera_pos;
float desired_heading = atan2(desired_forward.z, desired_forward.x);
Then find the rotation needed:
float rotation_needed = desired_heading - heading;
if(rotation_needed > Math.PI)
rotation_needed -= 2 * Math.PI;
if(rotation_needed < -Math.PI)
rotation_needed += 2 * Math.PI;
Now tell the user to rotate left or right based on the sign of the rotation needed.
If you want to do it for look up/down, you can calculate a pitch angle by first calculating the length of the forward vector in the XZ plane and then using atan2 again:
float xzLength = sqrt(forward.x * forward.x + forward.z * forward.z);
float pitch_angle = atan2(forward.y, xzLength);
Do the same for the desired forward vector and subtract the current from the desired. Check the sign to tell the user whether to look up or down.
There's a few likely complications. For example, depending on whether the camera quaternion specifies the transform from world space to camera space or vice versa, you might need to negate the calculated camera heading.
I'm about to project image into cylindrical panorama. But first I need to get the pixel (or color from pixel) I'm going to draw, then then do some Math in shaders with polar coordinates to get new position of pixel and then finally draw pixel.
Using this way I'll be able to change shape of image from polygon shape to whatever I want.
But I cannot find anything about this method (get pixel first, then do the Math and get new position for pixel).
Is there something like this, please?
OpenGL historically doesn't work that way around; it forward renders — from geometry to pixels — rather than backwards — from pixel to geometry.
The most natural way to achieve what you want to do is to calculate texture coordinates based on geometry, then render as usual. For a cylindrical mapping:
establish a mapping from cylindrical coordinates to texture coordinates;
with your actual geometry, imagine it placed within the cylinder, then from each vertex proceed along the normal until you intersect the cylinder. Use that location to determine the texture coordinate for the original vertex.
The latter is most easily and conveniently done within your geometry shader; it's a simple ray intersection test, with attributes therefore being only vertex location and vertex normal, and texture location being a varying that is calculated purely from the location and normal.
Extemporaneously, something like:
// get intersection as if ray hits the circular region of the cylinder,
// i.e. where |(position + n*normal).xy| = 1
float planarLengthOfPosition = length(position.xy);
float planarLengthOfNormal = length(normal.xy);
float planarDistanceToPerimeter = 1.0 - planarLengthOfNormal;
vec3 circularIntersection = position +
(planarDistanceToPerimeter/planarLengthOfNormal)*normal;
// get intersection as if ray hits the bottom or top of the cylinder,
// i.e. where |(position + n*normal).z| = 1
float linearLengthOfPosition = abs(position.z);
float linearLengthOfNormal = abs(normal.z);
float linearDistanceToEdge = 1.0 - linearLengthOfPosition;
vec3 endIntersection = position +
(linearDistanceToEdge/linearLengthOfNormal)*normal;
// pick whichever of those was lesser
vec3 cylindricalIntersection = mix(circularIntersection,
endIntersection,
step(linearDistanceToEdge,
planarDistanceToPerimeter));
// ... do something to map cylindrical intersection to texture coordinates ...
textureCoordinateVarying =
coordinateFromCylindricalPosition(cylindricalIntersection);
With a common implementation of coordinateFromCylindricalPosition possibly being simply return vec2(atan(cylindricalIntersection.y, cylindricalIntersection.x) / 6.28318530717959, cylindricalIntersection.z * 0.5);.
I have a scene in Three.js (r67) with a camera that is controlled by OrbitControls.
If I now select an arbitrary point (Vector3) in the scene, what would be the best way to bring this point (programmatically) to the nearest camera position just by rotating the camera?
Example Scenario
In the below picture the left side is the starting point. The camera rotates around the green sphere (like OrbitControls) where the center of the camera is the center of the sphere. I now like to automatically rotate the camera around the sphere (doing the minimum amount of moves) so that the red box is nearest to the camera (like on the right side).
Independntly to the method of selecting the point in the scene, there's several understanding to what you mean by "bringing camera just by rotating".
I suppose, You want to rotate the camera in the way, to make the selected point in the center of the screen.
This is simple:
camera.lookAt(your_point_in_scene);
You could do this more complicated. Firstly, find the current pointing vector. By default camera looks in direction Vector(0,0,1). When we rotate it in the same rotation as a camera, we will have camera direction:
var vec = new THREE.Vector3(0,0,1);
vec.applyQuaternion(camera.rotation._quaternion);
Now we must determine angle to rotate our camera, and axis, around which we would rotate.
Axis of rotation could be found as a cross product of camera direction and vector from camera to object. Angel could be extracted from dot product:
var object_dir = object_world_point.clone().sub(camera.position);
var axis = vec.clone().crossProduct(object_dir);
var angle = Math.acos( vec.clone().dot(object_dir) / vec.length() / object_dir.length());
Having angle and axis, we could rotate camera:
camera.rotateOnAxis(axis, angle);
Or, if you want to make it smooth:
// before animation started
var total_rotation = 0,
rotateon,
avel = 0.01; // 0.01 radian per second
if(total_rotation < angle){
rotateon = avel * time_delta;
camera.rotateOnAxis(axis, angle);
total_rotation += rotateon;
}
Well that's not hard Oo
You have a center/target point for the camera. You calculate the difference from the target position to the point position and normalize that vector to the length of the camera-centerpoint-distance (i.e. something like pointdistance.multiplyScalar(cameradistance.length() / pointdistance.length()) ).
And that's it. If I understood your question correctly. All you do is "extend" the point's positioni onto your "camera movement dome" and then you have the ideal new camera position. The camera's rotation is done automatic since you always target the center point.
Aaand if you want to smoothen the camera movement a bit you can just interpolate the angle (not the positions directly) with e.g. an exponential function, whatever you prefer.
Hi Dear please follow this
Independntly to the method of selecting the point in the scene, there's several understanding to what you mean by "bringing camera just by rotating".
I suppose, You want to rotate the camera in the way, to make the selected point in the center of the screen.
This is simple:
camera.lookAt(your_point_in_scene);
You could do this more complicated. Firstly, find the current pointing vector. By default camera looks in direction Vector(0,0,1). When we rotate it in the same rotation as a camera, we will have camera direction:
var vec = new THREE.Vector3(0,0,1);
vec.applyQuaternion(camera.rotation._quaternion);
Now we must determine angle to rotate our camera, and axis, around which we would rotate.
Axis of rotation could be found as a cross product of camera direction and vector from camera to object.
Angle could be extracted from dot product:
var object_dir = object_world_point.clone().sub(camera.position);
var axis = vec.clone().crossProduct(object_dir);
var angle = Math.acos( vec.clone().dot(object_dir) / vec.length() / object_dir.length());