前言
本文介绍了OpenGL ES 2.0 中的顶点缓冲对象(VBO: Vertex Buffer Object)和索引缓冲对象(IBO: Indice Buffer Object)的用法,
在之前的文章中图元的绘制没用使用VBO, 要绘制的顶点数据是以顶点数组的形式保存在客户端的内存中的,在每次调用glDrawArrays 或者glDrawElements 的时候,顶点数组都会被从客户端内存copy到显卡内存。
VBO的作用,就是把这份每次都要copy的顶点数组缓存在显卡的内存中,VBO使得我可以直接在显卡内存中分配并缓存顶点数据。这样就避免了每次调用draw的时候的copy操作,从而提高了渲染性能同时降低了内存带宽和设备的电量消耗。
IBO跟VBO的原理类似,只不过IBO是缓存了VBO绘制时候的Indices.
根据OpenGL ES 2.0 “Golden Book”的建议,要想获得最好的性能,就要尽可能使用VBO和IBO来完成绘制任务。
下面以一个具体的例子来展示如何使用VBO和IBO完成一个正方体的绘制。
效果图
图中这个绿色的正方体就是绘制的结果
实现
主要分三步:
-
准备好顶点数据,顶点索引数据;
-
创建VBO和IBO,分别和顶点数据、顶点索引数据绑定;
-
使用绑定后的VBO和IBO来完成绘制
1. 准备好顶点数据,顶点索引数据
正方体有八个顶点,定义如下:
绘制正方体主要是确定其八个顶点的坐标,如下图所示:
按编号从0~7以不同的颜色标识,下面定义出这8个顶点
2. 创建VBO和IBO,分别和顶点数据、顶点索引数据绑定
上面定义好了两个数组,接下来分别把顶点数组和索引数据绑定到VBO和IBO。
unsigned int _vbo;
unsigned int _ibo;
3. 使用绑定后的VBO和IBO来完成绘制
万事俱备,现在开始绘制:
glBindTexture(GL_TEXTURE_2D, _textureCube);
完整的源代码和Shader
VboScene.h
#pragma once
#include "gl_include.h"
#include "ELShaderProgram.h"
#include <string>
#include <vector>
NS_BEGIN(elloop);
NS_BEGIN(vbo_scene);
class FirstCamera
{
public:
FirstCamera()
: _moveSpeed(5)
, _eye(0, 10, 0)
, _look(0.5, -0.4, -0.5)
, _up(0, 1, 0)
, _right(1, 0, 0)
{
}
CELL::float3 _eye;
CELL::float3 _look;
CELL::float3 _up;
CELL::float3 _right;
float _moveSpeed;
void updateCamera(float dt)
{
using namespace CELL;
float3 tempLook = _look;
float3 direction = _look - _eye;
direction = normalize(direction);
unsigned char keys[300];
GetKeyboardState(keys);
if (keys[VK_UP] & 0x80)
{
_eye -= direction * (-_moveSpeed) * dt;
_look -= direction * (-_moveSpeed) * dt;
}
if (keys[VK_DOWN] & 0x80)
{
_eye += direction * (-_moveSpeed) * dt;
_look += direction * (-_moveSpeed) * dt;
}
if (keys[VK_LEFT] & 0x80)
{
_eye -= _right * _moveSpeed * dt;
_look -= _right * _moveSpeed * dt;
}
if (keys[VK_RIGHT] & 0x80)
{
_eye += _right * _moveSpeed * dt;
_look += _right * _moveSpeed * dt;
}
}
};
class VboScene : public ShaderProgram
{
public:
struct Vertex
{
float x, y, z;
float u, v;
float r, g, b, a;
};
static VboScene* create();
void begin() override;
void end() override;
void render() override;
uniform _mvp;
uniform _textureBg;
attribute _position;
attribute _uv;
unsigned int _textureBgId;
unsigned int _textureCube;
unsigned int _vbo;
unsigned int _ibo;
FirstCamera _camera;
protected:
bool init();
VboScene()
: _mvp(-1)
, _textureBg(-1)
, _textureBgId(0)
, _position(-1)
, _uv(-1)
, _textureCube(0)
, _vbo(0)
, _ibo(0)
{
_vsFileName = "shaders/3D_projection_vs.glsl";
_fsFileName = "shaders/3D_projection_fs.glsl";
}
~VboScene()
{
glDeleteTextures(1, &_textureBgId);
glDeleteTextures(1, &_textureCube);
}
unsigned int loadMipMap(const std::vector<std::string> &fileNames);
unsigned int loadTexture(const std::string &fileName );
};
NS_END(vbo_scene);
NS_END(elloop);
VboScene.cpp
#include "scenes/VboScene.h"
#include "app_control/ELDirector.h"
#include "math/ELGeometry.h"
#include "include/freeImage/FreeImage.h"
NS_BEGIN(elloop);
NS_BEGIN(vbo_scene);
void VboScene::begin()
{
glUseProgram(_programId);
glEnableVertexAttribArray(_position);
glEnableVertexAttribArray(_uv);
}
void VboScene::end()
{
glDisableVertexAttribArray(_uv);
glDisableVertexAttribArray(_position);
glUseProgram(0);
}
bool VboScene::init()
{
_valid = ShaderProgram::initWithFile(_vsFileName, _fsFileName);
if ( _valid )
{
_position = glGetAttribLocation(_programId, "_position");
_uv = glGetAttribLocation(_programId, "_uv");
_textureBg = glGetUniformLocation(_programId, "_textureBg");
_mvp = glGetUniformLocation(_programId, "_mvp");
}
std::vector<std::string> fileNames =
{
"images/p32x32.bmp",
"images/p16x16.bmp",
"images/p8x8.bmp",
"images/p4x4.bmp",
"images/p2X2.bmp",
"images/p1x1.bmp"
};
_textureBgId = loadMipMap(fileNames);
_textureCube = loadTexture("images/1.jpg");
_camera._eye = CELL::float3(1, 1, 1);
_camera._look = CELL::float3(0.5f, -0.4f, -5.5f);
_camera._up = CELL::float3(0.0f, 1.0f, 0.0f);
_camera._right = CELL::float3(1.0f, 0.0f, 0.0f);
Vertex cubeVertex[] =
{
{ -1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f },
顶点shader: 3D_projection_vs.glsl
precision lowp float;
attribute vec3 _position;
uniform mat4 _mvp;
attribute vec2 _uv;
varying vec2 _outUv;
void main()
{
vec4 pos = vec4(_position.x, _position.y, _position.z, 1);
gl_Position = _mvp * pos;
_outUv = _uv;
}
片段shader: 3D_projection_fs.glsl
precision lowp float;
varying vec2 _outUv;
uniform sampler2D _textureBg;
void main()
{
vec4 bgColor = texture2D(_textureBg, _outUv);
gl_FragColor = bgColor;
}
源码下载
如果源码对您有帮助,请帮忙在github上给我点个Star, 感谢 :)
参考
本文侧重实战,api的使用细节请参考下面第二个链接,那里有各种OpenGL的API说明。
|
请发表评论