【问题标题】:Thickness of lines using THREE.LineBasicMaterial使用 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。”

标签: javascript webgl three.js


【解决方案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 answerTHREE.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 之类的值? 注意:这仅在您为某物设置边框时才有效,如果它后面没有任何东西,它将不起作用。

        【讨论】:

          猜你喜欢
          • 2011-01-17
          • 1970-01-01
          • 1970-01-01
          • 2022-12-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-02-02
          相关资源
          最近更新 更多