本节我们将尝试利用三角形制作一个“走马灯”效果。

一个三角形如图示方式,从左向右依次移动。

先看一下代码:

MyGlWindow.cpp

 #include <gl\glew.h>
#include "MyGlWindow.h"
#include <iostream>
#include <fstream> float triangleWidth = 0.1f;
float bytesPerTriangle = sizeof(GLfloat) * ;
uint triangleIndex = ;
uint maxTriangleCount = ; void MyGlWindow::sendDataToOpenGL()
{
//GLfloat verts[] =
//{
// -1.0f, -1.0f, +0.5f,//Vertex 0
// +1.0f, +0.0f, +0.0f,//Color 0
// +0.0f, +1.0f, -0.5f,//Vertex 1
// +0.0f, +1.0f, +0.0f,//Color 1
// +1.0f, -1.0f, +0.5f,//Vertex 2
// +0.0f, +0.0f, +1.0f,//Color 2 // -1.0f, +1.0f, +0.5f,//Vertex 3
// +0.5f, +0.3f, +0.1f,//Color 3
// +0.0f, -1.0f, -0.5f,//Vertex 4
// +0.1f, +0.4f, +0.2f,//Color 4
// +1.0f, +1.0f, +0.5f,//Vertex 5
// +1.0f, +0.5f, +0.2f,//Color 5
//}; GLuint vertexBufferID;
glGenBuffers(, &vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, maxTriangleCount * bytesPerTriangle, NULL, GL_STATIC_DRAW); //GLushort indices[] =
//{
// 0,1,2,
// 3,4,5,
//};
//GLuint indexBufferID;
//glGenBuffers(1, &indexBufferID);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
//glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glEnableVertexAttribArray();
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, sizeof(GLfloat) * , ); glEnableVertexAttribArray();
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, sizeof(GLfloat) * , (char*)(sizeof(GLfloat) * ));
} void MyGlWindow::installShaders()
{
//未修改,省略...
} void MyGlWindow::initializeGL()
{
glewInit();
glEnable(GL_DEPTH_TEST);
sendDataToOpenGL();
installShaders();
} void MyGlWindow::paintGL()
{
glClear(GL_DEPTH_BUFFER_BIT);
glViewport(, , width(), height());
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
sendAnotherTriangle();
glDrawArrays(GL_TRIANGLES, (triangleIndex-)*, triangleIndex * bytesPerTriangle);
} void MyGlWindow::sendAnotherTriangle()
{
if (triangleIndex == maxTriangleCount)
return;
GLfloat xVal = - + triangleIndex * triangleWidth;
GLfloat newTriangle[] =
{
xVal, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f, xVal + triangleWidth, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, xVal, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
}; glBufferSubData(GL_ARRAY_BUFFER, bytesPerTriangle * triangleIndex, bytesPerTriangle, newTriangle); triangleIndex++;
} std::string MyGlWindow::ReadShaderCode(const char* fileName)
{
//未修改,省略...
}

MyGlWindow.h

 #pragma once
#include <QtOpenGL\qgl.h>
#include <string>
class MyGlWindow :public QGLWidget
{
protected:
void sendDataToOpenGL();
void installShaders();
void initializeGL();
void paintGL();
std::string ReadShaderCode(const char* fileName);
void sendAnotherTriangle();
};

重点看cpp文件里的变化。

先定义了几个变量(其实也可以定义成常量),方便后面使用,他们分别是:

  • float triangleWidth = 0.1f 表示三角形的宽度
  • float bytesPerTriangle = sizeof(GLfloat) * 18 表示每个三角形包含的顶点信息数据字节数,一个三角形使用了3个顶点,每个顶点有6个GLfloat类型数据
  • uint triangleIndex = 0 表示当前绘制的三角形的索引
  • uint maxTriangleCount = 20 “走马灯”最多有多少个三角形

此前我们是在sendDataToOpenGL()函数中创建一个verts数组,把所有的数据一次性发送到OpenGL中进行绘制,本次我们需要动态改变绘制的内容,所以就不事先将数据一次性发送了。首先删除掉sendDataToOpenGL函数中的verts数组。(13-28行)

