实验2——三角形的显示

JSP——通过表单main.jsp向triangle.jsp提交三角形三边的长度,triangle.jsp计算并显示三角形的面积 1.main.jsp文件代码 <%@page contentType="text/html;charset=utf-8"%> <html> <head>输入三角形的的三边长,求面积</head> <body> <form action="triangle.jsp" method=post> ... 阅读详情

复制粘贴运行

我只会复制和粘贴,哪里会这个?

可是,这个实验,单纯的CV也不是不行……

 release:

debug:

 在实验1里,release模式下是报错的。

在实验2里,两个模式 的环境,都按实验1的路径设置的,都正常了?

前面,刚把动态lib,静态lib给“为什么不设置DLL也能运行”勉强糊弄过去;

这里,又冒出来个debug和release都用一个lib还都正常?lib不是分debug和release吗?

实际和预期不符,还是个计算机方面的问题

所以,自己用cmake编译一个试试吧……

看看到底如何,虽然已经能跑了

cmake编译lib

照着指导书搞吧,这次不用预编译好的了,尝试自己编译一下

新版的没有32位的啊……

 终于在这里找到一样的版本了

但是不知道得下载多久…… 

下完了,18年的cmake没有VS2019……还报错

 因为这个?

(33条消息) cmake按要求配置好点configure后却一直报:cmake Error in Configuration process,project files maybe invalid_随心Lc的博客-优快云博客_cmake configure出错

直接换最新的64位cmake吧……

依旧不快

 下完了,这是正常的吗?

编译完了,但是,只有X64的?

 这里说可以直接新建一个X86

 照着搞了,报错,那就64位的吧……

实验指导书,为什么让32位的?不知道。

 lib还分位数?越搞越复杂。

用这个64位的,重配一下环境试试。

还是得x64对x64:

然后,实测,debug和release的lib,混用也正常……玄学。。

如何cmake出32位的项目?

设置这个吗?试试吧……

 win32了?

试验一下:

 重新生成:

 改为x64

 恢复正常

上次那个debug和release通用,是不是因为没有重新生成项目啊?

报错

cmake的总结 

算了吧,反正release也不常用。。

先这样吧,能跑就行。

至少下了一个cmake,然后知道了cmake如何生成32/64位的VS项目

多关注关注代码吧,VAO,VBO什么的。

感觉核心是OpenGL如何画图,这个GLFW充其量是个和窗口有关的外边的壳……

 GLFW初体验-阿里云开发者社区 (aliyun.com)

新陈代谢

上面那个阿里云的链接,里面配完环境,还找了个代码跑了一下

我也跑了一下,报错了

 为什么呢?

昨天下载的时候,好像确实选了一下core。。

这下是真真实实的感受到了什么叫新陈代谢了。

新版OpenGL就这么取代了旧版OpenGL

引用:

(33条消息) glfw+glad配置后glbegin未定义标识符错误_dook33的博客-优快云博客_未定义标识符gl

代码的解释

计算机图形学_中国大学MOOC(慕课) (icourse163.org)

直接CV,也不大行,还是尝试看一看具体内容吧

核心模式,直接抛弃了之前旧OpenGL的那个模式?VAO,VBO,着色器……

这个慕课,看样子是跳过固定管线,直接从现代的OpenGL开始了……

太强了。不是我这样的小白搞得来的。 能力有限,跟着混一混吧……看看热闹

这个现代流程和我脑子里那个古早的流程完全不是一回事

 OpenGL是个大的状态机,这个状态,又叫作上下文

GLAD是管理函数指针的。图形学+指针=劝退

 《现代》

我只会传统的。

 核心模式,要求用VAO

VAO,我只知道它一次传一大串数据到GPU

就听明白了这一句…… 

 VAO,VBO,是把数据发送到显卡GPU上的。之后,就是用shader,来处理这些数据

  

 

以后用着色器就可以了,所以这些用不到的就删除了 

 

跟着视频又看了一遍代码,加了点注释

/***
 * 例程  绘制三角形 (MAKE后运行时可删除ALL_BUILD,也可以将Task-triangle设为默认启动工程)
 * 步骤:
 * 1-初始化:   GLFW窗口,GLAD。
 * 2-数据处理: 给定顶点数据,生成并绑定VAO&VBO(准备在GPU中进行处理),设置顶点属性指针(本质上就是告诉OpenGL如何处理数据)。
 * 3-着色器:   给出顶点和片段着色器,然后链接为着色器程序,渲染时使用着色器程序。
 * 4-渲染:     清空缓冲,绑定纹理,使用着色器程序,绘制三角形,交换缓冲区检查触发事件后释放资源
 */

#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"

 // 三角形的顶点数据
const float triangle[] = {
    //     ---- 位置 ----    
         -0.5f, -0.5f, 0.0f,   // 左下
          0.5f, -0.5f, 0.0f,   // 右下
          0.0f,  0.5f, 0.0f    // 正上
};

// 屏幕宽,高
int screen_width = 1280;
int screen_height = 720;

