Skip to content

UIPerformance2


WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

ts
import { AtmosphericComponent, BoundingBox, CameraUtil, Color, DirectLight, Engine3D, GUIConfig, GUIQuad, HoverCameraController, KelvinUtil, Object3D, Scene3D, TextAnchor, UIImageGroup, UITextField, Vector2, Vector3, View3D, ViewPanel, clamp, webGPUContext } from '@orillusion/core';
import { Stats } from '@orillusion/stats';
import * as dat from 'dat.gui';

class SpriteSheet {
    public static toggleMove: boolean = false;
    public static toggleAnim: boolean = true;

    private imgGroup: UIImageGroup;
    private lastIndex: number = -1;
    private frame: number = 100 * Math.random();
    private frameSpeed: number = 0.5 + Math.random();
    private frameCount = 13;
    private keyFrames: string[];
    private moveSpeed: Vector2;
    private bound: BoundingBox;
    private index: number;

    private quad: GUIQuad;
    constructor(img: UIImageGroup, index: number, keyFrames: string[], bound: BoundingBox) {
        this.imgGroup = img;
        this.index = index;
        this.bound = bound;
        this.keyFrames = keyFrames;
        this.moveSpeed = new Vector2(Math.random() - 0.5, Math.random() - 0.5);
        this.quad = img.getQuad(index);
    }

    updateFrame(): void {
        if (SpriteSheet.toggleAnim) {
            this.frame += this.frameSpeed;
            let newIndex = Math.floor(this.frame * 0.1) % this.frameCount;
            if (newIndex != this.lastIndex) {
                this.lastIndex = newIndex;
                this.imgGroup.setSprite(this.index, Engine3D.res.getGUISprite(this.keyFrames[newIndex]));
            }
        }

        if (SpriteSheet.toggleMove) {
            let x = this.quad.x;
            let y = this.quad.y;
            x += this.moveSpeed.x;
            y += this.moveSpeed.y;
            if (x < this.bound.min.x || x > this.bound.max.x) {
                this.moveSpeed.x *= -1;
            }
            if (y < this.bound.min.y || y > this.bound.max.y) {
                this.moveSpeed.y *= -1;
            }
            this.imgGroup.setXY(this.index, x, y);
        }
    }
}

class Sample_UIPerformance2 {
    text: UITextField;
    scene: Scene3D;
    keyFrames: string[];

    async run() {
        Engine3D.setting.shadow.autoUpdate = true;
        GUIConfig.quadMaxCountForView = 5001;

        this.spriteSheets = [];
        this.keyFrames = [];
        let frameStart = 65; //65~77
        for (let i = 0; i < 13; i++) {
            this.keyFrames.push((frameStart + i).toString().padStart(5, '0'));
        }

        await Engine3D.init({
            renderLoop: () => {
                this.renderUpdate();
            }
        });
        // init Scene3D
        this.scene = new Scene3D();
        this.scene.addComponent(Stats);

        // init sky
        let atmosphericSky: AtmosphericComponent;
        atmosphericSky = this.scene.addComponent(AtmosphericComponent);

        // init Camera3D
        let camera = CameraUtil.createCamera3DObject(this.scene);
        camera.perspective(60, Engine3D.aspect, 1, 5000);

        // init Camera Controller
        let hoverCtrl = camera.object3D.addComponent(HoverCameraController);
        hoverCtrl.setCamera(-30, -15, 100);

        // init View3D
        let view = new View3D();
        view.scene = this.scene;
        view.camera = camera;

        // create direction light
        let lightObj3D = new Object3D();
        lightObj3D.x = 0;
        lightObj3D.y = 30;
        lightObj3D.z = -40;
        lightObj3D.rotationX = 20;
        lightObj3D.rotationY = 160;
        lightObj3D.rotationZ = 0;

        let light = lightObj3D.addComponent(DirectLight);
        light.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
        light.castShadow = true;
        light.intensity = 30;

        this.scene.addChild(light.object3D);

        // relative light to sky
        atmosphericSky.relativeTransform = light.transform;

        Engine3D.startRenderView(view);

        await Engine3D.res.loadAtlas('https://cdn.orillusion.com/atlas/Sheet_atlas.json');
        await Engine3D.res.loadFont('https://cdn.orillusion.com/fnt/0.fnt');

        this.text = this.createText();
        this.addLotOfSprite();

        let gui = new dat.GUI();
        gui.add(SpriteSheet, 'toggleMove');
        gui.add(SpriteSheet, 'toggleAnim');
        gui.add(
            {
                add: () => {
                    if (this.spriteSheets.length < 99999) {
                        this.addLotOfSprite();
                    }
                }
            },
            'add'
        );
    }

    addLotOfSprite() {
        // enable ui canvas at index 0
        let canvas = this.scene.view.enableUICanvas(0);
        //create UI root
        let panelRoot: Object3D = new Object3D();
        //create panel
        let panel = panelRoot.addComponent(ViewPanel);
        canvas.addChild(panel.object3D);
        //create sprite sheet list
        this.createSpriteSheets(panelRoot);
    }

    createText(): UITextField {
        let canvas = this.scene.view.enableUICanvas(0);
        //create UI root
        let panelRoot: Object3D = new Object3D();
        //create panel
        let panel = panelRoot.addComponent(ViewPanel);
        panel.panelOrder = 10000;
        canvas.addChild(panel.object3D);
        let textQuad = new Object3D();
        panelRoot.addChild(textQuad);
        let text = textQuad.addComponent(UITextField);
        text.uiTransform.resize(400, 60);

        text.fontSize = 24;
        text.alignment = TextAnchor.MiddleCenter;

        return text;
    }

    spriteSheets: SpriteSheet[];

    private createSpriteSheets(root: Object3D) {
        let width = Engine3D.width;
        let height = Engine3D.height;
        let bound = new BoundingBox(new Vector3(0, 0, 0), new Vector3(width, height));
        //color
        let color: Color = Color.random();
        color.a = 1;
        color.r = clamp(color.r * 1.5, 0.5, 1);
        color.g = clamp(color.g * 1.5, 0.5, 1);
        color.b = clamp(color.b * 1.5, 0.5, 1);

        let sprite = Engine3D.res.getGUISprite('00065');

        let size = 64;
        let halfSize = size * 0.5;
        let groupNode = new Object3D();
        root.addChild(groupNode);
        let imgGroup = groupNode.addComponent(UIImageGroup, { count: 5000 });
        for (let i = 0; i < 5000; i++) {
            imgGroup.setColor(i, color);
            imgGroup.setSprite(i, sprite);
            imgGroup.setSize(i, size, size);
            imgGroup.setXY(i, (Math.random() - 0.5) * width - halfSize, (Math.random() - 0.5) * height - halfSize);
            let sheet: SpriteSheet = new SpriteSheet(imgGroup, i, this.keyFrames, bound);
            this.spriteSheets.push(sheet);
        }

        this.text.text = this.spriteSheets.length.toString() + ' Sprites';
    }

    renderUpdate() {
        for (const item of this.spriteSheets) {
            item.updateFrame();
        }
    }
}

new Sample_UIPerformance2().run();