首页 > 编程语言 >阅读《计算机图形学编程(使用OpenGL和C++)》6

阅读《计算机图形学编程(使用OpenGL和C++)》6

时间:2022-08-19 11:34:07浏览次数:72  
标签:1.0 glm OpenGL 0.0 vbo 图形学 C++ 缓冲区 GL

同一个场景渲染不同的对象,一种简单的方法是为每个模型使用单独的缓冲区。每个模型都需要自己的模型矩阵,这样我们就需要为我们渲染的每个模型生成一个新的模型-视图矩阵。还需要为每个模型单独调用glDrawArrays()。因此,我们需要修改init()和display()函数。

让我们继续添加一个简单的金字塔,这样我们的场景就包括一个立方体和一个金字塔。

顶点和片段着色器代码被省略了,他们和之前3一样。

main.cpp

void setupVertices(void)
{    
    // 立方体
    float cubePositions[108] = {
        -1.0f,  1.0f, -1.0f, -1.0f, -1.0f, -1.0f,  1.0f, -1.0f, -1.0f,
         1.0f, -1.0f, -1.0f,  1.0f,  1.0f, -1.0f, -1.0f,  1.0f, -1.0f,
         1.0f, -1.0f, -1.0f,  1.0f, -1.0f,  1.0f,  1.0f,  1.0f, -1.0f,
         1.0f, -1.0f,  1.0f,  1.0f,  1.0f,  1.0f,  1.0f,  1.0f, -1.0f,
         1.0f, -1.0f,  1.0f, -1.0f, -1.0f,  1.0f,  1.0f,  1.0f,  1.0f,
        -1.0f, -1.0f,  1.0f, -1.0f,  1.0f,  1.0f,  1.0f,  1.0f,  1.0f,
        -1.0f, -1.0f,  1.0f, -1.0f, -1.0f, -1.0f, -1.0f,  1.0f,  1.0f,
        -1.0f, -1.0f, -1.0f, -1.0f,  1.0f, -1.0f, -1.0f,  1.0f,  1.0f,
        -1.0f, -1.0f,  1.0f,  1.0f, -1.0f,  1.0f,  1.0f, -1.0f, -1.0f,
         1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,  1.0f,
        -1.0f,  1.0f, -1.0f,  1.0f,  1.0f, -1.0f,  1.0f,  1.0f,  1.0f,
         1.0f,  1.0f,  1.0f, -1.0f,  1.0f,  1.0f, -1.0f,  1.0f, -1.0f,
    };
    // 金字塔有18个顶点,由6个三角形组成(侧面4个,底面2个)
    float pyramidOsitions[54] = {
        -1.0f, -1.0f,  1.0f,  1.0f, -1.0f,  1.0f,  0.0f,  1.0f,  0.0f, // 前面
         1.0f, -1.0f,  1.0f,  1.0f, -1.0f, -1.0f,  0.0f,  1.0f,  0.0f, // 右面
         1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,  0.0f,  1.0f,  0.0f, // 后面
        -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,  1.0f,  0.0f,  1.0f,  0.0f, // 左面
        -1.0f, -1.0f, -1.0f,  1.0f, -1.0f,  1.0f, -1.0f, -1.0f,  1.0f, // 底面 - 左前一半
         1.0f, -1.0f,  1.0f, -1.0f, -1.0f, -1.0f,  1.0f, -1.0f, -1.0f, // 底面 - 右后一半
    };
    glGenVertexArrays(1, vao); // 创建一个vao,并返回它的整数型ID存进数组vao中
    glBindVertexArray(vao[0]); // 激活vao
    glGenBuffers(numVBOs, vbo);// 创建两个vbo,并返回它们的整数型ID存进数组vbo中

    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // 激活vbo第0个缓冲区
    glBufferData(GL_ARRAY_BUFFER, sizeof(cubePositions), cubePositions, GL_STATIC_DRAW); // 将包含顶点数据的数组复制进活跃缓冲区(这里是第0个VBO)

    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // 激活vbo第0个缓冲区
    glBufferData(GL_ARRAY_BUFFER, sizeof(pyramidOsitions), pyramidOsitions, GL_STATIC_DRAW); // 将包含顶点数据的数组复制进活跃缓冲区(这里是第1个VBO)
}

void init(GLFWwindow* window) {
    renderingProgram = Utils::createShaderProgram("vertShader.glsl", "fragShader.glsl");
    cameraX = 0.0f;  cameraY = 0.0f;    cameraZ = 8.0f;
    cubeLocX = 0.0f; cubeLocY = -2.0f; cubeLocZ = 0.0f; // 沿Y轴下移以展示透视
    pyrLocX = 2.0f; pyrLocY = 2.0f; pyrLocZ = 0.0f;
    setupVertices();
}