另外也不需要所以数组了,也把索引数组相关的内容删除掉。(35-43行以及69行)

33行也做了修改,首先我们要给VertexArrayBuffer分配足够的空间,所以第二个参数改成了maxTriangleCount * bytesPerTriangle,提供20个三角形需要的空间。而我们在这个阶段不需要提供任何数据(后面会讲如何提供),所以第三个参数直接给个空值NULL。

在71行绘制Array之前,我们调用了一个新添加的函数sendAnotherTriangle(),这个函数的前半部分(78-89行)是准备数据,准备每次走马灯要绘制的三角形的数据,由数据内容也能看出来,主要区别就是位置向右移动了。

重点是91行的函数

glBufferSubData(GL_ARRAY_BUFFER, bytesPerTriangle * triangleIndex, bytesPerTriangle, newTriangle);

glBufferSubData 这个OpenGL函数的作用是“部分填充” Array Buffer。可以对比观察33行的glBufferData(一次性全部填充), 名字只是多了一个Sub,但是两者的参数还是有些区别的。

  • 第一个参数和glBufferData是一样的,表示设置哪个绑定点的数据。
  • 第二个参数是一个绘制的起始位置,因为我们右了一个三角形的索引triangleIndex,所以起始值就是它乘以每个三角形的字节数。
  • 第三个参数表示每个元素的长度,正好使用我们一开始定义的每个三角形的字节数 bytesPerTriangle
  • 第四个参数是数据本身

71行绘制Array Buffer, 注意第二个参数是每个三角形的起始点。

完成后编译运行,发现画面并没有变化,主要原因是画面没有重绘,为了激活重绘,最简单的办法就是让窗口失去焦点和得到焦点,也就是可以在opengl窗口和其他任意窗口之间点击切换。

但是看到的效果仍然不是我们期望的。效果如下:

这是什么原因呢?

原因是OpenGL使用了双重缓存。一个Front Buffer, 一个Back Buffer。

绘制工作都是在Back Buffer上进行的,以免用户看到绘制的过程,绘制好以后,会和Front Buffer进行一次交换。这就是为什么我们看到了似乎有两副不同的图在反复切换。

另外,我们明确指定了每次只绘制一个三角形,但是为什么之前的三角形都保存下来了?

原因是我们没有进行一次“清理”。

找到MyGlWindow.cpp的67行,我们对它进行如下修改:

glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

既然要清理Depth Buffer,我们顺便使用一个"位或" 运算符把 Color Buffer也添加上。

这样修改以后,就可以实现"走马灯"效果了!(效果就不截图了,动图太难弄了)

