如何创建宽度和厚度的Three.js 3D系列?

The*_*heo 12 javascript geometry lines three.js

有没有办法创建宽度和厚度的Three.js 3D系列?

尽管Three.js line对象支持linewidth,但WebGL中所有平台上的所有浏览器都不支持此属性.

这是你在Three.js中设置线宽的地方:

    var material = new THREE.LineBasicMaterial({
        color: 0xff0000,
        linewidth: 5
    });
Run Code Online (Sandbox Code Playgroud)

最近放弃了具有宽度的Three.js功能区对象.

Three.js管对象生成3D挤压但是 - 基于贝塞尔 - 线不通过控制点.

任何人都可以想到在Three.js中绘制线系列(折线,情节线)的方法,它具有某种用户可定义的"体积",如宽度,厚度或半径?

这个问题可能是这个问题的重述: 在three.js中挤出一个图形.

鉴于我认为没有现成的方法,我很乐意参与创建一个响应这个问题的简单函数.

但是,指出现有可行方法的反应会很酷......

正如WestLangley建议的那样,一种可能的解决方案包括折线具有恒定像素宽度 - 目前可用于Three.js画布渲染器.

这里显示了两个渲染器的比较:

Canvas和WebGL线通过GitHub页面进行比较

画布和WebGL线通过jsFiddle进行比较

在此输入图像描述

您可以在两个渲染器上指定线宽和类似结果的解决方案非常酷.

然而,还有其他思考3D线的方法,其中线具有实际的物理结构.他们投下阴影,他们回应事件.这些也需要进行研究.

以下是GitHub页面的链接,其中包含两个由多个网格组成的线条:

球体和立方体折线

球体和圆柱折线

'昂贵的解决方案.每个关节由一个完整的球体组成.

立方体折线

立方体折线

我的猜测是,将这些中的任何一个构建为平滑的单个网格对于要解决的问题将是复杂的.所以在此期间,这里有一个链接到3D线条的部分可视化,这些线条很宽并且有高度:

在jsFiddle的3D箱子线

3d框线

目标是必须以低复杂度编码 - 换句话说 - 对于假人来说.因此,3D线应该像添加球体或立方体一样简单和熟悉.几何+材质=网格>场景.在创建顶点和面时,几何图形应该非常经济.

线条应具有宽度和高度.向上总是在Y方向.该演示展示了这一点.演示没有显示的是角落被很好地贬低了......

Gar*_*ado 7

我制定了一个可能的解决方案,我认为这个解决方案可以满

http://codepen.io/garciahurtado/pen/AGEsf?editors=001

在此输入图像描述

这个概念非常简单:在"线框模式"下渲染任意几何体,然后对其应用全屏GLSL着色器以增加线框线的粗细.

着色器的灵感来自ThreeJS发行版中的模糊着色器,它基本上沿水平和垂直轴复制图像.我自动化了该过程并使副本数量成为用户定义的参数,同时确保副本偏移1个像素.

我在我的演示中使用了3D立方体网格(使用正射相机),但将它转换为多边形线条应该是微不足道的.

这个东西的真正的肉和土豆在自定义着色器(片段着色器部分)中:

    uniform sampler2D tDiffuse;
    uniform int edgeWidth;
    uniform int diagOffset;
    uniform float totalWidth;
    uniform float totalHeight;
    const int MAX_LINE_WIDTH = 30; // Needed due to weird limitations in GLSL around for loops
    varying vec2 vUv;

    void main() {
        int offset = int( floor(float(edgeWidth) / float(2) + 0.5) );
        vec4 color = vec4( 0.0, 0.0, 0.0, 0.0);

        // Horizontal copies of the wireframe first
        for (int i = 0; i < MAX_LINE_WIDTH; i++) {
            float uvFactor = (float(1) / totalWidth);
            float newUvX = vUv.x + float(i - offset) * uvFactor;
            float newUvY = vUv.y + (float(i - offset) * float(diagOffset) ) * uvFactor;  // only modifies vUv.y if diagOffset > 0
            color = max(color, texture2D( tDiffuse, vec2( newUvX,  newUvY  ) ));    
            // GLSL does not allow loop comparisons against dynamic variables. Workaround below
            if(i == edgeWidth) break; 
        }

        // Now we create the vertical copies
        for (int i = 0; i < MAX_LINE_WIDTH; i++) {
            float uvFactor = (float(1) / totalHeight);
            float newUvX = vUv.x + (float(i - offset) * float(-diagOffset) ) * uvFactor; // only modifies vUv.x if diagOffset > 0
            float newUvY = vUv.y + float(i - offset) * uvFactor;
            color = max(color, texture2D( tDiffuse, vec2( newUvX, newUvY ) ));  
            if(i == edgeWidth) break;
        }

        gl_FragColor = color;
    }
Run Code Online (Sandbox Code Playgroud)

优点:

  • 无需在线顶点之外的其他几何体
  • 线宽是用户可定义的
  • 全屏着色器在GPU上应该相对温和
  • 可以在WebGL画布中完全实现

缺点:

  • 线条厚度在水平和垂直边缘处接近完美像素,但在对角线边缘略微偏离.这是由于使用的算法,并且是解决方案的限制.话虽如此,对于低线厚度和复杂的几何形状,用肉眼几乎看不到这一点.
  • 线之间的关节将显示足够大的线厚度的间隙.您可以使用Codepen演示来查看我的意思.我开始通过添加第二个"对角线传递"来实现这个解决方案,但它有点毛茸茸,我认为这只会是更高线宽(+8像素)或极端线角度的问题.如果您对此解决方案感兴趣,可以查看原始来源以了解我的目标.
  • 由于这使用全屏滤镜,因此您只能使用WebGL上下文来显示此厚度的对象.显示各种线宽需要额外的渲染通道.


tra*_*nik 2

作为一个潜在的解决方案。您可以获取 3d 点,然后使用THREE.Vector3.project方法来计算屏幕空间坐标。然后只需使用canvas及其lineTo操作即可moveTo。Canvas 2d 上下文确实支持可变线宽。

var w = renderer.domElement.innerWidth;
var h = renderer.domElement.innerHeight;
vector.project(camera);
context2d.lineWidth = 3;
var x = (vector.x+1)*(w/2);
var y = h - (vector.y+1)*(h/2);
context2d.lineTo(x,y);
Run Code Online (Sandbox Code Playgroud)

另外,我认为您不能为此使用相同的画布,因此它必须是 gl 渲染上下文画布上方的一层(另一个画布)。

如果您不经常更换相机 - 也可以从多边形构造线并根据相机变换更新其顶点位置。对于正交相机来说,这效果最好,因为只有旋转才需要顶点位置操作。

最后,您可以禁用画布清除功能,并在圆或框内偏移多次绘制线条。之后您可以重新启用清算。这将需要几次额外的绘制操作,但这可能是最具可扩展性的方法。

线条不能按您期望的开箱即用的方式工作的原因是 ANGLE 的工作方式,据我所知,它在 Chrome 和 Firefox 中使用,它通过 DirectX 模拟 OpenGL。ANGLE 的人员表示,WebGL 规范仅要求支持线宽最大为 1,因此他们不认为这是一个错误,也不打算“修复”它。不过,线条粗细应该适用于不使用 ANGLE 的非 Windows 操作系统。