使用 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.MeshLineTHREE.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有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)