Compact representation of OpenGL modelview matrix 4x4 - c

What is the most user friendly way to store only the rotation part of an OGL modelview (4x4) matrix?
For example; in a level editor to set the rotation for an object it would be easy to use the XYZ Euler angles. However this seems a very tricky system to use with matrices.
I need to be able to get AND set the rotation from this new representation.
(The alternative is to store the rotation part (4*3 numbers) but it is hard for a user to manipulate these)
I found some code here http://www.google.com/codesearch/p?hl=en#HQY9Wd_snmY/mesh/matrix3.h&q=matrix3&sa=N&cd=1&ct=rc that allows me to set and get rotation from angles (3 floats). This is ideal.

Although they're used regularily, I disregard the use of Euler angles. They're problematic as they only preserve the pointing direction of the object, but not the bitangent to that direction. More important: They're prone to gibal lock http://en.wikipedia.org/wiki/Gimbal_lock
A far superior method for storing rotations are Quarternions. In layman terms a quaternion consists of the rotational axis and the angle of rotation around this axis. It is thus a tuple of 4 scalars a,b,c,d. The quaternion is then Q = a + i*b + j*c + k*d, |Q| = 1, with the special properties of i,j,k that i² = j² = k² = i·j·k = -1 and i·j = k, j·k = i, k·i = j, which implies j·i = -k, k·j = -i, i·k = -j
Quaterions are thus extensions of complex numbers. If you recall complex number theory, you'll remember that the product of two complex numbers a =/= b with |a| = |b| = 1 is a rotation in the complex plane. It is thus easy to assume that rotations in 3D can be described by an extension of complex numbers into a complex hyperplane. This is what quaternions are.
See this article on the details.
http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation

In a standard 3D matrix you only need the top left 3x3 values to give the rotation. To apply the matrix as a 4x4 later on, you need to make the other values 0 apart from on the diagonal.
Here's a rotation only matrix where the values vXY give the rotations.
[v00 v01 v02 0]
[v10 v11 v12 0]
[v20 v21 v22 0]
[ 0 0 0 1]
Interestingly, the values form the bases of the coordinate system you have rotated the object into, so in the new system, the x-axis is along [v00 v01 v02], the y-axis is along [v10 v11 v12] and the z-axis obviously [v20 v21 v22].
You could show these axes beside the object and let the other drag them around to change the rotation, perhaps.

I would say this depends on the user, but to me the most "user friendly" way is to store "roll", "pitch" and "yaw". These are very non-technical terms that an average user can understand and adjust, and it should be easy for you to take these values and compute the matrix.

IMO, the most 'user friendly format' for rotation is storing Euler XYZ angles, this is generally how rotations are exposed in any 3d content creation software.
Euler angles are easy to transform to matrices, see here for the involved matrix product.
But you should not confuse the format given to the GUI/user and the storage format of the data: Euler XYZ angles have problems of their own when doing animation, gimbal lock can introduce unwanted behaviour.
Another candidate for storing/computing rotations is quaternions. They offer mathematical advantages over XYZ angles, essentially when interpolating between two rotations. Of course, you don't want to expose the quaternion values directly to any human user, you'll need to convert them to XYZ angles. You'll find plenty of code to that on the Web.
I would not recommend storing the rotation directly in matrix format. Extracting user friendly values from it is difficult, it does not offer any interesting behaviour for animation/interpolation, it takes for storage. IMO, matrices are to be created when needed to transform the geometry.
To conclude, there are a few options, you should select what suits you most. Do you plan to having animation or not ? etc.
EDIT
Also, you should not make an amalgam with model and view matrices. They are semantically very different, and are combined in OpenGL only for performance reasons. What I had in mind above in the 'model matrix'. The view matrix is generally given by your view system/camera manager, and is combined with you model matrix.

A quaternion is, although the math is "obscure and unintellegible" surprisingly user friendly, as it represents rotation around an axis by a given angle.
The axis of rotation is simply a unit vector pointing in that direction, multiplied by the sine of 1/2 the rotation angle, and the "obscure" 4th component equals the cosine of 1/2 the rotation angle.
It feels kind of "unnatural" at first sight, but once you grasp it... can it be any easier?

