需要: この需要は緊急に必要です!地下鉄のシーンでは、脱出経路を示す矢印を描かなければなりません。この矢印を描くのに十数時間かかり、ようやく完成しましたが、まだ問題がありました。この矢印に対する私の要件は、シーンを拡大または縮小しても、矢印が大きすぎたり小さすぎたりしてはっきりと見えないこと、また形状が変化しないことです。そうしないと、矢印に見えなくなります。 three.jsのLine2.jsとオープンソースライブラリMeshLine.jsを使用します コードの一部: 描画パス: /** * ルートを描く */ '../build/three.module.js' から THREE として * をインポートします。 '../js.my/MeshLine.js' から { MeshLine、MeshLineMaterial、MeshLineRaycast } をインポートします。 '../js/lines/Line2.js' から { Line2 } をインポートします。 '../js/lines/LineMaterial.js' から LineMaterial をインポートします。 '../js/lines/LineGeometry.js' から LineGeometry をインポートします。 '../js/utils/GeometryUtils.js' から GeometryUtils をインポートします。 '../js.my/CanvasDraw.js' から CanvasDraw をインポートします。 '../js.my/Utils.js' から Utils をインポートします。 '../js.my/Msg.js' から { Msg } をインポートします。 DrawPath = 関数(){ _self = this とします。 _canvasDraw = 新しい CanvasDraw() を作成します。 utils = new Utils(); とします。 msg = new Msg(); とします。 this._isDrawing = false; this._path = []; this._lines = []; this._arrows = []; _depthTest を true にします。 _side = 0 とします。 ビューアコンテナIdを'#cc'とします。 ビューアコンテナを$(ビューアコンテナId)[0]とします。 オブジェクトをletします。 カメラを回す 回す; シーンを演出する this.config = 関数 (オブジェクト、カメラ、シーン、ターン) { オブジェクト = オブジェクト_; カメラ = カメラ_; ターン = turn_; シーン = scene_; this._oldDistance = 1; this._oldCameraPos = { x: カメラの位置 x、 y: カメラの位置 y、 z: カメラの位置 z } } this.start = 関数(){ if (!this._isDrawing) { this._isDrawing = true; viewerContainer.addEventListener('click', ray); viewerContainer.addEventListener('mousedown', マウスダウン); ビューアコンテナにイベントリスナーを追加します('mouseup', mouseup); } msg.show("線を描くには地面をクリックしてください"); } this.stop = 関数 () { if (this._isDrawing) { this._isDrawing = false; viewerContainer.removeEventListener('click', ray); viewerContainer.addEventListener('mousedown', マウスダウン); ビューアコンテナにイベントリスナーを追加します('mouseup', mouseup); } msg.show("線の描画を停止"); } 関数 mousedown(パラメータ) { this._mousedownPosition = { x: camera.position.x、 y: camera.position.y、 z: camera.position.z } } 関数 mouseup(パラメータ) { this._mouseupPosition = { x: camera.position.x、 y: camera.position.y、 z: camera.position.z } } 関数 ray(e) { フォーカスボタンを消します。 raycaster = createRaycaster(e.clientX, e.clientY); とします。 intersects = raycaster.intersectObjects(objects.all); とします。 交差する長さが0より大きい場合 point = intersects[0].pointとします。 距離を utils.distance(this._mousedownPosition.x、this._mousedownPosition.y、this._mousedownPosition.z、this._mouseupPosition.x、this._mouseupPosition.y、this._mouseupPosition.z) とします。 (距離<5)の場合{ _self._path.push({ x: point.x, y: point.y + 50, z: point.z }); _self._path.length > 1 の場合 { point1 = _self._path[_self._path.length - 2]とします。 point2 = _self._path[_self._path.length - 1]とします。 線を描画します(ポイント1、ポイント2)。 矢印を描画します(ポイント1、ポイント2)。 } } } } 関数createRaycaster(clientX, clientY) { x = (clientX / $(viewerContainerId).width()) * 2 - 1 とします。 y = -(clientY / $(viewerContainerId).height()) * 2 + 1 とします。 standardVector = new THREE.Vector3(x, y, 0.5); とします。 worldVector = standardVector.unproject(カメラ) とします。 ray = worldVector.sub(camera.position).normalize() とします。 raycaster = new THREE.Raycaster(camera.position, ray); を作成します。 レイキャスターを返します。 } this.refresh = 関数 () { _self._path.length > 1 の場合 { 距離を utils.distance(this._oldCameraPos.x、this._oldCameraPos.y、this._oldCameraPos.z、camera.position.x、camera.position.y、camera.position.z) とします。 比率を1にします。 this._oldDistance が 0 の場合 比率 = Math.abs((this._oldDistance - 距離) / this._oldDistance) } (距離 > 5 && 比率 > 0.1)の場合{ console.log("======== DrawPath の更新====================================================================================") (i = 0 とします; i < _self._path.length - 1; i++) { 矢印を_self._arrows[i]とします。 point1 = _self._path[i]とします。 point2 = _self._path[i + 1]とします。 リフレッシュ矢印(ポイント1、ポイント2、矢印); } this._oldDistance = 距離; this._oldCameraPos = { x: カメラの位置 x、 y: カメラの位置 y、 z: カメラの位置 z } } } } 関数drawLine(point1, point2) { const位置 = []; 位置をプッシュします(point1.x / 50、point1.y / 50、point1.z / 50); 位置をプッシュします(point2.x / 50、point2.y / 50、point2.z / 50)。 ジオメトリを新しい LineGeometry() にします。 ジオメトリの位置を設定します。 matLine = new LineMaterial({ 色: 0x009900、 線幅: 0.003, // サイズ減衰のあるワールド単位、それ以外の場合はピクセル 破線: 真、 深さテスト: _depthTest、 サイド: _サイド }); line = new Line2(geometry, matLine); とします。 行の距離を計算します。 ラインスケールを50, 50, 50に設定します。 シーンに行を追加します。 _self._lines.push(行); } 関数drawArrow(point1, point2) { _self.createArrowLine(point1, point2) とします。 var メッシュライン = arrowLine.メッシュライン; let canvasTexture = _canvasDraw.drawArrow(THREE, renderer, 300, 100); //矢印 var material = new MeshLineMaterial({ 使用マップ: true、 マップ: キャンバステクスチャ、 色: 新しい THREE.Color(0x00f300)、 不透明度: 1, 解像度: 新しい THREE.Vector2($(viewerContainerId).width(), $(viewerContainerId).height()), 線幅: arrowLine.lineWidth、 深さテスト: _depthTest、 サイド: _サイド、 繰り返し: 新しい THREE.Vector2(1, 1)、 透明: true、 サイズ減衰: 1 }); var mesh = new THREE.Mesh(meshLine.geometry, material); メッシュスケールを50に設定(50, 50, 50); シーンを追加します(メッシュ); _self._arrows.push(メッシュ); } 関数refreshArrow(point1, point2, arrow) { _self.createArrowLine(point1, point2) とします。 var メッシュライン = arrowLine.メッシュライン; let canvasTexture = _canvasDraw.drawArrow(THREE, renderer, 300, 100); //矢印 var material = new MeshLineMaterial({ 使用マップ: true、 マップ: キャンバステクスチャ、 色: 新しい THREE.Color(0x00f300)、 不透明度: 1, 解像度: 新しい THREE.Vector2($(viewerContainerId).width(), $(viewerContainerId).height()), 線幅: arrowLine.lineWidth、 深さテスト: _depthTest、 サイド: _サイド、 繰り返し: 新しい THREE.Vector2(1, 1)、 透明: true、 サイズ減衰: 1 }); 矢印のジオメトリ = メッシュラインのジオメトリ; 矢印.material = マテリアル; } this.createArrowLine = 関数 (point1, point2) { centerPoint を { x: (point1.x + point2.x) / 2、 y: (point1.y + point2.y) / 2、 z: (point1.z + point2.z) / 2 } とします。 距離を utils.distance(point1.x、point1.y、point1.z、point2.x、point2.y、point2.z) とします。 var startPos = { x: (point1.x + point2.x) / 2 / 50、 y: (point1.y + point2.y) / 2 / 50、 z: (point1.z + point2.z) / 2 / 50 } d = utils.distance(centerPoint.x、centerPoint.y、centerPoint.z、camera.position.x、camera.position.y、camera.position.z); とします。 (d < 2000)の場合d = 2000; d > 10000 の場合、d = 10000; 線幅を 100 * d / 4000 とします。 //コンソールログ("d=", d); sc = 0.035とします。 var endPos = { x: startPos.x + (point2.x - point1.x) * sc * d / 距離 / 50、 y: startPos.y + (point2.y - point1.y) * sc * d / 距離 / 50、 z: startPos.z + (point2.z - point1.z) * sc * d / 距離 / 50 } var arrowLinePoints = []; 矢印の線ポイントをプッシュします(開始位置 x、開始位置 y、開始位置 z); 矢印の線分ポイントをプッシュします(endPos.x、endPos.y、endPos.z); var meshLine = 新しい MeshLine(); メッシュラインにジオメトリを設定します。 戻り値: meshLine, lineWidth: lineWidth }; } this.setDepthTest = 関数 (bl) { もし(bl){ _depthTest = true; this._lines.map(行 => { ライン.マテリアル.深さテスト = true; ライン.マテリアル.サイド = 0; }); this._arrows.map(矢印 => { 矢印.material.depthTest = true; 矢印.material.side = 0; }); } それ以外 { _depthTest = false; this._lines.map(行 => { ライン.マテリアル.深さテスト = false; ライン.マテリアル.サイド = THREE.DoubleSide; }); this._arrows.map(矢印 => { 矢印.material.depthTest = false; arrow.material.side = THREE.DoubleSide; }); } } /** * キャンセル */ this.undo = 関数(){ scene.remove(this._lines[this._lines.length - 1]); scene.remove(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 プロトタイプ コンストラクター = DrawPath; エクスポート {DrawPath} show.js のコードの一部: パスを描画します。 //線を描画する drawPath = new DrawPath(); 描画パス.config( オブジェクト、 カメラ、 シーン、 振り向く ); $("#rightContainer").show(); $("#line-start").on("click", 関数(イベント) { 描画パスを開始します。 }); $("#line-stop").on("click", 関数(イベント) { 描画パスを停止します。 }); $("#line-undo").on("click", 関数(イベント) { 描画パスを元に戻す(); }); $("#line-show").on("click", 関数(イベント) { 描画パスを更新します。 }); depthTest を true にします。 $("#line-depthTest").on("click", 関数(イベント) { if (深さテスト) { パスを描画します。 深さテスト = false; } それ以外 { 深度テストを true に設定します。 深さテスト = true; } }); 間隔を設定する(() => { 描画パス && 描画パス.refresh(); }, 100); 効果画像: まだいくつか問題があります: このレンダリングではシーンがズームインされ、矢印が少し大きくなっていますが、最大サイズは制御されています。形状に問題があるだけで、これは遠近法の問題である可能性があります。 私が期待する効果は次のようになります。つまり、どの角度から見ても矢印が変形しないはずです。 これで、人生の半分を費やした three.js を使用して 3 次元矢印線を描く方法についての記事は終わりです。three.js 3 次元矢印線に関するその他の関連コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM を応援してください。 以下もご興味があるかもしれません:
|
>>: CSS3のボックスサイズプロパティの興味深いボックスモデルについての簡単な説明
この例では、デバッグ用の MySQL データベースをダウンロードしてインストールする必要があります。...
今日は、ネイティブ JS で実装されたブリージング カルーセルを紹介します。効果は次のとおりです。 ...
1. MySQL マスタースレーブ非同期1.1 ネットワーク遅延MySQLのマスタースレーブレプリケ...
質問ガイド1. Hadoop 3.x はどのようにして障害を許容するのでしょうか? 2. Hadoo...
この記事では、ローカル yum ソースを使用して CentOS 上に LAMP 環境を構築する方法に...
目次1. 構造体はメモリにどのように保存されますか? 2. container_ofマクロ3. 型4...
VirtualBoxのインストールディレクトリを見つけます。ディレクトリ内には容量を拡張するために...
この記事の例では、円形のプログレスバーのドラッグアンドスライドを実現するための具体的なJSコードを紹...
クリック時に背景色を生成する要素の CSS スタイルに次のコードを追加します。 -webkit-ta...
1. vue uiでプロジェクトを作成する 2. 基本設定項目を選択する 3. プロジェクトを実行す...
目次はじめにNginx Dockerファイル新しい会議もっと参考文献はじめに最近、アプリケーションの...
1. /usr/local/services/zookeeper フォルダを作成します。 mkdir...
目次序文1. Props、$emit一方向データフロー2. $親、$子3. $attrs、$list...
ベースイメージベースイメージには 2 つの意味があります。他のイメージに依存せず、ゼロから構築します...
目次導入ミラーリポジトリログイン引く押す検索ローカル画像管理画像rmiタグ建てる歴史保存負荷輸入コン...