Irrlicht GLES 分析。
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
... // 上传图片等操作
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
// Bind Textures using texture units
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(Program, "ourTexture"), 0);
纹理与 sampler2D 变量的关联是通过索引来关联的。 状态机,A 关联 B,B 关联 C,从而实现了 A 关联 C。开始不理解为什么设计成这样,慢慢的居然感受到了一种暴力美学。 这边绑定状态机,那边绑定 Shader,中间再关联一下,这样任何一边都可以自由修改和接入。
从本地内存向 GPU 的传输(UNPACK),包括各种 glTexImage、glDrawPixel; 从 GPU 到本地内存的传输(PACK),包括 glGetTexImage、glReadPixel 等。 也正因如此,PBO 也有 PACK 和 UNPACK 模式的区别。
// 我们可以给 sampler2D 变量赋 int 值。
GLuint tex_loc = glGetUniformLocation(program, "tex");
// GL_TEXTURE1 又与值为 1 的 sampler2D 变量关联
glUniform1i(tex_loc, 1); // 这个 1 其实代表 GL_TEXTURE1
glActiveTexture(GL_TEXTURE1); // 将纹理与 GL_TEXTURE1 关联起来。
glBindTexture(GL_TEXTURE_2D, tex_id); // tex_id 与 GL_TEXTUR1 关联
平时使用单张纹理怎么不需要 glActiveTexture?
sampler2D 默认值为 0,纹理也默认与 GL_TEXTURE0 关联。
GLuint GetDebugTextureId() {
static GLuint texture = 0;
if (texture != 0) {
return texture;
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
if (true) {
GLubyte data[] = {
255, 0, 0, 155,
0, 255, 0, 155,
0, 0, 255, 155,
255, 255, 255, 155 };
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLsizei width = 2;
GLsizei height = 2;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
glBindTexture(GL_TEXTURE_2D, 0);
return texture;
}
GLint SetProgramUniformTexture(GLuint program, const GLchar* name, GLuint texture) {
glActiveTexture(GL_TEXTURE0);
// texture 和 GL_TEXTURE0 绑定
glBindTexture(GL_TEXTURE_2D, texture);
int location = glGetUniformLocation(program, name);
// Shader 和 GL_TEXTURE0 绑定。
glUniform1i(location, 0);
}
OpenGL 的 GLSL 中声明的 Uniform 变量用于应用程序向 GLSL 程序传递参数。 glGetActiveUniform 函数通过索引号取得 GLSL 中声明的 Uniform 变量的名称、类型、是否是数组等信息, 而 glGetUniformLocation 函数则是通过变量名称取得 Location 值,Location 可以视为 GLSL 程序编译后,各个 Uniform 变量在 GPU 内存中的布局的顺序号。
Uniform 变量可以使用单个变量、数组、结构体变量、结构体数组等。令人比较疑惑的是数组元素和结构体成员与 Location 值的关系,因此我通过实验,得出结果如下:
// 这是 GLSL 的,没有什么实际功能,只是把声明的变量用上,防止编译优化时被忽略掉。
uniform sampler2D qt_Texture0; // 这个采样器没在代码中使用,编译后就不存在了。
varying vec4 qt_TexCoord0;
uniform int _intVar;
uniform int _intArr[5];
uniform float _floatVar;
uniform float _floatArr[6];
uniform vec2 _vec2ver;
uniform vec2 _vec2Arr[7];
uniform ivec2 _ivec2ver;
uniform ivec2 _ivec2Arr[8];
uniform vec3 _vec3Arr[1];
struct StrUct
{
float fa;
float fArr[3];
int ia;
int iArr[4];
vec2 va;
vec2 vArr[5];
mat4 mArr[6];
};
uniform StrUct _sVar;
uniform StrUct _sArr[6];
void main(void)
{
float a = float(_intVar) + float(_intArr[0]) + float(_intArr[1]) + float(_intArr[2]);
float b = _floatVar + _floatArr[0] + _floatArr[1] + _floatArr[2] + _vec3Arr[0].x;
a += _vec2ver.x;
b += _vec2Arr[6].y;
int c = _ivec2ver.r + _ivec2Arr[5].r + _ivec2Arr[6].r + _ivec2Arr[7].r;
float d = float(c) * a * b;
float e = _sVar.fa + _sVar.fArr[1];
float f = float(_sVar.ia + _sVar.iArr[1]) * _sArr[1].va.x + _sArr[0].vArr[3].g;
gl_FragColor.x = float(c);
gl_FragColor.y = d;
gl_FragColor.z = e;
gl_FragColor.a = f;
}
// 这是一段取得 Uniform 变量数量和最大名称字符串长度之后,枚举每个变量信息的 C++ 代码。
GLintcount = 0;
GLintbufSize = 0;
GLintlength = 0;
std::stringname;
glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &count);
glGetProgramiv(programId, GL_ACTIVE_UNIFORM_MAX_LENGTH, &bufSize);
if (count && bufSize)
{
for (int32_t i = 0; i < count; ++i)
{
GLenum symbolicConstant;
name.resize(static_cast<size_t>(bufSize));
glGetActiveUniform(programId, i, bufSize, &length, &elementCount, &symbolicConstant, &name.front());
name.resize(static_cast<size_t>(length));
location = glGetUniformLocation(programId, name.c_str());
if (location < 0) continue;
fprintf(stderr, "%d, Location:%d\tsize:%d, type:%04X\tname:%s\n", i, location, elementCount, symbolicConstant, name.c_str());
}
}
代码输出的内容:
0, Location:0 size:1, type:8B5C name:qt_ModelViewProjectionMatrix
1, Location:1 size:1, type:1404 name:_intVar
2, Location:2 size:3, type:1404 name:_intArr[0]
3, Location:5 size:1, type:1406 name:_floatVar
4, Location:6 size:3, type:1406 name:_floatArr[0]
5, Location:9 size:1, type:8B50 name:_vec2ver
6, Location:10 size:7, type:8B50 name:_vec2Arr[0]
7, Location:17 size:1, type:8B53 name:_ivec2ver
8, Location:18 size:8, type:8B53 name:_ivec2Arr[0]
9, Location:26 size:1, type:8B51 name:_vec3Arr[0]
10, Location:27 size:1, type:1406 name:_sVar.fa
11, Location:28 size:3, type:1406 name:_sVar.fArr[0]
12, Location:31 size:1, type:1404 name:_sVar.ia
13, Location:32 size:4, type:1404 name:_sVar.iArr[0]
14, Location:36 size:1, type:8B50 name:_sVar.va
15, Location:37 size:5, type:8B50 name:_sVar.vArr[0]
16, Location:42 size:6, type:8B5C name:_sVar.mArr[0]
17, Location:48 size:1, type:1406 name:_sArr[0].fa
18, Location:49 size:3, type:1406 name:_sArr[0].fArr[0]
19, Location:52 size:1, type:1404 name:_sArr[0].ia
20, Location:53 size:4, type:1404 name:_sArr[0].iArr[0]
21, Location:57 size:1, type:8B50 name:_sArr[0].va
22, Location:58 size:5, type:8B50 name:_sArr[0].vArr[0]
23, Location:63 size:6, type:8B5C name:_sArr[0].mArr[0]
24, Location:69 size:1, type:1406 name:_sArr[1].fa
25, Location:70 size:3, type:1406 name:_sArr[1].fArr[0]
26, Location:73 size:1, type:1404 name:_sArr[1].ia
27, Location:74 size:4, type:1404 name:_sArr[1].iArr[0]
28, Location:78 size:1, type:8B50 name:_sArr[1].va
29, Location:79 size:5, type:8B50 name:_sArr[1].vArr[0]
30, Location:84 size:6, type:8B5C name:_sArr[1].mArr[0]
OpenGL 状态机 和 面向过程的 C 语言接口,令人眼花缭乱。几处早莺争暖树,谁家新燕啄春泥。 为了实现一个功能,需要一组 API 配合食用。整理了一些入门级常用的,加强理解。
#include <GLFW/glfw3.h>
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
while (!glfwWindowShouldClose(window))
glfwPollEvents();
glfwSwapBuffers(window);
glfwTerminate();
// key_callback
glfwSetWindowShouldClose(window, GL_TRUE);
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
geometry = glCreateShader(GL_GEOMETRY_SHADER);
glShaderSource(geometry, 1, &gShaderCode, NULL);
glCompileShader(geometry);
Program = glCreateProgram();
glAttachShader(Program, vertex);
glAttachShader(Program, fragment);
glAttachShader(Program, geometry);
glLinkProgram(Program);
// 连接完成,就可以删除了。
glDeleteShader(vertex);
glDeleteShader(fragment);
glDeleteShader(geometry);
glGenTextures(1, &texture);
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);
int width, height;
unsigned char* image = SOIL_load_image("..\\resources\\textures\\container.jpg", &width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture when done, so we won't accidentily mess up our texture.
// Set up vertex data (and buffer(s)) and attribute pointers
GLfloat vertices[] = {
// Positions // Texture Coords
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // Top Right
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // Bottom Right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // Bottom Left
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // Top Left
};
GLuint indices[] = { // Note that we start from 0!
0, 1, 3, // First Triangle
1, 2, 3 // Second Triangle
};
// 这玩意是针对 VBO 的。
void glVertexAttribPointer(
GLuint index, // 指定要修改的顶点属性的索引值
GLint size, // 指定每个顶点属性的组件数量。
GLenum type, // 指定数组中每个组件的数据类型。
GLboolean normalized, // 指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)
// 或者直接转换为固定点值(GL_FALSE)。
GLsizei stride, // 指定连续顶点属性之间的偏移量。
const GLvoid* pointer // 指定第一个组件在数组的第一个顶点属性中的偏移量。
);
GLuint VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO); // array buffer
glGenBuffers(1, &EBO); // element array buffer
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Position attribute
// layout (location = 0) in vec3 position;
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// TexCoord attribute
// layout (location = 2) in vec2 texCoord;
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
glBindVertexArray(0); // Unbind VAO
// 绘制 Draw container
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
// 释放
// Properly de-allocate all resources once they've outlived their purpose
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
// Define the viewport dimensions
glViewport(0, 0, WIDTH, HEIGHT);
// Render
// Clear the color buffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Bind Textures using texture units
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(Program, "ourTexture"), 0);
// Activate shader
glUseProgram(Program);
// Get their uniform location
GLint modelLoc = glGetUniformLocation(Program, "model");
GLint viewLoc = glGetUniformLocation(Program, "view");
GLint projLoc = glGetUniformLocation(Program, "projection");
// Pass them to the shaders
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
// 绘制 !! glDrawElements
// framebuffer configuration
// -------------------------
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// create a color attachment texture
unsigned int textureColorbuffer;
glGenTextures(1, &textureColorbuffer);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
/* 创建 */
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
/* 参数 */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/* 挂载 */
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
// create a renderbuffer object for depth and stencil attachment (we won't be sampling these)
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
// use a single renderbuffer object for both a depth AND stencil buffer.
/* 创建 */
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT);
// now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now
/* 挂载 */
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
/* 检查 */
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)
// 绘制各种东东 -- 绘制到缓冲里面了
glBindVertexArray(cubeVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cubeTexture);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// 再次绘制
glBindVertexArray(planeVAO);
glBindTexture(GL_TEXTURE_2D, floorTexture);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
glBindVertexArray(quadVAO);
// use the color attachment texture as the texture of the quad plane
glBindTexture(GL_TEXTURE_2D, textureColorbuffer); // 前面创建的纹理缓冲附件
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
// 纹理送入
uniform sampler2D screenTexture;
// 最终颜色生成
out vec4 FragColor;
// 纹理取值
FragColor = texture(screenTexture, TexCoords);
// 顶点着色器传参到片段着色器
out vec2 TexCoords;
in vec2 TexCoords;
// CPU 到 GPU 参数传递
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoords;
// 顶点着色器输出
gl_Position = vec4(aPos, 1.0);