【译】【PyOpenGL教程-介绍着色器】 varying变量(颜色)

原文地址:http://pyopengl.sourceforge.net/context/tutorials/shader_2.html

varying变量(颜色)

【译】【PyOpenGL教程-介绍着色器】 varying变量(颜色)
本教程基于以往的教程之上新增了:
- 使用varying变量在顶点着色器和片段着色器之间进行通信
- 捕捉着色器中的编译错误
- 将顶点和颜色值打包到一个VBO中
- 启用带有跨步值的顶点数组
- 启用颜色数组(传统方法)
我们为本教程import的内容和上一篇教程几乎相同,因此我们可以忽略它们。如果您不认识某些东西,请返回上一教程的介绍。

from OpenGLContext import testingcontext
BaseContext = testingcontext.getInteractive()
from OpenGL.GL import *
from OpenGL.arrays import vbo
from OpenGLContext.arrays import *
from OpenGL.GL import shaders
class TestContext(BaseContext):
    """This shader just passes gl_Color from an input array to
    the fragment shader , which interpolates the values across the
    face(via a"varying" data type"""
    def OnInit(self):
        """Initialize the context once we have a valid OpenGL environ"""

除此之外:编译错误

随着我们获得越来越复杂的着色器,您将不可避免地遇到着色器出现编译错误并需要调试的情况。当着色器编译失败时,着色器的PyOpenGL便利包会引发RuntimeError实例。RuntimeError的第二个参数是发生在故障时正在编译的源代码。通常,这个错误的Python追溯足以帮助你追踪问题(当然有适当的参考)

try:
    shaders.compileShader("""void main(){""",GL_VERTEX_SHADER)
except(GLError, RuntimeError) as err:
    print("Example of shader compile error", err)
else:
    raise RuntimeError("""Didn't catch compilation error!""")

Varying变量

在我们之前的教程中,我们将每个片元的颜色值算为常量颜色(绿色)。现在我们将为每个顶点赋予不同的颜色值,并让GL对这些颜色之间进行插值。

我们将为顶点使用传统的OpenGL颜色,也就是通常提供给传统(固定功能)管线的颜色。该值显示为内置的vec4 “gl_Color”。在顶点着色器中,顶点着色器每次调用都将分配gl_Color。

为了将每个顶点的颜色传递给片段着色器,我们需要定义一个”varying”变量。对每个片元在三角形内插变化变量,对构成三角形的每个角的顶点采用视角正确的混合值。因此,如果我们将一个顶点定义为黑色,而另一个顶点定义为白色,那么为它们之间的区域生成的碎片将会从黑色变成白色(通过灰色)

你会注意到我们在主函数的外部定义了变化的值,可以粗略地将变化的值视为“全局”,以便可以在两个着色器之间看到它。但是,变化的值正在通过中间的插值处理。

        vertex = shaders.compileShader(
            """
            varying vec4 vertex_color;
            void main(){
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
                vertex_color = gl_Color;
            }""", GL_VERTEX_SHADER)

我们的片段着色器再次声明了vertex_color变化值。由于我们希望最终的片段着色器是顶点之间的插值颜色,我们可以简单地将vertex_color分配给gl_FragColor.

        fragment = shaders.compileShader(
            """
            varying vec4 vertex_color;
            void main(){
                gl_FragColor = vertex_color;
            }""", GL_FRAGMENT_SHADER)

现在我们的几何体对于每个顶点都有两个分量,第一个是顶点位置,它与我们前面的教程中看到的是相同的一组值。每个顶点(行)中的前三个浮点就是位置,后三个值表示每个顶点的颜色。因此三角形(前三个顶点),将从红色到黄色混合为青色。

