说明:本系列视频使用 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();
glm::mat4 model;
glm::mat4 view;
glm::mat4 projection;
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
projection = glm::perspective(glm::radians(45.0f),(GLfloat)SCR_WIDTH / (GLfloat)SCR_HEIGHT, 0.1f, 100.0f);
// Get their uniform location
GLint modelLoc = glGetUniformLocation(texture_box_Shader.getID(), "model");
GLint viewLoc = glGetUniformLocation(texture_box_Shader.getID(), "view");
GLint projLoc = glGetUniformLocation(texture_box_Shader.getID(), "projection");
// Pass them to the shaders
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
// Note: currently we set the projection matrix each frame, but since the projection matrix rarely changes it's often best practice to set it outside the main loop only once.
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
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 position;
layout (location = 2) in vec2 texCoord;
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
TexCoord = vec2(texCoord.x, 1.0 - texCoord.y);
}
@2 texture.fs 片段着色器代码
#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
// texture sampler
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
}
该系列文章主要参考openGL官网 和学习 learnopenGL官网 进行知识体系的梳理和重构,重在形成自己对openGL知识的理解和知识体系。
- 参考相关链接总站:LearnOpenGL-CN
- 参考OpenGL官网:About The Khronos Group - The Khronos Group Inc
- 同时也参考了网上其他内容知识 进而 进行整合。