Python之OpenGL笔记(4):使用不同的VAO、VBO和着色器画两个三角形

一、目的

1、创建相同的两个三角形,但对它们的数据使用不同的VAO和VBO:
(类初始化实例时,初始数据生成不同的VAO)
2、创建两个着色器程序,第二个程序使用与第一个不同的片段着色器;
绘制这两个三角形,其中一个输出为绿色,一个输出为红色:
(类初始化实例时,根据side3的正负值,调用不同的片段着色器)

二、程序运行结果

Triangle02.PNG

三、着色器Shaders

  在现代OpenGL中,画图要加入的效果都会使用着色器 Shaders 来实现,Shaders 是进行三维图形学编程的先进方法,从某种意义上来说 Shader 的出现是图形学中的一种”退步”,因为在这之前所有的功能都直接由固定管线提供,而开发人员只需要为其指定参数(如光照属性、旋转角度等),但是由于 Shader 的出现这些功能现在都需要开发者自己通过 Shader 实现。尽管如此,这种可编程性能够提供给开发者更多的灵活性和创造性。
  顶点处理器负责对传入渲染管线的每个顶点执行顶点着色器中的内容,(传入的顶点的数量由绘制函数确定),顶点着色器并不关心所要渲染的基本图元的拓扑结构。此外,你不能在顶点处理器中丢弃任何一个顶点。每个顶点都只被顶点处理器处理一次,在经过矩阵变换之后继续进入接下来的流水线。
  下一个阶段是几何处理器,组成图元所需要的顶点以及其邻接关系都会被提供给着色器。这使得着色器能够考虑除顶点本身之外的其他信息。除此之外,几何处理器也可以将在绘制函数中确定的拓扑关系修改成另外一种拓扑关系。例如你可以通过创建一个顶点列表来生成两个三角形(如一个正方形).除此之外,你也可以在每次调用几何着色器的时候对一个顶点进行多次引用,通过这样的方式我们可以按照我们在几何着色器中选定的拓扑结构来生成多个图元。
  渲染管线中的下一个阶段是裁剪,这是一个单一功能的固定功能单元——它通过我们前面课程中见过的规范化盒子对图元进行裁剪。同时它还通过近裁剪面和远裁剪面对其进行裁剪。同时他也支持用户自定义裁剪面对场景进行裁剪。未被裁剪掉的顶点会变换到屏幕坐标系之下,之后通过光栅化将顶点按照拓扑结构渲染到屏幕上。例如,如果我们要绘制一个三角形那就意味着要找出位于三角形内部的所有点。对于这样每一个点,在光栅化过程中都会调用片元处理器对其进行处理。在片元处理器中我们可以通过对纹理进行取样或者使用其他技术来确定像素的颜色。
  顶点着色器、片元着色器、几何着色器这三个可编程阶段是可选择的,如果我们不向其绑定 Shader 程序就会执行默认的固定管线的函数。

四、顶点着色器(Vertex Shader)

  顶点着色器(Vertex Shader)是几个可编程着色器中的一个。如果我们打算做渲染的话,现代OpenGL需要我们至少设置一个顶点和一个片段着色器。
  我们需要做的第一件事是用着色器语言GLSL(OpenGL Shading Language)编写顶点着色器,然后编译这个着色器,这样我们就可以在程序中使用它了。
  下面是一个非常基础的GLSL顶点着色器的源代码:

#version 330 core
layout (location = 0) in vec3 position;
void main()
{
    gl_Position = vec4(position.x, position.y, position.z, 1.0);
}

  可以看到,GLSL看起来很像C语言。每个着色器都起始于一个版本声明。OpenGL 3.3以及和更高版本中,GLSL版本号和OpenGL的版本是匹配的(比如说GLSL 420版本对应于OpenGL 4.2)。我们同样明确表示我们会使用核心模式。
  下一步,使用in关键字,在顶点着色器中声明所有的输入顶点属性(Input Vertex Attribute)。现在我们只关心位置(Position)数据,所以我们只需要一个顶点属性。GLSL有一个向量数据类型,它包含1到4个float分量,包含的数量可以从它的后缀数字看出来。由于每个顶点都有一个3D坐标,我们就创建一个vec3输入变量position。我们同样也通过layout (location = 0)设定了输入变量的位置值(Location)。

五、片段着色器(Fragment Shader)

  片段着色器(Fragment Shader)是第二个也是最后一个我们打算创建的用于渲染三角形的着色器。片段着色器全是关于计算你的像素最后的颜色输出。
  在计算机图形中颜色被表示为有4个元素的数组:红色、绿色、蓝色和alpha(透明度)分量,通常缩写为RGBA。当在OpenGL或GLSL中定义一个颜色的时候,我们把颜色每个分量的强度设置在0.0到1.0之间。比如说我们设置红为1.0f,绿为1.0f,我们会得到两个颜色的混合色,即黄色。这三种颜色分量的不同调配可以生成超过1600万种不同的颜色!

