About avoiding IFs in GLSL - opengl

Somebody knows how to avoid using these IF statements?
float v = 9999.0;
if (a.x > 0.0 && a.x < v) { v = a.x; }
if (a.y > 0.0 && a.y < v) { v = a.y; }
if (a.z > 0.0 && a.z < v) { v = a.z; }
Initially I used the following lines but then I realized I only wanted the minimum iff it does not equal zero.
float v = min(a.x, min(a.y, a.z));
I also assume that a.xyz are always greater or equal than zero, being at least one of the components greater than zero.

You could use a construct like
vec3 b=a+10000.0*step(0.0, -a);
float v=min(b.x, min(b.y, b.z));
which also assumes (as your code does) that your minimal element is < 10000. Note that the step(0,0, -a) was chosen in favour of (1.0-step(0.0, a)) since step is defined to return 0.0 only if the value is below the edge (0.0 in this case), not if it is equal. In pratice it might still be a good idea to use a small epsilon value.

Related

Optimizing Complex Mobius Transformations on a Fragment Shader

I'm developing my own graphics engine to render all sorts of fractals (like my video here for example), and I'm currently working on optimizing my code for Julia Set matings (see this question and my project for more details). In the fragment shader, I use this function:
vec3 JuliaMatingLoop(dvec2 z)
{
...
for (int k = some_n; k >= 0; --k)
{
// z = z^2
z = dcproj(c_2(z));
// Mobius Transformation: (ma[k] * z + mb[k]) / (mc[k] * z + md[k])
z = dcproj(dc_div(cd_mult(ma[k], z) + mb[k], dc_mult(mc[k], z) + md[k]));
}
...
}
And after reading this, I realized that I'm doing Mobius transformations in this code, and (mathematically speaking) I can use matrices to accomplish the same operation. However, the a, b, c, and d constants are all complex numbers (represented as ma[k], mb[k], mc[k], and md[k] in my code), whereas the elements in GLSL matrices contain only real numbers (rather than vec2). And so to my question: is there a way to optimize these Mobius transformations using matrices in GLSL? Or any other way of optimizing this part of my code?
Helper functions (I need to use doubles for this part, so I can't optimize by switching to using floats):
// Squaring
dvec2 c_2(dvec2 c)
{
return dvec2(c.x*c.x - c.y*c.y, 2*c.x*c.y);
}
// Multiplying
dvec2 dc_mult(dvec2 a, dvec2 b)
{
return dvec2(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x);
}
// Dividing
dvec2 dc_div(dvec2 a, dvec2 b)
{
double x = b.x * b.x + b.y * b.y;
return vec2((a.x * b.x + a.y * b.y) / x, (b.x * a.y - a.x * b.y) / x);
}
// Riemann Projecting
dvec2 dcproj(dvec2 c)
{
if (!isinf(c.x) && !isinf(c.y) && !isnan(c.x) && !isnan(c.y))
return c;
return dvec2(infinity, 0);
}
I'm not sure if this will help, but yes you can do complex arithmetic by matrices.
If you regard a complex number z as a real two-vector with components Re(z), Im(z)
Then
A*z + B ~ (Re(A) -Im(A) ) * (Re(z)) + (Re(B))
(Im(A) Re(A) ) (Im(z)) (Im(B))
Of course you actually want
(A*z + B) / (C*z + D)
If you compute
A*z+b as (x)
(y)
C*z+d as (x')
(y')
Then the answer you seek is
inv( x' -y') * ( x)
( y' x' ) ( y)
i.e
(1/(x'*x'+y'*y')) * (x' y') * (x)
(-y' x') (y)
One thing to note, though, is that in these formulae, as in your code, division is not implemented as robustly as it could be. The trouble lies in evaluating b.x * b.x + b.y * b.y. This could overflow to infinity, or underflow to 0, even though the result of division could be quite reasonable. A commonly used way round this is Smith's method eg here and if you search for 'robust complex division' you'll find more recent work. Often this sort of thing matters little, but if you are iterating off to infinity it could make a difference.

Quadratic Algebra advice for Array like return function

I have a problem. I want to write a method, which uses the PQ-Formula to calculate Zeros on quadratic algebra.
As I see C++ doesn't support Arrays, unlike C#, which I use normally.
How do I get either, ZERO, 1 or 2 results returned?
Is there any other way without Array, which doesn't exists?
Actually I am not into pointers so my actual code is corrupted.
I'd glad if someone can help me.
float* calculateZeros(float p, float q)
{
float *x1, *x2;
if (((p) / 2)*((p) / 2) - (q) < 0)
throw std::exception("No Zeros!");
x1 *= -((p) / 2) + sqrt(static_cast<double>(((p) / 2)*((p) / 2) - (q)));
x2 *= -((p) / 2) - sqrt(static_cast<double>(((p) / 2)*((p) / 2) - (q)));
float returnValue[1];
returnValue[0] = x1;
returnValue[1] = x2;
return x1 != x2 ? returnValue[0] : x1;
}
Actualy this code is not compilable but this is the code I've done so far.
There are quite a fiew issues with; at very first, I'll be dropping all those totally needless parentheses, they just make the code (much) harder to read:
float* calculateZeros(float p, float q)
{
float *x1, *x2; // pointers are never initialized!!!
if ((p / 2)*(p / 2) - q < 0)
throw std::exception("No Zeros!"); // zeros? q just needs to be large enough!
x1 *= -(p / 2) + sqrt(static_cast<double>((p / 2)*(p / 2) - q);
x2 *= -(p / 2) - sqrt(static_cast<double>((p / 2)*(p / 2) - q);
// ^ this would multiply the pointer values! but these are not initialized -> UB!!!
float returnValue[1];
returnValue[0] = x1; // you are assigning pointer to value here
returnValue[1] = x2;
return x1 != x2 ? returnValue[0] : x1;
// ^ value! ^ pointer!
// apart from, if you returned a pointer to returnValue array, then you would
// return a pointer to data with scope local to the function – i. e. the array
// is destroyed upon leaving the function, thus the pointer returned will get
// INVALID as soon as the function is exited; using it would again result in UB!
}
As is, your code wouldn't even compile...
As I see C++ doesn't support arrays
Well... I assume you meant: 'arrays as return values or function parameters'. That's true for raw arrays, these can only be passed as pointers. But you can accept structs and classes as parameters or use them as return values. You want to return both calculated values? So you could use e. g. std::array<float, 2>; std::array is a wrapper around raw arrays avoiding all the hassle you have with the latter... As there are exactly two values, you could use std::pair<float, float>, too, or std::tuple<float, float>.
Want to be able to return either 2, 1 or 0 values? std::vector<float> might be your choice...
std::vector<float> calculateZeros(float p, float q)
{
std::vector<float> results;
// don't repeat the code all the time...
double h = static_cast<double>(p) / 2; // "half"
s = h * h; // "square" (of half)
if(/* s greater than or equal q */)
{
// only enter, if we CAN have a result otherwise, the vector remains empty
// this is far better behaviour than the exception
double r = sqrt(s - q); // "root"
h = -h;
if(/* r equals 0*/)
{
results.push_back(h);
}
else
{
results.reserve(2); // prevents re-allocations;
// admitted, for just two values, we could live with...
results.push_back(h + r);
results.push_back(h - r);
}
}
return results;
}
Now there's one final issue left: as precision even of double is limited, rounding errors can occur (and the matter is even worth if using float; I would recommend making all floats to doubles, parameters and return values as well!). You shouldn't ever compare for exact equality (someValue == 0.0), but consider some epsilon to cover badly rounded values:
-epsilon < someValue && someValue < +epsilon
Ok, in given case, there are two originally exact comparisons involved, we might want to do as little epsilon-comparisons as possible. So:
double d = r - s;
if(d > -epsilon)
{
// considered 0 or greater than
h = -h;
if(d < +epsilon)
{
// considered 0 (and then no need to calculate the root at all...)
results.push_back(h);
}
else
{
// considered greater 0
double r = sqrt(d);
results.push_back(h - r);
results.push_back(h + r);
}
}
Value of epsilon? Well, either use a fix, small enough value or calculate it dynamically based on the smaller of the two values (multiply some small factor to) – and be sure to have it positive... You might be interested in a bit more of information on the matter. You don't have to care about not being C++ – the issue is the same for all languages using IEEE754 representation for doubles.

Is it possible generate normal map from heightmap texture from math point of view?

My view is that you can not generate normal map only from height map texture?
Am I right or not?
Math Arguments:
Assume that surface is given a continuous bijection from
S = [0,1]
T = [0,1]
Let's call SxT as image space.
It can be proved from differentional geometry that normal to that parametric surface is
If assume that mapping from SxT image space to geometric euclidian space is very simple then we can retrive:
Then you can calculate such partial derivatives with some difference scheme.
We came to that simple formula, only with bold suggestion and this suggestion is absolutely not true.
Sample of the problem from graphics.
Let assume we have triangle in geometric eclidian space with 3 vertices.
Terms are:
normalmap --
it is normal for point with (u,v,1-u-v) barycentric coordinates fetched from (u,v) from suitable 2d texture, and it is in local coord. system relative to triangle.
heihtmap --
it is geometric offset for point with (u,v,1-u-v) barycentric coordinates in normal direction relative to triangle localspace fetched from (u,v) from suitable 2d texture.
During building normalmap we absolutely ignore how heightmap is distributed near (u,v,1-u-v) eculidian point. And we retrive only some approximation of normal map.
Ohh, looks like my comment was too brief.
It's easier to write a full answer with code to describe the method.
I'm going to use a pseudocode mix of C++ and GLSL.
constexpr int width = 32, height = 32;
constexpr float height_scale = 16.0f; // Change if necessary.
float hmap[W][H] = {...};
float normalmap[W][H];
vec3 GetPoint(ivec2 a)
{
a.x %= W;
a.y %= H;
return {a.x, a.y, hmap[a.x][a.y] * height_scale};
}
vec3 GetNormal(ivec2 a, bool loop_hmap)
{
vec3 o = GetPoint(a),
a = GetPoint({a.x + 1, a.y}),
b = GetPoint({a.x, a.y + 1}),
c = GetPoint({a.x - 1, a.y}),
d = GetPoint({a.x, a.y - 1});
vec3 n1 = normalize(cross(a-o, b-o));
vec3 n2 = normalize(cross(b-o, c-o));
vec3 n3 = normalize(cross(c-o, d-o));
vec3 n4 = normalize(cross(d-o, a-o));
if (loop_hmap)
return normalize(n1+n2+n3+n4);
else
{
vec3 sum = {0,0,0};
bool b1 = (a.x+1 >= 0 && a.y >= 0 && a.x+1 < W && a.y < H);
bool b2 = (a.x >= 0 && a.y+1 >= 0 && a.x < W && a.y+1 < H);
bool b3 = (a.x-1 >= 0 && a.y >= 0 && a.x-1 < W && a.y < H);
bool b4 = (a.x >= 0 && a.y-1 >= 0 && a.x < W && a.y-1 < H);
if (b1 && b2) sum += n1;
if (b2 && b3) sum += n2;
if (b3 && b4) sum += n3;
if (b4 && b1) sum += n4;
return normalize(sum);
}
}
int main()
{
for (int i = 0; i < H; i++)
for (int j = 0; j < W; j++)
normalmap[j][i] = GetNormal(j, i, 0);
}
loop_hmap argument of GetNormal() changes how the function computes normals for edge pixels. 1 should be used for tiled textures, like sand and water. 0 should be used for nontiled textures, like items, mobs, trees.
For me my own initial question is invalid and it has a bug!!!
I – original parametric surface with domain as cartesian product of [0,1] and range of it as euclidean space
II - normal to original surface
III - modified original surface with heightmap
IV - normal map which we want to receive with even ignoring geometric modification of the surface by “III”
Final step IV includes a lot of stuff to differentiate: H(s,t) and original definition of the function...I don't perform futher analytic of that equations...But as for me you can't generate normalmap only from (heightmap)...
P.S. To perform futher analytics if you want to do it retrive *.docx file from that place https://yadi.sk/d/Qqx-jO1Ugo3uL As I know it impossible to convert formulas in ms word to latex, but in any case please use it asa draft.

sorting a vector not obeying sort function

I'm trying to sort a vector of points in clockwise order around 0,0 based on Sort points in clockwise order? .
The logic of the sort function makes sense and checks out when I manually calculate the results for individual points. However, the resulting vector does not appear to be sorted according to the sort function. For instance, here are the first 4 elements after one particular run of the sort:
[22.3701,450.519,-1045] <- correct
[-22.429,-29.0513,-1006] <- should be in position 2
[-147.806,65.0482,-1095] <- should be in position 3
[68.0652,590.091,-942] <- should be in position 1
This case should be caught by the first guard clause of the sort algorithm:
if ( a.x >= 0 && b.x < 0 ) return true
becomes:
if ( 68.0652 >= 0 && -22.429 < 0 ) return true
which should certainly sort the (68.0652,590.091) point higher.
Here's my implementation of the sort function, simplified because my center point is (0,0):
bool sortVectorsClockwise( const Vec3f &a, const Vec3f &b )
{
if ( a.x >= 0 && b.x < 0 ) return true;
if ( a.x == 0 && b.x == 0 ) return a.y > b.y;
float det = a.x * b.y - b.x * a.y;
if ( det < 0 ) return true;
if ( det > 0 ) return false;
// points a and b are on the same line from the center, check which is
// closer to the center
return a.xy().length() > b.xy().length();
}
and I call and print the results like this:
sort( points.begin(), points.end(), sortVectorsClockwise );
for ( auto &p : points ) {
cout << p << endl;
}
I'm compiling using XCode 4.6, LLVM 4.2, C++11.
As I suspected (actually worse than I suspected). I tried this code
int main()
{
Vec3f a(22.3701, 450.519, -1045);
Vec3f b(-22.429,-29.0513,-1006);
if (sortVectorsClockwise(a, b))
cout << "a<b\n";
if (sortVectorsClockwise(b, a))
cout << "b<a\n";
}
The output is
a<b
b<a
In other words your sort function is saying that one value is less than another and vice versa. Obviously no sorting algorithm can handle that.

C++ floating point comparison

Suppose you have have a rectangle, bottom-left point 0,0 and upper-right point is 100,100.
Now two line intersects the rectangle. I have to find out the coordinate of the intersection point. I have done that. Now the problem is I can't tell whether it is inside the rectangle or not. I used double comparison. But I think it is giving me wrong answer. Suppose the intersection point is ( x , y ). I used this checking for comparison : if( x >= 0.0 && x <= 100.0 && y >= 0.0 && y <= 100.0 ). What should I do?
//this function generates line
line genline( int x1 , int y1 , int x2 , int y2 ){
line l ;
l.A = y2 - y1 ;
l.B = x1 - x2 ;
l.C = l.A * x1 + l.B * y1 ;
return l ;
}
//this function checks intersection
bool intersect( line m ,line n ) {
int det = m.A * n.B - m.B * n.A ;
if( det == 0 ){
return false ;
}
else {
double x = ( n.B * m.C - m.B * n.C ) / ( det * 1.0 ) ;
double y = ( m.A * n.C - n.A * m.C ) / ( det * 1.0 ) ;
if( x >= 0.0 && x <= L && y >= 0.0 && y <= W ) { return true ; }
else{ return false ; }
}
}
EDIT:
Both the line are stretched to infinity.
Your math looks like it's right. By the way, If a line intersects something, it is always inside that something.
Checking to see if a point is inside a rectangle is relatively easy. However, the challenge is to find the intersection between two line segments. There are a large number of corner cases to that problem and limited accuracy of floating point numbers play a huge roll here.
Your algorithm seems to be overly simplistic. For a deeper discussion about this topic you can look at this and this. This two parts article investigates the problem of finding the intersection of two lines using floating point numbers. Notice that they are about MATLAB not C++ though that does not change the problem and the algorithms are easily translatable to any language.
Depending on application, even with clever tricks floating point representation might not simply cut it for some geometry problems. CGAL is a C++ library dedicated to computational geometry that deals with these kind problems. When necessary it uses arbitrary precision arithmetic to handle degenerate cases.
When you're dealing with floating point (or double), testing for equality is naïve and will fail in edge cases. Every comparison you make should be in reference to "epsilon", an extremely small quantity that doesn't matter. If two numbers are within epsilon for each other, then they are considered equal.
For example, instead of "if(a == b)", you need:
bool isEqual(double a, double b, double epsilon = 1.E-10)
{ return fabs(a - b) <= epsilon;
}
Pick a suitable value for epsilon depending on your problem domain.