Detaillierter Prozess zum Zeichnen dreidimensionaler Pfeillinien mit three.js

Detaillierter Prozess zum Zeichnen dreidimensionaler Pfeillinien mit three.js

Nachfrage: Diese Nachfrage ist ein dringender Bedarf! In einer U-Bahn-Szene muss ein Fluchtweg mit einem Pfeil angezeigt werden, der den Weg anzeigt. Ich habe nicht weniger als ein Dutzend Stunden gebraucht, um diesen Pfeil zu zeichnen, und ich war schließlich fertig, aber es gab noch ein Problem. Meine Anforderung an diesen Pfeil ist, dass er, egal ob in der Szene hinein- oder herausgezoomt wird, weder zu groß noch zu klein sein darf, um deutlich erkannt zu werden, und dass sich seine Form nicht ändern darf, da er sonst nicht wie ein Pfeil aussieht.

Verwendet Line2.js von three.js und eine Open-Source-Bibliothek MeshLine.js

Teil des Codes:

DrawPath.js:

/**
 * Zeichne eine Route */

importiere * als DREI aus „../build/three.module.js“;
importiere { MeshLine, MeshLineMaterial, MeshLineRaycast } aus '../js.my/MeshLine.js';

importiere { Line2 } aus '../js/lines/Line2.js';
importiere { LineMaterial } aus '../js/lines/LineMaterial.js';
importiere { LineGeometry } aus '../js/lines/LineGeometry.js';
importiere { GeometryUtils } aus '../js/utils/GeometryUtils.js';

importiere { CanvasDraw } von '../js.my/CanvasDraw.js';

importiere { Utils } von '../js.my/Utils.js';
importiere { Msg } von '../js.my/Msg.js';

