光线追踪归一化屏幕空间

时间:2019-04-24 21:56:53

标签: c++ mapping raytracing euclidean-distance rasterizing

我将屏幕坐标标准化为-1到+1。然后,我从归一化的坐标开始追踪一些射线,并用原点和方向矢量计算带符号的距离场(sdf)。

for (int i = 0; i < rterm::w; i++)
  for (int j = 0; j < rterm::h; j++) {
    float x = i / (rterm::w / 2.0f) - 1.0f;
    float y = j / (rterm::h / 2.0f) - 1.0f;

    glm::vec3 o = glm::vec3(x, y, -10.0f);
    glm::vec3 d = glm::vec3(0.0f, 0.0f, 1.0f);

    if (trace(o, d))
      rterm::ctx->buffer[i + j * rterm::w] = '#';
}

sdf正常工作,但是我的代码中必须有一个错误。栅格化的球体不是球体,更像是这样。

+---------------------------------+
|                                 |
|                                 |
|#########                        |
|#################                |
|#####################            |
|#######################          |
|#########################        |
|#########################        |
|#########################        |
|#########################        |
|#########################        |
|#######################          |
|#####################            |
|#################                |
|#########                        |
|                                 |
|                                 |
+---------------------------------+

sdf只是一个简单的领域。

float sphere(glm::vec3 p, float r) {
  return glm::length(p) - r;
}

float get(glm::vec3 p) {
  float ds = sphere(p, 0.8f);

  return ds;
}

这是我的跟踪实现。

bool trace(glm::vec3 o, glm::vec3 d) {
  float depth = 1.0f;

  for (int i = 0; i < MARCH_STEPS; i++) {
    float dist = sdf::get(o + d * depth);

    if (dist < EPSILON) return true;
    depth += dist;
    if (depth >= CLIP_FAR) return false;
  }

  return false;
}

1 个答案:

答案 0 :(得分:1)

您必须考虑到图像的长宽比,通常不会是1。目前,您要有效执行的操作是将图像平面定义为2个宽度单位和2个单位高度单位。然后,您可以将此图像平面细分为沿x维度为rterm::w像素和沿y维度为rterm::h像素的网格。请注意,将光线投射到世界上的区域仍然是矩形,只需沿x和y轴以不同的间隔细分即可。然后,当您通过某种标准机制显示图像时,假设沿两个维度以相同的规则间隔对像素进行采样,则图像会显得失真。

通常要做的是在x和y轴上使用相同的空间采样率。到达那里的典型方法是调整投射光线的区域的x或y尺寸,以匹配要生成的图像的分辨率的纵横比。长宽比通常定义为x分辨率和y分辨率之间的比率:

float a = rterm::w * 1.0f / rterm::h;

例如,如果图像宽于高,则宽高比将大于1。如果图像宽于高,则宽高比将小于1。对于非正方形图像,要使沿x和y的像素位置之间的距离相同,我们可以按a缩放x坐标,也可以按1.0f / a缩放y坐标。例如

float x = a * (i / (rterm::w / 2.0f) - 1.0f);
float y = j / (rterm::h / 2.0f) - 1.0f;

注意:上述长宽比的计算中的* 1.0f不是多余的。在这里强制在float中进行计算;否则,您将得到整数除法(假设分辨率由整数类型的值给定)…