• (Python OpenGL)【3】着色器 PyOpenGL


    (Python OpenGL)现在开始我们使用着色器来进行渲染。着色器是目前做3D图形最流行的方式。

    OpenGL的渲染管线流程:

    数据传输到OpenGL—>顶点处理器—>细分着色—>几何处理器—>图元装配—>裁剪器—>光栅器(片段处理器)

    详细信息可以参考《OpenGL编程指南》 原书第8版  王锐译   中的P8 -P10

    一些Shader的注意:

    Shader着色器的使用跟C/C++程序的创建过程类似。

    1、写一个shader着色器文本并使其在你的程序中有效可用

    2、Shader着色器文本全为字符串类型          例如     S = “ coding部分” 代码部分为字符串

    3、将字符串编译为Shader对象

    4、使用GLSL编译器(编译器的语法见《OpenGL编程指南》 原书第8版  王锐译)

    对于每一个着色器程序需要进行下面的步骤设置:

    对于着色器对象:

    1、创建Shader对象

    2、编译

    3、验证编译成功?

    然后将上述的着色器对象链接为一个着色器程序:

    1、创建程序

    2、将Shader对象关联到着色器程序

    3、链接程序

    4、判断链接是否成功

    5、使用着色器处理数据

     Shader程序:

     1 __author__ = "WSX"
     2 
     3 import numpy as np
     4 from OpenGL.GLUT import *
     5 from OpenGL.GL import *
     6 import ctypes
     7 #顶点着色器部分
     8 VERTEX_SHADER = """   
     9 #version 330
    10 
    11 layout (location = 0) in vec3 Position;
    12 
    13 void main()
    14 {
    15     gl_Position = vec4(0.5 * Position.x, 0.5 * Position.y, Position.z, 1.0);
    16     }
    17 """
    18 #片段着色器部分,字符串类型
    19 FRAGMENT_SHADER = """ 
    20 #version 330
    21 out vec4 FragColor;
    22 void main()
    23 {
    24     FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    25     }
    26 """
    27 def Create_Shader( ShaderProgram, Shader_Type , Source):  #创建并且添加着色器(相当于AddShader)Shader_Type为类型
    28     ShaderObj = glCreateShader( Shader_Type )  #创建Shader对象
    29     glShaderSource(ShaderObj , Source)
    30     glCompileShader(ShaderObj)  #进行编译
    31     glAttachShader(ShaderProgram, ShaderObj)  #将着色器对象关联到程序上
    32 
    33 
    34 def Compile_Shader():  #编译着色器
    35     Shader_Program = glCreateProgram()  #创建空的着色器程序
    36     Create_Shader(Shader_Program , GL_VERTEX_SHADER , VERTEX_SHADER)
    37     Create_Shader(Shader_Program , GL_FRAGMENT_SHADER , FRAGMENT_SHADER)
    38     glLinkProgram(Shader_Program)
    39     glUseProgram(Shader_Program)
    40 
    41 def Draw():
    42     glClear(GL_COLOR_BUFFER_BIT)
    43     glEnableVertexAttribArray(0)
    44     glBindBuffer(GL_ARRAY_BUFFER, VBO)
    45     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) #这里的None不能写为0
    46     glDrawArrays(GL_TRIANGLES, 0, 3)
    47     glDisableVertexAttribArray(0)  #解析数据 例如一个矩阵里含有 位置 、颜色、多种信息
    48     glutSwapBuffers()
    49 
    50 
    51 def CreateBuffer():  #创建顶点缓存器
    52     global VBO   #设置为全局变量
    53     vertex = np.array([[-1.0,-1.0,0.0],
    54                        [1.0,-1.0,0.0],
    55                        [0.0,1.0,0.0]],dtype="float32")   #创建顶点数组
    56     VBO = glGenBuffers(1)  #创建缓存
    57     glBindBuffer(GL_ARRAY_BUFFER , VBO)   #绑定
    58     glBufferData(GL_ARRAY_BUFFER , vertex.nbytes , vertex , GL_STATIC_DRAW)   #输入数据
    59 
    60 
    61 def main():
    62     glutInit([])
    63     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA)  # 显示模式 双缓存
    64     glutInitWindowPosition(100, 100)  # 窗口位置
    65     glutInitWindowSize(500, 500)  # 窗口大小
    66     glutCreateWindow("sanjiao")  # 创建窗口
    67     glutInitContextVersion(4,3)   #为了兼容
    68     glutInitContextProfile(GLUT_CORE_PROFILE)   #为了兼容
    69     glutDisplayFunc(Draw)  # 回调函数
    70     glClearColor(0.0, 0.0, 0.0, 0.0)
    71     CreateBuffer()
    72     Compile_Shader()
    73     glutMainLoop()
    74 
    75 main()

    结果:

    关于着色器代码部分(字符串)的解释:

    #version 330

    这告诉编译器我们的目标是3.3版的GLSL。如果编译器不支持它,它会发出错误。

    layout (location = 0) in vec3 Position;

    该语句出现在顶点着色器中。它声明了一个顶点特定属性,它是3个浮点数的向量,在着色器中将被称为'位置'。“特定于顶点”表示对于GPU中每个对着色器的调用,将提供缓冲区中新顶点的值。

     layout (location = 0)创建缓冲区中属性名称和属性之间的绑定。

    您可以通过将多个着色器对象链接在一起来创建着色器。但是,每个着色器阶段(VS,GS,FS)只能有一个主要函数,用作着色器的入口点。例如,您可以创建一个具有多个函数的光照库,并将其与着色器链接,前提是这些函数中没有任何一个函数名为“main”。

    gl_Position = vec4(0.5 * Position.x, 0.5 * Position.y, Position.z, 1.0);

    这里我们对输入的顶点位置进行硬编码转换。我们将X和Y值减半,并保持Z不变。'gl_Position'是一个特殊的内置变量,它应该包含齐次(包含X,Y,Z和W分量)顶点位置。光栅化器将查找该变量并将其用作屏幕空间中的位置(在进行了几次转换之后)。将X和Y值减半意味着我们将看到一个三角形,它是前一教程中三角形大小的四分之一。请注意,我们将W设置为1.0。这对于正确显示三角形非常重要。从3D到2D的投影实际上分两个阶段完成。首先,您需要将所有顶点乘以投影矩阵(我们将在一些教程中开发),然后GPU在位置属性到达光栅化器之前自动执行所谓的“透视分割”。这意味着它将W组件的所有组件分割成W组件。在本教程中,我们尚未在顶点着色器中进行任何投影,但透视分割阶段是我们无法禁用的。无论我们从顶点着色器输出的gl_Position值是用HW分量还是HW分量。我们需要记住,否则我们不会得到我们期望的结果。为了规避视角分割的影响,我们将W设置为1.0。由1除。

    如果一切工作正常,则具有值(-0.5,-0.5),(0.5,-0.5)和(0.0,0.5)的三个顶点到达光栅器。裁剪器不需要做任何事情,因为所有的顶点都在标准化的框内。这些值被映射到屏幕空间坐标,并且光栅化器开始运行三角形内的所有点。对于每个点,执行片段着色器。以下着色器代码是从片段着色器中获取的。

    out vec4 FragColor;

    通常片段着色器的工作是确定片段(像素)的颜色。此外,片段着色器可以完全丢弃像素或更改其Z值(这会影响后续Z测试的结果)。通过声明上述变量来输出颜色。四个分量表示R,G,B和A(对于alpha)。您设置到该变量中的值将由光栅化器接收并写入帧缓冲区。

    FragColor = vec4(1.0, 0.0, 0.0, 1.0);

    在之前的几个教程中,没有片段着色器,因此所有内容都以白色的默认颜色绘制。在这里,我们将FragColor设置为红色。

    更多关于着色器部分的解释:http://ogldev.atspace.co.uk/www/tutorial04/tutorial04.html

  • 相关阅读:
    jquery实现页面的搜索功能
    url中的查询字符串的参数解析
    5.14日学习内容1:jquery表单相关知识
    5.12日北京“咖啡陪你”咖啡吧学习笔记
    layui基础上的tree菜单动态渲染;
    H5area的热区锚点随着图片的尺寸而变化
    Python3基础 raise 产生RuntimeError 异常
    Python3基础 raise + 指定类型异常+异常的解释 产生特定类型异常
    Python3基础 判断变量大于一个数并且小于另外一个数
    Python3基础 内嵌函数 简单示例
  • 原文地址:https://www.cnblogs.com/WSX1994/p/9096385.html
Copyright © 2020-2023  润新知