OpengGL教程(六)---坐标的变换和坐标系的变换
本章参考官方教程:坐标系统
本系列历史文
OpengGL教程(一)—OpenGL环境的配置(GLFW3,GLAD)
OpengGL教程(二)—渲染一个简单的窗体
OpengGL教程(三)—使用VAO和VBO方式绘制三角形
OpengGL教程(四)—使用EBO方式绘制矩形
OpengGL教程(五)—纹理的应用
经历前五章的学习我们最终实现了下述效果
本章节主要讲述了,坐标的变换和坐标系的变换问题,涉及到一些线性代数知识,这部分知识本章不做重点。笔者也是初学OpenGL,其中的一些数学相关的空间变化问题是需要自己独立思考才能理解的,希望读者可以根据文章中的“需求 -> 实现”的代码实现,去掌握其中的数学知识。
注意 : 笔者也是边学边记录,也会存在理解有误的地方,下文若有错误欢迎大家指正。谢谢!
坐标的变换
坐标的变化是比较简单的,通过对顶点坐标的变化从而实现不同的显示效果。此部分主要实现一张图片围绕Z轴旋转。
片元着色器的代码不需要修改和第五章的相同。
VertexShader.glsl
#version 330 core
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec2 aTexture;
uniform mat4 projection;
uniform mat4 trans;
out vec2 ourTexture;
void main()
{
vec4 ndcPos = projection * vec4(aPosition,1.0f);
gl_Position = trans * ndcPos;
ourTexture = aTexture;
}
main.cpp
#include <iostream>
#include <string>
#include "glew.h"
#include "glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "log.h"
#include "GlslDealConfig.h"
// 顶点数据
GLfloat vertices_1[] = {
0.0f, 600.0f, 0.0f,
0.0f, 0.0f, 0.0f,
600.0f, 0.0f, 0.0f,
600.0f, 600.0f, 0.0f
};
GLfloat vertices_2[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
GLint indices[] = {
0, 1, 2,
0, 2, 3
};
// 主函数
int main() {
GlslDealConfig glslConfig;
// 初始化 GLFW
if (!glfwInit()) {
LOGE("Failed to initialize GLFW");
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 创建窗口
GLFWwindow* window = glfwCreateWindow(600, 600, "Texture", nullptr, nullptr);
if (!window) {
LOGE("Failed to create GLFW window");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// 初始化 GLEW
GLenum err = glewInit();
if (err != GLEW_OK) {
LOGE("Failed to initialize GLEW: %s", reinterpret_cast<const char*>(glewGetErrorString(err)));
return -1;
}
glfwSwapInterval(1);
// 加载着色器
std::string vertexShaderCode = glslConfig.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/Trans/VertexShader.glsl");
std::string fragmentShaderCode = glslConfig.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/Trans/FragmentShader.glsl");
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
const GLchar* vShaderSource = vertexShaderCode.c_str();
const GLchar* fShaderSource = fragmentShaderCode.c_str();
glShaderSource(vertexShader, 1, &vShaderSource, nullptr);
glShaderSource(fragmentShader, 1, &fShaderSource, nullptr);
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
glslConfig.CheckShaderCompileV(vertexShader);
glslConfig.CheckShaderCompileF(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glslConfig.CheckProgmaLinkStatus(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 配置 VAO, VBO, EBO
GLuint VAO, VBO[2], EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(2, VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_1), vertices_1, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_2), vertices_2, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 加载纹理
GLuint texture[2];
texture[0] = glslConfig.loadTexture("/home/ryan/zxp/Rendering/demo/resource/brickwall.jpg", GL_RGB);
texture[1] = glslConfig.loadTexture("/home/ryan/zxp/Rendering/demo/resource/awesomeface.png", GL_RGBA);
// 设置投影矩阵
glm::mat4 projection = glm::ortho(0.0f, 600.0f, 0.0f, 600.0f, -1.0f, 1.0f);
glUseProgram(shaderProgram);
GLuint projLoc = glGetUniformLocation(shaderProgram, "projection");
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
// 激活纹理单元
glActiveTexture(GL_TEXTURE3);
GLuint textureLocation = glGetUniformLocation(shaderProgram, "textureClass");
glUniform1i(textureLocation, 3);
glActiveTexture(GL_TEXTURE6);
GLuint textureLocation2 = glGetUniformLocation(shaderProgram, "textureClass2");
glUniform1i(textureLocation2, 6);
// 渲染循环
while (!glfwWindowShouldClose(window)) {
glViewport(0, 0, 600, 600);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glActiveTexture(GL_TEXTURE6);
glBindTexture(GL_TEXTURE_2D, texture[1]);
glm::mat4 transform = glm::mat4(1.0f);
transform = glm::rotate(transform, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
// transform = glm::translate(transform, glm::vec3(0.1f, -0.1f, 0.0f)); // switched the order
GLuint Trans = glGetUniformLocation(shaderProgram, "trans");
glUniformMatrix4fv(Trans, 1, GL_FALSE, glm::value_ptr(transform));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
// 清理资源
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(2, VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram);
glfwTerminate();
return 0;
}
相对于第五章的代码主要是在while循环中增加了下列代码
glm::mat4 transform = glm::mat4(1.0f);
//构建绕Z轴旋转矩阵
transform = glm::rotate(transform, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
//平移矩阵
// transform = glm::translate(transform, glm::vec3(0.1f, -0.1f, 0.0f)); // switched the order
GLuint Trans = glGetUniformLocation(shaderProgram, "trans");
glUniformMatrix4fv(Trans, 1, GL_FALSE, glm::value_ptr(transform));
运行效果
(实际效果就是逆时针旋转,动画上传太麻烦…)
坐标系的变换
为了将坐标从一个坐标系变换到另一个坐标系,我们需要用到几个变换矩阵,最重要的几个分别是模型(Model)、观察(View)、投影(Projection)三个矩阵。我们的顶点坐标起始于局部空间(Local Space),在这里它称为局部坐标(Local Coordinate),它在之后会变为世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)的形式结束。下面的这张图展示了整个流程以及各个变换过程做了什么:
1、局部坐标是对象相对于局部原点的坐标,也是物体起始的坐标。
2、下一步是将局部坐标变换为世界空间坐标,世界空间坐标是处于一个更大的空间范围的。这些坐标相对于世界的全局原点,它们会和其它物体一起相对于世界的原点进行摆放。
3、接下来我们将世界坐标变换为观察空间坐标,使得每个坐标都是从摄像机或者说观察者的角度进行观察的。
4、坐标到达观察空间之后,我们需要将其投影到裁剪坐标。裁剪坐标会被处理至-1.0到1.0的范围内,并判断哪些顶点将会出现在屏幕上。
5、最后,我们将裁剪坐标变换为屏幕坐标,我们将使用一个叫做视口变换(Viewport Transform)的过程。视口变换将位于-1.0到1.0范围的坐标变换到由glViewport函数所定义的坐标范围内。最后变换出来的坐标将会送到光栅器,将其转化为片段。
简单来说主要就是:局部空间->世界空间( M )->观察空间( V )->裁剪空间( P )的变换。
具体含义请详细阅读:坐标系统
在“坐标的变换”中我们实现了一个图片的Z轴旋转,下面根据上述MVP的讲解,我们实现一个图片绕X轴旋转的动画。
VertexShader.glsl
#version 330 core
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec2 aTexture;
uniform mat4 projection;
uniform mat4 Mtrans;
uniform mat4 Vtrans;
uniform mat4 Ptrans;
out vec2 ourTexture;
void main()
{
vec4 ndcPos = projection * vec4(aPosition,1.0f);
gl_Position = Ptrans * Vtrans * Mtrans * ndcPos;
ourTexture = aTexture;
}
main.cpp
#include <iostream>
#include <string>
#include "glew.h"
#include "glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "log.h"
#include "GlslDealConfig.h"
// 顶点数据
GLfloat vertices_1[] = {
0.0f, 1000.0f, 0.0f,
0.0f, 0.0f, 0.0f,
1000.0f, 0.0f, 0.0f,
1000.0f, 1000.0f, 0.0f
};
GLfloat vertices_2[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
GLint indices[] = {
0, 1, 2,
0, 2, 3
};
// 主函数
int main() {
GlslDealConfig glslConfig;
// 初始化 GLFW
if (!glfwInit()) {
LOGE("Failed to initialize GLFW");
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 创建窗口
GLFWwindow* window = glfwCreateWindow(1000, 1000, "Texture", nullptr, nullptr);
if (!window) {
LOGE("Failed to create GLFW window");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// 初始化 GLEW
GLenum err = glewInit();
if (err != GLEW_OK) {
LOGE("Failed to initialize GLEW: %s", reinterpret_cast<const char*>(glewGetErrorString(err)));
return -1;
}
glfwSwapInterval(1);
// 加载着色器
std::string vertexShaderCode = glslConfig.ReadGlslFile("/home/ryan/Rendering/demo/glsl/Trans/VertexShader.glsl");
std::string fragmentShaderCode = glslConfig.ReadGlslFile("/home/ryan/Rendering/demo/glsl/Trans/FragmentShader.glsl");
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
const GLchar* vShaderSource = vertexShaderCode.c_str();
const GLchar* fShaderSource = fragmentShaderCode.c_str();
glShaderSource(vertexShader, 1, &vShaderSource, nullptr);
glShaderSource(fragmentShader, 1, &fShaderSource, nullptr);
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
glslConfig.CheckShaderCompileV(vertexShader);
glslConfig.CheckShaderCompileF(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glslConfig.CheckProgmaLinkStatus(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 配置 VAO, VBO, EBO
GLuint VAO, VBO[2], EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(2, VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_1), vertices_1, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_2), vertices_2, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 加载纹理
GLuint texture[2];
texture[0] = glslConfig.loadTexture("/home/ryan/Rendering/demo/resource/brickwall.jpg", GL_RGB);
texture[1] = glslConfig.loadTexture("/home/ryan/Rendering/demo/resource/awesomeface.png", GL_RGBA);
// 设置投影矩阵
glm::mat4 projection = glm::mat4(1.0f);
projection = glm::ortho(0.0f, 1000.0f, 0.0f, 1000.0f, -1.0f, 1.0f);
glUseProgram(shaderProgram);
GLuint projLoc = glGetUniformLocation(shaderProgram, "projection");
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
// 激活纹理单元
glActiveTexture(GL_TEXTURE3);
GLuint textureLocation = glGetUniformLocation(shaderProgram, "textureClass");
glUniform1i(textureLocation, 3);
glActiveTexture(GL_TEXTURE6);
GLuint textureLocation2 = glGetUniformLocation(shaderProgram, "textureClass2");
glUniform1i(textureLocation2, 6);
// 渲染循环
while (!glfwWindowShouldClose(window)) {
glViewport(0, 0, 1000, 1000);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glActiveTexture(GL_TEXTURE6);
glBindTexture(GL_TEXTURE_2D, texture[1]);
//此例子视点只在Z轴移动
glm::mat4 Mmatrix = glm::mat4(1.0f);
glm::mat4 Vmatrix = glm::mat4(1.0f);
glm::mat4 Pmatrix = glm::mat4(1.0f);
Mmatrix = glm::rotate(Mmatrix,(float)glfwGetTime(), glm::vec3(1.0f, 0.0f, 0.0f));
Vmatrix = glm::translate(Vmatrix, glm::vec3(0.0f, 0.0f, -3.0f));
Pmatrix = glm::perspective(glm::radians(90.0f), 1000.0f/1000.0f, 0.1f, 100.0f);
GLuint TransM = glGetUniformLocation(shaderProgram, "Mtrans");
GLuint TransV = glGetUniformLocation(shaderProgram, "Vtrans");
GLuint TransP = glGetUniformLocation(shaderProgram, "Ptrans");
glUniformMatrix4fv(TransM, 1, GL_FALSE, glm::value_ptr(Mmatrix));
glUniformMatrix4fv(TransV, 1, GL_FALSE, glm::value_ptr(Vmatrix));
glUniformMatrix4fv(TransP, 1, GL_FALSE, glm::value_ptr(Pmatrix));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
// 清理资源
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(2, VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram);
glfwTerminate();
return 0;
}
主要部分代码
实现效果
3D效果
下面看一3D表示的效果,不需要修改着色器。
main.cpp
#include <iostream>
#include <string>
#include "glew.h"
#include "glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "log.h"
#include "GlslDealConfig.h"
GLfloat vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
// 主函数
int main() {
GlslDealConfig glslConfig;
// 初始化 GLFW
if (!glfwInit()) {
LOGE("Failed to initialize GLFW");
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 创建窗口
GLFWwindow* window = glfwCreateWindow(1000, 1000, "3D Demo", nullptr, nullptr);
if (!window) {
LOGE("Failed to create GLFW window");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// 初始化 GLEW
GLenum err = glewInit();
if (err != GLEW_OK) {
LOGE("Failed to initialize GLEW: %s", reinterpret_cast<const char*>(glewGetErrorString(err)));
return -1;
}
glfwSwapInterval(1);
// 加载着色器
std::string vertexShaderCode = glslConfig.ReadGlslFile("/home/ryan/Rendering/demo/glsl/Trans/VertexShader.glsl");
std::string fragmentShaderCode = glslConfig.ReadGlslFile("/home/ryan/Rendering/demo/glsl/Trans/FragmentShader.glsl");
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
const GLchar* vShaderSource = vertexShaderCode.c_str();
const GLchar* fShaderSource = fragmentShaderCode.c_str();
glShaderSource(vertexShader, 1, &vShaderSource, nullptr);
glShaderSource(fragmentShader, 1, &fShaderSource, nullptr);
glCompileShader(vertexShader);
glCompileShader(fragmentShader);
glslConfig.CheckShaderCompileV(vertexShader);
glslConfig.CheckShaderCompileF(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glslConfig.CheckProgmaLinkStatus(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 配置 VAO, VBO, EBO
GLuint VAO, VBO[2];
glGenVertexArrays(1, &VAO);
glGenBuffers(2, VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3*sizeof(GLfloat)));
glEnableVertexAttribArray(1);
// 加载纹理
GLuint texture[2];
texture[0] = glslConfig.loadTexture("/home/ryan/Rendering/demo/resource/brickwall.jpg", GL_RGB);
texture[1] = glslConfig.loadTexture("/home/ryan/Rendering/demo/resource/awesomeface.png", GL_RGBA);
// 设置投影矩阵
glm::mat4 projection = glm::mat4(1.0f);
// projection = glm::ortho(0.0f, 1000.0f, 0.0f, 1000.0f, -1.0f, 1.0f);
glUseProgram(shaderProgram);
GLuint projLoc = glGetUniformLocation(shaderProgram, "projection");
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
// 激活纹理单元
glActiveTexture(GL_TEXTURE3);
GLuint textureLocation = glGetUniformLocation(shaderProgram, "textureClass");
glUniform1i(textureLocation, 3);
glActiveTexture(GL_TEXTURE6);
GLuint textureLocation2 = glGetUniformLocation(shaderProgram, "textureClass2");
glUniform1i(textureLocation2, 6);
glEnable(GL_DEPTH_TEST);
// 渲染循环
while (!glfwWindowShouldClose(window))
{
glViewport(0, 0, 1000, 1000);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glActiveTexture(GL_TEXTURE6);
glBindTexture(GL_TEXTURE_2D, texture[1]);
//此例子视点只在Z轴移动
glm::mat4 Mmatrix = glm::mat4(1.0f);
glm::mat4 Vmatrix = glm::mat4(1.0f);
glm::mat4 Pmatrix = glm::mat4(1.0f);
Mmatrix = glm::rotate(Mmatrix,(float)glfwGetTime(), glm::vec3(1.0f, 1.0f, 0.0f));
Vmatrix = glm::translate(Vmatrix, glm::vec3(0.0f, 0.0f, -3.0f));
Pmatrix = glm::perspective(glm::radians(45.0f), 1000.0f/1000.0f, 0.1f, 100.0f);
GLuint TransM = glGetUniformLocation(shaderProgram, "Mtrans");
GLuint TransV = glGetUniformLocation(shaderProgram, "Vtrans");
GLuint TransP = glGetUniformLocation(shaderProgram, "Ptrans");
glUniformMatrix4fv(TransM, 1, GL_FALSE, glm::value_ptr(Mmatrix));
glUniformMatrix4fv(TransV, 1, GL_FALSE, glm::value_ptr(Vmatrix));
glUniformMatrix4fv(TransP, 1, GL_FALSE, glm::value_ptr(Pmatrix));
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
// 清理资源
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(2, VBO);
glDeleteProgram(shaderProgram);
glfwTerminate();
return 0;
}
运行效果
感谢阅读^ _ ^
如有问题欢迎评论区交流指正,如需要对应源码资源可私聊我。