三维空间物体视锥投影数学推导

一、三维空间基转换

1.绕原点旋转

二维坐标旋转可以用矩阵表示:

设有向量\textbf{\emph{v}} = (x,y)^T=\begin{bmatrix} x\\y\end{bmatrix},那么当向量\textbf{\emph{v}}绕原点逆时针旋转\theta度,那么旋转矩阵为T= \begin{bmatrix} cos\theta &-sin\theta\\ sin\theta &cos\theta \end{bmatrix}

推导略。

注:向量\textbf{\emph{v}}是列向量,因此旋转后的向量为:\tilde{\textbf{\emph{v}}} = T\textbf{\emph{v}}

旋转矩阵可以推广至更高维度的空间,以三维空间为例:

设有向量\textbf{\emph{v}} = (x,y,z)^T=\begin{bmatrix} x\\y\\z\end{bmatrix},那么当向量\textbf{\emph{v}}z轴逆时针旋转\theta度时,相当于在向量\textbf{\emph{v}}在一个平行于xOy平面的的二维空间中,绕原点旋转,旋转后z坐标保持不变,那么旋转矩阵可以改为:

T_z= \begin{bmatrix} cos\theta_z &-sin\theta_z &0\\ sin\theta_z & cos\theta_z & 0\\ 0 &0 &1 \end{bmatrix}

向量\textbf{\emph{v}}x轴和y轴逆时针旋转\theta度的旋转矩阵为:

T_x= \begin{bmatrix} 1 &0 &0 \\ 0 &cos\theta_x &-sin\theta_x\\ 0 &sin\theta_x & cos\theta_x \end{bmatrix}

T_y= \begin{bmatrix} cos\theta_y &0 &-sin\theta_y\\ 0 &1 &0 \\ sin\theta_y & 0 &cos\theta_y \end{bmatrix}

因此向量\textbf{\emph{v}}在三维空间中,绕原点旋转任意角度,可由以上三个旋转矩阵连乘得到,即:

T = T_zT_yT_z

2.绕特定点旋转

二维空间中绕特定\textbf{\emph{c}}=(x_c,y_c)^T= \begin{bmatrix} x_c\\ y_c \end{bmatrix}旋转可以用以下矩阵乘法表示:

\tilde{\textbf{\emph{v}}} = \begin{bmatrix} 1&0&x_c\\ 0&1&y_c\\ 0&0&1 \end{bmatrix} \begin{bmatrix} cos\theta &-sin\theta &0\\ sin\theta &cos\theta &0\\ 0 &0 &1 \end{bmatrix} \begin{bmatrix} 1&0&-x_c\\ 0&1&-y_c\\ 0&0&1 \end{bmatrix} \textbf{\emph{v}} = \begin{bmatrix} \Lambda & \textbf{\emph{c}}\\ O &1 \end{bmatrix} \begin{bmatrix} T' & O\\ O &1 \end{bmatrix} \begin{bmatrix} \Lambda & -\textbf{\emph{c}}\\ O &1 \end{bmatrix} \textbf{\emph{v}}

其中向量\textbf{\emph{v}}用齐次坐标表示,即\textbf{\emph{v}} = (x,y,1)^T=\begin{bmatrix} x\\y\\1\end{bmatrix}T'= \begin{bmatrix} cos\theta &-sin\theta\\ sin\theta &cos\theta \end{bmatrix}

三个矩阵从右至左的含义分别是:

\begin{bmatrix} \Lambda & -\textbf{\emph{c}}\\ O &1 \end{bmatrix}:平移向量使得空间以\textbf{\emph{c}}为原点

\begin{bmatrix} T' & O\\ O &1 \end{bmatrix}:绕原点\textbf{\emph{c}}旋转

\begin{bmatrix} \Lambda & \textbf{\emph{c}}\\ O &1 \end{bmatrix}:还原空间的原点

推导略。

推广至三维空间,绕特定点\textbf{\emph{c}}=(x_c,y_c,z_c)^T= \begin{bmatrix} x_c\\ y_c\\z_c \end{bmatrix}旋转可以表示为:

\tilde{\textbf{\emph{v}}} = \begin{bmatrix} 1&0 &0 &x_c\\ 0&1 &0 &y_c\\ 0&0 &1 &z_c\\ 0 &0 &0 &1 \end{bmatrix} T_{xyz} \begin{bmatrix} 1&0 &0 &-x_c\\ 0&1 &0 &-y_c\\ 0&0 &1 &-z_c\\ 0 &0 &0 &1 \end{bmatrix} \textbf{\emph{v}} = \begin{bmatrix} \Lambda & \textbf{\emph{c}}\\ O &1 \end{bmatrix} T_{xyz} \begin{bmatrix} \Lambda & -\textbf{\emph{c}}\\ O &1 \end{bmatrix} \textbf{\emph{v}}

