光线追踪归一化屏幕空间
Raytracing Normalizing Screenspace
我在 -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。您目前有效的做法是将图像平面定义为宽度为 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 的像素位置之间的距离相同,我们可以将 x 坐标缩放 a
或将 y 坐标缩放 1.0f / a
。例如
float x = a * (i / (rterm::w / 2.0f) - 1.0f);
float y = j / (rterm::h / 2.0f) - 1.0f;
注:上面计算纵横比的* 1.0f
不是多余的。它在那里强制在 float
中执行计算;否则你最终会得到一个整数除法(假设你的分辨率是由整数类型的值给出的)…
我在 -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。您目前有效的做法是将图像平面定义为宽度为 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 的像素位置之间的距离相同,我们可以将 x 坐标缩放 a
或将 y 坐标缩放 1.0f / a
。例如
float x = a * (i / (rterm::w / 2.0f) - 1.0f);
float y = j / (rterm::h / 2.0f) - 1.0f;
注:上面计算纵横比的* 1.0f
不是多余的。它在那里强制在 float
中执行计算;否则你最终会得到一个整数除法(假设你的分辨率是由整数类型的值给出的)…