Related

Generating a set of N random convex disjoint 2D polygons with at most V vertices, and two additional points?

I want to create a set of N random convex disjoint polygons on a plane where each polygon must have at most V vertices, where N and V are parameters for my function, and I'd like to obtain a distribution as close as possible to uniform (every possible set being equally probable). Also I need to randomly select two points on the plane that either match with one of the vertices in the scene or are in empty space (not inside a polygon).
I already implemented for other reasons in the same programming language an AABB tree, Separating Axis Theorem-based collision detection between convex polygons and I can generate a random convex polygon with arbitrary amount of vertices inside a circle of given radius. My best bet thus far:
Generate a random polygon using the function I have available.
Query the AABB tree to test for interception with existing polygons.
If the AABB tree query returns empty set I push the generated polygon into it, otherwise I test with SAT against all the other polygons whose AABB overlaps with the generated one's. If SAT returns "no intersection" I push the polygon, otherwise I discard it.
Repeat from 1 until N polygons are generated.
Generate a random number in {0,1}
If the generated number is 1 I pick a random polygon and a random vertex on it as a point
If the generated number is 0 I generate a random position in (x,y) and test if it falls within some polygon (I might create a tiny AABB around it and exploit the AABB tree to reduce the required number of PiP tests). In case it's not inside any polygon I approve it as a valid point, otherwise I repeat from 5.
Repeat from 5 once more to get the second point.
I think the solution would possibly work, but unfortunately there's no way to guarantee that I can generate N such polygons for very large N, or find two good points in an acceptable time, and I'm programming in React, where long operations run on the main thread blocking the UI till they end. I could circumvent the issue by ejecting from create-react-app and learn Web Workers, which would require probably more time than it's worth for me.
This is definitely non-uniform distribution, but perhaps you could begin by generating N points in the plane and then computing the Voronoi diagram for those points. The Voronoi diagram can be computed in O(n log n) time with Fortune's algorithm. The cells of the Voronoi diagram are convex, so you can then construct a random polygon of the desired number of vertices that lies within each cell of the diagram.
By Balu Ertl - Own work, CC BY-SA 4.0, Link
Ok, here is another proposal. I have little knowledge of js, but could cook up something in Python.
Use Poisson disk sampling with distance parameter d to generate N samples of the centers
For a given center make a circle with R≤d.
Generate V angles using Dirichlet distribution such that sum of angles is equal to 2π. Sort them.
Place vertices on the circle using angles generate at step#3 and connect them. This would be be your polygon
UPDATE
Instead using Poisson disk sampling for step 1, one could use Sobol quasi-random sequences. For N points sampled in the 1x1 box (well, you have to scale it afterwards), least distance between points would be
d = 0.5 * sqrt(D) / N,
where D is dimension of the problem, 2 in your case. So radius of the circle for step 2 would be 0.25 * sqrt(2) / N. This ties nicely N and d.
https://www.sciencedirect.com/science/article/abs/pii/S0378475406002382

Robustly finding the local maximum of an image patch with sub-pixel accuracy

