Loading...
提供基于 WebGL 1/2 和 WebGPU 的渲染能力,也包括基于 GPU 的拾取能力。内置 G 核心包提供的全部 2D 基础图形,同时暴露其他自定义 2D/3D 图形的扩展能力。
g-webgl
和 g-webgpu
渲染器默认内置,因此无需手动引入。
import { Renderer as WebGLRenderer } from '@antv/g-webgl';// 创建 WebGL 渲染器,其中内置了该插件const renderer = new WebGLRenderer();
它代表 GPU 设备(与之相对 Host 通常指指 CPU),提供统一的 HAL 硬件适配层供 WebGL 1/2 和 WebGPU 实现。在设计相关 API 时大量参考了 WebGPU 相关 API。
由于设备初始化可能为异步操作(例如 WebGPU 的 adapter.requestDevice()
),因此提供了两种获取 Device 方式:
import { CanvasEvent } from '@antv/g';// 监听画布准备就绪事件canvas.addEventListener(CanvasEvent.READY, () => {// 通过渲染器获取 Deviceconst plugin = renderer.getPlugin('device-renderer');const device = plugin.getDevice();});// 或者等待画布准备就绪await canvas.ready;// 通过渲染器获取 Deviceconst plugin = renderer.getPlugin('device-renderer');const device = plugin.getDevice();
获取 Device 之后可以使用它创建一系列 GPU 相关的资源,例如 Buffer、Texture 等。
Buffer 代表 GPU 操作中使用的一块内存,在创建时可以指定初始化数据,随后也可以对其中部分数据进行修改。数据以线性布局的方式存储。当需要在 CPU 侧(Host)读取其中的数据时,需要通过 Readback 完成。
export interface Buffer {setSubData(dstByteOffset: number,src: ArrayBufferView,srcByteOffset?: number,byteLength?: number,): void;destroy(): void;}
创建 Buffer 方式如下,需要指定:
interface Device {createBuffer(descriptor: BufferDescriptor): Buffer;}export interface BufferDescriptor {viewOrSize: ArrayBufferView | number;usage: BufferUsage;hint?: BufferFrequencyHint;}export enum BufferUsage {MAP_READ = 0x0001,MAP_WRITE = 0x0002,COPY_SRC = 0x0004,COPY_DST = 0x0008,INDEX = 0x0010,VERTEX = 0x0020,UNIFORM = 0x0040,STORAGE = 0x0080,INDIRECT = 0x0100,QUERY_RESOLVE = 0x0200,}export enum BufferFrequencyHint {Static = 0x01,Dynamic = 0x02,}
例如配合 g-plugin-gpgpu 使用时,用来分配输入和输出 Buffer:
const buffer = device.createBuffer({usage: BufferUsage.STORAGE | BufferUsage.COPY_SRC,viewOrSize: new Float32Array([1, 2, 3, 4]),});
例如修改 Uniform 中的某个变量,它位于原始 Buffer 中的第 20 个 bytes:
paramBuffer.setSubData(5 * Float32Array.BYTES_PER_ELEMENT,new Float32Array([maxDisplace]),);
释放 Buffer 资源。
buffer.destroy();
有时我们需要在 CPU 侧(Host)读取 GPU 侧(Device) Buffer 或者 Texture 中的数据,此时需要通过 Readback 对象实现,它提供异步读取方法。
interface Device {createReadback(): Readback;}
异步读取 Buffer 内容。
参数列表如下:
返回值为读取结果 ArrayBufferView。
export interface Readback {readBuffer(srcBuffer: Buffer,srcByteOffset?: number,dstBuffer?: ArrayBufferView,dstOffset?: number,length?: number,): Promise<ArrayBufferView>;}
例如配合 g-plugin-gpgpu
使用时,读取计算结果:
const result = await readback.readBuffer(resultBuffer); // Float32Array([...])
读取纹理内容。
参数列表如下:
返回值为读取结果 ArrayBufferView。
export interface Readback {readTexture(t: Texture,x: number,y: number,width: number,height: number,dstBuffer: ArrayBufferView,dstOffset?: number,length?: number,): Promise<ArrayBufferView>;}
例如在实现基于 GPU 颜色编码的拾取时:
const pickedColors = await readback.readTexture(this.pickingTexture,rect.x,rect.y,rect.width,rect.height,new Uint8Array(rect.width * rect.height * 4),);
释放 Readback 资源。
readback.destroy();
纹理是很常用的 GPU 资源。
export interface Texture {setImageData(data: TexImageSource | ArrayBufferView[]): void;}
interface Device {createTexture(descriptor: TextureDescriptor): Texture;}export interface TextureDescriptor {dimension: TextureDimension;pixelFormat: Format;width: number;height: number;depth: number;numLevels: number;usage: TextureUsage;pixelStore?: Partial<{packAlignment: number,unpackAlignment: number,unpackFlipY: boolean,}>;}
例如在加载图片成功后,设置纹理内容:
const image = new window.Image();image.onload = () => {// 设置纹理内容,以 Image 形式texture.setImageData(image);};image.onerror = () => {};image.crossOrigin = 'Anonymous';image.src = src;
释放 Texture 资源。
texture.destroy();
interface Device {createSampler(descriptor: SamplerDescriptor): Sampler;}export interface SamplerDescriptor {wrapS: WrapMode;wrapT: WrapMode;wrapQ?: WrapMode;minFilter: TexFilterMode;magFilter: TexFilterMode;mipFilter: MipFilterMode;minLOD?: number;maxLOD?: number;maxAnisotropy?: number;compareMode?: CompareMode;}
释放 Sampler 资源。
sampler.destroy();
有两种方式可以创建:
interface Device {createRenderTarget(descriptor: RenderTargetDescriptor): RenderTarget;createRenderTargetFromTexture(texture: Texture): RenderTarget;}export interface RenderTargetDescriptor {pixelFormat: Format;width: number;height: number;sampleCount: number;texture?: Texture;}
释放 RenderTarget 资源。
renderTarget.destroy();
interface Device {createProgram(program: ProgramDescriptor): Program;}export interface ProgramDescriptor {vert?: string;frag?: string;preprocessedVert?: string;preprocessedFrag?: string;preprocessedCompute?: string;}
释放 Program 资源。
program.destroy();
与 g-plugin-canvas-picker 和 g-plugin-svg-picker 这些基于 CPU 的拾取方案不同,我们使用使用一种基于 GPU 称作“颜色编码”的方式。
该方式包含以下步骤: