???????学霸笔记
???????还是学霸笔记
???????写这个作业写
b
u
g
bug
bug 写到吐了,首先强调一点,
w
i
n
d
o
w
window
window 下跑这份代码的同学,需要修改
g
l
o
b
a
l
.
c
p
p
global.cpp
global.cpp 中的
g
e
t
_
r
a
n
d
o
m
_
f
l
o
a
t
get\_random\_float
get_random_float 函数,不然你的这个"随机函数"每次都是跑出来相同的结果(而且改了这个函数显著的提升效率,
l
i
n
u
x
linux
linux 的同学应该也可以改改)。
???????修改如下👇
static std::random_device dev;
static std::mt19937 rng(dev());
static std::uniform_real_distribution<float> dist(0.f, 1.f);
inline float get_random_float()
{
return dist(rng);
}
???????前三个函数参考作业6,差异在于
I
n
t
e
r
s
e
c
t
P
IntersectP
IntersectP 函数的判别条件,因为这个灯 tmd 没有厚度,你以文本格式查看
l
i
g
h
t
.
o
b
j
light.obj
light.obj 可以发现它的顶点
Y
Y
Y 值相同。而路径追踪中,间接光照的最终光来源都是灯,如果与灯求交都是
f
a
l
s
e
false
false,那最终的结果肯定是全黑。
return (t_enter < t_exit) && (t_exit >= 0);
???????改为👇
return (t_enter <= t_exit) && (t_exit >= 0);
???????
c
a
s
t
R
a
y
castRay
castRay 函数我按
s
h
a
d
e
shade
shade 函数的伪代码来实现,其中第二个参数
d
e
p
t
h
depth
depth 貌似没用,所以我去掉了。代码如下👇
Vector3f Scene::castRay(const Ray &ray) const
{
Intersection inter = this->intersect(ray);
if (inter.happened){
if (inter.m->hasEmission()){
return inter.m->getEmission();
}
Vector3f L_dir, L_indir;
Intersection pos;
float pdf = 0;
sampleLight(pos, pdf);
Vector3f wo = ray.direction;
Vector3f p = inter.coords;
Vector3f N = inter.normal;
Vector3f x = pos.coords;
Vector3f NN = pos.normal;
Vector3f emit = pos.emit;
Vector3f ws = normalize(x - p);
float length_sq = length_square(x - p);
Ray light(p, ws);
Intersection tmp_pos = this->intersect(light);
if (tmp_pos.happened && length_square(tmp_pos.coords - x) <= EPSILON){
L_dir = emit * inter.m->eval(wo, ws, N) * dotProduct(ws, N) * dotProduct(-ws, NN)
/ length_sq / pdf;
}
if (get_random_float() <= RussianRoulette){
Vector3f wi = normalize(inter.m->sample(wo, N));
Ray reflect(p, wi);
Intersection re_inter = this->intersect(reflect);
if (re_inter.happened && !re_inter.m->hasEmission()){
L_indir = castRay(reflect) * inter.m->eval(wo, wi, N) * dotProduct(wi, N)
/ inter.m->pdf(wo, wi, N) / RussianRoulette;
}
}
return L_dir + L_indir;
}
return Vector3f{};
}
???????几个关键的点:
-
直视灯光的时候应该直接把灯光显示出来,即返回灯光的自发光 emission -
伪代码部分的
L
_
d
i
r
L\_dir
L_dir 计算是有小错误的,
c
o
s
θ
′
cos\theta'
cosθ′ 对应的
d
o
t
(
w
s
,
N
N
)
dot(ws,NN)
dot(ws,NN) 应改为
d
o
t
(
?
w
s
,
N
N
)
dot(-ws,NN)
dot(?ws,NN),理由如下图所示,计算
c
o
s
θ
′
cos\theta'
cosθ′ 时需要把
w
s
ws
ws 的方向倒置。 -
光线中间无阻碍理解为最终的交点相近,精度误差控制自行定义。 -
求
L
_
i
n
d
i
r
L\_indir
L_indir 时,
c
a
s
t
R
a
y
castRay
castRay 的函数入口处的
!
r
e
_
i
n
t
e
r
.
m
?
>
h
a
s
E
m
i
s
s
i
o
n
(
)
!re\_inter.m->hasEmission()
!re_inter.m?>hasEmission() 保证了下一个交点不是光源,所以能保证
i
n
t
e
r
.
m
?
>
g
e
t
E
m
i
s
s
i
o
n
(
)
inter.m->getEmission()
inter.m?>getEmission() 只在直视灯光时返回结果。
???????
S
P
P
=
1
SPP=1
SPP=1 👇
???????
S
P
P
=
200
SPP=200
SPP=200 👇
???????
S
P
P
=
20
SPP=20
SPP=20,
c
n
t
?
o
f
?
s
a
m
p
l
e
=
20
cnt\ of\ sample=20
cnt?of?sample=20 👇
|