Troika: Advertencia "Gran cantidad de solicitudes WorkerModule abiertas, es posible que algunas no regresen"

Creado en 30 mar. 2021  ·  14Comentarios  ·  Fuente: protectwise/troika

Hola, estoy viendo una gran cantidad de advertencias provenientes de troika-worker.utils.esm.js con este mensaje.

Screen Shot 2021-03-29 at 8 19 42 PM

Aunque todo parece funcionar bien

¿alguna idea?

Todos 14 comentarios

Hmm, esa advertencia no se activa hasta que haya más de 1000 solicitudes de trabajadores abiertas. ¿Tiene una gran cantidad de instancias de texto?

Sí, pero no más de 1000 (al menos no intencionalmente)

más como un par de cientos

Esto es lo que estoy representando

Screen Shot 2021-03-30 at 11 03 39 AM

Pero entonces, ¿qué está diciendo que tal vez haya un error de mi parte en el que creo más instancias de las que realmente necesito y una vez que cruzo el conteo de 1000 comienza a arrojar un error?

He estado configurando instancias que no tienen contenido en .visible = false

pero supongo que eso todavía significa que la instancia existe

¿Recomendaría en lugar de usar el accesorio .visible para eliminar por completo las instancias no utilizadas?

Ahh, eso podría explicarlo. Todas las llamadas a .sync() aún se emitirán al trabajador en segundo plano, incluso si están visibles:falso , y se acumularán.

Creo que personalmente optaría por crear/eliminar las etiquetas a pedido, o al menos evitar las llamadas .sync() para las ocultas. Todas esas solicitudes de trabajadores usan el mismo trabajador, por lo que si está ocupado procesando etiquetas ocultas, eso podría retrasar el procesamiento de las visibles.

Sin embargo, estoy haciendo algunas suposiciones, sin haber visto su código exacto de LabelView. Todavía es posible que haya un error de mi parte, así que LMK lo que encuentre.

Acabo de intentar llamar solo a .sync() cuando .visible === verdadero

pero sigo recibiendo las advertencias

si, en cambio, solo creo instancias para objetos visibles y destruyo los no utilizados, las advertencias desaparecen

Hmm, Text solo llama a sync() en onBeforeRender, que _no_ debería activarse si es visible=falso.

¿Está disponible su código de envoltorio de LabelView en algún lugar donde pueda echar un vistazo?

Es parte de un proyecto de código cerrado.

pero aquí está la clase relevante, que podría ser suficiente

import {Mesh, MeshBasicMaterial} from "three";
import R from "../../../../../../../../../../resources/Namespace";
import BaseView, {ViewType} from "./BaseView";
import {Text} from "troika-three-text";
import {GeometryInstances} from "../instances/GeometryInstances";
import {MaterialInstances} from "../instances/MaterialInstances";

export enum TextAlign {
    left = "left",
    right = "right",
    center = "center",
    justify = "justify",
}

export enum HorizontalAlign {
    left = "left",
    right = "right",
    center = "center",
}

export enum VerticalAlign {
    top = "top",
    topBaseline = "top-baseline",
    middle = "middle",
    bottomBaseline = "bottom-baseline",
    bottom = "bottom",
}

export interface ILabelData {
    content: string;
    fontFace?: string;
    fontSize?: number;
    alignment?: TextAlign;
    horizontalAlign?: HorizontalAlign;
    verticalAlign?: VerticalAlign;
    color?: string;
    opacity?: number;
    backgroundColor?: string;
    highlightable: boolean;
}

export default class LabelView extends BaseView {
    get viewObject() {
        return this._viewObject as any;
    }

    get content() {
        return this.textMesh.text;
    }

    set content(content: string) {
        if (content !== this.textMesh.text) {
            this.textMesh.text = content;
            this.textMesh.visible = !!content;

            this.syncIfVisible();
        }
    }

    private syncIfVisible() {
        // Better for perf: https://github.com/protectwise/troika/issues/112
        if (this.textMesh?.text && this.textMesh?.visible && this._isVisible) {
            this.textMesh.sync();
        }
    }

    set textAlign(alignment: TextAlign) {
        this.textMesh.textAlign = alignment;
        this.syncIfVisible();
    }

    set horizontalAlign(alignment: HorizontalAlign) {
        this.textMesh.anchorX = alignment;
        this.syncIfVisible();
    }

    set verticalAlign(alignment: VerticalAlign) {
        this.textMesh.anchorY = alignment;
        this.syncIfVisible();
    }

    private backgroundMesh: Mesh | undefined;
    private readonly textMesh: any;
    private readonly foregroundColor: string;
    private highlightable: boolean;

