Dark Bit Factory & Gravity
GENERAL => Projects => Topic started by: Rbz on March 09, 2011
-
Here a project page for everyone to start learning raymarching with distance fields (http://www.iquilezles.org/www/material/nvscene2008/rwwtt.pdf) or also called sphere tracing (http://graphics.cs.uiuc.edu/~jch/papers/zeno.pdf).
This thread is inspired on pouet (http://www.pouet.net/topic.php?which=7920&page=1&x=13&y=10)page with same name, where beginners already made great progress.
Well, I'm also a beginner on this subject but I was managed to understand it's principle reading a great article by @lx:
http://code4k.blogspot.com/2009/10/potatro-and-raymarching-story-of.html#more
So, I've made an example using RenderMonkey 1.82 (http://developer.amd.com/archive/gpu/rendermonkey/pages/default.aspx#download) that use opengl and directx for you to start, it's a colorful rotated cube :).
Also there's an exe with my current progress.
Our function tool box (all code came from pouet):
float3 RotateXAxis(float3 p, float angle)
{
return float3(p.x, p.y * cos(angle) + p.z * sin(angle), p.z * cos(angle) - p.y * sin(angle));
}
float3 RotateYAxis(float3 p, float angle)
{
return float3(p.x * cos(angle) + p.z * sin(angle), p.y, p.z * cos(angle) - p.x * sin(angle));
}
float3 RotateZAxis(float3 p, float angle)
{
return float3(p.x * cos(angle) + p.y * sin(angle), p.y * cos(angle) - p.x * sin(angle), p.z);
}
float capsule(float3 p, float r, float c) {
return lerp(length(p.xz)-r, length(float3(p.x,abs(p.y)-c,p.z))-r, step(c,abs(p.y)));
}
float plane(float3 p)
{
return abs(p.y);
}
float sphere(float3 p, float r)
{
return length(p) - r;
}
float cube(float3 p, float r)
{
return max(max(abs(p.x) - r, abs(p.y) - r), abs(p.z) - r);
}
//distance to a rounded cube:
float distToCBox( float3 p, float3 box, float rad )
{
return length( max( abs(p) - box + float3(rad,rad,rad), 0.0 ) ) - rad;
}
float3 GetNormal(float3 p)
{
float eps = 0.1f;
return
normalize(
float3(
distance(p + float3(eps, 0, 0)) - distance(p - float3(eps, 0, 0)),
distance(p + float3(0, eps, 0)) - distance(p - float3(0, eps, 0)),
distance(p + float3(0, 0, eps)) - distance(p - float3(0, 0, eps))));
}
//negative d -> sss, positive d -> ao
float ao(vec3 p, vec3 n, float d, float i) {
float o,s=sign(d);
for (o=s*.5+.5;i>0.;i--) {
o-=(i*d-f(p+n*i*d*s))/exp2(i);
}
return o;
}
// p pos, l direction to light - normalized, d stepwidth, i number of steps
float shadow(vec3 p, vec3 l, float d, float i) {
float o;
for (o = 0.; i > 0.; i--) {
o += f(p+l*i*d);
}
return clamp(o, 0.0, 1.0);
}
float perlin(vec3 p) {
vec3 i = floor(p);
vec4 a = dot(i, vec3(1., 57., 21.)) + vec4(0., 57., 21., 78.);
vec3 f = cos((p-i)*acos(-1.))*(-.5)+.5;
a = mix(sin(cos(a)*a),sin(cos(1.+a)*(1.+a)), f.x);
a.xy = mix(a.xz, a.yw, f.y);
return mix(a.x, a.y, f.z);
}
Choose your preferred api (dx9 or ogl) and start raymarching!
-
That looks great, the twister looks like it's made out of plastacine. :)
I've been reading the Pouet thread a bit, it would be cool if some other people here got interested in this.
-
Interesting stuff and I've been trying meself, but somehow I'm limited to planes, spheres and cylinders.
Cubes just don't work :(
Probably something in the calling code before the shader.
It's on my todo list but first concentrate on destruction entry
-
The pouet thread(s) are a wealth of information when it comes to raymarching.
For the ones that want to see some example of what can be done with raymarching
(http://www.plane9.com/content/scenes/70/scene.jpg)
The following two are essentially a bunch of sin/cos values and thats the fun part with it. The work/reward ration is really good with raymarching. Once you have something working it requires very little work to make interesting scenes.
(http://www.plane9.com/content/scenes/25/scene.jpg)
(http://www.plane9.com/content/scenes/41/scene.jpg)
This isn't realtime though, 1fps I heard. But has global illumination. I really like the design and how this is synced to the music.
[youtube]http://www.youtube.com/watch?v=BtEQ2cz-NfM[/youtube]
Haven't looked into it that much but it's certainly on my list of things to do
-
I've always wanted to try 3D rendering software, but found the big contenders (including "Maya") to be too processor intensive and fiddly to use.
I think I'll give RenderMonkey a try.
Does the term raymarching refer to a lighting effect or a distortion effect?
-
@combatking0: the basic concept is constructing a ray from your camera position into your scene, from that point you will be "marching" in steps until you hit a surface and then you can extract information from this surface like colors etc.
Btw, I've managed to add shadows and ambient occlusion, this code was kinda provided by las/mercury on here (http://www.pouet.net/topic.php?which=7931&page=2), I'll post an image and perhaps an .exe tomorrow :)
//negative d -> sss, positive d -> ao
float ao(vec3 p, vec3 n, float d, float i) {
float o,s=sign(d);
for (o=s*.5+.5;i>0.;i--) {
o-=(i*d-f(p+n*i*d*s))/exp2(i);
}
return o;
}
// p pos, l direction to light - normalized, d stepwidth, i number of steps
float shadow(vec3 p, vec3 l, float d, float i) {
float o;
for (o = 0.; i > 0.; i--) {
o += f(p+l*i*d);
}
return clamp(o, 0.0, 1.0);
}
-
Great stuff rbz, hope to get started as well someday, love the movie you posted!
CK, have a look at Cinema4d by Maxon. It's one of the more user friendly, fully featured 3d software packages around. I'm somewhat of an expert on it, so you can shoot me mail whenever you get stuck.
-
K+ for rounding up this info, This is exactly what I've been needing for my voxel engine. I was planning on going down the Sparse Octree Voxel Traversal meathod but I really hated the idea of stepping forward finding a voxel that was full and backing up only to step forward by half the original step size. With this meathod the ray is constantly moving forward. You never have to take a step backwards and you still have a step size that will accellerate vast empty expanses spending more time in densely populated areas.
At the moment I am testing my voxel engine at a resolution of 640x480 in an environment of 256x256x256 so long as most of the visible voxels are close by I can even push the resolution up to 1024x768 with no obvious slow down, but once you enter into an open area its far too slow to even think of any resolution higher than 640x480.
Thanks for gathering all of this info into one post.
Edit - Hehehe It worked like a dream worth some extra karma to rbz
Resolution=1024x768
Environment=128x128x128
Framerate is acceptable
-
Well done Rain_storm, it works pretty well here on 1280x1024 res and I believe it's software rendered?
Here's an image with shadows added.
-
Yup thats all software rendered. The best thing is:
rgba == 0, distance != 0 (empty voxels)
rgba != 0, distance == 0 (filled voxels)
looks like a marriage made in heaven
I've been playing around with the cube distance function from your first post. Its starting to look like a morphed square but still aint got anything 3D yet. Will keep at this.
Do you think it would be possible to model a SuperShape as a distance function? That would be awesome.
-
Do you think it would be possible to model a SuperShape as a distance function? That would be awesome.
I also don't know, need try more of those math formulas.
But I think you can do some nice things with just sin and cos while distorting basic shapes like a sphere.
-
Okay I got the cube distance function to work, quite slow but its working nonetheless, My GFX card (is card the right word when its the internal built into the motherboard variety) is ancient technology, without the benefit of shaders, so this is all done in software.
Next I'll be moving on to GetNormal...
float3 GetNormal(float3 p)
{
float eps = 0.1f;
return
normalize(
float3(
distance(p + float3(eps, 0, 0)) - distance(p - float3(eps, 0, 0)),
distance(p + float3(0, eps, 0)) - distance(p - float3(0, eps, 0)),
distance(p + float3(0, 0, eps)) - distance(p - float3(0, 0, eps))));
}
This is awesome stuff, I'm like a child on Christmas morning here.
-
Nice work!
Here's a "domain repetition", a trick with "mod(p,1.0)" (glsl) or "fmod(p,1.0)" (hlsl), thanks iq/rgba for that :), added "ao + noise" which was provided by las/mercury once again :).
float perlin(vec3 p) {
vec3 i = floor(p);
vec4 a = dot(i, vec3(1., 57., 21.)) + vec4(0., 57., 21., 78.);
vec3 f = cos((p-i)*acos(-1.))*(-.5)+.5;
a = mix(sin(cos(a)*a),sin(cos(1.+a)*(1.+a)), f.x);
a.xy = mix(a.xz, a.yw, f.y);
return mix(a.x, a.y, f.z);
}
-
Thanks Kirl and Rbz. K+'s there for explaining how it works and for suggesting some 3D software for beginners. I'll have a look at it.
-
How do you take the intersection / union of two objects?
Here I am trying to break out of the ray traversal loop if
the ray is intersecting the cube but outside the sphere. This should give the intersection (a cube with a sphere cut out of its center) but instead Im getting the union (a sphere and cube overlapping)
real d1 = cube(ray, 8.0);
real d2 = sphere(ray, 10.0);
if ((d1 < 0.0) && (d2 > 0.0)) {
break;
}
real d = min(d1, d2);
Edit : I figured it out it was the distance that I was taking for the step sometimes it was less than the minimum step size and it ended up breaking out of the loop because of that
-
Try it using "max" instead and negating d1 or d2:, you should get same results without "if" statement:
max(d1, d2);
max(-d1, d2);
max(d1, -d2);
-
Thanks rbz thats much more efficient and cleaner, but now I have another problem with the capsule function. It uses lerp and step.
float capsule(float3 p, float r, float c) {
return lerp(length(p.xz)-r, length(float3(p.x,abs(p.y)-c,p.z))-r, step(c,abs(p.y)));
}
I figured out that lerp is just a linear interpolation, o it should be the exact same as taking the average, is this correct?
lerpx = (ax+bx)/2
lerpy = (ay+by)/2
lerpz = (az+bz)/2
But what is the step function? Does anyone know how I translate that into c?
step(c,abs(p.y))
-
"lerp(a,b,s)" (hlsl) or "mix(a,b,s)" (glsl) linearly interpolate between a and b.
return a+s*(b-a);
And step(a,x) returns (x >=a ) ? 1 : 0
if(x>=a) return 1;
else return 0;
-
I think I'll give RenderMonkey a try.
Depending on what you want to do. Plane9 (http://www.plane9.com) might be worth looking at for experimentation projects.
The good
- It comes with few demo scene intros (Raymarching and otherwise) to get you going very quickly
- Shader editor works in realtime. That is, you dont have to press a key to compile
- Contains a few very good helper functions (http://www.plane9.com/Wiki/shaderfunctions) ready to use
- Shader has a expression that can be used to precalc frame values
- It has access to objects. Check the Android scene for example. large optimization by splitting up the shader to two objects. One background. One foreground.
- When your done you can use your scene as a sound responsive screensaver or a music visualizer in winamp/wmp
- Most unneeded things are removed. You have your vertex and pixel shader. No need to define texture sampler formats and all that. It's handled for you
The bad
- Shader errors are only shown in the log file
- Uses CG so very similary to HSLS. If you use GLSL a bit of conversion is needed mainly vec4->float4 kind of things
- The intelisence doesn't work that well
- No way to debug/single step a shader
- Since the shader is compiled in realtime if you do a infinite loop you will lockup your graphics card. Nvidia handles this well. Not sure what happens on a ATI card.
I haven't tried render monkey though so I'm not sure of its advantages
-
Awesome thread. Needs to have a deeper look at in soon!
-
Seems like someone else has had the same idea as Rain Storm;
http://www.pouet.net/prod.php?which=56879
-
Thats a minecraft hack not a demo. Funny that it doesn't run on this machine (much like Minecraft)
I'm heavily into modding games and I've played around with Minecrafts internals. Theres just something about the usage of java as a source language, lwjgl as an interface to OpenGL and there's definately something fishy about these two texture maps...
-
really really great stuff rbz and rain,
i will need to break all the info up and try some stuff out. cheers.
-
Nice :)
Keep it coming!
(http://research.mercury-labs.org/schillerdings.png)
Posted that one on pouet already, but that's the last thing I'll post in public for a while.
I'm working on "something".
I use FX Composer and Rendermonkey.
FX Composer works better with HLSL and doesn't crash that often...
And for some reason I like Rendermonkey to archive the stuff.
-
Hey las,
screeny looks very interesting! Looking forward to see "something" soon ;-)
Best,
benny!
-
Lovely choice of colours in that screenshot Las. I wonder what it looks like in motion :)
-
Thanks :)
Seems I killed the conversation here.
Just go ahead and play around with the stuff, keep posting screenshots and asking questions!
-
The picture of it look great :)
-
I came across this link, its got some awesome algebraic raytracing worthy of a read:
http://chuyeshov.com/ray.html
-
Finally got a bit of a raymarcher working.
(yeah, finally back looking at an ide :) )
Have a problem with iq's box function thou.
Anyone know the HLSL alternative for maxcomp.
HLSL doesn't seem to know that, neither seems google :(
-
maxcomp( v ) returns the largest component of the given vector v.
For example:
vec3 v( 3.0, 5.0, 1.0 );
float m= maxcomp(v);results in m= 5.0.
-
Thanks Hellfire!
K++
-
A couple of new things I've come across that are quite interesting:
Sunset on the sea experiment (Raymarched sea tutorial) (http://www.postronic.org/h3/pid65.html)
Progress on Raymarching an infinite city (http://y-alice.blogspot.co.uk/search/label/ray%20marching) and here it is running in the GLSL Sandbox (http://glsl.heroku.com/e#2233.0). It's worth checking out the GLSL Sandbox gallery (http://glsl.heroku.com/) as there are some lovely examples of Raymarching various things.
This is also worth a look (http://www.mazapan.se/news/2010/07/15/gpu-ray-marching-with-distance-fields/). It's DirectX HLSL (rather than OpenGL GLSL). This is what got me going with Raymarching a while back. I converted this to GLSL at the time (I'll try and dig up the code and post the conversion).