int main() {
    // 第一部分,初始化GLFW和GLAD,分为4个步骤进行/////////////////////////////////////////////////////////
    
    // 初始化GLFW
    glfwInit();                                                     // 初始化GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);                  // OpenGL版本为3.3,主次版本号均设为3
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 使用核心模式(无需向后兼容性)
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // 如果使用的是Mac OS X系统,需加上这行
    glfwWindowHint(GLFW_RESIZABLE, false);						    // 不可改变窗口大小

    // 创建窗口(宽、高、窗口名称)
    auto window = glfwCreateWindow(screen_width, screen_height, "Triangle", nullptr, nullptr);
    if (window == nullptr) {                                        // 如果窗口创建失败,输出Failed to Create OpenGL Context
        std::cout << "Failed to Create OpenGL Context" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);                                 // 将窗口的上下文设置为当前线程的主上下文

    // 初始化GLAD,加载OpenGL函数指针地址的函数
    // 在调用任何OpenGL函数之前
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // 指定当前视口尺寸(前两个参数为左下角位置,后两个参数是渲染窗口宽、高)
    glViewport(0, 0, screen_width, screen_height);



    // 第二部分,数据处理,通过VAO,VBO,把顶点数据发送到显卡GPU上,并设置属性指针,告诉GPU如何解释这些数据/////////////////////////////////////////////////////////////
    
    // 生成并绑定VAO和VBO
    GLuint vertex_array_object; // == VAO   核心模式要求必须使用VAO
    glGenVertexArrays(1, &vertex_array_object);//先生成
    glBindVertexArray(vertex_array_object);//再绑定

    GLuint vertex_buffer_object; // == VBO
    glGenBuffers(1, &vertex_buffer_object);//先生成
    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object);//再绑定
    // 将顶点数据绑定至当前默认的缓冲中
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), triangle, GL_STATIC_DRAW);

    // 设置顶点属性指针——告知OpenGL,如何解释这些数据
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // 解绑VAO和VBO    为了代码更规范
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // 第三部分,着色器,用来处理GPU里的数据//////////////////////////////////////////////////////////////////////////
    
    // 顶点着色器和片段着色器源码【GLSL】
    const char* vertex_shader_source =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;\n"           // 位置变量的属性位置值为0
        "void main()\n"
        "{\n"
        "    gl_Position = vec4(aPos, 1.0);\n" //内建变量
        "}\n\0";
    const char* fragment_shader_source =
        "#version 330 core\n"
        "out vec4 FragColor;\n"                           // 输出的颜色向量
        "void main()\n"
        "{\n"
        "    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
        "}\n\0";

    // 生成并编译着色器
        // 顶点着色器
        int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
        glCompileShader(vertex_shader);
        int success;
        char info_log[512];
        // 检查着色器是否成功编译,如果编译失败,打印错误信息
        glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
        if (!success)
        {
            glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
            std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << info_log << std::endl;
        }
        // 片段着色器
        int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
        glCompileShader(fragment_shader);
        // 检查着色器是否成功编译,如果编译失败,打印错误信息
        glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
        if (!success)
        {
            glGetShaderInfoLog(fragment_shader, 512, NULL, info_log);
            std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << info_log << std::endl;
        }

    // 链接顶点和片段着色器至一个着色器程序
    int shader_program = glCreateProgram();
    glAttachShader(shader_program, vertex_shader);
    glAttachShader(shader_program, fragment_shader);
    glLinkProgram(shader_program);
    // 检查着色器是否成功链接,如果链接失败,打印错误信息
    glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shader_program, 512, NULL, info_log);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << info_log << std::endl;
    }

    // 删除着色器    需要的着色器程序已经拿到了,这个没用了,就删除了
    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);

    // 线框模式
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // 第4部分,渲染//////////////////////////////////////////////////////////////////////////

    // 渲染循环
    while (!glfwWindowShouldClose(window)) {

        // 清空颜色缓冲
        glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // 使用着色器程序  【之前链接好的那个】
        glUseProgram(shader_program);

        // 绘制三角形
        glBindVertexArray(vertex_array_object);                                    // 绑定VAO
        glDrawArrays(GL_TRIANGLES, 0, 3);                                          // 绘制三角形
        glBindVertexArray(0);                                                      // 解除绑定

        // 交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动等)
        glfwSwapBuffers(window);//双缓冲
        glfwPollEvents();
    }

    // 第五部分,善后工作

    // 删除VAO和VBO
    glDeleteVertexArrays(1, &vertex_array_object);
    glDeleteBuffers(1, &vertex_buffer_object);

    // 清理所有的资源并正确退出程序
    glfwTerminate();
    return 0;
}

 五个部分,绘制出了三角形

 挺清晰的,现代OpenGL

VAO和VBO的介绍

百度,启动

网页1

可以理解为VBO就是显存中的一个存储区域,可以保持大量的顶点属性信息。并且可以开辟很多个VBO,每个VBO在OpenGL中有它的唯一标识ID,这个ID对应着具体的VBO的显存地址,通过这个ID可以对特定的VBO内的数据进行存取操作。

【ID,显存地址,指针?有计算机内味儿了】

还有个图,这个图画的挺漂亮的,虽然看不懂。

只能看明白这里面有一堆指针。

引用:

(33条消息) openGL关于VAO和VBO和EBO的区分和理解_在路上的菜鸡的博客-优快云博客_vao vbo

网页2 

这个里面有代码的解释:

能看明白的一共是这么几句解释VBO的代码:

//声明一个int作为VBO对象的id
unsigned int VBO;
//生成一个Buffer对象,id为VBO
glGenBuffers(1, &VBO);
//将缓冲对象绑定到顶点缓冲对象,相当于指定了这个缓冲对象是啥类型的
glBindBuffer(GL_ARRAY_BUFFER, VBO); 
//传数据给VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//设置如何解释这些数据
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//开启顶点属性
glEnableVertexAttribArray(0);

具体解释如下:

VBO也就是一个OpenGL里的结构体,它用来存一些顶点数据方便一次性给GPU内存多发一点。

首先,按照惯例,先生成一个缓冲对象(注意这里还不是顶点缓冲对象哦),得到它的id:

unsigned int VBO;//声明一个int作为VBO对象的id
glGenBuffers(1, &VBO);//生成一个Buffer对象,id为VBO

这一步就是将缓冲对象绑定到顶点缓冲对象,相当于就是指定了这个缓冲对象是啥类型的

glBindBuffer(GL_ARRAY_BUFFER, VBO);  

id,,和上个链接好像呼应上了

现在,我们任何在GL_ARRAY_BUFFER上的缓冲调用都是对VBO这个对象起作用的。这里有点难理解吧?我再来举例子。

C语言总学过吧
我们声明一个变量是用 int a;
给他初始化后就能用 addOne(a)各种函数来调用了。

OpenGL里呢,没有那么方便,因为他的函数很多是直接调用“类型”的,就这样的:
addOne(int),你传一个a进去,不认得啊。
所以呢要首先bind(int,a)把a跟int这个类型绑定,告诉它现在int就是专指a了!然后addOne(int)这个函数呢,就知道是给a加一了。简单理解,这个例子里int就是GL_ARRAY_BUFFER,a就是VBO。

下一步,是这句:

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

把我们之前的那个一维数组,传给了GL_ARRAY_BUFFER对象,注意它已经被我们的VBO给绑定了哦,所以就传给了VBO对象。

