问题描述
我正在尝试在pygame中创建一个简单的3D渲染引擎(我知道,不是最快的程序,但我至少想尝试一下),我使用了this将3D坐标投影到2D屏幕。
接下来,我正在使用ChiliTomatoNoodle's很棒的教程(尽管稍作改动),使用水平(扫描线)光栅化,然后是我自己的zBuffer实现,将3个顶点变成一个实心的实心三角形。
最慢和最有问题的部分是底部的for x in range(lineLength)循环,在该循环中,我尝试将值放入Numpy数组:
# Draw a triangle with a flat top with horizontal rasterization
def drawFlatBottom(p1,p2,p3,col):
global pxarray
global zbuffer
# Calculate slope of line (Is RUN/RISE,not other way around to prevent a slope of infinity)
try:
m1 = (p2[0] - p1[0]) / (p2[1] - p1[1]) # I may be doing this wrong,but this is a hotfix for Now to avoid divide by 0 errors
except ZeroDivisionError:
m1 = 0
try:
m2 = (p3[0] - p1[0]) / (p3[1] - p1[1])
except ZeroDivisionError:
m2 = 0
# Calculate the z slope. Again,is RUN/RISE
try:
mz1 = (p2[2] - p1[2]) / (p2[1] - p1[1])
except ZeroDivisionError:
mz1 = 0
try:
mz2 = (p3[2] - p1[2]) / (p3[1] - p1[1])
except ZeroDivisionError:
mz2 = 0
yStart = int(p1[1])
yEnd = int(p3[1])
if yEnd > height:
yEnd = height
if yStart < 0:
yStart = 0
# Repeat for each row
y = yStart
while y < yEnd:
# Get the x positions where it intercepts with the edge
xStart = int(m1 * (y - p1[1]) + p1[0])
xEnd = int(m2 * (y - p1[1]) + p1[0])
if xEnd > width:
xEnd = width
if xStart < 0:
xStart = 0
lineLength = xEnd - xStart
# Do the same with the z positions
zStart = mz1 * (y - p1[1]) + p1[2]
zEnd = mz2 * (y - p1[1]) + p1[2]
# Find the new slope,RUN/RISE
try:
mz = (zEnd - zStart) / lineLength
except ZeroDivisionError:
mz = 0
z = zStart
# Fill each pixel
for x in range(lineLength):
# Check if the pixel in the z buffer is further away than this pixel
if zbuffer[x + xStart][y] > z:
# Write the new value to the depth buffer
zbuffer[x + xStart][y] = z
# Draw the pixel
pxarray[x + xStart][y] = col
z += mz
y += 1
在函数drawFilledTop()中,p1
,p2
和p3
在屏幕空间中都是格式为[x,y,z]
的列表,并且是三角形的3个顶点。 col
表示(255,255,255)
形式的RGB值。
pxarray
是一个numpy数组,该数组在调用函数drawFlatTop()之前在帧的开头声明:
pxarray = pygame.PixelArray(win)
然后将其关闭:
pygame.PixelArray.close(pxarray)
zbuffer
与pxarray完全相同,只是一个600 x 480的数组,值999以确保绘制第一个三角形:
zbuffer = np.full((width,height),999,dtype=float)
问题
所有这些工作都很好,但速度非常慢。我希望在迭代每个像素时会有点慢,但是我不知道三联A游戏如何在大量的照明和着色器等情况下获得如此高的帧率,但是这个带有4个三角形的简单场景几乎无法达到30fps
我用pprofile生成了一个单帧需要花费多长时间的报告,它显示了我绘制所有4个三角形的函数花费了总运行时间的 44%,即0.316672总运行时间0.342588秒。
这是三角形的实际图形(这是所有平底三角形,drawFlatTop看起来相似):
364| 0| 0| 0| 0.00%| # Fill each pixel
365| 11890| 0.0352542| 2.96503e-06| 10.29%| for x in range(lineLength):
366| 0| 0| 0| 0.00%| # Check if the pixel in the z buffer is further away than this pixel
367| 11673| 0.0446463| 3.82475e-06| 13.03%| if zbuffer[x + xStart][y] > z:
368| 0| 0| 0| 0.00%| # Write the new value to the depth buffer
369| 11673| 0.0573983| 4.91719e-06| 16.75%| zbuffer[x + xStart][y] = z
370| 0| 0| 0| 0.00%|
371| 0| 0| 0| 0.00%| # Draw the pixel
372| 11673| 0.0462677| 3.96366e-06| 13.51%| pxarray[x + xStart][y] = col
373| 0| 0| 0| 0.00%|
374| 11673| 0.0377977| 3.23804e-06| 11.03%| z += mz
问题
向数组中的屏幕/位置值绘制一堆像素的最佳方法是什么?我不希望这么大量的运行时间专门用于将像素绘制到屏幕上!
非常感谢您可以提供的任何帮助:)
编辑: 这些测量是用一个三角形占据屏幕的一小部分来进行的。现在,如果屏幕甚至被像素覆盖一半,它的帧率就会降低到可笑的水平,而在大部分被屏幕覆盖的情况下,它甚至达不到1 FPS。
由于我打算在Arduino上做一个基本的3D游戏,并且时钟速度比我的计算机慢得多,所以我愿意尝试做任何事情来优化此图形。
有没有更快的遍历像素的方法?我什至可以在汇编中写一些东西来最大化效率吗? python是否允许/是否可行?再次感谢您的帮助
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)