3d terrain.
I have 3 vertices that define a plane. (the 3 nearest pixels in a height map)
I have an x,z on that plane. (my location in the world)
How do you find the y-intercept? (so that I stand on the surface of that plane)
The equation of a plane is:
Ax + By + Cz = D, where D = Ax0 + By0 + Cz0,
If you have three vertices, find two vectors from the vertices. For example, for three vertices T, U, V, there would be, for example, a vector TU, and a a vector UV.
Find the cross product of the two vectors. That's your normal vector, n, which has three components n1, n2, and n3.
A = n1
B = n2
C = n3
Take one of the points. The coordinates of that point are x0, y0, and z0.
Input this into the equation to calculate D.
Then substitute your x and z for x and z and solve for y!
So in the end y is:
y = (A*x0 + B*y0 + C*z0 - A*x - C*z)/B
Somebody correct me if my algebra was wrong.
You can calculate the cross product like this:
For two vectors a and b, with components a1, a2, a3 and b1, b2, b3, respectively, the cross product is :
which goes to:
A = the coefficient of i-hat (the bolded i)
B = the coefficient of j-hat (the bolded j)
C = the coefficient of k-hat (the bolded k)
You say that you are looking at the three nearest pixels in the height map, which makes me assume that you have a regular grid from which you extract your vertices. In this case, you can use image interpolation methods to perform linear being similar to the answer from eboix or bicubic interpolation. Your height value is then equivalent to the brightness value in the image processing domain.
The math is much easier in the linear case, and the grid structure makes it possible to use a simple form. Let c by your cell size, and p, q, r the height values of your 3 vertices, like this
p q
+--.
| /
|/
r
and x, and y the distances along the legs of your right angled triangle. Where the triangle is of course the projection of your 3 vertices on the x, y plane. Then your interpolated height value is
z = (q-p)/c * x + (r-q)/c * y
Related
This question already exists:
circle in three dimensional coordiantes [closed]
Closed 1 year ago.
I want to draw a circle in three dimensional coordiantes, i'm given a vector, the angle where vector's intersects with the circle is 90 degrees, the intersection point is the centre of the circle. The radius can be parametrized. EDIT: I am programming a server plugin for minecraft. At this point I have made a sword that can be thrown. I want to add some decor. I want that after the sword there was a trace in the form of a circle. But I don't understand how to draw a circle in 3D coordinates so that the angle of intersection of the sword throw vector with the center of the circle is 90 degrees. The radius can be arbitrary, and the vector can enter the center of the circle. I thought I could just rotate the throw vector on 3 axes and get a circle, but nothing worked. I need an equation with which I can draw a given circle.
You have center C, normal vector N, radius R. Seems you want to get points at the circumference.
At first get some base vector in the circle plane.
Possible way:
Reveal normal component with the largest magnitude and with the second magnitude. For example, abs(N.X) is the largest, abs(N.Z) has the second magnitude, and abs(N.Y) is the smallest. Make the smallest component zero, exchange two larger ones, and negate the largest. For this example base vector will be:
A = (N.Z, 0, -N.X)
It is perpendicular to normal, hence lies in the circle plane.
Then get the next basis vector using vector product (B will be perpendicular both to A and to N, it lies in the plane too)
B = N x A
Now normalize vectors A and B (make them unit length)
A = A / len(A)
B = B / len(B)
and you can get any point at the circumeference with parametric equation where t changes in the range 0..2*Pi
P(t) = C + R * A * Cos(t) + R * B * Sin(t)
or in components:
P.X = C.X + R * A.X * Cos(t) + R * B.X * Sin(t)
and so on
I am writing a raytracer in java, and I was able to get tracing of spheres working, but I believe I have something wrong with how I am tracing triangles.
Here is the basic algorithm, as I understand it:
First determine if the ray even intersects the plane that the triangle is on.
Clip all points so they are on the same plane as the triangle (so to the xy plane, as an example).
Determine if the potential intersection point falls inside or out of the triangle, based on the number of polygon edges you cross when sending out a ray in an arbitrary direction along the new plane.
Now, here is my implementation of that (specifically the first point):
public Vector getIntersectionVector(Ray ray)
{
Vector planeIntersectionVector = getPlaneIntersectionVector(ray, getPlaneNormal());
if (planeIntersectionVector != null)
{
if (isIntersectionVectorInsideTriangle(planeIntersectionVector))
{
return planeIntersectionVector;
}
else
{
return null;
}
}
else
{
return null;
}
}
Where getPlaceIntersectionVector() is:
private Vector getPlaneIntersectionVector(Ray ray, Vector planeNormal)
{
double vd = planeNormal.dotProduct(ray.getDirection());
//(p_n \dot r_d) == 0, parallel. (p_n \dot r_d) > 0 Plane normal pointing away from ray.
if (vd >= 0)
{
return null;
}
double distance = planeNormal.distance(0d, 0d, 0d);
double vo = -(planeNormal.dotProduct(ray.getOrigin()) + distance);
double intersectionDistance = vo / vd;
//intersectionDistance <= 0 means the "intersection" is behind the ray, so not a real intersection
return (intersectionDistance <= 0) ? null : ray.getLocation(intersectionDistance);
}
Which basically tries to mimic this:
And this:
Where t is the distance along the ray that the point hits, ro is the origin of the ray, rd is the direction of the ray, pn refers to the plane normal of the triangle/plane, and d is the distance from the plane that the triangle is on to the origin (0,0,0)
Am I doing that wrong? When I send out the ray from the first pixel in the image (0,0), I am seeing that the intersectionDistance (or t) is almost 1100, which intuitively seems wrong to me. I would think that the intersection point would be much closer.
Here is the relevant data:
Ray origin (0,0,1), Ray Direction is roughly (0.000917, -0.4689, -0.8833).
Triangle has vertices as (-0.2, 0.1, 0.1), (-0.2, -0.5, 0.2), (-0.2, 0.1, -0.3), which makes the plane normal (-1, 0, 0).
According to my code, the Ray intersects the plane 1090 distance away, which as I mentioned before, seems wrong to me. The scene is only -1.0 to 1.0 in every direction, which means the intersection is very very far in the distance.
Am I doing the plane intersection wrong?
Please let me know where to clarify points, and if you need any more information.
The problem is this line:
double distance = planeNormal.distance(0d, 0d, 0d);
A plane is defined by a normal and a distance from the plane to the origin. The distance of a vector from the origin is the length of a vector, so what you are calculating there is just the length of the plane normal (which will always be 1.0 if it has been normalized).
The distance of the plane from the origin is an extra piece of information that needs to be passed into your function, you can't just calculate it from the normal because it's independent of it (you can can have lots of planes with normals pointing in the same direction at different distances from the origin).
So define your function something like this:
private Vector getPlaneIntersectionVector(Ray ray, Vector planeNormal, double planeDistance)
and call it something like this:
Vector planeIntersectionVector = getPlaneIntersectionVector(ray, getPlaneNormal(), getPlaneDistance());
Then you can calculate vo like this:
double vo = -(planeNormal.dotProduct(ray.getOrigin()) + planeDistance);
Slightly different approach:
Let's triangle vertices are V0, V1, V2
Edge vectors are
A = V1-V0
B = V2 - V0
Ray has parametric equation (as you wrote)
P = R0 + t * Rd
From the other side, intersection point has parametric coordinates u, v in the triangle plane
P = V0 + u * A + v * B
So you can write system of three linear equation for x, y, z coordinates and solve it for t, u, v. If determinant ius non-zero (ray is not parallel to the plane), and t >=0, and u, v, u+v lie in range 0..1, then P is inside triangle.
R0.X + t * Rd.X = V0.X + u * A.X + v * B.X
R0.Y + t * Rd.Y = V0.Y + u * A.Y + v * B.Y
R0.Z + t * Rd.Z = V0.Z + u * A.Z + v * B.Z
How can I lerp between two 3d vectors?
I use this method for 2d vectors:
public Vector2d lerp(Vector2d other, double speed, double error) {
if (equals(other) || getDistanceSquared(other) <= error * error)
return other;
double dx = other.getX() - this.x, dy = other.getY() - this.y;
double direction = Math.atan2(dy, dx);
double x = this.x + (speed * Math.cos(direction));
double y = this.y + (speed * Math.sin(direction));
return new Vector2d(x, y);
}
Note: this is not exactly "linear interpolation"; this method will interpolate at a constant rate, which is what I want.
I want to do exactly what this does but with an added z component for the third dimension. How can I do this?
The easiest way would be to transform your two vectors such that they lie in the (u, v) plane; then apply your method above; then transform back to the original coordinate space.
This requires you to construct a rotation matrix:
Take the cross product of your two vectors to get the mutual normal vector; call this cross_1;
Define that this points along the u axis;
Take the cross product of this and cross_1 to get a vector cross_2, which is the direction of your v axis.
Normalize each of these three vectors; call them this_norm, cross_2_norm and cross_1_norm.
These three vectors can be written as a 3x3 orthonormal matrix (each of the vectors is a 3-element column vector):
R = [ this_norm cross_2_norm cross_1_norm ]
Now: you can multiply your 3d vectors this and other by this matrix, and you will get vectors which have the form
[ u ]
[ v ]
[ 0 ]
i.e. a 3-dimensional column vector with zero as the third element (or, at least, you should. I may have forgotten to transpose the 3x3 matrix above).
So, you can obviously discard the third element, and have 2-element column vectors: you can store these in Vector2d. And so you can apply your method above to do the interpolation.
That gives you a Vector2d which interpolates in the (u, v) plane. You can transform that back to the (x, y, z) space by attaching a zero third element to it, and pre-multiplying by R' (which is the inverse of R, since it is orthonormal).
Of course, you need to handle degenerate cases, like zero and (anti-)parallel vectors. In these cases, one or both of the cross products are zero, meaning you can't normalize them; simply pick arbitrary directions instead.
If I understand your code correctly, when you compute dx and dy offsets, then compute angle from it, and finally sin/cos pair - you're basically normalizing the dx,dy vector, so you could write it like that:
Vector2d delta = other - this; // I'm not sure about your API here,
delta.normalize(); // you may need to fix those lines
double x = this.x + (speed * delta.x);
double y = this.y + (speed * delta.y);
Now it should be straightforward to add a Z component.
Alright, so I'm trying to get the distance of a point in a 2d triangle without calculating perpendicular vectors.
float qd = Vector2f.dot(new Vector2f(pos.x, pos.z),
new Vector2f(normal.pos.x, normal.pos.z)) -
Vector2f.dot(new Vector2f(q.center.x, q.center.z),
new Vector2f(normal.pos.x, normal.pos.z));
That's the code I'm using. (Note: it's converting 3f vectors to 2d ones, but you don't have to worry about that). I need the result of the calculation to be between 0 and 1 I.E. 0.5 or something.
If I'm still not explaining right maybe this will help?
My question is: How do I get the distance of a point in a 2d triangle without calculating perpendicular vector's distance? I.E. if the triangle is facing up (y = -1) without any tilt
I would need the distance in the triangle without any X.
Edit1: About what you're saying, Banthar, This is what I got out of it, and it doesn't work, but it seems like it's close to working.
float d = (float) Math.sqrt( 0 /*cause the two x's should be the same */ + Math.pow(pos.z - q.max.z, 2));
float h = (float) Math.sqrt( 0 /*cause the two x's should be the same */ + Math.pow(q.min.z - q.max.z, 2));
float myDist = d/h;
Let's say your triangle is ABC and the point is P.
The number you are looking for is the distance from P to AB divided by the distance from C to AB.
This is the same as the ratio of the corresponding areas. So you can compute the two areas:
Area(ABP) / Area(ABC)
The best way to compute the triangle area depends on what information you have about your triangle.
If you have the vertices only, then you can use:
Area(ABP) / Area(ABC) = ( Ax*By - Ax*Py + Ay*Px - Ay*Bx + Bx*Py - By*Px ) /
( Ax*By - Ax*Cy + Ay*Cx - Ay*Bx + Bx*Cy - By*Cx )
Alright, so I'm trying to achieve whats in this image:
I believe this would be a barycentric coord system, but where the X always equals 1? Basically I need it to only increase/decrease when I move towards/away from the highest point in my triangle. This is the code I got for it so far (Note I'm using the LWJGL library in java).
public float getDist( Vector3f p, Vector3f a, Vector3f b, Vector3f c )
{
Vector3f v0 = new Vector3f(0,0,0);
Vector3f.sub( c, a, v0 );
Vector3f v1 = new Vector3f(0,0,0);
Vector3f.sub( b, a, v1);
Vector3f v2 = new Vector3f(0,0,0);
Vector3f.sub( p, a, v2 );
float dot00 = Vector3f.dot(v0, v0);
float dot01 = Vector3f.dot(v0, v1);
float dot02 = Vector3f.dot(v0, v2);
float dot11 = Vector3f.dot(v1, v1);
float dot12 = Vector3f.dot(v1, v2);
float inverse = 1.0f / (dot00 * dot11 - dot01 * dot01);
float u = (dot11 * dot02 - dot01 * dot12) * inverse;
float v = (dot00 * dot12 - dot01 * dot02) * inverse;
if((u >= 0) && (v >= 0) && (u + v <= 1)) return (float) (Math.sin(u) * Math.cos(v));
else return 0;
}
edit: I guess what I'm asking is: Is there a way to get the distance that a point inside a triangle has travailed from the lowest point the triangle has in space where 1 would be the highest point on the triangle (mosty far away from the lowist) without taking it's deviating vector into account? I.E. notice that the two red dots on the image have the same coords even though they have different dists from the top's x?
Edit2:
If I understand what you're saying: you have a triangle (abc) in 3D coordinates, and you want to evaluate the elevation of a fourth point (p) above one edge, proportionate to its opposite point:
b --------------- 1.0
|\
| \
| p\ ------------- (result)
| \
a----c ---------- 0.0
You are correct in that this result is one of three barycentric coordinates for a point on the triangle.
I recommend something like the following:
find the normal of the plane of the triangle: vABC = cross(c-a, b-a)
find a normal perpendicular to vABC and ac: vPerpAC = cross(c-a, vABC)
evaluate the vector ab with respect to it: sAB = dot(vPerpAC, b-a)
evaluate your target point: sAP = dot(vPerpAC, p-a)
your final result is the ratio of these last two evaluations: return sAP / sAB
This should be robust against points that aren't actually on the triangle: they are effectively projected perpendicularly onto the abc plane.
Note that, if you know abc beforehand, you can precalculate the following values:
the scaled normal: vScaled = vPerpAC / sAB
the scaled offset: sScaled = dot(vScaled, a)
and compute the result of a series of points p more efficiently:
return dot(vScaled, p) - sScaled
This effectively precomputes an oriented plane, pre-scaled to directly provide the desired result.