Finding the direction in which the camera faces - aframe

I am able to get the current position the camera is in, i.e, its x,y,z co-ordinates in aframe.
In the below code, I am making my camera move forward.
function move_camera_forward(){
x=$("#cam").attr("position").x;
y=$("#cam").attr("position").y;
z=$("#cam").attr("position").z;
updated_pos=x+" "+y+" "+String(Number(z)-0.2);
$("#cam").attr("position",updated_pos);
}
But this moves the camera along z axis irrespective the direction the camera is facing. I want to move the camera based on the direction faced by the camera. If the camera is facing lets say 45 degrees, I want to update the three co-ordinates. For this I need to find out in which direction the camera is facing. How can I do this? Does it have something to do with fov?

I finally figured out how to do this. camera has a rotation attribute which gives me the angle of rotation. With this data and a bit of trigonometry, we can find the updated position. The below code moves the camera in the direction in which the user sees.
new_x = 0;
new_z = 0;
function move_camera_forward() {
x = $("#cam").attr("position").x;
y = $("#cam").attr("position").y;
z = $("#cam").attr("position").z;
radian = -($("#cam").attr("rotation").y) * (Math.PI / 180);
new_z = (new_z + (0.1 * Math.cos(radian)));
new_x = new_x + (0.1 * Math.sin(radian));
new_pos = new_x + " " + y + " " + (-new_z);
console.log(new_pos)
$("#cam").attr("position", new_pos)
}

You can dive into the Three.js API to get any additional info that Aframe doesn't necessarily bubble to the surface. So you can get the camera object using
var camera = document.querySelector('[camera]').object3D
and then you have access to all the Vector data for the camera. To get the direction the camera is facing you can use camera.getWorldDirection() and that returns a Vector3 with X,Y and Z values.

Related

How to convert from Equirectangular Projection Coordinates to 3D coordinates

I use the following code to get equirectangular texture coordinates based on an object's position in the world:
Equirec(positionX, positionY, positionZ) {
radius = sqrt(positionX^2 + positionZ^2);
a = atan2(-positionX, positionZ);
b = atan2(positionY, radius);
uv.x = (a - pi) / -2pi;
uv.y = (b + pi/2) / pi;
return uv;
}
Is it possible to invert this function?
What I want to do is, given the uv coordinates returned from this function, figure out the corresponding position in the world.
Not possible. You have thrown away information. The UV coordinates are within a single plane. If you knew the location of that plane in 3D space, you could do it.

Rotate 3D vectors on 2D plane

