How to plot two equidistant moving points? - opengl

Imagine a surface which has got 2 points which are moving over the surface (resulting into various lines and curves) while adhering to the following conditions.
These two points are always and always at a constant C distance from each other.
Each point has it's own velocity and direction vector. Of course both these parameters will be restricted based on condition 1.
Ex. if point 1 has 0 velocity and point 2 is moving it will result into a circle like shape with point one being it's center.
I am unable to express these conditions in programming constructs. Can someone help me with that?
I am using OpenGL but even a pseudo code will do for me.

vec3 center;
while(1):
vec3 centerDirection = ...
center += centerDirection
float angle = ...
vec3 dir(cos(angle), 0, sin(angle))
vec3 p1 = center + (C/2) * dir
vec3 p2 = center - (C/2) * dir
draw p1
draw p2
This is a solution where you move the center of a circle and make sure p1 and p2 are two diametrically opposed points
Another solution :
while 1:
p1 += random
p2 += random
delta = p1-p2
delta.normalize()
p2 = p1 + C * delta
i.e you restrain p2, not both points.

In openGL I achieved is as below
PlotTwoPoints(-SPAN,0,+SPAN,0); //two points on x axis
Then I rotated the co-ordinate system and kept on drawing two points at above two locations.
Simple!

Related

Trying to deform any mesh into a sphere. How to translate the vertex position to lie on a sphere?

I am trying to write a deformer script for maya, using the maya API which deforms any mesh into a sphere by translating it's vertices.
What i already have is a deformer which translates every vertex of mesh in the direction of it's normal with the amount specified. This is done using the below equation.
point += normals[itGeo.index()] * bulgeAmount * w * env;
Where, point is the vertex on the mesh. normals[itGeo.index()] is a vector array which represents the normals of each vertex. w and env are to control the weights of the deformation and the envelope.
What this code basically does is, it translates the vertex in the direction of the normal with the amount specified. While this works for a sphere, because a sphere's vertex normals would point at the center. It would not work for other meshes as the normals would not point at the center of the mesh.
float bulgeAmount = data.inputValue(aBulgeAmount).asFloat();
float env = data.inputValue(envelope).asFloat();
MPoint point;
float w;
for (; !itGeo.isDone(); itGeo.next())
{
w = weightValue(data, geomIndex, itGeo.index());
point = itGeo.position();
point += normals[itGeo.index()] * bulgeAmount * w * env;
itGeo.setPosition(point);
}
I initially thought changing the direction of translation would solve the problem. As in, if we can find the vector in the direction from the center of the mesh to each vertex and translate it along that direction for an amount specified would solve it. Like so :
point += (Center - point) * bulgeAmount * w * env;
Where, Center is the center of the mesh. But this does not give the desired result. I also would want the deformer to be setup in such a way that the user can input radius "r" value and can also change the amount attribute from 0 to 1 to deform the mesh from it's original state to a spherical one. So that he can choose a value in between if her desires and the mesh would be something between a sphere and it's original shape.
This is my very first post in stackOverflow. I apologize if the format does not follow the community expectations. Any help on this will be greatly appreciated.
Thank You.
About the direction:
I think your line :
point += (Center - point) * bulgeAmount * w * env;
is a good starting point.
But instead of using (Center - point), you should use its opposite, (point-Center) and normalize it before using it. If you don't use a normalized version of this (point-Center) vector, every vertex will be translated to a wrong position.
About your variation between 0.0 (original) to 1.0 (sphere):
If Po is the original position
If Pf is the final position
If d is the original distance between the point Po and the Center C:
d=norm(Center - point) = norm(C-Po)
If Direction is (Center - point)/d (so normalized, as explained above)
What we want:
At r=0.0 your vertex must stay at its original position: Pf = Center + Direction * d
At r=1.0 your vertex must stick to the sphere of radius R: Pf = Center + Direction * R
And if we generalize:
Pf = C + Direction * ( r*R + (1-r)*d )
With d = norm(C-Po)
Direction = (C-Po)/d
R the radius of your sphere
and r a user param between [0.0; 1.0]
Not sure I am clear enough, I'm not used neither to answer here :)
Best

OpenGl Rotate object on Y axis to look at another object

