Skip to content

Multiple Buffers

Most built-in renderers interleave all data in a single buffer. This sample uses a renderer that stores color info in a separate buffer. Because only the color of the meshes is changed, only the color buffer is updated and uploaded to the GPU.

Code
ts
import { spawnInGrid } from '../../samples/generation';
import { buildAMesh } from '../../samples/shared';
import {
    CanvasApp,
    Color,
    MeshColorBatchEntry,
    MeshColorBatcher,
    MeshObject,
    TexturedMaterial,
    WGLDriver,
    WGLTexturedMeshColorBatchRenderer,
} from '../../src';

const BACKGROUND_COLOR = Color.fromHexString('#111');

interface Entity {
    mesh: MeshObject;
    entry?: MeshColorBatchEntry;
}

export class MultipleBuffersApp extends CanvasApp<WGLDriver> {
    private readonly meshRenderer = new WGLTexturedMeshColorBatchRenderer(
        this.driver,
    );

    private readonly meshBatches = new MeshColorBatcher(this.changeTracker);

    constructor(canvas: HTMLCanvasElement, driver: WGLDriver) {
        super(canvas, driver, 'always');
    }

    override async initialize(): Promise<void> {
        await super.initialize();

        this.meshBatches.setMaximums(this.driver.textures.maxTextureCount);

        const meshEntities: Entity[] = [];

        const mesh = buildAMesh();

        const total = spawnInGrid(60, 60, 688, 344, (i, x, y, tt) => {
            const ms = {
                mesh: new MeshObject({
                    mesh,
                    material: new TexturedMaterial(
                        this.driver.textures.white,
                        new Color(0.8, 0.8, 0.8),
                    ),
                    x: x - 304,
                    y: y - 117,
                    scale: 2,
                }),
            } as Entity;

            meshEntities.push(ms);
        });

        meshEntities.forEach(e => {
            e.entry = this.meshBatches.add(e.mesh);
            this.transforms.change(e.mesh);
        });

        this.tickers.add(() => {
            const index = Math.floor(Math.random() * total);

            const m = meshEntities[index]!;

            m.mesh.material.color.setHSV(
                Math.random() * 360,
                1 - Math.random() * 0.5,
                1 - Math.random() * 0.5,
            );

            m.entry!.onlyColorChanged = true;

            this.meshBatches.change(m.entry!);
        });
    }

    protected override render(): void {
        super.render();

        this.driver.useRenderTarget('canvas');

        this.driver.clear(BACKGROUND_COLOR);

        this.meshRenderer.render(this.meshBatches.finalize(), this.camera);
    }
}