Cesium渲染模块之Buffer

1. 引言

Cesium是一款三维地球和地图可视化开源JavaScript库,使用WebGL来进行硬件加速图形,使用时不需要任何插件支持,基于Apache2.0许可的开源程序,可以免费用于商业和非商业用途

Cesium官网:Cesium: The Platform for 3D Geospatial

Cesium GitHub站点:CesiumGS/cesium: An open-source JavaScript library for world-class 3D globes and maps (github.com)

API文档:Index - Cesium Documentation

通过阅读源码,理清代码逻辑,有助于扩展与开发,笔者主要参考了以下两个系列的文章

渲染是前端可视化的核心,本文描述Cesium渲染模块的Buffer

2. WebGL中的Buffer

以下大致是一个最简的WebGL绘制代码:

<canvas id="canvas"></canvas>
<script>
const vertexSource = `
attribute vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
`
const fragmentSource = `
void main()
{
gl_FragColor = vec4(1.0, 0.5, 0.2, 1.0);
}
`
const canvas = document.getElementById('canvas');
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
const gl = canvas.getContext('webgl2');
if (!gl) {
alert('WebGL not supported');
}
const vertices = new Float32Array([
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.0, 0.5, 0.0,
]);
const vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(0)
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.clearColor(0.2, 0.3, 0.3, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(shaderProgram);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>

image-20230227214406870

其中,vbo是顶点缓冲对象(Vertex Buffer Objects, VBO),主要用来储存顶点数据:

const vertices = new Float32Array([
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.0, 0.5, 0.0,
]);
const vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

WebGLBuffer 接口属于 WebGL API 的一部分,表示一个不透明的缓冲区对象,储存诸如顶点或着色之类的数据

WebGLBuffer 对象没有定义任何自己的方法或属性,且内容不能被直接访问。当使用 WebGLBuffer 对象时, WebGLRenderingContext 下的这些方法会很有用:

示例代码中:

createBuffer() 方法可创建并初始化一个用于储存顶点数据或着色数据的WebGLBuffer对象

bindBuffer(target, buffer) 方法将给定的WebGLBuffer绑定到目标,参数:

  • target

    GLenum (en-US) 指定绑定点 (target)。可能的值:

    • gl.ARRAY_BUFFER: 包含顶点属性的 Buffer,如顶点坐标,纹理坐标数据或顶点颜色数据。
    • gl.ELEMENT_ARRAY_BUFFER: 用于元素索引的 Buffer
  • buffer

    要绑定的 WebGLBuffer

bufferData(target, size, usage) 方法创建并初始化了 Buffer 对象的数据存储区,参数:

  • target

    GLenum (en-US) 指定 Buffer 绑定点(目标)。可取以下值:

    • gl.ARRAY_BUFFER: 包含顶点属性的 Buffer,如顶点坐标,纹理坐标数据或顶点颜色数据。
    • gl.ELEMENT_ARRAY_BUFFER: 用于元素索引的 Buffer
  • size

  • usage

    GLenum (en-US) 指定数据存储区的使用方法。可取以下值:

    • gl.STATIC_DRAW: 缓冲区的内容可能经常使用,而不会经常更改。内容被写入缓冲区,但不被读取。
    • gl.DYNAMIC_DRAW: 缓冲区的内容可能经常被使用,并且经常更改。内容被写入缓冲区,但不被读取。
    • gl.STREAM_DRAW: 缓冲区的内容可能不会经常使用。内容被写入缓冲区,但不被读取

以上大致就是WebGL中Buffer(VBO)的用法

3. Cesium中的Buffer

Cesium中,对WebGL的Buffer进行了封装:

function Buffer(options) {
const gl = options.context._gl;
gl.bindBuffer(bufferTarget, buffer);
gl.bufferData(bufferTarget, hasArray ? typedArray : sizeInBytes, usage);
gl.bindBuffer(bufferTarget, null);
}
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) {
const buffer = new Buffer({
// ...
});
return buffer;
};

Buffer类的构造函数只是一次简单的封装,Buffer.createVertexBuffer函数可以更为快速的构建Buffer,搜索源码就会发现大多也是使用Buffer.createVertexBuffer创建Buffer,比如GeoJsonLoader.js

// ...
// Create GPU buffers
const positionBuffer = Buffer.createVertexBuffer({
typedArray: positionsTypedArray,
context: frameState.context,
usage: BufferUsage.STATIC_DRAW,
});
positionBuffer.vertexArrayDestroyable = false;
const featureIdBuffer = Buffer.createVertexBuffer({
typedArray: featureIdsTypedArray,
context: frameState.context,
usage: BufferUsage.STATIC_DRAW,
});
featureIdBuffer.vertexArrayDestroyable = false;
const indexBuffer = Buffer.createIndexBuffer({
typedArray: indicesTypedArray,
context: frameState.context,
usage: BufferUsage.STATIC_DRAW,
indexDatatype: indexDatatype,
});
indexBuffer.vertexArrayDestroyable = false;
// ...

使用Buffer.createVertexBuffer创建指定数据大小而数据未确定的VBO的例子:

// Example 1. Create a dynamic vertex buffer 16 bytes in size.
const buffer = Buffer.createVertexBuffer({
context : context,
sizeInBytes : 16,
usage : BufferUsage.DYNAMIC_DRAW
});

使用Buffer.createVertexBuffer创建数据确定的VBO的例子:

// Example 2. Create a dynamic vertex buffer from three floating-point values.
// The data copied to the vertex buffer is considered raw bytes until it is
// interpreted as vertices using a vertex array.
const positionBuffer = buffer.createVertexBuffer({
context : context,
typedArray : new Float32Array([0, 0, 0]),
usage : BufferUsage.STATIC_DRAW
});

使用Buffer.createIndexBuffer创建指定数据大小而数据未确定的IBO的例子:

// Example 1. Create a stream index buffer of unsigned shorts that is
// 16 bytes in size.
const buffer = Buffer.createIndexBuffer({
context : context,
sizeInBytes : 16,
usage : BufferUsage.STREAM_DRAW,
indexDatatype : IndexDatatype.UNSIGNED_SHORT
});

使用Buffer.createIndexBuffer创建数据确定的IBO的例子:

// Example 2. Create a static index buffer containing three unsigned shorts.
const buffer = Buffer.createIndexBuffer({
context : context,
typedArray : new Uint16Array([0, 1, 2]),
usage : BufferUsage.STATIC_DRAW,
indexDatatype : IndexDatatype.UNSIGNED_SHORT
});

此外,Buffer封装的函数有:

Buffer.prototype.copyFromArrayView = function (arrayView, offsetInBytes)
Buffer.prototype.copyFromBuffer = function (
readBuffer,
readOffset,
writeOffset,
sizeInBytes
)
Buffer.prototype.getBufferData = function (
arrayView,
sourceOffset,
destinationOffset,
length
)
Buffer.prototype.isDestroyed
Buffer.prototype.destroy

4. 参考资料

[1]Cesium原理篇:6 Renderer模块(1: Buffer) - fu*k - 博客园 (cnblogs.com)

[2]WebGLRenderingContext - Web API 接口参考 | MDN (mozilla.org)

[3]Cesium渲染模块之概述 - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)

posted @   当时明月在曾照彩云归  阅读(629)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示