I am developing a SLAM algorithm in C, and I have implemented the FAST corner finding method which gives me some strong keypoints in the image. The next step is to get the center of the keypoints with a sub-pixel accuracy, therefore I extract a 3x3 patch around each of them, and do a Least Squares fit of a two dimensional quadratic:
Where f(x,y) is the corner saliency measure of each pixel, similar to the FAST score proposed on the original paper, but modified to also provide a saliency measure in non corner pixels.
And the least squares:
With being the estimated parameters.
I can now calculate the location of the peak of the fitted quadratic, by taking the gradient equal to zero, achieving my original goal.
The issue arises on some corner cases, where the local peak is closer to the edge of the window, resulting in a fit with low residuals but a peak of the quadratic way outside the window.
An example:
The corner saliency and a contour of the fitted quadratic:
The saliency (blue) and fit (red) as 3D meshes:
Numeric values of this example are (row-major ordering):
[336, 522, 483, 423, 539, 153, 221, 412, 234]
And the resulting sub pixel center of (2.6, -17.1) being wrong.
How can I constrain the fit so the center is within the window?
I'm open to alternative methods for finding the sub pixel peak.
The obvious answer is to reject 3x3 (or 5x5, whatever you use) boxes whose discrete maximum is not at the center. In other words, to use a quadratic approximation only to refine the location of a maximum that must be located inside the box.
More generally, in such cases the first questions to ask is not "How do I constrain my model-fitting procedure to shoehorn a solution for this edge case?", but rather
"Does my model apply to this edge case?" and "Is this edge case even worth spending time on, or can I just ignore it?"
I tried my own code to fit a 2D quadratic function to the 3x3 values, using a stable least-squares solving algorithm, and also found a maximum outside of the domain. The 3x3 patch of data does not match a quadratic function, and therefore the fit is not useful.
Fitting a 2D quadratic to a 3x3 neighborhood requires a degree of smoothness in the data that you don't seem to have in your FAST output.
There are many other methods to find the sub-pixel location of the maximum. One that I like because it is more stable and less computationally intensive is the fitting of a "separable" quadratic function. In short, you fit a quadratic function to the three values around the local maximum in one dimension, and then another in the other dimension. Instead of solving 6 parameters with 9 values, this solves 3 parameters with 3 values, twice. The solution is guaranteed stable, as long as the center pixel is larger or equal to all pixels in the 4-connected neighborhood.
z1 = [f(-1,0), f(0,0), f(1,0)]^T
[1,-1,0]
X = [0,0,0]
[1,1,0]
solve: X b1 = z1
and
z2 = [f(0,-1), f(0,0), f(0,1)]^T
[1,-1,0]
X = [0,0,0]
[1,1,0]
solve: X b2 = z2
Now you get the x-coordinate of the centroid from b1 and the y-coordinate from b2.

Plotting a frequency response from biquad filter

This is a hard one and although I can think of a few kludge methods of doing it, I have a feeling there is a clean mathematical method, although I am having difficulty inventing it myself.
I have a number of parameters which control (software) biquad filters for audio. Essentially there are just 3 parameters, frequency, gain and Q (or bandwidth). In audio terms, the frequency represents the center frequency of the filter. The gain represents whether this frequency is boosted or cut (a gain of 0 results in no change to the audio passing through the filter). Q represents the width of the filter - IE a very wide filter might affect frequencies far away from the center frequency, whereas a narrow (low Q) filter will only affect frequencies close to the center frequency.The filters take the form of a bell curve, or at least thats an approximation, whether its mathematically accurate I am not sure.
I want to display the characteristics of these filters graphically - display a graph of gain against frequency. There are several of these filters applied to the audio channel, and I want to be able to add the different result graphs, to produce an overall graph (IE a graph summing all the components of the combined filters). But I also want to be able to access the individual filters graphs.
I can handle adding the component graphs into a single 'total' graph, but how to produce the original x-y graph from the filter parameters escapes me. I will draw bitmaps so all I need is to be able to create arrays of the form frequency[x]=y. Im doing this in C so I don't have the mathematical tools in matlab etc. So I might have a filter with a center frequency of say 1000 (Hz), a gain of say 20 (db or linear I understand how to convert that), and a Q of say 3. The Q factor is relative and does not have to be exactly mathematically correct if that causes any complication.
It seems like a quite simple mathematical function but maths is not my strong point and I don't know enough - I have been messing round with sine functions etc but its not working and I suspect is probably wasting processing power by over complicating the maths (although I might be wrong there).
TIA, Pete
I have my doubts about the relationships between biquad filters, Q values, and bell curves. But I'll put those aside and just tell you how to draw a bell curve, since that's what you asked.
From this wikipedia article, the equation for a bell curve is
where for your application
a corresponds to the gain
b determines the center frequency
2c^2 is related to Q (larger values will make the curve wider)
The C code below computes a sample bell curve. For this example, the numbers were chosen based on drawing into a window that is 250 pixels wide by 200 pixels high, with a coordinate system where the origin {0,0} is at the bottom left corner.
int width = 250;
int height = 200;
int bellCurve[width]; // the output array that holds the f(x) values
double gain = 180; // the 'a' value, determines how high the peak is from the baseline
double offset = 10; // the 'd' value, determines the y coordinate of the baseline
double qFactor = 1000; // the '2c^2' value, determines how fat the curve is
double center = 100; // the 'b' value, determines the x coordinate of the peak
double dx;
for ( int x = 0; x < width; x++ )
{
dx = x - center;
bellCurve[x] = gain * exp( -( dx * dx ) / qFactor ) + offset;
}
Plotting the curve results in an image like this where the peak is at x=100, y=10+180=190
You could input a unit impulse (an array of all zeros, except one element=1.0) into your digital filters, treating them as black boxes. Then FFT the impulse response output array to get the frequency response of the filter. Plotting the magnitude of the complex frequency samples will give you a pretty picture. Python+numpy+matplotlib would probably be an easier way to go about it. You will need to know the sampling period to get meaningful plots.
What you really want is the bode plot of the filter. This is non trivial to calculate yourself, a cursory search for a library to do it for you in C yielded nothing. If accuracy is not important and you can approximate the shape once and stretch it based on the parameters of the particular filter. For example, you might have a normalized array of relative values and construct a new curve (array) based on the parameters of the filter and the base curve you generated earlier.
The base curve could be generated from MATLAB if you can or Wolfram Alpha or something like that.
Here is one in javascript.
http://www.earlevel.com/main/2013/10/13/biquad-calculator-v2/
The filter you describe is the 'peak' filter. Use the log scale to display frequencies.
—Tom

