2017-05-01 5 views
2

10x10x10 격자의 라즈베리 파이 (모델 2B)에 3 차원 LED 배열을 모델링하려고합니다. 패턴 생성 알고리즘에 따라 간단히 켜고 끄기를 원할뿐입니다.라즈베리 파이에 대한 효율적인 3d

필자는 배열로 보유 된 1000 개의 구형 모델을 만들기 위해 pi3d에 몇 가지 기본 코드를 작성했습니다. 배열을 순환하고 구체의 색상을 파란색 또는 검은 색으로 변경하여 각 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 

하지만, 나에게 약 5 FPS를 제공합니다. 구체를 큐브로 변경하면이 기능이 약간 향상되었지만 최소한 성능은 어느 정도 향상되었습니다. 저는 수학에서 몇 가지 효율성 향상이 있었음을 알고 있지만, 비슷한 성능을 무작위로 켜고 끄는 것을 경험했습니다. 그래서 지금은 그것에 집중하지 않을 것입니다.

아마도 이것은 단지 나무 딸기 파이를 너무 많이 묻는 것일 뿐이지 만, 번들로 제공되는 미니 크래프트 게임을 재생하고 원활하게 렌더링하는 동안 더 복잡 해지는 것을 발견했습니다.

내가 원하는 성능을 제공하기 위해 사용할 수있는 또 다른 접근법 또는 다른 언어가 있는지 궁금합니다.

3D 프로그래밍이 거의 없으므로 누구나 나를 가리켜 줄 수있는 제안이나 자습서가 유용 할 수 있습니다.

+0

당신이 사용하고있는 3D 패키지를 설명하기 위해 답을 수정하십시오 – Soviut

+1