#version 330 core
out vec4 color;
void main()
{
    color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}

  片段着色器只需要一个输出变量,这个变量是一个4分量向量,它表示的是最终的输出颜色,我们应该自己将其计算出来。我们可以用out关键字声明输出变量,这里我们命名为color。下面,我们将一个alpha值为1.0(1.0代表完全不透明)的橘黄色的vec4赋值给颜色输出。

六、着色器程序

  着色器程序对象(Shader Program Object)是多个着色器合并之后并最终链接完成的版本。如果要使用刚才编译的着色器我们必须把它们链接为一个着色器程序对象,然后在渲染对象的时候激活这个着色器程序。已激活着色器程序的着色器将在我们发送渲染调用的时候被使用。

七、源代码

"""
glfw_Triangle02.py
Author: dalong10
Description: Draw a Triagle, learning OPENGL 
"""
import glutils    #Common OpenGL utilities,see glutils.py
import sys, random, math
import OpenGL
from OpenGL.GL import *
from OpenGL.GL.shaders import *
import numpy 
import numpy as np
import glfw

strVS = """
#version 330 core
layout(location = 0) in vec3 position;
void main(){
    gl_Position = vec4(position.x, position.y, position.z, 1.0);
    }
"""

strFS1 = """
#version 330 core
out vec4 color;
void main(){
    color = vec4(1.0, 0.0, 0.0, 1.0);
    }
"""

strFS2 = """
#version 330 core
out vec4 color;
void main(){
    color = vec4(0.0, 1.0, 0.0, 1.0);
    }
"""

class FirstTriangle:
    def __init__(self, side1, side2, side3):
        self.side1 = side1
        self.side2 = side2
        self.side3 = side3

        # load shaders
        if side3>0:
            strFS=strFS1
        else:
            strFS=strFS2    
        self.program = glutils.loadShaders(strVS, strFS)
        glUseProgram(self.program)
        
        s1 = side1/1.0
        s2 = side2/1.0
        s3 = side3/1.0
        vertices = [
             s1, -0.5, 0, 
             s2, -0.5, 0,
             s3, 0.5, 0
             ]             
        # set up vertex array object (VAO)
        self.vao = glGenVertexArrays(1)
        glBindVertexArray(self.vao)
        # set up VBOs
        vertexData = numpy.array(vertices, numpy.float32)
        self.vertexBuffer = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer)
        glBufferData(GL_ARRAY_BUFFER, 4*len(vertexData), vertexData, 
                     GL_STATIC_DRAW)
        #enable arrays
        self.vertIndex = 0
        glEnableVertexAttribArray(self.vertIndex)
        # set buffers 
        glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer)
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None)
        # unbind VAO
        glBindVertexArray(0)

    def render(self):
        # use shader
        glUseProgram(self.program)
        # bind VAO
        glBindVertexArray(self.vao)
        # draw
        glDrawArrays(GL_TRIANGLES, 0, 3)
        # unbind VAO
        glBindVertexArray(0)

if __name__ == '__main__':
    import sys
    import glfw
    import OpenGL.GL as gl
    def on_key(window, key, scancode, action, mods):
        if key == glfw.KEY_ESCAPE and action == glfw.PRESS:
            glfw.set_window_should_close(window,1)

    # Initialize the library
    if not glfw.init():
        sys.exit()

    # Create a windowed mode window and its OpenGL context
    window = glfw.create_window(640, 480, "glfw_Triangle02", None, None)
    if not window:
        glfw.terminate()
        sys.exit()

    # Make the window's context current
    glfw.make_context_current(window)
    # Install a key handler
    glfw.set_key_callback(window, on_key)

    # Loop until the user closes the window
    while not glfw.window_should_close(window):
        # Render here
        width, height = glfw.get_framebuffer_size(window)
        ratio = width / float(height)
        gl.glViewport(0, 0, width, height)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT)

        gl.glClearColor(0.0,0.0,4.0,0.0)
        firstTriangle0 = FirstTriangle(-0.9,-0.0,-0.45)
        firstTriangle1 = FirstTriangle(0,0.9,0.45)
        # render
        firstTriangle0.render()
        firstTriangle1.render()

        # Swap front and back buffers
        glfw.swap_buffers(window)

        # Poll for and process events
        glfw.poll_events()

    glfw.terminate()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345