OpenGL rotation and scaling

Does rotation always occur about the origin (0,0,0)?
Does translation always occur relative to previous translation?
Does scaling increase the coordinates axes size?
I suggest that a good way for a beginner is to start by thinking about points rather than 3D objects. Then all the transformation can be thought of as functions to change a point position to a new position.
First imagine an XYZ cartesian coordinate space, then imagine a point (X,Y,Z) in space with origin (0, 0, 0). All OpenGL knows at this stage is the point X,Y,Z. Now you are ready to begin:
Rotation requires an angle and a center of rotation. glRotate allows you to only specify the angles. By virtue of mathematics, conceptually, the center of rotation is at the location (X-X,Y-Y,Z-Z) or (0,0,0).
Translation is just an offset from the current position. Since OpenGL knows your point (X,Y,Z) it simply adds the offest to the position vector. It is therefore more correct to say it is relative to the current position rather than previous translation.
Scaling is a multiplication of the point vector (X.m,Y.m,Z.m) hence it simply just translating that point by a factor of m. Hence conceptually one can say it doesn't change the coordinate axes size.
However, when you start to think in 3D things get abit tricky because you will realise that if you are not careful, the all the points in a single 3D object doesn't always change position in the way you desire relative to each other. You will learn for example that if you want to rotate about the object's center, you will have to "move it to the origin, rotate, and then move it back again". This process of moving it back an forth can be thought as specifying the center of rotation. These are actually mathematical "tricks" that you apply.
Does rotation always occur about the origin (0,0,0)?
Indeed this is the case.
Does translation always occur relative to previous translation?
Does scaling increase the coordinates axes size?
This requires some explanation: OpenGL, and so many other software operating with geometry data don't build a list of chained transformations. What they maintain is one single homogenous transformation matrix.
"Appending" a transformation is done by multiplying the current transformation matrix with the transformation matrix describing the "next" transformation, replacing the old transformation. This also means that a compound transformation matrix, like what you end up having in the OpenGL modelview, may be applied as transformation as well.
To make a long story short, it depends all on the transformation applied. Old OpenGL gives you some basic matrix manipulations. In OpenGL-3 they have been removed, because OpenGL is not a math library, but draws stuff.
So how does such a transformation matrix look like? Like this:
Xx Yx Zx Tx
Xy Yy Zy Ty
Xz Yz Zz Tz
_x _y _z w
Maybe you noticed that there are 3 major columns designated by capital X, Y, Z. Those columns form vectors. And in the case of 3D transformations those are the base vectors of a coordinate system, relative the one the transformation is applied upon. However vectors only give "directions" and a length. So what's needed as well is the relative point of origin of the new coordinate system, and that's what the T vector contains.
Most of the time _x = _y = _z = 0 and w = 1
Transforming a point of geometry happens by multiplying the points vector with the matrix. Let such a matrix be M, the point p, then
p' = M * p
Now assume we chain transformations:
p'' = M' * p' = M' * M * p
We can substitute M_ = M' * M, so
p'' = M_ * p
It's easy to see, that we can chain this arbitrarily long
To answer your two last questions: Transformations (not just translations) do chain. And yes, applying a scaling transform will "scale" the axes.
And to clear up some commong misunderstanding: OpenGL is not a scene graph, it does not deal with "objects", but just lists of geometry. glScale, glTranslate, glRotate don't transform objects, but "chain up" transformation operations.
someone with more experience will surely point you to a good tutorial but your question reflect that you don't understand the 3D graphical pipeline and more precisely the concept of projection matrix (I might have the wrong name here since I studied this ages ago in French lol).
Basically whenever you apply a rotation/translation/scaling you are modifying the same matix
therefor when you each operation modifies the existing state.
For example doing rotation then a translation will give you a different result that translation then rotaiton (try doing the solar system sun earth moon it will help you understand)
regarding your questions:
No the basic rotation will not always occur in 0,0,0. for example if you first translate to 2,3,4 then the rotation will happen in 2,3,4.
the simple answer is yes, you are moving your matrice form its last position.(read my comment at the end for the not the simple answer ^^)
scaling will affect all the transformations done after. example scale 1,2,2 followed by a translation 2,3,4 could be seen as a a global translation 2,6,8
now for the not so simple part:
as explained each change will be affected by the previous changes (example of the scale)
also there is a lot of ways to do the same thing or to alter the behavior, for example:
achieving absolute translation can be done like this
-translate
-create an object
-indentity (reset the matrix to 0)
-translate2
-create object2
My advice is read tutorials but also global 3D programing blogs or a book (red book is good when you start lol)

