快速设置像素

8

我已经寻找了很久,但依然无法找到一个好的答案,现在我已经非常沮丧了。我是一名业余程序员,我做事情并不是因为它们有意义,或者因为它们是正确的方式;我做这些只是为了学习如何做,而现在我卡住了。

我想在屏幕上设置单个像素。这听起来很容易,但我的其他条件使它变得困难。我需要快速完成,仅使用CPU,在400x300或更高分辨率(全屏?)下以20fps或更快的速度运行(当然还有其他程序元素运行)。

我已经使用我用Python编写的程序,使用Pygame渲染了一些很酷的图像,但仅使用随机像素填充100x100像素的屏幕就需要50毫秒(那就是我的20fps,其他程序部分会使其减速)。理想情况下,我希望能制作自己的(糟糕的)3D游戏,仅使用CPU,在屏幕上设置像素(也许是体素八叉树之类的图形)。

是否有任何方法(使用任何语言,但最好是Python),我可以创建一个像素值的2D数组(更像是RGB的3D数组)(这被称为位图吗?),并将其转储到显示器上或其他地方?那不是很快吗?如何直接与窗口上的像素进行交互。啊!我真的一点也不懂。我是/不是一个编程新手。给我任何你能想到的东西,我都可以消化它。我只需要一些指引(哈哈)。


1
是的。抽象应该很容易被放弃。我刚刚读了一篇文章,声称DOS在90年代晚期因为你可以用两行C代码写到屏幕上而在游戏中存活下来。使用抽象化可能需要100多行代码。-.- - Matt Joiner
那么,我该如何理解这个抽象概念呢?我应该去尝试制作DOS程序吗?这样在现代计算机上也能运行,对吧? - Void Star
我认为可以明确地说,在现代计算机上,您不需要降级到DOS才能在400x300像素窗口上获得20 fps。 - JJJ
请不要重新添加“set pixel ram quick”标签。 “set”标签是用于数学集合的,而“pixel”,“ram”和“quick”对于分类问题的主题并不有用。请记住,每个标签本身都应该是相关的;它们不是一个句子。 - Wyzard
尽管存在一些缺点,但在Flash中执行应该是最容易的。 - lprsd
显示剩余2条评论
5个回答

4
如果你想自己编写“每个像素”数学计算(而不仅仅是移动圆形和位图),你需要使用C(或C ++)来接近机器速度。
另一方面,如果你想制作完整的游戏,在低级语言(如C)中编写所有内容将不会很有趣。你需要将快速的C代码与一些高级脚本语言结合使用。使用Python,你可以通过numpy连接到C扩展模块,或者将一种语言(如Lua)嵌入到C代码中,或者尝试(可怕的)在C ++中学习高级编码。无论哪种方法,事情都会变得复杂。
如果你只是想尝试快速渲染像素,我建议你只使用C或C++的SDL(这就是pygame内部使用的)。参照这篇教程并玩得开心。
如果你想留在Python的舒适区内,我建议你先尝试制作2D游戏(加载并移动位图),或者尝试cairo(渲染几何图形)。

我很高兴能够帮忙,但是能够如此快速地让所有东西运行成功,这都是你自己的功劳 :-) - maxy
它肯定会对我有用,我只需要弄清楚Python绑定。有趣的是,当我第一次尝试时,我在C中使用了一个char数组来存储我设置像素的数据。我通过在数组中设置特定值来画了一个绿色的圆。我得到了一些奇怪的点阵图案,这些图案不属于我的图像。当我确保在我的数组中设置每个值时,它可以毫无问题地工作。程序是否分配了自由RAM给仍然有剩余垃圾的数组?我是否看到了旧的被丢弃的数据,这些数据还没有被覆盖? - Void Star
如果你真的想将C代码与Python集成,我有一些关于此的示例代码:https://github.com/martinxyz/python/ 可以尝试将其与pygame.surfarray连接起来。但是要提醒你的是,这条路还没有被很好地开发过。 - maxy