其中

\begin{align*} T_{xyz}&= \begin{bmatrix} 1 &0 &0 &0\\ 0 &cos\theta_x &-sin\theta_x &0\\ 0 &sin\theta_x & cos\theta_x &0\\ 0 &0 &0 &1 \end{bmatrix} \begin{bmatrix} cos\theta_y &0 &-sin\theta_y &0\\ 0 &1 &0 &0\\ sin\theta_y & 0 &cos\theta_y &0\\ 0 &0 &0 &1 \end{bmatrix} \begin{bmatrix} cos\theta_z &-sin\theta_z &0 &0\\ sin\theta_z &cos\theta_z & 0 &0\\ 0 &0 &1 &0\\ 0 &0 &0 &1 \end{bmatrix}\\ & = \begin{bmatrix} cos\theta_ycos\theta_z &-cos\theta_y sin\theta_z &-sin\theta_y & 0\\ cos\theta_x sin\theta_z - sin\theta_x sin\theta_y cos\theta_z & cos\theta_x cos\theta_z + sin\theta_x sin\theta_y sin\theta_z & -sin\theta_x cos\theta_y & 0\\ sin\theta_x sin\theta_z + cos\theta_x sin\theta_y cos\theta_z & sin\theta_x cos\theta_z - cos\theta_x sin\theta_y sin\theta_z & cos\theta_x cos\theta_y & 0\\ 0 &0 &0 &1 \end{bmatrix} \end{align*}

3. 

 

二、视锥体成像

1.视点空间中的视椎体成像

如下图所示,在一个视点空间\mathbb{R}^3_s中有一根棍子(线段)AB,其中A=(x_A, y_A, z_A)B=(x_B, y_B, z_B),点S=(x_S,y_S,z_S)为视点,平面xoy|_{z=z_0}为成像平面,A'B'为棍子AB在视平面上的成像。

注:视点空间\mathbb{R}^3_s是一个左手系的三维线性空间

由于点A'和点B'分别是点S和点A和点B的线性组合,因此视线SASB的空间可以表示为

\begin{matrix} &\textbf{A}=(\textbf{x}_A,\textbf{y}_A,\textbf{z}_A)=S+k_A(A-S)\\&\textbf{B}=(\textbf{x}_B,\textbf{y}_B,\textbf{z}_B)=S+k_B(B-S)\end{matrix}  即

\begin{align*} &\textbf{x}_A = x_S+k_A(x_A-x_S)\\ &\textbf{y}_A= y_S+k_A(y_A-y_S)\\ &\textbf{z}_A = z_S+k_A(z_A-x_S)\\ \end{align*} \qquad \begin{align*} &\textbf{x}_B = x_S+k_B(x_B-x_S)\\ &\textbf{y}_B= y_S+k_B(y_B-y_S)\\ &\textbf{z}_B = z_S+k_B(z_B-z_S)\\ \end{align*} \qquad\qquad(1)

k_A=\frac{|S-A'|}{|S-A|}=\frac{|z_S-z_0|}{|z_S-z_A|}, k_B=\frac{|S-B'|}{|S-B|}=\frac{|z_S-z_0|}{|z_S-z_B|}时(z_0为视平面xoy|_{z=z_0}在三维空间中的z坐标),便能得到AB在成像平面xoy|_{z=z_0}上的成像。