I have two Vec3s, Camera Forward and Turret Forward. Both of these vectors are on different planes where Camera Forward is based on a free-look camera and Turret Forward is determined by the tank it sits on, the terrain the tank is on, etc. Turret Up and Camera Up are rarely ever going to match.
My issue is as follows: I want the turret to be able to rotate using a fixed velocity (44 degrees per second) so that it always converges with the direction that the camera is pointed. If the tank is at a weird angle where it simply cannot converge with the camera, it should find the closest place and sit there instead of jitter around indefinitely.
I cannot for the life of me seem to solve this problem. I've tried several methods I found online that always produce weird results.
local forward = player.direction:rotate(player.turret, player.up)
local side = forward:cross(player.up)
local projection = self.camera.direction:dot(forward) * forward + self.camera.direction:dot(side) * side
local angle = math.atan2(forward.y, forward.x) - math.atan2(projection.y, projection.x)
if angle ~= 0 then
local dt = love.timer.getDelta()
if angle <= turret_speed * dt then
player.turret_velocity = turret_speed
elseif angle >= -turret_speed * dt then
player.turret_velocity = -turret_speed
else
player.turret_velocity = 0
player.turret = player.turret + angle
end
end
I would do it differently
obtain camera direction vector c in GCS (global coordinate system)
I use Z axis as viewing axis so just extract z axis from transform matrix
for more info look here understanding transform matrices
obtain turret direction vector t in GCS
the same as bullet 1.
compute rotated turret direction vectors in booth directions
t0=rotation(-44.0deg/s)*t
t1=rotation(+44.0deg/s)*t
now compute the dot products
a =dot(c,t)
a0=dot(c,t0)
a1=dot(c,t1)
determine turret rotation
if max(a0,a,a1)==a0 rotate(-44.0deg/s)`
if max(a0,a,a1)==a1 rotate(+44.0deg/s)`
[Notes]
this should converge to desired direction
the angle step should be resized to match the time interval used for update this
you can use any common coordinate system for bullets 1,2 not just GCS
in this case the dot product is cos(angle between vectors) because both c,t are unit vectors (if taken from standard transform matrix)
so if cos(angle)==1 then the directions are the same
but your camera can be rotated in different axis so just find the maximum of cos(angle)
After some more research and testing, I ended up with the following solution. It works swimmingly!
function Gameplay:moved_axisright(joystick, x, y)
if not self.manager.id then return end
local turret_speed = math.rad(44)
local stick = cpml.vec2(-x, -y)
local player = self.players[self.manager.id]
-- Mouse and axis control camera view
self.camera:rotateXY(stick.x * 18, stick.y * 9)
-- Get angle between Camera Forward and Turret Forward
local fwd = cpml.vec2(0, 1):rotate(player.orientation.z + player.turret)
local cam = cpml.vec2(1, 0):rotate(math.atan2(self.camera.direction.y, self.camera.direction.x))
local angle = fwd:angle_to(cam)
-- If the turret is not true, adjust it
if math.abs(angle) > 0 then
local function new_angle(direction)
local dt = love.timer.getDelta()
local velocity = direction * turret_speed * dt
return cpml.vec2(0, 1):rotate(player.orientation.z + player.turret + velocity):angle_to(cam)
end
-- Rotate turret into the correct direction
if new_angle(1) < 0 then
player.turret_velocity = turret_speed
elseif new_angle(-1) > 0 then
player.turret_velocity = -turret_speed
else
-- If rotating the turret a full frame will overshoot, set turret to camera position
-- atan2 starts from the left and we need to also add half a rotation. subtract player orientation to convert to local space.
player.turret = math.atan2(self.camera.direction.y, self.camera.direction.x) + (math.pi * 1.5) - player.orientation.z
player.turret_velocity = 0
end
end
local direction = cpml.mat4():rotate(player.turret, { 0, 0, 1 }) * cpml.mat4():rotate(player.orientation.z, { 0, 0, 1 })
player.turret_direction = cpml.vec3(direction * { 0, 1, 0, 1 })
end

Perspective projection - help me duplicate blender's default scene

