使用GLSL进行纹理处理(在PyOpenGL和Pygame中)

时间:2012-03-02 23:04:34

标签: python opengl glsl pygame pyopengl

在对Python中的固定功能管道感到沮丧之后,我开始研究着色器来绘制我的游戏的视差背景。但是,我找不到任何简单的方法来纹理绘制哪些顶点。

我目前有一个带有顶点数组的PyOpenGL顶点缓冲区对象,每个顶点都是这样的:[x,y,z,texX,texY,texID]

我使用getAttribLocation / glEnableVertexAttribArray将这些传递给着色器。我不确定它是否有效,因为着色器当前没有编译,但在我添加可能很糟糕的纹理代码之前,事情已经正常用彩色顶点。

我想要的是使用着色器绘制带有多个纹理的纹理模型,但模型是平坦的背景。它是一个大的(1600x800左右)图像,分为256x256纹理和四边形多边形。 (旁边的问题:拥有更多的小多边形是否更好,因此多边形的多边形在屏幕外或大多边形,以便减少纹理绑定?)

因为它是多个相关的纹理,我想在着色器中完成所有操作,而不必为CPU上的每个块绑定纹理,所以我认为发送带有顶点数据的纹理数据会是最好的,但我不能让它发挥作用。

有人可以给我一个简单的例子,说明顶点和片段着色器是否相互作用,以制作具有不同纹理的多个多边形?

编辑:着色器,vbo和这里的东西:http://pastebin.com/3LaYiyvh着色器现在编译,但三角形是不可见的。

EDITEDIT:到了!不确定最终破解了什么,但这是程序:http://pastebin.com/k87sfiEf 我认为它就像是,只要你在开始时绑定所有纹理,着色器就可以在它们之间进行交换。但我不确定。 另外值得注意的是,由于在绘制时交换纹理,将大背景分割成较小的块是一个坏主意。浪费空间的大纹理很好,地图集更好!

3 个答案:

答案 0 :(得分:2)

  

在对Python中的固定功能管道感到沮丧之后,我开始研究着色器来绘制我的游戏的视差背景。

如果固定功能对你来说很慢,使用着色器不会让它更快。

可能你只是做了一些根本错误的事情,比如使用立即模式,或者根本没有硬件加速(由于缺少正确安装的驱动程序或类似的东西)。

答案 1 :(得分:2)

  

有人可以给我一个简单的例子,说明顶点和片段着色器是否相互作用,以制作具有不同纹理的多个多边形?

Google for GLSL教程。之前写的是例子,没有理由再为你编写它们。或者下载NVidia OpenGL SDK并进行检查。 OpenGL.org也推荐书籍。 “橙皮书”涵盖了着色器。

  

分为256x256

传统上建议采取相反的做法 - 尽可能采用所有纹理并将它们组合成单个“图谱”纹理,最好是像16384x16384一样 - 以最小化状态切换。

  

我想要的是使用着色器绘制带有多个纹理的纹理模型,但模型是平坦的背景。这是一个很大的(1600x800左右)图像

自从Riva TNT 2 pro以来,1600x800将完全适合任何硬件上的纹理。如果你关心“浪费”纹理内存,那么很多卡都支持非2次幂纹理。然而,非2次幂纹理通常具有局限性,并且使用这种纹理的某些硬件(某些ati卡+驱动程序)将导致fps掉头。即从200..400到40,这是不值得的。在具有甚至256MB VRam的硬件上,未使用的40%纹理是微优化。然后再次,您可以使用纹理图集,并使用有用的东西填充“浪费”空间,如果您对vram使用感到吝啬。另外,请记住,您永远不知道驱动程序使用视频内存的效率如何。

  

我想在着色器中完成所有操作,而不必为CPU上的每个块绑定纹理,

你做不到。着色器不会绑定纹理。他们使用已绑定的纹理。

  

我不确定它是否有效,因为着色器当前没有编译,

好吧,让他们编译并再次询问。如果没有看到着色器或错误消息,则无法帮助您。你知道着色器编译器produces error messages,对吧?

  

对Python中的固定功能管道感到沮丧

考虑切换到C或C ++等编译语言。使用C / C ++应用程序(“dungeon crawler”)中的原始固定功能opengl,而不使用缓冲区或显示列表,您可以轻松获得每秒200..400帧 - IF 您使用正确的算法进行隐藏曲面删除(并禁用vsync) AND 您的纹理是mip映射的。众所周知的“固定功能”应用程序包括Quake 1..3,Half-Life 1,Cube和其他许多非常快速的游戏。这意味着 - 如果它很慢,那就是你的错。

与C / C ++不同,Python具有更大的函数调用开销 - 执行字节码,从列表/元组中提取未知类型的值(可以通过设计包含“任何东西”)然后将其作为浮点数转储到类似glVertex3f的内容中,同时最终转发它对本机API调用将比没有中间步骤的类似C / C ++调用慢。您可以通过使用显示列表或缓冲区对象来抵消它,但对我来说它是不值得的。但是,对特定任务使用特定语言是个人偏好的问题。

- 编辑 -

  

但是,如果着色器无法绑定纹理,多纹理如何工作?

有N个纹理阶段(至少2-se glGet / GL_MAX_TEXTURE_COORDS / GL_MAX_TEXTURE_UNITS),您可以一次设置多个纹理。见glActiveTexture。没有着色器(固定功能),您可以使用glTexEnv为每个阶段指定颜色操作。使用着色器,您可以设置多个纹理,使用glUniform1i/glUniform1v指定哪个采样器使用哪个纹理阶段,然后使用Sampler2D和类似函数从着色器中读取数据。着色器无法切换​​纹理。它可以使用已由程序设置的纹理。 Shader不了解着色器之外的任何纹理。从技术上讲,着色器甚至不知道“纹理”它有“采样器”用于读取数据。

  

纹理采样?着色器必须能够在选择/更改纹理方面做一些工作......

Shader根本不会切换或选择纹理。这部分由您的程序完成。有关更多信息,请阅读您的opengl / glsl版本的OpenGL规范和GLSL规范。两者都可以从opengl.org网站“文档”菜单下载。

正如我已经说过的,此时你需要GLSL教程或书籍。两者都很容易找到。得到任何一个并继续阅读它,直到你“得到它”。目前它看起来不像你做了你的功课,并尝试使用书籍或教程制作一个简单的着色器。如果你找不到一本书,那么NVidia OpenGL SDK有很多例子(在C / C ++中,但转换它们并不难)。

答案 2 :(得分:1)

也许你可以在Minecraft mapping blog posts找到有用的东西。所有示例都使用Python,Pygame和PyOpenGL。他们在片段着色器中做了很多东西。它们只使用琐碎的几何形状:只有一个四边形。

根据你的描述,听起来你使用一个大纹理而不是多个小纹理要好得多。但是,在某些情况下,拥有大量小纹理并在着色器中在它们之间进行选择确实很有意义。 Array textures 在这种情况下可能很有用,因为它们在使用纹理图集时不会遇到过滤和夹紧的问题。 (实际上,我的博客中的示例使用了纹理图集,并且在缩小到远处时遇到了mip-mapping的一些问题。我最近一直在使用数组纹理来解决这个问题。)