WebGL triangle layout for deformation - three.js

I am implementing simple deformation in WebGL by moving vertices up or down, but stumbled upon a problem with the way the triangles are laid out.
I am using the PlaneGeometry in three.js and it uses the following layout for the triangles:
indices.push( a, b, d )
indices.push( b, c, d )
The layout used by three.js is on the left. Mine alternates between both.
Moving vertices up or down results in the image on the left, where, after moving the vertex, the deformation looks off. The blue dot represents the center vertex.
I decided to alternate the triangles using the following code:
if ( ( ix + iy ) % 2 === 0 ) {
// Even segment
indices.push( a, b, d )
indices.push( b, c, d )
} else {
// Odd segment
indices.push( a, b, c )
indices.push( a, c, d )
}
As you can see on the right, it gives me a much better result.
The two questions I have are:
Is the layout I used valid and what is its name?
Is there a better better way to solve this problem?

Related

Find point perpendicular to 2 points

It seems I am bad at vectors and math or forgot my entire university studies...
I have A, B, C points coordinates (X, Y, Z) where Z = 0.
C is placed in a half distance between A, B points.
D, E points are in parallel to A,B line
Any idea how to find D and E positions with three.js?
A, B, C are Vector3 three.js objects.
Any help is appreciated.
If C is at half the distance between A and B, offset orthogonally, as your figure seems to indicate, then it is simple:
D = C - 0.5AB and
E = C + 0.5AB,
where AB is the vector from A to B.
In THREE.js, you could write it for example like this:
const abHalf = b.clone().sub(a).multiplyScalar(0.5);
const d = c.clone().sub(abHalf);
const e = c.clone().add(abHalf);
though as usual when working with vectors, there are many other ways to calculate it; you may pick your favourite approach.
Is this what you meant?

How to do Ray and Triangle Edge intersect?

