PyOpenGL-05.几何着色器编程

该教程介绍了如何利用Python、OpenGL以及glfw库开发三维图形程序,特别是通过glDrawArraysInstanced实现批量绘制多个相同物体,提高渲染效率。教程适合对几何和编程有一定基础的初三以上学生学习。
摘要由CSDN通过智能技术生成

本系列教程主要讲解利用Python和OpenGL开发三维图形程序。这里主要用到的工具库是glfw开源图形库。本系列内容较难。要求学生对几何和编程有一定的了解。建议初三以上同学学习。

目录

triangle.vs顶点着色文件

 triangle.fs文件

main.py主文件

运行结果


当我们在一个场景中绘制多个相同物体时。比如绘制多棵树、草。大家想到的肯定是用一个for语句来重复绘制命令来实现。这种方法效率是非常低的。小场景还好,在大场景采用这种方法效率会非常低下。

效率低下原因是,for语句是在cpu下执行的。我要绘制100棵树,CPU就要提交100次数据给GPU,效率可想而知。那我们一次把100棵树提交给GPU可行吗?可以是可以,但是你的数据模型就会相当复杂,且庞大。

在OpenGL里提供了两个命令来解决此类,批量绘制相同物体的命令:glDrawArraysInstanced和glDrawElementsInstanced,它们分别对应glDrawArrays或glDrawElements函数。

下面例子是这样的,我要在屏幕绘制5个三角形,每个三角形的坐标都不一样。大家看下程序。

triangle.vs顶点着色文件

#version 330
  
layout (location = 0) in vec2 in_Pos;
layout (location = 1) in vec3 in_Color;
layout (location = 2) in vec2 in_offset;
    
out vec3 out_Color;
    
void main()
{
     gl_Position = vec4(in_Pos.x*0.1+in_offset.x, in_Pos.y*0.1+in_offset.y, 0, 1.0);
        
     out_Color = in_Color;
}

 triangle.fs文件

#version 330
   
out vec4 FragColor;
in vec3  out_Color;
    
void main()
{
    FragColor = vec4(out_Color,1);
}

main.py主文件

import glfw
import numpy as np
from OpenGL.GLUT import *
from OpenGL.GL import *
    
#获取文件内容
def get_file(fname):
    tmp = open(fname,"r")
    ret = tmp.read()
    tmp.close()
    return ret
        
#=======================================
#创建着色器
def Create_Shader( ShaderProgram, Shader_Type , Source):
    #创建并且添加着色器
    ShaderObj = glCreateShader( Shader_Type )  #创建Shader对象
    glShaderSource(ShaderObj , Source)
    glCompileShader(ShaderObj)  #进行编译
    glAttachShader(ShaderProgram, ShaderObj)  #将着色器对象关联到程序上
    
#=======================================
#编译着色器
def Compile_Shader():
    vs_file = get_file("triangle.vs")
    fs_file = get_file("triangle.fs")
        
    Shader_Program = glCreateProgram()  #创建空的着色器程序
    Create_Shader(Shader_Program , GL_VERTEX_SHADER , vs_file)
    Create_Shader(Shader_Program , GL_FRAGMENT_SHADER , fs_file)
       
    glLinkProgram(Shader_Program)
    glUseProgram(Shader_Program)
   
    return Shader_Program
    
#=======================================
def CreateBuffer():  #创建顶点缓存器
    
    global VBO   #设置为全局变量
        
    #创建顶点数组
    vertex = np.array([[-1.0,-1.0],
                       [1.0,-1.0],
                       [0.0,1.0],],dtype="float32")
    #创建顶点颜色                
    color = np.array([[1,0,0],
                      [0,1,0],
                      [0,0,1],],dtype="float32")
           
    #创建偏移数组
    offsets = np.array([[-0.5,0.25],
                        [-0.25,-0.25],
                        [0,0],
                        [0.25,-0.25],
                        [0.5,0.25]],dtype="float32")
      
      
    #创建缓存
    VBO = glGenBuffers(3)
        
    #绑定缓冲区
    glBindBuffer(GL_ARRAY_BUFFER , VBO[0])
    #输入数据
    glBufferData(GL_ARRAY_BUFFER , vertex.nbytes , vertex , GL_STATIC_DRAW)
        
    #绑定缓冲区
    glBindBuffer(GL_ARRAY_BUFFER , VBO[1])
    #输入数据
    glBufferData(GL_ARRAY_BUFFER , color.nbytes , color , GL_STATIC_DRAW)
      
    #绑定缓冲区
    glBindBuffer(GL_ARRAY_BUFFER , VBO[2])
    #输入数据
    glBufferData(GL_ARRAY_BUFFER , offsets.nbytes , offsets , GL_STATIC_DRAW)
    print(offsets.nbytes)
        
    
#=======================================
if __name__ == '__main__':
    
    # 初始化GLFW
    glfw.init()     
            
    # 创建窗口
    window = glfw.create_window(640, 480, "实例化绘制", None, None)
        
    if not window:
        glfw.terminate()
            
    
    #生成窗口上下文设备
    glfw.make_context_current(window)
        
    CreateBuffer()
    Shader_Program = Compile_Shader()
        
    
    # 窗口事件循环
    while not glfw.window_should_close(window):
        
        glClear(GL_COLOR_BUFFER_BIT)
        glClearColor(0,0,0,1)
            
        #绑定顶点缓冲区
        glBindBuffer(GL_ARRAY_BUFFER, VBO[0])     
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, None) #这里的None不能写为0
        glEnableVertexAttribArray(0)
            
        #绑定颜色缓冲区
        glBindBuffer(GL_ARRAY_BUFFER, VBO[1])
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, None) #这里的None不能写为0
        glEnableVertexAttribArray(1)
          
        #绑定偏移缓冲区
        glBindBuffer(GL_ARRAY_BUFFER, VBO[2])
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, None) #这里的None不能写为0
        glEnableVertexAttribArray(2)
        glVertexAttribDivisor(2, 1);
          
        #glVertexAttribDivisor第二个参数含义:
        #0:默认情况下是0,告诉OpenGL我们需要在顶点着色器的每次迭代时更新顶点属性。
        #将它设置为1时,我们告诉OpenGL我们希望在渲染一个新实例的时候更新顶点属性。
        #设置为2时,我们希望每2个实例更新一次属性,以此类推。
          
   
        glLineWidth(10);
        glUseProgram(Shader_Program)
        #绘制三角形      
        glDrawArraysInstanced(GL_TRIANGLES,0,3,5)
        #恢复禁止通道
        glDisableVertexAttribArray(0)
        glDisableVertexAttribArray(1)
    
        # 交换缓冲区,提交渲染内容
        glfw.swap_buffers(window)
    
        # 窗口事件轮询
        glfw.poll_events()
    
    glfw.terminate()

运行结果

f6ab24820f329cc70024f5aef112d8cb.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值