用 Three.js 画一个圆圈(不加阴影)

问题描述 投票:0回答:13

我正在尝试画一个与this网站上的轨道图案非常相似的圆。我想使用 Three.js 而不是纯 WebGL。

javascript three.js geometry
13个回答
28
投票
添加了

Three.js r50

CircleGeometry
。它可以在 WebGL 几何示例中看到(尽管有一张脸)。

几何体中的第一个顶点是在圆的中心创建的(在 r84 中,请参阅 CircleGeometry.js 第 71 行,在 r65 中,请参阅 CircleGeometry.js 第 18 行),如果您想要这样做,这很漂亮“完整的吃豆人”或“无信息的饼图”外观。哦,如果您要使用

LineBasicMaterial
/
LineDashedMaterial
之外的任何材料,这似乎是必要的。

我已经验证以下代码适用于 r60 和 r65:

var radius   = 100,
    segments = 64,
    material = new THREE.LineBasicMaterial( { color: 0x0000ff } ),
    geometry = new THREE.CircleGeometry( radius, segments );

// Remove center vertex
geometry.vertices.shift();

// Non closed circle with one open segment:
scene.add( new THREE.Line( geometry, material ) );

// To get a closed circle use LineLoop instead (see also @jackrugile his comment):
scene.add( new THREE.LineLoop( geometry, material ) );

PS:“文档”现在包含一个很好的

CircleGeometry
交互式示例:https://thirdjs.org/docs/#api/geometries/CircleGeometry


13
投票

在 Threejs 的新版本中,API 略有变化。

var segmentCount = 32,
    radius = 100,
    geometry = new THREE.Geometry(),
    material = new THREE.LineBasicMaterial({ color: 0xFFFFFF });

for (var i = 0; i <= segmentCount; i++) {
    var theta = (i / segmentCount) * Math.PI * 2;
    geometry.vertices.push(
        new THREE.Vector3(
            Math.cos(theta) * radius,
            Math.sin(theta) * radius,
            0));            
}

scene.add(new THREE.Line(geometry, material));

修改

segmentCount
以使圆圈根据场景需要变得更平滑或更锯齿状。对于小圆来说,32 段将非常平滑。对于诸如您链接到的网站上的轨道,您可能需要几百个。

修改

Vector3
构造函数中三个组件的顺序以选择圆的方向。如此处所示,圆将与 x/y 平面对齐。


5
投票

我必须这样做,哈哈:

function createCircle() {
    let circleGeometry = new THREE.CircleGeometry(1.0, 30.0);
    circleGeometry.vertices.splice(0, 1); //<= This.
    return new THREE.LineLoop(circleGeometry,
        new THREE.LineBasicMaterial({ color: 'blue' }));
}
let circle = createCircle();

原因:否则,它不会绘制一个“纯粹”的圆,有一条线从中心到圆的边缘,即使你使用LineLoop而不是Line。从数组中拼接(删除)第一个顶点是一种黑客行为,但似乎可以解决问题。 :)

(请注意,显然,根据 mrienstra 的回答,“哦,如果您要使用除 LineBasicMaterial / LineDashedMaterial 之外的任何材质,这似乎是必要的。”)


如果你想要厚度,你就完蛋了“由于大多数平台上WebGL渲染器的OpenGL核心配置文件的限制,线宽将始终为1,无论设置值如何。”)...除非您使用:https://github.com/spite/THREE.MeshLine

代码示例在这里:https://stackoverflow.com/a/61312721/1599699


4
投票

我使用了 Mr.doob 在 this github post 中引用的代码。

var resolution = 100;
var amplitude = 100;
var size = 360 / resolution;

var geometry = new THREE.Geometry();
var material = new THREE.LineBasicMaterial( { color: 0xFFFFFF, opacity: 1.0} );
for(var i = 0; i <= resolution; i++) {
    var segment = ( i * size ) * Math.PI / 180;
    geometry.vertices.push( new THREE.Vertex( new THREE.Vector3( Math.cos( segment ) * amplitude, 0, Math.sin( segment ) * amplitude ) ) );         
}

var line = new THREE.Line( geometry, material );
scene.add(line);

3
投票

此示例位于 Three.js 文档中:

var material = new THREE.MeshBasicMaterial({
    color: 0x0000ff
});

var radius = 5;
var segments = 32; //<-- Increase or decrease for more resolution I guess

var circleGeometry = new THREE.CircleGeometry( radius, segments );              
var circle = new THREE.Mesh( circleGeometry, material );
scene.add( circle );

2
投票

我在获取其他答案时遇到了一些问题 - 特别是,

CircleGeometry
在圆的中心有一个额外的点,而且我不喜欢尝试删除该顶点的做法。

EllipseCurve
做了我想要的(在r135中验证):

const curve = new THREE.EllipseCurve(
  0.0, 0.0,            // Center x, y
  10.0, 10.0,          // x radius, y radius
  0.0, 2.0 * Math.PI,  // Start angle, stop angle
);

const pts = curve.getSpacedPoints(256);
const geo = new THREE.BufferGeometry().setFromPoints(pts);

