I’ve recently had a need to simultaneously render using both DirectX and OpenGL. There are a number of reasons why this is useful, particularly in tools where you may wish to compare multiple rendering engines simultaneously. With this technique it is also possible to efficiently perform some rendering operations on one API to a render target, and switch to the other API to continue rendering to that render target. It can also be used to perform all rendering in a specific API, while presenting that final render target using another API. Providing direct access to textures and render targets in graphics memory regardless of API has the potential of efficiently pipelining surfaces through multiple discrete renderers.

It’s been too long! Here’s an effect I was taking a look at a few months ago.

So there is this cool technique that had gained significant popularity in the demoscene called “Signed Distance Fields”. There’s a truly excellent presentation by iq of rgba (Iñigo Quilez) posted on his website http://www.iquilezles.org which he presented at nvscene back in 2008 called “Rendering Worlds with Two Triangles”. I wanted to play around with some GLSL and thought this would be a really interesting algorithm to take a look at. You can see some of the power of these types of functions in a presentation that smash of fairlight (Matt Swaboda) gave at GDC earlier this year http://directtovideo.wordpress.com.

So here’s an extremely basic GLSL shader I made to learn exactly how the distance fields work. A frequent question when working with signed distance fields, is why march through the scene if you already know the exact distance from your viewpoint to the surface of an object? Well, if you consider the path of a ray fired into a scene, in order to determine the intersection point of that that ray with the implicitly defined surface of one out of many objects, a great deal of math would be involved to determine the exact intersection point; too much for a real time application. The signed distance fields are a way to describe geometry by providing a distance from a given point in 3d space for the entire scene. Combined with ray marching, we can start at the camera and step at least the distance to the nearest surface, but in the direction of the ray. If the ray pointed directly into that nearest surface, the ray would return the intersection point in 3D space. Otherwise, we can run the equation again given a point in 3D space that is that distance along the ray to find a value for the nearest surface. March again, test for intersection, return if we intersected, otherwise continue marching.

To really solidify the algorithm in my brain, I wrote up this little shader. The only input I use is the window dimensions, which are only used for coloring. I hope to soon add shadow computations to provide a true 3D look.

// Distance functions from:

// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm

uniform vec2 resolution;

vec3 translate(in vec3 pos, in vec3 translate)

{

mat4 transform = mat4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);

transform[3][0] = translate.x;

transform[3][1] = translate.y;

transform[3][2] = translate.z;

return vec3(inverse(transform) * vec4(pos,1));

}

vec3 scale(in vec3 pos, in float scale)

{

mat4 transform = mat4(scale,0,0,0,0,scale,0,0,0,0,scale,0,0,0,0,scale);

return vec3(inverse(transform) * vec4(pos,1));

}

vec3 repeat(in vec3 pos, in vec3 repeat)

{

return mod(pos, repeat) - 0.5 * repeat;

}

float sdSphere(in vec3 pos, in float scale)

{

return length(pos) - scale;

}

float udBox(in vec3 pos, in vec3 corner)

{

return length(max(abs(pos) - corner, 0.0));

}

float raymarch(in vec3 ro, in vec3 rd)

{

float epsilon = 0.0001;

float farplane = 30;

vec3 raypos = 0;

vec3 boxCorner = vec3(1.0, 0.2, 0.7);

float sphereScale = 0.7;

vec3 repeatDelta = vec3(5, 5, 5);

for (float t = 0; t < farplane;)

{

raypos = ro + t*rd;

float h = min( udBox(repeat(translate(raypos, vec3(-0.5, 0.5, 0)), repeatDelta), boxCorner),

sdSphere(repeat(raypos, repeatDelta), sphereScale)); // distance to nearest object

t += h;

if (h < epsilon)

{

return t;

}

}

return -1.0;

}

void main()

{

// normalize pixel position

vec2 uv = gl_FragCoord.xy/resolution.xy;

// generate a ray with origin ro and direction rd

vec3 ro = vec3(0.0, 0.0, 2.0);

float aspect = 1.6; // resolution.x/resolution.y

vec3 rd = normalize(vec3((-1.0+2.0*uv)*vec2(aspect,1.0), -1.0));

// fire the ray and intersect with the scene

float t = raymarch(ro, rd);

// draw black by default

vec3 col = vec3(0.0);

if (t > 0.0)

{

// if intersection, draw color

col = vec3(uv.x, 0, uv.y);

}

gl_FragColor = vec4(col, 1.0);

}

// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm

uniform vec2 resolution;

vec3 translate(in vec3 pos, in vec3 translate)

{

mat4 transform = mat4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);

transform[3][0] = translate.x;

transform[3][1] = translate.y;

transform[3][2] = translate.z;

return vec3(inverse(transform) * vec4(pos,1));

}

vec3 scale(in vec3 pos, in float scale)

{

mat4 transform = mat4(scale,0,0,0,0,scale,0,0,0,0,scale,0,0,0,0,scale);

return vec3(inverse(transform) * vec4(pos,1));

}

vec3 repeat(in vec3 pos, in vec3 repeat)

{

return mod(pos, repeat) - 0.5 * repeat;

}

float sdSphere(in vec3 pos, in float scale)

{

return length(pos) - scale;

}

float udBox(in vec3 pos, in vec3 corner)

{

return length(max(abs(pos) - corner, 0.0));

}