这个函数的介绍如下:

  1. 它的第一个参数是目标缓冲的类型:顶点缓冲对象当前绑定到GL_ARRAY_BUFFER目标上。
  2. 第二个参数指定传输数据的大小(以字节为单位);用一个简单的sizeof计算出顶点数据大小就行。
  3. 第三个参数是我们希望发送的实际数据。
  4. 第四个参数指定了我们希望显卡如何管理给定的数据。它有三种形式:
  • GL_STATIC_DRAW :数据不会或几乎不会改变。
  • GL_DYNAMIC_DRAW:数据会被改变很多。
  • GL_STREAM_DRAW :数据每次绘制时都会改变。

说那么多,其实就一句话,把一个一维数组,给了一个结构体来存储。

然后:一个简简单单的一维数组,咋让顶点着色器知道这代表了三个顶点呢?用这两句:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

 第一行是告诉OpenGL如何解释数据,第二行是启用顶点属性。
简单来说就是一维数组是如何变成三维点的。注意这里一个点的信息只有位置坐标,之后还会有颜色、贴图等信息,这样就要修改一个单位的大小和单位之间的偏移量了。

引用自:

(33条消息) 是人都能懂,通俗解释VBO和VAO在OpenGL中的作用_kiss_the_rain86的博客-优快云博客_opengl vbo

网页3 

 这个里面有完整点的代码

VBO的B为Buffer之意,用来存储顶点数据;VAO的A为Array,但我认为理解为 Attribute(属性) 之意更好,意思是 Buffer(VBO)的属性。

即,我们用VBO来存储数据,而用VAO来告诉计算机这些数据分别有什么属性、起什么作用。

《自动》

 VAO如何解释数据?这么解释:

当数据来自同一数组时:

float buffer = {
   	//顶点坐标(3个一组)              //顶点颜色(3个一组)              //纹理坐标(2个一组)
    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
};


//把对VBO中数据的描述存到了一个VAO中
//在一些复杂的OpenGL程序中,VBO可能会有多个,但VAO只有一个

//vertex coord
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);

// texture coord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);

当数据来自不同的数组时: 

 

用一个VAO来解释多个VBO的操作流程就如下 

首先,绑定VAO,以告知OpenGL程序该使用这个VAO来对VBO做出解释。

然后,绑定第一个VBO,向这个VBO中写入数据,告知VAO该如何解释这个VBO的信息;
然后,解绑这个VBO。

然后,绑定第二个VBO,向这个VBO中写入数据,并在VAO中保存该如何解释这个VBO的信息;
然后,解绑这个VBO。
……
	unsigned int VBO[2], VAO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(2, VBO);

//=========================绑定VAO===============================
	glBindVertexArray(VAO); 
//===============================================================

//=======================绑定第一个VBO============================
	glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
//===============================================================
	 
	glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW); //向第一个VBO中写入数据

//================告知VAO该如何解释第一个VBO的信息=================
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
//===============================================================

//=======================解绑第一个VBO===========================
	glBindBuffer(GL_ARRAY_BUFFER, 0);
//===============================================================

//=======================绑定第二个VBO============================
	glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
//===============================================================

	glBufferData(GL_ARRAY_BUFFER, sizeof(texVertrices), texVertrices, GL_STATIC_DRAW);//向第二个VBO中写入数据

//================告知VAO该如何解释第二个VBO的信息=================
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(1);
//=============================================================

引用:

(33条消息) 【图像】【OpenGL】VAO和VBO的关系_西西敏的博客-优快云博客_vao vbo

网页4 

这个可能偏应用一点: 

一个enable函数的解释

引用:

(33条消息) OpenGL VAO VBO EBO(IBO)的绑定、解绑问题_csu_xiji的博客-优快云博客

看来,这个VAO+VBO里的VAO,和之前理解的用来加快传数据速度的VAO,好像不大一样。 

一个VAO,两个VBO,两个三角形

 实际运用吧这应该算是

初始

一开始,根据猜测,改写成了这样:

代码:

/***
 * 例程  绘制三角形 (MAKE后运行时可删除ALL_BUILD,也可以将Task-triangle设为默认启动工程)
 * 步骤:
 * 1-初始化:   GLFW窗口,GLAD。
 * 2-数据处理: 给定顶点数据,生成并绑定VAO&VBO(准备在GPU中进行处理),设置顶点属性指针(本质上就是告诉OpenGL如何处理数据)。
 * 3-着色器:   给出顶点和片段着色器,然后链接为着色器程序,渲染时使用着色器程序。
 * 4-渲染:     清空缓冲,绑定纹理,使用着色器程序,绘制三角形,交换缓冲区检查触发事件后释放资源
 */

#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"

 // 三角形的顶点数据
const float triangle[] = {
    //     ---- 位置 ----    
         -0.5f, -0.5f, 0.0f,   // 左下
          0.5f, -0.5f, 0.0f,   // 右下
          0.0f,  0.5f, 0.0f    // 正上
};

const float triangle2[] = {
    //     ---- 位置 ----    
         0.6f, -0.5f, 0.0f,   // 左下
          0.8f, -0.5f, 0.0f,   // 右下
          0.7f,  0.5f, 0.0f    // 正上
};

// 屏幕宽,高
int screen_width = 1280;
int screen_height = 720;