So like in a topic I got 2 objects one i moving around (on z and x axis) the other one is static but should rotate around y axis to always like a look at the other... and i am fighting with this already a week
what i got now is
vector from 1object to 2object and actual look at(also vector) of the 2object
i'am calculating angel betwean this two vectors and adding this to rotattion.y of the 2 object but its not working properly
any idea how to make it work? btw i'am using eular angel transforms
pseudCode:
vectorFrom1to2 = vector1 - vector2;
lookatVectorof2ndObject;
i normalize both of them and then
float angle = acos(dot(vectorFrom1to2, lookatVectorof2ndObject));
object2.rotateY = angle;
i dont know where i do mistake
As a general rule of thumb, which proved itself true in many situations I observed is: As soon as you find yourself calculating angles from vectors, you are most likely doing something in a more unnecessarily complicated way than necessary.
All you need is a basis transformation which transforms the first object's local coordinate system to make its local Z axis point towards the second object. You can do this with a simple rotation matrix (provided you have a matrix/vector library ready to facilitate this more easily).
So, provided you have object 1 with position p1 and object 2 with position p2 and you want p1 to rotate towards p2, then the rotation matrix can be obtained as follows:
(I am just using GLSL pseudo syntax here)
vec3 p1 = ... // <- position of first object
vec3 p2 = ... // <- position of second object
vec3 d = normalize(p2 - p1)
vec3 r = cross(vec3(0.0, 1.0, 0.0), d)
= vec3(d.z, 0, -d.x)
mat3 m = mat3(d.z, 0, -d.x, // <- first column ('right' vector)
0, 1, 0, // <- second column (keep Y)
d.x, 0, d.z) // <- third column (map Z to point towards p2)
When transforming the vertices v of the first object with m by: v' = m * v you get the Z axis of object p1 to point towards the position of p2, all formulated in the same "world" coordinate system.

3D coordinates interpolation

Let's suppose a square (4 points), viewed from top.
Each of the 4 points do not have the same altimetry.
If you look from top (or from bottom), you see a square, but if you look from side, you will see that the 4 points are not at the same level.
So you have a plane which is not horizontal.
Lets imagine a fifth point inside the square. What i want to do is to calculate the altimetry of this fifth point. This altimetry is a function of the position of the point inside the square, and the altimetry of the 4 points of the square.
I think i have to compute an interpolation but i did not managed to do it...
Any idea ?
Thanks
So unless you know for certain that all points lie on a single plane, which would be a simplification of this method, I'll assume you have divided your square into two triangles. Furthermore, I'll assume there are 4 vertices, v_00, v_10, v_01, and v_11 representing each vertex of your square. I will also assume that your triangles are defined as (v_00, v_10, v_11), and (v_00, v_11, v_01).
vec4 v00 = vec4(...);
vec4 v01 = vec4(...);
vec4 v10 = vec4(...);
vec4 v11 = vec4(---);
vec4[2][3] triangles = {{v00, v10, v11}, {v00, v11, v01}};
Finally, I'll assume you know the X and Y coordinates relative to the bottom left vertex (just subtract the x and y coordinate of your fifth point from the x and y coordinates of v_00). I'll call this point P. We'd like to know its z coorinate.
vec4 fifthPoint = vec4(...);
vec4 P = fifthPoint - v00;
This means the "shared border" of both triangles lies along the diagonal going between the bottom left and top right of your square.
Since both triangles can be entirely different, determining the coordinates of your arbitrary fifth point starts with determining which of the two triangles it is on.
Since we know the shape is a square, we can take the coordinates of our point P relative to v_00 (as I assumed previously), and see which is greater than the other. If the x coordinate of P is greater than the y coordinate, we know P is on the bottom right triangle. Otherwise it's on the top left one.
bool whichTriangle = P.x > P.y;
int triangleIndex = whichTriangle ? 0 : 1;
Now that we know which triangle we're on, we can interpolate their coordinates to obtain any point on the surface of the triangle.
For triangle 0:
vec4 vectorX = triangles[0][1] - triangles[0][0];
vec4 vectorY = triangles[0][2] - triangles[0][1];
For triangle 1:
vec4 vectorX = triangles[1][1] - triangles[1][2];
vec4 vectorY = triangles[1][2] - triangles[1][0];
Notice that each vector here goes along the x and y axis. That's important, so that we can directly use the x and y coordinates from P to calculate interpolated values.
Next, we normalise the two vectors we just created.
vectorX = vectorX.normalize();
vectorY = vectorY.normalize();
Now we just need to multiply these two values with the X and Y coordinates of P to get any point on the triangle, and add it to a base point.
For triangle 0:
P = triangles[0][0] + vectorX * P.x + vectorY * P.y;
For triangle 1:
P = triangles[1][1] - vectorX * (1.0 - P.x) - vectorY * (1.0 - P.y);
And there you have it. A far too complicated explanation for something that's actually not all that hard. P.z now contains the Z-coordinate of your arbitrary point.
Being a trapezoid ABCD consider this ruled surface:
Then you can interpolate P1 from A and B, and P2 from C and D. Finally you can interpolate P height from P1 and P2 heights