I'm facing problem intersecting ray with triangle edges. Actually, I'm trying to pick/intersect with triangle, vertex, edge of a mesh using Mouse. So I made ray from the Mouse current position and then I intersect it with the mesh elements like triangle/polygon, vertex, edge etc to work with it. Basically, 3d modeling stuffs. Intersecting with triangle was easy and fun. And the vertex part was tricky.
But now, I don't know how to intersect/pick with triangle edges. I mean how I treat them when intersecting with the Mouse Ray? First I thought they can be treated like a 3D line. But eventually failed to do the Ray and the Line intersect. Searched on the Internet but not found any helpful info. Although I found some open source projects are using OpenGL built-in picking features to pick/intersect with Edge. But in my case, I can't use that. :(
My current edge picking code structure looks like the following:
void pickEdge(Ray ray, Scene scene)
{
for each object in scene
{
mesh = getMesh(object)
for each triangle in mesh
{
for each edge in triangle
{
v1 = getV1(edge)
v2 = getV2(edge)
// Do intersect with 'ray' and 'v1', 'v2'. But how?
}
}
}
}
So I'm stuck here and really need some help. Any idea, algorithm or a small help is greatly appreciated.
In your case problem of finding intersection between triangle and ray in 3D space can be boiled down to finding point location (INSIDE, OUTSIDE, ON BOUNDARY) in triangle in 2D space (plane). All you should do is project triangle on screen plane, find intersection on edge and perform reverse projection on edge. Position of point is position of mouse. The only problem is to treat degenerate cases like mapping triangle into line segment. But I think it will not be problem, because such cases can be easily coped.
Please give a look to the algorithms at the end of this page and more in general all the ones that this website offers: http://geomalgorithms.com/a05-_intersect-1.html
The first approach is to orthogonally project the edge (and the ray) to a plane perpendicular to the ray, and then to compute the distance of the projected ray to the projected edge.
Ie., first you determine two orthogonal vectors rdir1, rdir2 orthogonal to your ray.
Then you calculate the projection of your ray (its base point) to this plane, which will simply yield a 2d point rp.
Then you project the edge to that plane, by simply applying dot products:
pv1 = new Vector2(DotProduct(v1, rdir1), DotProduct(v1, rdir2))
pv2 = new Vector2(DotProduct(v2, rdir1), DotProduct(v2, rdir2))
Now you can compute the distance from this 2d line pv1, pv2 to the point rp.
Provided that the direction of the edge is taken from the view matrix's "forward" direction, then two vectors orthogonal to that would be the view matrix's left and right vectors.
Doing the above recipe will then yield something similar to projecting the edge to the screen. Hence, alternatively you could project the edge to the screen and work with those coordinates.
First of all, what is the distance between two geometric objects A and B ? It is the minimal distance between any two points on A and B, ie. dist(A,B) = min { EuclideanLength(x - y) | x in A, y in B}. (If it exists and is unique, which it does in your case.)
Here EuclideanLength((x,y,z)) = sqrt(x^2 + y^2 + z^2) as you already know. Because sqrt is strictly increasing it suffices to minimize SquareEuclideanLength((x,y,z)) = x^2 + y^2 + z^2, which greatly simplifies the problem.
In your question the objects are a line segment A := {v1 + t*(v2-v1) | 0 <= t <= 1} and a line B := {p + s*d | s is any real number}. (Don't worry that you asked about a ray, a line is really what you want.)
Now calculating the distance comes down to finding appropriate t and s such that SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d) is minimal and then computing EuclideanLength(v1 + t*(v2-v1) - p - s*d) to get the real distance.
To solve this we need some analytic geometry. Because d is not zero, we can write each vector v as a sum of a part that is orthogonal to d and a part that is a multiple of d: v = Ov + Mv. For such an "orthogonal decomposition" it always holds SquareEuclideanLength(v) = SquareEuclideanLength(Ov) + SquareEuclideanLength(Mv).
Because of d = Md in the above
SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d) =
SquareEuclideanLength(Ov1 + t*(Ov2-Ov1) - Op)
+ SquareEuclideanLength(Mv1 + t*(Mv2-Mv1) - Mp - s*d)
the left addend does not depend on s and however you chose t you can find an s such that the right addend is 0 ! (Remember that Mv1, Mv2, ... are multiples of d.)
Hence to find the minimum you just have to find such maps O, M as above and find the minimizer t.
Assuming that d is normalized, these are actually given by Ov := CrossProduct(v, d) and Mv := DotProduct(v, d)*d, but just believe me, that this also works if d is not normalized.
So the recipe for finding the distance is now: find 0 <= t <= 1 that minimizes
SquareEuclideanLength(Cross(v1 - p, d) + t*Cross(v2 - v1, d))
= SquareEuclideanLength(Cross(v1 - p, d))
+ 2*t*Dot(Cross(v1 - p, d), Cross(v2 - v1, d))
+ t^2 SquareEuclideanLength(Cross(v2 - v1, d)).
You will already know this formula from Point-Line distance calculation (that's what it is) and it is solved by differentiating with respect to t and equalling 0.
So the minimizer of this equation is
t = -Dot(Cross(v1 - p, d), Cross(v2 - v1, d))/SquareEuclideanLength(Cross(v2 - v1, d))
Using this t you calculate v1 + t*(v2 - v1), the point on the line segment A that is closest to line B and you can plug this into your point-line distance algorithm to find the sought after distance.
I hope this helps you !

Test if point inside angle

In 2D plane there are four points: O, A, B, P.
O, A, B define an "angle", i.e. two rays, both originating at O, and one passing though A, while the other goes through B. How to tell on which "side" of the angle the point P lies, i.e. whether it is inside the space marked by the two rays?
Note that the points are placed arbitrarily, i.e. the angle might have larger size than π.
This is similar problem to determining which side of line a point lies, as discussed e.g. in comp.graphics.algorithms FAQ (Subject 1.02: How do I find the distance from a point to a line?), but here it is about two rays, instead of one line.
Edit: Apologies for not stating it more explicitly: the angle is oriented, i.e. given P, it might lay on the right of O, A, B, but then it is on the left of O, B, A. Let's say the triangle O, A, B has clock-wise orientation. Again, it is similar to the "which side of line" problem: there it also matters whether the line passes though A, B, or B, A.
An example:
\ \
A B
\ right \ left
left \ right \
O------B---- O------A----
When looking from O, we can split the plane into two regions or "sides".
A region that sweeps ray OA towards ray OB while rotating counterclockwise.
And the rest, i.e. ray OB sweeps counterclockwise to OA.
To check if the point is in which region, you can use
// if isInRegion(O, A, B) is true, P is in the first region.
// otherwise, isInRegion(O, B, A) will be true.
bool isInRegion(O, A, B, P) {
return isCCW(O, A, P) && !isCCW(O, B, P)
}
// ref: http://www.cs.cmu.edu/%7Equake/robust.html
// For more robust methods, see the link.
bool isCCW(a, b, c) {
return ((a.x - c.x)*(b.y - c.y) - (a.y - c.y)*(b.x - c.x)) > 0;
}
I tried it here.
The discussion that follows is meant to detect points inside the hatched area.
There are two cases to be considered:
the angle AOB is smaller than a flat, then the point P must be to the right of AO and to the right of OB (intersection of the two half planes),
the angle AOB is larger than a flat, then the point P must be to the right of AO or to the right of OB (union of the two half planes).
The complete boolean expression is
AO|B . (AO|P . OB|P) + ¬ AO|B . (AO|P + OB|P),
where XY|Z expresses that Z lies on the right of XY, which is equivalent to "XYZ is clockwise" and is determined by the sign of the triangle area.
I don't think it is possible to make the expression simpler, unless you have several P for the same AOB.

Determinate the closest bounding border (graph theory and geometry)

Example figure
Point A: { x: xA; y: yA; neighbors: { B, J } }
Point B: { x: xB; y: yB; neighbors: { A, C } }
Point C: { x: xC; y: yC; neighbors: { B, D, G, H } }
etc.
Input
Set of verticies (points, cartesian coordinate system).
Some verticies are connected to others.
There is no edge's intersection on the input.
Question
How to find the closest bounding border for the given point (for example one of the green points 1, 2, 3)? I can use only connected verticies.
Solution for point 1 is { A, B, C, D, E, F, G, I, J }.
(Not { A, B, D } – there is no edge between { B and D } and { D and A }).
Solution for point 2 is { C, D, E, F, G }.
Solution for point 3 is { C, G, H }.
My idea
Find intersection of the vertical line (this line goes through question point) and the edge (between 2 verticies). I know 2 verticies now. How continue??
Can I use any algorithm from graph theory for this situation?
First, there are three corner cases in your idea, that must be dealt with:
the vertical line intersects above and below, you must choose one
the vertical line could intersect with a vertex not an edge
the vertical line could intersect with an edge that is also vertical
(so that there is an infinity of common points)
This said,
Say you find an edge below the point. So you found 1 edge and 2 vertices. You can select the left vertex, compute the angle of the found edge relative to each segment originating from this vertex, and select the segment with the lowest angle. Then you follow this new edge to find a new vertex, and iterate.

How to scale a torus and keep the radius of tube unchanged?

If I have a torus defined like this.
u,v are in the interval [0, 2π),
R is the distance from the center of the tube to the center of the torus,
r is the radius of the tube.
I want to enlarge the R and keep r unchanged, how to use transformation matrix to do it, or is it possible?
The transformation you're looking for is not linear, so it can't be represented by a matrix.
To tell that it's not linear, imagine the torus centered at the origin laid out parallel to the xy-plane. The positive x-axis intersects the torus at two points; let's call the one closer to the origin a and the farther one b.
After you apply your transformation, we expect that a and b both moved away from the origin by the same amount. But since b is a multiple of a, this is impossible:
b = c*a
f(b) - b = f(c*a) - c*a
= c*f(a) - c*a
= c*( f(a) - a )
The same multiple that relates a and b also relates how far a moved compared to b.
You will have the same problem even if you project the torus onto a plane.

Resources