int main() {
    // 第一部分,初始化GLFW和GLAD,分为4个步骤进行/////////////////////////////////////////////////////////

    // 初始化GLFW
    glfwInit();                                                     // 初始化GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);                  // OpenGL版本为3.3,主次版本号均设为3
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 使用核心模式(无需向后兼容性)
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // 如果使用的是Mac OS X系统,需加上这行
    glfwWindowHint(GLFW_RESIZABLE, false);						    // 不可改变窗口大小

    // 创建窗口(宽、高、窗口名称)
    auto window = glfwCreateWindow(screen_width, screen_height, "Triangle", nullptr, nullptr);
    if (window == nullptr) {                                        // 如果窗口创建失败,输出Failed to Create OpenGL Context
        std::cout << "Failed to Create OpenGL Context" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);                                 // 将窗口的上下文设置为当前线程的主上下文

    // 初始化GLAD,加载OpenGL函数指针地址的函数
    // 在调用任何OpenGL函数之前
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // 指定当前视口尺寸(前两个参数为左下角位置,后两个参数是渲染窗口宽、高)
    glViewport(0, 0, screen_width, screen_height);



    // 第二部分,数据处理,通过VAO,VBO,把顶点数据发送到显卡GPU上,并设置属性指针,告诉GPU如何解释这些数据/////////////////////////////////////////////////////////////

    // 生成并绑定VAO和VBO
    GLuint vertex_array_object; // == VAO   核心模式要求必须使用VAO
    glGenVertexArrays(1, &vertex_array_object);//先生成
    glBindVertexArray(vertex_array_object);//再绑定

    GLuint vertex_buffer_object[2]; // == VBO
    glGenBuffers(2, &vertex_buffer_object[0]);//先生成

    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[0]);//再绑定
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), triangle, GL_STATIC_DRAW);    // 将顶点数据绑定至当前默认的缓冲中
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置顶点属性指针——告知OpenGL,如何解释这些数据
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[1]);//再绑定
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle2), triangle2, GL_STATIC_DRAW);    // 将顶点数据绑定至当前默认的缓冲中
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置顶点属性指针——告知OpenGL,如何解释这些数据
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // 解绑VAO和VBO    为了代码更规范
    glBindVertexArray(0);


    // 第三部分,着色器,用来处理GPU里的数据//////////////////////////////////////////////////////////////////////////

    // 顶点着色器和片段着色器源码【GLSL】
    const char* vertex_shader_source =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;\n"           // 位置变量的属性位置值为0
        "void main()\n"
        "{\n"
        "    gl_Position = vec4(aPos, 1.0);\n" //内建变量
        "}\n\0";
    const char* fragment_shader_source =
        "#version 330 core\n"
        "out vec4 FragColor;\n"                           // 输出的颜色向量
        "void main()\n"
        "{\n"
        "    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
        "}\n\0";

    // 生成并编译着色器
        // 顶点着色器
    int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
    glCompileShader(vertex_shader);
    int success;
    char info_log[512];
    // 检查着色器是否成功编译,如果编译失败,打印错误信息
    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << info_log << std::endl;
    }
    // 片段着色器
    int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
    glCompileShader(fragment_shader);
    // 检查着色器是否成功编译,如果编译失败,打印错误信息
    glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragment_shader, 512, NULL, info_log);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << info_log << std::endl;
    }

    // 链接顶点和片段着色器至一个着色器程序
    int shader_program = glCreateProgram();
    glAttachShader(shader_program, vertex_shader);
    glAttachShader(shader_program, fragment_shader);
    glLinkProgram(shader_program);
    // 检查着色器是否成功链接,如果链接失败,打印错误信息
    glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shader_program, 512, NULL, info_log);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << info_log << std::endl;
    }

    // 删除着色器    需要的着色器程序已经拿到了,这个没用了,就删除了
    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);

    // 线框模式
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // 第4部分,渲染//////////////////////////////////////////////////////////////////////////

    // 渲染循环
    while (!glfwWindowShouldClose(window)) {

        // 清空颜色缓冲
        glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // 使用着色器程序  【之前链接好的那个】
        glUseProgram(shader_program);

        // 绘制三角形
        glBindVertexArray(vertex_array_object);                                    // 绑定VAO


        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[0]);

        glDrawArrays(GL_TRIANGLES, 0, 3);                                          // 绘制三角形

        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[1]);

        glDrawArrays(GL_TRIANGLES, 0, 3);                                          // 绘制三角形


        glBindVertexArray(0);                                                      // 解除绑定

        // 交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动等)
        glfwSwapBuffers(window);//双缓冲
        glfwPollEvents();
    }

    // 第五部分,善后工作

    // 删除VAO和VBO
    glDeleteVertexArrays(1, &vertex_array_object);
    glDeleteBuffers(1, &vertex_buffer_object[0]);

    // 清理所有的资源并正确退出程序
    glfwTerminate();
    return 0;
}

 运行结果,明显不对……

不对就改嘛,实践——认识——再实践——。。。

小白,所以,百度,启动

修改1

《这个问题和我遇到的差不多》《也使用属性0》

想起了上面的某个图

又想起了代码里的某一行 

 好像能呼应上似的

引用:

渲染一个包含两个 VBO 的 VAO | (1r1g.com)

修改2

这个说是,渲染绘制之前,需要设置一下这个指针

引用:

你如何渲染多个VBO / IBO? - 码客 (oomake.com)

进行修改 

然后,就修改了 这两部分,死马当活马医而已,因为我是小白,只会百度

    // 第二部分,数据处理,通过VAO,VBO,把顶点数据发送到显卡GPU上,并设置属性指针,告诉GPU如何解释这些数据/////////////////////////////////////////////////////////////

    // 生成并绑定VAO和VBO
    GLuint vertex_array_object; // == VAO   核心模式要求必须使用VAO
    glGenVertexArrays(1, &vertex_array_object);//先生成
    glBindVertexArray(vertex_array_object);//再绑定

    GLuint vertex_buffer_object[2]; // == VBO
    glGenBuffers(2, &vertex_buffer_object[0]);//先生成

    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[0]);//再绑定
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), triangle, GL_STATIC_DRAW);    // 将顶点数据绑定至当前默认的缓冲中
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置顶点属性指针——告知OpenGL,如何解释这些数据
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[1]);//再绑定
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle2), triangle2, GL_STATIC_DRAW);    // 将顶点数据绑定至当前默认的缓冲中
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置顶点属性指针——告知OpenGL,如何解释这些数据
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // 解绑VAO和VBO    为了代码更规范
    glBindVertexArray(0);

    // 渲染循环
    while (!glfwWindowShouldClose(window)) {

        // 清空颜色缓冲
        glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        // 使用着色器程序  【之前链接好的那个】
        glUseProgram(shader_program);

        // 绘制三角形
        glBindVertexArray(vertex_array_object);                                    // 绑定VAO


        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[0]);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置指针位置,以便后续从此处读取数据进行渲染
        glDrawArrays(GL_TRIANGLES, 0, 3);                                          // 绘制三角形

        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[1]);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置指针位置,以便后续从此处读取数据进行渲染
        glDrawArrays(GL_TRIANGLES, 0, 3);                                          // 绘制三角形


        glBindVertexArray(0);                                                      // 解除绑定

        // 交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动等)
        glfwSwapBuffers(window);//双缓冲
        glfwPollEvents();
    }

