四维空间的二维线框投影可视化(附matlab代码)

写这篇博客的动机是来源于Matrix67大神的一篇博客
不同维度的对话:带你进入四维世界http://www.matrix67.com/blog/archives/1323

里面有非常酷炫的展示效果。很早就想实际实践一波,但是实际动手才发现要想获得可视化效果还是不容易的。

之后查找相关的资料,发现Steven Richard Hollasch的Four-Space Visualization of 4D Objects在四维可视化部分写的非常的详细。详情可以点击http://hollasch.github.io/ray4/Four-Space_Visualization_of_4D_Objects.html。页面打不开的话,在bing上搜索这篇文章,有Cached镜像。
注意它默认用到的是左手坐标系。本文由于采用的是对称的正方体进行演示,所以用的是右手坐标系,不太影响展示效果,所以没有加以修正。

还是惯例声明:本人没有相关的工程应用经验,只是纯粹对相关算法和展示效果感兴趣才写此博客。所以如果有错误,欢迎在评论区指正,不胜感激。本文主要关注于算法的实现,对于实际应用等问题本人没有任何经验,所以也不再涉及。

1 三维空间在2维屏幕上的投影

首先常见的三维空间在2维屏幕上的投影,用来验证算法的正确性。

由于眼睛结构构造的限制,视网膜只能接受二维的光线信息。我们人类直接观察3维物体时,丢失掉垂直于视网膜方向上的维度信息,也就是物体距离眼睛的距离,或者可以叫景深。这常常被应用与某些3维游戏设计,或者一些视觉错觉方面。
当然人类也可以间接的通过两只眼睛进行距离判断,或者根据参照物,或者运动时物体相对关系,或者眼球的运动等间接因素,来感知距离。当然,这不是本文的重点。

本文拟根据相机或眼球的拍摄投影原理,进行3维空间在2维屏幕上投影的算法概述。

1.1平行投影

首先我们定义观察原点From,观测方向点To,以及定义向上方向Up。如下图所示:
在这里插入图片描述
我们的看物体的方向是从From点到To点,投影到屏幕上后,还需要定义哪里是上方,也就是从From点到Up点。

之后,求出刚才3个观察点所确定的ABC坐标系,作为眼睛坐标系。
C = T o − F r o m ∥ T o − F r o m ∥ C=\frac{To-From}{\lVert To-From \rVert} C=ToFromToFrom
A = U p × C ∥ U p × C ∥ A=\frac{Up \times C}{\lVert Up \times C \rVert} A=Up×CUp×C
B = C × A B=C \times A B=C×A
其中, ∥ X ∥ \lVert X \rVert X代表向量的2范数,或者可以叫做绝对值,它的值等于向量每个元素平方和的开根号。 C × A C \times A C×A代表向量C叉乘以向量A,得到的结果仍然是一个向量,垂直于A和C。

之后,真实空间中某个点的Px、Py、Pz坐标就可以转换为眼睛坐标系下的坐标P’:
P ′ = [ P x ′ P y ′ P z ′ ] = [ ( P x − F x ) ( P y − F y ) ( P z − F z ) ] ∗ [ A x B x C x A y B y C y A z B z C z ] P'=\left[ \begin{matrix} P'_x& P'_y& P'_z\\ \end{matrix} \right] \\ =\left[ \begin{matrix} (P_x-F_x)& (P_y-F_y)& (P_z-F_z)\\ \end{matrix} \right] *\left[ \begin{matrix} A_x& B_x& C_x\\ A_y& B_y& C_y\\ A_z& B_z& C_z\\ \end{matrix} \right] P=[PxPyPz]=[(PxFx)(PyFy)(PzFz)] AxAyAzBxByBzCxCyCz
上式中,Fx、Fy、Fz对应着观察点的位置,可以视为From点的坐标。公式中Ax、Ay、Az代表之前求出的A向量三个值,其余B和C向量同理。

到此,我们得到了新的空间上一点的坐标。其中P’x和P’y是在2维上的投影坐标,P’z是距离2维平面的距离。绘图时,只需要绘制P’x和P’y即可。

所以三维投影到二维算法步骤大致为:

1定义From、To、Up点
2计算对应着ABC坐标
3将实际坐标P(x,y,z)转换到眼睛坐标P'(x,y,x)
4绘制P'(x,y)作为2维投影

matlab代码如下:

%创建3维物体的二维投影(平行)
clear
clc
close all

