用透视绘制立方体

时间:2012-07-09 20:20:25

标签: math graphics 3d fractals

enter image description here

我正在尝试使用我自己的Mandelbox在CPU上绘制ray marching

我有一个width * height位图要渲染。

对于每个像素,我想向立方体前进:

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;
                }
        }
}

我的距离估算函数非常literal translation,看起来像这样:

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);
}

输出看起来完全像unbox一样:

如何设置眼睛变换以便正确看到立方体?

enter image description here

2 个答案:

答案 0 :(得分:1)

问题是必须对光线的长度进行标准化:

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;
    ...

答案 1 :(得分:0)

您可以使用概述here的方法生成正确的光线(及其长度)。