OpenGL贴图、小图片叠加(10)
作者:互联网
基于前边两篇博文:OpenGL多层纹理叠加_部分区域(九-2) - 邗影 - 博客园 (cnblogs.com)
OpenGL多层纹理叠加MIX(九-1) - 邗影 - 博客园 (cnblogs.com)
本篇文章效果类似,也是一个贴图,但是是一个完整小图贴到一张大图上;我们经常看视频的时候会有logo贴图的那种效果;或者像看电视,角落上有电视台小图;但是目前本博客的程序还做不到透明贴图(如图,彩虹中的透明部分是黑色的,而不是透明的)
本博客仅展示个人实现效果(不代表真实原理、机制);通过使用多个VBO进行实现;
1 #include "stdafx.h" 2 #include<windows.h> 3 #include <glad/glad.h> 4 #include <GLFW/glfw3.h> 5 #define STB_IMAGE_IMPLEMENTATION 6 #include <stb_image.h> 7 #include<string> 8 #include<fstream> 9 #include<sstream> 10 #include<iostream> 11 12 #include <stdio.h> 13 14 // settings 15 const unsigned int SCR_WIDTH = 800; 16 const unsigned int SCR_HEIGHT = 600; 17 unsigned int VBO = 0; 18 unsigned int VBO2 = 0; 19 unsigned int VAO = 0; 20 unsigned int VAO2 = 0; 21 unsigned int EBO = 0; 22 unsigned int texturePIC = 0; 23 unsigned int texturePIC2 = 0; 24 int shaderProgram = 0; 25 GLuint texId_bottom = 99; 26 GLuint texId_top = 99; 27 28 //本地文件夹下有个图片加载到项目上(注意参数列表中的引用表示变量本身,不要用变量的副本) 29 void LoadPicture(unsigned int& textureIndex,unsigned int& textureIndex2) 30 { 31 //返回不同采样器的序号 32 glUseProgram(shaderProgram); 33 texId_bottom = glGetUniformLocation(shaderProgram, " ourTextureB"); 34 texId_top = glGetUniformLocation(shaderProgram, "ourTextureT"); 35 36 glGenTextures(1, &textureIndex); 37 glActiveTexture(GL_TEXTURE0); 38 glBindTexture(GL_TEXTURE_2D, textureIndex); 39 40 //为bind的纹理设置环绕,过滤方式 41 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 42 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 43 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 44 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 45 46 //加载图片生成纹理 : 47 stbi_set_flip_vertically_on_load(true); 48 //stbi是一个图片载入的开源组件,文件名,宽高,通道数,你期望的通道数(使用的是宽大于高的图片,如果是高>宽,程序需要改否则渲染异常) 49 int W, H, channels_in_file, desired_channels = 3; 50 unsigned char* data = stbi_load("./F.jpg ", &W, &H, &channels_in_file, desired_channels); 51 if (channels_in_file == 3) 52 { 53 //数据生成纹理;根据指定的参数,把输入数据生成一张2D纹理 54 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, W, H, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 55 glUniform1i(texId_bottom,0); 56 //生成mipmap数组 57 glGenerateMipmap(GL_TEXTURE_2D); 58 } 59 stbi_image_free(data); 60 data = nullptr; 61 62 //加载图片2 63 glGenTextures(1, &textureIndex2); 64 65 glActiveTexture(GL_TEXTURE1); 66 glBindTexture(GL_TEXTURE_2D, textureIndex2); 67 //为bind的纹理设置环绕,过滤方式 68 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 69 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 70 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 71 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 72 //加载图片生成纹理 : 73 stbi_set_flip_vertically_on_load(true); 74 //stbi是一个图片载入的开源组件,文件名,宽高,通道数,你期望的通道数 75 int W2, H2, channels_in_file2, desired_channels2 = 3; 76 unsigned char* data2 = stbi_load("./lyf.jpg", &W2, &H2, &channels_in_file2, desired_channels2); 77 if (channels_in_file2 == 3) 78 { 79 //数据生成纹理;根据指定的参数,把输入数据生成一张2D纹理 80 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, W2, H2, 0, GL_RGB, GL_UNSIGNED_BYTE, data2); 81 glUniform1i(texId_top, 1); 82 //生成mipmap数组 83 glGenerateMipmap(GL_TEXTURE_2D); 84 } 85 stbi_image_free(data2); 86 data2 = nullptr; 87 88 glUseProgram(0); 89 } 90 91 92 void render() 93 { 94 95 glBindVertexArray(VAO); 96 glUseProgram(shaderProgram); 97 glUniform1i(glGetUniformLocation(shaderProgram, "mixValue"), 1);//要先启用着色器程序咋,再指定变量的值 98 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); 99 glUseProgram(0); 100 glBindVertexArray(0); 101 102 //不同的图片要画两次 103 104 glBindVertexArray(VAO2); 105 glUseProgram(shaderProgram); 106 glUniform1i(glGetUniformLocation(shaderProgram, "mixValue"), 2);//为了给片元着色器区分采样 107 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); 108 glUseProgram(0); 109 glBindVertexArray(0); 110 } 111 112 void initmodule() 113 { 114 //做个一模型;正方形;映射了顶点坐标和纹理坐标的对应关系 115 float vertexs[] = { 116 //顶点坐标-------纹理坐标 117 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // 右上 118 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // 右下 119 -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // 左下 120 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上 121 122 123 }; 124 125 float vertexs2[] = { 126 //顶点坐标-------纹理坐标 127 0.9f, 1.0f, 0.0f, 1.0f, 1.0f, // 右上 128 0.9f, 0.5f, 0.0f, 1.0f, 0.0f, // 右下 129 -0.1f, 0.5f, 0.0f, 0.0f, 0.0f, // 左下 130 -0.1f, 1.0f, 0.0f, 0.0f, 1.0f // 左上 131 132 133 }; 134 135 136 137 //一个正方形是由两个三角形得来的;记录顶点的索引顺序 138 unsigned int indexs[] = { 139 0,1,3, 140 1,2,3, 141 }; 142 143 144 //加载纹理图片,生成纹理 145 LoadPicture(texturePIC, texturePIC2); 146 147 //做VAO 148 glGenVertexArrays(1, &VAO); 149 glBindVertexArray(VAO); 150 151 //做VBO 152 153 glGenBuffers(1, &VBO); 154 glBindBuffer(GL_ARRAY_BUFFER, VBO); 155 //创建显存空间 156 glBufferData(GL_ARRAY_BUFFER, sizeof(vertexs), vertexs, GL_STATIC_DRAW); 157 158 glGenBuffers(1, &EBO); 159 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); 160 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexs), indexs, GL_STATIC_DRAW); 161 162 163 //设置第0个锚点,3个点,不需要归一化,跨度5个float可以读下一个点 164 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); 165 //打开顶点 166 glEnableVertexAttribArray(0); 167 //纹理属性设置,纹理在第一个锚点上(指定顶点数据)你在顶点着色器程序中制定了锚点1的位置对应的是纹理坐标 168 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); 169 //打开纹理 170 glEnableVertexAttribArray(1); 171 172 //解除绑定VBO 173 glBindBuffer(GL_ARRAY_BUFFER, 0); 174 175 //解绑VAO 176 glBindVertexArray(0); 177 178 179 //叠图的VAO,VBO,EBO--------------注意不能用同一个VAO(VBO), 180 //对每个VAO可以使用同样的EBO,但是一定要在每个VAO下都写一次EBO以及glVertexAttribPointer 181 glGenVertexArrays(1, &VAO2); 182 glBindVertexArray(VAO2); 183 184 glGenBuffers(1, &VBO2); 185 glBindBuffer(GL_ARRAY_BUFFER, VBO2); 186 //创建显存空间 187 glBufferData(GL_ARRAY_BUFFER, sizeof(vertexs2), vertexs2, GL_STATIC_DRAW); 188 189 190 //设置索引缓冲 191 glGenBuffers(1, &EBO); 192 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); 193 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexs), indexs, GL_STATIC_DRAW); 194 195 //绑定纹理,OpenGL至少保证有16个纹理单元供你使用,也就是说你可以激活从GL_TEXTURE0到GL_TEXTRUE15 196 197 //设置第0个锚点,3个点,不需要归一化,跨度5个float可以读下一个点 198 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); 199 //打开顶点 200 glEnableVertexAttribArray(0); 201 //纹理属性设置,纹理在第一个锚点上(指定顶点数据)你在顶点着色器程序中制定了锚点1的位置对应的是纹理坐标 202 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); 203 //打开纹理 204 glEnableVertexAttribArray(1); 205 206 //解除绑定VBO 207 glBindBuffer(GL_ARRAY_BUFFER, 0); 208 209 //解绑VAO 210 glBindVertexArray(0); 211 212 } 213 214 void initshader(const char* verpath, const char* fragpath) 215 { 216 //编译shader,并记录shaderID 217 std::string VerCode(""); 218 std::string fregCode(""); 219 //读文件 220 std::ifstream vShaderFile; 221 std::ifstream fShaderFile; 222 223 vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); 224 fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); 225 226 try 227 { 228 vShaderFile.open(verpath); 229 fShaderFile.open(fragpath); 230 231 std::stringstream vsstream, fsstream; 232 vsstream << vShaderFile.rdbuf(); 233 fsstream << fShaderFile.rdbuf(); 234 VerCode = vsstream.str(); 235 fregCode = fsstream.str(); 236 237 } 238 catch (const std::exception&) 239 { 240 std::cout << "read file error" << std::endl; 241 } 242 243 const char* vshader = VerCode.c_str(); 244 const char* fshader = fregCode.c_str(); 245 246 //shader 编译连接 247 unsigned int vertexID = 0, fragID = 0; 248 char infoLog[512];//存储错误信息 249 int successflag = 0; 250 vertexID = glCreateShader(GL_VERTEX_SHADER); 251 glShaderSource(vertexID, 1, &vshader, NULL); 252 glCompileShader(vertexID); 253 //获取编译是否成功 254 glGetShaderiv(vertexID, GL_COMPILE_STATUS, &successflag); 255 if (!successflag) 256 { 257 glGetShaderInfoLog(vertexID, 512, NULL, infoLog); 258 std::string errstr(infoLog); 259 std::cout << "v shader err" << infoLog; 260 } 261 //frag 262 fragID = glCreateShader(GL_FRAGMENT_SHADER); 263 glShaderSource(fragID, 1, &fshader, NULL); 264 glCompileShader(fragID); 265 //获取编译是否成功 266 glGetShaderiv(fragID, GL_COMPILE_STATUS, &successflag); 267 if (!successflag) 268 { 269 glGetShaderInfoLog(fragID, 512, NULL, infoLog); 270 std::string errstr(infoLog); 271 std::cout << "f shader err" << infoLog; 272 } 273 //链接 274 shaderProgram = glCreateProgram(); 275 glAttachShader(shaderProgram, vertexID); 276 glAttachShader(shaderProgram, fragID); 277 glLinkProgram(shaderProgram); 278 glGetProgramiv(shaderProgram, GL_LINK_STATUS, &successflag); 279 if (!successflag) 280 { 281 glGetShaderInfoLog(shaderProgram, 512, NULL, infoLog); 282 std::string errstr(infoLog); 283 std::cout << "link error"; 284 } 285 286 //编译完成后,可以把中间的步骤程序删除 287 glDeleteShader(vertexID); 288 glDeleteShader(fragID); 289 } 290 void processInput(GLFWwindow *window) 291 { 292 if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) 293 { 294 //将窗口设置为关闭,跳出循环 295 glfwSetWindowShouldClose(window, true); 296 } 297 } 298 299 void framebuffer_size_callback(GLFWwindow* window, int width, int height) 300 { 301 glViewport(0, 0, width, height); 302 } 303 304 int main() 305 { 306 //glfw初始化 307 glfwInit(); 308 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 309 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 310 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 311 312 //glfw创建窗口 313 GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); 314 if (window == NULL) 315 { 316 printf("创建窗口失败"); 317 //终止 318 glfwTerminate(); 319 return -1; 320 } 321 //显示窗口 322 glfwMakeContextCurrent(window); 323 324 //设置回调,当窗口大小调整后将调用该回调函数 325 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 326 327 // glad初始化 328 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) 329 { 330 printf("加载失败"); 331 return -1; 332 } 333 334 initshader("vertexShader.glsl", "fragmentShader.glsl"); 335 initmodule(); 336 // 使用循环达到循环渲染效果 337 while (!glfwWindowShouldClose(window)) 338 { 339 //自定义输入事件 340 processInput(window); 341 glEnable(GL_BLEND); 342 glClearColor(0.5f, 0.5f, 0.3f, 1.0f); 343 glClear(GL_COLOR_BUFFER_BIT); 344 render(); 345 //交互缓冲区,否则显示空白 346 glfwSwapBuffers(window); 347 //输入输出事件,否则无法对窗口进行交互 348 glfwPollEvents(); 349 } 350 351 //终止渲染 关闭并清理glfw本地资源 352 glfwTerminate(); 353 return 0; 354 }
片元着色器:
#version 330 core out vec4 FragColor; in vec2 TexCoord; float alpha; uniform int mixValue; uniform sampler2D ourTextureB; uniform sampler2D ourTextureT; void main() { if(mixValue == 1) { FragColor = texture(ourTextureB, TexCoord); }else{ FragColor = texture(ourTextureT, TexCoord); } };
顶点着色器:
#version 330 core layout(location = 0) in vec3 aPos; layout(location = 1) in vec2 texCoord; out vec2 TexCoord; void main() { gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0); TexCoord = texCoord; };
效果展示:
标签:贴图,10,1.0,OpenGL,0.0,TEXTURE,纹理,2D,GL 来源: https://www.cnblogs.com/8335IT/p/16414875.html