OpenGL_Learn07 (Transform)

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) and k = (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 the sin 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)