修改后 

总的代码:

/***
 * 例程  绘制三角形 (MAKE后运行时可删除ALL_BUILD,也可以将Task-triangle设为默认启动工程)
 * 步骤:
 * 1-初始化:   GLFW窗口,GLAD。
 * 2-数据处理: 给定顶点数据,生成并绑定VAO&VBO(准备在GPU中进行处理),设置顶点属性指针(本质上就是告诉OpenGL如何处理数据)。
 * 3-着色器:   给出顶点和片段着色器,然后链接为着色器程序,渲染时使用着色器程序。
 * 4-渲染:     清空缓冲,绑定纹理,使用着色器程序,绘制三角形,交换缓冲区检查触发事件后释放资源
 */

#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"

 // 三角形的顶点数据
const float triangle[] = {
    //     ---- 位置 ----    
         -0.5f, -0.5f, 0.0f,   // 左下
          0.5f, -0.5f, 0.0f,   // 右下
          0.0f,  0.5f, 0.0f    // 正上
};

const float triangle2[] = {
    //     ---- 位置 ----    
         0.6f, -0.5f, 0.0f,   // 左下
          0.8f, -0.5f, 0.0f,   // 右下
          0.7f,  0.5f, 0.0f    // 正上
};

// 屏幕宽,高
int screen_width = 1280;
int screen_height = 720;

int main() {
    // 第一部分,初始化GLFW和GLAD,分为4个步骤进行/////////////////////////////////////////////////////////

    // 初始化GLFW
    glfwInit();                                                     // 初始化GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);                  // OpenGL版本为3.3,主次版本号均设为3
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 使用核心模式(无需向后兼容性)
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // 如果使用的是Mac OS X系统,需加上这行
    glfwWindowHint(GLFW_RESIZABLE, false);						    // 不可改变窗口大小

    // 创建窗口(宽、高、窗口名称)
    auto window = glfwCreateWindow(screen_width, screen_height, "Triangle", nullptr, nullptr);
    if (window == nullptr) {                                        // 如果窗口创建失败,输出Failed to Create OpenGL Context
        std::cout << "Failed to Create OpenGL Context" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);                                 // 将窗口的上下文设置为当前线程的主上下文

    // 初始化GLAD,加载OpenGL函数指针地址的函数
    // 在调用任何OpenGL函数之前
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // 指定当前视口尺寸(前两个参数为左下角位置,后两个参数是渲染窗口宽、高)
    glViewport(0, 0, screen_width, screen_height);



    // 第二部分,数据处理,通过VAO,VBO,把顶点数据发送到显卡GPU上,并设置属性指针,告诉GPU如何解释这些数据/////////////////////////////////////////////////////////////

    // 生成并绑定VAO和VBO
    GLuint vertex_array_object; // == VAO   核心模式要求必须使用VAO
    glGenVertexArrays(1, &vertex_array_object);//先生成
    glBindVertexArray(vertex_array_object);//再绑定

    GLuint vertex_buffer_object[2]; // == VBO
    glGenBuffers(2, &vertex_buffer_object[0]);//先生成

    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[0]);//再绑定
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), triangle, GL_STATIC_DRAW);    // 将顶点数据绑定至当前默认的缓冲中
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置顶点属性指针——告知OpenGL,如何解释这些数据
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[1]);//再绑定
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle2), triangle2, GL_STATIC_DRAW);    // 将顶点数据绑定至当前默认的缓冲中
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置顶点属性指针——告知OpenGL,如何解释这些数据
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // 解绑VAO和VBO    为了代码更规范
    glBindVertexArray(0);


    // 第三部分,着色器,用来处理GPU里的数据//////////////////////////////////////////////////////////////////////////

    // 顶点着色器和片段着色器源码【GLSL】
    const char* vertex_shader_source =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;\n"           // 位置变量的属性位置值为0
        "void main()\n"
        "{\n"
        "    gl_Position = vec4(aPos, 1.0);\n" //内建变量
        "}\n\0";
    const char* fragment_shader_source =
        "#version 330 core\n"
        "out vec4 FragColor;\n"                           // 输出的颜色向量
        "void main()\n"
        "{\n"
        "    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
        "}\n\0";

    // 生成并编译着色器
        // 顶点着色器
    int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
    glCompileShader(vertex_shader);
    int success;
    char info_log[512];
    // 检查着色器是否成功编译,如果编译失败,打印错误信息
    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << info_log << std::endl;
    }
    // 片段着色器
    int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
    glCompileShader(fragment_shader);
    // 检查着色器是否成功编译,如果编译失败,打印错误信息
    glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragment_shader, 512, NULL, info_log);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << info_log << std::endl;
    }

    // 链接顶点和片段着色器至一个着色器程序
    int shader_program = glCreateProgram();
    glAttachShader(shader_program, vertex_shader);
    glAttachShader(shader_program, fragment_shader);
    glLinkProgram(shader_program);
    // 检查着色器是否成功链接,如果链接失败,打印错误信息
    glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shader_program, 512, NULL, info_log);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << info_log << std::endl;
    }

    // 删除着色器    需要的着色器程序已经拿到了,这个没用了,就删除了
    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);

    // 线框模式
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // 第4部分,渲染//////////////////////////////////////////////////////////////////////////

    // 渲染循环
    while (!glfwWindowShouldClose(window)) {

        // 清空颜色缓冲
        glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        // 使用着色器程序  【之前链接好的那个】
        glUseProgram(shader_program);

        // 绘制三角形
        glBindVertexArray(vertex_array_object);                                    // 绑定VAO


        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[0]);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置指针位置,以便后续从此处读取数据进行渲染
        glDrawArrays(GL_TRIANGLES, 0, 3);                                          // 绘制三角形

        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[1]);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置指针位置,以便后续从此处读取数据进行渲染
        glDrawArrays(GL_TRIANGLES, 0, 3);                                          // 绘制三角形


        glBindVertexArray(0);                                                      // 解除绑定

        // 交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动等)
        glfwSwapBuffers(window);//双缓冲
        glfwPollEvents();
    }

    // 第五部分,善后工作

    // 删除VAO和VBO
    glDeleteVertexArrays(1, &vertex_array_object);
    glDeleteBuffers(1, &vertex_buffer_object[0]);

    // 清理所有的资源并正确退出程序
    glfwTerminate();
    return 0;
}

