Logo by Pauldelbrot - Contribute your own Logo!

END OF AN ERA, FRACTALFORUMS.COM IS CONTINUED ON FRACTALFORUMS.ORG

it was a great time but no longer maintainable by c.Kleinhuis contact him for any data retrieval,
thanks and see you perhaps in 10 years again

this forum will stay online for reference
News: Did you know ? you can use LaTex inside Postings on fractalforums.com!
 
*
Welcome, Guest. Please login or register. April 18, 2024, 08:58:59 AM


Login with username, password and session length


The All New FractalForums is now in Public Beta Testing! Visit FractalForums.org and check it out!


Pages: [1]   Go Down
  Print  
Share this topic on DiggShare this topic on FacebookShare this topic on GoogleShare this topic on RedditShare this topic on StumbleUponShare this topic on Twitter
Author Topic: bug in perspective  (Read 2169 times)
0 Members and 1 Guest are viewing this topic.
willvarfar
Explorer
****
Posts: 57


« on: July 10, 2012, 10:52:52 AM »

I am failing at an embarrassingly simple task - trying to draw a mandelbox (or anything) on the CPU.

I have a width*height bitmap to render to.

For each pixel, I want to march towards the cube:

Code:
   static float eye = 0.0f; eye = glm::clamp(eye+0.005f,0.0f,1.0f); // animate
    const glm::mat4 projection = glm::perspective(35.0f, (float)width/height, 0.1f, 10.0f),
            modelview = glm::lookAt(glm::vec3(cos(eye),sin(eye),-1),glm::vec3(0,0,0),glm::vec3(0,0,1));    
    const float epsilon = sqrt(1.0f/std::max(width,height))/2.0f;
    for(int y=0; y<height; y++) {
            for(int x=0; x<width; x++) {
                    glm::vec3 p = glm::unProject(glm::vec3(x,y,0),modelview,projection,glm::vec4(0,0,width,height)),
                            dir = glm::unProject(glm::vec3(x,y,1),modelview,projection,glm::vec4(0,0,width,height))-p;
                    //std::cout << x << "," << y << " " << p.x << "," << p.y << "," << p.z << " " << dir.x << "," << dir.y << "," << dir.z << std::endl;
                    float D = 0;
                    for(int i=0; i<MAX_ITER; i++) {
                            const float d = DE(dir*D + p);
                            D += d;
                            if(d<epsilon) {
                                    depth_bmp[y*width+x] = 255.0f/(i+1);
                                    break;
                            }
                    }
            }
    }

I think my fundamental problem is working out where my rays should go for each pixel.

My distance estimator function is a very literal classic mandelbox and looks like this:

Code:
   float DE(glm::vec3 p) {
     const float Scale = -1.77f, fixedRadius2 = 1.0f, minRadius2 = (0.5f*0.5f);
     const glm::vec3 p0 = p;
     float dr = 1.0f;
     for(int n = 0; n < 13; n++) {
     // Reflect
     p = (glm::clamp(p,-1.0f,1.0f) * 2.0f) - p;
     // Sphere Inversion
     const float r2 = glm::dot(p,p);
     if(r2<minRadius2) {
     const float t = (fixedRadius2/minRadius2);
     p *= t;
     dr *= t;
     } else if(r2<fixedRadius2) {
     const float t = (fixedRadius2/r2);
     p *= t;
     dr *= t;
     }
     // Scale & Translate
                    p = p * Scale + p0;
                    dr = dr * abs(Scale) + 1.0f;
     }
     return glm::length(p)/abs(dr);
    }

And the output looks completely unbox-like:



I asked on StackOverflow but no bites.

How do I set the eye transform up so I see the cube properly?
« Last Edit: July 10, 2012, 10:54:50 AM by willvarfar » Logged
bib
Global Moderator
Fractal Senior
******
Posts: 2070


At the borders...


100008697663777 @bib993
WWW
« Reply #1 on: July 10, 2012, 11:40:59 AM »

I have no idea what your code means but I can tell you that your image definitely looks like a cut Mandelbox, so you are on the right track.
Perhaps you should try to set the viewpoint somewhere else, farther from the origin, in order to get the big picture.
Logged

Between order and disorder reigns a delicious moment. (Paul Valéry)
willvarfar
Explorer
****
Posts: 57


« Reply #2 on: July 10, 2012, 01:01:52 PM »

Obvious fixes and now it draws cubes and spheres and such spinning as I'd expect.

It doesn't draw any mandelbox though sad

