Python 树莓皮的高效三维重建

Python 树莓皮的高效三维重建,python,3d,raspberry-pi2,Python,3d,Raspberry Pi2,我试图在10x10网格中的树莓pi(型号2B)上模拟LED的3d阵列。 我只是希望它们根据模式生成算法打开和关闭 我已经在pi3d中编写了一些基本代码来模拟1000个球体,这些球体放在一个数组中。它在阵列中循环,通过将球体颜色更改为蓝色或黑色来打开或关闭每个led 守则的核心部分如下: spheres = [[[pi3d.Sphere(x=x-5,y=y-5,z=z-5,radius=0.1) for x in range(dim)] for y in range(dim)] for z in

我试图在10x10网格中的树莓pi(型号2B)上模拟LED的3d阵列。 我只是希望它们根据模式生成算法打开和关闭

我已经在pi3d中编写了一些基本代码来模拟1000个球体,这些球体放在一个数组中。它在阵列中循环,通过将球体颜色更改为蓝色或黑色来打开或关闭每个led

守则的核心部分如下:

spheres = [[[pi3d.Sphere(x=x-5,y=y-5,z=z-5,radius=0.1) for x in range(dim)] for y in range(dim)] for z in range(dim)]
i = 0

while DISPLAY.loop_running():
    k = mykeys.read()
    if k == 27:
        mykeys.close()
        ISPLAY.destroy()
        break

    CAM.update(mymouse)
    for x in range (dim):
        for y in range(dim):
            for z in range(dim):
                colour=0.1
                if(((x-dim/2.0) * (x-dim/2.0)) + ((y-dim/2.0) * (y-dim/2.0)) + ((z-dim/2.0) * (z-dim/2.0)) <= i * dim):
                    colour = 1.0
                spheres[x][y][z].set_material((0.0,0.0,colour))
                spheres[x][y][z].draw()
    i=i+0.1
    if i > 4:
        i=0
spheres=[[pi3d.Sphere(x=x-5,y=y-5,z=z-5,半径=0.1)用于x范围内(dim)]用于y范围内(dim)]用于z范围内(dim)]
i=0
在DISPLAY.loop_运行()时:
k=mykeys.read()
如果k==27:
mykeys.close()
ISPLAY.destroy()
打破
更新(我的鼠标)
对于范围内的x(尺寸):
对于范围内的y(变暗):
对于范围内的z(尺寸):
颜色=0.1
如果((x-dim/2.0)*(x-dim/2.0))+((y-dim/2.0)*(y-dim/2.0))+((z-dim/2.0)*(z-dim/2.0))4:
i=0
这很好,但给了我大约5 fps。将球体更改为立方体稍微改善了这一点,但我真的希望至少有一个数量级的性能改进。我知道我可以在数学中提高一些效率,但我经历了类似的性能随机打开和关闭它们,所以我不关注t现在戴帽子

我想这可能只是要求太多的树莓圆周率,但后来玩了它附带的minecraft游戏,发现它有更大的复杂性,同时渲染顺利

我想知道是否有另一种方法,或者甚至是另一种语言,我可以用来提供我想要的性能


我对3d编程知之甚少,因此任何人可以向我提供的建议或教程都可能非常有用。

一个真正好的开始是将所有这些代码放入一个函数中,然后调用该函数。现在,您正在处理的所有内容都被放入全局命名空间中,这无疑是一个好的开始

然后,将循环中当前不需要的所有内容从循环中取出。例如,您可以在绘制球体之前尝试对球体进行着色/纹理处理,或者至少在循环外进行颜色计算(如果可能的话)


如果您想更改语言,请尝试使用,它会将此代码编译为C,同时保留所有库调用等。

在您做任何事情之前,请分析您的代码以查看其运行缓慢的位置。值得注意的是,pi3D的运行速度不一定会像Minecraft的调优3D引擎一样快

一个球体需要很多多边形才能绘制平滑的边。即使保守估计每个球体只有32个多边形,您的多边形总数最终也会是:

10 * 10 * 10 * 32 = 32000
一种简单的优化方法是将球体替换为立方体:

10 * 10 * 10 * 6 = 6000
如果需要球体的外观,可以通过渲染面向摄影机(也称为:广告牌)的1个多边形平面,并在这些平面上渲染球体纹理来进一步减少多边形数

10 * 10 * 10 * 1 = 1000
尝试用乘法而不是除法
10/2
10*0.5
相同,并且不要做两次相同的工作:

x_dim = x - dim * 0.5
y_dim = y - dim * 0.5
z_dim = z - dim * 0.5

if((x_dim * x_dim) + (y_dim * y_dim) + (z_dim * z_dim) <= i * dim):
x_dim=x-dim*0.5
y_尺寸=y-尺寸*0.5
z_尺寸=z-尺寸*0.5