float raymarch(in vec3 ro, in vec3 rd)

{

float epsilon = 0.0001;

float farplane = 30;

vec3 raypos = 0;

vec3 boxCorner = vec3(1.0, 0.2, 0.7);

float sphereScale = 0.7;

vec3 repeatDelta = vec3(5, 5, 5);

for (float t = 0; t < farplane;)

{

raypos = ro + t*rd;

float h = min( udBox(repeat(translate(raypos, vec3(-0.5, 0.5, 0)), repeatDelta), boxCorner),

sdSphere(repeat(raypos, repeatDelta), sphereScale)); // distance to nearest object

t += h;

if (h < epsilon)

{

return t;

}

}

return -1.0;

}

void main()

{

// normalize pixel position

vec2 uv = gl_FragCoord.xy/resolution.xy;

// generate a ray with origin ro and direction rd

vec3 ro = vec3(0.0, 0.0, 2.0);

float aspect = 1.6; // resolution.x/resolution.y

vec3 rd = normalize(vec3((-1.0+2.0*uv)*vec2(aspect,1.0), -1.0));

// fire the ray and intersect with the scene

float t = raymarch(ro, rd);

// draw black by default

vec3 col = vec3(0.0);

if (t > 0.0)

{

// if intersection, draw color

col = vec3(uv.x, 0, uv.y);

}

gl_FragColor = vec4(col, 1.0);

}

It only took two weeks, but I sorted out (almost) all the kinks with bullet physics. Check it out:

I just wanted to post a quick sneak peek of what I’ve been working on this past week: integrating bullet physics. Below is just a test, it doesn’t use the full particle system yet (so the framerate suffers greatly due to the naive method used for drawing cubes).

Check out the physics library here: http://bulletphysics.org

This update adds the ability to create shapes using a particle collector. The physics for each particle is calculated independently for individual destinations; they do not need to have the same destination. This allows me to specify any number of destinations, which can be moved independently. Because the physics system takes care of tweening between positions, the collector destinations can jump from place to place, and the physics will result in a fluid animation.

Well, it turns out I was able to guarantee the destination of particles by a deadline. This requires a little bit of cheating; as the lifetime of the particle advances, the velocity vector dictated by the physics is blended with a velocity vector of the same magnitude pointing directly at the destination. This, in combination with a maximum velocity can virtually guarantee that the particle will hit its destination by a specific time. If the velocity vector is blended to point directly at the destination by half the lifetime, and the forces acting on the particle only contribute to increase the velocity towards the destination regardless of its position, then the particle is guaranteed to hit the destination by the end of its life.

Attempt number 2 at getting particles to stick to a collector: apply gravitational pull to the collector. The ideal is simple; the closer a particle gets to the collector, the greater the force of gravity acting on the particle towards that collector. In this case, I used the inverse of the distance squared. This produces an “Ideal” orbital pattern as shown below:

D3DXVECTOR3 Collector::GetIdealOrbitalForce(const D3DXVECTOR3& magVector,

const float& magLength)

{

float grav = 1000.0f;

D3DXVECTOR3 force = magVector * grav;

if(magLength > 1)

{

force /= (magLength * magLength);

}

return force;

}

const float& magLength)

{

float grav = 1000.0f;

D3DXVECTOR3 force = magVector * grav;

if(magLength > 1)

{

force /= (magLength * magLength);

}

return force;

}

I saw a video online recently of several cubes flying into the scene and stacking up to form a larger cube. A pretty simple yet powerful effect. The effect was achieved using Particle Flow, so the movement of the particles are entirely animated. Check it out below:

After seeing this, I immediately wanted to try it, but with a more general solution. So, off I went to write a physics system for my particle engine. Now, there are a lot of challenges in getting a particle rocketing through 3D space to land in exactly the right position with physics alone. There are a few options. With physics, we can exponentially increase a force on the particle in the direction of the destination with relation to the distance from the destination. Another possibility is merging a pure physics system with a pure spline animation to allow a random initial velocity, but a guaranteed stopping point.

My first step however, is developing some way to attract the particles to their destination. I decided to start with a spring system. Although the system will exert forces on the particles to aim the particles at the destination, it is very unlikely that they will pass directly through a predetermined point, and instead orbit around the destination.

For those interested, here’s the nice little gem used to compute the spring force. I modified this algorithm from a cloth simulator used in the book “Physics for Game Developers”.

D3DXVECTOR3 Collector::GetForce(Particle particle)

{

D3DXVECTOR3 forceVector = GetVector(particle); // From particle to destination

float length = D3DXVec3Length(&forceVector);

float k = 1; // tensile constant

float d = 1; // damping constant

float dot = D3DXVec3Dot(&particle.m_velocity, &forceVector);

D3DXVECTOR3 force = (k * length + d * (dot / length)) * (forceVector / length);

return force;

}

{

D3DXVECTOR3 forceVector = GetVector(particle); // From particle to destination

float length = D3DXVec3Length(&forceVector);

float k = 1; // tensile constant

float d = 1; // damping constant

float dot = D3DXVec3Dot(&particle.m_velocity, &forceVector);

D3DXVECTOR3 force = (k * length + d * (dot / length)) * (forceVector / length);

return force;

}

© 2014 Halogenica | Stumblr by Eleven Themes