2013-12-23 129 views
12

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

尽管Three.js线对象支持线宽,但WebGL中所有平台上的所有浏览器都不支持该属性。

在这里你在three.js所设置线宽:

var material = new THREE.LineBasicMaterial({ 
     color: 0xff0000, 
     linewidth: 5 
    }); 

的three.js所带状物 - 其中有宽度 - 最近已经下降。

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

任何人都可以想到在Three.js中绘制直线系列(多段线,图线)的方法,它具有某种用户可定义的“体积”,例如宽度,厚度或半径?

此问题可能是对此问题的重述: Extruding a graph in three.js

鉴于我不认为有一个现成的方法,我很乐意参与努力创建一个简单的函数来回应这个问题。

但是,指向现有可行的方法将降温的应答...

作为WestLangley所暗示的,一个可能的解决方案包括恒定像素宽度的折线为 - 当前可用与three.js所画布渲染器。

两个渲染器的比较如下所示:

Canvas and WebGL Lines Compared via GitHub Pages

Canvas and WebGL Lines Compared via jsFiddle

enter image description here

在那里你可以指定线宽和类似结果的解决方案出现在两个渲染器将是非常凉。

然而,还有其他思考3D线的方法,其中线具有实际的物理构造。他们投下阴影,他们对事件做出反应。这些也需要研究。

下面是联结到GitHub的页数与由多个网格线的两条演示:

Spheres and Cubes Polyline

Sphere and Cylinder Polylines

一个“昂贵的解决方案。每个关节都由一个完整的球体组成。

Cubes Polylines

Cubes Polylines

我的猜测是建立这两种顺利单一网格将复杂的问题需要解决。因此,在这里同时是那宽3D线的部分可视化链接,并具有高度:

3D Box Line on jsFiddle

3d box lines

的目标是必须的代码“与复杂的低水平 - 换句话说 - 对于傻瓜来说。因此,3D线条应该与添加球体或立方体一样容易和熟悉。几何体+材质=网格>场景。就创建顶点和面而言,几何图形应该非常经济。

线应该有宽度和高度。向上始终在Y方向。演示显示了这一点。该演示没有显示的角落被很好地缓和...

+0

分段线性'TubeGeometry'就足够了吗? (你必须避免尖角。) – WestLangley

+0

嗨WestLangley。 TubeGeometry确实是一个强大的工具,但它甚至不绘制矩形。控制点不是角落。并且有很多图表事物,其中线柱通过顶点或者不可信... – Theo

+0

另外,我不确定'分段线性'是什么意思。你能更完整地描述这个术语吗? – Theo

回答

2

作为一个潜在的解决方案。你可以把你的3d点,然后用THREE.Vector3.project方法来确定屏幕空间坐标。然后,简单地使用画布,它的作业为lineTomoveTo。 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); 

另外,我不认为你可以使用相同的画布,所以它必须是你的gl渲染上下文画布上方的图层(另一个画布)。

如果您偶尔发生相机更改 - 也可以根据相机变换构造出多边形的线条并更新它的顶点位置。对于正射相机而言,这将最有效,因为只有旋转需要顶点位置操作。

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

原因线不能正常工作,这是因为ANGLE的工作原理,它在Chrome和Firefox中使用,据我所知,它通过DirectX模拟OpenGL。来自ANGLE的专家表示,WebGL规范只需要支持最多1行的线宽,所以他们不会将其视为bug并且不打算“修复”它。虽然在不使用ANGLE的情况下,线条粗细应该适用于非Windows操作系统。

7

我想出一个可行的解决方案,我相信满足你的大部分需求:

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

enter image description here

的概念相当简单:渲染“线框模式”任意形状,然后对其应用全屏GLSL着色器以向线框线添加厚度。

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

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

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

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; 
    } 

优点:

  • 无需超越行额外几何顶点
  • 线条粗细是用户可定义的
  • 全屏着色器在GPU上应该比较温和
  • 能充分WebGL的画面内实现

缺点:

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