#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头文件,但是没有报“超出内存”的错误,不知道为什么的更多相关文章

  1. 使用某些Widows API时,明明包含了该头文件,却报错“error C2065: undeclared identifier”

    在使用一些新版本的API,或者控件的新特性(比如新版的ComCtl32.dll)的时候,你可能会得到“error C2065: undeclared identifier.“这个错误.原因是这些功能是 ...

  2. C语言头文件中定义全局变量导致重复定义错误

    合作方升级SDK后,程序编译出现变量重复定义的错误,通过错误提示无法找到什么位置重复定义了,但确定是引入新SDK后才出现的错误,从SDK的头文件中查找,最终发现在头文件中定义了全局变量 我们的项目在多 ...

  3. 系统头文件cmath,cstdlib报错

    >C:\Program Files (x86)\Microsoft Visual Studio\\Community\VC\Tools\MSVC\\include\cstdlib(): erro ...

  4. linux编译模块,包含了头文件却还是报undifind警告

    在编写一个自己写的gadget驱动的时候遇到一个这样的问题,编译的时候报了个警告:WARNING: "usb_composite_register" [-/my_zero.ko] ...

  5. 转载: Javah生成JNI头文件出现找不到类的错误

    错误: 找不到 'com.chnic.jni.SayHellotoCPP' 的类文件. 上图可以看到错误和解决办法. 不要忘记那个点 javah -classpath . -jni com.chnic ...

  6. 不小心改了Xcode系统的头文件,运行报错,解决办法

  7. c语言头文件的认识

    c头文件的作用是什么,和.c文件是怎么联系的,该怎么样编写头文件呢?这些问题我一直没搞明白,在阅读uCOS-II(邵贝贝)“全局变量”部分有些疑惑,今天终于搞清楚了头文件的一些基础知识,特地分享一下. ...

  8. iOS开发中遇到的错误整理 - 集成第三方框架时,编译后XXX头文件找不到

    iOS编译报错-XXX头文件找不到 错误出现的情况: 自己在继承第三方的SDK的时候,明明导入了头文件,但是系统报错,提示头文件找不到 解决方法 既然系统找不到,给他个具体路径,继续找去! 路径就填写 ...

  9. c语言头文件中定义全局变量的问题

    c语言头文件中定义全局变量的问题 (转http://www.cnblogs.com/Sorean/) 先说一下,全局变量只能定义在 函数里面,任意函数,其他函数在使用的时候用extern声明.千万不要 ...

随机推荐

  1. 20165214 实验二 Java面向对象程序设计

    一.实验报告封面 课程:Java程序设计 班级:1652班 姓名:朱文远 学号:20165214 指导教师:娄嘉鹏 实验日期:2018年4月16日 实验时间:13:45 - 15:25 实验序号:二 ...

  2. ChinaCock界面控件介绍-CCNavigateTitle

    先看一下实际项目中的运行效果,如图,通过品牌的导航栏,显示不同品牌的商品列表. 完全基于ChinaCock控件包中CCNavigateTitle组件实现的,这是一个可视控件,从组件面板上拖放一个到Fo ...

  3. ubantu 设置默认python3.叽叽叽的环境变量

    wkp 发表于 2017-8-22 17:49:08 | 只看该作者 sudo vi ~/.bashrc 在里面加一句 alias python='python3' 或者再简单一点 alias p=' ...

  4. Day12作业及默写

    1.整理今天的博客,写课上代码,整理流程图. 2.用列表推导式做下列小题 li=['alex','wusir','abds','meet','ab'] a. 过滤掉长度小于3的字符串列表,并将剩下的转 ...

  5. web.config 冲突的解决办法 (主目录子目录分别帮定域名导至出现错误)

    IIS上在主站点下搭建虚拟目录后,子站点中的<system.web>节点与主站点的<system.web>冲突解决方法: 在主站点的<system.web>上一级添 ...

  6. css引入外部字体使网站字体更美观

    @font-face{font-family: myFont;src:url("../font/timesi.ttf");src:url("../font/timesbi ...

  7. 30行python让图灵机器人和茉莉机器人无止尽的瞎扯蛋

    首先注册申请图灵机器人的API: http://www.tuling123.com/ 查看一下API的格式,很简单: { "key": "APIKEY", &q ...

  8. think in java 读书笔记

    第三章 操作符 3.1 更简单的打印语句  原:System.out.println("打印"); 简单:print("我是更简单的");  =======需要 ...

  9. 【webdriver自动化】整理API框架(主要是关键字,具体例子在本地)

    1. 获取网页源码 pageSource = self.driver.page_source print pageSource.encode("gbk","ignore& ...

  10. 安卓 dex 通用脱壳技术研究(一)

    注:以下4篇博文中,部分图片引用自DexHunter作者zyqqyz在slide.pptx中的图片,版本归原作者所有: 0x01 背景介绍 安卓 APP 的保护一般分为下列几个方面: JAVA/C代码 ...