蒙特卡洛光線追蹤技術系列 見 蒙特卡洛光線追蹤技術
我們現在可以對以前的積分進行採樣
I = integral(x^2, 0, 2)
我們需要解釋x的pdf的不均勻性。如果我們在某個位置的樣本太多,我們應該降低其權重。
比如我們之前的例子,分兩段,要計算從0-2的平均值,從1-2產生了150個數據,從0-1產生了50個數據,則最後的結果就是需要用1-2的150個數據的和除以150,再加上0-1的和除以50,而不是直接用所有的和除以200
pdf 是一個很好的度量方法,可以用來衡量在不同位置抽樣的多少。所以權重函數應該與 1/pdf 成正比。實際上就是1/pdf:
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "time.h"
double myRandom() {
return rand() / (RAND_MAX + 1.0);
}
inline float pdf(float x) {
return 0.5*x;
}
int main() {
int N = 1000000;
double sum = 0.0;
for (int i = 0;i < N;i++) {
double x = sqrt(4 * myRandom());
if (x == 0)printf("error\n");
sum += x*x / pdf(x);
}
printf("I = %lf \n",sum/N);
system("pause");
}
結果打印了一堆error,表示有的x是0,所以還是得修改一下原程序:
int main() {
int N = 1000000;
double sum = 0.0;
for (int i = 0;i < N;i++) {
double x = sqrt(4 * myRandom());
if (x == 0) {
printf("error\n");
}
else {
sum += x*x / pdf(x);
}
}
printf("I = %lf \n",sum/N);
system("pause");
}
打印結果爲:
說明估計是很準的。
由於我們在被積函數較大的地方採樣更多,我們就可能得到更少的噪聲,從而更快地收斂。這就是爲什麼使用精心選擇的非均勻pdf通常被稱爲重要性抽樣。
如果我們對相同的代碼取相同的樣本,使 pdf = ½ 在[0,2]範圍內,我們可以使用機器得到x=2*drand48(),代碼是:
inline float pdf(float x) {
return 0.5;
}
int main() {
int N = 1000000;
float sum = 0.0;
for (int i = 0;i < N;i++) {
float x = 2 * myRandom();
if (x == 0) {
printf("error\n");
}
else {
sum += x*x / pdf(x);
}
}
printf("I = %lf \n", sum / N);
system("pause");
}
請注意,我們不再需要2*sum/N中的2了-這是由pdf處理的,當您除以它時,pdf是0.5。你會注意到重要性抽樣有點幫助,但不是很大。我們可以使pdf完全遵循被積函數:
p(x) = (3/8)x^2
我們得到相應的:
P(x) = (⅛)x^3
以及
P^-1(x) = pow(8x,⅓)
只有當我們已經知道答案(通過解析積分p得到P)時,這種完美的重要性抽樣纔是可能的,但是這是確保代碼工作的一個很好的練習。
我們只需要一個樣品:
inline float pdf(float x) {
return 3*x*x/8;
}
int main() {
int N = 1;
float sum = 0.0;
for (int i = 0;i < N;i++) {
float x = pow(8*myRandom(),1./3.);
if (x == 0) {
printf("error\n");
}
else {
sum += x*x / pdf(x);
}
}
printf("I = %lf \n", sum / N);
system("pause");
}
得到結果:
現在讓我們回顧一下,因爲這是MC光線跟蹤器的基本概念。
1. 在某個域 [a,b] 上有f(x)的積分。
2. 你在[a,b]上選擇一個非零的pdf p。
3. 一大堆 f(r)/p(r) 取平均,其中 r 是隨機數 r 和pdf p。
這總是會收斂到正確的答案。p跟隨 f 的次數越多,它的收斂速度就越快。