我正在尝试画一个与this网站上的轨道图案非常相似的圆。我想使用 Three.js 而不是纯 WebGL。
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
在 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 平面对齐。
我必须这样做,哈哈:
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
我使用了 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);
此示例位于 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 );
我在获取其他答案时遇到了一些问题 - 特别是,
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);
嗯,我不知道他们什么时候添加的 - 但 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 );
不知道,但我认为它不应该比线路贵(很多),而且它是一个缓冲区几何形状,您可以调整尺寸和材料等...
请参阅 Three.js 示例 http://mrdoob.github.com/third.js/examples/webgl_lines_colors.html 了解如何绘制彩色线条。
像您引用的那样的圆圈被绘制为大量小直线段。 (其实你显示的可能是省略号)
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;
}
无法读取未定义的属性(读取“拼接”)
对于
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();
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 透视相机角度,我旋转了。
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 ) );
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);
}