【问题标题】:Raytracing outputting double?光线追踪输出双倍?
【发布时间】:2019-10-21 03:28:30
【问题描述】:

在一个周末使用 Peter Shirley 的光线跟踪,我在尝试将球体渲染为红色时遇到了问题。我的数学似乎是准确的,但是它输出看起来像 2 个并排的球体并且还倾斜/拉伸,而不是场景中的 1 个球体。我怀疑它与光线投射的视野宽度有关,但不确定如何确认。代码如下:

ma​​in.cpp

#include "vectors.h"
#include "Geometry3D.h"
#include <fstream>

vec3 Color(const Ray& r, const Sphere& s) {
    if (Raycast(s, r) != -1)
        return vec3(1, 0, 0);
    else
        return vec3(0, 0, 0);
}

int main() {
    const int WIDTH = 200;
    const int HEIGHT = 100;

    std::ofstream out;
    out.open("image.ppm");

    if (out.is_open()) {
        out << "P3\n" << WIDTH << ' ' << HEIGHT << "\n255\n";
        vec3 lowerLeftCorner(-2.0f, -1.0f, -1.0f);
        vec3 horizontal(4.0f, 0.0f, 0.0f);
        vec3 vertical(0.0, 2.0f, 0.0);
        vec3 origin(0.0, 0.0, 0.0);
        for (int i = 0; i < WIDTH; i++) {
            for (int j = 0; j < HEIGHT; j++) {
                float u = float(i) / float(WIDTH);
                float v = float(j) / float(HEIGHT);

                Sphere s(vec3(0, 0, -5.0f), 1.0f);

                Ray r(origin, lowerLeftCorner + (horizontal * u) + (vertical * v));
                vec3 color = Color(r, s);

                int ir = int(255.99f * color.x);
                int ig = int(255.99f * color.y);
                int ib = int(255.99f * color.z);
                out << ir << ' ' << ig << ' ' << ib << '\n';
            }
        }
    }
}

Geometry3D.h

#ifndef _GEOMETRY_3D_H
#define _GEOMETRY_3D_H

#include "vectors.h"
#include <cmath>
#include <cfloat>

typedef vec3 Point;

typedef struct Ray {
    Point origin;
    vec3 direction;

    Ray() : direction(0.0f, 0.0f, 1.0f) { }
    Ray(const Point& o, const vec3& d) : origin(o), direction(d) {
        NormalizeDirection();
    }
    inline void NormalizeDirection() {
        Normalize(direction);
    }

} Ray;

typedef struct Sphere {
    Point position;
    float radius;

    Sphere() : radius(1.0f) { }
    Sphere(const Point& p, float r) : position(p), radius(r) { }

} Sphere;

float Raycast(const Sphere& sphere, const Ray& ray);

#endif

Geometry3D.cpp

#include "Geometry3D.h"
#include <iostream>

float Raycast(const Sphere& sphere, const Ray& ray) {
    vec3 e = sphere.position - ray.origin;
    float rSq = sphere.radius * sphere.radius;
    float eSq = MagnitudeSq(e);

    float a = Dot(e, ray.direction);
    float bSq = eSq - (a * a);
    float f = sqrt(rSq - bSq);

    if (rSq - (eSq - (a * a)) < 0.0f) 
        return -1;
    else if (eSq < rSq) {
        return a + f;
    }
    return a - f;
}

这是输出:

感谢任何帮助。

【问题讨论】:

  • 你确定不是简单的读/写图片文件的问题?看起来好像两行会被塞进一排。可能是设置宽度/高度或步幅有问题?

标签: c++ graphics raytracing


【解决方案1】:

错误在于写入 .ppm 图像。

for (int i = 0; i < WIDTH; i++) {
        for (int j = 0; j < HEIGHT; j++) {
            float u = float(i) / float(WIDTH);
            float v = float(j) / float(HEIGHT);
            ...
            out << ir << ' ' << ig << ' ' << ib << '\n';
        }
    }

您正在使用普通 PPM 图像 (P3)。 根据PPM Specification,栅格(颜色数据)应如下所示:

高度行的栅格,按从上到下的顺序排列。每行由宽度像素组成,从左到右的顺序。每个像素都是红色、绿色和蓝色样本的三元组,按此顺序。

但是,您正在使用循环构建具有 HEIGHT 像素的 WIDTH 行的栅格。 外循环创建一行,内循环创建行中的像素。 更改索引将解决此问题。

//switch the loop indices
for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < WIDTH; j++) {
            float u = float(i) / float(HEIGHT);
            float v = float(j) / float(WIDTH);
            ...
            //added spaces between each color value
            //this way each pixel is separated with 2 spaces
            out << ' '<< ir << ' ' << ig << ' ' << ib << ' ';
        }
        //and each row ends on a newline
        //this makes it easier to read them with a text editor
        out << '\n';
    }

您遇到的情况如下: 宽度是高度的两倍,

    const int WIDTH = 200;
    const int HEIGHT = 100;

然后您将 200 行 100 像素写入 ppm 图像。然而,图像查看器读取 100 行 200 像素,这会导致“镜像”效果。 考虑下图:

B是黑色像素,R是红色像素

我试图用绘画图像来说明它,但实际上图像数据只不过是一个矩阵;)

宽度:8

身高:4

B B B B B B B B
B B B B R R R R
R R R R B B B B
B B B B B B B B

此图像顶部有一条黑色像素线,然后是一条半黑半红像素线。下一行具有相同的图案,只是相反:一半红色,一半黑色。最后一行是纯黑色。

您的代码基本上转置了图像。它用高度切换宽度并这样写:

B B R B
B B R B
B B R B
B B R B
B R B B
B R B B
B R B B
B R B B

所以图片阅读器会这样读:

B B R B B B R B
B B R B B B R B
B R B B B R B B
B R B B B R B B

如果您浏览每一行,您可以看到图像在第 4 行之后被镜像。 这就是您在图像中看到的内容,但是由于您使用的是圆形,因此由于对称性,图像看起来像是被写了两次。你看不到图像是颠倒的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    相关资源
    最近更新 更多