Angle at corner of two lines

I search for the fastest or simplest method to compute the outer angle at any point of a convex polygon. That means, always the bigger angle, whereas the two angles in question add up to 360 degrees.
Here is an illustration:
Now I know that I may compute the angles between the two vectors A-B and C-B which involves the dot product, normalization and cosine. Then I would still have to determine which of the two resulting angles (second one is 180 degrees minus first one) I want to take two times added to the other one.
However, I thought there might be a much simpler, less tricky solution, probably using the mighty atan2() function. I got stuck and ask you about this :-)
UPDATE:
I was asked what I need the angle for. I need to calculate the area of this specific circle around B, but only of the polygon that is described by A, B, C, ...
So to calculate the area, I need the angle to use the formula 0.5*angle*r*r.
Use the inner-product (dot product) of the vectors describing the lines to get the inner angle and subtract from 360 degrees?
Works best if you already have the lines in point-vector form, but you can get vectors from point-to-point form pretty easily (i.e. by subtraction).
Taking . to be the dot product we have
v . w = |v| * |w| * cos(theta)
where v and w are vectors and theta is the angle between the lines. And the dot product can be computed from the components of the vectors by
v . w = SUM(v_i * w_i : i=0..3) // 3 for three dimensions. Use more or fewer as needed
here the subscripts indicate components.
Having actually read the question:
The angle returned from inverting the dot-product will always be less than 180 degrees, so it is always the inner angle.
Use this formula:
beta = 360° - arccos(<BA,BC>/|BA||BC|)
Where <,> is the scalar product and BA (BC) are the vectors from B to A (B to C).
I need to calculate the area of the circle outside of the polygon that is described by A, B, C, ...
It sounds like you're taking the wrong approach, then. You need to calculate the area of the circumcircle, then subtract the area of the polygon.
If you need the angle there is no way around normalizing the vectors and do a dot or cross-product. You often have a choice if you want to calculate the angle via asin, acos or atan but in the end that does not make a difference to execution speed.
However, It would be nice if you could tell us what you're trying to archive. If we have a better picture of what you're doing we might be able to give you some hints how to solve the problem without calculating the angle at the first place.
Lots of geometric algorithms can be rewritten to work with cross and dot-products only. Euler-angles are rarely needed.

Resources