how do I get rotations of each axis from rotations with a vector axis? - graphics

so I have an AxisAngle4f object with a vector3D as axis and an angle, how do I get rotation angle for each of x,y,z axes?

create 4x4 homogenous transform matrix representing your rotation
first see Understanding 4x4 homogenous transform matrices so basically you want 3 basis vectors and origin of unit matrix then rotate each by your rotation (for that you can use this or glRotate or whatever). Here C++ example:
void rotate3d(float alfa,float *axis,float *point)
{
float p[3],q[3],c=cos(alfa),s=sin(alfa);
//Euler Rodrigues' rotation formula
vector_mul(q,point,c);
vector_mul(p,axis,point);
vector_mul(p,p,s);
vector_add(p,p,q);
vector_mul(q,axis,vector_mul(axis,point)*(1.0-c));
vector_add(point,p,q);
}
The vector math functions are described (with source) in the link above. Just change the double into float as you are using those. So it boils up to something like this in C++:
float X[3] = { 1.0,0.0,0.0 };
float Y[3] = { 0.0,1.0,0.0 };
float Z[3] = { 0.0,0.0,1.0 };
float O[3] = { 0.0,0.0,0.0 };
float M[16];
float AxisAngle4f[4]={x,y,z,angle};
rotate3d(AxisAngle4f[3],AxisAngle4f,X);
rotate3d(AxisAngle4f[3],AxisAngle4f,Y);
rotate3d(AxisAngle4f[3],AxisAngle4f,Z);
rotate3d(AxisAngle4f[3],AxisAngle4f,O);
M[0]=X[0]; M[4]=Y[0]; M[ 8]=Z[0]; M[12]=O[0];
M[1]=X[1]; M[5]=Y[1]; M[ 9]=Z[1]; M[13]=O[1];
M[2]=X[2]; M[6]=Y[2]; M[10]=Z[2]; M[14]=O[2];
M[3]= 0.0; M[7]= 0.0; M[11]= 0.0; M[15]= 1.0;
Where M is OpenGL style direct matrix representing your rotation.
convert M into your Euler angles
see Is there a way to calculate 3D rotation on X and Y axis from a 4x4 matrix on how (again change to floats)...
const float deg=M_PI/180.0;
const float rad=180.0/M_PI;
// variables
float e[3],m[16];
int euler_cfg[_euler_cfgs];
// init angles
e[0]=10.0*deg;
e[1]=20.0*deg;
e[2]=30.0*deg;
// compute coresponding rotation matrix with your environment
m = some_rotate_of yours(e)
// cross match e,m -> euler_cfg
matrix2euler_init(e,m,euler_cfg);
// now we can convert M into e
matrix2euler(e,M,euler_cfg);
// e holds your euler angles you want
The init of euler_cfg is needed just once then you can use matrix2euler at will.

Related

2D Signed distance function of simplex noise

I'm using simplex noise to generate a 2D terrain.
Here is the simplex noise.
Pixel shader code:
float GetNoise2D(float x, float y = 1, int seed = 1337, float frequency = 0.1);
float4 color (float2 position)
{
return position.y <= GetNoise2D(position.x) ? color.brown : color.black;
}
Now how do I get the Signed distance function(sdf) from a point P to the terrain?
Currently I'm shooting a ray in all direction from the point and check if it collides a brown pixel and get the shortest distance of all collided pixel (which is a very naive approach). any help?

ray traversing in 3D ray casting algorithm