Code:
enum { DEBUG = 0 };
const float rotation = (double)now_nanosecs()/1000000000, distance = 8.0f;
const glm::vec3 eye = glm::vec3(cos(rotation),0.5f,sin(rotation))*distance;
const glm::mat4
projection = glm::perspective(35.0f,(float)depth_w/depth_h,0.1f,100.0f),
modelview = glm::lookAt(eye,glm::vec3(0,0,0),glm::vec3(0.0f,1.0f,0.0f));
for(int y=0; y<depth_h; y++) {
for(int x=0; x<depth_w; x++) {
glm::vec3
p = glm::unProject(glm::vec3(x,y,0),modelview,projection,glm::vec4(0,0,depth_w,depth_h)),
dir = glm::unProject(glm::vec3(x,y,1),modelview,projection,glm::vec4(0,0,depth_w,depth_h))-p;
const float len = glm::length(dir),
epsilon = 0.001; // how best to compute scaled epsilon too?
dir = glm::normalize(dir);
if(DEBUG) std::cout << x << "," << y << " " << p.x << "," << p.y << "," << p.z << " " << dir.x << "," << dir.y << "," << dir.z << std::endl;
float D = 0.01f;
for(int i=0; i<MAX_ITER; i++) {
const float d = DE(p + dir*D);
if(DEBUG) std::cout << " " << x << "," << y << " " << i << " " << D << "," << d << "," << (D+d) << "," << (D+d>len) << std::endl;
D += d;
if(D>len)
break;
if(d<epsilon) {
depth_bmp[y*depth_w+x] = 255.0f/(i+1); // colour by ray march steps
break;
}
}
}
}



Presumably the mandelbox is at -1,-1,-1 to 1,1,1 ?  And asking for a DE from a point outside that will compute the distance to that?
« Last Edit: July 10, 2012, 01:06:49 PM by willvarfar » Logged
taurus
Fractal Supremo
*****
Posts: 1175



profile.php?id=1339106810 @taurus_arts_66
WWW
« Reply #3 on: July 10, 2012, 01:15:50 PM »

Presumably the mandelbox is at -1,-1,-1 to 1,1,1 ?

i have also no clou about code, but depending on scale it should be bigger. At least -2 to 2
Logged

when life offers you a lemon, get yourself some salt and tequila!
willvarfar
Explorer
****
Posts: 57


« Reply #4 on: July 10, 2012, 05:39:03 PM »

Basic spheres and cubes and such that I ray-march on work fine with proper perspective and draw where I put them.

But my mandelbox - which I copied, naturally - doesn't want to compute properly; it shows nothing, and the estimates it gives back are in the 1000s.

When I change the dr to Scale - as emphasised in this link by Buddhi - it draws... this:



As it rotates it wobbles; its not properly box-shaped.

Code:
const float Scale = -1.77f, fixedRadius2 = 1.0f, minRadius2 = (0.5f*0.5f);
const glm::vec3 p0 = p;
float dr = Scale;
for(int n = 0; n < 13; n++) {
// Reflect
p = (glm::clamp(p,-1.0f,1.0f) * 2.0f) - p;
// Sphere Inversion
const float r2 = glm::dot(p,p);
if(r2<minRadius2) {
const float t = (fixedRadius2/minRadius2);
p *= t;
dr *= t;
} else if(r2<fixedRadius2) {
const float t = (fixedRadius2/r2);
p *= t;
dr *= t;
}
// Scale & Translate
                p = p * Scale + p0;
                dr *= Scale;
}
return glm::length(p)/abs(dr);

I had imagined it was clipping problems but, really, how?  The sphere and box tests spin around the entire viewport.
Logged
taurus
Fractal Supremo
*****
Posts: 1175



profile.php?id=1339106810 @taurus_arts_66
WWW
« Reply #5 on: July 10, 2012, 06:12:54 PM »

still looks cut. Try a standard scale like 2 and get the camera off from the orgin, five or six i'd suggest.
Logged

when life offers you a lemon, get yourself some salt and tequila!
Syntopia
Fractal Molossus
**
Posts: 681



syntopiadk
WWW
« Reply #6 on: July 10, 2012, 10:15:45 PM »

Hi Willvarfar,

You DE-code look right - it works in Fragmentarium, but I must set a fudge-factor to 0.5 to avoid clipping, when the scale is negative. This might also be your problem: try multiplying the returned DE-value by 0.5.

Since you have a clamp-function, you can also try this version (due to Rrrola, I think), which works good for both positive and negative values:
Code:
float AbsScalem1 = abs(Scale - 1.0);
float AbsScaleRaisedTo1mIters = pow(abs(Scale), float(1-Iterations));

