PyOpenGL-04.曲面细分着色器编程

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

目录

triangle.vs顶点着色文件

 triangle.cs曲面细分控制着色文件

 triangle.es曲面细分求值着色文件

triangle.fs片元着色文件

main.py主文件

 运行结果


曲面细分着色器,就是在一个基础图形的基础上,按照一定规律重复递归细分。这样做有两个好处,1.模型数据加载不用再那么庞大。把细分工作放到渲染阶段。而且这个细分过程是可控。2.由于细分过程是在GPU上完成,所以速度比CPU上细分快得多。

曲面细分过程分为两个过程。1.曲面细分控制着色器(Tessellation Control Shaders)。2.曲面细分求值着色器(Tessellation Evaluation Shaders)。前者负责细分的精细度和规律,后者实现细分过程。

Tessellation Control Shader的核心就是gl_TessLevelOuter和gl_TessLevelInner,前者决定外围的细分等级,后者决定内部的细分等级。其数值代表将该段分为几部分,即如果值为2,那么就是在中间插入1个点分为两段。如下图:

cf86f51f8cd4db7269f75ae19c531c0b.png

下面我在上节渲染三角形基础上,改写一个细分的例子。

triangle.vs顶点着色文件

#version 430
  
layout (location = 0) in vec2 in_Pos;
layout (location = 1) in vec3 in_Color;
   
out vec4 out_Pos;
out vec3 out_Color;
   
void main()
{
     gl_Position = vec4(in_Pos.x, in_Pos.y, 0, 1.0);
     out_Pos = vec4(in_Pos.x, in_Pos.y, 0, 1.0);
     out_Color = in_Color;
}

 triangle.cs曲面细分控制着色文件

#version 450 core
layout (vertices = 3) out;
  
in vec4 out_Pos[];
in vec3 out_Color[];
  
out vec4 tcs_pos[];
out vec3 tcs_color[];
  
void main(){
    //inner
    gl_TessLevelInner[0] = 5;
    // outer
    gl_TessLevelOuter[0] = 5;
    gl_TessLevelOuter[1] = 5;
    gl_TessLevelOuter[2] = 5;
  
    tcs_pos[gl_InvocationID]   = out_Pos[gl_InvocationID];
    tcs_color[gl_InvocationID] = out_Color[gl_InvocationID];
}

 triangle.es曲面细分求值着色文件

#version 450 core
layout(triangles, equal_spacing,ccw) in;
  
vec3 interpolate3D(vec3 v0, vec3 v1, vec3 v2)
{
    return vec3(gl_TessCoord.x) * v0 + vec3(gl_TessCoord.y) * v1 + vec3(gl_TessCoord.z) * v2;
}
  
in vec4 tcs_pos[];
in vec3 tcs_color[];
  
out vec3 out_Color;
  
void main(){
    vec3 iterP = interpolate3D(tcs_pos[0].xyz,tcs_pos[1].xyz,tcs_pos[2].xyz);
    vec3 iterCd = interpolate3D(tcs_color[0],tcs_color[1],tcs_color[2]);
      
    out_Color = iterCd;
    gl_Position = vec4(iterP , 1);
}

triangle.fs片元着色文件

#version 450 core
  
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)  #将着色器对象关联到程序上
      
    return ShaderObj
   
#=======================================
#编译着色器
def Compile_Shader():
    vs_file = get_file("triangle.vs")
      
    cs_file = get_file("triangle.cs")
    es_file = get_file("triangle.es")
      
    fs_file = get_file("triangle.fs")
       
    Shader_Program = glCreateProgram()  #创建空的着色器程序
  
    vs_shader = Create_Shader(Shader_Program , GL_VERTEX_SHADER , vs_file)  
    fs_shader = Create_Shader(Shader_Program , GL_FRAGMENT_SHADER , fs_file)
    cs_shader = Create_Shader(Shader_Program , GL_TESS_CONTROL_SHADER , cs_file)
    es_shader = Create_Shader(Shader_Program , GL_TESS_EVALUATION_SHADER , es_file)
              
    glLinkProgram(Shader_Program)  
    glUseProgram(Shader_Program)
      
    glDeleteShader(vs_shader)
    glDeleteShader(cs_shader)
    glDeleteShader(es_shader)
    glDeleteShader(fs_shader)
  
    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")
          
   
    #创建缓存
    VBO = glGenBuffers(2)
       
    #绑定缓冲区
    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) 
     
       
   