void display(GLFWwindow* window, double currentTime)
{
    glClear(GL_DEPTH_BUFFER_BIT);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(renderingProgram);

    // 获取MV矩阵和投影矩阵的统一变量的引用
    mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");
    projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");
    
    // 构建透视矩阵
    glfwGetFramebufferSize(window, &width, &height);
    aspect = (float)width / (float)height;
    pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f); // 1.0472 radians = 60 degrees
    
    // 构建视图矩阵、模型矩阵
    vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));

    // 绘制立方体(使用0号缓冲区)
    mMat = glm::translate(glm::mat4(1.0f), glm::vec3(cubeLocX, cubeLocY, cubeLocZ));
    mvMat = vMat * mMat;

    glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat)); // 着色器需要视图矩阵的统一变量
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));

    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);                    // 标记第0个缓冲区为“活跃”
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);    // 将第0个属性关联到缓冲区
    glEnableVertexAttribArray(0);                            // 启用第0个顶点属性

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glDrawArrays(GL_TRIANGLES, 0, 36);                        // 执行该语句,第0个VBO中的数据将被传输给拥有位置0的layout修饰符的顶点属性中。这会将立方体的顶点数据发送到着色器。

    // 绘制金字塔(使用1号缓冲区)
    mMat = glm::translate(glm::mat4(1.0f), glm::vec3(pyrLocX, pyrLocY, pyrLocZ));
    mvMat = vMat * mMat;

    glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat)); // 着色器需要视图矩阵的统一变量
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));

    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);                    // 标记第1个缓冲区为“活跃”
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);    // 将第0个属性关联到缓冲区
    glEnableVertexAttribArray(0);                            // 启用第0个顶点属性

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glDrawArrays(GL_TRIANGLES, 0, 18);                        // 执行该语句,第1个VBO中的数据将被传输给拥有位置0的layout修饰符的顶点属性中。这会将金字塔的顶点数据发送到着色器。
    
}

结果如下:

标签:1.0,glm,OpenGL,0.0,vbo,图形学,C++,缓冲区,GL
From: https://www.cnblogs.com/lely/p/16601446.html

相关文章

  • 配置工程及引入测试--针对C++
     书写CMakeList同时支持windows、Linux、Mac,将头文件,三方库,源文件,测试代码目录进行分离使用CMAKE区分Debug版本和Release版本;工程中同时生成动态库和测试用例;动态库方......
  • 从C过渡到C++——换一个视角深入数组[初始化](1)
    从C过渡到C++——换一个视角深入数组[初始化](1)目录从C过渡到C++——换一个视角深入数组[初始化](1)数组的初始化从C入手作用域代码块作用域文件作用域原型作用域函数作用域......
  • c++指针常量和常量指针怎么记
    指针常量:int*constp  按中文,"指针"二字在前,没有const去修饰,所以int开头,那const肯定在后面修饰p,p可以理解为方向,就是该指针的方向不能变,值可以变常量指针:const......
  • C++primer练习15.1-14
    练习15.1什么是虚成员?::需要派生类自己定义的成员练习15.2protected访问说明符与private有何区别?::protected允许派生类访问,private一律不允许访问练习15.3定义你自己的......
  • c++ 批量修改文件名
    在网上找了很久如何利用c++批量修改文件名,但是很不幸,找到的都不全,或者跑起来没效果。我就整合了以下批量修改文件名的代码(我跑完之后,文件名并没有改,好奇怪,你们可以试着找一......
  • Linux c++ 试验-10 一例undefined reference to symbol 'pthread_create@@GLIBC_2.2.5
    最近在编写一个程序时(x64Linux,Arm下没有这个问题),出现了undefinedreferencetosymbol'pthread_create@@GLIBC_2.2.5'”,明明有设置-pthread(l60870里用到了这个库)。经过......
  • C++primer练习14.44-53
    练习14.44编写一个简单的桌面计算器使其处理二元计算doubleadd(doublea,doubleb){returna+b;}autosubtra=[](doublea,doubleb){returna-b;};stru......
  • VSCode运行C/C++配置
    将MinGw安装目录下的1、安装 VSCode2、安装 MinGW链接:点击跳转3、MinGW 内安装两个模块1.右键MarkforInstallation勾选(此处已安装好,所以是绿色实心)2.......
  • Effective C++ - 条款2 - in-class初值设定问题
    pre针对EffectiveC++(55条)中的每一个条款写一个blog。0x02尽量以const,enum,inline替换#define为什么需要这样做?因为使用define会使得变量被define的符号替换,在......
  • c++基本编程体验第3节之命名空间
    3.1、何为命名空间3.1.1、命名空间的引入(1)命名空间namespace,是c++引入的一种解决全局变量和函数名冲突机制(2)c语言没有namespace,但是c++及之后的javapy......