1. 概述

本文基于Python语言,描述OpenGL的着色器

前置知识可参考:

笔者这里不过多描述每个名词、函数和细节,更详细的文档可以参考:

2. 纹理使用流程

参考:纹理 - LearnOpenGL CN (learnopengl-cn.github.io)

OpenGL中纹理使用流程大致如下:

  • 加载图片数据
  • 创建纹理对象
  • 绑定纹理对象
  • 使用图片数据生成纹理
  • 设置纹理坐标
  • 在顶点着色器中传递纹理
  • 在片段着色器中采用纹理
  • (绘制时)激活纹理并绑定纹理

3. 具体流程

3.1 加载图片数据

使用PIL(Pillow )实现图片数据的读取

参考官方说明:Image Module - Pillow (PIL Fork) 9.2.0 documentation

使用以下方式导入:

from PIL.Image import open

加载图片数据:

image = open('./textures/container.jpg')

3.2 创建纹理对象

纹理对象也是使用ID进行引用:

texture = glGenTextures(1)

3.3 绑定纹理对象

绑定纹理对象,进行之后的纹理配置:

glBindTexture(GL_TEXTURE_2D, texture)

进行纹理配置:

// 为当前绑定的纹理对象设置环绕、过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

3.4 使用图片数据生成纹理

通过glTexImage2D()生成纹理:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.size[0], image.size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, image.tobytes())
glGenerateMipmap(GL_TEXTURE_2D)

3.5 设置纹理坐标

纹理坐标:

vertices = np.array([
# ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -
0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, # 右上
0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, # 右下
-0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, # 左下
-0.5, 0.5, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0 # 左上
])

现在内存中的坐标格式:

指定纹理坐标属性:

glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, int(8 * 8), ctypes.c_void_p(8 * 6));
glEnableVertexAttribArray(2);

3.6 在顶点着色器中传递纹理坐标

在顶点着色器中编写GLSL实现数据传递:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord; out vec3 ourColor;
out vec2 TexCoord; void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}

3.7 在片段着色器中采用纹理

在片段着色器中接收纹理坐标与纹理:

#version 330 core
out vec4 FragColor; in vec3 ourColor;
in vec2 TexCoord; uniform sampler2D ourTexture; void main()
{
FragColor = texture(ourTexture, TexCoord);
}

使用GLSL内置的texture函数来采样纹理的颜色

3.8 激活纹理并绑定纹理(绘制时)

激活纹理单元并绑定纹理数据:

glActiveTexture(GL_TEXTURE0)  # 在绑定纹理之前先激活纹理单元
glBindTexture(GL_TEXTURE_2D, texture);

4. 代码总结

一个简单的纹理绘制流程完整代码如下:

import glfw as glfw
from OpenGL.GL import *
import numpy as np
from PIL.Image import open import shader as shader glfw.init()
window = glfw.create_window(800, 600, "texture", None, None)
glfw.make_context_current(window) VAO = glGenVertexArrays(1)
glBindVertexArray(VAO) vertices = np.array([
# ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -
0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, # 右上
0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, # 右下
-0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, # 左下
-0.5, 0.5, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, # 左上
])
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, 8 * vertices.size, vertices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_DOUBLE, GL_FALSE, int(8 * 8), None)
glEnableVertexArrayAttrib(VAO, 0)
glVertexAttribPointer(1, 3, GL_DOUBLE, GL_FALSE, int(8 * 8), ctypes.c_void_p(8 * 3))
glEnableVertexArrayAttrib(VAO, 1)
glVertexAttribPointer(2, 2, GL_DOUBLE, GL_FALSE, int(8 * 8), ctypes.c_void_p(8 * 6));
glEnableVertexAttribArray(2); indices = np.array([
0, 1, 3, # first triangle
1, 2, 3 # second triangle
])
EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 8 * indices.size, indices, GL_STATIC_DRAW) image = open('./textures/container.jpg')
# print(image.tobytes())
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
# 为当前绑定的纹理对象设置环绕、过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.size[0], image.size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, image.tobytes())
glGenerateMipmap(GL_TEXTURE_2D) shaderProgram = shader.Shader("./glsl/test.vs.glsl", "./glsl/test.fs.glsl") while not glfw.window_should_close(window):
glClearColor(0.2, 0.3, 0.3, 1.0)
glClear(GL_COLOR_BUFFER_BIT) shaderProgram.use()
glBindVertexArray(VAO)
glActiveTexture(GL_TEXTURE0) # 在绑定纹理之前先激活纹理单元
glBindTexture(GL_TEXTURE_2D, texture) glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None) glfw.swap_buffers(window)
glfw.poll_events() shaderProgram.delete()

顶点着色器test.vs.glsl:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord; out vec3 ourColor;
out vec2 TexCoord; void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}

片段着色器test.fs.glsl:

#version 330 core
out vec4 FragColor; in vec3 ourColor;
in vec2 TexCoord; uniform sampler2D texture1; void main()
{
FragColor = texture(texture1, TexCoord);
}

编译代码并运行:

5. 参考资料

[1]纹理 - LearnOpenGL CN (learnopengl-cn.github.io)

[2]nothings/stb: stb single-file public domain libraries for C/C++ (github.com)

[3]OpenGL学习笔记(五)纹理 - 知乎 (zhihu.com)

[4]PyOpenGL 3.1.0 Function Reference (sourceforge.net)

[5]~mcfletch/openglcontext/trunk : contents of tests/dek_texturesurf.py at revision 699 (launchpad.net)

[6]Image Module - Pillow (PIL Fork) 9.2.0 documentation

