Examples on scalar distance field or directed distance field? - graphics

I come across the scalar distance field and directed distance field in this paper Feature Sensitive Surface Extraction from Volume Data.
What is the difference and can anyone provide an example. Thanks a lot.

from http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
I figured it out...
directed distance will be
If a Sphere is defined as follow
float sdSphere( vec3 p, float s )
{
return length(p)-s;
}
Given any point
vec3 a
in the space, The directed distance will has direction
a - p
with signed distance
sdSphere(a, s)
scalar distance will be
Sphere - signed - exact
float sdSphere( vec3 p, float s )
{
return length(p)-s;
}
Sphere - unsigned - exact
float sdSphere( vec3 p, float s )
{
return abs(length(p)-s);
}

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?

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

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.

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);
}

How do you calculate the angle between two normals in glsl?

How do you calculate the angle between two normals in glsl? I am trying to add the fresnel effect to the outer edges of an object (combining that effect with phong shading), and I think that the angle is the only thing I am missing.
Fragment Shader:
varying vec3 N;
varying vec3 v;
void main(void) {
v = vec3(gl_ModelViewMatrix * gl_Vertex);
N = normalize(gl_NormalMatrix * gl_Normal);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Vertex Shader:
varying vec3 N;
varying vec3 v;
void main(void) {
vec3 L = normalize(gl_LightSource[0].position.xyz - v);
vec3 E = normalize(-v);
vec3 R = normalize(-reflect(L,N));
vec4 Iamb = gl_FrontLightProduct[0].ambient
vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);
vec4 Ispec = gl_FrontLightProduct[0].specular * pow(max(dot(R,E),0.0), gl_FrontMaterial.shininess);
vec4 Itot = gl_FrontLightModelProduct.sceneColor + Iamb + Idiff + Ispec;
vec3 A = //calculate the angle between the lighting direction and the normal//
float F = 0.33 + 0.67*(1-cos(A))*(1-cos(A))*(1-cos(A))*(1-cos(A))*(1-cos(A));
vec4 white = {1.0, 1.0, 1.0, 1.0};
gl_FragColor = F*white + (1.0-F)*Itot;
}
varying vec3
dot product between two vectors will return the cosine of the angle (in GLSL it's dot(a,b)). Taking arc-cosine of that will return angle in radians (in GLSL it's acos(x)).
Dot product is very cheap, arc-cosine is quite expensive.
However, Fresnel effect does not really need the angle. Just having dot result between the vectors is enough. There are many approximations for the Fresnel effect, one of the cheapest is just using the dot directly. Or squaring it (x*x), or raising to some other power.
In your shader above, it looks like you just want to raise dot to 5th power. Something like:
float oneMinusDot = 1.0 - dot(L, N);
float F = pow(oneMinusDot, 5.0);
From the dot product of two vectors you can get the cosine of the angle between them
cos A = DotProduct(v1, v2) / (Length(v1) * Length(v2))
Using this, you don't need to calculate the cosine when calculating F. Since your vectors are unit vectors, e.g., have length one, you can even avoid the division.

Resources