Thickness of lines using THREE.LineBasicMaterial

后端 未结 8 1506
小鲜肉
小鲜肉 2020-11-27 06:53

I am using the code below to create hundreds of lines in my three.js scene

edgeGeometry[i] = new THREE.Geometry();
edgeGeometry[i].vertices[0] = v(x1,y1,z1);         


        
相关标签:
8条回答
  • 2020-11-27 06:56

    This is no longer an issue just in ANGLE it's an issue on all platforms. Browsers needed to switching to the OpenGL 4+ core profile to support WebGL2 and the OpenGL 4+ core profile does not support line widths greater than 1. From the OpenGL 4.0+ spec, section E.2.1

    E.2.1 Deprecated But Still Supported Features

    The following features are deprecated, but still present in the core profile. They may be removed from a future version of OpenGL, and are removed in a forward compatible context implementing the core profile.

    • Wide lines - LineWidth values greater than 1.0 will generate an INVALID_VALUE error.

    To draw thicker lines you need generate geometry. For three.js there is this library (pointed out by Wilt as well)

    https://github.com/spite/THREE.MeshLine

    0 讨论(0)
  • 2020-11-27 07:01

    This occurs in Windows Chrome and Firefox, both using ANGLE (WebGL to DirectX wrapper).

    The issue is still not solved by the ANGLE project. You can star the issue here to get higher priority and get a notification if it's going to be implemented:

    https://code.google.com/p/angleproject/issues/detail?id=119

    0 讨论(0)
  • 2020-11-27 07:02

    1) Use native OpenGL

    You can achieve rendering of line thicknesses with a workaround by setting your browser to use native OpenGL instead of ANGLE. You can read here on how to do this on Chrome. Keep in mind that you will experience performance differences if you swap to native OpenGL.

    EDIT:

    The master MrDoob himself posted here how to do this for both Chrome and Firefox.

    Note: This first option is no longer a valid solution since the latest OpenGL versions no longer support line thickness either. Check also @gman his answer. This means if you want to use line thickness the second option is the way to go.


    2) Use THREE.MeshLine class

    There is also another solution; this THREE.MeshLine class on github is a nice workaround. It comes with a special THREE.MeshLineMaterial. According to the docs it is as simple as:

    • Create and populate a geometry
    • Create a THREE.MeshLine and assign the geometry
    • Create a THREE.MeshLineMaterial
    • Use THREE.MeshLine and THREE.MeshLineMaterial to create a THREE.Mesh
    0 讨论(0)
  • 2020-11-27 07:02

    You can use CanvasRenderer instead of Webglrenderer. Check out the ifficial documentation here where each shape has a border of linewidth = 10;

    0 讨论(0)
  • 2020-11-27 07:03

    Thanks to Wilt's answer for pointing me in the right direction with THREE.MeshLine.

    It can be slightly trickier than they make it out to be, however... So here's my solution following their docs and their demo code very carefully... (assuming you've already included Three and 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;
    

    With size attenuation off and using THREE.DoubleSide, like I did above, the circle will look like a nice, consistent circle no matter where you're looking at it from (not "true 3D").

    For just a line, you can obviously easily adapt.

    0 讨论(0)
  • 2020-11-27 07:16

    You can achieve the same effect using extrude-polyline to generate a simplicial complex for the thickened (poly)line and three-simplicial-complex to convert this to a three.js Mesh:

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

    Here's a complete example along with the source. (There's currently an issue on requirebin that prevents it from rendering the source example).

    If you want to texture map the polyline, things get a little more complicated.

    0 讨论(0)
提交回复
热议问题