龙空技术网

9.Python趣味数学笔记:三维对象投影到二维平面

吃饱了的饭团 27

前言:

目前姐妹们对“python背景变黑”大约比较注重,我们都想要知道一些“python背景变黑”的相关知识。那么小编也在网上网罗了一些有关“python背景变黑””的相关知识,希望兄弟们能喜欢,我们快快来学习一下吧!

我们在《7.Python趣味数学笔记:三维向量及其运算》一章中,通过多组三维向量绘制出了正八面体的结构。

本章我们将在二维平面上渲染出三维对象的俯视图,以便熟悉上一章的点积和叉积运算。假设:光源为上斜侧光,位置坐标;视角为相对于XY平面的俯视。

如果正八面体是个实体,我们只能看到一侧,也就是四个面。在二维平面上渲染出三维对象的俯视图,相当于对四个面进行着色,同时需要考虑光源照射强弱(使用颜色深浅代表明暗变化)。

基本思路:

1)定义三维空间中的三角形,找到视角内可见的四个三角面

2)找到四个三角面的朝外的法向量

3)将三角面投影到二维平面,得到投影面

4)根据四个三角面距离光源的远近,设置投影面的颜色深浅

三角面和法向量

三个顶点向量可以定义一个三角面,不过只知道面还不够,还需要知道面的朝向。

为此需要合理安排三个顶点向量的顺序,使得叉积后得到的法向量垂直于当前面,而且是朝外的(根据右手法则),这意味着我们可以看到这个面。

另外,我们只需要视角内可见的四个三角面。可以根据向量的Z轴分量的正负判断,取所有为正的。

二维投影

将三维对象投影到二维平面,可以转换成:将定义三维对象的点投影到二维平面,消除一个维度的值。

是不是想到了点积?通过点积计算,我们可以得到:一个向量在另一个向量上面的投影。

为此,我们可以定义两个单位向量:X轴和Y轴,然后跟三角面(视角内可见的四个三角面)的顶点分别计算点积,可以得到投影到二维平面上的点坐标。

假设:,根据点积计算公式:

投影到二维平面上的点坐标:

可以看出,三维向量跟某个坐标轴的单位向量的点积,实际上就是:三维向量在该坐标轴上的投影,也就是三维向量在该坐标轴上的分量。

距离光源的远近

距离光源越近,亮度越高,颜色越发白;距离光源越远,亮度越低,颜色越发黑。

如何度量距离光源的远近?

上一章关于点积,我们提到“一般来说,点积越大,两向量夹角越小,彼此越靠近”。借助于点积,度量距离光源的远近,可以转换成:度量三角面的法向量跟光源向量的夹角大小。

使用cmap设置颜色,需要提供。假设透明度固定为1.0,那么黑色:,白色:,灰色:调整0到1之间的值。

因此,设置颜色的过程,可以使用如下计算方式:

是垂直于三角面的法向量的单位化向量;是光源向量的单位化向量;是三角面的法向量跟光源向量的夹角

因为光源位于斜上方,颜色值的计算结果会落在0到1之间。

部分代码

from draw_objects import Lines,draw_objects#使用点积计算投影长度def component(v,direction):    return dot(v,direction)/length(direction)#三维向量投影到(x,y)平面def vector_to_2d(v):    return (component(v,(1,0,0)),component(v,(0,1,0)))#将单个面投影到(x,y)平面def face_to_2d(face):    return [vector_to_2d(v) for v in face]#转换成单位向量def unit(v):    return scale(1. / length(v), v)#叉积运算得到垂直于三角面的法向量def normal(face):    return  cross(subtract(face[0],face[2]),subtract(face[1],face[2]))#在二维平面上渲染三维对象的投影def render(faces,color_map,light=(1,2,3),lines=None):    lines=[]    #遍历所有面    for face in faces:        #计算垂直于该面的单位向量        unit_normal=unit(normal(face))        #只有当向量的z轴分量为正(指向观察者),俯视图?        if unit_normal[2]>0 :           #法向量和光源的点积越大,说明越靠近光源,阴影越少           value=1-dot(unit_normal,unit(light))           #有效值在[0,1]范围内           if value < 0 :               value=0.0           elif value>1.0:               value=1.0           c=color_map(value)           #print(c)           p=Lines(face_to_2d(face),fill=c,color=lines)           lines.append(p)    draw_objects(*lines,axes=False,origin=False,grid=None)#在二维平面上渲染三维对象的投影,俯视图v=[1,-1]#6个顶点vertexs=[(x,0,0) for x in v]+ \        [(0,y,0) for y in v] + \        [(0,0,z) for z in v]#8个面faces=[    #这里是有顺序的(a,b,c),(a-c)×(b-c)指向八面体外部    [(1,0,0),(0,1,0),(0,0,1)],#右上    [(1,0,0),(0, 0,-1),(0, 1, 0)],#右下    [(1,0,0),(0,0,1),(0,-1,0)],#左上    [(1,0,0),(0,-1,0),(0,0,-1)],#左下    [(-1,0,0),(0,0,1),(0,1,0)],#后右上    [(-1,0,0),(0,1,0),(0,0,-1)],#后右下    [(-1,0,0),(0,-1,0),(0,0,1)],#后左上    [(-1,0,0),(0,0,-1),(0,-1,0)],#后左下]#使用灰色greys=cm.get_cmap('Greys')#在二维平面上渲染三维对象的投影render(faces=faces,color_map=greys,lines=black)
绘制效果图

距离光源越近,亮度越高,颜色越发白;距离光源越远,亮度越低,颜色越发黑:

对比图:

标签: #python背景变黑 #python背景变黑代码