    constructor(labelData: ILabelData) {
        super(ViewType.Label);

        this.foregroundColor = labelData.color || R.colors.elements.labels.foreground;

        this.highlightable = labelData.highlightable;

        if (labelData.backgroundColor) {
            this.textMesh = this.createTextMesh(
                labelData.content,
                labelData.fontFace,
                labelData.fontSize,
                labelData.alignment,
                labelData.horizontalAlign,
                labelData.verticalAlign,
                this.foregroundColor,
                labelData.opacity,
                1);

            this.textMesh.addEventListener("synccomplete", () => {
                if (this.backgroundMesh) {
                    this._viewObject.remove(this.backgroundMesh);
                }

                if (this.textMesh.text) {
                    const bounds = this.textMesh.textRenderInfo.blockBounds;
                    this.backgroundMesh =
                        this.createBackgroundBox(bounds[0], bounds[1], bounds[2], bounds[3], 0);
                    this._viewObject.add(this.backgroundMesh);
                }
            });

        } else {
            this.textMesh = this.createTextMesh(
                labelData.content,
                labelData.fontFace,
                labelData.fontSize,
                labelData.alignment,
                labelData.horizontalAlign,
                labelData.verticalAlign,
                this.foregroundColor,
                labelData.opacity,
                0);
        }

        this.syncIfVisible();

        this._viewObject.add(this.textMesh);
    }

    public onFrameRendered(elapsedTime: number) {
        if (this.highlightable) {
            this.setLabelHighlightState();
        }
    }

    private setLabelHighlightState() {
        const labelMaterial = this.textMesh.material as MeshBasicMaterial;
        if (this._isHighlighted) {
            labelMaterial.color.set(R.colors.elements.labels.highlighted);
        } else {
            labelMaterial.color.set(this.foregroundColor);
        }
    }

    private createTextMesh(content: string,
                           fontFace = R.layout.labels.font_face.regular,
                           fontSize = R.layout.labels.font_size,
                           textAlign = TextAlign.center,
                           horizontalAlign = HorizontalAlign.center,
                           verticalAlign = VerticalAlign.middle,
                           color: string,
                           opacity = 1,
                           zLevel: number) {
        const labelMesh = new Text();

        labelMesh.font = fontFace;
        labelMesh.text = content || "";
        labelMesh.fontSize = fontSize;
        labelMesh.position.z = zLevel;
        labelMesh.color = color;
        labelMesh.textAlign = textAlign;
        labelMesh.anchorX = horizontalAlign;
        labelMesh.anchorY = verticalAlign;

        labelMesh.material.opacity = opacity;
        labelMesh.name = "LabelView";

        return labelMesh;
    }

    private createBackgroundBox(startX: number, startY: number, endX: number, endY: number, zLevel: number) {
        const paddingLeft = 1;
        const paddingRight = 2;
        const paddingTop = 1;
        const paddingBottom = 0;

        const width = Math.abs(startX) + Math.abs(endX) + paddingLeft + paddingRight;
        const height = Math.abs(startY) + Math.abs(endY) + (paddingTop + paddingBottom);

        const geometry = GeometryInstances.getInstance().getPlaneGeometryInstance(width, height);
        const material = MaterialInstances.getInstance().backgroundColorMaterial;
        const mesh = new Mesh(geometry, material);

        const posX = ((startX + endX) / 2) + (paddingLeft / 4);
        const posY = ((startY + endY) / 2) - (paddingBottom);

        // The z level of element in accordance with standards defined in resources
        mesh.position.set(posX, posY, zLevel);
        mesh.name = "LabelBackgroundBox";

        return mesh;
    }
}

Hmm, mi corazonada sería syncIfVisible() está siendo llamado antes de que .visible se establezca en falso, pero es difícil decirlo con seguridad sin saber cómo funciona su sistema de visualización.

Otra cosa que estoy notando es que está emitiendo llamadas syncIfVisible después de cada cambio de propiedad individual (contenido, textAlign, horizontalAlign, etc.) que emitirá más llamadas al trabajador de las necesarias. Si su sistema de visualización tiene un ciclo de vida en el que puede emitir una sola llamada de sincronización después de configurar todas las propiedades individuales, eso sería mucho mejor.

Por lo que ha descrito, creo que esta advertencia se está comportando como se esperaba; destacó correctamente un problema de rendimiento. Doy por cerrado este tema; siéntete libre de reabrirlo si crees lo contrario. ¡Gracias!

Solo volviendo a esto

Resulta que fácilmente tengo más de 1000 instancias de texto en mi escena. Pero no todos son visibles al mismo tiempo.

Muchos de ellos simplemente aparecen al pasar el mouse sobre ciertos objetos.

Así que me pregunto cuál es la mejor manera de avanzar aquí:

  1. crear instancias solo para texto visible y luego desmontar tan pronto como se vuelva invisible?
  2. ¿Usar objetos ThreeJS CSS en su lugar?

Personalmente me decantaría por la primera opción. Podría estar equivocado, pero no creo que haya ningún beneficio en tener todos esos objetos de etiqueta ocultos presentes en el gráfico de escena.

Entiendo

Necesito poder mostrarlos rápidamente al pasar el mouse sobre los objetos.

¿Recomendaría simplemente destruirlos después de usarlos y crear otros nuevos al pasar el mouse por encima o simplemente eliminarlos de la escena de los tres J?

Honestamente, no creo que vaya a haber una diferencia notable de cualquier manera. Comenzaría con lo que sea más simple de administrar y optimizar solo si nota un problema.

Personalmente, he hecho mucho el enfoque de creación/destrucción, y siempre es bastante rápido para mí.

¿Fue útil esta página
0 / 5 - 0 calificaciones