使用 THREE.LineBasicMaterial 的线条粗细
Posted
技术标签:
【中文标题】使用 THREE.LineBasicMaterial 的线条粗细【英文标题】:Thickness of lines using THREE.LineBasicMaterial 【发布时间】:2012-07-23 05:51:51 【问题描述】:我正在使用下面的代码在我的 three.js 场景中创建数百行
edgeGeometry[i] = new THREE.Geometry();
edgeGeometry[i].vertices[0] = v(x1,y1,z1);
edgeGeometry[i].vertices[1] = v(x2,y2,z2);
edgesMat[i] = new THREE.LineBasicMaterial(
color: 0x6699FF, linewidth: 1, fog:true);
edge[i] = new THREE.Line(edgeGeometry[i], edgesMat[i]);
edge[i].type = THREE.Lines;
scene2.add(edge[i]);
它工作得很好,但是当我将“线宽”的值更改为更大或更小的值时,我发现场景没有区别。 我应该如何改变线条的粗细?有什么想法吗? 谢谢,迪米特里斯
【问题讨论】:
您好,根据 THREE.JS document:“由于大多数平台上带有 WebGL 渲染器的 OpenGL 核心配置文件的限制,无论设置值如何,线宽都将始终为 1。” 【参考方案1】:1) 使用原生 OpenGL
您可以通过将浏览器设置为使用原生 OpenGL 而不是 ANGLE 来实现线条粗细的渲染。 You can read here on how to do this on Chrome。 请记住,如果您切换到原生 OpenGL,您会遇到性能差异。
编辑:
MrDoob 大师本人posted here how to do this for both Chrome and Firefox。
注意: 第一个选项不再是有效的解决方案,因为最新的 OpenGL 版本也不再支持线条粗细。检查also @gman his answer。这意味着如果您想使用线条粗细,第二个选项是可行的方法。
2) 使用THREE.MeshLine
类
还有另一种解决方案; this THREE.MeshLine
class on github 是一个很好的解决方法。它带有一个特殊的THREE.MeshLineMaterial
。根据文档,它很简单:
创建和填充几何图形 创建一个THREE.MeshLine
并分配几何图形 创建THREE.MeshLineMaterial
使用THREE.MeshLine
和THREE.MeshLineMaterial
创建THREE.Mesh
【讨论】:
使用原生 OpenGL 不再是一种解决方案 - 也许您想更新您的答案? @gman 感谢您的评论。您能否添加一些对此信息来源的参考。然后我可以更新我的问题并添加对该来源的引用。 我做了,看我的回答 three.meshline 不支持缓冲几何。有谁知道我如何使它与缓冲几何一起使用? 不是最佳选择,不受THREE.Fog影响【参考方案2】:您使用的是 Windows 吗? 我记得这在 Windows 上不起作用,因为它没有在 ANGLE 中实现。
【讨论】:
是的,我使用的是 Windows 7。既然你提到了它,那一定是因为我一个月前在 Ubuntu 上运行我的应用程序并且宽度完全改变了。我怎样才能让它在 Windows 中也能工作? 嗯,不确定...这是角度限制。我不知道他们是否可以添加。 感谢您的快速回复...至少现在我知道导致问题的不是我的代码中的错误... 可惜了。无论我尝试什么,我总是在开始时遇到任何麻烦,我可能需要成为一名 QA。尝试实现简单的时钟图像,现在我必须覆盖线宽问题)我认为我们可以尝试使用矩形而不是线(2px 宽度的矩形) 我在 OS X Chrome 上也发生了这种情况,刚刚找到了关于它的报告:github.com/mrdoob/three.js/issues/10357【参考方案3】:这发生在 Windows Chrome 和 Firefox 中,两者都使用 ANGLE(WebGL 到 DirectX 包装器)。
ANGLE 项目仍未解决该问题。您可以在此处为问题加注星标以获得更高的优先级,并在将要实施时收到通知:
https://code.google.com/p/angleproject/issues/detail?id=119
【讨论】:
【参考方案4】:我使用 TubeGeometry 在两点之间创建一条粗线:
查看 Helix 中的绿线
// line material
var lineMaterial = new THREE.LineBasicMaterial( color: 0x00ff00 );
let startVector = new THREE.Vector3(
RADI * Math.cos(t),
RADI * Math.sin(t),
3 * t
);
let endVector = new THREE.Vector3(
RADI * Math.cos(t + 10),
RADI * Math.sin(t + 10),
3 * t
);
let linePoints = [];
linePoints.push(startVector, endVector);
// Create Tube Geometry
var tubeGeometry = new THREE.TubeGeometry(
new THREE.CatmullRomCurve3(linePoints),
512,// path segments
0.5,// THICKNESS
8, //Roundness of Tube
false //closed
);
let line = new THREE.Line(tubeGeometry, lineMaterial);
scene.add(line);
【讨论】:
【参考方案5】:这不再只是 ANGLE 中的问题,而是所有平台上的问题。浏览器需要切换到 OpenGL 4+ 核心配置文件以支持 WebGL2,而 OpenGL 4+ 核心配置文件不支持大于 1 的线宽。来自 OpenGL 4.0+ 规范,E.2.1 节
E.2.1 已弃用但仍受支持的功能
以下功能已弃用,但仍存在于核心配置文件中。它们可能会从 OpenGL 的未来版本中删除,并在实现核心配置文件的前向兼容上下文中删除。
宽线 - LineWidth 值大于 1.0 将生成 INVALID_VALUE 错误。
要绘制较粗的线条,您需要生成几何图形。对于three.js,有这个库(Wilt 也指出了)
https://github.com/spite/THREE.MeshLine
【讨论】:
截至今天(2018 年 2 月 26 日),Safari 实际上仍然正确呈现 lineWidth > 1,而最新的 Chrome 则没有; 是的,我在那里用了一个不正确的词。改变规格真的很糟糕,但这就是生活;)。可能会使用来自 github 的 THREE.LineMesh。 WebGL 规范没有改变,但实现改变了。规范一直说 1 是所有必须支持的东西,而对于大多数人来说,在 windows 上就是一直支持的东西。如果您希望行数 > 1,并且希望您的应用程序可以在任何地方工作,那么您总是必须实施诸如 THREE.MeshLine 之类的解决方案。 是的,我现在正在使用 THREE.MeshLine :)。干杯。 我有 > 10k 行,所以 THREE.MeshLine 对我来说还不够。我能做些什么?将线拉伸到服务器上的网格?【参考方案6】:您可以使用 CanvasRenderer 代替 Webglrenderer。查看官方文档here,其中每个形状的边框为 linewidth = 10;
【讨论】:
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review @Serafeim 链接只是一个例子。答案是使用 CanvasRenderer。【参考方案7】:您可以使用extrude-polyline
为加粗的(多段)线生成simplicial complex 并使用three-simplicial-complex
将其转换为three.js 网格来实现相同的效果:
const THREE = require('three');
const extrudePolyline = require('extrude-polyline');
const Complex = require('three-simplicial-complex')(THREE);
function thickPolyline(points, lineWidth)
const simplicialComplex = extrudePolyline(
// Adjust to taste!
thickness: lineWidth,
cap: 'square', // or 'butt'
join: 'bevel', // or 'miter',
miterLimit: 10,
).build(points);
// Add a z-coordinate.
for (const position of simplicialComplex.positions)
position[2] = 0;
return Complex(simplicialComplex);
const vertices = [[0, 0], [10, 0], [10, 10], [20, 10], [30, 00]];
const geometry = thickPolyline(vertices, 10);
const material = new THREE.MeshBasicMaterial(
color: 0x009900,
side: THREE.DoubleSide
);
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
如果你想对折线进行纹理贴图,事情会变得有点复杂。
【讨论】:
您可能会发现感兴趣的this three.js pull request。 该 PR 使用着色器来生成恒定粗细的线条。如果您想生成在世界坐标中确实具有特定厚度的多段线(例如,从其中心线生成一条道路),那么这种方法更有意义。【参考方案8】:感谢Wilt's answer 用THREE.MeshLine 为我指明了正确的方向。
这可能比他们想象的要复杂一些,但是...所以这是我非常仔细地遵循他们的文档和demo 代码的解决方案...(假设您已经包含了 Three 和 MeshLine):
renderer = new THREE.WebGLRenderer( canvas );
//...
function createCircle(resolution)
let circleGeometry = new THREE.Geometry();
for (let rotation = 0; rotation <= Math.PI * 2.0; rotation += Math.PI * 0.1)
circleGeometry.vertices.push(
new THREE.Vector3(Math.cos(rotation), Math.sin(rotation), 0));
let circleLine = new MeshLine();
circleLine.setGeometry(circleGeometry);
//Bonus: parabolic width! (See Z rotation below.)
//circleLine.setGeometry(circleGeometry, function(point)
//return Math.pow(4 * point * (1 - point), 1);
//);
//Note: resolution is *required*!
return new THREE.Mesh(circleLine.geometry,
new MeshLineMaterial(
color: 'blue',
resolution,
sizeAttenuation: 0,
lineWidth: 5.0,
side: THREE.DoubleSide
));
let circle = createCircle(new THREE.Vector2(canvas.width, canvas.height));
circle.rotation.x = Math.PI * 0.5;
circle.position.y = 20.0;
scene.add(circle);
//In update, to rotate the circle (e.g. if using parabola above):
world.circle.rotation.z += 0.05;
关闭尺寸衰减并使用THREE.DoubleSide
,就像我在上面所做的那样,无论你从哪里看,这个圆圈看起来都是一个漂亮、一致的圆圈(不是“真正的 3D”)。
仅仅一条线,你显然可以轻松适应。
【讨论】:
【参考方案9】:为什么不将不透明度设置为 0.1 之类的值? 注意:这仅在您为某物设置边框时才有效,如果它后面没有任何东西,它将不起作用。
【讨论】:
以上是关于使用 THREE.LineBasicMaterial 的线条粗细的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?
Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)