簡體   English   中英

ThreeJS:將邊緣幾何應用於 ArrowHelper

[英]ThreeJS: applying edge geometry to ArrowHelper

我正在嘗試使用 ThreeJS 中的 ArrowHelper 創建一個箭頭:

let arrow = new THREE.ArrowHelper(direction.normalize(), new THREE.Vector3(), length, color, headLength, headWidth);

另外我想為邊緣使用單獨的顏色。 我意識到我需要使用 THREE.EdgesGeometry,但我不太明白如何應用它。 有人可以幫我嗎?

更新抱歉混淆,我認為箭頭使用金字塔,而不是錐形。 有沒有辦法用金字塔代替錐體並為邊緣使用不同的顏色?

更新

謝謝大家的回答,他們真的很有幫助。 我最終創建了自定義箭頭類(從 ArrowHelper 復制了大部分代碼):

class CustomArrow extends THREE.Object3D {

    constructor( dir, origin, length, color, edgeColor, headLength, headWidth ) {

        super();
        // dir is assumed to be normalized

        this.type = 'CustomArrow';

        if ( dir === undefined ) dir = new THREE.Vector3( 0, 0, 1 );
        if ( origin === undefined ) origin = new THREE.Vector3( 0, 0, 0 );
        if ( length === undefined ) length = 1;
        if ( color === undefined ) color = 0xffff00;
        if ( headLength === undefined ) headLength = 0.2 * length;
        if ( headWidth === undefined ) headWidth = 0.2 * headLength;

        if ( this._lineGeometry === undefined ) {
            this._lineGeometry = new THREE.BufferGeometry();
            this._lineGeometry.setAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
            this._coneGeometry = new THREE.ConeBufferGeometry( 0.5, 1, 6);
            this._coneGeometry.translate( 0, - 0.5, 0 );
            this._axis = new THREE.Vector3();
        }

        this.position.copy( origin );

        this.line = new THREE.Line( this._lineGeometry, new THREE.LineBasicMaterial( { color: color, toneMapped: false, linewidth: 4 } ) );
        this.line.matrixAutoUpdate = false;
        this.add( this.line )

        // base material        
        this.cone = new THREE.Mesh( this._coneGeometry, new THREE.MeshBasicMaterial( { color: color, toneMapped: false } ) );
        this.add(this.cone);

        // wire frame
        this.wireframe = new THREE.Mesh( this._coneGeometry, new THREE.MeshBasicMaterial( { 
            color: edgeColor, 
            toneMapped: false, 
            wireframe: true,
            wireframeLinewidth: 2 } ) );
        this.add(this.wireframe);

        this.setDirection( dir );
        this.setLength( length, headLength, headWidth );
    }

    setDirection( dir ) {

        // dir is assumed to be normalized

        if ( dir.y > 0.99999 ) {

            this.quaternion.set( 0, 0, 0, 1 );

        } else if ( dir.y < - 0.99999 ) {

            this.quaternion.set( 1, 0, 0, 0 );

        } else {

            this._axis.set( dir.z, 0, - dir.x ).normalize();

            const radians = Math.acos( dir.y );

            this.quaternion.setFromAxisAngle( this._axis, radians );

        }

    }

    setLength( length, headLength, headWidth ) {

        if ( headLength === undefined ) headLength = 0.2 * length;
        if ( headWidth === undefined ) headWidth = 0.2 * headLength;

        this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458
        this.line.updateMatrix();
        
        this.cone.scale.set( headWidth, headLength, headWidth );
        this.cone.position.y = length;
        this.cone.updateMatrix();
        
        this.wireframe.scale.set( headWidth, headLength, headWidth );
        this.wireframe.position.y = length;
        this.wireframe.updateMatrix();
    }

    setColor( color ) {
        this.line.material.color.set( color );
        // this.cone.material.color.set( color );
        // this.wireframe.material.color.set( color );
    }

    copy( source ) {
        super.copy( source, false );
        this.line.copy( source.line );
        this.cone.copy( source.cone );
        this.wireframe.copy( source.wireframe );
        return this;
    }
}

出於某種原因,線寬和線框線寬不會影響線寬。 知道為什么嗎?

編輯:金字塔是具有 4 個徑向段的圓錐體,如果您需要,請查看箭頭助手如何根據參數構建它的圓錐體(具有錐形 CylinderGeometry)和線,並將其替換為如下構造的圓錐體幾何體:

原來的:

_coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );

新的:

_coneGeometry = new ConeBufferGeometry( 0.5, 1, 4);

然后您不必使用 EdgesGeometry,而是使用線框材料選項(根據 @prisoner849 的評論):

let wireframeMaterial = new THREE.MeshBasicMaterial({color: "aqua", wireframe: true});

let coneEdgeMesh = new THREE.Mesh(_coneGeometry, wireframeMaterial);

原答案:

THREE.ArrowHelper 由 2 個 Object3D 組成:一個用於直線的 THREE.Line 和一個用於箭頭錐體的 THREE.Mesh。 線幾何只包含 2 個點並且沒有邊,因為它是一條線,但是對於圓錐,您可以使用:

let coneEdgeGeometry = new THREE.EdgesGeometry(arrow.cone.geometry);

然后使用邊緣幾何圖形和所需顏色構造一個 LineSegments 對象:

let line = new THREE.LineSegments( coneEdgeGeometry, new THREE.LineBasicMaterial( { color: 0xffffff } ) );
arrow.add(line);

如果錐體邊緣未顯示,請嘗試將 THREE.LineSegments 的 renderOrder 設置為 -1(這可能會產生其他問題)

您可以像這樣更改箭頭錐體的顏色:

 body { overflow: hidden; margin: 0; }
 <script type="module"> import * as THREE from "https://threejs.org/build/three.module.js"; import {OrbitControls} from "https://threejs.org/examples/jsm/controls/OrbitControls.js"; let scene = new THREE.Scene(); let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100); camera.position.set(0, 5, 10); let renderer = new THREE.WebGLRenderer(); renderer.setSize(innerWidth, innerHeight); document.body.appendChild(renderer.domElement); new OrbitControls(camera, renderer.domElement); scene.add(new THREE.GridHelper()); // different colors let ah = new THREE.ArrowHelper( new THREE.Vector3(0, 1, 0), new THREE.Vector3(-4, 0, 0), 5, "magenta" /* default colour */); ah.cone.material.color.set("red"); // change color of cone scene.add(ah); // colourful pyramid let cg = new THREE.SphereBufferGeometry(0.5, 4, 2).toNonIndexed(); let pos = cg.attributes.position; for (let i = 0; i < pos.count; i++){ if (pos.getY(i) < 0) pos.setY(i, 0); } console.log(cg); let cls = [ new THREE.Color("red"), new THREE.Color("green"), new THREE.Color("blue"), new THREE.Color("yellow") ] let colors = []; for(let i = 0; i < 2; i++){ cls.forEach( (c) => { colors.push(cr, cg, cb); colors.push(cr, cg, cb); colors.push(cr, cg, cb); }); } cg.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3)); let cm = new THREE.MeshBasicMaterial({vertexColors: true}); let co = new THREE.Mesh(cg, cm); co.scale.set(1, 5, 1); scene.add(co); renderer.setAnimationLoop(()=>{ renderer.render(scene, camera); }); </script>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM