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>
其中,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
下的这些方法会很有用:
WebGLRenderingContext.bindBuffer()
WebGLRenderingContext.createBuffer()
WebGLRenderingContext.deleteBuffer()
WebGLRenderingContext.isBuffer()
- 更详细的内容可以参考:WebGLBuffer - Web API 接口参考 | MDN (mozilla.org)
示例代码中:
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
GLsizeiptr
(en-US) 设定 Buffer 对象的数据存储区大小
-
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)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律