运行结果 

结果,符合预期

代码,是正经的写法吗?不知道……小白总是一问三不知,我就是小白,所以……先这样吧…… 

一点函数解释

名称

glBindBuffer- 绑定一个命名(ID)的缓冲区对象

C规范

void glBindBuffer(GLenum target,GLuint buffer);

参数

target

指定缓冲区对象绑定的目标。

 符号常量必须为GL_ARRAY_BUFFER或GL_ELEMENT_ARRAY_BUFFER。【只能二选一?】

buffer

指定缓冲区对象的名称(ID)。

描述

glBindBuffer允许您创建或使用命名缓冲区对象。 调用glBindBuffer,目标设置为GL_ARRAY_BUFFER或GL_ELEMENT_ARRAY_BUFFER,缓冲区设置为新缓冲区对象的名称,这样就将缓冲区对象名称绑定到目标了。 当缓冲区对象绑定到目标时,该目标的先前绑定将自动中断。

缓冲区对象名称是无符号整数。 0值保留,但每个缓冲区对象目标没有默认缓冲区对象。 相反,缓冲区设置为0可以有效地取消绑定先前绑定的任何缓冲区对象,并恢复该缓冲区对象目标的客户机内存使用情况。 缓冲区对象名称和相应的缓冲区对象内容对于当前GL渲染上下文的共享对象空间是本地的。

引用:

(31条消息) GLES2.0中文API-glBindBuffer_flycatdeng的博客-优快云博客_glbindbuffer

GLuint vbo;
glGenBuffers(1,&vbo);
GLuint vbo[3];
glGenBuffers(3,vbo);

glGenBuffers()函数仅仅是生成一个缓冲对象的名称,这个缓冲对象并不具备任何意义,它仅仅是个缓冲对象,还不是一个顶点数组缓冲,它类似于C语言中的一个指针变量【这个类比挺好的】,我们可以分配内存对象并且用它的名称来引用这个内存对象。OpenGL有很多缓冲对象类型,那么这个缓冲对象到底是什么类型,就要用到下面的glBindBuffer()函数了。

glBindBuffer(GL_ARRAY_BUFFER, VBO);  //VBO变成了一个顶点缓冲类型
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

第一个就是缓冲对象的类型,第二个参数就是要绑定的缓冲对象的名称,也就是我们在上一个函数里生成的名称,使用该函数将缓冲对象绑定到OpenGL上下文环境中以便使用。如果把target绑定到一个已经创建好的缓冲对象,那么这个缓冲对象将为当前target的激活对象;但是如果绑定的buffer值为0,那么OpenGL将不再对当前target使用任何缓存对象。

在OpenGL红宝书中给出了一个恰当的比喻:绑定对象的过程就像设置铁路的道岔开关,每一个缓冲类型中的各个对象就像不同的轨道一样,我们将开关设置为其中一个状态,那么之后的列车都会驶入这条轨道。

  • 我要把数据存入顶点缓冲区,但是顶点缓冲区可以有很多缓冲对象,我需要传入哪个呢,于是我就要提前绑定一个,之后,我只要向顶点缓冲区内传入数据,这个数据就会自动进入被绑定的那个对象里面。
  • 之后调用glBufferData()传输所需数据,其中第一个参数就是要制定缓冲类型,根据这个类型锁定当前唯一的目标缓冲。

引用:

(31条消息) glGenBuffers与glBindBuffer理解_莫之的博客-优快云博客_glgenbuffers

《渲染时》

glVertexAttribPointer_百度百科 (baidu.com)

 试了试,这么搞也能画出来图


    // 第二部分,数据处理,通过VAO,VBO,把顶点数据发送到显卡GPU上,并设置属性指针,告诉GPU如何解释这些数据/////////////////////////////////////////////////////////////

    // 生成并绑定VAO和VBO
    GLuint vertex_array_object; // == VAO   核心模式要求必须使用VAO
    glGenVertexArrays(1, &vertex_array_object);//先生成
    glBindVertexArray(vertex_array_object);//再绑定

    GLuint vertex_buffer_object[2]; // == VBO
    glGenBuffers(2, &vertex_buffer_object[0]);//先生成,相当于C里声明的指针

    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[0]);//再绑定, 相当于声明指针指向的变量类型,同时设置一下状态机的状态(火车轨道变轨,变完了后面的车都得按变了的轨道走)
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), triangle, GL_STATIC_DRAW);    // 将顶点数据绑定至当前默认的缓冲中
    //glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置顶点属性指针——告知OpenGL,如何解释这些数据
    //glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[1]);//再绑定
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle2), triangle2, GL_STATIC_DRAW);    // 将顶点数据绑定至当前默认的缓冲中
    //glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置顶点属性指针——告知OpenGL,如何解释这些数据
    //glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // 解绑VAO和VBO    为了代码更规范
    glBindVertexArray(0);

    // 渲染循环
    while (!glfwWindowShouldClose(window)) {

        // 清空颜色缓冲
        glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        // 使用着色器程序  【之前链接好的那个】
        glUseProgram(shader_program);

        // 绘制三角形
        glBindVertexArray(vertex_array_object);                                    // 绑定VAO

        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[0]);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 【渲染时】设置指针位置,以便后续从此处读取数据进行渲染
        glDrawArrays(GL_TRIANGLES, 0, 3);                                          // 绘制三角形

        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object[1]);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);    // 设置指针位置,以便后续从此处读取数据进行渲染
        glDrawArrays(GL_TRIANGLES, 0, 3);                                          // 绘制三角形


        glBindVertexArray(0);                                                      // 解除绑定

        // 交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动等)
        glfwSwapBuffers(window);//双缓冲
        glfwPollEvents();
    }

 

 

