1. Vector
Vectors have a direction and a magnitude. If a vector has 2 dimensions, it represents the direction of a plane (imagine a 2D image), and when it has 3 dimensions, it can represent the direction of a 3D world.
You can think of these 2D vectors as 3D vectors with z coordinate 0.
2. Vector inner and outer products
Dot product (inner product) of vectors: Simply put, it can determine the similarity of vector directions
Vector outer product: simply put, you can get its normal vector
3. Addition, subtraction and length of vectors
Vector addition can be defined as component-wise addition, that is, each component of one vector is added to the corresponding component of another vector.
Add
v = (4, 2)
andk = (1, 2) to get (4 + 1, 2 + 2)
Subtraction of a vector is equal to adding the opposite of the second vector. Subtracting two vectors gives you the difference in where the two vectors point.
We use the Pythagoras Theorem to obtain the length/magnitude of a vector. If you graph the x and y components of a vector, the vector will form a triangle with the x and y components as sides.
4. Rotate
5. Code to implement rotation and scaling
texture.vs
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aTexCorrd; out vec2 TexCoord; uniform mat4 transform; void main() { gl_Position = transform * vec4(aPos, 1.0); TexCoord=vec2(aTexCorrd.x,1.0-aTexCorrd.y); }
texture.fs
#version 330 core out vec4 FragColor; in vec3 ourColor; in vec2 TexCoord; uniform float mixValue; //texture sampler uniform sampler2D textureone; uniform sampler2D texturetwo; void main() { FragColor = mix(texture(textureone,TexCoord),texture(texturetwo,TexCoord),mixValue); }
shader.h
#pragma once #include <glad/glad.h> #include <string> #include <fstream> #include <sstream> #include <iostream> class Shader { public: //Program ID unsigned int ID; \t //The constructor reads and builds the shader Shader(const char* vertexPath, const char* fagmentPath) { std::string vertexCode; std::string fragmentCode; std::ifstream vShaderFile; std::ifstream fShaderFile; vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); try { vShaderFile.open(vertexPath); fShaderFile.open(fagmentPath); std::stringstream vShaderStream, fShaderStream; vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); vShaderFile.close(); fShaderFile.close(); vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); } catch (std::ifstream::failure & amp; e) { std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl; } const char* vShaderCode = vertexCode.c_str(); const char* fShaderCode = fragmentCode.c_str(); //2.complie shaders unsigned int vertex, fragment; //vertex shader vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, & amp;vShaderCode, NULL); glCompileShader(vertex); checkCompileErros(vertex, "VERTEX"); //fragment Shader fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, & amp;fShaderCode, NULL); glCompileShader(fragment); checkCompileErros(fragment, "FRAGMENT"); //shader Program ID = glCreateProgram(); glAttachShader(ID, vertex); glAttachShader(ID, fragment); glLinkProgram(ID); checkCompileErros(ID, "PROGAM"); glDeleteShader(vertex); glDeleteShader(fragment); } //Use/activate program void use() { glUseProgram(ID); } //uniform tool function void setBool(const std::string & amp; name, bool value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); } void setInt(const std::string & amp; name, int value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), value); } void setFloat(const std::string & amp; name, float value) const { glUniform1f(glGetUniformLocation(ID, name.c_str()), value); } private: void checkCompileErros(unsigned int shader, std::string type) { int success; char infoLog[1024]; if (type != "PROGRAM") { glGetShaderiv(shader, GL_COMPILE_STATUS, & amp;success); if (!success) { glGetShaderInfoLog(shader, 1024, NULL, infoLog); std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\\ " << infoLog << "\\ -- --------- ------------------------------------------ -- " << std: :endl; } } else { glGetProgramiv(shader, GL_LINK_STATUS, & amp;success); if (!success) { glGetProgramInfoLog(shader, 1024, NULL, infoLog); std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\\ " << infoLog << "\\ -- --------- ------------------------------------------ -- " << std: :endl; } } } };
main.cpp
download glm
Tags · g-truc/glm (github.com)
#include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> #include "stb_image.h" #include <cmath> #include "shader.h" #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> 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; float mixValue = 0.2f; int main() { //1.Initialization configuration 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, GLFW_TRUE); #endif // __APPLE__ //2.gltf window creation GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LeranOpenGL", NULL, NULL); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); //3. Load all GL function pointers if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } Shader ourShader("./texture.vs", "./texture.fs"); //4. Set vertex data float vertices[] = { // positions // colors // 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 }; unsigned int indices[] = { 0, 1, 3, // first triangle 1, 2, 3 // second triangle }; unsigned int VBO, VAO, EBO; glGenVertexArrays(1, & amp;VAO); glGenBuffers(1, & amp;VBO); glGenBuffers(1, & amp;EBO);//Element Buffer Object: Element Buffer Object, EBO glBindVertexArray(VAO); \t //Copy the vertex array to the buffer for use by opengl 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); //Set the vertex attribute pointer glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); //Set texture attribute pointer glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); //Load and create texture unsigned int textureone,texturetwo; glGenTextures(1, & amp;textureone); glBindTexture(GL_TEXTURE_2D, textureone); //Set texture wrapping parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 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); //Load images and generate mipmaps int width, height, nrChannels; stbi_set_flip_vertically_on_load(true); std::string filePath = R"(D:\CPlusProject\LearnOpenGL\DataSet\container.jpg)"; unsigned char* data = stbi_load(filePath.c_str(), & amp;width, & amp;height, & amp;nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << "Failed to load texture" << std::endl; } stbi_image_free(data); glGenTextures(1, & amp;texturetwo); glBindTexture(GL_TEXTURE_2D, texturetwo); //Set texture wrapping parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 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); //Load images and generate mipmaps filePath = R"(D:\CPlusProject\LearnOpenGL\DataSet\awesomeface.png)"; unsigned char* data2 = stbi_load(filePath.c_str(), & amp;width, & amp;height, & amp;nrChannels, 0); if (data2) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2); glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << "Failed to load texture" << std::endl; } stbi_image_free(data2); \t ourShader.use(); glUniform1i(glGetUniformLocation(ourShader.ID, "textureone"), 0);//Choose one of the two ourShader.setInt("texturetwo", 1);//Choose one of the two //glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f); Annotation: The following is an example of matrix initialization, if you are using version 0.9.9 and above //glm::mat4 trans = glm::mat4(1.0f); //trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f)); //vec = trans * vec; //std::cout << vec.x << vec.y << vec.z << std::endl; glm::mat4 trans = glm::mat4(1.0f); trans = glm::rotate(trans, glm::radians(90.f), glm::vec3(0.0, 0.0, 1.0)); trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5)); unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform"); glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans)); //5. Loop rendering while (!glfwWindowShouldClose(window)) { processInput(window); // render glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); //Bind texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureone); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texturetwo); ourShader.setFloat("mixValue", mixValue); ourShader.use(); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0); glfwSwapBuffers(window); glfwPollEvents(); } glDeleteVertexArrays(1, & amp;VAO); glDeleteBuffers(1, & amp;VBO); glDeleteBuffers(1, & amp;EBO); glfwTerminate(); 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); if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) { std::cout << "up" << std::endl; mixValue + = 0.001f; if (mixValue >= 1.0f) { mixValue = 1.0f; } } if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) { std::cout << "down" << std::endl; mixValue -= 0.001f; // change this value accordingly (might be too slow or too fast based on system hardware) if (mixValue <= 0.0f) mixValue = 0.0f; } std::cout << "mixValue:" << mixValue <<std::endl; } // 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); }
6. Continuous rotation
To make the box rotate over time, we have to update the transformation matrix in the game loop. That is, in the while structure.
Here we first rotate the box around the origin (0, 0, 0), and then we move the rotated box to the lower right corner of the screen.
//5. Loop rendering while (!glfwWindowShouldClose(window)) { processInput(window); // render glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); //Bind texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureone); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texturetwo); ourShader.setFloat("mixValue", mixValue); glm::mat4 trans = glm::mat4(1.0f); trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)); trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f)); unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform"); glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans)); ourShader.use(); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0); glfwSwapBuffers(window); glfwPollEvents(); }
7. First translate and then rotate And first rotate and then translate
The above example is to first translate and then rotate. The following code is to first rotate and then translate.
//5. Loop rendering while (!glfwWindowShouldClose(window)) { processInput(window); // render glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); //Bind texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureone); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texturetwo); ourShader.setFloat("mixValue", mixValue); \t\t glm::mat4 trans = glm::mat4(1.0f); //First translate and then rotate //trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)); //trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f)); //Rotate first and then translate trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f)); trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)); unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform"); glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans)); ourShader.use(); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0); glfwSwapBuffers(window); glfwPollEvents(); }
8. Draw two triangles with different display methods
Try calling glDrawElements again to draw the second box, only using transformation to place it in a different position. Let the box be placed in the upper left corner of the window and scale (rather than rotate). (The
sin
function can be useful here, but note that applying negative values when using thesin
function will cause the object to be flipped).
//5. Loop rendering while (!glfwWindowShouldClose(window)) { processInput(window); // render glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); //Bind texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureone); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texturetwo); ourShader.setFloat("mixValue", mixValue); \t\t glm::mat4 trans = glm::mat4(1.0f); //First translate and then rotate //trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)); //trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f)); //Rotate first and then translate trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f)); trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)); unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform"); glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans)); ourShader.use(); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0); //second transformation trans = glm::mat4(1.0f); trans = glm::translate(trans, glm::vec3(-0.5f, 0.5f, 0.0f)); float scaleAmount = static_cast<float>(sin(glfwGetTime())); trans = glm::scale(trans, glm::vec3(scaleAmount, scaleAmount, scaleAmount)); glUniformMatrix4fv(transformLoc, 1, GL_FALSE, & trans[0][0]);// this time take the matrix value array's first element as its memory pointer value glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glfwSwapBuffers(window); glfwPollEvents(); }
The concepts and geometric significance of vector dot products and cross products – Zhihu (zhihu.com)
Transformation – LearnOpenGL CN (learnopengl-cn.github.io)