for k=0:1:40
    
    %创建3维立方体
    Line_AB = Create_Cube(3);
    Line_AB = Line_AB*2-1;
    N=size(Line_AB,1);
    Line_List_1 = Line_AB(:,1:3)';
    Line_List_2 = Line_AB(:,4:6)';
    %旋转一定角度
    Line_List_1 = Ro_Ma_3D(2,pi/80*k)*Ro_Ma_3D(1,pi/80*k)*Line_List_1;
    Line_List_2 = Ro_Ma_3D(2,pi/80*k)*Ro_Ma_3D(1,pi/80*k)*Line_List_2;
    %定义To From Up
    To = [0,0,0];
    From = [0,0,1];
    Up = [0,1,0];
    %3D眼睛坐标
    C = (To-From)/norm(To-From);
    A = cross(C,Up)/norm(cross(C,Up));
    B = cross(A,C);
    ABC = [A',B',C'];
    %xyz坐标下的点转换
    Line_AB_ABC = zeros(size(Line_AB));
    F_xyz = [0,0,0];%定义原点,透视视角有用
    Line_ABC_1 = (Line_List_1'-ones(N,1)*F_xyz)*ABC;
    Line_ABC_2 = (Line_List_2'-ones(N,1)*F_xyz)*ABC;

    
    %投影到2D屏幕上
    figure(1)
    clf
    hold on
    for m = 1:size(Line_AB_ABC,1)
        P1 = Line_AB_ABC(m,1:2);
        P2 = Line_AB_ABC(m,4:5);
        plot([Line_ABC_1(m,1),Line_ABC_2(m,1)],[Line_ABC_1(m,2),Line_ABC_2(m,2)])
    end
    hold off
    xlim([-2,2])
    ylim([-2,2])
    pause(0.5)
end







function Line_AB = Create_Cube(Dim)
%创建Dim维度的正方体,坐标范围0-1
%Dim = 3;
Line_AB = zeros(1,2*Dim);
Line_AB(Dim+1) = 1;
Line_AB_Old = Line_AB;
for k = 2:Dim
    %向另一个维度复制
    P_Old = size(Line_AB_Old,1);%上一个维度的线数
    Line_AB_New1 = [Line_AB_Old;Line_AB_Old];
    Line_AB_New1(P_Old+1:end,k) = 1;
    Line_AB_New1(P_Old+1:end,Dim+k) = 1;
    %连接相邻维度的线
    P_Old2 = 2^(k-1);%上一个维度的点数
    Vertex2 = Full_Choose([0;1],k-1);
    Line_AB_New2 = zeros(P_Old2,2*Dim);
    Line_AB_New2(:,1:k-1) = Vertex2;
    Line_AB_New2(:,Dim+1:Dim+k
  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的PyOpenGL三空间可视化代码示例,它使用了PyOpenGL和Pygame库。它创建了一个立方体,并使用键盘控制旋转和缩放。 ```python import pygame from pygame.locals import * from OpenGL.GL import * from OpenGL.GLU import * vertices = ( (1, -1, -1), (1, 1, -1), (-1, 1, -1), (-1, -1, -1), (1, -1, 1), (1, 1, 1), (-1, -1, 1), (-1, 1, 1) ) edges = ( (0, 1), (0, 3), (0, 4), (1, 2), (1, 5), (2, 3), (2, 7), (3, 6), (4, 5), (4, 6), (5, 7), (6, 7) ) def Cube(): glBegin(GL_LINES) for edge in edges: for vertex in edge: glVertex3fv(vertices[vertex]) glEnd() def main(): pygame.init() display = (800, 600) pygame.display.set_mode(display, DOUBLEBUF|OPENGL) gluPerspective(45, (display[0]/display[1]), 0.1, 50.0) glTranslatef(0.0, 0.0, -5) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: glTranslatef(-0.5, 0, 0) if event.key == pygame.K_RIGHT: glTranslatef(0.5, 0, 0) if event.key == pygame.K_UP: glTranslatef(0, 0.5, 0) if event.key == pygame.K_DOWN: glTranslatef(0, -0.5, 0) if event.key == pygame.K_KP_PLUS: glTranslatef(0, 0, 1) if event.key == pygame.K_KP_MINUS: glTranslatef(0, 0, -1) glRotatef(1, 3, 1, 1) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) Cube() pygame.display.flip() pygame.time.wait(10) main() ``` 该程序创建了一个名为`Cube()`的函数,该函数绘制了一个立方体。它使用了OpenGL的`glBegin()`和`glEnd()`函数来绘制线框,并使用glVertex3fv()函数指定每个顶点的坐标。在主循环中,使用键盘事件来控制立方体的旋转和缩放。在每个循环迭代中,使用`glRotatef()`函数和`glTranslatef()`函数来旋转和平移立方体,然后使用`glClear()`函数来清除屏幕并绘制立方体。最后,使用`pygame.display.flip()`函数来更新屏幕。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值