const mat = new THREE.LineBasicMaterial({ color: 0xFF00FF });
const circle = new THREE.LineLoop(geo, mat);
scene.add(circle);

2
投票

嗯,我不知道他们什么时候添加的 - 但 TorusGeometry 应该可以完成这项工作...... 三个环面几何

const geometry = new THREE.TorusGeometry( 10, 3, 16, 100 );
const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
const torus = new THREE.Mesh( geometry, material );
scene.add( torus );

不知道,但我认为它不应该比线路贵(很多),而且它是一个缓冲区几何形状,您可以调整尺寸和材料等...


1
投票

请参阅 Three.js 示例 http://mrdoob.github.com/third.js/examples/webgl_lines_colors.html 了解如何绘制彩色线条。

像您引用的那样的圆圈被绘制为大量小直线段。 (其实你显示的可能是省略号)


1
投票
var getStuffDashCircle2 = function () {

var segment = 100, radius = 100;

var lineGeometry = new THREE.Geometry();
var vertArray = lineGeometry.vertices;
var angle = 2 * Math.PI / segment;
for (var i = 0; i < segment; i++) {
    var x = radius * Math.cos(angle * i);
    var y = radius * Math.sin(angle * i);
    vertArray.push(new THREE.Vector3(x, y, 0));
}
lineGeometry.computeLineDistances();
var lineMaterial = new THREE.LineDashedMaterial({ color: 0x00cc00, dashSize: 4, gapSize: 2 });
var circle = new THREE.Line(lineGeometry, lineMaterial);

circle.rotation.x = Math.PI / 2;
circle.position.y = cylinderParam.trackHeight+20;
return   circle;
}

1
投票
对于 THREE.REVISION =“150”,安德鲁答案中的

代码已被弃用。我看到一条错误消息:

无法读取未定义的属性(读取“拼接”)

对于

circleGeometry.vertices.splice(0, 1);
线。

请参阅下面我编辑的代码以获取解决方案:

function createCircle() { const circleGeometry = new THREE.CircleGeometry(1.0, 30); // Remove center vertex const itemSize = 3; circleGeometry.setAttribute( 'position', new THREE.BufferAttribute( circleGeometry.attributes.position.array.slice( itemSize, circleGeometry.attributes.position.array.length - itemSize ), itemSize ) ); circleGeometry.index = null; return new THREE.LineLoop(circleGeometry, new THREE.LineBasicMaterial({ color: 'blue' })); } const circle = createCircle();
    

0
投票
不用绘制固定厚度的 3D 对象(放大时会变得很明显),您可以只制作一个固定厚度的圆圈,保持细线,这对于 UI 覆盖非常好,就像 OP 示例链接

absarc()

setFromPoints()
 在这里非常有用。

//Draws an orbit at 0,0 with given distance let pts = new THREE.Path().absarc(0, 0, orbitDist, 0, Math.PI * 2).getPoints(90); let g = new THREE.BufferGeometry().setFromPoints(pts); let m = new THREE.LineBasicMaterial( { color: 0x00ffff, transparent: true, opacity: 0.5 } ); g.rotateX( - Math.PI / 2); let l = new THREE.Line(g, m); scene.add( l );
由于它在 2D 中形成弧线,因此如果您愿意,可以使用 

.position.set(x,y,z)

 在 3D 中移动它,或者,我无论如何都将其添加到场景中的 3D 原点 (0,0,0)。由于 3D 透视相机角度,我旋转了。


0
投票
mrienstra 答案中的

code 已被弃用,因为 THREE.REVISION =“150”。我看到一条错误消息:

无法读取未定义的属性(读取“shift”)

对于

geometry.vertices.shift();
线。

请参阅下面我编辑的代码以获取解决方案:

const radius = 100, segments = 64, material = new THREE.LineBasicMaterial( { color: 0x0000ff } ), geometry = new THREE.CircleGeometry( radius, segments ); // Remove center vertex const itemSize = 3; geometry.setAttribute( 'position', new THREE.BufferAttribute( geometry.attributes.position.array.slice( itemSize, geometry.attributes.position.array.length - itemSize ), itemSize ) ); geometry.index = null; // Non closed circle with one open segment: scene.add( new THREE.Line( geometry, material ) ); // To get a closed circle use LineLoop instead (see also @jackrugile his comment): scene.add( new THREE.LineLoop( geometry, material ) );
    

0
投票
“暴力”方法(使用 for、cos、sin)现在(R149)需要使用 BufferGeometry 而不是 Geometry:

function docircle(r, segs, color) { let x,y,angle,avertices=[],geometry,material,lines; for (let i=0; i<segs; i+=1 ) { angle = i/segs*Math.PI*2; x = r*Math.cos(angle); y = r*Math.sin(angle); avertices.push(x,y,0); } geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.Float32BufferAttribute(avertices, 3)); material = new THREE.LineBasicMaterial( { color:color } ); lines = new THREE.LineLoop(geometry, material); scene.add(lines); }
    
© www.soinside.com 2019 - 2024. All rights reserved.