光线传输、蒙特卡罗与基于图像的光照技术解析
在计算机图形学领域,光线传输和蒙特卡罗方法是实现逼真渲染的关键技术,而基于图像的光照则能让虚拟场景的光照与现实世界相匹配。下面将详细介绍相关的算法和技术。
光线传输与路径追踪算法
路径追踪算法是一种基本的渲染算法,用于从场景描述中生成合成图像。下面是相关代码:
v0 = v3_make(p->v[0].x, p->v[0].y, p->v[0].z);
v1 = v3_make(p->v[1].x, p->v[1].y, p->v[1].z);
v2 = v3_make(p->v[2].x, p->v[2].y, p->v[2].z);
a = v3_scale(1 - sqrt(r1), v0);
b = v3_scale(sqrt(r1)*(1 - r2), v1);
c = v3_scale(sqrt(r1)*r2, v2);
return ray_make( v3_add(a, v3_add(b, c)), hpoly_normal(p));
在这个代码中,主要是根据给定的顶点信息生成光线。
路径追踪的主程序代码如下:
// ptrace/main.h
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include "image.h"
#include "defs.h"
#include "geom.h"
#include "stack.h"
#include "view.h"
#include "poly.h"
#include "prim.h"
#include "hier.h"
#include "lang.h"
#include "clip.h"
#include "raster.h"
#include "shade.h"
#include "ray.h"
#include "csg.h"
#include "rt.h"
#include "rshade.h"
#include "scene.h"
#include "ptrace.h"
#include "ibl.h"
void init_render(Scene *s);
Ray ray_view(int u, int v);
void init_lang(void);
// ptrace/main.c
#include "main.h"
static Scene *s;
static Matrix4 mclip, mdpy;
#define MAX_PTRACE_SAMPLES 200
#define PATH_SIZE 3
int main(int argc, char **argv)
{
Color c, c_aux;
int u, v, smpl, ll_y, ur_y;
Ray r;
init_lang();
s = scene_read();
init_render(s);
s->objs = graph_flatten(graph_transform(s->objs));
ll_y = s->view->sc.ll.y;
ur_y = s->view->sc.ur.y;
#pragma omp parallel for private(u, r, c, smpl, c_aux) shared(s)
schedule(dynamic, 1)
for (v = ll_y; v < ur_y; v += 1) {
for (u = s->view->sc.ll.x; u < s->view->sc.ur.x; u += 1) {
r = ray_unit(ray_transform(ray_view(u, v), mclip));
c = c_make(0,0,0);
for( smpl = 0; smpl < MAX_PTRACE_SAMPLES; smpl++ ){
c_aux = trace_path(PATH_SIZE, PATH_SIZE, r, s->objs, c_make(0,0,0) );
c = c_add( c, c_aux );
}
img_putc(s->img, u, v,
col_dpymap( c_scale(1./MAX_PTRACE_SAMPLES, c))
);
}
}
img_write(s->img,"stdout",0);
exit(0);
}
Ray ray_view(int u, int v)
{
Vector4 w = v4_m4mult(v4_make(u, v,s->view->sc.ur.z, 1), mdpy);
return ray_make(v3_v4conv(v4_m4mult(v4_make(0, 0, 1, 0), mdpy)),
v3_make(w.x, w.y, w.z));
}
void init_render(Scene *s)
{
mclip = m4_m4prod(s->view->Vinv, s->view->Cinv);
mdpy = m4_m4prod(s->view->Pinv, s->view->Sinv);
}
void init_lang(void)
{
lang_defun("scene", scene_parse);
lang_defun("view", view_parse);
lang_defun("dist_light", distlight_parse);
lang_defun("plastic", plastic_parse);
lang_defun("primobj", obj_parse);
lang_defun("sphere", sphere_parse);
lang_defun("polyobj", obj_parse);
lang_defun("trilist", htrilist_parse);
lang_defun("group", group_parse);
lang_defun("hdrdome", hdrdome_parse);
lang_defun("polylight", plight_parse);
}
在上述代码中,
MAX_PTRACE_SAMPLES
和
PATH_SIZE
宏分别定义了从每个像素追踪的路径数量和路径的深度。主程序的执行流程如下:
1. 初始化语言环境。
2. 读取场景信息。
3. 初始化渲染参数。
4. 对场景对象进行扁平化和变换处理。
5. 并行遍历每个像素,对每个像素追踪多条路径并累加颜色值。
6. 将累加的颜色值进行缩放并写入图像。
7. 输出图像并退出程序。
下面是一个简单的流程图展示主程序的执行流程:
graph TD;
A[初始化语言环境] --> B[读取场景信息];
B --> C[初始化渲染参数];
C --> D[场景对象处理];
D --> E[遍历像素];
E --> F[追踪路径并累加颜色];
F --> G[颜色缩放并写入图像];
G --> H[输出图像并退出];
基于图像的光照技术
基于图像的光照技术旨在让虚拟场景的光照与现实世界的光照相兼容。下面将详细介绍相关的步骤。
HDR 图片与辐射度图重建
在拍摄图片时,像素值通常与入射辐射度不成比例,并且可能存在颜色饱和或过暗的问题。为了获取每个方向的辐射度信息,需要使用高动态范围(HDR)图像。
可以通过以下步骤重建 HDR 辐射度图:
1.
使用互易方程
:互易方程建立了像素传感器接收到的辐照度 $E_i$ 与像素值 $Z_{ij}$ 之间的关系,其中 $i$ 表示像素的空间索引,$j$ 表示不同的曝光时间 $\Delta t_j$,方程为 $Z_{ij} = f(E_i\Delta t_j)$。
2.
对数变换
:假设 $f$ 是单调的,则可以进行逆变换并取对数,得到 $g(Z_{ij}) = \ln E_i + \ln \Delta t_j$,其中 $g = \ln f^{-1}$。
3.
优化求解
:通过最小化目标函数来恢复函数 $g$ 和辐照度 $E_i$,目标函数为:
$$
\sum_{i=1}^{N} \sum_{j=1}^{P} (g(Z_{ij}) - \ln E_i + \ln \Delta t_j)^2 + \lambda \sum_{z=Z_{min}+1}^{Z_{max}-1} g’‘(z)^2
$$
其中 $N$ 是像素位置的数量,$P$ 是图片的数量,$Z_{min}$ 是最小像素值,$Z_{max}$ 是最大像素值,$\lambda$ 控制估计函数 $g$ 的平滑度。
4.
添加约束
:为了解决 $g(z)$ 和 $E_i$ 的尺度因子问题,添加约束 $g(Z_{mid}) = 0$,其中 $Z_{mid} = \frac{1}{2}[Z_{min} + Z_{max}]$。
5.
加权处理
:考虑到函数 $g$ 在 $Z_{min}$ 和 $Z_{max}$ 附近可能不太平滑,定义加权函数 $w(z)$ 来强调 $g$ 函数中间的值。改进后的目标函数为:
$$
\sum_{i=1}^{N} \sum_{j=1}^{P} [w(Z_{ij})(g(Z_{ij}) - \ln E_i + \ln \Delta t_j)]^2 + \lambda \sum_{z=Z_{min}+1}^{Z_{max}-1} [w(z)g(z - 1) - 2g(z) + g(z + 1)]^2 + g(Z_{mid})^2
$$
通过求解上述优化问题,可以恢复函数 $g$,进而计算出每个传感器的入射辐射度 $E_i$:
$$
\ln E_i = \frac{\sum_{j=1}^{P} w(Z_{ij})(g(Z_{ij}) - \ln \Delta t_j)}{\sum_{j=1}^{P} w(Z_{ij})}
$$
PFM 文件格式与图像转换
HDR 图片可以存储为 PFM(Portable FloatMap)文件,其文件头包含以下信息:
| 信息 | 说明 |
| ---- | ---- |
| [type] | 若存储 RGB HDR 图片为 “PF”,单色为 “Pf” |
| [xres][yres] | 图像的分辨率 |
| [byte order] | “1.0” 表示大端存储,”-1.0” 表示小端存储 |
在处理基于图像的光照时,需要进行 LDR 与 HDR 图像的转换,可以使用 Image Magick 软件的
convert
命令:
- 从 LDR 视频生成 HDR 输入帧:
convert video.mp4 -endian lsb bk%d.pfm
- 从 HDR 输出帧生成 LDR 视频:
convert out%d.pfm[0-n] output.mp4
从 HDR 图片到等距柱状投影
为了捕获场景的辐射度,可以使用不同曝光时间拍摄镜子球的多张图片。假设相机远离镜子球并进行变焦,相机近似为正交投影相机,光线几乎平行。
每条光线可以映射到纬度和经度值,最终映射到一个矩形 $[-\pi, \pi] \times [0, \pi]$,然后在网格上均匀采样,生成分辨率为 $2w \times w$ 的等距柱状投影图像。
可以使用 HDR Luminance 软件生成辐射度等距柱状投影图,并使用 Gimp 调整曝光。
辐射度穹顶的定向与渲染
在渲染时,将辐射度等距柱状投影图视为一个无限远的穹顶作为光源。为了将光线映射到等距柱状投影图的像素上,需要根据 MatchMove 参考系统定义穹顶的方向。
可以通过以下步骤确定穹顶的方向:
1.
相机校准
:使用 3D 点云的对应关系和相机的 2D 投影进行相机校准,得到相机参数 $k[R|t]$。
2.
定义坐标系原点
:经度坐标系的原点 $o = -R^T(0, 0, 1)^T$,纬度坐标系的原点 $s = R^T(0, 1, 0)^T$。
3.
定义正交向量
:定义与 $o$ 和 $s$ 正交的单位向量 $w = s \times o$。
在路径追踪算法中,选择不与任何物体相交的单位向量 $v$ 后,可以通过以下步骤找到等距柱状投影图中对应的像素:
1.
定向辐射度穹顶
:按照上述方法确定穹顶的方向。
2.
定义转换矩阵
:矩阵 $M$ 的行分别为 $o$、$w$ 和 $s$,即
$$
M = \begin{pmatrix}
o_x & o_y & o_z \
w_x & w_y & w_z \
s_x & s_y & s_z
\end{pmatrix}
$$
3.
计算投影点
:计算 $p = Mv$。
4.
计算经纬度
:纬度 $\theta = \arccos(p_z)$,经度 $\varphi = \arctan2(p_y, p_x)$。
5.
确定像素坐标
:在分辨率为 $w \times h$ 的 HDR 图像中,像素坐标为 $x = \text{round}((1 - \frac{\varphi}{\pi}) \frac{w}{2})$ 和 $y = \text{round}(\frac{\theta}{\pi}h)$。
下面是一个流程图展示从光线到像素的映射过程:
graph TD;
A[定向辐射度穹顶] --> B[定义转换矩阵];
B --> C[计算投影点];
C --> D[计算经纬度];
D --> E[确定像素坐标];
真实与虚拟场景的交互
在基于图像的光照中,场景可以分为三个部分:远处场景、局部场景和合成对象。远处场景为局部场景和合成对象提供光照,局部场景是与合成对象接近且交互较大的真实物体,合成对象由用户创建。
在我们的模型中,合成对象不接收来自局部场景的光照,因为辐射度穹顶的辐射度已经近似包含了局部场景的反射辐射度。
对于局部场景的 BRDF 建模,可以先假设 S3D 材料的 $k_d = 1$ 和 $d_{col} = (1, 1, 1)$ 进行渲染,然后通过比较渲染图像和背景图像的颜色来调整颜色。
综上所述,光线传输和基于图像的光照技术是实现逼真渲染的重要手段,通过合理的算法和处理步骤,可以让虚拟场景的光照与现实世界相匹配。
光线传输、蒙特卡罗与基于图像的光照技术解析
光线传输与路径追踪算法的应用示例
下面给出一个具体的场景描述示例,通过路径追踪软件可以生成相应的图像:
scene{
polylight{
color = {10,10,10},
shape = trilist {
{{3.3,3.3,9.9999}, {6.6,3.3,9.9999}, {3.3,6.6,9.9999}},
{{3.3,6.6,9.9999}, {6.6,3.3,9.9999}, {6.6,6.6,9.9999}}
}
},
camera = view {
from = {5, 20, 5}, at = {5, 0, 5}, up = {0,0,1}, fov = 60
imgw = 640, imgh = 480
},
object = primobj{
material = plastic { kd = 0.4, ks = 0.9, kt =0, se = -1
d_col = {1, 1, 1}, s_col = {1,1,1}},
shape = sphere { center = {2, 3, 2}, radius = 2}},
object = primobj{
material = plastic { kd = 0.4, ks = 0.3, kt = 0,
d_col = {.9, .9, .6}, s_col = {1,1,1}},
shape = sphere { center = {6, 6, 2}, radius = 2}},
object = primobj{
material = plastic { kd = 0.4, ks = 0.3, kt = 0,
d_col = {1, 1, 1}, s_col = {1,1,1}},
shape = sphere { center = {3, 6, .9}, radius = .9}},
object = polyobj {
material = plastic { kd = .4, ks = 0, kt = 0,
d_col = {.9, .9, .9}, s_col = {1,1,1}},
shape = trilist {
{{0, 0, 0},
{10, 0, 0}, {0, 10, 0}},
{{10, 10, 0}, {0, 10, 0}, {10, 0, 0}}
}
},
object = polyobj {
material = plastic { kd = .4, ks = 0, kt = 0,
d_col = {.9, .9, .9}, s_col = {1,1,1}},
shape = trilist {
{{0, 0, 10},
{0, 10, 10}, {10, 0, 10}},
{{10, 10, 10}, {10, 0, 10}, {0, 10, 10}}
}
},
object = polyobj {
material = plastic { kd = .4, ks = 0, kt = 0,
d_col = {.6, .6, .9}, s_col = {1,1,1}},
shape = trilist {
{{0,0,0},
{0,10,0}, {0,10, 10}},
{{0,0,0}, {0,10,10}, {0,0,10}}
}
},
object = polyobj {
material = plastic { kd = .4, ks = 0, kt = 0,
d_col = {.9, .6, .6}, s_col = {1,1,1}},
shape = trilist {
{{10,0,0},
{10,10,10}, {10,10, 0}},
{{10,0,0}, {10,0,10}, {10,10,10}}
}
},
object = polyobj {
material = plastic { kd = .4, ks = 0, kt = 0,
d_col = {.9, .9, .9}, s_col = {1,1,1}},
shape = trilist {
{{0,0,0},
{10,0,10}, {10,0, 0}},
{{0,0,0}, {0,0,10}, {10,0,10}}
}
},
};
在这个场景描述中,定义了一个多边形光源、相机以及多个球体和多边形对象,每个对象都有相应的材质属性。通过路径追踪算法对这个场景进行渲染,能够得到具有真实光照效果的图像。
基于图像的光照技术的优化与拓展
辐射度图采样优化
在从辐射度图采样时,可以采用更高效的采样策略来提高渲染效率。例如,使用重要性采样方法,根据辐射度图中不同区域的辐射度值进行采样,将更多的采样点分配到辐射度值高的区域,从而减少不必要的采样,提高渲染质量和速度。
具体步骤如下:
1.
计算辐射度分布
:对辐射度图进行分析,计算每个区域的辐射度值总和。
2.
构建累积分布函数(CDF)
:根据辐射度分布构建 CDF,用于后续的采样。
3.
重要性采样
:生成随机数,根据 CDF 进行采样,选择辐射度值高的区域进行采样。
多分辨率辐射度图
为了在不同的渲染距离和精度要求下都能高效地使用辐射度图,可以采用多分辨率辐射度图。在渲染时,根据相机与场景的距离和渲染精度要求,选择合适分辨率的辐射度图进行采样。
具体实现步骤如下:
1.
生成多分辨率辐射度图
:对原始辐射度图进行降采样,生成不同分辨率的辐射度图。
2.
距离和精度判断
:在渲染时,根据相机与场景的距离和渲染精度要求,选择合适分辨率的辐射度图。
3.
采样与渲染
:使用选择的辐射度图进行采样和渲染。
实时基于图像的光照
为了实现实时基于图像的光照,可以采用预计算和实时计算相结合的方法。预计算部分包括辐射度图的生成和存储,实时计算部分包括根据相机位置和姿态对辐射度图进行采样和光照计算。
具体流程如下:
graph TD;
A[预计算辐射度图] --> B[存储辐射度图];
B --> C[实时获取相机信息];
C --> D[根据相机信息选择辐射度图区域];
D --> E[采样辐射度值];
E --> F[光照计算与渲染];
总结
光线传输和基于图像的光照技术在计算机图形学中具有重要的应用价值。路径追踪算法通过模拟光线的传播路径,能够实现逼真的全局光照效果。基于图像的光照技术则能够让虚拟场景的光照与现实世界相匹配,提高渲染的真实感。
通过本文的介绍,我们了解了路径追踪算法的实现步骤和代码示例,以及基于图像的光照技术的各个环节,包括 HDR 图片处理、辐射度图重建、PFM 文件格式、等距柱状投影、辐射度穹顶定向和渲染等。同时,我们还探讨了这些技术的优化和拓展方法,如辐射度图采样优化、多分辨率辐射度图和实时基于图像的光照等。
在实际应用中,可以根据具体的需求和场景选择合适的算法和技术,不断优化渲染效果和效率。希望本文能够为读者在光线传输和基于图像的光照技术方面提供有益的参考和指导。
| 技术名称 | 关键步骤 | 应用场景 |
|---|---|---|
| 路径追踪算法 | 初始化、读取场景、渲染参数设置、路径追踪、颜色累加、图像输出 | 全局光照渲染 |
| 基于图像的光照技术 | HDR 图片处理、辐射度图重建、等距柱状投影、辐射度穹顶定向和渲染 | 虚拟场景与现实光照匹配 |
| 辐射度图采样优化 | 计算辐射度分布、构建 CDF、重要性采样 | 提高渲染效率和质量 |
| 多分辨率辐射度图 | 生成多分辨率图、距离和精度判断、采样与渲染 | 不同距离和精度要求的渲染 |
| 实时基于图像的光照 | 预计算辐射度图、实时获取相机信息、采样与渲染 | 实时渲染场景 |
通过合理运用这些技术和优化方法,能够在计算机图形学领域实现更加逼真、高效的渲染效果。
超级会员免费看
1041

被折叠的 条评论
为什么被折叠?