3D Computer Grapihcs Using OpenGL - 10 Color Buffer的更多相关文章

  1. 3D Computer Grapihcs Using OpenGL - 20 结合Buffer

    在上一节的案例中,我们使用了四个Buffer Object,立方体的VertexBuffer,立方体的索引Buffer,四面体的VertexBuffer,四面体的索引Buffer. 我们这节尝试把两个 ...

  2. 3D Computer Grapihcs Using OpenGL - 03 OpenGL Buffer Data

    本节绘制一个三角形,并讲解Buffer Object-缓冲对象 OpenGL的窗口坐标 屏幕中心为坐标原点,横向朝右为x正方向,纵向朝上为y正方向,最大值最小值分别为1,-1. Buffer Obje ...

  3. 3D Computer Grapihcs Using OpenGL - 16 使用DrawElementsInstanced绘制立方体

    我们使用15节学到的知识来绘制14节的立方体. 在第14节我们使用了两次glDrawElements实现了OpenGL实例化,发现这样仍然不太方便,如果需要绘制成千上万的立方体,就需要手写成千上万次的 ...

  4. 3D Computer Grapihcs Using OpenGL - 09 Enable Depth Test

    启用Depth Test OpenGL是个3D绘图API,也就是说不只有xy坐标轴,还有第三个坐标轴z,z轴的方向是垂直于屏幕,指向屏幕内. 靠近人眼的方向是负方向,标准化设备坐标的最小值是-1, 最 ...

  5. 3D Computer Grapihcs Using OpenGL - 19 Vertex Array Object(顶点数组对象)

    大部分OpenGL教程都会在一开始就讲解VAO,但是该教程的作者认为这是很不合理的,因为要理解它的作用需要建立在我们此前学过的知识基础上.因此直到教程已经进行了一大半,作者才引入VAO这个概念.在我看 ...

  6. 3D Computer Grapihcs Using OpenGL - 11 Model View Projection Matrices

    本节我们将绘制一个3维物体,立方体. 如果要渲染3D物体,我们需要了解MVP(Model View Projection),它表示三个转换矩阵.实际上这个名字不够明确,更加确切的释义如下: Model ...

  7. 3D Computer Grapihcs Using OpenGL - 06 Vertex and Fragment Shaders

    从这里就接触到了可编程图形渲染管线. 下面介绍使用Vertex Shader (顶点着色器)和 Fragment Shader(像素着色器)的方法. 我们的目标是使用这两个着色器给三角形填充绿色. 添 ...

  8. 3D Computer Grapihcs Using OpenGL - 17 添加相机(旋转)

    在11节我们说过,MVP矩阵中目前只应用了两个矩阵,World to View 矩阵被省略了,这就导致我们的画面没有办法转换视角. 本节我们将添加这一环节,让相机可以旋转. 为了实现这一目的,我们添加 ...

  9. 3D Computer Grapihcs Using OpenGL - 14 OpenGL Instancing

    如果我们需要绘制两个(或者多个)一样的立方体(或者物体),只是位置.缩放.旋转不一样,那么我们可以不需要多次将这个物体的顶点信息.颜色信息等发送到显卡,而是发送一次,绘制多次,仅仅是每次绘制之前应用不 ...

随机推荐

  1. 简述Vue的路由与视图

    1.vue-router 安装方式 npm/cnpm:(个人偏向于cnpm) npm/cnpm install vue-router --save-dev bower: bower install v ...

  2. 深入理解java:1.3.2 JVM监控与调优

    学习Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分析原因并解决之. 本篇,来看看[ 如何监控和优化GC机制.] 通过学习,我觉得JVM监控与调优,主要在3个着眼点上: 1,如何配置 ...

  3. Clover的简单使用

    官网: http://cn.ejie.me 操作说明相关: 方便的 Tab 页功能 要掌握功能强大,操作简单的标签页,只需记住Ctrl+T新开页面,Ctrl+W关闭页面,Ctrl+Tab切换页面,工作 ...

  4. 【监控实践】【4.1】利用trace实现阻塞跟踪和慢查询跟踪

    原文:https://blog.csdn.net/kk185800961/article/details/49252037 分享个SQLServer profiler 的一个技巧吧.很早用过,忘记总结 ...

  5. java常用类详细介绍及总结:字符串相关类、日期时间API、比较器接口、System、Math、BigInteger与BigDecimal

    一.字符串相关的类 1.String及常用方法 1.1 String的特性 String:字符串,使用一对""引起来表示. String声明为final的,不可被继承 String ...

  6. OpenGL字体绘制

    /* glfont.hpp sdragonx 2019-08-15 00:03:33 opengl字体类,提供初学者参考学习 opengl初始化之后,创建字体 font.init(L"微软雅 ...

  7. Nginx工作机制

    Nginx分为单工作进程和多工作进程两种模式.通常采用1个master+多个worker进程配合异步非阻塞的工作机制.master进程主要负责管理自身和下属的worker进程,worker负责处理请求 ...

  8. django中的FBV和CBV??

    django中请求处理方式有2种:FBV 和 CBV 一.FBV FBV(function base views) 就是在视图里使用函数处理请求. 看代码: urls.py from django.c ...

  9. 【目标检测+域适应】CVPR18 CVPR19总结

    域适应已经是一个很火的方向了,目标检测更不用说,二者结合的工作也开始出现了,这里我总结了CVPR18和CVPR19的相关论文,希望对这个交叉方向的近况有一个了解. 1. 2018_CVPR Domai ...

  10. JDK集合框架源码分析 - 简单概要

    1.类继承体系 在集合框架的类继承体系中,最顶层有两个接口Collection.Map: Collection 表示一组纯数据 Map 表示一组key-value对 Collection的类继承体系: ...