您好,我看到来自 troika-worker.utils.esm.js 的大量警告以及此消息。
一切似乎都运行良好
任何想法?
嗯,直到有超过 1000 个打开的工作请求时才会触发该警告。 你有大量的文本实例吗?
我有,但不超过 1000(至少不是故意的)
更像是几百
这是我正在渲染的
但是,您所说的也许是我这边有一个错误,我创建的实例比我实际需要的多,一旦我超过 1000 个计数,它就会开始抛出错误?
我一直在将没有内容的实例设置为 .visible = false
但我想这仍然意味着实例存在
您会建议不要使用 .visible 道具来完全删除未使用的实例吗?
啊,这可以解释。 即使visible:false ,任何对 .sync() 的调用仍将在后台发送给工作人员,并且它们会堆积起来。
我确实认为我个人会选择按需创建/处置标签,或者至少防止 .sync() 调用隐藏的标签。 这些工作人员请求都使用同一个工作人员,因此如果它忙于处理隐藏标签,那么这可能会延迟对可见标签的处理。
不过,我正在做一些假设,但没有看到您确切的 LabelView 代码。 我仍然可能有一个错误,所以LMK你发现了什么。
只是尝试仅在 .visible === true 时调用 .sync()
但仍然收到警告
相反,如果我只为可见对象创建实例并销毁未使用的对象,那么警告就会消失
嗯, Text
本身仅在 onBeforeRender 中调用 sync(),如果 visible=false,则_不应该_触发。
您的 LabelView 包装器代码在我可以窥视的任何地方都可用吗?
它是封闭源代码项目的一部分
但这是相关的课程,可能就足够了
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;
}
}
嗯,我的预感是 syncIfVisible() 在 .visible 设置为 false 之前被调用,但如果不知道您的视图系统如何工作,就很难确定。
我注意到的另一件事是,您在每个单独的属性更改(内容、textAlign、horizontalAlign 等)之后发出 syncIfVisible 调用,这将向工作人员发出不必要的调用。 如果您的视图系统有一个生命周期,您可以在设置所有单个属性后发出单个同步调用,那会好得多。
根据您的描述,我认为此警告的行为符合预期; 它正确地突出了性能问题。 我要结束这个问题; 如果您有不同的看法,请随时重新打开它。 谢谢!
刚刚回到这个
所以事实证明,我的场景中轻松拥有超过 1000 个文本实例。 但并不是所有的都同时可见
它们中的许多只是出现在某些对象的鼠标悬停上
所以我想知道最好的前进方式是什么:
就我个人而言,我会选择第一个选项。 我可能是错的,但我认为将所有这些隐藏的标签对象都存在于场景图中没有任何好处。
知道了
我需要能够在对象的鼠标悬停时快速显示它们
您是否建议在使用后将它们销毁并在悬停时创建新的,或者只是将它们从 threeJs 场景中删除?
老实说,我认为这两种方式都不会有明显的差异。 只有当您发现问题时,我才会从最简单的管理和优化开始。
就我个人而言,我已经做了很多创建/销毁方法,而且它对我来说总是很活泼。