let DrawPath = Funktion () {

    lass _self = dies;

    let _canvasDraw = neues CanvasDraw();
    Utils();
    let msg = neue Msg();

    dies._isDrawing = falsch;
    dieser._Pfad = [];
    diese._zeilen = [];
    diese._arrows = [];

    Lassen Sie _depthTest = true;
    lass _side = 0;

    let viewerContainerId = '#cc';
    let viewerContainer = $(viewerContainerId)[0];

    Objekte lassen;
    lass die Kamera;
    lass dich wenden;
    lass Szene;

    this.config = Funktion (Objekte_, Kamera_, Szene_, Drehung_) {
        Objekte = Objekte_;
        Kamera = Kamera_;
        drehen = drehen_;
        Szene = Szene_;

        this._oldDistance = 1;
        this._oldCameraPos = { x: Kamera.position.x, y: Kamera.position.y, z: Kamera.position.z }
    }

    dies.start = Funktion () {
        wenn (!this._isDrawing) {
            dies._isDrawing = wahr;
            viewerContainer.addEventListener('klicken', ray);
            viewerContainer.addEventListener('Maus nach unten', Maus nach unten);
            viewerContainer.addEventListener('Maus hoch', Maus hoch);
        }
        msg.show("Bitte klicken Sie auf den Boden, um die Linie zu zeichnen");
    }

    dies.stop = Funktion () {
        wenn (this._isDrawing) {
            dies._isDrawing = falsch;
            viewerContainer.removeEventListener('klicken', ray);
            viewerContainer.addEventListener('Maus nach unten', Maus nach unten);
            viewerContainer.addEventListener('Maus hoch', Maus hoch);
        }
        msg.show("Linienzeichnung beenden");
    }

    Funktion mousedown(params) {
        this._mousedownPosition = { x: Kamera.position.x, y: Kamera.position.y, z: Kamera.position.z }
    }

    Funktion mouseup(Parameter) {
        this._mouseupPosition = { x: Kamera.position.x, y: Kamera.position.y, z: Kamera.position.z }
    }

    Funktion Strahl(e) {
        schalte.unFocusButton();

        let raycaster = createRaycaster(e.clientX, e.clientY);
        lass intersects = raycaster.intersectObjects(Objekte.alle);
        wenn (Schnittpunkt.Länge > 0) {
            lass Punkt = schneidet[0].Punkt;

            lass Abstand = utils.abstand(diese._mousedownPosition.x, diese._mousedownPosition.y, diese._mousedownPosition.z, diese._mouseupPosition.x, diese._mouseupPosition.y, diese._mouseupPosition.z);

            wenn (Abstand < 5) {
                _self._path.push({ x: Punkt.x, y: Punkt.y + 50, z: Punkt.z });

                wenn (_self._path.length > 1) {
                    lass Punkt1 = _self._Pfad[_self._Pfad.Länge - 2];
                    lass Punkt2 = _self._path[_self._path.length - 1];

                    zeichneLinie(Punkt1, Punkt2);
                    zeichnePfeil(Punkt1, Punkt2);
                }
            }
        }
    }

    Funktion erstelleRaycaster(ClientX, ClientY) {
        sei x = (ClientX / $(viewerContainerId).width()) * 2 - 1;
        sei y = -(clientY / $(viewerContainerId).height()) * 2 + 1;

        sei Standardvektor = neuer DREI.Vektor3(x, y, 0,5);

        lass worldVector = standardVector.unproject(Kamera);

        lass ray = worldVector.sub(camera.position).normalize();

        lass raycaster = neu THREE.Raycaster(Kameraposition, Strahl);

        Raycaster zurückgeben;
    }

    dies.refresh = Funktion () {
        wenn (_self._path.length > 1) {
            lass Abstand = utils.abstand(diese._alteKameraPos.x, diese._alteKameraPos.y, diese._alteKameraPos.z, Kamera.position.x, Kamera.position.y, Kamera.position.z);
            sei das Verhältnis = 1;
            wenn (this._oldDistance != 0) {
                Verhältnis = Math.abs((this._oldDistance - Entfernung) / this._oldDistance)
            }

            wenn (Abstand > 5 && Verhältnis > 0,1) {
                console.log("======= DrawPath-Aktualisierung= ...
                für (lass i = 0; i < _self._path.length - 1; i++) {
                    lass Pfeil = _self._arrows[i];
                    lass Punkt1 = _self._Pfad[i];
                    lass Punkt2 = _self._Pfad[i + 1];
                    Pfeil aktualisieren(Punkt1, Punkt2, Pfeil);
                }
                this._oldDistance = Entfernung;
                this._oldCameraPos = { x: Kamera.position.x, y: Kamera.position.y, z: Kamera.position.z }
            }
        }
    }

    Funktion zeichneLinie(Punkt1, Punkt2) {
        const Positionen = [];

        Positionen.Push(Punkt1.x / 50, Punkt1.y / 50, Punkt1.z / 50);
        Positionen.Push(Punkt2.x / 50, Punkt2.y / 50, Punkt2.z / 50);

        let geometrie = neue LineGeometry();
        geometrie.setPositions(Positionen);

        let matLine = neues Linienmaterial({
            Farbe: 0x009900,
            Linienbreite: 0,003, // in Welteinheiten mit Größendämpfung, andernfalls Pixel
            gestrichelt: wahr,
            Tiefentest: _Tiefentest,
            Seite: _Seite
        });

        lass Linie = neue Linie2(Geometrie, matLine);
        line.computeLineDistances();
        Linie.Skala.Satz(50, 50, 50);

        Szene.Hinzufügen(Zeile);
        _self._lines.push(Zeile);

    }

    Funktion zeichnePfeil(Punkt1, Punkt2) {
        let arrowLine = _self.createArrowLine(punkt1, punkt2);
        var meshLine = Pfeillinie.meshLine;

        let canvasTexture = _canvasDraw.drawArrow(DREI, Renderer, 300, 100); //Pfeil var Material = neues MeshLineMaterial({
            useMap: wahr,
            Karte: CanvasTexture,
            Farbe: neue THREE.Color(0x00f300),
            Deckkraft: 1,
            Auflösung: neuer THREE.Vector2($(viewerContainerId).width(), $(viewerContainerId).height()),
            Linienbreite: Pfeillinie.Linienbreite,
            Tiefentest: _Tiefentest,
            Seite: _Seite,
            Wiederholung: new THREE.Vector2(1, 1),
            transparent: wahr,
            GrößeDämpfung: 1
        });

        var mesh = neues THREE.Mesh(meshLine.geometry, material);
        mesh.scale.set(50, 50, 50);
        Szene.Hinzufügen(Netz);
        _self._arrows.push(Netz);

    }

    Funktion RefreshArrow(Punkt1, Punkt2, Pfeil) {
        let arrowLine = _self.createArrowLine(punkt1, punkt2);
        var meshLine = Pfeillinie.meshLine;

        let canvasTexture = _canvasDraw.drawArrow(DREI, Renderer, 300, 100); //Pfeil var Material = neues MeshLineMaterial({
            useMap: wahr,
            Karte: CanvasTexture,
            Farbe: neue THREE.Color(0x00f300),
            Deckkraft: 1,
            Auflösung: neuer THREE.Vector2($(viewerContainerId).width(), $(viewerContainerId).height()),
            Linienbreite: Pfeillinie.Linienbreite,
            Tiefentest: _Tiefentest,
            Seite: _Seite,
            Wiederholung: new THREE.Vector2(1, 1),
            transparent: wahr,
            GrößeDämpfung: 1
        });

        Pfeil.Geometrie = MeshLine.Geometrie;
        Pfeil.Material = Material;

    }

    this.createArrowLine = Funktion (Punkt1, Punkt2) {
        lass centerPoint = { x: (punkt1.x + punkt2.x) / 2, y: (punkt1.y + punkt2.y) / 2, z: (punkt1.z + punkt2.z) / 2 };
        let Abstand = utils.Abstand(Punkt1.x, Punkt1.y, Punkt1.z, Punkt2.x, Punkt2.y, Punkt2.z);

        var startPos = { x: (Punkt1.x + Punkt2.x) / 2 / 50, y: (Punkt1.y + Punkt2.y) / 2 / 50, z: (Punkt1.z + Punkt2.z) / 2 / 50 }

        sei d = utils.distance(centerPoint.x, centerPoint.y, centerPoint.z, Kameraposition.x, Kameraposition.y, Kameraposition.z);
        wenn (d < 2000) d = 2000;
        wenn (d > 10000) d = 10000;
        sei Zeilenbreite = 100 * d / 4000;
        //Konsole.log("d=", d);

        sei sc = 0,035;
        var endPos = { x: startPos.x + (punkt2.x - punkt1.x) * sc * d / Abstand / 50, y: startPos.y + (punkt2.y - punkt1.y) * sc * d / Abstand / 50, z: startPos.z + (punkt2.z - punkt1.z) * sc * d / Abstand / 50 }

        var Pfeillinienpunkte = [];
        : arrowLinePoints.push(startPos.x, startPos.y, startPos.z);
        : arrowLinePoints.push(endPos.x, endPos.y, endPos.z);

        var meshLine = neue MeshLine();
        meshLine.setGeometry(arrowLinePoints);

        return { meshLine: meshLine, Linienbreite: Linienbreite };
    }

    this.setDepthTest = Funktion (bl) {
        wenn (bl) {
            _depthTest = wahr;
            this._lines.map(Zeile => {
                Linie.Material.TiefenTest = true;
                Linie.Material.Seite = 0;
            });
            diese._arrows.map(arrow => {
                Pfeil.Material.TiefenTest = true;
                Pfeil.Material.Seite = 0;
            });
        } anders {
            _depthTest = falsch;
            this._lines.map(Zeile => {
                Linie.Material.TiefenTest = falsch;
                Linie.Material.Seite = DREI.Doppelseite;
            });
            diese._arrows.map(arrow => {
                Pfeil.Material.TiefenTest = falsch;
                Pfeil.Material.Seite = DREI.Doppelseite;
            });
        }
    }

    /**
     * Stornieren */
    dies.undo = Funktion () {
        Szene.entfernen(this._lines[this._lines.length - 1]);
        Szene.entfernen(this._arrows[this._arrows.length - 1]);
        _self._path.splice(this._path.length - 1, 1);
        _self._lines.splice(this._lines.length - 1, 1);
        _self._arrows.splice(this._arrows.length - 1, 1);
    }

}