I am working on volumetric raycasting and I am having a hard time finding the way to calculate the step size so that every step, the ray would step to a new voxel in my fragment shader GLSL.
I have a 3D box of dimension which doesn't have equal dimension on all side (x,y,z) and I already have that value and I also have a vec3 ray direction.
I need to know the step size for the ray or normalized ray to traverse from the starting and end of the hitting point in the cube.
From the axis-aligned box intersection, I know the tmin and tmax.
I know the code of AABI is irrelevant but I am adding this for any reference if needed.
vec2 boxIntersection(vec3 ray_direction2, float origin[3]){
float boxmin[3] = float[3](0.0, 0.0, 0.0);
float boxmax[3] = float[3](1.0, 1.0, 1.0);
vec3 invdir = 1.0/ray_direction2;
float inv_raydirection[3] = float[3](invdir.x, invdir.y, invdir.z);
for(int i=0; i<3; i++ ){
float t1 = (boxmin[i]-origin[i])*inv_raydirection[i];
float t2 = (boxmax[i]-origin[i])*inv_raydirection[i];
tmin = min(tmin, min(t1, t2));
tmax = max(tmax, max(t1, t2));
if(tmax>max(tmin,0.0)){
return vec2(tmin, tmax);
}
else{
discard;
}
}

Converting X, Z coords to RGB using GLSL shaders

I have a Three js scene that contains a 100x100 plane centred at the origin (ie. min coord: (-50,-50), max coord: (50,50)). I am trying to have the plane appear as a colour wheel by using the x and z coords in a custom glsl shader. Using this guide (see HSB in polar coordinates, towards the bottom of the page) I have gotten my
Shader Code with Three.js Scene
but it is not quite right.
I have played around tweaking all the variables that make sense to me, but as you can see in the screenshot the colours change twice as often as what they should. My math intuition says just divide the angle by 2 but when I tried that it was completely incorrect.
I know the solution is very simple but I have tried for a couple hours and I haven't got it.
How do I turn my shader that I currently have into one that makes exactly 1 full colour rotation in 2pi radians?
EDIT: here is the relevant shader code in plain text
varying vec3 vColor;
const float PI = 3.1415926535897932384626433832795;
uniform float delta;
uniform float scale;
uniform float size;
vec3 hsb2rgb( in vec3 c ){
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
6.0)-3.0)-1.0,
0.0,
1.0 );
rgb = rgb*rgb*(3.0-2.0*rgb);
return c.z * mix( vec3(1.0), rgb, c.y);
}
void main()
{
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
float r = 0.875;
float g = 0.875;
float b = 0.875;
if (worldPosition.y > 0.06 || worldPosition.y < -0.06) {
vec2 toCenter = vec2(0.5) - vec2((worldPosition.z+50.0)/100.0, (worldPosition.x+50.0)/100.0);
float angle = atan(worldPosition.z/worldPosition.x);
float radius = length(toCenter) * 2.0;
vColor = hsb2rgb(vec3((angle/(PI))+0.5,radius,1.0));
} else {
vColor = vec3(r,g,b);
}
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_PointSize = size * (scale/length(mvPosition.xyz));
gl_Position = projectionMatrix * mvPosition;
}
I have discovered that the guide I was following was incorrect. I wasn't thinking about my math properly but I now know what the problem was.
atan has a range from -PI/2 to PI/2 which only accounts for half of a circle. When worldPosition.x is negative atan will not return the correct angle since it is out of range of the function. The angle needs to be adjusted based on what quadrant it is in the plane.
Q1: do nothing
Q2: add PI to the angle
Q3: add PI to the angle
Q4: add 2PI to the angle
After this normalize the angle (divide by 2PI) then pass it to the hsb2rgb function.

Calculate signed distance between point and rectangle