根据以上可以得出,视点空间中一个物体的成像和两个因素有关:视线(视点和物体的连线)与视平面的相对角度(直接决定在物体在三维空间中的坐标),视平面在物体和视点间的相对位置(即k

如果将视点S平移至原点(0,0,0),即如下图所示:

那么等式组(1)可以简化为

\begin{matrix} &x'_A = k_Ax_A\\ &y'_A= k_Ay_A\\ &z'_A =k_Az_A\\ \end{matrix} \qquad \begin{matrix} &x'_B = k_Bx_B\\ &y'_B=k_By_B\\ &z'_B = k_Bz_B\\ \end{matrix} \qquad\qquad(2)

其中k_A=\frac{|A'|}{|A|}=\frac{|z_0|}{|z_A|}, k_B=\frac{|B'|}{|B|}=\frac{|z_0|}{|z_B|},因此可以得出:

\begin{align*} x'_A&=\frac{x_Az_0}{z_A}\\ y'_A&=\frac{y_Az_0}{z_A}\\ z'_A&=z_0 \end{align*} \qquad\qquad\begin{align*} x'_B&=\frac{x_Bz_0}{z_B}\\ y'_B&=\frac{y_Bz_0}{z_B}\\ z'_B&=z_0 \end{align*}

在成像平面xoy|_{z=z_0}上,点A'=(x'_A, y'_A)B'=(x'_B, y'_B)即平面成像。

一般情况下,z_0\in (0, min(z_i)), \quad k_i \in (0, 1),即成像屏幕介于视点和物体之间。

2.透视效果

下图是一个二维空间中的成像示意图,视点为s,成像平面为\textbf{S},蓝色实线代表两个离视点距离不同,但是大小相同的物体,蓝色虚线为实际成像,图(a)为正射投影,图(b)为视锥体投影。

从对比图中可以看到,两个一样的物体(物体形状及物体与视平面的角度均一致)在视平面上的正射投影是一致的,但是视椎体投影会因为距离的原因而出现不同的成像,这种现象就是透视效果(近大远小)。

当等式组(2)中的k_i\rightarrow 0\quad(z_0\rightarrow 0)时,即成像屏幕与物体的距离趋向于无穷远时,视椎体投影的比例和正射投影一致,证明略。

3.物体空间到视点空间的转换

物体空间\mathbb{R}^3是一个服从右手系的三维空间,蓝色平面为地面,如下图所示:

下图(b)为视点空间,图(a)是成像平面,图(c)为物体空间。

物体空间中的物体映射到视点空间主要有两部操作:

STEP1 翻转z

STEP2 绕x轴逆时针旋转\pi/2

可以通过转换矩阵实现

\begin{align*} T&= \begin{bmatrix} cos\theta_ycos\theta_z &-cos\theta_y sin\theta_z &-sin\theta_y & 0\\ cos\theta_x sin\theta_z - sin\theta_x sin\theta_y cos\theta_z & cos\theta_x cos\theta_z + sin\theta_x sin\theta_y sin\theta_z & -sin\theta_x cos\theta_y & 0\\ sin\theta_x sin\theta_z + cos\theta_x sin\theta_y cos\theta_z & sin\theta_x cos\theta_z - cos\theta_x sin\theta_y sin\theta_z & cos\theta_x cos\theta_y & 0\\ 0 &0 &0 &1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & -1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \end{align*}

其中\theta_x = -\frac{\pi}{2},\quad\theta_y =\theta_z =0,即:

T & = \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

三、总结

当需要计算一个三维空间\mathbb{R}^3中的物体A_1的二维成像,只需要进行以下两步操作,如下图所示:

STEP1:通过基转换把物体\mathbb{R}^3中的物体A_1转换至视点坐标系\mathbb{R}^3_s中,得到物体A,即:

A_1 &= \begin{bmatrix} x^1_1 &y^1_1 &z^1_1&0\\ x^1_2 &y^1_2 &z^1_2&0\\ \vdots&\vdots&\vdots&\vdots\\ x^1_n &y^1_n &z^1_n &0\\ 0 &0 &0 &1\end{bmatrix}\\

\begin{align*} A &= A_1T= \begin{bmatrix} x_1 &y_1 &z_1 &0\\ x_2 &y_2 &z_2 &0\\ &...&\\ x_n &y_n &z_n &0\\ 0 &0 &0 &1 \end{bmatrix} \end{align*}

其中T & = \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

STEP2:在视点坐标系\mathbb{R}^3_s中,计算物体A'在成像屏幕\textbf{S}|_{z=z_0}处的成像,即:A' = z_0\begin{bmatrix} \frac{1}{z_1 } &0 &\cdots &0\\ 0 & \frac{1}{z_2 } &\cdots &0\\ \vdots & \vdots &\ddots &\vdots\\ 0 &0 &\cdots& \frac{1}{z_n }\\ \end{bmatrix} \begin{bmatrix} x_1 &y_1 &z_1\\ x_2 &y_2 &z_2\\ \vdots&\vdots&\vdots\\ x_n &y_n &z_n \end{bmatrix} = \begin{align*} \begin{bmatrix} x'_1 &y'_1 &z'_0\\ x'_2 &y'_2 &z'_0\\ \vdots&\vdots&\vdots\\ x'_n &y'_n &z'_0 \end{bmatrix} \end{align*}

 

四、PYTHON实现

# -*- coding:utf-8 -*-

import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


def trans_base(x, y, z):
    # 计算三维空间中的旋转矩阵
    Txyz = np.array(
        [
            [np.cos(y) * np.cos(z), -np.cos(y) * np.sin(z), -np.sin(y), 0],
            [np.cos(x) * np.sin(z) - np.sin(x) * np.sin(y) * np.cos(z),
             np.cos(x) * np.cos(z) + np.sin(x) * np.sin(y) * np.sin(z),
             -np.sin(x) * np.cos(y), 0
             ],
            [np.sin(x) * np.sin(z) + np.cos(x) * np.sin(y) * np.cos(z),
             np.sin(x) * np.cos(z) - np.cos(x) * np.sin(y) * np.sin(z),
             np.cos(x) * np.cos(y), 0
             ],
            [0, 0, 0, 1]
        ]
    )
    return Txyz


def gen_cube(a=1):
    # 生成一个以原点为中心,边长为a的正方体
    d = []
    X = np.linspace(a/2, -a/2, 2)
    for x1 in X:
        for x2 in X:
            for x3 in X:
                d.append([x1, x2, x3])
    return np.array(d)


def to_hc(a):
    # 齐次坐标表示矩阵
    a = np.column_stack((a,np.zeros(a.shape[0])))
    r = np.zeros(a.shape[1])
    r[-1] = 1
    a = np.row_stack((a, r))
    return a


def trans_cube(cube, x=0, y=0, z=0):
    # 旋转立方体
    x_ = x / 180 * np.pi
    y_ = y / 180 * np.pi
    z_ = z / 180 * np.pi
    T = trans_base(x_, y_, z_)
    cube2 = to_hc(cube)
    c2 = np.dot(T, cube2.T).T
    return c2[:-1, :-1]


def map_2d(cube, z0):
    # 在二维平面上计算视锥体投影
    cube_ = cube.copy()
    z0_ = max(z0, np.abs(cube_[:, 2].min()))   # 确保立方体不会被成像屏幕穿过
    cube_[:, 2] = cube_[:, 2] + z0_               # 平移立方体
    cube2 = np.dot(np.diag(z0_/cube_[:,2]), cube_)
    l = []
    for i in range(len(cube_)):
        for j in range(len(cube_)):
            d = cube_[i] - cube_[j]
            if d.dot(d)/1-1 < 1E-10:
                tc = np.array([cube2[i], cube2[j]])
                l.append(tc)
    return cube2, l


def plot_2d(cube, thetax, thetay, thetaz, d, color):
    # 旋转并投影
    cube_ = trans_cube(cube, thetax, thetay, thetaz)    # 为了更加生动,对立方体做了旋转
    cube_t = np.dot(trans_cube(cube_, -90, 0, 0), np.diag([1, 1, -1]))   # 从物体空间映射至视点空间
    cube_2d, edges = map_2d(cube_t, d)
    plt.scatter(x=cube_2d[:,0], y=cube_2d[:,1], color=color)
    for e in edges:
        plt.plot(e[:,0], e[:,1], c='grey', alpha=0.3)


def plot_3d(cube, thetax, thetay, thetaz, color):
    # 立方体矩阵
    cube_ = trans_cube(cube, thetax, thetay, thetaz)    # 为了更加生动,对立方体做了旋转
    x, y, z = cube_[:,0], cube_[:,1], cube_[:,2]
    fig=plt.figure()
    ax2 = Axes3D(fig)
    ax2.scatter3D(x, y, z, color=color, s=30)
    for i in range(len(cube_)):
        for j in range(len(cube_)):
            # 绘制棱
            d = cube_[i] - cube_[j]
            if d.dot(d)/1-1 < 1E-10:
                tc = np.array([cube_[i], cube_[j]])
                tx, ty, tz = tc[:,0], tc[:,1], tc[:,2]
                ax2.plot3D(tx, ty, tz, alpha=0.3, c='grey', lw=2)
    fig.show()


# 定义正方体顶角的颜色
color = ['red', 'orange', 'limegreen', 'cyan', 'blue', 'royalblue', 'purple', 'deeppink']

# 生成立方体
cube = gen_cube(a=1)

# 绘图
plot_3d(cube, 45, 45, 45, color)
plot_2d(cube, 45, 45, 45, 1.5, color)    # 近距离投影
plot_2d(cube, 45, 45, 45, 100, color)    # 远距离投影

下图是生成的立方体在三维空间中的呈现:

 

plot_2d函数会生成该立方体在视点空间中的视锥体投影,如下图所示(视距参数z_0=1.5):

如果把视距调远至100,则透视效果将会降低,视锥投影会逼近正射投影,如下图所示:

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 三维物体裁剪 shader 是一种在Unity引擎中使用的渲染技术。它用于在渲染对象时将超出指定区域的部分进行裁剪,只保留目标区域的可见部分进行渲染。三维物体裁剪对于提高渲染性能和减少不必要的计算是非常重要的。 在Unity中,三维物体裁剪 shader 主要通过在渲染流水线的不同阶段中进行操作来实现。它需要将物体的顶点数据传入 shader 中进行处理,并根据裁剪区域的定义来判断是否需要丢弃某些顶点或面。裁剪的结果会影响到后续的几何计算和光栅化过程,从而只渲染裁剪区域内的可见部分。 在编写三维物体裁剪 shader 时,需要定义裁剪区域的边界条件,通常是一个包围盒或一个几何体,来限制渲染的范围。裁剪 shader 还可以根据需要选择采用不同的裁剪算法,例如平面裁剪、多边形裁剪等,以满足场景需求。 另外,为了提高裁剪性能,可以使用一些优化技术,如视锥剔除 (frustum culling)、遮挡剔除 (occlusion culling) 等来减少不必要的渲染计算。这些技术可以在场景中动态地判断物体是否在视野范围内,并且不在则直接剔除,节省渲染资源。 总之,三维物体裁剪 shader 是一项重要的技术,它通过裁剪不可见部分,提高渲染性能,并且可以根据需求来定义裁剪区域和算法,为游戏和应用程序的渲染过程带来更好的效果和性能。 ### 回答2: 三维物体裁剪是指在计算机图形学中,通过某种算法将三维物体在渲染过程中裁剪成适合显示的部分。使用裁剪shader可以实现这一过程。在Unity引擎中,我们可以使用裁剪shader来处理在渲染管线中对物体进行裁剪操作。 裁剪shader在渲染过程的不同阶段被调用,其中最常见的是在顶点着色器和片段着色器中。在顶点着色器中,我们可以根据物体的位置,将超出视锥体的顶点进行裁剪,从而减少不需要渲染的部分。这样可以大大提高渲染效率。 在片段着色器中,我们可以使用裁剪算法的结果来决定是否绘制当前片段。例如,在使用手绘效果的时候,我们可以将线条渲染在物体的表面上,并通过裁剪算法来决定需要渲染的线条。 裁剪shader可以使用多种裁剪算法,如视锥体裁剪、平面裁剪、正交裁剪等。每种算法都有其独特的优缺点,可以根据需求选择合适的算法。裁剪shader还可以根据物体的位置、大小和旋转等属性,对物体进行不同的裁剪操作。 总之,裁剪shader在三维物体的渲染过程中起着重要的作用。通过裁剪算法,我们可以将不需要显示的部分裁剪掉,从而提高渲染效率和视觉效果。在Unity中,我们可以通过编写裁剪shader来实现这一功能,从而实现更加灵活和高效的渲染。 ### 回答3: 三维物体裁剪是指在计算机图形学中,通过特定的算法和技术对三维物体进行可视化处理,将其在屏幕上显示出来。而裁剪(shader)是指在计算机图形学中,使用着色器(Shader)对三维物体进行剪裁操作,以提高渲染效率和视觉效果。 在Unity中,三维物体裁剪通常通过使用着色器来实现。着色器是一种用于描述渲染效果的代码,Unity使用的是基于HLSL (High-Level Shading Language)的着色器语言。通过编写自定义的裁剪着色器,我们可以实现不同类型的裁剪效果。 在编写三维物体裁剪着色器时,我们通常会使用裁剪平面的概念。裁剪平面是一个虚拟的平面,可以将物体中在平面两侧的部分分别裁剪掉或保留下来。通过在裁剪着色器中添加适当的代码,我们可以根据裁剪平面的位置和法线,对物体进行裁剪操作。 裁剪着色器还可以与其他渲染效果结合使用,例如使用透明度贴图实现透明效果,使用法线贴图实现凹凸效果等。通过合理地组织和调整裁剪着色器的代码,我们可以达到更好的渲染效果和性能。 在使用Unity进行三维物体裁剪时,我们可以借助Unity内置的ShaderGraph工具或编写自定义着色器来实现。ShaderGraph是Unity的一种可视化着色器编辑器,使得裁剪效果的实现更加直观和便捷。 总而言之,使用裁剪着色器可以对三维物体进行裁剪操作,从而提高渲染效率和视觉效果。Unity提供了丰富的工具和编程语言支持,使得裁剪着色器的开发变得更加简单和灵活。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值