float DE(vec3 pos) {
vec4 p = vec4(pos,1), p0 = p;  // p.w is the distance estimate
for (int i=0; i<Iterations; i++) {
p.xyz = clamp(p.xyz, -1.0, 1.0) * 2.0 - p.xyz; 
float r2 = dot(p.xyz, p.xyz);
p *= clamp(max(MinRad2/r2, MinRad2), 0.0, 1.0); 
p = p*scale + p0;
}
return ((length(p.xyz) - AbsScalem1) / p.w - AbsScaleRaisedTo1mIters);
}

Btw, consider using a 'using namespace glm;' - then I could have pasted your C++ directly as GLSL :-)
Logged
willvarfar
Explorer
****
Posts: 57


« Reply #7 on: July 11, 2012, 09:28:47 AM »

Thx Syntopia,

a scale of 2 or -2 works; -1.77 doesn't.  I have not experimented with other values nor tried to work out why.

I will park this mystery as I now have a nice -2 mandelbox to depth-estimate against.

http://www.pouet.net/topic.php?which=6675&page=4 sounds like the demo guys used a put-spheres-on-a-list sphere-marching kind of thing.
Logged
willvarfar
Explorer
****
Posts: 57


« Reply #8 on: July 12, 2012, 02:33:48 PM »

I don't have swizzle so this is my translation of Rrrola's mandelbox:

Code:
const int Iterations = 13;
const float Scale = 2.0f,
MinRad2 = (0.5f*0.5f),
AbsScalem1 = abs(Scale - 1.0f),
AbsScaleRaisedTo1mIters = pow(abs(Scale),float(1-Iterations));
const vec3 p0 = p;
float p_w = 1.0f;
for(int i=0; i<Iterations; i++) {
p = (clamp(p,-1.0f,1.0f) * 2.0f) - p;
const float r2 = dot(p,p),
adj = clamp(max(MinRad2/r2,MinRad2),0.0f,1.0f)*Scale;
p = p*adj + p0;
p_w = p_w*adj + 1.0f;
}
return ((length(p)-AbsScalem1)/p_w) - AbsScaleRaisedTo1mIters;

But I must have a strange bug in it (apart from not working with negative numbers etc too); it draws this ugly unstable thing that wobbles when viewed from different angles:



What can I possibly have mistranslated to C++?
Logged
willvarfar
Explorer
****
Posts: 57


« Reply #9 on: July 12, 2012, 09:50:41 PM »

I seem beset with problems

For example, rendering a very normal mandelbulb with this code:

Code:
const Vec3 pos = p;
const int Iterations = 20, Power = 8;
const Float DEPTH_OF_FIELD = 1000.0;
Float dr = 1.0f, r = 0.0f;
for(int i=0; i<Iterations; i++) {
r = length(p);
if(r>DEPTH_OF_FIELD) break;
const Float theta = acos(p.z/r)*Power,
        phi = atan2(p.y,p.x)*Power;
dr =  pow(r,Power-1)*Power*dr + 1.0f;
p.x = sin(theta)*cos(phi);
p.y = sin(phi)*sin(theta);
p.z = cos(theta);
p *= pow(r,Power);
p += pos;
}
return 0.5f*log(r)*r/dr;

I have typedefs to switch between floats (32 bits) and doubles (64).

The left column shows doubles
The right column shows floats
The top row shows deep inside the mandelbulb
The bottom row shows it from outside



How do I get this to work with floats?  GPUs are 32 bits; why does a literal copy of the GLSL code, like the mandelbox in the code in my previous post, not work when I compile it (linux, gcc 4.6.3, 64-bit)?

What simple thing am I doing wrong?  I'm going to kick myself when you point this out to me, promise!
Logged
eiffie
Guest
« Reply #10 on: July 13, 2012, 12:02:33 AM »

Try a smaller bailout like 2.0 perhaps.
Logged
Pages: [1]   Go Down
  Print  
 
Jump to:  

Related Topics
Subject Started by Replies Views Last post
Help with Escher and perspective General Discussion Devke 2 1173 Last post February 09, 2011, 06:20:44 PM
by DarkBeam
A Different Perspective Mandelbulb3D Gallery dainbramage 0 942 Last post July 10, 2011, 08:26:42 AM
by dainbramage
Atmospheric Perspective Feature Requests geomagnet 0 1016 Last post February 15, 2014, 04:55:02 PM
by geomagnet
A Higher Perspective Fractal Science Kit Gallery Ross Hilbert 0 1046 Last post May 05, 2014, 03:21:54 PM
by Ross Hilbert
Tree in 3/4 perspective Images Showcase (Rate My Fractal) Max Sinister 0 927 Last post May 13, 2016, 11:06:44 PM
by Max Sinister

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines

Valid XHTML 1.0! Valid CSS! Dilber MC Theme by HarzeM
Page created in 0.142 seconds with 24 queries. (Pretty URLs adds 0.006s, 2q)