一、简介
本文介绍了如何在半球表面上进行半球面均匀采样
、半球面cos加权采样
采样。
给出了相关公式推导和python代码实现。
二、在半球上采样
0.预备知识
1).球面坐标系与笛卡尔坐标系
在半球面上采样时,常使用球面坐标系
。先采样球面坐标系
下的坐标参数
(
θ
,
ϕ
)
(\theta,\phi)
(θ,ϕ),然后转换为笛卡尔坐标系
参数
(
x
,
y
,
z
)
(x,y,z)
(x,y,z)。两个坐标系下的参数示意图如下:
笛卡尔坐标系
示意图:
球面坐标系
示意图:
从球面坐标系
转为笛卡尔坐标系
的公式如下:
x
=
c
o
s
(
ϕ
)
×
s
i
n
(
θ
)
y
=
c
o
s
(
θ
)
z
=
s
i
n
(
ϕ
)
×
s
i
n
(
θ
)
x = cos(\phi) \times sin(\theta) \\ y = cos(\theta) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\ z = sin(\phi) \times sin(\theta)
x=cos(ϕ)×sin(θ)y=cos(θ) z=sin(ϕ)×sin(θ)
在单位球面坐标系上的立体角微元等于:
d
ω
=
d
A
r
2
=
d
A
\rm{d}\omega = \frac{\rm{d}A}{r^2}=\rm{d}A
dω=r2dA=dA
在单位球面上的面积微元
d
A
\rm{d}A
dA等于:
d
A
=
r
2
×
s
i
n
(
θ
)
d
θ
d
ϕ
=
s
i
n
(
θ
)
d
θ
d
ϕ
\rm{d}A=r^2\times sin(\theta)\rm{d}\theta\rm{d}\phi=sin(\theta)\rm{d}\theta\rm{d}\phi
dA=r2×sin(θ)dθdϕ=sin(θ)dθdϕ
2).逆变换采样
逆变换采样是伪随机数采样的一种基本方法,在已知任意概率分布函数(probability distribution function, PDF)
的累计分布函数(cumulative distribution function, CDF)
时,可以从该PDF
中生成随机样本。本文只简单介绍逆变换采样的步骤和示例,对其推导过程和原理不做过多介绍。
使用逆变换采样方法的步骤如下:
- (1).根据已知的PDF函数 f ( x ) = y f(x)=y f(x)=y,计算对应的CDF函数 F ( X ) F(X) F(X);
- (2).根据 CDF函数 F ( X ) F(X) F(X) 求出其反函数 F − 1 ( Y ) F^{-1}(Y) F−1(Y);
- (3).在[0,1]上均匀采样随机变量 u u u;
- (4).那么 F − 1 ( u ) F^{-1}(u) F−1(u)即为满足PDF函数 f ( x ) = y f(x)=y f(x)=y的随机变量。
示例:
已知PDF函数为 f ( x ) = 1 2 ( x ) exp ( − ( x ) ) , x ≥ 0 f(x)=\frac{1}{2\sqrt(x)}\exp(-\sqrt(x)), x\geq 0 f(x)=2(x)1exp(−(x)),x≥0,求采样得到满足 f ( x ) f(x) f(x)分布的随机变量。
- (1).PDF为 f ( x ) = 1 2 ( x ) exp ( − ( x ) ) , x ≥ 0 f(x)=\frac{1}{2\sqrt(x)}\exp(-\sqrt(x)), x\geq 0 f(x)=2(x)1exp(−(x)),x≥0,那么CDF为 F ( X ) = 1 − e x p ( − ( X ) ) F(X)=1-exp(-\sqrt(X)) F(X)=1−exp(−(X));
- (2).CDF对应的逆函数为 F − 1 ( Y ) = ( l o g ( 1 − Y ) ) 2 F^{-1}(Y)=(log(1-Y))^2 F−1(Y)=(log(1−Y))2;
- (3).在[0,1]上均匀采样随机变量 u u u;
- (4).那么随机变量 x ′ = F − 1 ( u ) = ( l o g ( 1 − u ) ) 2 x'=F^{-1}(u)=(log(1-u))^2 x′=F−1(u)=(log(1−u))2即满足目标PDF函数;
1.在半球面上均匀采样 uniform sample
对于半球面上的均匀采样,PDF应与微元面积成正比,那么对于
ϕ
\phi
ϕ和
θ
\theta
θ的累计密度函数应该为:
C
D
F
(
ϕ
)
=
∫
0
ϕ
∫
0
π
/
2
s
i
n
(
θ
)
d
θ
d
ϕ
∫
0
2
π
∫
0
π
/
2
s
i
n
(
θ
)
d
θ
d
ϕ
=
∫
0
ϕ
∫
0
π
/
2
s
i
n
(
θ
)
d
θ
d
ϕ
2
π
=
ϕ
2
π
C
D
F
(
θ
)
=
∫
0
2
π
∫
0
θ
s
i
n
(
θ
)
d
θ
d
ϕ
∫
0
2
π
∫
0
π
/
2
s
i
n
(
θ
)
d
θ
d
ϕ
=
∫
0
2
π
∫
0
θ
s
i
n
(
θ
)
d
θ
d
ϕ
2
π
=
1
−
c
o
s
(
θ
)
CDF(\phi)=\frac{\int_{0}^{\phi}\int_{0}^{\pi/2}sin(\theta)\rm{d}\theta\rm{d}\phi}{\int_{0}^{2\pi}\int_{0}^{\pi/2}sin(\theta)\rm{d}\theta\rm{d}\phi}=\frac{\int_{0}^{\phi}\int_{0}^{\pi/2}sin(\theta)\rm{d}\theta\rm{d}\phi}{2\pi}=\frac{\phi}{2\pi} \\ CDF(\theta)=\frac{\int_{0}^{2\pi}\int_{0}^{\theta}sin(\theta)\rm{d}\theta\rm{d}\phi}{\int_{0}^{2\pi}\int_{0}^{\pi/2}sin(\theta)\rm{d}\theta\rm{d}\phi}=\frac{\int_{0}^{2\pi}\int_{0}^{\theta}sin(\theta)\rm{d}\theta\rm{d}\phi}{2\pi}=1-cos(\theta)
CDF(ϕ)=∫02π∫0π/2sin(θ)dθdϕ∫0ϕ∫0π/2sin(θ)dθdϕ=2π∫0ϕ∫0π/2sin(θ)dθdϕ=2πϕCDF(θ)=∫02π∫0π/2sin(θ)dθdϕ∫02π∫0θsin(θ)dθdϕ=2π∫02π∫0θsin(θ)dθdϕ=1−cos(θ)
对应的逆函数分别为:
C
D
F
−
1
(
ϕ
′
)
=
2
π
×
ϕ
′
C
D
F
−
1
(
θ
′
)
=
a
r
c
c
o
s
(
1
−
θ
′
)
CDF^{-1}(\phi') = 2\pi \times \phi' \\ CDF^{-1}(\theta') = arccos(1-\theta')
CDF−1(ϕ′)=2π×ϕ′CDF−1(θ′)=arccos(1−θ′)
之后在[0,1]之间均匀采样随机变量
u
1
,
u
2
u1,u2
u1,u2,然后令:
ϕ
=
C
D
F
−
1
(
u
1
)
=
2
π
×
u
1
θ
=
C
D
F
−
1
(
u
2
)
=
a
r
c
o
s
(
1
−
u
2
)
\phi = CDF^{-1}(u1)=2\pi \times u1 \\ \theta = CDF^{-1}(u2)=arcos(1-u2)
ϕ=CDF−1(u1)=2π×u1θ=CDF−1(u2)=arcos(1−u2)
根据上式计算得到的
(
ϕ
,
θ
)
(\phi,\theta)
(ϕ,θ)就满足在半球面上按照面积均匀分布。
下面是采样python代码和结果(需要注意代码中笛卡尔坐标系的Y轴和Z轴做了交换):
代码:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def uniform_sample_hemisphere(n_samples):
points = []
for _ in range(n_samples):
u1 = np.random.rand()
u2 = np.random.rand()
phi = 2 * np.pi * u1 # 计算方位角
theta = np.arccos(1.0-u2) # 计算极角
# 转换到笛卡尔坐标系
x = np.sin(theta) * np.cos(phi)
y = np.sin(theta) * np.sin(phi)
z = np.cos(theta)
points.append((x, y, z))
return np.array(points)
# 生成样本
n_samples = 5000
samples = uniform_sample_hemisphere(n_samples)
# 3D 可视化
fig = plt.figure(figsize=(12, 6))
# 绘制 3D 采样
ax1 = fig.add_subplot(121, projection='3d')
ax1.scatter(samples[:, 0], samples[:, 1], samples[:, 2], alpha=0.6, s=1)
ax1.set_xlabel('X axis')
ax1.set_ylabel('Y axis')
ax1.set_zlabel('Z axis')
ax1.set_title('Uniform Sampling on Hemisphere')
# 绘制 x-y 平面映射
ax2 = fig.add_subplot(122)
ax2.scatter(samples[:, 0], samples[:, 1], alpha=0.6, s=1)
ax2.set_xlabel('X axis')
ax2.set_ylabel('Y axis')
ax2.set_title('Projection onto XY Plane')
ax2.axis('equal')
plt.tight_layout()
plt.show()
可视化结果:
2.在半球上使用cos加权采样
对于半球面上的cos加权均匀采样,PDF应与
微元面积
×
c
o
s
(
θ
)
微元面积\times cos(\theta)
微元面积×cos(θ)成正比,即在
θ
\theta
θ越小的区域采样概率越大,在
θ
\theta
θ越大的区域概率越小,那么对于
ϕ
\phi
ϕ和
θ
\theta
θ的累计密度函数应该为:
C
D
F
(
ϕ
)
=
∫
0
ϕ
∫
0
π
/
2
c
o
s
(
θ
)
s
i
n
(
θ
)
d
θ
d
ϕ
∫
0
2
π
∫
0
π
/
2
c
o
s
(
θ
)
s
i
n
(
θ
)
d
θ
d
ϕ
=
∫
0
ϕ
∫
0
π
/
2
c
o
s
(
θ
)
s
i
n
(
θ
)
d
θ
d
ϕ
π
=
ϕ
/
2
π
=
ϕ
2
π
C
D
F
(
θ
)
=
∫
0
2
π
∫
0
θ
c
o
s
(
θ
)
s
i
n
(
θ
)
d
θ
d
ϕ
∫
0
2
π
∫
0
π
/
2
c
o
s
(
θ
)
s
i
n
(
θ
)
d
θ
d
ϕ
=
∫
0
2
π
∫
0
θ
c
o
s
(
θ
)
s
i
n
(
θ
)
d
θ
d
ϕ
π
=
π
×
s
i
n
2
(
θ
)
π
=
s
i
n
2
(
θ
)
=
1
−
c
o
s
2
(
θ
)
CDF(\phi)=\frac{\int_{0}^{\phi}\int_{0}^{\pi/2}cos(\theta)sin(\theta)\rm{d}\theta\rm{d}\phi}{\int_{0}^{2\pi}\int_{0}^{\pi/2}cos(\theta)sin(\theta)\rm{d}\theta\rm{d}\phi}=\frac{\int_{0}^{\phi}\int_{0}^{\pi/2}cos(\theta)sin(\theta)\rm{d}\theta\rm{d}\phi}{\pi}=\frac{\phi/2}{\pi}=\frac{\phi}{2\pi} \\ CDF(\theta)=\frac{\int_{0}^{2\pi}\int_{0}^{\theta}cos(\theta)sin(\theta)\rm{d}\theta\rm{d}\phi}{\int_{0}^{2\pi}\int_{0}^{\pi/2}cos(\theta)sin(\theta)\rm{d}\theta\rm{d}\phi}=\frac{\int_{0}^{2\pi}\int_{0}^{\theta}cos(\theta)sin(\theta)\rm{d}\theta\rm{d}\phi}{\pi}=\frac{\pi \times sin^{2}(\theta)}{\pi} = sin^{2}(\theta)=1-cos^2(\theta)
CDF(ϕ)=∫02π∫0π/2cos(θ)sin(θ)dθdϕ∫0ϕ∫0π/2cos(θ)sin(θ)dθdϕ=π∫0ϕ∫0π/2cos(θ)sin(θ)dθdϕ=πϕ/2=2πϕCDF(θ)=∫02π∫0π/2cos(θ)sin(θ)dθdϕ∫02π∫0θcos(θ)sin(θ)dθdϕ=π∫02π∫0θcos(θ)sin(θ)dθdϕ=ππ×sin2(θ)=sin2(θ)=1−cos2(θ)
对应的逆函数分别为:
C
D
F
−
1
(
ϕ
′
)
=
2
π
×
ϕ
′
C
D
F
−
1
(
θ
′
)
=
a
r
c
c
o
s
(
1
−
θ
′
)
CDF^{-1}(\phi') = 2\pi \times \phi' \\ CDF^{-1}(\theta') = arccos(\sqrt{1-\theta'})
CDF−1(ϕ′)=2π×ϕ′CDF−1(θ′)=arccos(1−θ′)
之后在[0,1]之间均匀采样随机变量
u
1
,
u
2
u1,u2
u1,u2,然后令:
ϕ
=
C
D
F
−
1
(
u
1
)
=
2
π
×
u
1
θ
=
C
D
F
−
1
(
u
2
)
=
a
r
c
o
s
(
1
−
u
2
)
\phi = CDF^{-1}(u1)=2\pi \times u1 \\ \theta = CDF^{-1}(u2)=arcos(\sqrt{1-u2})
ϕ=CDF−1(u1)=2π×u1θ=CDF−1(u2)=arcos(1−u2)
根据上式计算得到的
(
ϕ
,
θ
)
(\phi,\theta)
(ϕ,θ)就满足在半球面上按照
微元面积
×
c
o
s
(
θ
)
微元面积\times cos(\theta)
微元面积×cos(θ)加权分布。
下面是采样python代码和结果(需要注意代码中笛卡尔坐标系的Y轴和Z轴做了交换):
代码
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def uniform_sample_hemisphere(n_samples):
points = []
for _ in range(n_samples):
u1 = np.random.rand()
u2 = np.random.rand()
phi = 2 * np.pi * u1 # 计算方位角
theta = np.arccos(np.sqrt(1 - u2)) # 计算极角
# 转换到笛卡尔坐标系
x = np.sin(theta) * np.cos(phi)
y = np.sin(theta) * np.sin(phi)
z = np.cos(theta)
points.append((x, y, z))
return np.array(points)
# 生成样本
n_samples = 5000
samples = uniform_sample_hemisphere(n_samples)
# 3D 可视化
fig = plt.figure(figsize=(12, 6))
# 绘制 3D 采样
ax1 = fig.add_subplot(121, projection='3d')
ax1.scatter(samples[:, 0], samples[:, 1], samples[:, 2], alpha=0.6, s=1)
ax1.set_xlabel('X axis')
ax1.set_ylabel('Y axis')
ax1.set_zlabel('Z axis')
ax1.set_title('Uniform Sampling on Hemisphere')
# 绘制 x-y 平面映射
ax2 = fig.add_subplot(122)
ax2.scatter(samples[:, 0], samples[:, 1], alpha=0.6, s=1)
ax2.set_xlabel('X axis')
ax2.set_ylabel('Y axis')
ax2.set_title('Projection onto XY Plane')
ax2.axis('equal')
plt.tight_layout()
plt.show()
结果
三、参考
[1].Sampling the hemisphere