如果((x_dim*x_dim)+(y_dim*y_dim)+(z_dim*z_dim),问题是有python代码为每个pi3d进行矩阵乘法。一次塑造一个。虽然这是使用numpy完成的,并且速度尽可能快,但仍然很慢

您可以将所有球体制作成一个pi3d.MergeShape,这样每帧只需要一个draw(),速度非常快……但是

  • 您的球体对象使用默认值12边x 12个切片,提供288个面和864个顶点,因此您的MergeShape将具有864000个顶点,这可能会开始降低GPU的速度

  • 捆绑着色器仅对整个形状使用一个材质RGB值,您希望为每个球体指定不同的颜色,这将需要一个黑客着色器(如果您习惯于黑客着色器,则很容易做到),在缓冲区阵列的纹理坐标字段中指定RGB值

  • 您的代码不会显示您正在使用的着色器,默认设置为mat_light,这将为每个球体提供平滑的3D效果,但如果您可以使用点(请参见演示Spriteball),则可以快速运行数千个球体…但您仍需修改着色器以改变每个顶点的漫反射颜色

    或者,你可以制作一个半蓝色、半黑色的纹理,并在每一帧中调整各个球体的纹理坐标。假设你已经将所有球体合并成一个形状,这将非常快(尽管会涉及一个笨拙的numpy公式来重现x、y、z嵌套循环的效果)

    在接下来的几天里,我将尝试设计一个演示,展示如何使用这些选项,并将其添加到

    编辑我刚刚想起Starfield.py演示,它使用可变颜色的“billboard”点。这可以在每帧渲染数千个点,但它有各种复杂情况,掩盖了相对简单的结构,正如我上面提到的,我将制作一个更简单的版本,用Eu演示您的10x10x10阵列的颜色变化clidean距离中心的距离

    这里的第二次编辑是使用
    pi3d\u演示/shaders/star\u point

    import pi3d
    import numpy as np
    
    DIM = 10
    half_d = DIM/2.0
    arr_len = DIM ** 3
    
    disp = pi3d.Display.create()
    shader = pi3d.Shader('shaders/star_point')
    cam = pi3d.Camera()
    spheres = pi3d.Points(camera=cam, point_size=400.0, z=15.0,
              vertices=[[x - half_d, y - half_d, z - half_d] for x in range(DIM) for y in range(DIM) for z in range(DIM)],
              normals=np.zeros((arr_len, 3)), tex_coords=np.full((arr_len, 2), 1.0))
    spheres.set_shader(shader)
    arr_buf = spheres.buf[0].array_buffer # shortcut to numpy array shape (1000,8) [[vx,vy,vz,nx,ny,nz,u,v]]
    # the star_point shader uses nx,ny,nz as RGB values, only the B value is being
    # changed here i.e. arr_buff[:,5]
    i = 0
    while disp.loop_running():
      spheres.draw()
      ix = np.where(np.sum((arr_buf[:,:3] - [half_d, half_d, half_d]) ** 2, axis=1) <= i * DIM)[0]
      arr_buf[:,5] = 0.1 # set all to midnight blue first
      arr_buf[ix,5] = 1.0 # set ones within (i * DIM) ** 0.5 to blue
      spheres.re_init() # have to update buffer
      i += 0.1
      if i > 4.0:
        i = 0.0
    
    导入pi3d
    将numpy作为np导入
    尺寸=10
    半尺寸=尺寸/2.0
    arr_len=尺寸**3
    disp=pi3d.Display.create()
    shader=pi3d.shader('shader/star_point')
    cam=pi3d.Camera()
    球体=pi3d。点(相机=凸轮,点大小=400.0,z=15.0,
    顶点=[[x-half_d,y-half_d,z-half_d]对于范围内的x(DIM)对于范围内的y(DIM)对于范围内的z(DIM)],
    法线=np.0((arr_len,3)),tex_坐标=np.full((arr_len,2),1.0))
    球体。设置_着色器(着色器)
    arr_buf=spheres.buf[0].array_buffer#numpy数组形状的快捷方式(1000,8)[[vx,vy,vz,nx,ny,nz,u,v]]
    #明星
    
    import pi3d
    import numpy as np
    
    DIM = 10
    half_d = DIM/2.0
    arr_len = DIM ** 3
    
    disp = pi3d.Display.create()
    shader = pi3d.Shader('uv_light')
    cam = pi3d.Camera()
    tex_array = np.zeros((16,16,3), dtype=np.uint8)
    tex_array[:8,:8] = [0, 0, 25] # top left midnight blue
    tex_array[8:, 8:] = [0, 0, 255] # bottom right bright blue
    tex = pi3d.Texture(tex_array, mipmap=False)
    spheres = pi3d.MergeShape(camera=cam, z=15.0)
    spheres.merge([[pi3d.Sphere(radius=0.1, sides=6, slices=6), x - half_d, y - half_d, z - half_d, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0] 
                                          for x in range(DIM) for y in range(DIM) for z in range(DIM)])
    spheres.set_draw_details(shader, [tex])
    arr_buf = spheres.buf[0].array_buffer # shortcut to numpy array shape (1000,8) [[vx,vy,vz,nx,ny,nz,u,v]]
    arr_buf[:,6:8] *= 0.5 # scale uv to just use top left part of texture
    base_tex_c = arr_buf[:,6:8].copy()
    i = 0
    while disp.loop_running():
      spheres.draw()
      ix = np.where(np.sum((arr_buf[:,:3] - [half_d, half_d, half_d]) ** 2, axis=1) <= i * DIM)[0]
      arr_buf[:,6:8] = base_tex_c # set uv to base (top left)
      arr_buf[ix,6:8] += 0.5 # set index ix to bottome right
      spheres.re_init() # have to update buffer
      i += 0.1
      if i > 4.0:
        i = 0.0