后记 

状态机 ,铁路岔道开关,所以最早的时候,只渲染不设指针的时候,指针还停留在向VBO里传数据时设置的地址,所以只画出了一个。

能自圆其说,对不对?不知道。小白一个,要求不能太高。

红宝书……好像是个字典。

【OpenGL手册】GLFW窗口指南 ​ 指南介绍GLFW的窗口相关功能。有关此类别中特定功能的详细信息,请参阅窗口参考。还有 GLFW 其他领域的指南。 阅读详情

相关推荐

第6章 - 多无人车系统的协同控制 --> 实验验证

多无人车系统的协同控制 --> 实验验证

赵继超的笔记 1859

g linux 未定义的引用_未定义的引用在Ubuntu上编译OpenGL / glfw / glew(g)

参见英文答案 >What is an undefined reference/unresolved external symbol error and how do I fix it?29个我正在关注this tutorial.我发现并制作/ make install’d glfw和glew完美(据我所知).但是,当我尝...

weixin_42297904的博客 763

Docker部署OnlyOffice踩坑实录:解决editor.bin下载失败的3种姿势

本文详细解析了Docker部署OnlyOffice时editor.bin下载失败的常见原因,并提供了三种核心解决方案。重点剖析了容器网络配置、Nginx反向代理(特别是proxy_pass设置)以及安全策略调整,帮助开发者彻底解决静态资源加载问题,确保文档协作平台稳定运行。

weixin_29281941的博客 872

OpenGL创建窗口

OpenGL常用的头文件 #include <glad/glad.h> #include <GLFW/glfw3.h> int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_

狗蛋的博客 1249

rk3568 RGMII KSZ8795 MAC TO MAC

参考《Rockchip_Developer_Guide_Linux_MAC_TO_MAC_CN.pdf》

明天乌儿会歌唱 6493

【推荐100个unity插件】帮助你快速开发一款FPS游戏—— FPS Framework

FPS Framework 快速入门指南 FPS Framework 是一个 Unity 开发框架,可加速 FPS 游戏开发。主要功能包括: 第一人称控制器:基于 Character Controller 实现,提供移动、跳跃、下蹲等功能,支持自定义参数调整 渲染管线转换:内置 RP 转换器,支持 URP/HDRP 等渲染管线一键切换 库存系统: 采用双列表管理:物品列表(Items)和可收集物列表(Collectables) 支持自定义库存物品和可收集物类型 提供拾取/丢弃功能实现 快速开始: 通过预制件

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2569