@Soviut 이미 나열되어 있습니다 ... [pi3d] (http://pi3d.github.io/html/index.html) – Aaron

답변

1

문제는 파이썬 코드가 각 pi3d.Shape에 대해 한 번에 하나씩 행렬 곱셈을 수행한다는 것입니다. 이것은 numpy를 사용하여 이루어 지지만 가능한 한 빠르지 만 여전히 느립니다.

당신은 프레임 당 만 1 무 필요합니다 하나 pi3d.MergeShape()로 구를 모두 만들 수 있으며, 매우 빠른 것입니다 ... 그러나

  1. 귀하의 구체 객체는 기본값을 사용 12면 × 12 조각으로 288면과 864 개의 정점을 제공하므로 MergeShape에 864,000 개의 꼭지점이 생겨 GPU의 속도가 느려지 게됩니다.

  2. 번들 셰이더는 전체 셰이프에 대해 하나의 재료 RGB 값을 사용하기 때문에 해킹 된 셰이더가 필요한 각 영역마다 다른 색을 지정해야합니다 (셰이더 해킹에 익숙하다면 쉽게 할 수 있음). 버퍼 배열의 텍스처 좌표 필드에 RGB 값을 지정하십시오.

당신이 기본이 각 영역에 대한 부드러운 3D 효과를 줄 것이다 mat_light됩니다 사용하고있는 쉐이더하지만 (데모 SpriteBalls 참조) 포인트를 관리 할 수있는 경우 표시되지 않습니다 코드는 당신이 할 수 수천 개의 구가 빠르게 실행됩니다 ...하지만 각 버텍스의 확산 색상을 변경하려면 쉐이더를 수정해야합니다.

또는 텍스처를 절반 파란색으로, 검정색으로 만들고 각 프레임의 다양한 영역의 텍스처 좌표를 조정할 수 있습니다. 모든 구체를 하나의 모양으로 병합했다고 가정하면 매우 빠르고 (x, y, z 중첩 루프의 효과를 재현 할 수있는 늠름없는 수식을 포함하지만)

앞으로 며칠 동안 이 옵션을하고 난 그냥 변수 색상 '빌보드'포인트를 사용하는 Starfield.py 데모를 기억 https://github.com/pi3d/pi3d_demos

편집에 추가하는 방법을 보여주는 데모를 고안한다. 이것은 매 프레임마다 수천 개의 포인트를 렌더링 할 수 있지만 비교적 단순한 구조를 모호하게 만드는 모든 종류의 복잡성을 가지고 있습니다. 위에서 언급했듯이 센터에서 유클리드 거리를 사용하여 색상 변경을 통해 10x10x10 어레이를 데모하는 간단한 버전을 만들 것입니다. 여기

2 편집 pi3d_demos/shaders/star_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 

를 사용 빌보드 또는 스프라이트 버전 여기 MergeShape 후 자외선을 조정 사용 버전 I 발견

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 

좌표 그 배열 버퍼의 크기 기본 Sphere에서 너무 커져서 6x6 버전으로 축소되었습니다. 희망이 누군가가 어떤 단계에서 도움이됩니다.

+0

MergeShape를 사용해 보았지만, 그것 안에서 물건을 바꾸지 마라. 당신의 다른 제안이 필자가 필요로하는 성능을 얻는 데 충분해야한다. 감사합니다! – user1111284

+0

예제는 약간 희소하지만 두려운 것이지만 여러분은 무슨 일이 일어나는지 파악할 수있을 것입니다. 당신이 shape (16,16,4) – paddyg

+0

을 사용하여 alpha로 텍스처를 생성 할 수있는 uv 조정 버전을 사용하면 루프 전에 ditances 배열을 계산하는 라인을 수행 할 수 있다는 것을 잊어 버렸습니다. ix = np.where (A > = i) 루프 내부에서 좀 더 빠른 속도. 중심점이 움직이지 않는 한. – paddyg

-1

정말 좋은 시작은이 코드를 모두 함수에 넣은 다음 해당 함수를 호출하는 것입니다. 지금은 작업중인 모든 것을 glob namespace에 넣고 있습니다. 의심 할 여지없이 slow입니다.

그런 다음 루프 안에있을 필요가없는 현재 루프 안에있는 모든 것을 가져옵니다. 예를 들어 구를 그리기 전에 구체를 채색/텍스처링하거나 적어도 루프 밖에서 색상 계산을 수행 할 수 있습니다 (가능한 경우).

당신은 아무것도하기 전에 실행의 위치를 ​​확인하는 코드를 프로파일

+0

전역은 파이썬에서 특별히 느리지 않습니다. – Aaron

+0

@Aaron은 당신입니까? (확실합니까?) (http://stackoverflow.com/questions/11241523/why-does-python-code-run-faster-in-a-function) (이 CPython 특정,하지만 가정 표준 파이썬 간주됩니다) –

+0

예. 여러 가지 이유가 있습니다 : [* 그건 그렇고, 글로벌 조회는 여전히 매우 최적화되어 있습니다 *] ​​(http://stackoverflow.com/a/11242447/3220135) 네임 스페이스 조회는 아마도 여기에서 둔화가 아닙니다. 이것은 .001 %의 속도 향상이되는 조기 최적화입니다. – Aaron

1

등, 라이브러리 호출을 모두 유지하면서, C에이 코드를 컴파일 cython을 사용해보십시오 언어를 변경하려면 천천히. pi3D가 Minecraft의 튜닝 된 3D 엔진만큼 빠르게 실행되지는 않는다는 점은 주목할 가치가 있습니다.

구체에는 부드러운 가장자리를 그리려면 많은 다각형이 필요합니다. 당신의 모양을 원하는 경우

10 * 10 * 10 * 6 = 6000 

:

10 * 10 * 10 * 32 = 32000 

쉬운 최적화 큐브 구체를 대체하는 것입니다 : 영역 당 32 다각형 심지어 보수적 인 추정치는 총 폴리곤 수는 웰빙 바람이 spheres를 사용하면 구형의 텍스처를 가진 카메라 (일명 광고 게시판)를 마주 보는 1 개의 다각형 평면을 렌더링하여 다각형 수를 더 줄일 수 있습니다.대신 10/2 나눔의 곱

10 * 10 * 10 * 1 = 1000 

봅니다 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): 

를 마지막 시도 만 draw()를 호출 한 번 전체 장면에 오히려보다는 각 구.

+0

라고도합니다. 광고판이나 [sprites] (https://en.wikipedia.org/wiki/Sprite_ (computer_graphics)) – Aaron

+0

* "구체를 입방체로 변경하면이 부분이 조금 개선되었습니다"* - 질문에서. – Ryan

+0

한 장면에서 전체 장면을 다시 그려 보면 큰 발전이 될 것입니다. pi3d에서는 그렇게 할 수있는 방법을 볼 수 없지만 한 번에 모든 것을 다시 그리기 위해 물건을 넣을 수있는 장면 그래프 나 캔버스가없는 것 같습니다. 하나의 캔버스 객체를 보았지만 그저 2D 드로잉 인 것처럼 보였습니다 – user1111284

관련 문제