DrawPath.prototype.constructor = Zeichenpfad;

exportiere { DrawPath }

Teil des Codes in show.js:

lass drawPath;

    //Zeichnen Sie die Linie drawPath = new DrawPath();
    drawPath.config(
        Objekte,
        Kamera,
        Szene,
        drehen
    );

    $("#rightContainer").anzeigen();
    $("#line-start").on("click", Funktion (Ereignis) {
        zeichnePath.start();
    });
    $("#line-stop").on("click", Funktion (Ereignis) {
        zeichnePath.stop();
    });
    $("#line-undo").on("click", Funktion (Ereignis) {
        drawPath.undo();
    });
    $("#line-show").on("click", Funktion (Ereignis) {
        zeichnePath.refresh();
    });
    lassen Sie Tiefentest = true;
    $("#line-depthTest").on("click", Funktion (Ereignis) {
        if (Tiefentest) {
            drawPath.setDepthTest(false);
            Tiefentest = falsch;
        } anders {
            drawPath.setDepthTest(true);
            Tiefentest = wahr;
        }
    });

setzeIntervall(() => {
    Zeichenpfad und Zeichenpfad.refresh();
}, 100);

Effektbild:

Es gibt noch einige Probleme:

Obwohl die Szene vergrößert ist und der Pfeil in dieser Darstellung etwas groß ist, wird die maximale Größe immer noch kontrolliert. Es gibt nur ein Problem mit der Form, das möglicherweise ein Perspektivproblem ist.