Error: undefined reference to `glCreateShader'-Android NDK OpenGLES

通过NDK调用OpenGLES时,发现报错许多gl开头的方法未定义,具体如下: 奇怪的是,报错的方法还可以点击去。网上查询结果 大部分是修改让Android.mk 原因是 未配置链接OpenGLES库文件。 可是我用的是Android Studio 2.3.3 NDK开发根本看不到Android.mk,只有一个CMakeList.txt

iblade的博客 2340

详解RT-DETR网络结构/数据集获取/环境搭建/训练/推理/验证/导出/部署

本文给大家带来是利用RT-DETR模训练自己的数据集,RT-DETR是一种新提出的目标检测模型,它利用的自注意力机制来处理图像数据。不同于YOLO通过连续的卷积层直接对图像区域进行分析,RT-DETR采用Transformer架构中的自注意力机制,这允许模型更有效地理解图像中不同部分之间的关系。这种方法使得RT-DETR在处理图像中的复杂场景和多对象环境时,能够展现出更高的准确性和效率。此外,RT-DETR在保持高精度的同时,也针对实时处理进行了优化,使其适合需要快速响应的应用场景。

Snu77的博客 6万+

实验2.1——彩色三角形的显示

查这段代码的时候:无意中看到了一个这个链接:(31条消息) 现代OpenGL学习笔记三:深入理解着色器_不想不努力的菜菜的博客-优快云博客里面讲了如何绘制一个彩色的三角形,还演示了index=0,1两种情况下,VBO与shader怎么呼应的,绘制有颜色的图形,很常用,值得学习。 图画的挺漂亮的: 尝试 作为一个小白,报错是常态,所以,不要有心理负担。之前做到了这样:第一次运行,是这样: 改,在这一行里,少了个vec3,少了个; 坏消息是依旧报错,好消息是错少了 这个const

averagePerson的博客 479

【Python3教程】Python3高级篇之uWSGI 安装配置

本文介绍了在Python 3环境中安装和配置uWSGI的完整流程,涵盖基本安装、Flask/Django应用部署、Nginx集成以及systemd管理等关键环节。主要内容包括:uWSGI的安装前提条件,创建简单WSGI应用,编写uWSGI配置文件(.ini格式),与Nginx配合实现生产环境部署,以及使用systemd实现服务管理。文章还提供了常见Web框架(Flask、Django)的部署示例和高级配置建议,如负载均衡、HTTPS设置等。最后列出了权限、端口占用等常见问题的解决方案,为开发者提供了一套完整

No8g攻城狮的博客 438

量化交易零基础入门教程

特点 从零开始教编程。靠谱的量化交易学习资源稀少,且具有不讲编程、代码较难、过多等不适合新手等问题,本教程中则会从零开始教编程,解决量化入门过难过编程门槛这一问题。 量化与编程相结合。本教程不仅会教编程,而且会尽量结合量化情景,减少“我要做量化交易为什么要看这些用来培训程序员的东西”的愤懑。 简易精炼,快速入门。尽量只讲最核心最常用的知识,助你快速摆脱想学习量化却处处陌生不知所措的茫然的新手阶段。 读前说明 文后会有自测与自学,包括一些额外的延伸自学内容以及稍有难度的自测题目。 最最最基础的股票.

JanLEE 2886

利用5个标签,4个文本框,2个按钮,自己设计布局实现输入三边求三角形面积。界面如下所示。三角形类的编写可以使用实验4中已经写过的三角形类,当点击“判断三边”时,若能构成三角形,在标签5上显示“可以构成三角形!”,如不能构成三角形,在标签5上显示“不能构成三

<br /> <br />利用5个标签,4个文本框,2个按钮,自己设计布局实现输入三边求三角形面积。界面如下所示。三角形类的编写可以使用实验4中已经写过的三角形类,当点击“判断三边”时,若能构成三角形,在标签5上显示“可以构成三角形!”,如不能构成三角形,在标签5上显示“不能构成三角形,请重新设置三边”,只有满足能够构成三角形条件时,点击“计算面积”按钮,将面积显示在第四个文本框中。当点击“退出程序” 按钮时,能够退出应用程序。<br />//方案一 import javax.swing.*; impo

zutuan5的专栏 3190

Marvell 88Q6113 如何制作一个完整的量产固件88Q6113_flash.bin并进行烧录

本章节介绍如何基于Marvell工具链,制作一个完整的量产固件88Q6113_flash.bin,集成用户自定义的配置文件 config.bin,用于88Q6113的Flash烧录。注:Marvell 88Q5072 与 Marvell 88Q6113 的配置流程是一样的。

老板来份猪脚拼叉烧的博客 2011

实验一 JavaScript基础

实验一 JavaScript基础 1.掌握JavaScript的语法规则 2.掌握JavaScript的变量声明 3.熟悉JavaScript的数据类型 4.掌握JavaScript的各种运算符 5.掌握JavaScript的函数定义

Lucky的博客 1291

从 on_event 到 lifespan:FastAPI 生命周期管理的旧方法与新方法对比与迁移

从 on_event 到 lifespan:FastAPI 生命周期管理的旧方法与新方法对比与迁移

XiaoqiangClub的博客 1021

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

html相反方向滑动要滑两次,冀教版六年级科学下册实验报告内容

冀教版六年级科学下册实验报告内容一、实验题目:研究哪种形状的纸桥承重能力强实验材料:一张32开的白纸、两个桥墩、棋子若干实验过程:1.将两个桥墩摆好.相距适当的距离.2.将纸直接放在桥墩上.放旗子.观察放几个塌.3.将纸做成弓形.放在桥墩间.放旗子.观察放几个塌.4.将纸折成瓦楞型.放在桥墩上.放旗子.观察放几个塌.……(如有其它方法还可添加)5.实验结论:折成瓦楞型的纸桥承重能力强.二、实验题目...

weixin_39926394的博客 153

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

三角形问题测试实验报告

软件质量保证与测试三角形问题实验报告,仅个人作品,不保证完全正确。

m0_59287223的博客 4529

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

JSP实验:三角形的边长,面积,周长

我这里有一个问题,如果不能构成三角形,就应该不出现面积和周长,但是我写不出来。 编写两个JSP页面:inputTriangle.jsp与showTriangle.jsp。inputTriangle.jsp提供一个表单,用户可以通过表单输入三角形的三条边提交给showTriangle.jsp。用户提交表单后,JSP页面将计算三角形面积和周长的任务交给一个bean去完成,创建bean的源文件是Triangle.java。页面运行效果如图所示。 (1) Triangle.java package com.

Claire的博客 7270

汇编实验——编制在屏幕上显示用*组成的三角形的程序(带详细注释)

问题描述 编制在屏幕上显示用*组成的三角形的程序 代码实现 STACK SEGMENT STACK;初始化堆栈段 DB 1024 DUP(0) STACK ENDS;堆栈段结束 DATA SEGMENT;定义数据段 I DB 8;行数 J DB 1;首行字符数 DATA ENDS;数据段结束 CODE SEGMENT;定义代码段 ASSUME CS:CODE, DS:DATA;指明段寄存器与段的关系 BEGIN: MOV AX, DATA MOV

weixin_46698891的博客 4882

PTA:实验2-1-3 输出三角形

浙大版《C语言程序设计实验与习题指导(第4版)》PTA题目集

m0_73422835的博客 647

数字三角形的显示 java

数字三角形的显示 java 实现一行符号的输出 public class line { public static void main(String[] args) { // 实现输出一行符号的功能 int start_num = 2; // 符号数量 for (int num = 1; num <= start_num; num++) { System.out.print("*"); } }

pyhui的技术博客 1173

JavaScript中使用for循环打印简单的三角形,等腰三角形,菱形,空心三角形,空心菱形

打印一个简单的等腰三角形 <script> for(var i=0;i<=5;i++){ for(var j=0;j<=5-i;j++){ document.writeln("&nbsp;"); } for(var k=0;k<i;k++){ document.writeln('口'); ...

amensia_ZhangSan的博客 1万+

OpenGL三角形绘制顺序详解:为什么你的三角形显示不出来?从原理到调试技巧

本文深入解析OpenGL中三角形绘制顺序的核心原理及其对渲染可见性的关键影响。当开启背面剔除时,错误的顶点环绕顺序(如顺时针)会导致三角形被判定为背面而无法显示。文章从原理出发,结合代码示例,详细讲解了如何通过调整glFrontFace或修正顶点数据来解决此问题,并提供了从状态检查到使用RenderDoc等图形调试工具的系统化排查技巧,帮助开发者高效定位并修复三角形“消失”的常见渲染问题。

rose2的博客 1116

7-23 显示Pascal三角形 (30分)

输入行数n,显示n行Pascal三角形。数字间有一个空格。每行最后一个数字后有一个空格。 输入格式: 在一行中输入行数n。 输出格式: 输出n行Pascal三角形。 输入样例: 在这里给出一组输入。例如: 4 输出样例: 在这里给出相应的输出。例如: 1 1 1 1 2 1 1 3 3 1 def triangle(): N = [1] while True: yield N N.append(0) N =

m0_46802255的博客 7755

java编写三角形问题_软件测试实验1:为三角形问题编写一个Java程序,并用Junit测试程序...

实验报告实验内容:1.Install Junit(4.12), Hamcrest(1.3)with Eclipse2.Install Eclemma with Eclipse3.Write a java program for the triangle problem and test the program with Junit.实验步骤:1.在eclipse中安装Junit、Hamcrest...

weixin_33026067的博客 3571
上一篇: 实验1——搭建 OpenGL 环境
下一篇: 实验3——绘制四边形(EBO)
averagePerson
博客等级 码龄5年 381粉丝 113原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值