Following the previous OpenGL_Learn05 (Texture)-CSDN Blog
1. Modify fragment shader
Modify the fragment shader to only make the smiley face look the other way
== ======>>>>>
The Y-axis of the texture coordinates has not been changed. What needs to be changed is the texture coordinates of the X-axis.
The code snippet is rewritten as follows
#version 330 core out vec4 FragColor; in vec3 ourColor; in vec2 TexCoord; //texture sampler uniform sampler2D textureone; uniform sampler2D texturetwo; void main() { FragColor = mix(texture(textureone,TexCoord),texture(texturetwo,vec2(1.0-TexCoord.x,TexCoord.y)),0.5); }
2. Try different texture wrapping methods
Set a range from
0.0f
to2.0f
(instead of the original0.0f
to1.0f
) texture coordinates, try to see if you can place 4 smiley faces in the corners of the box.
Original texture coordinates:
//4. Set vertex data
float 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
};
Change it to the following:
//4. Set vertex data
float vertices[] = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 2.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, 2.0f // top left
};
3. Texture filtering
Try displaying only the middle part of the texture image on the rectangle and modifying the texture coordinates to achieve the effect of seeing individual pixels. Try using the GL_NEAREST texture filtering method to make the pixels appear clearer.
#include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> #include "stb_image.h" #include <cmath> #include "shader.h" 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.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 (note that we changed them to 'zoom in' on our texture image) 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.55f, 0.55f, // top right 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.55f, 0.45f, // bottom right -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.45f, 0.45f, // bottom left -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.45f, 0.55f // 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, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); //Set the color attribute pointer glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); //Set texture attribute pointer glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); //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_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); //Set texture filtering parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //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_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //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 //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.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); } // 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); }
4. Dynamically adjust texture visibility
Use a uniform variable as the third argument to the mix function to change the visibility of both textures, and use the up and down keys to change the visibility of the box or smiley.
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,vec2(1.0-TexCoord.x,TexCoord.y)),mixValue); }
main.cpp
#include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> #include "stb_image.h" #include <cmath> #include "shader.h" 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, 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 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, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); //Set the color attribute pointer glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); //Set texture attribute pointer glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); //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 //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); }
Texture – LearnOpenGL CN (learnopengl-cn.github.io)