I'm currently attempting to teach myself perspective projection, my reference is the wikipedia page on the subject here: http://en.wikipedia.org/wiki/3D_projection#cite_note-3
My understanding is that you take your object to be project it and rotate and translate it in to "camera space", such that your camera is now assumed to be origin looking directly down the z axis. (This matrix op from the wikipedia page: http://upload.wikimedia.org/math/5/1/c/51c6a530c7bdd83ed129f7c3f0ff6637.png)
You then project your new points in to 2D space using this equation: http://upload.wikimedia.org/math/6/8/c/68cb8ee3a483cc4e7ee6553ce58b18ac.png
The first step I can do flawlessly. Granted I wrote my own matrix library to do it, but I verified it was spitting out the right answer by typing the results in to blender and moving the camera to 0,0,0 and checking it renders the same as the default scene.
However, the projection part is where it all goes wrong.
From what I can see, I ought to be taking the field of view, which by default in blender is 28.842 degrees, and using it to calculate the value wikipedia calls ez, by doing
ez = 1 / tan(fov / 2);
which is approximately 3.88 in this case.
I should then for every point be doing:
x = (ez / dz) * dx;
y = (ez / dz) * dy;
to get x and y coordinates in the range of -1 to 1 which I can then scale appropriately for the screen width.
However, when I do that my projected image is mirrored in the x axis and in any case doesn't match with the cube blender renders. What am I doing wrong, and what should I be doing to get the right projected coordinates?
I'm aware that you can do this whole thing with one matrix op, but for the moment I'm just trying to understand the equations, so please just stick to the question asked.
From what you say in your question it's unclear whether you're having trouble with the Projection matrix or the Model matrix.
Like I said in my comments, you can Google glFrustum and gluLookAt to see exactly what these matrices look like. If you're familiar with matrix math (and it looks like you are), you will then understand how the coordinates are transformed into a 2D perspective.
Here is some sample OpenGL code to make the View and Projection Matrices and Model matrix for a simple 30 degree rotation about the Y axis so you can see how the components that go into these matrices are calculated.
// The Projection Matrix
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
near = -camera.viewPos.z - shapeSize * 0.5;
if (near < 0.00001)
near = 0.00001;
far = -camera.viewPos.z + shapeSize * 0.5;
if (far < 1.0)
far = 1.0;
radians = 0.0174532925 * camera.aperture / 2; // half aperture degrees to radians
wd2 = near * tan(radians);
ratio = camera.viewWidth / (float) camera.viewHeight;
if (ratio >= 1.0) {
left = -ratio * wd2;
right = ratio * wd2;
top = wd2;
bottom = -wd2;
} else {
left = -wd2;
right = wd2;
top = wd2 / ratio;
bottom = -wd2 / ratio;
}
glFrustum (left, right, bottom, top, near, far);
// The View Matrix
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
gluLookAt (camera.viewPos.x, camera.viewPos.y, camera.viewPos.z,
camera.viewPos.x + camera.viewDir.x,
camera.viewPos.y + camera.viewDir.y,
camera.viewPos.z + camera.viewDir.z,
camera.viewUp.x, camera.viewUp.y ,camera.viewUp.z);
// The Model Matrix
glRotatef (30.0, 0.0, 1.0, 0.0);
You'll see that glRotate actually does a quaternion rotation (angle of rotation plus a vector about which to do the rotation).
You could also do separate rotations about the X, Y and Z axis.
There's lot's of information on the web about how to form 4X4 matrices for rotations, translations and scales. If you do each of these separately, you'll need to multiply them to get the Model matrix. e.g:
If you have 4X4 matrices rotateX, rotateY, rotateZ, translate, scale, you might form your Model matrix by:
Model = scale * rotateX * rotateZ * rotateY * translate.
Order matters when you form the Model matrix. You'll get different results if you do the multiplication in a different order.
If your object is at the origin, I doubt you want to also put the camera at the origin.

Convert Cartesian point to point on rotated plane (pic)

I have a cartesian point that I am being given (blue line), and I need to convert it to a point relative to a rotated plane (green box). The plane is rotated at 28.227ยบ as shown below.
Sadly, my lack of math education has me completely baffled as to how to solve this. I need to be able to take any x,y point and convert it for the rotated plane.
Any help at all on this would be greatly appreciated as I am at a total loss.
Best I can figure out, I will need several different calculations depending on where the input point is.
(source: adam-meyer.com)
I love friends who know math. Thanks KJ!
Here is the answer.
function convertPoint(x,y){
var degree = -28.227;
var offset = 0; //change if your corner is not 0,0
x2 = x *Math.cos(radians(degree)) + (y - offset) *Math.sin(radians(degree));
y2 = x *Math.sin(radians(degree)) - (y - offset) *Math.cos(radians(degree));
return {x: x2, y: y2}
}
function radians(degrees){
return degrees * (Math.PI / 180);
}

Calculation of the position of an object moving in a circular motion in 3D

i have an object that is doing a circular motion in a 3d space, the center or the circle is at x:0,y:0,z:0 the radius is a variable. i know where the object is on the circle (by its angle [lets call that ar] or by the distance it has moved). the circle can be tilted in all 3 directions, so i got three variables for angles, lets call them ax,ay and az. now i need to calculate where exactly the object is in space. i need its x,y and z coordinates.
float radius = someValue;
float ax = someValue;
float ay = someValue;
float az = someValue;
float ar = someValue; //this is representing the angle of the object on circle
//what i need to know
object.x = ?;
object.y = ?;
object.z = ?;
You need to provide more information to get the exact formula. The answer depends on which order you apply your rotations, which direction you are rotating in, and what the starting orientation of your circle is. Also, it will be much easier to calculate the position of the object considering one rotation at a time.
So, where is your object if all rotations are 0?
Let's assume it's at (r,0,0).
The pseudo-code will be something like:
pos0 = (r,0,0)
pos1 = pos0, rotated around Z-axis by ar (may not be Z-axis!)
pos2 = pos1, rotated around Z-axis by az
pos3 = pos2, rotated around Y-axis by ay
pos4 = pos3, rotated around X-axis by ax
pos4 will be the position of your object, if everything is set up right. If you have trouble setting it up, try keeping ax=ay=az=0 and worry about just ar, until your get that right. Then, start setting the other angles one at a time and updating your formula.
Each rotation can be performed with
x' = x * cos(angle) - y * sin(angle)
y' = y * cos(angle) + x * sin(angle)
This is rotation on the Z-axis. To rotate on the Y-axis, use z and x instead of x and y, etc. Also, note that angle is in radians here. You may need to make angle negative for some of the rotations (depending which direction ar, ax, ay, az are).
You can also accomplish this rotation with matrix multiplication, like Marcelo said, but that may be overkill for your project.
Use a rotation matrix. Make sure you use a unit vector.

Resources