OpenGL-- Shader 多个纹理 变换
2016-12-13 19:02
218 查看
源码参考:
http://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/08%20Coordinate%20Systems/ http://blog.csdn.net/qq_28637193/article/details/52504590
此博用FreeImage加载纹理
1
主程序
2
Shader处理
3
vertexShader 顶点着色器
4
fragementShader 片断着色器
采用素材:
效果: (静态截图, 实为动态)
局部效果:
http://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/08%20Coordinate%20Systems/ http://blog.csdn.net/qq_28637193/article/details/52504590
此博用FreeImage加载纹理
1
主程序
// OpenGL 为状态机,数据为自上往下流动 #define GLEW_STATIC #include <GL/glew.h> #include <GLFW/glfw3.h> #include <SOIL/SOIL.h> // 用于加载纹理 // GLM Mathematics #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <iostream> #include "Shader.h" #pragma comment(lib, "glfw3.lib") #pragma comment(lib, "glfw3dll.lib") #pragma comment (lib, "glew32s.lib") #pragma comment (lib, "opengl32.lib") #pragma comment (lib, "glu32.lib") #pragma comment (lib, "SOIL.lib") // 键盘回调函数 void key_callback(GLFWwindow* pWnd, int key, int scancode, int action, int mode); // 窗口大小 const GLuint WIDTH = 800, HEIGHT = 600; // *************************************************************************** int main() { // Init GLFW glfwInit(); // Set all the required options for GLFW glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // 用 GLFW 的函数创建一个窗口 宽 高 名称 窗口模式(全屏/窗口nullptr) 共享上下文资源nullptr不共享 //GLFWmonitor* pMonitor = glfwGetPrimaryMonitor(); // 此两句为全屏模式 //GLFWwindow* pWnd = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", pMonitor, nullptr); GLFWwindow* pWnd = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); glfwMakeContextCurrent(pWnd); // Set the required callback functions glfwSetKeyCallback(pWnd, key_callback); // 键盘回调 // GLEW 使用新方式检索函数指针和扩展(不太了解) glewExperimental = GL_TRUE; // 注释掉也能正常显示图形 // Initialize GLEW to setup the OpenGL Function pointers glewInit(); glViewport(0, 0, WIDTH, HEIGHT); // 设置视图尺寸 glEnable(GL_DEPTH_TEST); // 启用深度测试 // 传入Shader源码位置, 加载Shader源码, 编译 链接 GLSL 程序 Shader ourShader("./vertexShader", "./fragementShader"); // Set up vertex data (and buffer(s)) and attribute pointers // 立方体顶点 用三角形绘制 前三为位置坐标 后二为纹理坐标 GLfloat vertices[] = { -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f }; // World space positions of our cubes 世界坐标系 点坐标 10个 glm::vec3 cubePositions[] = { glm::vec3(-3.0f, -1.0f, -5.0f), glm::vec3(2.0f, 5.0f, -1.0f), glm::vec3(-1.5f, -2.2f, -2.5f), glm::vec3(0.0f, -2.0f, -5.3f), glm::vec3(2.4f, -0.4f, -3.5f), glm::vec3(-1.7f, 0.0f, -7.5f), glm::vec3(1.3f, -2.0f, -2.5f), glm::vec3(1.5f, 2.0f, -2.5f), glm::vec3(1.5f, 0.2f, -1.5f), glm::vec3(-1.3f, 1.0f, -1.5f) }; GLuint VBO, VAO; //生成一个VAO 并绑定 glGenVertexArrays(1, &VAO); // Vertex Array Object VAO是所有顶点数据的状态集合 glBindVertexArray(VAO); // VAO是一个容器,可以包括多个VBO glGenBuffers(1, &VBO); // Veretx Buffer Object glBindBuffer(GL_ARRAY_BUFFER, VBO); // VBO其实就是显卡中的显存 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将顶点传至GPU // void glVertexAttribPointer(GLuint index, GLint size, GLenum type, // GLboolean normalized, GLsizei stride, const void* pointer); // 位置属性如何索引 //索引位置 大小 数据类型 是否要归一化 两个连续点间的偏移量 数据中第一个数据 // 第一个参数 index 指定要修改的顶点属性的索引值 被 Shader 中 layout (location = 0) 使用 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); // 启用 // 纹理坐标属性 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(2); glBindVertexArray(0); // Unbind VAO // 可注释 // ==================== // Texture 1 纹理1 // ==================== GLuint textureA; glGenTextures(1, &textureA); // 生成一个纹理, textureA指向此纹理所在位置 // All upcoming GL_TEXTURE_2D operations now have effect on our texture object glBindTexture(GL_TEXTURE_2D, textureA); // 绑定此二维纹理,即接下来的纹理操作,都在 textureA 上 // 纹理坐标的第一维坐标值大于1.0或小于0.0时,应该如何处理 重复 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // 纹理坐标的第二维坐标值大于1.0或小于0.0时,应该如何处理 重复 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // 大纹理用于一个小面积物体上, 使用最接近的若干颜色,加权平均得到绘制的像素颜色 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 小纹理用于一个大面积物体上, 使用最接近的若干颜色,加权平均得到绘制的像素颜色 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); int width, height; // 用 SOIL 库 加载图片 unsigned char* pChImg = SOIL_load_image("./box.jpg", &width, &height, 0, SOIL_LOAD_RGB); // 载入纹理 目标 多层次细节(0不考虑) 颜色 宽 高 边框大小 数据类型 数据 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pChImg); glGenerateMipmap(GL_TEXTURE_2D); //为与target相关联的纹理图像生成一组完整的mipmap glBindTexture(GL_TEXTURE_2D, 0); // 解绑 SOIL_free_image_data(pChImg); // 释放加载的图片内存 // =================== // Texture 2 纹理2 // =================== GLuint textureB; glGenTextures(1, &textureB); glBindTexture(GL_TEXTURE_2D, textureB); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); pChImg = SOIL_load_image("./gold.jpg", &width, &height, 0, SOIL_LOAD_RGB); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pChImg); glGenerateMipmap(GL_TEXTURE_2D); SOIL_free_image_data(pChImg); glBindTexture(GL_TEXTURE_2D, 0); while (!glfwWindowShouldClose(pWnd)) { // 检查窗口事件 glfwPollEvents(); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 设置清除颜色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 用设置好的清除颜色设置窗口颜色 // Bind Textures using texture units glActiveTexture(GL_TEXTURE0); // 激活纹理A glBindTexture(GL_TEXTURE_2D, textureA); // 使用纹理A // 获取着色器程序中,指定为uniform类型变量的id 即获取纹理采样器 GLint textureALocation = glGetUniformLocation(ourShader.getPrograme(), "textureA"); glUniform1i(textureALocation, 0); // 将纹理A传至Shader的纹理采样器中 glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureB); glUniform1i(glGetUniformLocation(ourShader.getPrograme(), "textureB"), 1); ourShader.useShaderPrograme(); // 激活Shader程序 // Create transformations 创建旋转矩阵 glm::mat4 view; glm::mat4 projection; view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f)); // 投影矩阵 视野范围 宽高比 近平面 远平面 projection = glm::perspective(45.0f, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f); // Get their uniform location GLint modelLoc = glGetUniformLocation(ourShader.getPrograme(), "model"); GLint viewLoc = glGetUniformLocation(ourShader.getPrograme(), "view"); GLint projLoc = glGetUniformLocation(ourShader.getPrograme(), "projection"); // 将转换矩阵传至Shader 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(VAO); // 绑定 VAO for (GLuint i = 0; i <10; i++) // 循环十次 绘制 每次绘制一个盒子 { glm::mat4 model; model = glm::translate(model, cubePositions[i]); GLfloat angle = glfwGetTime(); // 随时间 变换角度旋转 model = glm::rotate(model, angle, glm::vec3(1.0f, 0.3f, 0.5f)); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); // 绘制三角形 从顶点数据 0 开始 绘制36个顶点 六面 每面两个三角形六个点 6*6 = 36 glDrawArrays(GL_TRIANGLES, 0, 36); } glBindVertexArray(0); // 解绑 VAO glfwSwapBuffers(pWnd); } // Properly de-allocate all resources once they've outlived their purpose glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glfwTerminate(); // 关闭并清理 return 0; } // Is called whenever a key is pressed/released via GLFW void key_callback(GLFWwindow* pWnd, int key, int scancode, int action, int mode) { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) // ESC键 退出 glfwSetWindowShouldClose(pWnd, GL_TRUE); }
2
Shader处理
#pragma once #ifndef TEXTURE_SHADER_H_ #define TEXTURE_SHADER_H_ #include <string> #include <fstream> #include <sstream> #include <iostream> #include <gl/glew.h> #include <string> #include <fstream> #include <sstream> #include <iostream> #include <GL/glew.h> class Shader { public: Shader(const GLchar* vertexPath, const GLchar* fragmentPath); ~Shader(); public: void useShaderPrograme(); GLuint getPrograme() { return this->m_nProgram; } private: GLuint m_nProgram; }; Shader::Shader(const GLchar* vertexPath, const GLchar* fragmentPath) { std::string vertexCode; std::string fragmentCode; std::ifstream vertexShaderF; std::ifstream fragementShaderF; vertexShaderF.exceptions(std::ifstream::badbit); fragementShaderF.exceptions(std::ifstream::badbit); try { vertexShaderF.open(vertexPath); // 打开文件 fragementShaderF.open(fragmentPath); std::stringstream vertexShaderStream, fragementShaderStream; vertexShaderStream << vertexShaderF.rdbuf(); // 读取文件至stringstream中 fragementShaderStream << fragementShaderF.rdbuf(); vertexShaderF.close(); fragementShaderF.close(); vertexCode = vertexShaderStream.str(); // 转换成string类型 fragmentCode = fragementShaderStream.str(); } catch (std::ifstream::failure e) { std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ:" << std::endl; } const GLchar* pVertexCode = vertexCode.c_str(); // string 转 char* const GLchar* pFragementCode = fragmentCode.c_str(); GLuint nVertexShader, nFragementShader; GLint nRes = 0; GLchar chLogInfo[512] = { '\0' }; // 创建顶点着色器 nVertexShader = glCreateShader(GL_VERTEX_SHADER); // 将顶点着色程序的源代码字符数组绑定到顶点着色器对象 glShaderSource(nVertexShader, 1, &pVertexCode, nullptr); glCompileShader(nVertexShader); // compile shader 编译着色器 // 获取编译结果 glGetShaderiv(nVertexShader, GL_COMPILE_STATUS, &nRes); if (!nRes) { glGetShaderInfoLog(nVertexShader, 512, nullptr, chLogInfo); std::cout << "ERROR::SHADEF::VERTEX::COMPILATION_FAILED:" << chLogInfo << std::endl; } // 创建片断着色器 nFragementShader = glCreateShader(GL_FRAGMENT_SHADER); // 将片段着色程序的源代码字符数组绑定到片段着色器对象 glShaderSource(nFragementShader, 1, &pFragementCode, nullptr); glCompileShader(nFragementShader); glGetShaderiv(nFragementShader, GL_COMPILE_STATUS, &nRes); if (!nRes) { glGetShaderInfoLog(nFragementShader, 512, nullptr, chLogInfo); std::cout << "ERROR::SHADEF::FRAGEMENT::COMPILATION_FAILED:" << chLogInfo << std::endl; } this->m_nProgram = glCreateProgram(); // 创建GLSL程序 glAttachShader(this->m_nProgram, nVertexShader); // 绑定shader到program glAttachShader(this->m_nProgram, nFragementShader); // glLinkProgram操作产生最后的可执行程序,它包含最后可以在硬件上执行的硬件指令 glLinkProgram(this->m_nProgram); // 链接 glGetProgramiv(this->m_nProgram, GL_LINK_STATUS, &nRes); if (!nRes) { glGetProgramInfoLog(this->m_nProgram, 512, nullptr, chLogInfo); std::cout << "ERROR::SHADEF::FRAGEMENT::LINK_FAILED:" << chLogInfo << std::endl; } glDeleteShader(nVertexShader); glDeleteShader(nFragementShader); } Shader::~Shader() { } #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> void Shader::useShaderPrograme() { glUseProgram(this->m_nProgram); // 使用porgram } #endif
3
vertexShader 顶点着色器
#version 330 core // 位置值 在C++ 中 glVertexAttribPointer 指定 layout (location = 0) in vec3 position; layout (location = 2) in vec2 texCoord; // out: 指定变量为着色器阶段的一个输出 out vec2 TexCoord; // Uniform前辍修饰的变量 初始值由外部程序赋值 // 指定这个值从应用程序传递个着色器 // 并在一个特定的图元中保持为常数值 // 在Shader中是只读的,只能由外部主机程序传入值 // 由顶点着色器和片段着色器 共享的,必须声明为全局变量 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); }
4
fragementShader 片断着色器
#version 330 core in vec2 TexCoord; out vec4 color; // sampler2D 采样器(Sampler) 内建数据类型 // 纹理采样 uniform sampler2D textureA; uniform sampler2D textureB; // void main() { // texture内置函数 将与纹理坐标对应的纹理值从内存中取出来 // mix内置函数 将两个纹理一起混合,得到最后的颜色 color = mix(texture(textureA, TexCoord), texture(textureB, TexCoord), 0.3); }
采用素材:
效果: (静态截图, 实为动态)
局部效果:
相关文章推荐
- qt5_qml_Opengl_shader 第二弹----------------------纹理贴图(RGB)
- qt5_qml_Opengl_shader 第三弹-----------------------纹理贴图(YUV)
- opengl 基本图元颜色变换后显示纹理位图本身的颜色
- qt5_qml_Opengl_shader 第四弹----------------------纹理贴图(YUV视频循环播放)
- 关于Opengl创建多个纹理
- 为OpenGL考试而准备的代码——鼠标控制视角变换+简单纹理映射+键盘的光照控制+Bezier曲线
- 6.OpenGL学习之多个纹理映射
- OpenGL ES Shader 多重纹理
- 【OpenGL学习】使用Shader处理纹理
- Opengl渲染管线 坐标变换 纹理与光照
- OPENGL 纹理贴图 过滤 mipmaps (shader)
- OpenGL.ES在Android上的简单实践:6-曲棍球(增加纹理,VAO,ShaderProgram)
- Opengl_20 _复习变换矩阵+复习光源+两个模型使用不同的shader
- Android OpenGL 使用纹理(五)
- opengl中添加纹理
- 思考:矩阵及变换,以及矩阵在DirectX和OpenGL中的运用问题:左乘/右乘,行优先/列优先,...
- opengl变换
- OpenGL 加载DDS文件(压缩纹理)
- Unity3D Shader官方教程翻译(八)----Shader语法:Pass的纹理处理
- OpenGL变换顺序的理解