接续上一篇http://blog.csdn.net/shenmifangke/article/details/50878084
根据这个网页的学习内容http://bullteacher.com/7-textures.html
发现载入图片还要使用SOIL图片库SOIL代表Simple OpenGL Image Library(简易OpenGL图像库)
所以这里继续写下去,使用openframeworks里面自带的freeimage库,因为已经默认集成在里面,所以使用非常方便
使用的图片和shader文件记住要放在data文件夹里
效果是一个载入一个png和一个jpg叠加的效果见下面图
素材图如下
(图片是自己无聊时候画的 感觉奇怪请无视)
http://blog.csdn.net/shenmifangke
下面直接上代码
OfApp.h
#pragma once #include "ofMain.h" class ofApp : public ofBaseApp{ public: void setup(); void update(); void draw(); void keyPressed(int key); void keyReleased(int key); void mouseMoved(int x, int y ); void mouseDragged(int x, int y, int button); void mousePressed(int x, int y, int button); void mouseReleased(int x, int y, int button); void windowResized(int w, int h); void dragEvent(ofDragInfo dragInfo); void gotMessage(ofMessage msg); string loadFragmentShader( string sPath ); GLuint texture1; GLuint texture2; };
#include "ofApp.h" //下面的库需要另外下 这里旋转之类我们使用of自带的库 //#include <glm/glm.hpp> //#include <glm/gtc/matrix_transform.hpp> //#include <glm/gtc/type_ptr.hpp> string ofApp::loadFragmentShader( string sPath ) { ofFile F; F.open(ofToDataPath(sPath), ofFile::ReadWrite, false); string ccc = F.readToBuffer().getText(); return ccc; } GLuint EBO; GLuint vbo; GLuint vao; const char* vertex_shader; const char* fragment_shader; GLuint shader_programme; //core-profile模式 所有新版本的OpenGL都是以3.3为基础 //这里使用的就是glfw3 void ofApp::setup(){ //这里用了4个点来表示一个方块所以要用EBO 如果不想用EBO 必须要六个点来表示两个三角形 //所以EBO是为了节约顶点量 GLfloat points[] = { // 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 }; GLuint indices[] = { // 起始于0! 索引数组 这个是多个三角必备的 0, 1, 3, // 第一个三角形 1, 2, 3 // 第二个三角形 }; //----------------------------------------------------vao绑定 glGenBuffers(1, &EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices),indices, GL_STATIC_DRAW); vao = 0; glGenVertexArrays (1, &vao); glBindVertexArray (vao); vbo = 0; glGenBuffers (1, &vbo); glBindBuffer (GL_ARRAY_BUFFER, vbo); glBufferData (GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);//glBufferData是一个用来把用户定义数据复制到当前绑定缓冲的函数 中间也能用sizeof (points) // 顶点属性 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); // 颜色属性 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3* sizeof(GLfloat))); glEnableVertexAttribArray(1); // UV属性 这个是增加的 glVertexAttribPointer(2, 2, GL_FLOAT,GL_FALSE, 8 * sizeof(GLfloat), (GLvoid * )(6*sizeof(GLfloat))); glEnableVertexAttribArray(2); glBindVertexArray(0); //----------------------------------------------------vao绑定 string a = loadFragmentShader("fragment.frag"); string b = loadFragmentShader("vertex_shader.vert"); fragment_shader = a.c_str(); vertex_shader = b.c_str(); GLint success;//是否错误 GLchar infoLog[512];//储存错误消息的容器 //动态编译glsl的源码 创建一个着色器对象,再次引用它的ID。所以我们储存这个顶点着色器为GLuint,然后用glCreateShader创建着色器 GLuint vs = glCreateShader (GL_VERTEX_SHADER);//把着色器的类型提供glCreateShader作为它的参数。这里我们传递的参数是GL_VERTEX_SHADER这样就创建了一个顶点着色器 glShaderSource (vs, 1, &vertex_shader, NULL);//把这个着色器源码附加到着色器对象,然后编译它 第二参数指定了源码中有多少个字符串,这里只有一个。第三个参数是顶点着色器真正的源码 glCompileShader (vs);//这步之后才能进行错误检测 //vs顶点着色器错误检测 glGetShaderiv(vs, GL_COMPILE_STATUS, &success);//用来检测错误 if(!success) { glGetShaderInfoLog(vs, 512, NULL, infoLog); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; } GLuint fs = glCreateShader (GL_FRAGMENT_SHADER);//使用GL_FRAGMENT_SHADER作为着色器类型 glShaderSource (fs, 1, &fragment_shader, NULL); glCompileShader (fs); //fs片段着色器错误检测 glGetShaderiv(fs, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(fs, 512, NULL, infoLog); std::cout << "ERROR::SHADER::FRANMENT::COMPILATION_FAILED\n" << infoLog << std::endl; } //着色器程序对象(shader program object)是多个着色器最后链接的版本。我们必须把它们链接为一个着色器程序对象,当渲染物体激活着色器程序。 //把着色器链接为一个程序就等于把每个着色器的输出链接到下一个着色器的输入。 shader_programme = glCreateProgram (); glAttachShader (shader_programme, fs); glAttachShader (shader_programme, vs); glLinkProgram (shader_programme); //着色器程序对象附加错误检测 glGetProgramiv(shader_programme, GL_LINK_STATUS, &success); if(!success) { glGetProgramInfoLog(shader_programme, 512, NULL, infoLog); std::cout << "last shader program object error \n" << infoLog << std::endl; } //最后删除着色器对象 glDeleteShader(vs); glDeleteShader(fs); //////////////////////////////生成绑定纹理 这里没有使用教程中的Simple OpenGL Image Library(简易OpenGL图像库)而是使用了of自带的freeimage库 ofImage image;//使用of自带的转换image.getPixels() 可以转换为const GLvoid*格式 image.loadImage("1.png");//放在data目录里 ofImage image2; image2.loadImage("2.jpg"); glGenTextures(1, &texture1); glBindTexture(GL_TEXTURE_2D, texture1); //纹理放置方式(Texture Wrapping) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); //纹理过滤(Texture Filtering) //中间项目 纹理过滤可已设置放大和缩小的选项,这样你可以在纹理被缩小的时候使用最临近过滤,被放大时使用线性过滤。我们必须通过glTexParameter*为放大和缩小指定过滤方式。 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //第一个参数指定纹理目标(环境);设置为GL_TEXTURE_2D意味着会生成与当前绑定的纹理对象在同一个目标(target)上的纹理(任何绑定到GL_TEXTURE_1D和GL_TEXTURE_3D的纹理不会受到影响)。 //第二个参数为我们打算创建的纹理指定mipmap层级,如果你希望为每个mimap层级单独手工设置的话。这里我们填0基本级。 //第三个参数告诉OpenGL,我们希望把纹理储存为何种格式。我们的图像只有RGB值,因此我们把纹理储存为RGB值。 //第四个和第五个参数设置最终的纹理的宽度和高度。我们加载图像的时候提前储存它们这样我们就能使用相应变量了。 //第六个参数应该一直被设为0(遗留问题)。 //第七第八个参数定义了源图的格式和数据类型。我们使用RGB值加载这个图像,并把它们储存在char(byte) //最后一个参数是真实的图像数据。 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.getPixels());//这里改成了RGBA 因为用的是透明png glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0);//生成了纹理和相应的mipmap后,解绑纹理对象、释放图像的内存很重要。 glGenTextures(2, &texture2); glBindTexture(GL_TEXTURE_2D, texture2); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image2.width, image2.height, 0, GL_RGB, GL_UNSIGNED_BYTE, image2.getPixels());//这里改成了RGB 因为用的是jpg glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 1); } //-------------------------------------------------------------- void ofApp::update(){ } #include <GLFW/glfw3.h>//glfwGetTime函数需要引入 //-------------------------------------------------------------- void ofApp::draw(){ glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glUseProgram (shader_programme); //激活多个纹理 glActiveTexture(GL_TEXTURE0); //在绑定纹理之前,先激活纹理单元 单纹理的时候可以忽略这个单元 glBindTexture(GL_TEXTURE_2D, texture1); glUniform1i(glGetUniformLocation(shader_programme, "ourTexture1"), 0);//单一纹理的时候可以忽略这个值 glActiveTexture(GL_TEXTURE1); //激活纹理单元2 glBindTexture(GL_TEXTURE_2D, texture2); glUniform1i(glGetUniformLocation(shader_programme, "ourTexture2"), 1); glBindVertexArray (vao); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0); } //-------------------------------------------------------------- void ofApp::keyPressed(int key){} void ofApp::keyReleased(int key){} void ofApp::mouseMoved(int x, int y ){} void ofApp::mouseDragged(int x, int y, int button){} void ofApp::mousePressed(int x, int y, int button){} void ofApp::mouseReleased(int x, int y, int button){} void ofApp::windowResized(int w, int h){} void ofApp::gotMessage(ofMessage msg){} void ofApp::dragEvent(ofDragInfo dragInfo){}
#version 330 core in vec3 ourColor; in vec2 TexCoord;//新增的纹理 out vec4 color; uniform sampler2D ourTexture1;//新增的纹理采样器 uniform sampler2D ourTexture2;//第二个纹理 void main() { vec2 texCoord = vec2(TexCoord.x,1 - TexCoord.y);//上下颠倒 //color = vec4(ourColor, 1.0f); color = texture(ourTexture1, TexCoord);//我们使用GLSL的内建texture函数来采样纹理的颜色,它第一个参数是纹理采样器,第二个参数是相应的纹理坐标 //简单混合 color = texture(ourTexture1, TexCoord) * vec4(ourColor, 1.0f); //图片混合 color = mix(texture(ourTexture1, texCoord), texture(ourTexture2, texCoord), 0.5); }
#version 330 core layout (location = 0) in vec3 position; // 位置变量的属性position为 0 layout (location = 1) in vec3 color; // 颜色变量的属性position为 1 layout (location = 2) in vec2 texCoord;//新增的纹理 out vec3 ourColor; // 向fragment shader输出一个颜色 out vec2 TexCoord;//新增的纹理 void main() { gl_Position = vec4(position, 1.0f); ourColor = color; // 把ourColor设置为我们从顶点数据那里得到的输入颜色 TexCoord = texCoord;//新增的纹理 }
因为后面教程上矩阵居然还是用的另一个库,一般刚入门的学习来也是麻烦