I'm trying to write a function in GLSL that returns the signed distance to a rectangle. The rectangle is axis-aligned. I feel a bit stuck; I just can't wrap my head around what I need to do to make it work.
The best I came up with is this:
float sdAxisAlignedRect(vec2 uv, vec2 tl, vec2 br)
{
// signed distances for x and y. these work fine.
float dx = max(tl.x - uv.x, uv.x - br.x);
float dy = max(tl.y - uv.y, uv.y - br.y);
dx = max(0.,dx);
dy = max(0.,dy);
return sqrt(dx*dx+dy*dy);
}
Which produces a rectangle that looks like:
The lines show distance from the rectangle. It works fine but ONLY for distances OUTSIDE the rectangle. Inside the rectangle the distance is a static 0..
How do I also get accurate distances inside the rectangle using a unified formula?
How about this...
float sdAxisAlignedRect(vec2 uv, vec2 tl, vec2 br)
{
vec2 d = max(tl-uv, uv-br);
return length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y));
}
Here's the result, where green marks a positive distance and red negative (code below):
Breakdown:
Get the signed distance from x and y borders. u - left and right - u are the two x axis distances. Taking the maximum of these values gives the signed distance to the closest border. Viewing d.x and d.y are shown individually in the images below.
Combine x and y:
If both values are negative, take the maximum (i.e. closest to a border). This is done with min(0.0, max(d.x, d.y)).
If only one value is positive, that's the distance we want.
If both values are positive, the closest point is a corner, in which case we want the length. This can be combined with the above case by taking the length anyway and making sure both values are positive: length(max(vec2(0.0), d)).
These two parts to the equation are mutually exclusive, i.e. only one will produce a non-zero value, and can be summed.
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord.xy / iResolution.xy;
uv -= 0.5;
uv *= vec2(iResolution.x/iResolution.y,1.0);
uv += 0.5;
float d = sdAxisAlignedRect(uv, vec2(0.3), vec2(0.7));
float m = 1.0 - abs(d)/0.1;
float s = sin(d*400.0) * 0.5 + 0.5;
fragColor = vec4(s*m*(-sign(d)*0.5+0.5),s*m*(sign(d)*0.5+0.5),0,1);
}

Determining a spheres vertices via polar coordinates, and rendering it

I am working with OpenGL ES 2.0 on an Android device.
I am trying to get a sphere up and running and drawing. Currentley, I almost have a sphere, but clearly it's being done very, very wrong.
In my app, I hold a list of Vector3's, which I convert to a ByteBuffer along the way, and pass to OpenGL.
I know my code is okay, since I have a Cube and Tetrahedron drawing nicley.
What two parts I changed were:
Determing the vertices
Drawing the vertices.
Here are the code snippits in question. What am I doing wrong?
Determining the polar coordinates:
private void ConstructPositionVertices()
{
for (float latitutde = 0.0f; latitutde < (float)(Math.PI * 2.0f); latitutde += 0.1f)
{
for (float longitude = 0.0f; longitude < (float)(2.0f * Math.PI); longitude += 0.1f)
{
mPositionVertices.add(ConvertFromSphericalToCartesian(1.0f, latitutde, longitude));
}
}
}
Converting from Polar to Cartesian:
public static Vector3 ConvertFromSphericalToCartesian(float inLength, float inPhi, float inTheta)
{
float x = inLength * (float)(Math.sin(inPhi) * Math.cos(inTheta));
float y = inLength * (float)(Math.sin(inPhi) * Math.sin(inTheta));
float z = inLength * (float)Math.cos(inTheta);
Vector3 convertedVector = new Vector3(x, y, z);
return convertedVector;
}
Drawing the circle:
inGL.glDrawArrays(GL10.GL_TRIANGLES, 0, numVertices);
Obviously I omitted some code, but I am positive my mistake lies in these snippits somewhere.
I do nothing more with the points than pass them to OpenGL, then call Triangles, which should connect the points for me.. right?
EDIT:
A picture might be nice!
your z must be calculated using phi. float z = inLength * (float)Math.cos(inPhi);
Also,the points generated are not triangles so it would be better to use GL_LINE_STRIP
Using triangle strip on Polar sphere is as easy as drawing points in pairs, for example:
const float GL_PI = 3.141592f;
GLfloat x, y, z, alpha, beta; // Storage for coordinates and angles
GLfloat radius = 60.0f;
const int gradation = 20;
for (alpha = 0.0; alpha < GL_PI; alpha += GL_PI/gradation)
{
glBegin(GL_TRIANGLE_STRIP);
for (beta = 0.0; beta < 2.01*GL_PI; beta += GL_PI/gradation)
{
x = radius*cos(beta)*sin(alpha);
y = radius*sin(beta)*sin(alpha);
z = radius*cos(alpha);
glVertex3f(x, y, z);
x = radius*cos(beta)*sin(alpha + GL_PI/gradation);
y = radius*sin(beta)*sin(alpha + GL_PI/gradation);
z = radius*cos(alpha + GL_PI/gradation);
glVertex3f(x, y, z);
}
glEnd();
}
First point entered is as follows the formula, and the second one is shifted by the single step of alpha angle (from the next parallel).

Resources