说明:本系列视频使用 mac平台的Xcode来实现,windows平台和Linux平台与之类似。
1 程序功能简介
主要是通过实战 理解矩阵与旋转的关系,该案例是一个持续旋转的四边形。
2 程序代码-旋转四边形
2.1 核心源码
源码如下所示:
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <learnopengl/filesystem.h>
#include <cmath>
#include <stb_image.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
//===================macro & header process start===================
//triangle draw test
#include <learnopengl/shader_s.h>
//===================macro & header process end===================
#define SHADER_ROOT_DIR "/Users/wangdaosheng/Desktop/X-Project/AGS_Repository/OpenGL/OpenGL-demo/openGLtest1/shader/"
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
int main()
{
// @1.1 glfw: initialize and configure---------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#endif
// @1.2 glfw window creation---------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "DaoshengOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// @1.3 glad: load all OpenGL function pointers---------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// @2 shader op
Shader texture_box_Shader(SHADER_ROOT_DIR"texture.vs", SHADER_ROOT_DIR"texture.fs");
float texture_box_vertices[] = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int texture_box_indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
unsigned int texture_box_VBO, texture_box_VAO, texture_box_EBO;
glGenVertexArrays(1, &texture_box_VAO);
glGenBuffers(1, &texture_box_VBO);
glGenBuffers(1, &texture_box_EBO);
glBindVertexArray(texture_box_VAO);
glBindBuffer(GL_ARRAY_BUFFER, texture_box_VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(texture_box_vertices), texture_box_vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, texture_box_EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(texture_box_indices), texture_box_indices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// texture coord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
unsigned int texture1,texture2;
int width,height,nrChannels;
//texture1 op start
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
unsigned char *texture1_data = stbi_load(FileSystem::getPath("resources/textures/container.jpg").c_str(), &width, &height, &nrChannels, 0);
if (texture1_data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture1_data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture1" << std::endl;
}
stbi_image_free(texture1_data);
//texture1 op end
//texture2 op start
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
unsigned char *texture2_data = stbi_load(FileSystem::getPath("resources/textures/brickwall_normal.jpg").c_str(), &width, &height, &nrChannels, 0);
if (texture2_data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture2_data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture2" << std::endl;
}
stbi_image_free(texture2_data);
//texture2 op end
// render loop
while (!glfwWindowShouldClose(window))
{
// input process
processInput(window);
// render process
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// render container
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glUniform1i(glGetUniformLocation(texture_box_Shader.getID(), "texture1"), 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glUniform1i(glGetUniformLocation(texture_box_Shader.getID(), "texture2"), 1);
texture_box_Shader.use();
// Create transformations
glm::mat4 transform;
transform = glm::translate(transform, glm::vec3(0.2f, -0.2f, 0.0f));
// transform = glm::rotate(transform, (GLfloat)glfwGetTime() * 50.0f, glm::vec3(0.0f, 0.0f, 1.0f));
transform = glm::rotate(transform, (GLfloat)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.0f, 0.0f, 1.0f));
// Get matrix's uniform location and set matrix
GLint transformLoc = glGetUniformLocation(texture_box_Shader.getID(), "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));
glBindVertexArray(texture_box_VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
glDeleteVertexArrays(1, &texture_box_VAO);
glDeleteBuffers(1, &texture_box_VBO);
glDeleteBuffers(1, &texture_box_EBO);
glfwTerminate(); // glfw: terminate, clearing all previously allocated GLFW resources.
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
2.2 关联头文件
@1 这里关键头文件 FileSystem文件内容为:
#ifndef FILESYSTEM_H
#define FILESYSTEM_H
#include <string>
#include <cstdlib>
#include "root_directory.h" // This is a configuration file generated by CMake.
class FileSystem
{
private:
typedef std::string (*Builder) (const std::string& path);
public:
static std::string getPath(const std::string& path)
{
static std::string(*pathBuilder)(std::string const &) = getPathBuilder();
return (*pathBuilder)(path);
}
private:
static std::string const & getRoot()
{
static char const * envRoot = getenv("LOGL_ROOT_PATH");
static char const * givenRoot = (envRoot != nullptr ? envRoot : logl_root);
static std::string root = (givenRoot != nullptr ? givenRoot : "");
return root;
}
//static std::string(*foo (std::string const &)) getPathBuilder()
static Builder getPathBuilder()
{
if (getRoot() != "")
return &FileSystem::getPathRelativeRoot;
else
return &FileSystem::getPathRelativeBinary;
}
static std::string getPathRelativeRoot(const std::string& path)
{
return getRoot() + std::string("/") + path;
}
static std::string getPathRelativeBinary(const std::string& path)
{
return "../../../" + path;
}
};
// FILESYSTEM_H
#endif
@2 这里关键头文件 shader_s.h文件内容为:章节 OpenGL基础(08)操作封装 shader文件&着色器操作中提到的文件封装内容。
2.3 纹理代码
本章节涉及到的shader代码如下:
@1 texture.vs 顶点着色器代码
#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;
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = vec2(aTexCoord.x,aTexCoord.y);
}
@2 texture.fs 片段着色器代码
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
// texture sampler
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
}
该系列文章主要参考openGL官网 和学习 learnopenGL官网 进行知识体系的梳理和重构,重在形成自己对openGL知识的理解和知识体系。
- 参考相关链接总站:https://learnopengl-cn.readthedocs.io/zh/latest/
- 参考OpenGL官网:https://www.opengl.org/about/
- 同时也参考了网上其他内容知识 进而 进行整合。