Will
Will

Reputation: 75635

drawing a cube with perspective

enter image description here

I am trying to draw the Mandelbox using my own ray marching on the CPU.

I have a width*height bitmap to render to.

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

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,
                        P0 = 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(p);
                        D += d;
                        if(d<epsilon) {
                                depth_bmp[y*width+x] = 255.0f/i;
                                break;
                        }
                        p = dir*D + P0;
                }
        }
}

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

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:

How do I set the eye transform up so I see the cube properly?

enter image description here

Upvotes: 1

Views: 384

Answers (2)

Will
Will

Reputation: 75635

The issue is that the length of the ray must be normalised:

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;
const float len = glm::length(dir);
dir = glm::normalise(dir);
float D = 0;
for(int i=0; i<MAX_ITER; i++) {
    const float d = DE(p + dir*D);
    D += d;
    if(D > len) break;
    ...

Upvotes: 1

Ani
Ani

Reputation: 10896

You can use the method outlined here to generate the correct rays (and their lengths).

Upvotes: 0

Related Questions