纹理,这次没用Shader头文件,但是没有报“超出内存”的错误,不知道为什么
#include <iostream>
using namespace std;
//using std::cout; using std::cin; using std::endl; #define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h> //#define STB_IMAGE_STATIC
//#define STR_IMAGE_IMPLEMENTATION
#include "stb_image.h" //#include "stb_image.h" void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window); //着色器源码
//明确表示我们使用核心模式,使用in关键字,在顶点着色器中声明所有的输入顶点属性
//由于每个顶点都有一个3D坐标,我们就创建一个vec3输入变量aPos;
//用layout(location = 0)设定了输入变量的位置值
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;\n"
"layout (location = 2) in vec2 aTexCoord;\n" "out vec3 ourColor;\n"
"out vec2 TexCoord;\n" "void main()\n"
"{\n"
//aPos.w用在所谓的透视除法上
//我们将gl_Postion设置的值会成为该顶点着色器的输出,由于我们的输入是一个3分量的向量,我们必须把它转换成4分量的
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
" ourColor = aColor;\n"
" TexCoord = aTexCoord\n;"
"}\n\0"; //片段着色器源码
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"in vec2 TexCoord;\n" //"uniform sampler2D ourTexture;\n" //采样器
"uniform sampler2D texture1;\n"
"uniform sampler2D texture2;\n"
"void main()\n"
"{\n"
//最终输出的颜色是两个纹理的结合
//" FragColor = texture(ourTexture, TexCoord);\n"
" FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.7);\n"
"}\n\0"; int main()
{
glfwInit(); //初始化glfw
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, ); //配置glfw,主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, ); //次版本号
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //核心模式
GLFWwindow* window = glfwCreateWindow(, , "LearnOpengl", NULL, NULL); //创建glfw窗口
if (window == NULL)
{
cout << "Fail to create window!\n" << endl;
glfwTerminate();
return -;
} //设置当前窗口的上下文
glfwMakeContextCurrent(window); //context环境、上下文 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); //每次改变窗口大小时都调用这个函数 glewExperimental = GL_TRUE; //使得glew在管理opengl函数指针时更多使用现代化技术 if (glewInit() != GLEW_OK)
{
cout << "Fail to initialize GLEW" << endl;
return -;
} //顶点着色器对象
unsigned int vertexShader; //用id来引导创建一个着色器对象
vertexShader = glCreateShader(GL_VERTEX_SHADER); //我们把需要创建的的着色器类型以参数形式提供给glCreateShader //把这个着色器源码附加到着色器对象上
//glShaderSource函数吧需要编译的着色器对象作为第一个参数,第二个参数指定了传递的源码字符串数量,这里只有一个
//第三个参数是顶点着色器真正的源码,第四个参数我们先设置为NULL
glShaderSource(vertexShader, , &vertexShaderSource, NULL); //编译这个着色器源码
glCompileShader(vertexShader); int success; //定义一个整型变量来表示是否成功编译
char infoLog[]; //定义一个储存错误消息的容器
//用glGetShaderiv检查是否编译成功
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success) //如果编译失败,用glGetShaderInfoLog获取错误消息,然后打印它
{
glGetShaderInfoLog(vertexShader, , NULL, infoLog);
cout << "ERROR R::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl;
} //片段着色器对象
unsigned int fragmentShader; //定义一个片段着色器对象
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); //给对象赋予GL_FRAGMENT_SHADER类型
glShaderSource(fragmentShader, , &fragmentShaderSource, NULL); //将片段着色器的源码绑定到对象上
glCompileShader(fragmentShader); //编译该对象
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); //检查是否编译成功 if (!success)
{
glGetShaderInfoLog(fragmentShader, , NULL, infoLog); //若不成功,获取错误信息,存入infoLog
cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl;
} //着色器对象
unsigned int shaderProgram; //定义一个用来链接的着色器程序中
shaderProgram = glCreateProgram(); //给对象赋一个实体 glAttachShader(shaderProgram, vertexShader); //将Vertex附加到程序对象上
glAttachShader(shaderProgram, fragmentShader); //将fragment着色器附加到程序对象上
glLinkProgram(shaderProgram); //用glLinkProgram来连接他们 glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); //检查是否链接成功
if (!success)
{
glGetProgramInfoLog(shaderProgram, , NULL, infoLog); //若不成功,获取错误信息,存入infoLog
cout << "ERROR::PROGRAM::SHADER::LINK_FAILED\n" << infoLog << endl;
} glDeleteShader(vertexShader); //删除顶点着色器对象,我们不再需要他了
glDeleteShader(fragmentShader); //删除片段着色器对象,我们也不再需要他了 GLfloat vertices[] = { //输入3个顶点坐标
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f,0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //位置,颜色,纹理坐标
-0.5f, -0.5f, 0.0f,0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f }; unsigned int indices[] = { //主义索引从0开始
, , , //第一个三角形
, , //第二个三角形
}; unsigned int VBO, VAO, EBO; //定义一个顶点缓冲变量
glGenVertexArrays(, &VAO); //创建一个VAO对象
glGenBuffers(, &VBO); //利用该函数和一个缓冲id生成一个VBO对象
glGenBuffers(, &EBO); //创建一个EBO对象 glBindVertexArray(VAO); //绑定VAO
glBindBuffer(GL_ARRAY_BUFFER, VBO); //顶点缓冲对象的缓冲类型为GL_ARRAY_BUFFER, 把新创建的缓冲绑定到GL_ARRAY_BUFFER上
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); //索引缓冲对象的缓冲类型为GL_ELEMENT_ARRAY_BUFFER, 把新创建的缓冲绑定到GL_ELEMENT_ARRAY_BUFFER上 //glBufferData是一个专门用来把用户定义的数据复制到当前绑定缓冲的的函数
//它的第一个参数是目标缓冲类型,顶点缓冲对象当前绑定到GL_ARRAY_BUFFER上
//第二个参数指定传输数据的大小,用sizeof函数计算
//第三个参数是我们希望发送的实际数据
//第四个参数指定了我们希望显卡如何管理给定的数据:GL_STATIC_DRAW / GL_DYNAMIC_DRAW / GL_STREAM_DRAW
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//将EBO对象复制到缓冲区 //链接顶点属性
//第一个参数表示顶点位置其实位置值,第二个表示每个顶点的维度,第三个参数表示每个数据的数据类型
//第四个参数表示是否希望数据被成标准化,如果是GL_TRUE的话,有符号被映射到(-1, 1),无符号映射到(0, 1)
//第五个参数表示一个顶点(所有维度相加)的数据大小,也称为连续顶点属性组之间的间隔,步长
//第6个参数表示位置数据在缓冲中起始位置的偏移量(offset),由于位置数据再数组的开头,所以这里是0
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*));//顶点位置属性
glEnableVertexAttribArray(); //启用顶点位置属性,顶点属性默认是禁用的 glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*)( * sizeof(float)));//顶点颜色属性
glEnableVertexAttribArray(); //启用顶点颜色属性 glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*)( * sizeof(float))); //纹理属性
glEnableVertexAttribArray(); //启用纹理属性 unsigned int texture1, texture2; //创建一个纹理对象,第一个参数是生成纹理的数量,然后把它们存储在第二个参数的unsigned in数组中(我们的例子只是一个单独的unsigned int)
glGenTextures(, &texture1);
//glGenTextures(1, &texture2); //glActiveTexture(GL_TEXTURE0); //在绑定纹理之前先激活纹理单元
glBindTexture(GL_TEXTURE_2D, texture1); //绑定该纹理对象,让之后任何的纹理指令都可以配置当前绑定的纹理
//glActiveTexture(GL_TEXTURE1);
//glBindTexture(GL_TEXTURE_2D, texture2); //为当前绑定的纹理对象设置环绕方式
//
//纹理图像环绕设置
//第一个参数为纹理目标,我们使用的是2D纹理,所以纹理目标为GL_TEXTURE_2D
//第二个参数需要我们指定设置的选项和应用的纹理轴,这里我们是WRAP选项,S 和T轴
//最后一个参数需要我们传递一个环绕方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); ////如果我们选择GL_CLAMP_TO_BOREDER选项,我们还需要指定一个边缘颜色
//float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
//glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); //为当前绑定的纹理对象设置过滤方式
//缩小时用临近过滤,放大时用线性过滤
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ////多级渐远纹理过滤
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//在两个临近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); int width, height, nrChannels; stbi_set_flip_vertically_on_load(true);
//用stbi_load函数加载图片,加载并生成纹理
unsigned char *data = stbi_load("timg.jpg", &width, &height, &nrChannels, ); if (data)
{
//用glTexImage函数来生成纹理,调用之后,当前绑定的纹理对象就会被附加上纹理图像
//第一个参数指定了纹理目标,设置为GL_TEXTURE_2D意味着会生成与当前绑定的纹理对象在同一个目标上的纹理
//第二个参数为纹理指定多级渐远纹理的级别,0就是基本级别
//第三个参数告诉OpenGL我们希望吧纹理存储为何种格式,我们的图像只有RGB值,因此我们也把纹理存储为RGB值
//第四个和第五个参数设置最终纹理的宽度和高度
//下个参数应该总是被设为0
//第七和第八参数定义了源图的格式和数据类型,我们使用RGB值加载这个图像,并把他们存储为char(byte)数组,我们将会传入对应值
//最后一个参数是真正的图像数据
glTexImage2D(GL_TEXTURE_2D, , GL_RGB, width, height, , GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D); //然而,目前只有基本级别(base-level)的纹理图像被加载了,如果要使用多级渐远纹理,我们必须手动设置所有不同的图像(不断递增
//第二个参数),或者,直接在生成纹理之后调用glGenerateMipmap,这会为当前绑定的纹理自动生成所有需要的多级渐远纹理
}
else
{
cout << "Failed to load texture1\n" << endl;
} //生成了纹理和相应的多级渐远纹理后,释放图像的内存是一个很好的习惯
stbi_image_free(data); glGenTextures(, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
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); data = stbi_load("wall.jpg", &width, &height, &nrChannels, );
if (data)
{
glTexImage2D(GL_TEXTURE_2D, , GL_RGB, width, height, , GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
cout << "Failed to load texture2!" << endl;
} stbi_image_free(data); glUseProgram(shaderProgram);
glUniform1i(glGetUniformLocation(shaderProgram, "texture1"), );
glUniform1i(glGetUniformLocation(shaderProgram, "texture2"), ); glBindBuffer(GL_ARRAY_BUFFER, ); glBindVertexArray(); while (!glfwWindowShouldClose(window))
{
processInput(window); //render
glClearColor(0.2f, 0.4f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2); //glBindTexture(GL_TEXTURE_2D, texture);
//画第一个三角形
glUseProgram(shaderProgram); //激活这个程序对象 glBindVertexArray(VAO); //glDrawArrays函数第一个参数是我们打算绘制Opengl图元的类型,这里是三角形GL_TRIANGLES
//第二个参数制定了顶点数组的起始索引,这里填0
//第三个参数指定我们打算绘制多少个顶点
//lDrawArrays(GL_TRIANGLES, 0, 3); // //绘制这个矩形
//glDrawElements第一个参数指定了我们绘制的图元模式
//第二个参数是需绘制的顶点个数
//第三个参数是索引类型,这里是GL_UNSIGNED_INT
//最后一个参数是我们指定EBO中的偏移量(或者传递一个索引数组)
glDrawElements(GL_TRIANGLES, , GL_UNSIGNED_INT, ); glfwSwapBuffers(window); //交换颜色缓冲,用来绘制,显示在屏幕上
glfwPollEvents(); //检查是否触发事件、更新窗口状态
} glDeleteVertexArrays(, &VAO); //释放顶点数组对象
glDeleteBuffers(, &VBO); //释放顶点缓冲对象
glDeleteBuffers(, &EBO); glfwTerminate(); //释放之前分配的资源 return ;
} void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(, , width, height);
} void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
纹理,这次没用Shader头文件,但是没有报“超出内存”的错误,不知道为什么的更多相关文章
- 使用某些Widows API时,明明包含了该头文件,却报错“error C2065: undeclared identifier”
在使用一些新版本的API,或者控件的新特性(比如新版的ComCtl32.dll)的时候,你可能会得到“error C2065: undeclared identifier.“这个错误.原因是这些功能是 ...
- C语言头文件中定义全局变量导致重复定义错误
合作方升级SDK后,程序编译出现变量重复定义的错误,通过错误提示无法找到什么位置重复定义了,但确定是引入新SDK后才出现的错误,从SDK的头文件中查找,最终发现在头文件中定义了全局变量 我们的项目在多 ...
- 系统头文件cmath,cstdlib报错
>C:\Program Files (x86)\Microsoft Visual Studio\\Community\VC\Tools\MSVC\\include\cstdlib(): erro ...
- linux编译模块,包含了头文件却还是报undifind警告
在编写一个自己写的gadget驱动的时候遇到一个这样的问题,编译的时候报了个警告:WARNING: "usb_composite_register" [-/my_zero.ko] ...
- 转载: Javah生成JNI头文件出现找不到类的错误
错误: 找不到 'com.chnic.jni.SayHellotoCPP' 的类文件. 上图可以看到错误和解决办法. 不要忘记那个点 javah -classpath . -jni com.chnic ...
- 不小心改了Xcode系统的头文件,运行报错,解决办法
- c语言头文件的认识
c头文件的作用是什么,和.c文件是怎么联系的,该怎么样编写头文件呢?这些问题我一直没搞明白,在阅读uCOS-II(邵贝贝)“全局变量”部分有些疑惑,今天终于搞清楚了头文件的一些基础知识,特地分享一下. ...
- iOS开发中遇到的错误整理 - 集成第三方框架时,编译后XXX头文件找不到
iOS编译报错-XXX头文件找不到 错误出现的情况: 自己在继承第三方的SDK的时候,明明导入了头文件,但是系统报错,提示头文件找不到 解决方法 既然系统找不到,给他个具体路径,继续找去! 路径就填写 ...
- c语言头文件中定义全局变量的问题
c语言头文件中定义全局变量的问题 (转http://www.cnblogs.com/Sorean/) 先说一下,全局变量只能定义在 函数里面,任意函数,其他函数在使用的时候用extern声明.千万不要 ...
随机推荐
- Beta阶段冲刺---Day3
一.Daily Scrum Meeting照片 二.今天冲刺情况反馈 昨天已完成的工作: (1)数字以扑克牌的形式给出 (2)答案的乘除符号与游戏中的符号保持一致. 今天计划完成的工作 (1)闯关模式 ...
- python redis操作数据库方法
Redis redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorte ...
- python 爬虫数据时间转换格式
from datetime import datetimea = '2018/9/18 10/10'print(datetime.strptime(a,'%Y/%m/%d %H/%M'))>&g ...
- 在Ubuntu上搭建IntelliJ IDEA license server服务器
1.下载激活文件 2.ubuntu需要使用 IntelliJIDEALicenseServer_linux_amd64 ,把该文件传到服务器的某个目录,我是放在了/jideal 下 3.进入上面的目录 ...
- 3--Selenium环境准备--Eclipse 引入 selenium-server包
1.下载selenium-server包 selenium-server-standalone包是Seleniumd的核心jar包,其中包含了各种元素定位和调用浏览器的方法.下载jar包后,在ID ...
- Insert插入不同的列数量,统计信息对比
一.实验目的: Insert插入表中相同的行数量,不同的列数量,通过10046 和autotrace工具对比查看逻辑读.物理读.time数据,并得出相应结论 二.测试 2.1测试流程: =>[为 ...
- Anaconda canda 安装 Python3 配置
链接: 1.安装Python 3.5以及tensorflow 以前用virtualenv觉得挺好用了,但是用多python版本下安装tensorflow,出现问题: pip is configured ...
- Unity 3D委托entrust
Unity 3D委托的多种用法 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分 ...
- 关于Java堆、栈和常量池的详解
在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register). 这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部.但是寄存器的数量极其有限,所以寄存器由编译 ...
- 2017-2018-1 20155208 课堂测试(ch06)(补做)
2017-2018-1 20155208 课堂测试(ch06)(补做) 1.( 多选题 | 1 分) 下面说法正确的是(ABC) A . 存储层次结构中最小的缓存是寄存器 B . 存储层次结构的中心思 ...