Olá, estou vendo uma grande quantidade de avisos vindos do troika-worker.utils.esm.js com esta mensagem.
Tudo parece estar funcionando bem embora
qualquer ideia?
Hmm, esse aviso não é acionado até que haja mais de 1.000 solicitações de trabalho abertas. Você tem um número muito grande de instâncias de texto?
Eu faço, mas não mais de 1000 (pelo menos não intencionalmente)
mais como algumas centenas
Aqui está o que estou renderizando
Mas então o que você está dizendo que talvez haja um bug do meu lado onde eu crio mais instâncias do que eu realmente preciso e uma vez que eu cruzo a contagem de 1000, ele começa a gerar um erro?
Eu tenho configurado instâncias que não têm conteúdo para .visible = false
mas acho que isso ainda significa que a instância existe
você recomendaria em vez de usar a prop .visible para remover completamente as instâncias não utilizadas?
Ah, isso pode explicar. Quaisquer chamadas para .sync() ainda serão emitidas para o trabalhador em segundo plano, mesmo se visible:false , e elas se acumularão.
Eu acho que pessoalmente optaria por criar/descartar os rótulos sob demanda, ou pelo menos evitar chamadas .sync() para os ocultos. Todas essas solicitações de trabalhador usam o mesmo trabalhador, portanto, se estiver ocupado processando rótulos ocultos, isso poderá atrasar o processamento de seus visíveis.
Estou fazendo algumas suposições, porém, não tendo visto seu código exato do LabelView. Ainda é possível que haja um bug do meu lado, então LMK o que você encontra.
Apenas tentei chamar .sync() quando .visible === true
mas ainda recebendo os avisos
se, em vez disso, eu apenas criar instâncias para objetos visíveis e destruir os não utilizados, os avisos desaparecerão
Hmm, Text
si só chama sync() em onBeforeRender, que _não deveria_ acionar se visible=false.
O código do seu wrapper LabelView está disponível em qualquer lugar que eu possa dar uma olhada?
Faz parte de um projeto de código fechado
mas aqui está a classe relevante, que pode 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, meu palpite seria syncIfVisible() sendo chamado antes de .visible ser definido como false, mas é difícil dizer com certeza sem saber como seu sistema de visualização funciona.
Outra coisa que estou notando é que você está emitindo chamadas syncIfVisible após cada alteração de propriedade individual (content, textAlign, horizontalAlign, etc.) que emitirá mais chamadas para o trabalhador do que o necessário. Se o seu sistema de visualização tiver um ciclo de vida em que você possa emitir uma única chamada de sincronização depois que todas as propriedades individuais forem definidas, isso seria muito melhor.
Pelo que você descreveu, acho que esse aviso está se comportando conforme o esperado; ele destacou corretamente um problema de desempenho. Estou encerrando este assunto; sinta-se à vontade para reabri-lo se você acredita de forma diferente. Obrigado!
Apenas voltando a isso
Então acontece que eu facilmente tenho mais de 1000 instâncias de texto na minha cena. Mas nem todos são visíveis ao mesmo tempo
Muitos deles aparecem apenas ao passar o mouse sobre certos objetos
Então eu estou querendo saber qual é o melhor caminho a seguir aqui:
Pessoalmente, eu iria para a primeira opção. Posso estar errado, mas não acho que haja nenhum benefício em ter todos esses objetos de rótulo ocultos presentes no gráfico de cena.
Entendi
Eu preciso ser capaz de mostrá-los rapidamente ao passar o mouse sobre objetos
Você recomendaria apenas destruí-los após o uso e criar novos ao passar o mouse ou apenas removê-los da cena dos três Js?
Honestamente, não acho que haverá uma diferença notável de qualquer maneira. Eu começaria com o que for mais simples de gerenciar e otimizar somente se você notar um problema.
Pessoalmente, eu fiz muito a abordagem de criar/destruir, e é sempre muito rápido para mim.