我的github

Cesium原理篇:6 Renderer模块(1: Buffer)

Cesium原理篇:6 Renderer模块(2 Texture)

Cesium原理篇:6 Render模块(3 Shader)

Cesium原理篇:6 Render模块(4 FBO)

Cesium原理篇:6 Render模块(5 VAO&RenderState&Command)

Cesium原理篇:6 Render模块(6 Instance实例化)

参考:https://www.cnblogs.com/fuckgiser/p/6027520.html

渲染器:

要讲3D Tiles,或者充分理解它,需要对DataSource,Primitive要有基础,而这要求对最底层的渲染模块,也就是Render有一个了解。

1. Buffer

当我们想要通过WebGL渲染该几何对象时,首先就是要讲该几何对象转化为WebGL可以识别的数据格式:(1)构建该对象的顶点数组,里面包括每一个点的XYZ位置(必须),该点的颜色,纹理坐标,法线等信息;(2)构建该对象对应的索引信息,也就是点之间的先后顺序。

上述说的就是一个VBO(顶点缓存)的概念,WebGL提供了bufferData接口,我们对其中的参数做一个简单介绍

//获取WebGL对象

var canvas = document.getElementById("canvas");

var gl = canvas.getContext("webgl");

//创建顶点缓存

var buffer = gl.createBuffer();

//绑定该顶点缓存类型为顶点属性数据

gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

//指定其指定的数据长度及方式

gl.bufferData(gl.ARRAY_BUFFER,1024,gl.STATIC_DRAW);

//解除绑定

gl.bindBuffer(bufferTarget, null);

通过上面的介绍,可见顶点属性和顶点索引的调用方法完全相同,逻辑上的创建过程也如出一辙,只是具体的参数稍有不同,因此,在Cesium中把创建VBO的过程化的函数封装为一个抽象的Buffer类,伪代码如下:

function Buffer(options) {
    var gl = options.context._gl;
    var bufferTarget = options.bufferTarget;
    var typedArray = options.typedArray;
    var sizeInBytes = options.sizeInBytes;
    var usage = options.usage;
    var hasArray = defined(typedArray);

    if (hasArray) {
        sizeInBytes = typedArray.byteLength;
    }
    // ……
    var buffer = gl.createBuffer();
    gl.bindBuffer(bufferTarget, buffer);
    gl.bufferData(bufferTarget, hasArray ? typedArray : sizeInBytes, usage);
    gl.bindBuffer(bufferTarget, null);
    // ……
    this._gl = gl;
    this._bufferTarget = bufferTarget;
    this._sizeInBytes = sizeInBytes;
    this._usage = usage;
    this._buffer = buffer;
    this.vertexArrayDestroyable = true;
}

可见,这个过程和刚才WebGL调用的方式几乎一模一样,只是把所需要的参数都封装了一下,并将调用函数的返回值,作为属性保存在该Buffer对象中。于是,一个过程式的函数调用封装成了一个Object,即可以重用,也方便内部细节的管理。

由于Options参数太多,不方便理解。于是接着Cesium在Buffer类中提供了Buffer.createVertexBuffer和Buffer.createIndexBuffer方法

Buffer.createVertexBuffer = function(options) {
    return new Buffer({
        context: options.context,
        bufferTarget: WebGLConstants.ARRAY_BUFFER,
        typedArray: options.typedArray,
        sizeInBytes: options.sizeInBytes,
        usage: options.usage
    });
};
    
Buffer.createIndexBuffer = function(options) {
    return new Buffer({
        context: options.context,
        bufferTarget : WebGLConstants.ELEMENT_ARRAY_BUFFER,
        typedArray : options.typedArray,
        sizeInBytes : options.sizeInBytes,
        usage : options.usage
    });
};

这下用起来就so easy了,用户创建顶点属性和顶点索引的范例如下:

var buffer = Buffer.createVertexBuffer({
  context : context,
  sizeInBytes : 16,
  usage : BufferUsage.DYNAMIC_DRAW
});
     
var buffer = Buffer.createIndexBuffer({
  context : context,
  typedArray : new Uint16Array([0, 1, 2]),
  usage : BufferUsage.STATIC_DRAW,
  indexDatatype : IndexDatatype.UNSIGNED_SHORT
});

当然,如果你此时是用的DYNAMIC_DRAW的方式,并没有指定bufferdata,则创建该顶点缓存对象,但数据还是空的,在获取数据后可以调用Buffer.prototype.copyFromArrayView方法更新一下该数据。可见,Buffer类的设计还是比较周全的,考虑到数据更新可能存在这种不确定的逻辑:

Buffer.prototype.copyFromArrayView = function(arrayView, offsetInBytes) {
    var gl = this._gl;
    var target = this._bufferTarget;
    gl.bindBuffer(target, this._buffer);
    gl.bufferSubData(target, offsetInBytes, arrayView);
    gl.bindBuffer(target, null);
};

 如上就是创建VBO的一个完整过程,可以仔细对比一下两者之间的不同。因为VBO是渲染中最基本的,也是最重要的概念和渲染对象,通过Buffer类对这个过程进行分装和管理,虽然难度不大,但意义却很重要。

通过Buffer,我们可以将Primitive(图元)中的几何数据转化为VBO,这相当于创建了该几何对象的骨架。通常我们还需要纹理信息,贴在这个骨架的表面,让它看上去有血有肉,惟妙惟肖。下一篇我们介绍Cesium是如何封装Texture。

 

posted on 2022-06-06 14:27  XiaoNiuFeiTian  阅读(262)  评论(0编辑  收藏  举报