正如前面教程中所指出的那样,这种“打包”格式在现代硬件上往往比为每种类型的数据提供单独的数据阵列效率更高。

        self.vbo = vbo.VBO(
            array([
                    [ 0, 1, 0, 0,1,0 ],
                    [ -1,-1, 0, 1,1,0 ], 
                    [ 1,-1, 0, 0,1,1 ], 
                    [ 2,-1, 0, 1,0,0], 
                    [ 4,-1, 0, 0,1,0 ], 
                    [ 4, 1, 0, 0,0,1 ], 
                    [ 2,-1, 0, 1,0,0 ], 
                    [ 4, 1, 0, 0,0,1 ],
                    [ 2, 1, 0, 0,1,1 ],
                ],'f')
            )
    def Render(self, mode):
        """Render the geometry for the scene"""
        BaseContext.Render(self, mode)

与前面一样,我们需要启用我们编译的着色器,并使VBO处于活动状态,以便数组规范例程将使用VBO作为我们几何数据的源。

        glUseProgram(self.shader)
        try:
            self.vbo.bind()
            try:

既然我们想为着色器提供位置和颜色数组,我们需要启用两个不同的数组。这两个内置数组映射到我们在顶点着色器中使用的内置gl_Vertex和gl_Color“属性”变量。

这些“启用”告诉OpenGL,对于我们渲染的两个顶点,我们希望从启用的阵列中读取一条记录。如果我们要在不指定数组的情况下执行此操作,则OpenGL可能会在尝试访问NULL内存位置时对车观念许进行分段错误。

                glEnableClientState(GL_VERTEX_ARRAY)
                glEnableClientState(GL_COLOR_ARRAY)

我们在这里使用数组定义调用的“完整”形式,因为我们希望能够在数据数组中“指定”跨度。指针定义调用的参数是:
- 大小:每条记录中值的数量
- 类型:常量定义记录中每个项目的值的类型
- 跨度:每个连续记录开始之间的字节数,在我们的例子中,每条纪律有6个32位浮点值,记录之间共有4*6 = 24个字 节。
- 指针:指向我们希望用于此数组的数据
顶点指针被传递给我们的VBO的引用,它告诉OpenGL从当前绑定的VBO中读取数据。实质上,VBO包装只是将一个空指针传递给GL。

                glVertexPointer(3, GL_FLOAT, 24, self.vbo)
                glColorPointer(3, GL_FLOAT, 24, self.vbo+12)

我们现在以我们之前学过的方式来调用渲染和清理的方法

                glDrawArrays(GL_TRIANGLES, 0, 9)
            finally:
                self.vbo.unbind()
                glDisableClientState(GL_VERTEX_ARRAY)
                glDisableClientState(GL_COLOR_ARRAY)
        finally:
            glUseProgram(0)
if __name__ == "__main__":
    TestContext.ContextMainLoop()

术语:
- 插值:
通过混合其他值来创建一个新值

附完整代码:

from OpenGLContext import testingcontext
BaseContext = testingcontext.getInteractive()
from OpenGL.GL import *
from OpenGL.arrays import vbo
from OpenGLContext.arrays import *
from OpenGL.GL import shaders

class TestContext(BaseContext):
    """This shader just passes gl_Color from an input array to
    the fragment shader , which interpolates the values across the
    face(via a"varying" data type"""
    def OnInit(self):
        """Initialize the context once we have a valid OpenGL environ"""
        # try:
        #   shaders.compileShader("""void main(){""",GL_VERTEX_SHADER)
        # except(GLError, RuntimeError) as err:
        #   print("Example of shader compile error", err)
        # else:
            # raise RuntimeError("""Didn't catch compilation error!""")

        vertex = shaders.compileShader(
            """
            varying vec4 vertex_color;
            void main(){
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
                vertex_color = gl_Color;
            }""", GL_VERTEX_SHADER)
        fragment = shaders.compileShader(
            """
            varying vec4 vertex_color;
            void main(){
                gl_FragColor = vertex_color;
            }""", GL_FRAGMENT_SHADER)
        self.shader = shaders.compileProgram(vertex, fragment)

        self.vbo = vbo.VBO(
            array([
                    [ 0, 1, 0, 0,1,0 ],
                    [ -1,-1, 0, 1,1,0 ], 
                    [ 1,-1, 0, 0,1,1 ], 
                    [ 2,-1, 0, 1,0,0], 
                    [ 4,-1, 0, 0,1,0 ], 
                    [ 4, 1, 0, 0,0,1 ], 
                    [ 2,-1, 0, 1,0,0 ], 
                    [ 4, 1, 0, 0,0,1 ],
                    [ 2, 1, 0, 0,1,1 ],
                ],'f')
            )

    def Render(self, mode):
        """Render the geometry for the scene"""
        BaseContext.Render(self, mode)
        glUseProgram(self.shader)
        try:
            self.vbo.bind()
            try:
                glEnableClientState(GL_VERTEX_ARRAY)
                glEnableClientState(GL_COLOR_ARRAY)

                glVertexPointer(3, GL_FLOAT, 24, self.vbo)
                glColorPointer(3, GL_FLOAT, 24, self.vbo+12)

                glDrawArrays(GL_TRIANGLES, 0, 9)
            finally:
                self.vbo.unbind()
                glDisableClientState(GL_VERTEX_ARRAY)
                glDisableClientState(GL_COLOR_ARRAY)
        finally:
            glUseProgram(0)
