gregkwaste
Forums Newbie
Posts: 4
|
|
« on: March 07, 2014, 10:48:29 PM » |
|
Hi everyone, i am a huge enthousiast of 3D art, a python programmer, and a wannabe opengl programmer. My basic interest until some 2-3 months ago, was studying 3d file formats, and extract their data into modeling software. I am mostly using blender for that, because it offers a great amount of tools for that purpose and also an integrated python console which is really convenient. So some months ago, and basically because of my math, physics and in general celestrial interest, i decided to simulate special relativity's spacetime mesh on blender game engine (so that it could work realtime) and so i learned about vertex shaders, their purpose and what they are able to do. Then it was time for fragment shaders, so the first thing i thought about was fractals . I always had them in my mind as some infinite shapes, but never got into the math behind it. One week now i am studying about them and i have to say that i am really AMAZED, from all the math background behind them, and as i did imply the gravity laws on the spacetime grid, i decided to try and visualize some fractals using the correct math, i searched for some code on that, understood the math behind the julia set and the mandelbrot set and managed to make some 2d prints of them, using pyopengl and pure python making the images in PIL. Here is a 400 frame gif of a julia set containing the mandelbrot fractal (its obvious near the end of the animation) Now i think its time for some 3D fractals. And that is the basic reason i found that forum here. A took a quick glimpse on the stuff contained here and i can say that my jaw is still on the ground. SO MUCH NEW STUFF TO LEARN. What i would like to find out at first -because i am not so comfortable with opengl- is to find out how am i supposed to draw these objects. What should i do in order to make the render to autoupdate deeper and deeper, should i use a vertex shader again or the drawing will be like drawing a primitive for example? So much new stuff i am really excited :D And also waiting for anyone who offers to answer some of my questions Thanks in advance
|
|
|
Logged
|
|
|
|
mclarekin
|
|
« Reply #1 on: March 08, 2014, 12:13:57 PM » |
|
Hello and welcome. I am not a programmer, artist or mathematician, just an opportunist playing with a cool program, so I cannot help you in your endeavours. BUT I know this is a great place to learn about it all and keep you enthusiastic. Have fun
|
|
|
Logged
|
|
|
|
eiffie
Guest
|
|
« Reply #2 on: March 08, 2014, 05:51:28 PM » |
|
We usually just draw a quad in the vertex shader to get a surface to draw on then do everything in the fragment shader. Check out ShaderToy.com for lots of examples of setting up the camera. You can search for particular fractals like the mandelbulb there. Zooming is then just a matter of moving the camera closer.
|
|
|
Logged
|
|
|
|
gregkwaste
Forums Newbie
Posts: 4
|
|
« Reply #3 on: March 08, 2014, 09:01:18 PM » |
|
We usually just draw a quad in the vertex shader to get a surface to draw on then do everything in the fragment shader. Check out ShaderToy.com for lots of examples of setting up the camera. You can search for particular fractals like the mandelbulb there. Zooming is then just a matter of moving the camera closer.
Thanks for the replies so far, so again for a 3d model we are still tweaking a 2d quad??? :O:O:O I can't say that i can fully get the procedure, but i will check the website you mentioned and see what is going on What i was thinking is that 2D is needed for the 2d fractals, and for 3d structures we are just using 3d primitives, spheres or cubes. Then again the fragment shader does all the job.
|
|
|
Logged
|
|
|
|
eiffie
Guest
|
|
« Reply #4 on: March 08, 2014, 10:43:50 PM » |
|
There are some software that produce fractals from primitives too. We mainly use ray marching which let's us fold and scale space. It is a bit mind bending at first but you will catch on.
The two apps I know that produce fractals by repeating primitives are wooscripter and StructureSynth. The creators of those apps hang out here too so just search for them if interested.
|
|
« Last Edit: March 08, 2014, 10:54:39 PM by eiffie »
|
Logged
|
|
|
|
gregkwaste
Forums Newbie
Posts: 4
|
|
« Reply #5 on: March 09, 2014, 01:00:51 AM » |
|
There are some software that produce fractals from primitives too. We mainly use ray marching which let's us fold and scale space. It is a bit mind bending at first but you will catch on.
The two apps I know that produce fractals by repeating primitives are wooscripter and StructureSynth. The creators of those apps hang out here too so just search for them if interested.
nice, i'll definitely do For the first option though, is there any basic algorithm or an exaxmple on that "ray-marching" thing that you talked about, that i can study on?
|
|
|
Logged
|
|
|
|
|
gregkwaste
Forums Newbie
Posts: 4
|
|
« Reply #7 on: March 09, 2014, 03:13:19 AM » |
|
Thanks a lot, i'll definitely have a look, the past hours i am reading about the ray marching stuff, i can say i am pretty amazed. I could never imagine that there would be a way to create stuff literally out of nothing.
|
|
|
Logged
|
|
|
|
eiffie
Guest
|
|
« Reply #8 on: March 09, 2014, 05:23:57 PM » |
|
I wrote the following code to see how simple I could make a ray marched scene. It helps to start with the basics. You would want to do better lighting eventually but try to understand this first. float DE(in vec3 p){//a conservative distance estimate to a plane and sphere return min(1.0+p.y,length(p)-1.0);//use min to form the union of two shapes } float ShadAO(in vec3 ro, in vec3 rd){//a simple soft shadow/AO based on IQ's float res=1.0,t=0.1,d=1.0;//t is total distance traveled for(int i=0;i<4;i++){//take a few giant steps towards the light and see how close d=DE(ro+rd*t)*2.0;//you come to hitting something res=min(res,d/t);//save the minimum distance as a ratio of the distance traveled t+=d; } return clamp(res,0.0,1.0);//keep the result within reason } vec3 scene(in vec3 ro, in vec3 rd){//this marchs into the scene and returns the color float t=0.0,d=1.0;//t is total distance traveled, d=step distance for(int i=0;i<100;i++){//the march loop if(t<10.0 && d>0.001)t+=d=DE(ro+rd*t);//march if we haven't gone out of bounds } //or hit a surface vec3 col=vec3(rd.y);//background color (a gradient) if(d<0.1){//we came close enough to call it a hit ro+=rd*t;//move to the surface vec3 L=normalize(vec3(0.4,0.6,-0.3));//a direction to the light col=vec3(1.0)*ShadAO(ro,L);//shade the object } return col; } mat3 lookat(vec3 fw,vec3 up){//creates a camera rotation matrix fw=normalize(fw);vec3 rt=normalize(cross(fw,normalize(up)));return mat3(rt,cross(rt,fw),fw); } void main() { vec2 uv=(2.0*gl_FragCoord.xy-iResolution.xy)/iResolution.y;//the 2d point vec3 ro=vec3(0.0,0.0,-3.0);//the camera's position vec3 rd=lookat(-ro,vec3(0.0,1.0,0.0))*normalize(vec3(uv,1.0));//a 3d ray that points towards the origin gl_FragColor = vec4(scene(ro,rd), 1.0);//color the pixel }
|
|
|
Logged
|
|
|
|
Imagyx
|
|
« Reply #9 on: May 19, 2016, 12:38:30 PM » |
|
I wrote the following code to see how simple I could make a ray marched scene. It helps to start with the basics. You would want to do better lighting eventually but try to understand this first. float DE(in vec3 p){//a conservative distance estimate to a plane and sphere return min(1.0+p.y,length(p)-1.0);//use min to form the union of two shapes } float ShadAO(in vec3 ro, in vec3 rd){//a simple soft shadow/AO based on IQ's float res=1.0,t=0.1,d=1.0;//t is total distance traveled for(int i=0;i<4;i++){//take a few giant steps towards the light and see how close d=DE(ro+rd*t)*2.0;//you come to hitting something res=min(res,d/t);//save the minimum distance as a ratio of the distance traveled t+=d; } return clamp(res,0.0,1.0);//keep the result within reason } vec3 scene(in vec3 ro, in vec3 rd){//this marchs into the scene and returns the color float t=0.0,d=1.0;//t is total distance traveled, d=step distance for(int i=0;i<100;i++){//the march loop if(t<10.0 && d>0.001)t+=d=DE(ro+rd*t);//march if we haven't gone out of bounds } //or hit a surface vec3 col=vec3(rd.y);//background color (a gradient) if(d<0.1){//we came close enough to call it a hit ro+=rd*t;//move to the surface vec3 L=normalize(vec3(0.4,0.6,-0.3));//a direction to the light col=vec3(1.0)*ShadAO(ro,L);//shade the object } return col; } mat3 lookat(vec3 fw,vec3 up){//creates a camera rotation matrix fw=normalize(fw);vec3 rt=normalize(cross(fw,normalize(up)));return mat3(rt,cross(rt,fw),fw); } void main() { vec2 uv=(2.0*gl_FragCoord.xy-iResolution.xy)/iResolution.y;//the 2d point vec3 ro=vec3(0.0,0.0,-3.0);//the camera's position vec3 rd=lookat(-ro,vec3(0.0,1.0,0.0))*normalize(vec3(uv,1.0));//a 3d ray that points towards the origin gl_FragColor = vec4(scene(ro,rd), 1.0);//color the pixel }
I know this thread is old, but I wanted to implement the soft shadow method in my raytracer and run in a few problems. When i calculate the distance estimation from an already found surface towards the light in my scene, I get weird results. I only use diffuse and specular coloring when the return value is > 0. This is pretty much the same as above, onyl in java and with several objects in the scene: public double getSoftShadow(Ray r, Illumination il) {//Illumination contains all light information, e.g. direction int l = objects.size(); V3D illNeg = il.direction; illNeg.neg();//turn direction to face the light from the object double res = 1.0, t = 0.1, d = 1.0; for(int i = 0 ; i < 4 ; i++){ for(int k2 = 0 ; k2 < l ; k2++){ DEElement obj = objects.get(k2); if(obj != r.hitObject){//don't want to shadow itself ?! d = Math.min(d, obj.DE(r.hitPoint.getAdd(illNeg.mult(t)))); } } res = Math.min(res, d / t); t += d; } return Calculations.clamp(res,0.0, 1.0);
|
|
|
Logged
|
During difficult times, keep steady and play the match.
|
|
|
eiffie
Guest
|
|
« Reply #10 on: May 19, 2016, 02:31:29 PM » |
|
In the code above you never reset d to something large. You continually compute d=min(d,... try setting d=t or d=1000 at the start of each outer loop ... also there are better versions of soft shadow functions. Most would include a value k so res=min(res,k*d/t); //k is around 8, adjust to taste (higher k gives sharper shadows) and again you'll need more steps.
|
|
|
Logged
|
|
|
|
Imagyx
|
|
« Reply #11 on: May 19, 2016, 03:26:56 PM » |
|
I'm tracing fractals and objects and you're tracing me, eiffie Thanks for answering. I thought it would be best, if I entered more of my code here. Even with 1000 steps and resetting d b big value at the start of each outer loop and using a k=8 doesn't change the result much. The error most be somewhere in the rest of my code. As I mentioned in the other thread, that you answered, I rewrote the crucial part of my raytracer. Just the core (using quadcore cpu on the images pixels), it's looking like this: protected void calculateColor(ScreenPixel sp) {
V3D raydir = getRayDirection(sp.xVal, sp.yVal, draw.cameraToWorld); Ray ray = new Ray(draw.c2wUrsprung, raydir, RayType.PRIMARY); V3D color = castRay(ray, 0); ....drawing etc..... }
private V3D castRay(Ray r, int depth) {
if(depth > maxDepth){ return draw.backgroundColorV3D; } /* ooo[ Begin with black ]ooo */ V3D hitColor = new V3D(0); /* ooo[ Trace objects along ray ]ooo */ Statistics.newRay(r); double t0 = 0.0; int k = 0; double eps = epsDE; double opacity = 0.0; DEElement nearest = null; double minDist = Double.MAX_VALUE; int l = objects.size(); BP: for(; k < maxRaySteps ; k++){ // calculate next position along the ray V3D next = r.orig.getAdd(r.dir.mult(t0)); // calculate min of distance estimation function for all elements double dist = Double.MAX_VALUE; for(int k2 = 0 ; k2 < l ; k2++){ DEElement obj = objects.get(k2); double nextDist = obj.DE(next); if(nextDist < dist){ nearest = obj; dist = nextDist; minDist = Math.min(minDist, dist); } } t0 += dist; //behind clipping sphere if(t0 >= fcp){ hitColor = draw.backgroundColorV3D; break BP; //near enough }else if(dist < eps * t0){ // bind hitobject to ray r.hit(nearest, t0, r.orig.z + t0 * r.dir.z, next, mats.get(nearest.hitMat), DEType.DE_ELEMENT); // get color from mats und lights V3D newColor = getMaterialAndLighting(r, hitColor, depth); double alpha = (1.0 - opacity) * Calculations.clamp(1.0 - dist / (eps * t0), 0.0, 1.0) * opaqueMultAA; hitColor.add(newColor.mult(alpha)); opacity += alpha; // close enough to opaque if(opacity > opaqueStopAA){ break BP; } } } // to many rays if(k >= maxRaySteps){ // but if near enough, still calculate mats and lights if(minDist < acceptDistanceDespiteNotHitObject){ V3D next = r.orig.getAdd(r.dir.mult(t0)); r.hit(nearest, t0, r.orig.z + t0 * r.dir.z, next, mats.get(nearest.hitMat), DEType.DE_ELEMENT); hitColor.add(getMaterialAndLighting(r, hitColor, depth)); } } // stats r.numSteps += k; Statistics.numStepsIntersect(k); // return color return hitColor; }
private V3D getMaterialAndLighting(Ray r, V3D hitColor, int depth) {
/* ooo[ Calculate Normal etc. ]ooo */ r.hitNormal = r.hitObject.getNormal(r, deltaNormaleDE); /* ooo[ Check material types ]ooo */ if(r.hitNormal != null){ switch(r.hitMaterial.matType){ case PHONG: hitColor = getPhong(hitColor, r, objects, lights); break; case REFLECTION: hitColor = getRefl(hitColor, r, objects, lights, depth); break; default: hitColor = draw.backgroundColorV3D; break; } /* ooo[ Ambient occlusion ]ooo */ double ao = ambientOcclusion(r.hitPoint, r.hitNormal, r.hitObject); hitColor = hitColor.mult(1.0 - ao); }else{ /* ooo[ No Normal found -> Background ]ooo */ hitColor = draw.backgroundColorV3D; } } return hitColor; }
private V3D getPhong(V3D hitColor, Ray r, List<DEElement> objects, List<Light> lights) {
/* ||Created on 21.10.2015 14:07:05|| */ /* ooo[ ]ooo */ Phong phong = (Phong) r.hitMaterial; V3D diffuse = new V3D(0), specular = new V3D(0); phong.albedo.calculateAlbedo(r.dir, r.hitNormal, r.hitPoint); for(int i = 0 ; i < lights.size() ; i++){ Light light = lights.get(i); Illumination illu = light.getIllumination(r.hitPoint); !1! double shadow = getSoftShadow(r, illu);
!1! if(shadow > 0){ V3D illuDirNeg = illu.direction.copy(); illuDirNeg.neg(); V3D dirNeg = r.dir.copy(); dirNeg.neg(); diffuse .add( phong.albedo.getAlbedo().getMult( illu.intensity.mult(shadow *Math.max(0.0, r.hitNormal.dot(illuDirNeg))))); V3D R = Calculations.reflect(illu.direction, r.hitNormal, 0); specular.add(illu.intensity.mult(shadow *Math.pow(Math.max(0.0, R.dot(dirNeg)), phong.n))); } } hitColor = diffuse.mult(phong.Kd).getAdd(specular.mult(phong.Ks)); return hitColor; }
public double getSoftShadow(Ray r, Illumination il) { double k = 8.0; int l = objects.size(); V3D illNeg = il.direction; !2! illNeg.neg(); double res = 1.0, t = 0.1, d; for(int i = 0 ; i < 4 ; i++){ d = Double.MAX_VALUE; for(int k2 = 0 ; k2 < l ; k2++){ DEElement obj = objects.get(k2); if(obj != r.hitObject){ d = Math.min(d, obj.DE(r.hitPoint.getAdd(illNeg.mult(t)))); } } res = Math.min(res, k * d / t); t += d; } return Calculations.clamp(0.0, 1.0, res); }
OMG I just found the decisive error, after writing all the code above in a hopefully readable manner. It's line !2! where the illumination direction gets changed all the time..... object orientated language got me Sorry for the trouble, I hope it at least interests somebody who's also new to CG or maybe you find other mistakes or certain unoptimized code in there.... Thank you Happy now that it works so well, and with all hints and tricks from before in it as well. Now looking that way: I just don't know where the banding comes from. It wasn't there before...
|
|
|
Logged
|
During difficult times, keep steady and play the match.
|
|
|
eiffie
Guest
|
|
« Reply #12 on: May 19, 2016, 05:43:38 PM » |
|
To get rid of banding you want to start your shadow rays at a random distance from the surface. t=0.01*rand();//or whatever distance looks good Also starting the primary ray (the intersection ray) at a random distance is a good idea. t=DE(cameraPosition)*rand();//rand() would return 0. to 1.
..and yes I'm stalking you. haha I just know these questions can sit unanswered for a long time - there is no definitive tutorial on Ray Marching and if you don't code glsl it can be hard to find examples. Still I would check out ShaderToy.com for examples from the user iq or dila and shane for simpler examples.
|
|
|
Logged
|
|
|
|
Imagyx
|
|
« Reply #13 on: May 20, 2016, 10:41:55 AM » |
|
I'm all the more thankful for any help, especially from you, because it made my code more stable, functional and efficient each time, you suggested something to change. I don't code glsl but as for every programmer it's not too hard, to understand code in another programming languange and adapt to it. Earlier on I used a lot of C++ code, in which I only corrected syntax errors to make it run in Java I looked at some of the wonderful shaders on shadertoy already, which is always mindblowing. And I used some of the terrainmarching code already from there... But I will gladly have a look at dila and shane's examples as well. Much of the things iq posted were a great inspiration to me already (e.g. from http://www.iquilezles.org/www/index.htm)
|
|
|
Logged
|
During difficult times, keep steady and play the match.
|
|
|
|