Is there a way to lazy load lines of varying widths?

Playground

I’m attempting to use GreasedLine but can’t seem to figure out what I would put in the widths array to make the lines different widths. I’ve tried single entries per line, double entries per line, with and without the width attribute… Is this even the right API for what I’m trying to accomplish?

Thanks,
Mike

cc @roland the master mind behind Greaselines!

2 Likes

Hello!

Here is an example PG for widths but I do believe you must have seen it:

Here is the part of the docs which explains the widths parameter:
https://doc.babylonjs.com/features/featuresDeepDive/mesh/creation/param/greased_line#widths-and-widthdistribution


Back to your PG. You are using the lazy parameter set to true but you are creating only one instance so there is no need to use lazy mode. Lazy mode is intended to use when you add lines dynamically to a GreasedLine instance. Lazy mode doesn’t create the GPU buffers each time you add a line. When you call updateLazy those buffers are created. It’s much more performant when you are adding a lot of lines this way.

So for example you can have some input data which you loop through and add lines one by one to a GreasedLine instance.
There is a for loop which calls CreateGreasesLine in instance and lazy mode in this example PG:

So in your PG you need to define all widths for all your lines.

    // 3 lines
    points = [
        [-2, 0, 2, 2, 0, 2],
        [-2, 0, 1, 2, 0, 1],
        [-2, 0, 0, 2, 0, 0],

    ]

    // 3 lines - for each line point you can define an upperWidth and lowerWidth
    widths = [
        0, 0, 1, 1,
        1, 1, 2, 2,
        1, 1, 0, 0
    ]

This results in:

This works in camera facing mode BUT when you use ribbonOptions (which sets the line into non camera facing mode - basically it creates a regular ribbon like mesh) as you did in your PG there seems to be an issue and it seems it applies the same widths to all lines.

    widths = [
        0.5, 0.5, 1, 1,
        2, 2, 0, 0,
        0, 0, 2, 2,
    ]

    var instance;

    instance = BABYLON.CreateGreasedLine("lines", {
        points,
        widths,
        ribbonOptions: {
            directions: BABYLON.Vector3.Backward()
        }
    }, { width: 0.5, color: BABYLON.Color3.Black() }, scene)

Result (the 3 lines are the same and that’s an issue):

I’ll check the bug ASAP.

However there is a workaround for now. You can set the ribbonOptions.directions as an Vector3[] so you can have different widths just by multiplying the desired direction vector (this solution unfortunatelly doesn’t allow to have different width at the start and different width at the end of the line):

    widths = [
        0.5,
        1,
        2
    ]

    var instance;
    instance = BABYLON.CreateGreasedLine("lines", {
        points,
        ribbonOptions: {
            directions: widths.map(w => BABYLON.Vector3.Backward().multiplyByFloats(w, w, w)),
        }
    }, { width: 0.5, color: BABYLON.Color3.Black() }, scene)

Result:

I’ll let you know when there will be a fix available.

:vulcan_salute:

1 Like

Thanks for the thorough explanation! I’ll use the workaround for now and wait for a bugfix.

You’re right, I simplified my example for the playground, but in reality I’m looping and creating ~1000 lines.

It would be nice if there was some create mode or factory option that let the developer define uniform line thickness per given line, but If each line needs 4 width parameters, I can do that. I don’t need different widths per line, I just need each line to be a certain width all the way from start point to end point.

This actually works:

You need to set the width distribution type and set the line width using the widths property as a single value in an array and you have to use instance mode. Each time a line is added to the instance the widths array will be filled/completed according the to the selected width distribution type.

Ok, lightbulb.

I think in my lack of knowledge in game development, I’m unfamiliar with some of the design patterns.

I would have expected calling that factory method again with the "line" name from the previous declaration would either overwrite that object, or throw an error. It seems that it instead adds the result of the factory function to that instance? That makes this playground make a lot more sense.

Ok, I think you might have just solved my underlying problem by correcting my API usage! Thanks! I should now be able to refactor my loops to correctly use the lazy parameter as well, now that your comment

You are using the lazy parameter set to true but you are creating only one instance so there is no need to use lazy mode

makes sense :slight_smile:

1 Like

If you use an instance you are not modifyng the name of the instance so you can leave the name even empty in subsequent calls to the factory method. The instance is specified by the instance object provided in the options and not by it’s name.

Maybe we could help to better understand GreasedLine for developers encountering it for the first time. Do you have any suggestions what could I add to the docs? Which part or parts are not enough clear or are missing? Don’t hesitate to be critical :slight_smile:

Thank you!

:vulcan_salute:

Ah, I think I’ve found something weird. Slightly different attribute I’m interested in: I’d like to change some of my line groups’ transparency.

const transparentMaterial = new BABYLON.SimpleMaterial("transparent line", scene);
transparentMaterial.diffuseColor = new BABYLON.Color3(0.9, 0.9, 0.9);
transparentMaterial.alpha = 0.5;
instance.material = transparentMaterial;

I thought I should be able to do this, and at first it seemed to just not work, but on closer inspection you can see the ribbons are actually below the ground (fly the camera around to see). I played with direction and y-index just to see if either of those were to blame and it seems not :confused:

Bug?

You must not never ever assign your own material to a GreasedLineMesh because you start to use the GPU shader provided by the newly assigned material. GreasedLine uses it’s own set of shaders.

You can choose from 3 materials when using GreasedLine

https://doc.babylonjs.com/features/featuresDeepDive/mesh/creation/param/greased_line#materialtype

enum GreasedLineMeshMaterialType {
    MATERIAL_TYPE_STANDARD = 0,
    MATERIAL_TYPE_PBR = 1,
    MATERIAL_TYPE_SIMPLE = 2
}

If you don’t need textures and light support and all the fancy stuff provides by StandardMaterial and PBRMaterial you are good to go with MATERIAL_TYPE_SIMPLE which is based on the ShaderMaterial. You still get support for multicolors, dashing, visibility, etc. This is the fastest GreasedLine material. Otherwise you can choose from the other two materials supported. MATERIAL_TYPE_SIMPLE doesn’t support transparency so in your case your best option is MATERIAL_TYPE_STANDARD. It is used by default. You can set the materialType in the third parameter of CreateGreasedLine builder function.

Back to your PG:
The choice of material is OK, you need alpha so the default MATERIAL_TYPE_STANDARD is the best option. All you have to do is create the line and then:

instance.material.alpha = 0.5;

results in:

:vulcan_salute:

1 Like

Awesome, that works!

1 Like

Hey @phill2mj !

I’m starting to fix this today :saluting_face:

2 Likes