if __name__ == "__main__":
    TestContext.ContextMainLoop()

这里写图片描述

下面是一个使用 PyOpenGL 创建着色器并绘制不同颜色点的示例代码: ```python import glfw from OpenGL.GL import * from OpenGL.GL.shaders import compileProgram, compileShader import numpy as np # 顶点着色器代码 vertex_shader = """ #version 330 in vec3 position; void main() { gl_Position = vec4(position, 1.0); } """ # 片段着色器代码 fragment_shader = """ #version 330 out vec4 color; void main() { color = vec4(1.0, 0.0, 0.0, 1.0); } """ # 初始化glfw if not glfw.init(): raise Exception("glfw初始化失败") # 创建窗口 window = glfw.create_window(640, 480, "PyOpenGL示例", None, None) if not window: glfw.terminate() raise Exception("创建窗口失败") # 设置当前窗口为OpenGL上下文 glfw.make_context_current(window) # 编着色器 shader = compileProgram(compileShader(vertex_shader, GL_VERTEX_SHADER), compileShader(fragment_shader, GL_FRAGMENT_SHADER)) # 设置着色器 glUseProgram(shader) # 顶点数据 vertices = np.array([ 0.0, 0.5, 0.0, # 顶点1坐标 -0.5, -0.5, 0.0, # 顶点2坐标 0.5, -0.5, 0.0, # 顶点3坐标 ], dtype=np.float32) # 创建缓冲区对象 vbo = glGenBuffers(1) # 绑定缓冲区对象 glBindBuffer(GL_ARRAY_BUFFER, vbo) # 设置数据 glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW) # 获取位置属性的位置 position = glGetAttribLocation(shader, "position") # 开启位置属性 glEnableVertexAttribArray(position) # 设置位置属性数据 glVertexAttribPointer(position, 3, GL_FLOAT, False, 0, None) # 渲染循环 while not glfw.window_should_close(window): # 清空颜色缓冲区 glClear(GL_COLOR_BUFFER_BIT) # 绘制三角形 glDrawArrays(GL_TRIANGLES, 0, 3) # 交换缓冲区 glfw.swap_buffers(window) # 处理事件 glfw.poll_events() # 删除着色器程序 glDeleteProgram(shader) # 终止glfw glfw.terminate() ``` 在上面的示例代码中,我们使用了 PyOpenGL 库创建了一个窗口,并编了一个顶点着色器和一个片段着色器。在顶点着色器中,我们只是简单地将顶点的位置设置为输出位置。在片段着色器中,我们将颜色设置为红色。 然后,我们定义了一个包含三个顶点的三角形,并将它们存储在一个 NumPy 数组中。我们创建了一个缓冲区对象,并将顶点数据存储到该缓冲区中。然后,我们启用位置属性,并将顶点数据绑定到该属性上。 最后,我们进入渲染循环,在其中使用 glDrawArrays 函数绘制三角形。注意,在每个渲染循环中,我们都要清空颜色缓冲区,并交换缓冲区。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值