#=======================================
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()
  
    print(glGetString(GL_VERSION))
    print(glGetString(GL_VENDOR))
      
   
    # 窗口事件循环
    while not glfw.window_should_close(window):
       
        glClear(GL_COLOR_BUFFER_BIT)
        glClearColor(0,0,0,1)
          
        glPolygonMode(GL_FRONT_AND_BACK ,GL_LINE );
        glPatchParameteri(GL_PATCH_VERTICES,3);
                  
           
        #绑定顶点缓冲区
        glEnableVertexAttribArray(0)
        glBindBuffer(GL_ARRAY_BUFFER, VBO[0])
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, None)
          
           
        #绑定颜色缓冲区
        glEnableVertexAttribArray(1)
        glBindBuffer(GL_ARRAY_BUFFER, VBO[1])
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, None)
  
          
        #引用Shader
        glUseProgram(Shader_Program)
          
        #绘制镶嵌三角形
        glDrawArrays(GL_PATCHES, 0, 3)
           
        #恢复禁止通道
        glDisableVertexAttribArray(0)
        glDisableVertexAttribArray(1)
   
        # 交换缓冲区,提交渲染内容
        glfw.swap_buffers(window)
   
        # 窗口事件轮询
        glfw.poll_events()
   
    glfw.terminate()

 运行结果

7d0a878d3fe2f9cf4d955cb15dee67fb.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用PyOpenGL的三角形网格绘制技术(triangulated mesh),通过离散化曲面上的点来近似表达该曲面。 具体步骤如下: 1. 定义曲面上的离散点集合,可以使用numpy的meshgrid函数生成一个二维网格点集合。 ```python import numpy as np x = np.linspace(-10, 10, 100) y = np.linspace(-10, 10, 100) X, Y = np.meshgrid(x, y) ``` 2. 计算每个离散点的z值。根据曲面公式计算每个点的z值。 ```python Z = -0.000*X**2 + 2.148*X*Y - 3.279*Y**2 + 0.262*X - 0.023*Y + 617.0 ``` 3. 定义三角形网格索引。使用numpy的reshape和concatenate函数将二维网格点集合转换为一维点集合,并定义三角形网格索引。 ```python indices = np.arange(0, X.size).reshape((X.shape[0]-1, X.shape[1]-1, 2, 3)) indices = np.concatenate((indices[:, :-1, :, :], indices[:, 1:, :, :]), axis=2) indices = np.concatenate((indices[:, :, 0, :], indices[:, :, 1, :]), axis=2) indices = indices.reshape((-1, 3)) ``` 4. 使用OpenGL绘制三角形网格。使用PyOpenGL的glBegin和glEnd函数对每个三角形进行绘制。 ```python from OpenGL.GL import * from OpenGL.GLUT import * def display(): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glBegin(GL_TRIANGLES) for i in range(indices.shape[0]): glVertex3f(X.flatten()[indices[i, 0]], Y.flatten()[indices[i, 0]], Z.flatten()[indices[i, 0]]) glVertex3f(X.flatten()[indices[i, 1]], Y.flatten()[indices[i, 1]], Z.flatten()[indices[i, 1]]) glVertex3f(X.flatten()[indices[i, 2]], Y.flatten()[indices[i, 2]], Z.flatten()[indices[i, 2]]) glEnd() glutSwapBuffers() glutInit() glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH) glutInitWindowSize(800, 800) glutCreateWindow("PyOpenGL Demo") glutDisplayFunc(display) glutMainLoop() ``` 运行代码后,就可以看到绘制出的曲面。可以使用鼠标拖动来旋转视角。 注意,由于这个曲面是开口向下的,因此需要开启深度测试(glEnable(GL_DEPTH_TEST))来正确显示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值