纹理,这次没用Shader头文件,但是没有报“超出内存”的错误,不知道为什么

  1 #include <iostream>
  2 using namespace std;
  3 //using std::cout;    using std::cin;    using std::endl;
  4 
  5 #define GLEW_STATIC
  6 #include <GL/glew.h>
  7 #include <GLFW/glfw3.h>
  8 
  9 //#define STB_IMAGE_STATIC
 10 //#define STR_IMAGE_IMPLEMENTATION
 11 #include "stb_image.h"
 12 
 13 //#include "stb_image.h"
 14 
 15 void framebuffer_size_callback(GLFWwindow* window, int width, int height);
 16 void processInput(GLFWwindow* window);
 17 
 18 //着色器源码
 19 //明确表示我们使用核心模式,使用in关键字,在顶点着色器中声明所有的输入顶点属性
 20 //由于每个顶点都有一个3D坐标,我们就创建一个vec3输入变量aPos;
 21 //用layout(location = 0)设定了输入变量的位置值
 22 const char *vertexShaderSource = "#version 330 core
"
 23 "layout (location = 0) in vec3 aPos;
"
 24 "layout (location = 1) in vec3 aColor;
"
 25 "layout (location = 2) in vec2 aTexCoord;
"
 26 
 27 "out vec3 ourColor;
"
 28 "out vec2 TexCoord;
"
 29 
 30 "void main()
"
 31 "{
"
 32 //aPos.w用在所谓的透视除法上
 33 //我们将gl_Postion设置的值会成为该顶点着色器的输出,由于我们的输入是一个3分量的向量,我们必须把它转换成4分量的
 34 "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
"
 35 "    ourColor = aColor;
"
 36 "    TexCoord = aTexCoord
;"
 37 "}
";
 38 
 39 //片段着色器源码
 40 const char* fragmentShaderSource = "#version 330 core
"
 41 "out vec4 FragColor;
"
 42 "in vec3 ourColor;
"
 43 "in vec2 TexCoord;
"
 44 
 45 //"uniform sampler2D ourTexture;
"    //采样器
 46 "uniform sampler2D texture1;
"
 47 "uniform sampler2D texture2;
"
 48 "void main()
"
 49 "{
"
 50 //最终输出的颜色是两个纹理的结合
 51 //"   FragColor = texture(ourTexture, TexCoord);
"
 52 "     FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.7);
"
 53 "}
";
 54 
 55 
 56 int main()
 57 {
 58     glfwInit();    //初始化glfw                        
 59     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);    //配置glfw,主版本号
 60     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);    //次版本号
 61     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);    //核心模式
 62     GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpengl", NULL, NULL);    //创建glfw窗口
 63     if (window == NULL)
 64     {
 65         cout << "Fail to create window!
" << endl;
 66         glfwTerminate();
 67         return -1;
 68     }
 69 
 70     //设置当前窗口的上下文
 71     glfwMakeContextCurrent(window);            //context环境、上下文
 72 
 73     glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);        //每次改变窗口大小时都调用这个函数
 74 
 75     glewExperimental = GL_TRUE;        //使得glew在管理opengl函数指针时更多使用现代化技术
 76 
 77     if (glewInit() != GLEW_OK)
 78     {
 79         cout << "Fail to initialize GLEW" << endl;
 80         return -1;
 81     }
 82 
 83     //顶点着色器对象
 84     unsigned int vertexShader;    //用id来引导创建一个着色器对象
 85     vertexShader = glCreateShader(GL_VERTEX_SHADER);    //我们把需要创建的的着色器类型以参数形式提供给glCreateShader
 86 
 87                                                         //把这个着色器源码附加到着色器对象上
 88                                                         //glShaderSource函数吧需要编译的着色器对象作为第一个参数,第二个参数指定了传递的源码字符串数量,这里只有一个
 89                                                         //第三个参数是顶点着色器真正的源码,第四个参数我们先设置为NULL
 90     glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
 91 
 92     //编译这个着色器源码
 93     glCompileShader(vertexShader);
 94 
 95     int success;        //定义一个整型变量来表示是否成功编译
 96     char infoLog[512];    //定义一个储存错误消息的容器
 97                         //用glGetShaderiv检查是否编译成功
 98     glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
 99 
