0

I want to create a line that smoothly curves into space and is colored by gradient, but also has 3d properties (something I do not get 100% from the MeshLine library, and closely approximates the fat-lines example - https://threejs.org/examples/webgl_lines_fat.html)


Issues I'm facing:

  • Creating gradient or shading on line
  • Making line "solid"
  • Line "resolution" (seems jagged) when using MeshLine
  • I would like to get advantage of MeshLine's easy-to-animate properties in the long term

Do you have any suggestions on how I could achieve that? It is my first time experimenting with THREE.js so I'm a bit of a novice when it comes to its limitations

My code so far:

function makeLine(geometry, color, width) {
    var newLine = new MeshLineGeometry()
    newLine.setPoints(geometry)

    var material = new MeshLineMaterial({
        //map - a THREE.Texture to paint along the line (requires useMap set to true)
        useMap: false, //tells the material to use map (0 - solid color, 1 use texture)
        //alphaMap - a THREE.Texture to paint along the line (requires useAlphaMap set to true)
        //useAlphaMap - tells the material to use alphaMap (0 - no alpha, 1 modulate alpha)
        //repeat - THREE.Vector2 to define the texture tiling (applies to map and alphaMap - MIGHT CHANGE IN THE FUTURE)
        color: new THREE.Color(color), //THREE.Color to paint the line width, or tint the texture with
        opacity: 1, //alpha value from 0 to 1 (requires transparent set to true)
        //alphaTest - cutoff value from 0 to 1
        //dashArray - the length and space between dashes. (0 - no dash)
        //dashOffset - defines the location where the dash will begin. Ideal to animate the line.
        //dashRatio - defines the ratio between that is visible or not (0 - more visible, 1 - more invisible).
        resolution: resolution, //THREE.Vector2 specifying the canvas size (REQUIRED)
        sizeAttenuation: false, //makes the line width constant regardless distance (1 unit is 1px on screen) (0 - attenuate, 1 - don't attenuate)
        lineWidth: width, //float defining width (if sizeAttenuation is true, it's world units; else is screen pixels)
        //near: camera.near,
        //far: camera.far
    })

    // Create a new Mesh and set its geometry and material, then add it to the graph
    var mesh = new MeshLine(newLine, material)
    graph.add(mesh)
}

// Define the init function to create the lines
function init() {
    createLines();
    createAxes();
    createCurve();
    createSpline()
}
function createSpline() {
    // create a curve using CatmullRomCurve3, which is a type of curve that smoothly interpolates points in 3D space
    var spline = new THREE.CatmullRomCurve3(
        [
            new THREE.Vector3(-30, 2, 0), // starting point of the curve
            new THREE.Vector3(10, 10, 0),
            new THREE.Vector3(30, 1, 0),
            new THREE.Vector3(-30, 12, 20) // ending point of the curve
        ]
    );
    var divisions = Math.round(12 * spline.points.length);
    console.log(spline.points.length);
    var positions = [];
    var colors = [];

    var color = new THREE.Color();


    for (var i = 0, l = divisions; i < l; i++) {

        var point = spline.getPoint(i / l);
        positions.push(point.x, point.y, point.z);

        color.setHSL(i / l, 1.0, 0.5);
        colors.push(color.r, color.g, color.b);

    }
    makeLine(positions, 'red', 40);
}

function createCurve() {
    // create a curve using CatmullRomCurve3, which is a type of curve that smoothly interpolates points in 3D space
    var curve = new THREE.CatmullRomCurve3(
        [
            new THREE.Vector3(-30, 2, 0), // starting point of the curve
            new THREE.Vector3(10, 10, 0),
            new THREE.Vector3(30, 1, 0),
            new THREE.Vector3(-30, 12, 20) // ending point of the curve
        ]
    );

    // define the number of points that will be used to create the ribbon
    var pointsCount = 100;

    // increase the number of points to create a more detailed ribbon
    var pointsCount1 = pointsCount + 1;

    // create a new array of points by offsetting the original points along the z-axis
    var points = curve.getPoints(pointsCount);
    var width = 5; // the width of the ribbon
    var widthSteps = 1; // the number of steps to use when creating the ribbon width
    let ptsZ = curve.getPoints(pointsCount);
    ptsZ.forEach(p => {
        p.z += width; // move each point in pts2 along the z-axis by the width of the ribbon
    });
    points = points.concat(ptsZ); // concatenate the two arrays of points to create the final array of points for the ribbon

    // create a BufferGeometry from the array of points
    var ribbonGeom = new THREE.BufferGeometry().setFromPoints(points);

    // create the faces of the ribbon using the indices of the points in the array
    var indices = [];
    for (var iy = 0; iy < widthSteps; iy++) { // iterate over the number of steps in the width of the ribbon
        for (var ix = 0; ix < pointsCount; ix++) { // iterate over the number of points along the curve
            var a = ix + pointsCount1 * iy;
            var b = ix + pointsCount1 * (iy + 1);
            var c = (ix + 1) + pointsCount1 * (iy + 1);
            var d = (ix + 1) + pointsCount1 * iy;
            // create two faces for each "quad" of points, which will create the shape of the ribbon
            indices.push(a, b, d);
            indices.push(b, c, d);
        }
    }
    ribbonGeom.setIndex(indices); // set the indices for the BufferGeometry to define the faces of the ribbon
    ribbonGeom.computeVertexNormals(); // compute the vertex normals for the ribbon, which will be used for shading

    // create a new Mesh using the BufferGeometry and a Material, and add it to the scene
    var ribbon = new THREE.Mesh(
        ribbonGeom,
        new THREE.MeshNormalMaterial({
            side: THREE.DoubleSide // make the ribbon double-sided to ensure it's visible from all angles
        })
    );
    scene.add(ribbon);
}

function createAxes() {
    var axesColor = 0x5ca4a9 //color of graph
    var axesWidth = 10 //width of graph

    //x-axis
    var line = [];
    line.push(new THREE.Vector3(-30, -30, -30)); //Point 1 x, z, y
    line.push(new THREE.Vector3(30, -30, -30));//Point 2 x, z, y
    //line connects points 1 and 2
    //more points can be added to create more complex lines
    makeLine(line, axesColor, axesWidth);

    //z-axis (vertical)
    var line = [];
    line.push(new THREE.Vector3(-30, -30, -30));
    line.push(new THREE.Vector3(-30, 30, -30));
    makeLine(line, axesColor, axesWidth);

    //y-axis
    var line = [];
    line.push(new THREE.Vector3(-30, -30, -30));
    line.push(new THREE.Vector3(-30, -30, 30));
    makeLine(line, axesColor, axesWidth);
}

function createLines() {
    // Creates a Float32Array for line data with 600 positions
    var line = new Float32Array(600);
    // For loop that increments by 3
    for (var j = 0; j < 200 * 3; j += 3) {
        // Assigns x, y, and z coordinates to line array
        line[j] = -30 + .1 * j;
        line[j + 1] = 5 * Math.sin(.01 * j);
        line[j + 2] = -20;
    }
    // Calls makeLine function and passes in the line array and color index 0
    makeLine(line, colors[0], 10);
}
}

Code is based on: http://spite.github.io/THREE.MeshLine/demo/graph.html How Can I Convert a THREE.CatmullRomCurve3 to a Mesh?

Tried using MeshLine and fat-lines, no progress

Lkjam
  • 1
  • 2
  • Maybe this forum topic will help somehow: https://discourse.threejs.org/t/vertexless-line-fat-lines-datatexture-instancing/46156 – prisoner849 Mar 05 '23 at 09:51

0 Answers0