defining a plane in R3 with just three numbers - data-structures

all the plane definitions i've found use either four numbers (for the plane normal and distance from origin definition) or six numbers (for the plane normal and point that is on the plane definition).
maybe i'm missing something, but shouldn't it be possible to define a plane with only three numbers, (nx, ny, nz) using the direction of the vector as the plane normal and the magnitude of the vector as the distance from the origin?
i am trying to write a game that generates billions of planes, and shaving 25% off of my plane struct would really help.

It is possible, at the cost of recalculating the distance to the origin every time you need it.

If you need a solution using 3 parameters that has no degenerate case, use two direction angles (U, V) and the distance to the origin D.
Equation of the plane: cos(U).X + sin(U).cos(V).Y + sin(U).sin(V).Z = D.
If high accuracy is not mandated, you can store the angles as shorts, with suitable scaling, achieving 0°00'20" resolution. With float D, this packs to 8 bytes per plane.

Related

Snapping vector to a point from a grid on a sphere (icosahedron)

here is a problem that will turn your brain inside out, I'm trying to deal with it for a quite some time already.
Suppose you have sphere located in the origin of a 3d space. The sphere is segmented into a grid of equidistant points. The procedure that forms grid isn't that important but what seems simple to me is to use regular 3d computer graphics sphere generation procedure (The algorithm that forms the sphere described in the picture below)
Now, after I have such sphere (i.e. icosahedron of some degree) I need a computationally trivial procedure that will be capable to snap (an angle) of a random unit vector to it's closest icosahedron edge points. Also it is acceptable if the vector will be snapped to a center point of triangle that the vector is intersecting.
I would like to emphasise that it is important that the procedure should be computationally trivial. This means that procedures that actually create a sphere in memory and then involve a search among every triangle in sphere is not a good idea because such search will require access to global heap and ram which is slow because I need to perform this procedure millions of times on a low end mobile hardware.
The procedure should yield it's result through a set of mathematical equations based only on two values, the vector and degree of icosahedron (i.e. sphere)
Any thoughts? Thank you in advance!
============
Edit
One afterthought that just came to my mind, it seems that within diagram below step 3 (i.e. Project each new vertex to the unit sphere) is not important at all, because after bisection, projection of every vertex to a sphere would preserve all angular characteristics of a bisected shape that we are trying to snap to. So the task simplifies to identifying a bisected sub triangle coordinates that are penetrated by vector.
Make a table with 20 entries of top-level icosahedron faces coordinates - for example, build them from wiki coordinate set)
The vertices of an icosahedron centered at the origin with an
edge-length of 2 and a circumscribed sphere radius of 2 sin (2π/5) are
described by circular permutations of:
V[] = (0, ±1, ±ϕ)
where ϕ = (1 + √5)/2
is the golden ratio (also written τ).
and calculate corresponding central vectors C[] (sum of three vectors for vertices of every face).
Find the closest central vector using maximum of dot product (DP) of your vector P and all C[]. Perhaps, it is possible to reduce number of checks accounting for P components (for example if dot product of P and some V[i] is negative, there is no sense to consider faces being neighbors of V[i]). Don't sure that this elimination takes less time than direct full comparison of DP's with centers.
When big triangle face is determined, project P onto the plane of that face and get coordinates of P' in u-v (decompose AP' by AB and AC, where A,B,C are face vertices).
Multiply u,v by 2^N (degree of subdivision).
u' = u * 2^N
v' = v * 2^N
iu = Floor(u')
iv = Floor(v')
fu = Frac(u')
fv = Frac(v')
Integer part of u' is "row" of small triangle, integer part of v' is "column". Fractional parts are trilinear coordinates inside small triangle face, so we can choose the smallest value of fu, fv, 1-fu-fv to get the closest vertice. Calculate this closest vertex and normalize vector if needed.
It's not equidistant, you can see if you study this version:
It's a problem of geodesic dome frequency and some people have spent time researching all known methods to do that geometry: http://geo-dome.co.uk/article.asp?uname=domefreq, see that guy is a self labelled geodesizer :)
One page told me that the progression goes like this: 2 + 10·4N (12,42,162...)
You can simplify it down to a simple flat fractal triangle, where every triangle devides into 4 smaller triangles, and every time the subdivision is rotated 12 times around a sphere.
Logically, it is only one triangle rotated 12 times, and if you solve the code on that side, then you have the lowest computation version of the geodesic spheres.
If you don't want to keep the 12 sides as a series of arrays, and you want a lower memory version, then you can read about midpoint subdivision code, there's a lot of versions of midpoint subdivision.
I may have completely missed something. just that there isn't a true equidistant geodesic dome, because a triangle doesn't map to a sphere, only for icos.

Translate and transform plane geometry based on corner coordinates

I have a plane mesh with divisions and I want to specify the coordinates that each of the corners should be positioned. Moving and updating the mesh vertices achieves what I'm trying to do, so long as the plane only has no internal segments. If internal segments are added then I have more vertices than I can manually place, so these need to automatically fall in line with the transformation of the outer edges.
My initial thought here was that I could create a geometry with only four vertices, reposition them, and then increase the number of segments on my plane, apparently, this isn't something that Three.js supports, so I'm looking for a workaround.
Any thoughts would be appreciated.
I don't think that this sort of transformation is expressible as a single matrix that you could then just apply to your plane mesh. I think you really do need to calculate the coordinates of each vertex of the subdivided plane manually.
There are different ways to do this calculation. Bilinear interpolation is this case seems to do the job. Here's how you do it. If you have four points A, B, C, D, then for each internal points, its position can be found as the weighted average of (the weighted average of A and B, and the weighted average of C and D). The weights for the averages come from the index of the subdivision vertex in one direction (say, X) for the inner averages and in the other direction (say, Y) for the outer average. Your indexes run from 0 up to the number of subdivisions in that direction (inclusive), the weight should be from 0 to 1, so the weight = index / number of subdivisions.

Three.js How do you get a Plane from a vector and a constant?

In three.js, the constructor for the Math Plane takes 2 inputs:
normal -- (Vector3) normal vector defining the plane pointing towards the origin
constant -- (Float) the negative distance from the origin to the plane along the normal vector
Can someone provide an illustration or explain how this works? I can understand given a point and normal how to construct a plane, or 3 co-planar points, but can't figure out how a normal vector and constant can be used.
TL:DR?
Mathy-ness and linear algebra
So planes in 3 dimensional space can be defined as a 2-dimensional infinite rectangle that falls on 3 points (what you know)
It can also be defined by a perpendicular (normal) vector and a constant of how far from the origin the plane is.
Three.js take the normal vector (a vector that is perpendicular to the plane you want) and basically applies linear algebra to find the plane, then moves it the constant distance away from the origin.
Math Calculation Explanation:
If we have a vector A and B that are orthogonal (perpendicular) then their dot product is 0. SO if we use this principle we can actually take a known Vector X and find 2 orthogonal Vectors Y and Z that will be co-planar (due to orthogonality properties) by backwards solving X (dot) Y = 0 and X (dot) Z = 0
Now we have 2 co-planar vectors to make our plane that we set the distance of the constant away from the origin
(think how vectors have an origin and an endpoint. If the co-planar vectors share an origin, then we have 3 points: 2 ends, and 1 origin, aka 3 points to make a plane.)
Math Theory Explanation on why this works ahead:
I can't draw very well (without pen and paper to show), but basically, think about a vector in 3D space. Now think about all the vectors that can be perpendicular to it. Basically, that creates an infinite amount of perpendicular vectors rotated in a circle perpendicularly to the original, and if we span them infinitely, we have created a plane.
If you ever have an opportunity to take a linear algebra class, I would highly recommend it. It is extremely interesting, very related to computer graphics, and explains a lot of 3D space math that THREEjs uses

Calculating the normal of a point on a heightfield

I have a spherical heightfield, defined by a function f(x, y, z) which returns the distance from the origin of the surface of the heightfield of a line which passes from the origin through (x,y,z).
(In other words, the isosurface for my heightfield is |x,y,z| = f(x,y,z).)
(Also, for the sake of discussion below, I'm going to assume that surface(x,y,z) is the location of the point on the surface directly below (x,y,z).)
When rendering this, I need to calculate the normal for any point on the heightfield. What's the cheapest way of doing this?
To calculate the normal of a point on a rectangular heightfield, the usual trick is to offset (x,y,z) slightly in two directions parallel to the nominal surface, calculate three points on the heightfield to form a triangle, and then use the cross product to calculate the triangle's normal. This is easy as the three points can simply be surface(x,y,z), surface(x+1,y,z) and surface(x,y+1,z) (or similar). But for a spherical heightfield it's a little trickier because the normal can point in any direction. Simply displacing by x and y won't do because if two of my points fall on a radius, then surface() of them will return the same location and I won't get a triangle.
In the past what I've done is to use the vector <x,y,z> as a radius from the sphere's origin; then calculate a vector perpendicular to it; then rotate this vector around <x,y,z> to give me my three points. But this is fiddly and expensive and shouldn't be necessary. There must be a cheaper way. What is it?
Calculate the surface() points and, if they are close enough to cause problems, carry out the more expensive (but accurate) calculation; otherwise, use the cheap/easy calculation.

How to perform spatial partitioning in n-dimensions?

I'm trying to design an implementation of Vector Quantization as a c++ template class that can handle different types and dimensions of vectors (e.g. 16 dimension vectors of bytes, or 4d vectors of doubles, etc).
I've been reading up on the algorithms, and I understand most of it:
here and here
I want to implement the Linde-Buzo-Gray (LBG) Algorithm, but I'm having difficulty figuring out the general algorithm for partitioning the clusters. I think I need to define a plane (hyperplane?) that splits the vectors in a cluster so there is an equal number on each side of the plane.
[edit to add more info]
This is an iterative process, but I think I start by finding the centroid of all the vectors, then use that centroid to define the splitting plane, get the centroid of each of the sides of the plane, continuing until I have the number of clusters needed for the VQ algorithm (iterating to optimize for less distortion along the way). The animation in the first link above shows it nicely.
My questions are:
What is an algorithm to find the plane once I have the centroid?
How can I test a vector to see if it is on either side of that plane?
If you start with one centroid, then you'll have to split it, basically by doubling it and slightly moving the points apart in an arbitrary direction. The plane is just the plane orthogonal to that direction.
But you don't need to compute that plane.
More generally, the region (i) is defined as the set of points which are closer to the centroid c_i than to any other centroid. When you have two centroids, each region is a half space, thus separated by a (hyper)plane.
How to test on a vector x to see on which side of the plane it is? (that's with two centroids)
Just compute the distance ||x-c1|| and ||x-c2||, the index of the minimum value (1 or 2) will give you which region the point x belongs to.
More generally, if you have n centroids, you would compute all the distances ||x-c_i||, and the centroid x is closest to (i.e., for which the distance is minimal) will give you the region x is belonging to.
I don't quite understand the algorithm, but the second question is easy:
Let's call V a vector which extends from any point on the plane to the point-in-question. Then the point-in-question lies on the same side of the (hyper)plane as the normal N iff V·N > 0

Resources