Troika: "λ§Žμ€ 수의 μ—΄λ € μžˆλŠ” WorkerModule μš”μ²­, μΌλΆ€λŠ” λ°˜ν™˜λ˜μ§€ μ•Šμ„ 수 있음" κ²½κ³ 

에 λ§Œλ“  2021λ…„ 03μ›” 30일  Β·  14μ½”λ©˜νŠΈ  Β·  좜처: protectwise/troika

μ•ˆλ…•ν•˜μ„Έμš”, μ €λŠ” 이 λ©”μ‹œμ§€μ™€ ν•¨κ»˜ troika-worker.utils.esm.jsμ—μ„œ μ˜€λŠ” λ§Žμ€ μ–‘μ˜ κ²½κ³ λ₯Ό 보고 μžˆμŠ΅λ‹ˆλ‹€.

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

λͺ¨λ“  것이 잘 μž‘λ™ν•˜λŠ” 것 κ°™μ§€λ§Œ

μ–΄λ–€ 생각?

λͺ¨λ“  14 λŒ“κΈ€

흠, ν•΄λ‹Ή κ²½κ³ λŠ” 1000개 μ΄μƒμ˜ μ—΄λ¦° μž‘μ—…μž μš”μ²­μ΄ μžˆμ„ λ•ŒκΉŒμ§€ νŠΈλ¦¬κ±°λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 맀우 λ§Žμ€ 수의 ν…μŠ€νŠΈ μΈμŠ€ν„΄μŠ€κ°€ μžˆμŠ΅λ‹ˆκΉŒ?

ν•˜μ§€λ§Œ 1000을 λ„˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€(적어도 μ˜λ„μ μœΌλ‘œλŠ” μ•„λ‹˜)

λͺ‡λ°±κ°œ 이상

μ—¬κΈ° λ‚΄κ°€ λ Œλ”λ§ν•˜λŠ” 것이 μžˆμŠ΅λ‹ˆλ‹€

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

ν•˜μ§€λ§Œ μ‹€μ œλ‘œ ν•„μš”ν•œ 것보닀 더 λ§Žμ€ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜κ³  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개 μ΄μƒμ˜ ν…μŠ€νŠΈ μΈμŠ€ν„΄μŠ€κ°€ μžˆλŠ” κ²ƒμœΌλ‘œ λ‚˜νƒ€λ‚¬μŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ™μ‹œμ— λͺ¨λ“  것이 λ³΄μ΄λŠ” 것은 μ•„λ‹™λ‹ˆλ‹€.

κ·Έλ“€ 쀑 λŒ€λΆ€λΆ„μ€ νŠΉμ • κ°œμ²΄μ— 마우슀λ₯Ό 올렀 λ†“μ•˜μ„ λ•Œ λ‚˜νƒ€λ‚©λ‹ˆλ‹€.

κ·Έλž˜μ„œ μ•žμœΌλ‘œ κ°€μž₯ 쒋은 방법이 무엇인지 κΆκΈˆν•©λ‹ˆλ‹€.

  1. λ³΄μ΄λŠ” ν…μŠ€νŠΈμ— λŒ€ν•΄μ„œλ§Œ μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“  λ‹€μŒ 보이지 μ•Šκ²Œ 되자마자 마운트λ₯Ό ν•΄μ œν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?
  2. λŒ€μ‹  ThreeJS CSS 객체λ₯Ό μ‚¬μš©ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?

κ°œμΈμ μœΌλ‘œλŠ” 첫 번째 μ˜΅μ…˜μ„ μ„ νƒν•˜κ² μŠ΅λ‹ˆλ‹€. λ‚΄κ°€ 틀릴 μˆ˜λŠ” μžˆμ§€λ§Œ μž₯λ©΄ κ·Έλž˜ν”„μ— μˆ¨κ²¨μ§„ λ ˆμ΄λΈ” κ°œμ²΄κ°€ λͺ¨λ‘ μ‘΄μž¬ν•˜λŠ” κ²ƒμ˜ 이점은 μ—†λ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

μ•Œμ•˜λ‹€

개체λ₯Ό 마우슀둜 가리킬 λ•Œ λΉ λ₯΄κ²Œ ν‘œμ‹œν•  수 μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€.

μ‚¬μš© 후에 κ·Έλƒ₯ νŒŒκ΄΄ν•˜κ³  ν˜Έλ²„μ—μ„œ μƒˆ ν•­λͺ©μ„ λ§Œλ“œλŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€. μ•„λ‹ˆλ©΄ λŒ€μ‹  threeJ μž₯λ©΄μ—μ„œ μ œκ±°ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?

μ†”μ§νžˆ μ–΄λŠ μͺ½μ΄λ“  λˆˆμ— λ„λŠ” μ°¨μ΄λŠ” 없을 것이라고 μƒκ°ν•©λ‹ˆλ‹€. 문제λ₯Ό λ°œκ²¬ν•œ κ²½μš°μ—λ§Œ 관리 및 μ΅œμ ν™”κ°€ κ°€μž₯ κ°„λ‹¨ν•œ 것뢀터 μ‹œμž‘ν•˜κ² μŠ΅λ‹ˆλ‹€.

개인적으둜 λ‚˜λŠ” 생성/파괴 μ ‘κ·Ό 방식을 많이 ν•΄μ™”κ³ , 항상 λ‚˜μ—κ²Œ μΆ©λΆ„νžˆ λΉ λ¦…λ‹ˆλ‹€.

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