基于Python的OpenGL 03 之纹理的更多相关文章

  1. 基于Cocos2d-x学习OpenGL ES 2.0之多纹理

    没想到原文出了那么多错别字,实在对不起观众了.介绍opengl es 2.0的不多.相信介绍基于Cocos2d-x学习OpenGL ES 2.0之多纹理的,我是独此一家吧.~~ 子龙山人出了一个系列: ...

  2. 基于Cocos2d-x学习OpenGL ES 2.0系列——纹理贴图(6)

    在上一篇文章中,我们介绍了如何绘制一个立方体,里面涉及的知识点有VBO(Vertex Buffer Object).IBO(Index Buffer Object)和MVP(Modile-View-P ...

  3. Python网络编程03 /缓存区、基于TCP的socket循环通信、执行远程命令、socketserver通信

    Python网络编程03 /缓存区.基于TCP的socket循环通信.执行远程命令.socketserver通信 目录 Python网络编程03 /缓存区.基于TCP的socket循环通信.执行远程命 ...

  4. 基于python的opcode优化和模块按需加载机制研究(学习与个人思路)(原创)

    基于python的opcode优化和模块按需加载机制研究(学习与思考) 姓名:XXX 学校信息:XXX 主用编程语言:python3.5 个人技术博客:http://www.cnblogs.com/M ...

  5. 基于Python的机器学习实战:KNN

    1.KNN原理: 存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系.输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应 ...

  6. 基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0

    基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0 目录 1. 开发环境2. 主要功能逻辑介绍3. 框架功能简介 4. 数据库的创建 5. 框架模块详细介绍6. Tes ...

  7. 基于Cocos2d-x学习OpenGL ES 2.0系列——使用VBO索引(4)

    在上一篇文章中,我们介绍了uniform和模型-视图-投影变换,相信大家对于OpenGL ES 2.0应该有一点感觉了.在这篇文章中,我们不再画三角形了,改为画四边形.下篇教程,我们就可以画立方体了, ...

  8. 基于Python操作redis介绍

    (注:本文部分内容摘自互联网,由于作者水平有限,不足之处,还望留言指正.) 毕业前的最后一个学期(2016.03),龙哥结婚了.可是总有些人喜欢嘲笑别人,调侃我.当时我就理直气壮的告诉他们,等龙哥孩子 ...

  9. 看我如何基于Python&Facepp打造智能监控系统

    由于种种原因,最近想亲自做一个基于python&facepp打造的智能监控系统. 0×00:萌芽 1:暑假在家很无聊 想出去玩,找不到人.玩个lol(已卸载),老是坑人.实在是无聊至极,不过, ...

  10. 从零学习基于Python的RobotFramework自动化

    从零学习基于Python的RobotFramework自动化 一.        Python基础 1)      版本差异 版本 编码 语法 其他 2.X ASCII try: raise Type ...

随机推荐

  1. 【消息队列面试】11-14:kafka高可靠、高吞吐量、消息丢失、消费模式

    十一.kafka消息高可靠的解决方案 1.高可靠=避免消息丢失 解决消息丢失的问题 2.如何解决 (1)保证消息发送是可靠的(发成功了/落到partition) a.ack参数 发送端,采用ack机制 ...

  2. SQL注入漏洞原理与利用

    SQL注入漏洞原理与利用 SQL注入漏洞流程 判断注入类型 判断字段个数 查询回显位 查询数据库名 查询表.字段名 查询内容 判断注入类型 1.数字型注入点判断 当要输入的参数x为数字型时,后端脚本中 ...

  3. [数学建模]层次分析法AHP

    评价类问题. 问题: ① 评价的目标? ② 可选的方案? ③ 评价的指标? 分层 目标层.准则层.方案层 层次分析法可分为四个步骤建立: 第一步:标度确定和构造判断矩阵: 第二步:特征向量,特征根计算 ...

  4. elasticsearch倒排索引(全面了解)

    SimpleAI推荐语: 前年转过这篇文章,最近在看检索相关论文,发现又有点忘记倒排索引(inverted index)的具体内容,遂翻出来再看看,不得不说,这个漫画画的太好了,娓娓道来,一看就懂,再 ...

  5. Qt网络编程-从0到多线程编程

    网络编程开发 1.简介 两个协议,一个是TCP协议,一个是UDP协议 先说TCP: TCP的话,服务器端需要端口监听,直到有客户端进行连接发送过来请求数据,然后客户端根据请求数据进行应答,之后就算tc ...

  6. 自研ORM框架 实现类似EF Core Include 拆分查询 支持自定义条件、排序、选择

    Baozi, I'm Mr.Zhong I like to brush TikTok, I know that anchors like to call it that, haha!Recently, ...

  7. plsql developer切换用户

    方法1: 1.双击plsql developer桌面软件图标启动软件 2.在连接窗口中填写连接信息,连接数据库 3.在新建窗口下拉选项中,选择命令窗口功能 4.在工作区内会出现当前用户连接数据库的窗口 ...

  8. STL list容器API

    list容器:链表容器,不支持随机遍历.不能用通用的sort算法(要有随机访问迭代器),容器自己有排序算法 #define _CRT_SECURE_NO_WARNINGS #include<io ...

  9. 可视化—AntV G6 高亮相邻节点的两种方式

    目录 内置的高亮节点 自定义高亮 自定义高亮时保持原始颜色 总结 案例完整代码 通过官方文档,可知高亮相邻节点分为两种方法,文档描述并不是很清楚,对刚接触这个库的小白并不是很友好,慢慢总结慢慢来吧 内 ...

  10. Vue中实现自定义excel下载

    目录 第一种:后端生成excel 第二种:前端合成excel 总结 参考资料 最近在工作中遇到一个需求,就是需要在前端实现一个错误模板Excel的下载功能. 实现下载有两种方式,一种是后端生成一个ex ...