3
我能够在 (1920,1080) 的分辨率下,使用 pygame 获得超过 20 帧每秒的速度。
正如 Mallett 指出的那样,您应该使用 pygame.surfarray.blit_array() 函数将像素数据复制到 pygame,并通过调用 pygame.display.flip() 更新屏幕。
>>> import timeit
>>> timeit.timeit('pygame.surfarray.blit_array(screen, pixels);pygame.display.flip()', setup='import pygame;import numpy as np;size=(1920,1080);screen=pygame.display.set_mode(size);pixels=np.random.randint(np.iinfo(np.uint32).max,size=size).astype(np.uint32)', number=20)
0.6346819400787354
>>> timeit.timeit("""
... pygame.surfarray.blit_array(screen, pixels)
... pygame.display.flip()
... """,setup="""
... import pygame
... import numpy as np
... size=(1920,1080)
... screen=pygame.display.set_mode(size)
... pixels=np.random.randint(np.iinfo(np.uint32).max,size=size).astype(np.uint32)
... """, number=20)
0.4848361015319824

哦,太酷了,我一直在使用C语言,因为我让SDL工作起来很痛苦。现在我要尝试一下Python解决方案!谢谢你啊! - Void Star

1

对于 PyGame,您真正想要做的是使用 pygame.surfarray 或 pygame.pixelarray。在您设置数组的值之后,可以一次性将它们全部复制。如果您阅读了有关 surface.set_at(...)(逐个设置像素)的文档,您会发现它不推荐用于除了最小任务外的所有任务。

pygame.surfarray 和 pygame.pixelarray 通常基于 NumPy 或 Numeric(使用 NumPy)。通过 Google 搜索 http://pygame.org/docs/tut/surfarray/SurfarrayIntro.html,您可以获得一些伟大功能的基本概述。


嘿!这也很有帮助!我一直在苦苦挣扎C语言,也许我可以用Python获得所需的性能。Python比C简单多了。不过,我还是要比较一下两者。如果C语言获得更好的性能,我会坚持使用它(至少在我因沮丧而爆炸之前)。 - Void Star
C语言肯定会给你更快的速度。比如说,可以提高一个或两个数量级。这并不是因为Python设计得不好之类的原因;解释型语言由于其架构的特性,必然会更慢。 - geometrian
不是这样的,我的朋友。看一下这个链接:http://morepypy.blogspot.com/2011/08/pypy-is-faster-than-c-again-string.html - user545424
. . . 对应的任务。该链接描述了编译器/解释器的优化。如果libc是与C程序一起编译而不是静态链接,那么编译器将能够像PyPy一样进行优化。<br/>在这种情况下,PyPy能够进行语义上的更改,而不会影响输出,以增加速度,但C编译器则不能。因此,实际上比较的是两个不同的程序。这种比较就像是说短跑运动员总是在比赛中击败汽车,仅仅因为在你的实验中短跑运动员有一个巨大的领先优势。 - geometrian

0

引用:有没有办法(使用任何语言,但最好是Python),我可以创建一个像素值的2D数组(更像是RGB的3D数组)(这被称为位图吗?)在RAM中,并将其转储到显示器或其他地方?

是的,这被称为帧缓冲区。您可以在内存中绘制位图,然后将该内存交换到显示内存中。


我已经完成了所有繁重的数学计算。你肯定会惊讶于我的3D数学模块。我已经掌握了所有的矩阵/Phong着色等等。不幸的是,pygame在像素设置方面太慢了。 - Void Star
抱歉,我不该妄下断言,在答案中已将该文字删除。 - Jason Hernandez
哈哈,没问题。我会对任何向我寻求建议的人说同样的话。我一段时间前将我的整个矩阵数学库移植到了C语言,因为我决定用这种语言来完成所有的图形工作。这是一个很大的痛苦,花费了好几个小时 :/ - Void Star

0

你需要研究一下bitblit,虽然我没有在Python中使用过bit-blit,但在谷歌上搜索它可以得到很有希望的结果。这里有一个相关的讨论来自于图形宝典p.134,他们讨论了类似的问题。


我问的是如何设置像素,而不是bliting。我已经知道如何进行bliting,并且我已经知道与设置像素相比,它非常快。 - Void Star

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接