Projecting an arc through two points about a sphere

I'm trying to solve a problem where I need to essentially project an arc from P0 some distance through P1 about a sphere of a known radius, however I have a fairly limited knowledge solving this sort of problem outside of the standard Cartesian context.
To simplify, if I were doing this on a plane I would simply do the following
float distance = 30;
Vector3 direction = (P1 - P0).Normalize();
Vector3 endPoint = P0 + (direction * distance);
I'm essentially trying to see if there is a way I can solve that same sort of problem, only on a sphere instead of on a plane. This get's conceptually difficult as I need to account for the fact that P0 and P1 can (and will) be at arbitrarily different altitudes on the sphere.
I have a feeling that I will potentially need to convert from Cartesian to spherical space, but finding a jump off point here has proven very difficult.
Thoughts?
Let P0 and P1 be points, and consider a sphere of radius r.
First, say that P0 and P1 lie on the sphere, and that we want to travel a distance d. First note that we need P0 ≠ P1, just like in the linear algebra case. (otherwise, P0 = P1 and so there is no unique arc through P0 and P1.) Similarly, we need P0 ≠ -P1, as otherwise there is no unique arc through P0 and P1.
Now the arc from P0 to P1 lies on what is known as a great circle of the sphere. Basically, this is an intersection of the sphere with some plane through O = (0,0,0). More precisely, this is the unique plane through the points O, P1 and P2.
Some basic linear algebra will show you that this is the plane perpendicular to the vector P0 × P1, the cross product of P0 and P1. Note that the order of P0 and P1 is important in this product: in general, P0 × P1 ≠ P1 × P0, and if we took P1 × P0 instead then the direction of motion would be reversed. (i.e. we would be going from P1 to P0 instead.) Therefore the "direction" of P0 to P1 is given by a rotation about P0 × P1.
Now consider general points P0, P1. As melak47 points out, we can first project P0 and P1 onto the sphere, so we can get the rotation above in the "direction" P0 to P1. To project these onto the sphere, we further need that both P0 and P1 are non-zero, i.e. are not the origin. We also run into a problem when P0 and P1 lie on the same line through the origin, because then they project to the same point (or antipodal points) on the sphere and so don't define a unique arc: so in general, we need to check that P0 and P1 are linearly independent. Now note that P0 lies on the sphere of radius ||P0||, where ||P0|| is the norm of the vector P0.
Note that the radius r introduced above hasn't actually been used anywhere yet, and so we can set r = ||P0||. To travel a total distance of d on the arc P0 to P1', where P1' is P1 projected onto the sphere of radius ||P0||, the angle becomes d/||P0||, as above. The good news is that P0 × P1 is still a valid axis of rotation.
So in summary, you want to rotate P0 about P0 × P1 by d/||P0|| radians. In pseudo-code,
float d;
Vector3 P0, P1;
float r = norm(P0);
float angle = d / r;
Vector3 axis = crossProduct(P0, P1);
Matrix3 rotationMatrix = RotationMatrix(angle, axis);
Vector3 endPoint = rotationMatrix * P0;
Checking that P0 and P1 are linearly independent is the same as checking that P0 × P1 is non-zero, so in general you may want to check that axis != Vector3(0,0,0) before constructing the rotation matrix.
If you instead want to travel in the direction P0 to P1 on the arc P0' to P1, where P0' is P0 projected onto the sphere of radius ||P1||, we first need to replace r = norm(P0) by r = norm(P1) (obviously). Further, P0' = ||P1||/||P0|| * P0, and so we also need to replace rotationMatrix * P0 by rotationMatrix * (r / norm(P0) * P0), or rotationMatrix * r * normalize(P0) if you prefer.
IMO, your question doesn't have a single answer. It seems to be a 2D problem that occurs in the plane formed by the two given points and the center of the sphere.
But you need to give more constraints on the trajectory. It could be a straight line, an Archimedean spiral, a logarithmic spiral, a spline... or whatever you like.

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.