Der von mir erwartete Effekt sollte etwa dieser sein, d. h., egal aus welchem ​​Blickwinkel man ihn betrachtet, der Pfeil sollte nicht verformt sein:

Dies ist das Ende dieses Artikels über die Verwendung von three.js zum Zeichnen dreidimensionaler Pfeillinien, der mein halbes Leben in Anspruch genommen hat. Weitere verwandte Inhalte zu dreidimensionalen Pfeillinien mit three.js finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Three.js realisiert den dynamischen 3D-Logoeffekt von Facebook Metaverse
  • Verwenden Sie three.js, um coole 3D-Seiteneffekte im Acid-Stil zu erzielen
  • So erzielen Sie mit three.js einen dynamischen 3D-Texteffekt
  • Three.js-Beispielcode zur Implementierung des Tautropfen-Animationseffekts
  • Detaillierte Erläuterung der Verwendung und Leistungstests von Multithreading in three.js
  • Erste Erfahrungen mit der Texterstellung mit Javascript Three.js

<<:  Erfahren Sie, wie Sie saubere und standardmäßige HTML-Tags schreiben

>>:  Eine kurze Diskussion des interessanten Boxmodells der CSS3-Boxgrößeneigenschaft

Artikel empfehlen

Sind Sie immer noch Select *?

Es gibt viele Gründe, warum eine Anwendung langsa...

CSS - overflow:hidden in Projektbeispielen

Hier sind einige Beispiele, wie ich diese Eigensch...

Detaillierte Erklärung des CSS-Pseudoelements::marker

Dieser Artikel stellt ein interessantes Pseudoele...

Das Vue-Projekt implementiert einen grafischen Überprüfungscode

In diesem Artikelbeispiel wird der spezifische Co...

Analyse der Nutzung des Xmeter API-Schnittstellentesttools

XMeter API bietet einen umfassenden Online-Schnit...

Wichtige Punkte zum Schreiben von Inhalten für META-Tags in HTML-Webseiten

Das META-Tag ist ein Hilfstag im Kopfbereich der ...

So verwenden Sie dl(dt,dd), ul(li), ol(li) in HTML

HTML <dl> Tag #Definition und Verwendung Da...

Docker-Bereinigungsumgebungsvorgang

Beginnen Sie vorsichtig mit der Reinigung! Auflis...

Ideen und Praxis einer mehrsprachigen Lösung für ein Vue.js-Frontend-Projekt

Inhaltsverzeichnis 1. Welche Inhalte müssen üblic...

Vue: Zwei Komponenten auf gleicher Ebene erreichen eine Wertübertragung

Vue-Komponenten sind verbunden, daher ist es unve...