100 
101     if (!success)    //如果编译失败,用glGetShaderInfoLog获取错误消息,然后打印它
102     {
103         glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
104         cout << "ERROR R::SHADER::VERTEX::COMPILATION_FAILED
" << infoLog << endl;
105     }
106 
107     //片段着色器对象
108     unsigned int fragmentShader;        //定义一个片段着色器对象
109     fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);    //给对象赋予GL_FRAGMENT_SHADER类型
110     glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);    //将片段着色器的源码绑定到对象上
111     glCompileShader(fragmentShader);        //编译该对象
112     glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);        //检查是否编译成功
113 
114     if (!success)
115     {
116         glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);            //若不成功,获取错误信息,存入infoLog
117         cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED
" << infoLog << endl;
118     }
119 
120     //着色器对象
121     unsigned int shaderProgram;        //定义一个用来链接的着色器程序中
122     shaderProgram = glCreateProgram();    //给对象赋一个实体
123 
124     glAttachShader(shaderProgram, vertexShader);    //将Vertex附加到程序对象上
125     glAttachShader(shaderProgram, fragmentShader);    //将fragment着色器附加到程序对象上
126     glLinkProgram(shaderProgram);        //用glLinkProgram来连接他们
127 
128     glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);    //检查是否链接成功
129     if (!success)
130     {
131         glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);    //若不成功,获取错误信息,存入infoLog
132         cout << "ERROR::PROGRAM::SHADER::LINK_FAILED
" << infoLog << endl;
133     }
134 
135     glDeleteShader(vertexShader);    //删除顶点着色器对象,我们不再需要他了
136     glDeleteShader(fragmentShader);        //删除片段着色器对象,我们也不再需要他了
137 
138 
139     GLfloat vertices[] = {            //输入3个顶点坐标
140         0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
141         0.5f, -0.5f, 0.0f,0.0f, 1.0f, 0.0f, 1.0f, 0.0f,        //位置,颜色,纹理坐标
142         -0.5f, -0.5f, 0.0f,0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
143         -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f
144         
145     };
146 
147     
148     unsigned int indices[] = {    //主义索引从0开始
149         0, 1, 3,    //第一个三角形
150         1, 2, 3        //第二个三角形
151     };
152 
153     unsigned int VBO, VAO, EBO;        //定义一个顶点缓冲变量
154     glGenVertexArrays(1, &VAO);        //创建一个VAO对象
155     glGenBuffers(1, &VBO);    //利用该函数和一个缓冲id生成一个VBO对象
156     glGenBuffers(1, &EBO);    //创建一个EBO对象
157 
158     glBindVertexArray(VAO);    //绑定VAO
159     glBindBuffer(GL_ARRAY_BUFFER, VBO);    //顶点缓冲对象的缓冲类型为GL_ARRAY_BUFFER, 把新创建的缓冲绑定到GL_ARRAY_BUFFER上
160     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);    //索引缓冲对象的缓冲类型为GL_ELEMENT_ARRAY_BUFFER, 把新创建的缓冲绑定到GL_ELEMENT_ARRAY_BUFFER上
161 
162     //glBufferData是一个专门用来把用户定义的数据复制到当前绑定缓冲的的函数
163     //它的第一个参数是目标缓冲类型,顶点缓冲对象当前绑定到GL_ARRAY_BUFFER上
164     //第二个参数指定传输数据的大小,用sizeof函数计算
165     //第三个参数是我们希望发送的实际数据
166     //第四个参数指定了我们希望显卡如何管理给定的数据:GL_STATIC_DRAW / GL_DYNAMIC_DRAW / GL_STREAM_DRAW
167     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
168     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//将EBO对象复制到缓冲区
169 
170     //链接顶点属性
171     //第一个参数表示顶点位置其实位置值,第二个表示每个顶点的维度,第三个参数表示每个数据的数据类型
172     //第四个参数表示是否希望数据被成标准化,如果是GL_TRUE的话,有符号被映射到(-1, 1),无符号映射到(0, 1)
173     //第五个参数表示一个顶点(所有维度相加)的数据大小,也称为连续顶点属性组之间的间隔,步长
174     //第6个参数表示位置数据在缓冲中起始位置的偏移量(offset),由于位置数据再数组的开头,所以这里是0
175     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);//顶点位置属性
176     glEnableVertexAttribArray(0);        //启用顶点位置属性,顶点属性默认是禁用的
177 
178 
179     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));//顶点颜色属性
180     glEnableVertexAttribArray(1);    //启用顶点颜色属性
181 
182     glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));    //纹理属性
183     glEnableVertexAttribArray(2);    //启用纹理属性
184 
185     unsigned int texture1, texture2;
186 
187     //创建一个纹理对象,第一个参数是生成纹理的数量,然后把它们存储在第二个参数的unsigned in数组中(我们的例子只是一个单独的unsigned int)
188     glGenTextures(1, &texture1);
189     //glGenTextures(1, &texture2);
190 
191     //glActiveTexture(GL_TEXTURE0);    //在绑定纹理之前先激活纹理单元
192     glBindTexture(GL_TEXTURE_2D, texture1); //绑定该纹理对象,让之后任何的纹理指令都可以配置当前绑定的纹理
193     //glActiveTexture(GL_TEXTURE1);
194     //glBindTexture(GL_TEXTURE_2D, texture2);
195 
196 
197     //为当前绑定的纹理对象设置环绕方式
198     //
199     //纹理图像环绕设置
200     //第一个参数为纹理目标,我们使用的是2D纹理,所以纹理目标为GL_TEXTURE_2D
201     //第二个参数需要我们指定设置的选项和应用的纹理轴,这里我们是WRAP选项,S 和T轴
202     //最后一个参数需要我们传递一个环绕方式
203     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
204     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
205 
206     ////如果我们选择GL_CLAMP_TO_BOREDER选项,我们还需要指定一个边缘颜色
207     //float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
208     //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
209 
210 
211     //为当前绑定的纹理对象设置过滤方式
212     //缩小时用临近过滤,放大时用线性过滤
213     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
214     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
215 
216     ////多级渐远纹理过滤
217     //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//在两个临近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样
218     //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
219 
220     int width, height, nrChannels;
221 
222     stbi_set_flip_vertically_on_load(true);
223     //用stbi_load函数加载图片,加载并生成纹理
224     unsigned char *data = stbi_load("timg.jpg", &width, &height, &nrChannels, 0);
225 
226     if (data)
227     {
228         //用glTexImage函数来生成纹理,调用之后,当前绑定的纹理对象就会被附加上纹理图像
229         //第一个参数指定了纹理目标,设置为GL_TEXTURE_2D意味着会生成与当前绑定的纹理对象在同一个目标上的纹理
230         //第二个参数为纹理指定多级渐远纹理的级别,0就是基本级别
231         //第三个参数告诉OpenGL我们希望吧纹理存储为何种格式,我们的图像只有RGB值,因此我们也把纹理存储为RGB值
232         //第四个和第五个参数设置最终纹理的宽度和高度
233         //下个参数应该总是被设为0
234         //第七和第八参数定义了源图的格式和数据类型,我们使用RGB值加载这个图像,并把他们存储为char(byte)数组,我们将会传入对应值
235         //最后一个参数是真正的图像数据
236         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
237         glGenerateMipmap(GL_TEXTURE_2D);
238 
239         //然而,目前只有基本级别(base-level)的纹理图像被加载了,如果要使用多级渐远纹理,我们必须手动设置所有不同的图像(不断递增
240         //第二个参数),或者,直接在生成纹理之后调用glGenerateMipmap,这会为当前绑定的纹理自动生成所有需要的多级渐远纹理
241     }
242     else
243     {
244         cout << "Failed to load texture1
" << endl;
245     }
246 
247     //生成了纹理和相应的多级渐远纹理后,释放图像的内存是一个很好的习惯
248     stbi_image_free(data);
249 
250     glGenTextures(1, &texture2);
251     glBindTexture(GL_TEXTURE_2D, texture2);
252     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
253     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
254     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
255     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
256 
257     data = stbi_load("wall.jpg", &width, &height, &nrChannels, 0);
258     if (data)
259     {
260         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
261         glGenerateMipmap(GL_TEXTURE_2D);
262     }
263     else
264     {
265         cout << "Failed to load texture2!" << endl;
266     }
267 
268     stbi_image_free(data);
269 
270     glUseProgram(shaderProgram);
271     glUniform1i(glGetUniformLocation(shaderProgram, "texture1"), 0);
272     glUniform1i(glGetUniformLocation(shaderProgram, "texture2"), 1);
273 
274 
275 
276     glBindBuffer(GL_ARRAY_BUFFER, 0);
277 
278     glBindVertexArray(0);
279 
280 
281     while (!glfwWindowShouldClose(window))
282     {
283         processInput(window);
284 
285         //render
286         glClearColor(0.2f, 0.4f, 0.5f, 1.0f);
287         glClear(GL_COLOR_BUFFER_BIT);
288 
289         glActiveTexture(GL_TEXTURE0);
290         glBindTexture(GL_TEXTURE_2D, texture1);
291         glActiveTexture(GL_TEXTURE1);
292         glBindTexture(GL_TEXTURE_2D, texture2);
293 
294         //glBindTexture(GL_TEXTURE_2D, texture);
295         //画第一个三角形
296         glUseProgram(shaderProgram);        //激活这个程序对象
297 
298 
299         glBindVertexArray(VAO);
300 
301         //glDrawArrays函数第一个参数是我们打算绘制Opengl图元的类型,这里是三角形GL_TRIANGLES
302         //第二个参数制定了顶点数组的起始索引,这里填0
303         //第三个参数指定我们打算绘制多少个顶点
304         //lDrawArrays(GL_TRIANGLES, 0, 3);    //
305 
306 
307         //绘制这个矩形
308         //glDrawElements第一个参数指定了我们绘制的图元模式
309         //第二个参数是需绘制的顶点个数
310         //第三个参数是索引类型,这里是GL_UNSIGNED_INT
311         //最后一个参数是我们指定EBO中的偏移量(或者传递一个索引数组)
312         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);    
313 
314         glfwSwapBuffers(window);    //交换颜色缓冲,用来绘制,显示在屏幕上
315         glfwPollEvents();        //检查是否触发事件、更新窗口状态
316     }
317 
318     glDeleteVertexArrays(1, &VAO);        //释放顶点数组对象
319     glDeleteBuffers(1, &VBO);            //释放顶点缓冲对象
320     glDeleteBuffers(1, &EBO);
321 
322     glfwTerminate();    //释放之前分配的资源
323 
324     return 0;
325 }
326 
327 void framebuffer_size_callback(GLFWwindow* window, int width, int height)
328 {
329     glViewport(0, 0, width, height);
330 }
331 
332 void processInput(GLFWwindow* window)
333 {
334     if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
335         glfwSetWindowShouldClose(window, true);
336 }
原文地址:https://www.cnblogs.com/hi3254014978/p/9575385.html