[英]ThreeJS: applying edge geometry to ArrowHelper
I'm trying to create an arrow using ArrowHelper in ThreeJS:我正在尝试使用 ThreeJS 中的 ArrowHelper 创建一个箭头:
let arrow = new THREE.ArrowHelper(direction.normalize(), new THREE.Vector3(), length, color, headLength, headWidth);
Also I want to use a separate color for edges.另外我想为边缘使用单独的颜色。 I realize that I need to use THREE.EdgesGeometry, but how to apply it I don't quite understand.我意识到我需要使用 THREE.EdgesGeometry,但我不太明白如何应用它。 Could anybody help me?有人可以帮我吗?
Update sorry for confusion, I thought the arrow uses pyramid, not cone.更新抱歉混淆,我认为箭头使用金字塔,而不是锥形。 Is there a way to replace cone with pyramid and use different color for edges?有没有办法用金字塔代替锥体并为边缘使用不同的颜色?
Update更新
Thank you all for your answers, they were really helpful.谢谢大家的回答,他们真的很有帮助。 I ended up with creating custom arrow class (copied most of the code from ArrowHelper):我最终创建了自定义箭头类(从 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;
}
}
For some reason linewidth and wireframeLinewidth don't affect lines widths.出于某种原因,线宽和线框线宽不会影响线宽。 Any idea why?知道为什么吗?
edit: A pyramid is a cone with 4 radial segments, if you want that, look at how the arrowhelper constructs it's cone (which is with a tapered CylinderGeometry) and line based on the parameters and replace it with a cone geometry constructed as follows:编辑:金字塔是具有 4 个径向段的圆锥体,如果您需要,请查看箭头助手如何根据参数构建它的圆锥体(具有锥形 CylinderGeometry)和线,并将其替换为如下构造的圆锥体几何体:
original:原来的:
_coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );
new:新的:
_coneGeometry = new ConeBufferGeometry( 0.5, 1, 4);
Then you don't have to use the EdgesGeometry, but use the wireframe material option (per @prisoner849's comment):然后您不必使用 EdgesGeometry,而是使用线框材料选项(根据 @prisoner849 的评论):
let wireframeMaterial = new THREE.MeshBasicMaterial({color: "aqua", wireframe: true});
let coneEdgeMesh = new THREE.Mesh(_coneGeometry, wireframeMaterial);
Original answer:原答案:
THREE.ArrowHelper consists of 2 Object3Ds: one THREE.Line for the line and one THREE.Mesh for the cone of the arrow. THREE.ArrowHelper 由 2 个 Object3D 组成:一个用于直线的 THREE.Line 和一个用于箭头锥体的 THREE.Mesh。 The Line geometry only consists of 2 points and has no edges because it is a line, but for the cone you can use:线几何只包含 2 个点并且没有边,因为它是一条线,但是对于圆锥,您可以使用:
let coneEdgeGeometry = new THREE.EdgesGeometry(arrow.cone.geometry);
Then you construct a LineSegments object with the edge geometry and the color you want:然后使用边缘几何图形和所需颜色构造一个 LineSegments 对象:
let line = new THREE.LineSegments( coneEdgeGeometry, new THREE.LineBasicMaterial( { color: 0xffffff } ) );
arrow.add(line);
If the cone edge is not showing, try setting the renderOrder of the THREE.LineSegments to -1 (this might give other issues)如果锥体边缘未显示,请尝试将 THREE.LineSegments 的 renderOrder 设置为 -1(这可能会产生其他问题)
You can change the colour of arrow's cone like this:您可以像这样更改箭头锥体的颜色:
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.