3D Vector (X, Y, Z) look at Vector - c++

Im working with the source sdk (Which uses c++) and I want to rotate a entity's angle so it looks at another entity.
A entity can be looked at as a gameobject or similar and has a position (Vector) in the world as well as a angle (Vector).
I can rotate the entity by using SetAbsAngles which takes a QAngle (Basically a Vector) as parameter.

Here is some pseudo-code:
vec3 p = entity2->getPosition();
vec3 r = entity1->getPosition();
float xdistance = p[0] - r[0];
float ydistance = p[1] - r[1];
float zdistance = p[2] - r[2];
float xzdistance = sqrt(xdistance * xdistance + zdistance * zdistance);
entitity1->setHeading(atan2(xdistance, zdistance)); // rotation around y
entitity1->setPitch(-atan2(ydistance, xzdistance)); // rotation around x
entitity1->setBank(0); // rotation around z
The z-rotation is set to 0 because it cannot be determined. You can set it freely if you like.
This works in a coordinate system with z facing forward, y up and x to the right. If you are using a different system you may have to adjust some signs.

Related

Path tracing: how to ensure the new direction vector is a valid direction vector with respect to a BSDF?

Given the BSDF function and the Normal vector of the intersection point in world space, how can I generate a new direction vector wi that is valid? Does the method for generating valid wis change based on the BSDF?
Here's an example of what I'm thinking to do for ideal diffuse material the BSDF: I generate a new direction vector wi as points on a unit hemisphere as follow and then compute the dot product of the produced vector with the Normal vector. If the dot product result is positive the direction vector wi is valid. Otherwise I negate wi as suggested here.
Here's how I get a random wi:
float theta = 2 * M_PI * uniform01(generator);
float phi = acos(uniform01(generator));
float x = sin(phi) * cos(theta);
float y = sin(phi) * sin(theta);
float z = cos(phi);
Vector3f wi(x, y, z);
if (dot(wi, Normal) > 0){
return wi;
}
else{
return -wi;
}
However, this doesn't seem to be the right approach based on a conversation I had with someone recently. Apparently the new direction vector produced this way is somehow not in the right space (not sure whether it was world or object space) and could only work if my material is ideal diffuse. So I will have to apply some transformations in order to be able to get the right wi. Is this correct? If so, can someone provide a solution that includes doing such transformation? Also, is there a general way to ensure all of my produced wis are valid with respect to the BSDF (not just ideal diffuse)?
You are generating your wi in tangent space, with z pointing along the normal. It is neither world nor object space, and you will have to transform into world space or do all your calculations in tangent space (or shading space, they're both the same).
What you should be doing, as it will make your life much easier when doing other calculations, is to transform your wo to tangent space, and do all calculations in it. Over here, you would choose z to be your normal, and generate x and y vectors orthogonal to it.
A function for generating the coordinate system like this would be:
void GenerateCoordinateSystem(const Vector& normalized, Vector& outFirst, Vector& outSecond)
{
if (std::abs(normalized.x) > std::abs(normalized.y))
{
outFirst = Vector(-normalized.z, 0, normalized.x) /
std::sqrt(normalized.x * normalized.x + normalized.z * normalized.z);
}
else
{
outFirst = Vector(0, normalized.z, -normalized.y) /
std::sqrt(normalized.z * normalized.z + normalized.y * normalized.y);
}
outSecond = Cross(normalized, outFirst);
}
Where normalized is the normal (z vector) at the point, and outFirst and outSecond are your x and y vectors respectively.
Now that you have your tangent space vectors, you transform into them by (wo is in object space):
Vector x, y;
GenerateCoordinateSystem(normal, x, y);
Vector tangentWo = Vector(Dot(wo, x), Dot(wo, y), Dot(wo, normal));
You would then generate your wi as you do above.
Then, to get wi in object space, you would:
Vector objWi = wi.X * x + wi.Y * y + wi.Z * normal;
If you want them in world space, you would obviously have to multiply them by the object's transformation matrix.
Uniform hemisphere sampling does ensure that your wi is valid for any BSDF, however, you have to ensure that the pdf for the BSDF takes into account the distribution.

Issues with rotation matrix

I'm currently working on the intermediates between a physics engine and a rendering engine. My physics engine takes in a series of forces and positions and returns a quaternion.
I am currently converting that quaternion into a rotation matrix using the answers to my previous question (which is working fine). My co-ordinate system is z - into the screen, y - up, and x - right.
Now after all that exposition, I have been testing via rotating a single axis at a time. I can rotate about the y axis and z axis without any issues what so ever. However, when i attempt to rotate around the z axis the system is producing a bizarre result. The rotation is fine, but as it rotates the object flattens (ie: negatively scales) in the z direction, before "flipping" and returning to full scale. It does so every 90 degrees, at a 45 degree offset to the cardinal directions.
This is my code to convert my quaternion to a rotation matrix:
Matrix4f output = new Matrix4f();
output.setIdentity();
if(input.length()!=0){
input.normalise();
}
float xx = input.x * input.x;
float xy = input.x * input.y;
float xz = input.x * input.z;
float xw = input.x * input.w;
float yy = input.y * input.y ;
float yz = input.y * input.z;
float yw = input.y * input.w;
float zz = input.z * input.z;
float zw = input.z * input.w;
output.m00 = 1 -2*((yy+zz));
output.m01 = 2*(xy+zw);
output.m02 = 2*(xz-yw);
output.m10 = 2*(xy-zw);
output.m11 = 1 - (2*(xx+zz));
output.m12 = 2*(yz+xw);
output.m20 = 2*(xz+yw);
output.m21 = 2*(yz+xw);
output.m22 = 1-(2*(xx+yy));
Now I'm viewing this in real time as the object rotates, and I see nothing that shouldn't be there. Also, this passes untouched from this equation directly to opengl, so it is really beyond me why I should have this issue. Any ideas?
output.m21 = 2*(yz+xw); should be output.m21 = 2*(yz-xw);

Need rotation matrix for opengl 3D transformation

The problem is I have two points in 3D space where y+ is up, x+ is to the right, and z+ is towards you. I want to orientate a cylinder between them that is the length of of the distance between both points, so that both its center ends touch the two points. I got the cylinder to translate to the location at the center of the two points, and I need help coming up with a rotation matrix to apply to the cylinder, so that it is orientated the correct way. My transformation matrix for the entire thing looks like this:
translate(center point) * rotateX(some X degrees) * rotateZ(some Z degrees)
The translation is applied last, that way I can get it to the correct orientation before I translate it.
Here is what I have so far for this:
mat4 getTransformation(vec3 point, vec3 parent)
{
float deltaX = point.x - parent.x;
float deltaY = point.y - parent.y;
float deltaZ = point.z - parent.z;
float yRotation = atan2f(deltaZ, deltaX) * (180.0 / M_PI);
float xRotation = atan2f(deltaZ, deltaY) * (180.0 / M_PI);
float zRotation = atan2f(deltaX, deltaY) * (-180.0 / M_PI);
if(point.y < parent.y)
{
zRotation = atan2f(deltaX, deltaY) * (180.0 / M_PI);
}
vec3 center = vec3((point.x + parent.x)/2.0, (point.y + parent.y)/2.0, (point.z + parent.z)/2.0);
mat4 translation = Translate(center);
return translation * RotateX(xRotation) * RotateZ(zRotation) * Scale(radius, 1, radius) * Scale(0.1, 0.1, 0.1);
}
I tried a solution given down below, but it did not seem to work at all
mat4 getTransformation(vec3 parent, vec3 point)
{
// moves base of cylinder to origin and gives it unit scaling
mat4 scaleFactor = Translate(0, 0.5, 0) * Scale(radius/2.0, 1/2.0, radius/2.0) * cylinderModel;
float length = sqrtf(pow((point.x - parent.x), 2) + pow((point.y - parent.y), 2) + pow((point.z - parent.z), 2));
vec3 direction = normalize(point - parent);
float pitch = acos(direction.y);
float yaw = atan2(direction.z, direction.x);
return Translate(parent) * Scale(length, length, length) * RotateX(pitch) * RotateY(yaw) * scaleFactor;
}
After running the above code I get this:
Every black point is a point with its parent being the point that spawned it (the one before it) I want the branches to fit into the points. Basically I am trying to implement the space colonization algorithm for random tree generation. I got most of it, but I want to map the branches to it so it looks good. I can use GL_LINES just to make a generic connection, but if I get this working it will look so much prettier. The algorithm is explained here.
Here is an image of what I am trying to do (pardon my paint skills)
Well, there's an arbitrary number of rotation matrices satisfying your constraints. But any will do. Instead of trying to figure out a specific rotation, we're just going to write down the matrix directly. Say your cylinder, when no transformation is applied, has its axis along the Z axis. So you have to transform the local space Z axis toward the direction between those two points. I.e. z_t = normalize(p_1 - p_2), where normalize(a) = a / length(a).
Now we just need to make this a full 3 dimensional coordinate base. We start with an arbitrary vector that's not parallel to z_t. Say, one of (1,0,0) or (0,1,0) or (0,0,1); use the scalar product ·(also called inner, or dot product) with z_t and use the vector for which the absolute value is the smallest, let's call this vector u.
In pseudocode:
# Start with (1,0,0)
mindotabs = abs( z_t · (1,0,0) )
minvec = (1,0,0)
for u_ in (0,1,0), (0,0,1):
dotabs = z_t · u_
if dotabs < mindotabs:
mindotabs = dotabs
minvec = u_
u = minvec_
Then you orthogonalize that vector yielding a local y transformation y_t = normalize(u - z_t · u).
Finally create the x transformation by taking the cross product x_t = z_t × y_t
To move the cylinder into place you combine that with a matching translation matrix.
Transformation matrices are effectively just the axes of the space you're "coming from" written down as if seen from the other space. So the resulting matrix, which is the rotation matrix you're looking for is simply the vectors x_t, y_t and z_t side by side as a matrix. OpenGL uses so called homogenuous matrices, so you have to pad it to a 4×4 form using a 0,0,0,1 bottommost row and rightmost column.
That you can load then into OpenGL; if using fixed functio using glMultMatrix to apply the rotation, or if using shader to multiply onto the matrix you're eventually pass to glUniform.
Begin with a unit length cylinder which has one of its ends, which I call C1, at the origin (note that your image indicates that your cylinder has its center at the origin, but you can easily transform that to what I begin with). The other end, which I call C2, is then at (0,1,0).
I'd like to call your two points in world coordinates P1 and P2 and we want to locate C1 on P1 and C2 to P2.
Start with translating the cylinder by P1, which successfully locates C1 to P1.
Then scale the cylinder by distance(P1, P2), since it originally had length 1.
The remaining rotation can be computed using spherical coordinates. If you're not familiar with this type of coordinate system: it's like GPS coordinates: two angles; one around the pole axis (in your case the world's Y-axis) which we typically call yaw, the other one is a pitch angle (in your case the X axis in model space). These two angles can be computed by converting P2-P1 (i.e. the local offset of P2 with respect to P1) into spherical coordinates. First rotate the object with the pitch angle around X, then with yaw around Y.
Something like this will do it (pseudo-code):
Matrix getTransformation(Point P1, Point P2) {
float length = distance(P1, P2);
Point direction = normalize(P2 - P1);
float pitch = acos(direction.y);
float yaw = atan2(direction.z, direction.x);
return translate(P1) * scaleY(length) * rotateX(pitch) * rotateY(yaw);
}
Call the axis of the cylinder A. The second rotation (about X) can't change the angle between A and X, so we have to get that angle right with the first rotation (about Z).
Call the destination vector (the one between the two points) B. Take -acos(BX/BY), and that's the angle of the first rotation.
Take B again, ignore the X component, and look at its projection in the (Y, Z) plane. Take acos(BZ/BY), and that's the angle of the second rotation.

OpenCV Computing Camera Position && Rotation

for a project I need to compute the real world position and orientation of a camera
with respect to a known object.
I have a set of photos, each displays a chessboard from different points of view.
Using CalibrateCamera and solvePnP I am able to reproject Points in 2d, to get a AR-thing.
So my situation is as such:
Intrinsic parameters are known
Distortioncoefficients are known
translation Vector and rotation Vector are known per photo.
I simply cannot figure out how to compute the position of the camera. My guess was:
invert translation vector. (=t')
transform rotation vector to degree (seems to be radian) and invert
use rodriguez on rotation vector
compute RotationMatrix * t'
But the results are somehow totally off...
Basically I want to to compute a ray for each pixel in world coordinates.
If more informations on my problem are needed, I'd be glad to answer quickly.
I dont' get it... somehow the rays are still off. This is my Code btw:
Mat image1CamPos = tvecs[0].clone(); //From calibrateCamera
Mat rot = rvecs[0].clone(); //From calibrateCamera
Rodrigues(rot, rot);
rot = rot.t();
//Position of Camera
Mat pos = rot * image1CamPos;
//Ray-Normal (( (double)mk[i][k].x) are known image-points)
float x = (( (double)mk[i][0].x) / fx) - (cx / fx);
float y = (( (double)mk[i][0].y) / fy) - (cy / fy);
float z = 1;
float mag = sqrt(x*x + y*y + z*z);
x /= mag;
y /= mag;
z /= mag;
Mat unit(3, 1, CV_64F);
unit.at<double>(0, 0) = x;
unit.at<double>(1, 0) = y;
unit.at<double>(2, 0) = z;
//Rotation of Ray
Mat rot = stof1 * unit;
But when plotting this, the rays are off :/
The translation t (3x1 vector) and rotation R (3x3 matrix) of an object with respect to the camera equals the coordinate transformation from object into camera space, which is given by:
v' = R * v + t
The inversion of the rotation matrix is simply the transposed:
R^-1 = R^T
Knowing this, you can easily resolve the transformation (first eq.) to v:
v = R^T * v' - R^T * t
This is the transformation from camera into object space, i.e., the position of the camera with respect to the object (rotation = R^T and translation = -R^T * t).
You can simply get a 4x4 homogeneous transformation matrix from this:
T = ( R^T -R^T * t )
( 0 1 )
If you now have any point in camera coordinates, you can transform it into object coordiantes:
p' = T * (x, y, z, 1)^T
So, if you'd like to project a ray from a pixel with coordinates (a,b) (probably you will need to define the center of the image, i.e. the principal point as reported by CalibrateCamera, as (0,0)) -- let that pixel be P = (a,b)^T. Its 3D coordinates in camera space are then P_3D = (a,b,0)^T. Let's project a ray 100 pixel in positive z-direction, i.e. to the point Q_3D = (a,b,100)^T. All you need to do is transform both 3D coordinates into the object coordinate system using the transformation matrix T and you should be able to draw a line between both points in object space. However, make sure that you don't confuse units: CalibrateCamera will report pixel values while your object coordinate system might be defined in, e.g., cm or mm.

How to orbit around the Z-axis in 3D

I'm primarily a Flash AS3 dev, but I'm jumping into openframeworks and having trouble using 3D (these examples are in AS)
In 2D you can simulate an object orbiting a point by using Math.Sin() and Math.cos(), like so
function update(event:Event):void
{
dot.x = xCenter + Math.cos(angle*Math.PI/180) * range;
dot.y = yCenter + Math.sin(angle*Math.PI/180) * range;
angle+=speed;
}
I am wondering how I would translate this into a 3D orbit, if I wanted to also orbit in the third dimension.
function update(event:Event):void
{
...
dot.z = zCenter + Math.sin(angle*Math.PI/180) * range;
// is this valid?
}
An help is greatly appreciated.
If you are orbiting around the z-axis, you are leaving your z-coordinate fixed and changing your x- and y-coordinates. So your first code sample is what you are looking for.
To rotate around the x-axis (or y-axes), just replace x (or y) with z. Use Cos on whichever axis you want to be 0-degrees; the choice is arbitrary.
If what you actually want is to orbit an object around a point in 3d-space, you'll need two angles to describe the orbit: its elevation angle and its inclination angle. See here and here.
For reference, those equations are (where θ and φ are your angles)
x = x0 + r sin(θ) cos(φ)
y = y0 + r sin(θ) sin(φ)
z = z0 + r cos(θ)
If you are orbiting around Z axis, then you just do your first code, and leave Z coordinate as is.
I would pick two unit perpendicular vectors v, w that define the plane in which to orbit, then loop over the angle and pick the proper ratio of these vectors v and w to build your vector p = av + bw.
More details are coming.
EDIT:
This might be of help
http://en.wikipedia.org/wiki/Orbit_equation
EDIT: I think it is actually
center + sin(angle) * v * radius1 + cos(angle) * w * radius2
Here v and w are your unit vectors for the circle.
In 2D they were (1,0) and (0,1).
In 3D you will need to compute them - depends on orientation of the plane.
If you set radius1 = radius 2, you will get a circle. Otherwise, you should get an ellipse.
If you just want the orbit to happen at an angled plane and don't mind it being elliptic you can just do something like z = 0.2*x + 0.2*y, or any combination you fancy, after you have determined the x and y coordinates.