μλ νμΈμ, μ λ μ΄ λ©μμ§μ ν¨κ» troika-worker.utils.esm.jsμμ μ€λ λ§μ μμ κ²½κ³ λ₯Ό λ³΄κ³ μμ΅λλ€.
λͺ¨λ κ²μ΄ μ μλνλ κ² κ°μ§λ§
μ΄λ€ μκ°?
ν , ν΄λΉ κ²½κ³ λ 1000κ° μ΄μμ μ΄λ¦° μμ μ μμ²μ΄ μμ λκΉμ§ νΈλ¦¬κ±°λμ§ μμ΅λλ€. λ§€μ° λ§μ μμ ν μ€νΈ μΈμ€ν΄μ€κ° μμ΅λκΉ?
νμ§λ§ 1000μ λμ§ μμ΅λλ€(μ μ΄λ μλμ μΌλ‘λ μλ)
λͺλ°±κ° μ΄μ
μ¬κΈ° λ΄κ° λ λλ§νλ κ²μ΄ μμ΅λλ€
νμ§λ§ μ€μ λ‘ νμν κ²λ³΄λ€ λ λ§μ μΈμ€ν΄μ€λ₯Ό μμ±νκ³ 1000κ°λ₯Ό λμΌλ©΄ μ€λ₯κ° λ°μνκΈ° μμνλ λ²κ·Έκ° μλ€λ λ§μμ΄μ κ°μ?
λ΄μ©μ΄ μλ μΈμ€ν΄μ€λ₯Ό .visible = falseλ‘ μ€μ νμ΅λλ€.
κ·Έλ¬λ λλ κ·Έκ²μ΄ μ¬μ ν μΈμ€ν΄μ€κ° μ‘΄μ¬νλ€λ κ²μ μλ―Ένλ€κ³ μκ°ν©λλ€
μ¬μ©νμ§ μλ μΈμ€ν΄μ€λ₯Ό μμ ν μ κ±°νκΈ° μν΄ .visible μνμ μ¬μ©νλ λμ κΆμ₯νμκ² μ΅λκΉ?
μ, κ·Έκ±Έλ‘ μ€λͺ ν μ μκ² λ€μ. .sync() μ λν λͺ¨λ νΈμΆμ visible:false μΈ κ²½μ°μλ λ°±κ·ΈλΌμ΄λμμ μμ μμκ² κ³μ λ°νλλ©° λμ λ©λλ€.
λλ κ°μΈμ μΌλ‘ νμμ λ°λΌ λ μ΄λΈμ μμ±/νκΈ°νκ±°λ μ΅μν μ¨κ²¨μ§ λ μ΄λΈμ λν .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;
}
}
ν , λ΄ μ§κ°μ .visibleμ΄ falseλ‘ μ€μ λκΈ° μ μ syncIfVisible()μ΄ νΈμΆλκ³ μμ§λ§ λ·° μμ€ν μ΄ μ΄λ»κ² μλνλμ§ μμ§ μκ³ λ νμ€ν λ§νκΈ° μ΄λ ΅μ΅λλ€.
λ΄κ° μ£Όλͺ©νκ³ μλ λ λ€λ₯Έ μ μ λͺ¨λ κ°λ³ μμ± λ³κ²½(content, textAlign, horizontalAlign λ±) νμ syncIfVisible νΈμΆμ μ€ννμ¬ μμ μμκ² νμν κ²λ³΄λ€ λ λ§μ νΈμΆμ λ°ννλ€λ κ²μ λλ€. λ·° μμ€ν μ λͺ¨λ κ°λ³ μμ±μ΄ μ€μ λ ν λ¨μΌ λκΈ°ν νΈμΆμ μ€νν μ μλ μλͺ μ£ΌκΈ°κ° μλ κ²½μ° ν¨μ¬ λ μ’μ΅λλ€.
μ€λͺ νμ λ΄μ©μ 보면 μ΄ κ²½κ³ κ° μμλλ‘ μλνκ³ μλ€κ³ μκ°ν©λλ€. μ±λ₯ λ¬Έμ λ₯Ό μ¬λ°λ₯΄κ² κ°μ‘° νμνμ΅λλ€. μ΄ λ¬Έμ λ₯Ό λ«μ΅λλ€. λ€λ₯΄κ² μκ°νλ€λ©΄ μμ λ‘κ² λ€μ μ΄μ΄λ³΄μμμ€. κ°μ¬ ν΄μ!
μ΄λ§ λμκ°λ©΄
λ°λΌμ λ΄ μ₯λ©΄μ 1000κ° μ΄μμ ν μ€νΈ μΈμ€ν΄μ€κ° μλ κ²μΌλ‘ λνλ¬μ΅λλ€. κ·Έλ¬λ λμμ λͺ¨λ κ²μ΄ 보μ΄λ κ²μ μλλλ€.
κ·Έλ€ μ€ λλΆλΆμ νΉμ κ°μ²΄μ λ§μ°μ€λ₯Ό μ¬λ € λμμ λ λνλ©λλ€.
κ·Έλμ μμΌλ‘ κ°μ₯ μ’μ λ°©λ²μ΄ 무μμΈμ§ κΆκΈν©λλ€.
κ°μΈμ μΌλ‘λ 첫 λ²μ§Έ μ΅μ μ μ ννκ² μ΅λλ€. λ΄κ° ν릴 μλ μμ§λ§ μ₯λ©΄ κ·Έλνμ μ¨κ²¨μ§ λ μ΄λΈ κ°μ²΄κ° λͺ¨λ μ‘΄μ¬νλ κ²μ μ΄μ μ μλ€κ³ μκ°ν©λλ€.
μμλ€
κ°μ²΄λ₯Ό λ§μ°μ€λ‘ κ°λ¦¬ν¬ λ λΉ λ₯΄κ² νμν μ μμ΄μΌ ν©λλ€.
μ¬μ© νμ κ·Έλ₯ νκ΄΄νκ³ νΈλ²μμ μ νλͺ©μ λ§λλ κ²μ΄ μ’μ΅λλ€. μλλ©΄ λμ threeJ μ₯λ©΄μμ μ κ±°νμκ² μ΅λκΉ?
μμ§ν μ΄λ μͺ½μ΄λ λμ λλ μ°¨μ΄λ μμ κ²μ΄λΌκ³ μκ°ν©λλ€. λ¬Έμ λ₯Ό λ°κ²¬ν κ²½μ°μλ§ κ΄λ¦¬ λ° μ΅μ νκ° κ°μ₯ κ°λ¨ν κ²λΆν° μμνκ² μ΅λλ€.
κ°μΈμ μΌλ‘ λλ μμ±/νκ΄΄ μ κ·Ό λ°©μμ λ§μ΄ ν΄μκ³ , νμ λμκ² μΆ©λΆν λΉ λ¦ λλ€.