Creating A GreasedLine
GreasedLine
GreasedLine is a special type of line that uses a regular mesh with triangles to display a line of any width. It incorporates custom shaders designed to ensure that the mesh always faces the camera, resulting in consistent thickness from all perspectives. The shaders are provided through a plugin material. You can use StandardMaterial or PBRMaterial with GreasedLine, so you can use any property of the material to stylize your line. GreasedLine also features dashing, multicolored lines with sampling options, color blending options, variable width on both sides of the line (upper and lower parts), visibility (what percentage of the line is visible), point coordinate offsets, instance mode (you can add more lines to an instance and they will be drawn in one draw call), and lazy mode. The values for these features are animatable. You can also translate, rotate, and scale the line because it's a mesh.
Create a GreasedLine
The easiest, preferred and recommended way to create a GreasedLine is to use the CreateGreasedLine function:
function CreateGreasedLine(name: string, options: GreasedLineMeshBuilderOptions, materialOptions?: Nullable<GreasedLineMaterialBuilderOptions>, scene?: Nullable<Scene>)The simplest usage is:
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const line = CreateGreasedLine("name", { points });Dispose a GreasedLine
Please note that the dispose function doesn't dispose the material created for the line by default. You have to set the disposeMaterialAndTextures parameter to true in the dispose function if you want to dispose the associated material and textures as well.
GreasedLineMeshBuilderOptions
You will find an explanation of these options below this code snippet.
points: GreasedLinePoints;pointsOptions?: GreasedLinePointsOptions;widths?: number[];widthDistribution?: GreasedLineMeshWidthDistribution;instance?: GreasedLineMesh;updatable?: boolean;uvs?: number[];lazy?: boolean;points
Points of the line specified as x, y, z coordinates. All the points connected are called a line. The part of the line between two points is called a line segment in this documentation.
points can be of type number[], number[][], Vector3[], Vector3[][], Float32Array, or Float32Array[].
If you want to draw only one contiguous line you can use 1D arrays or Float32Array. If you want to draw multiple lines you have to use 2D arrays or Float32Array[].
To draw multiple disconnected lines using a flat Float32Array, you can specify the pointsOptions.stride property in the GreasedLineMeshBuilderOptions object. This value sets how many entries from the Float32Array will be used to create one line. One entry = 3 float values.
import { Vector3 } from "@babylonjs/core/Maths/math.vector";const points =[ 0, 0, 0, 1, 0, 0, 1, 1, 0]// x, y, z,// x, y, z, ...
// is the same asconst points =[ new Vector3(0,0,0) new Vector3(1,0,0) new Vector3(1,1,0)]It's a good habit to format your number coordinates for better readability.
We recommend using number or Float32Array objects when possible to avoid the unnecessary creation of temporary Vector3 objects holding the points, especially if you are creating the coordinates dynamically on the fly. The coordinates are converted to number[][] internally, so number[] or number[][] are the fastest options.
To draw two or more lines at once, you can define the points as:
const points = [ [0, 0, 0, 1, 0, 0], [0, 1, 0, 1, 1, 0],];You can draw more lines at once by using the instance option. See the Instance mode example below.
You need to specify at least two points to draw a line, obviously.
Do not use sharp-angle connected long lines because they can be distorted by perspective. Use smaller line segments. There are helper functions available in BABYLON.GreasedLineTools for that. See the GreasedLineTools section for more info. Another option is to create two lines and add them to one instance, or add them as separate lines like this (this approach can cause small quirks where the lines 'connect' to each other when using dash mode, depending on your line width):
const points = [ [-10, 0, 0, 0, 10, 0], [0, 10, 0, 10, 0, 0],];There is another option to avoid distortion when drawing thick, connected, long line segments: you need to duplicate each position, as demonstrated here:
Duplicating pointsPlease note that the points property is not updatable, unlike when using a LineMesh. You have to use the offsets property on the line instance to update point positions without recreating the mesh. Updating the offsets doesn't involve any calculations and updates only one vertex buffer. See the Offsets section below and the PG example Offsetting line vertices.
However, there are two public methods available on the line instance for manipulating the points. Both of these functions will destroy the mesh and create a new one. This point-manipulation method is slower, but if you are not dealing with a lot of lines, it should not cause FPS issues.
addPoints(points: number[][]) // ads points to the existing ones and recreates the meshsetPoints(points: number[][]) // sets the points and recreates the mesh - the number of points must be the same as in the original lineIf you are using the right-handed coordinate system, please create the lines after you switch the scene to it.
If you modify the number of points in the line, you have to set the widths for the new lines or line segments before calling either of these two methods.
widths and widthDistribution
You can specify two width multiplier values for each point in your line. These values are multiplied with the width of the line to draw the resulting line. The first value specifies the width multiplier of the line below the line and the second above the line. These values are not normalized so if you use a value of 2, 2 the line will be twice the width at that point. There must be exactly the same count of width pair values as there are points.
The CreateGreasedLine function uses the function CompleteGreasedLineWidthTable to fill the missing values, if any. You can use the widthDistribution option to set the method used to automatically fill the widths table.
You can choose from these values:
enum GreasedLineMeshWidthDistribution { WIDTH_DISTRIBUTION_NONE = 0, WIDTH_DISTRIBUTION_REPEAT = 1, WIDTH_DISTRIBUTION_EVEN = 2, WIDTH_DISTRIBUTION_START = 3, WIDTH_DISTRIBUTION_END = 4, WIDTH_DISTRIBUTION_START_END = 5,}The default for this option is WIDTH_DISTRIBUTION_START.
Let's see an example:
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [0, 0, 0, 1, 0, 0];const widths = [2, 2];const line = CreateGreasedLine("line", { points, widths });You can use the function CompleteGreasedLineWidthTable manually and set the widthDistribution to WIDTH_DISTRIBUTION_NONE. If you prepared the width table with the correct number of entries, set widthDistribution to WIDTH_DISTRIBUTION_NONE as well.
Please have a look at the API docs for more explanation about the width distribution modes.
You might wonder, as you continue reading, why you'll find the width option specified in materialOptions and widths here. It's because the options object contains all the mesh-related options, and width is used when creating the material, so it is material-related.
instance
You can add lines to an existing line whenever you want. All you need to do is specify the instance option and set a GreasedLineMesh instance on it. Every time you add a new line, all the data needed to render the line will be recalculated and the buffers will be updated. If you are adding many lines to an instance, use the lazy option. Lines added to an instance are joined with the existing mesh. See the examples for code.
updatable
If you want to update your line mesh after it was created, set this option to true when creating the line. This applies to offsets, segmentWidths, and colorPointers. This option doesn't affect the line materials, which can be updated at any time. Set this value to false if you don't intend to update the line mesh, for better performance. If you are adding lines to an existing line instance, you have to set this option on the line that was created first.
uvs
You can set your custom UVs when creating the line.
lazy
You can disable recalculating line data and updating the buffers when adding a new line to a line instance by setting this option to true. This option is always used with the instance option specified. If you're done adding new lines, you just need to call line.updateLazy() to recalculate the data and update the buffers. See the examples for code.
GreasedLineMaterialBuilderOptions
createAndAssignMaterial?: boolean;width?: number;sizeAttenuation?: boolean;materialType?: GreasedLineMeshMaterialType;color?: Color3;colorMode?: GreasedLineMeshColorMode;colors?: Color3[];colorDistribution?: GreasedLineMeshColorDistribution;colorDistributionType?: GreasedLineMeshColorDistributionType;useColors?: boolean;colorsSampling?: number;useDash?: boolean;dashCount?: number;dashOffset?: number;dashRatio?: number;visibility?: number;resolution?: Vector2;cameraFacing?: boolean;createAndAssignMaterial
If set to true a new material will be created and a new material plugin will be attached to the material. The material will be set on the mesh. If the instance option is specified in the mesh options, no material will be created/assigned. If you omit GreasedLineMaterialBuilderOptions when calling CreateGreasedLine it behaves as if this option was set to true so it creates the material and the plugin. The default value is true. You can share the material between multiple lines so if you don't need a new material, set this to false to save resources and gain performance.
width
Line width in scene units unless sizeAttenuation is true. You can override the default value:
GreasedLineMaterialDefaults.DEFAULT_WIDTH_ATTENUATED = 10;GreasedLineMaterialDefaults.DEFAULT_WIDTH = 0.5;All lines created after setting this value and not providing a width option will use this value as the default one.
sizeAttenuation
If true, the line width will always be the same regardless of the distance from the camera. The upper line has constant width no matter how far it is from the camera. This PG also demonstrates how to use default values:
Size attenuation and GreasedLineMaterialDefaultsmaterialType
Type of the material to use to render the line. Default is StandardMaterial. Currently you can choose from:
enum GreasedLineMeshMaterialType { MATERIAL_TYPE_STANDARD = 0, MATERIAL_TYPE_PBR = 1, MATERIAL_TYPE_SIMPLE = 2}The first two materials are implemented using material plugins. The simple material is based on a shader material. It is super fast but supports only plain colors without lighting.
color
Color of the line. Applies to all line segments. Defaults to White. You can change the default color to any other color.
import { GreasedLinePluginMaterial } from "@babylonjs/core/Materials/GreasedLine/greasedLinePluginMaterial";import { Color3 } from "@babylonjs/core/Maths/math.color";GreasedLinePluginMaterial.DEFAULT_COLOR = Color3.Green();colorMode
Color mode of the line. Applies to all line segments. The pixel color from the material shader will be modified with the value of color using the colorMode. The default mode is GreasedLineMeshColorMode.SET. This means it will set the color regardless of the color from the material shader. To be more precise, it sets the color to the exact value and doesn't care about the color information from the material (textures, lighting, ...).
You can choose from and the names are self-explanatory:
enum GreasedLineMeshColorMode { COLOR_MODE_SET = 0, COLOR_MODE_ADD = 1, COLOR_MODE_MULTIPLY = 2,}Please note a difference: MATERIAL_TYPE_SIMPLE mixes the color and colors of the greased line material. MATERIAL_TYPE_STANDARD and MATERIAL_TYPE_PBR mix the color from the base material with the color or the colors of the greased line material.
colors and colorDistribution
An array of colors for the line segments. The maximum number of colors supported for one line instance depends on the maximum texture width your GPU can support (we use 1D textures here for maximum performance). The minimum for all WebGL systems is 4k. On most modern desktop GPUs it is 16k. Each color in the array represents a line segment color. There must be exactly the same number of colors in the array as there are line segments in the line.
The CreateGreasedLine function uses the function CompleteGreasedLineColorTable to fill the missing values, if any. You can use the colorDistribution option to set the method used to automatically fill the colors table.
You can choose from these values:
enum GreasedLineMeshColorDistribution { COLOR_DISTRIBUTION_NONE = 0, COLOR_DISTRIBUTION_REPEAT = 1, COLOR_DISTRIBUTION_EVEN = 2, COLOR_DISTRIBUTION_START = 3, COLOR_DISTRIBUTION_END = 4, COLOR_DISTRIBUTION_START_END = 5,}The default for this option is COLOR_MODE_START.
Let's see an example (you will end up with a half-red, half-white line).
import { Color3 } from "@babylonjs/core/Maths/math.color";import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [0, 0, 0, 1, 0, 0, 2, 0, 0];const colors = [Color3.Red()];const line = CreateGreasedLine("line", { points }, { colors });The colors are used only when the option useColors is set to true and you do not set the color option. There is one exception; see the documentation for the useColors option below.
The color blending of the colors depends on colorMode option.
colorDistributionType
The method used to distribute the colors along the line. You can use segment distribution, where each segment uses one color from the color table. Or you can use line distribution, where the colors are distributed evenly along the line while ignoring the segments.
Color distribution type Line colors using your own textureWhen running on WebGPU/WGSL you must use RGBA textures:
Line colors using your own texture - WebGPU/WGSL Animating line colors using your own texture Setting color pointers manuallycolorsSampling
Sampling type of the colors texture. Defaults to NEAREST_NEAREST. The line segment will be distinctly colored. If you use for example LINEAR_LINEAR you'll get a smooth color gradient.
Colors samplinguseColors
If true, colors are used, otherwise they're ignored.
There is a scenario when you need to set useColors to true and set the color option as well. Look at the PG:
useDash
If true, dashing is used.
DashingdashCount
Number of dashes in the line. If you add more lines, all of them will use this dash count and they are not treated as one line.
dashRatio
Length of the dash. 0 to 1. 0.5 means half empty, half drawn.
dashOffset
Offset of the dashes along the line. 0 to 1. Normalized value.
visibility
Sets the line length visibility. Normalized value. 0 - 0% of the line will be visible. 1 - 100% of the line will be visible.
Visibilityresolution
Rendering resolution. There may be special occasions when you want to change the resolution. In most cases do not set this value.
cameraFacing
Whether to use camera facing for the line. Defaults to true. If set to true, you have to use the GreasedLineMesh class to create the mesh. If set to false, you have to use the GreasedLineRibbonMesh class. The builder function automatically takes care of this decision and sets this value to false if ribbonOptions is present in the GreasedLineBuilderMeshOptions.
GreasedLine materials
GreasedLine uses StandardMaterial, PBRMaterial, or ShaderMaterial (MATERIAL_TYPE_SIMPLE) as the base material for rendering. It also uses a GreasedLinePluginMaterial, which plugs into the base material and provides the additional features of GreasedLine.
If you want to alter the properties of the material, you need to use line.material, but if you want to change the GreasedLine-specific material properties, you need to do it on the line.greasedMaterial object. All three materials implement the IGreasedLineMaterial interface:
/** * Interface which defines the available methods for a GreasedLineMaterial */export interface IGreasedLineMaterial { /** * Normalized value of how much of the line will be visible * 0 - 0% of the line will be visible * 1 - 100% of the line will be visible */ visibility: number;
/** * Line base width. At each point the line width is calculated by widths[pointIndex] * width */ width: number;
/** * Turns on/off dash mode */ useDash: boolean;
/** * @see GreasedLinePluginMaterial.setDashCount * Number of dashes in the line. * Defaults to 1. */ dashCount: number;
/** * Dash offset */ dashOffset: number;
/** * Length of the dash. 0 to 1. 0.5 means half empty, half drawn. */ dashRatio: number;
/** * Whether to use the colors option to colorize the line */ useColors: boolean;
/** * The mixing mode of the color paramater. Default value is GreasedLineMeshColorMode.SET. MATERIAL_TYPE_SIMPLE supports only the default value/mode. * @see GreasedLineMeshColorMode */ colorMode: GreasedLineMeshColorMode;
/** * Colors of the line segments. * Defaults to empty. */ colors: Nullable<Color3[]>;
/** * If false then width units = scene units. If true then line will width be reduced. * Defaults to false. */ sizeAttenuation: boolean;
/** * Color of the line. Applies to all line segments. * Defaults to White. * MATERIAL_TYPE_STANDARD and MATERIAL_TYPE_PBR material's shaders will get recompiled if there was no color set and you set a color or when there was a color set and you set it to null. */ color: Nullable<Color3>;
/** * The method used to distribute the colors along the line. * You can use segment distribution when each segment will use on color from the color table. * Or you can use line distribution when the colors are distributed evenly along the line ignoring the segments. */ colorsDistributionType: GreasedLineMeshColorDistributionType;
/** * Defaults to engine.getRenderWidth() and engine.getRenderHeight() * Rendering resolution */ resolution: Vector2;
/** * Allows to change the color without marking the material dirty. * MATERIAL_TYPE_STANDARD and MATERIAL_TYPE_PBR material's shaders will get recompiled if there was no color set and you set a color or when there was a color set and you set it to null. Use the flag to not to recompile immediately. * @param value the color * @param doNotMarkDirty the flag */ setColor(value: Nullable<Color3>, doNotMarkDirty?: boolean): void;
/** * * @param colors colors array * @param lazy if true the colors texture will not be updated * @param forceNewTexture forces to create a new colors texture */ setColors(colors: Nullable<Color3[]>, lazy: boolean, forceNewTexture?: boolean): void;
/** * Creates and sets the colors texture from the colors array which was created in lazy mode */ updateLazy(): void;}All other properties must be defined when creating the line.
As you can see in the comment of the color public property, the shader gets recompiled if there are specific changes of this property. A real life scenario: You might want to draw textured lines. On a specific event you want to colorize the texture. In this case create the line with color set to Color3.White() and set the colorMode to GreasedLineColorMode.COLOR_MODE_MULTIPLY. The result will be the same as not setting a color. However now you can change the color to for example rgb(0.5, 0.5, 0.5) to dim the texture colors without shader recompilation. This doesn't apply to MATERIAL_TYPE_SIMPLE because this material supports only GreasedLineColorMode.COLOR_MODE_SET so there will be no shader recompilation upon changes of the color property at all.
Materials can be shared between line instances. If you create a line and the other should have the same material options, then create the other line(s) by setting the createAndAssignMaterial option to false and simply set the material:
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points1 = [-1, 0, 0, 1, 0, 0];const line1 = CreateGreasedLine("line1", { points: points1 });const points2 = [-1, 1, 0, 1, 1, 0];const line2 = CreateGreasedLine("line2", { points: points2 }, { createAndAssignMaterial: false });line2.material = line1.material;Examples
The best way to show the possibilities of GreasedLine is to go through the following examples.
Basic code snippets with StandardMaterial
Line with no material settings, default width, default color
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, 1, 0, 0];const line = CreateGreasedLine("line", { points });Lines with no material settings, default width, default color
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [ [-1, 0, 0, 1, 0, 0], [-1, 1, 0, 1, 1, 0],];const lines = CreateGreasedLine("lines", { points });Line with a color specified
import { Color3 } from "@babylonjs/core/Maths/math.color";import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, 1, 0, 0];const line = CreateGreasedLine("line", { points }, { color: Color3.Red() });You can set the default color:
import { Color3 } from "@babylonjs/core/Maths/math.color";GreasedLineMaterialDefaults.DEFAULT_COLOR = Color3.Red();Please note that the color will be cloned so changing this value will not affect the existing lines.
Line with a width specified
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, 1, 0, 0];const line = CreateGreasedLine("line", { points }, { width: 0.5 });Line with multiple colors
import { Color3 } from "@babylonjs/core/Maths/math.color";import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, 1, 0, 0];const colors = [Color3.Red(), Color3.Yellow()];const line = CreateGreasedLine("line", { points }, { useColors: true, colors });Line with multiple widths
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, -0.5, 0, 0, 0, 0, 0, 0.5, 0, 0, 1, 0, 0];const widths = [1, 1, 2, 2, 3, 3, 2, 2];const line = CreateGreasedLine("line", { points, widths });Instance mode
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, 1, 0, 0];const line = CreateGreasedLine("line", { points });const points2 = [-1, 1, 0, 1, 1, 0];CreateGreasedLine("line", { instance: line, points: points2 });Lazy mode
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, 1, 0, 0];const line = CreateGreasedLine("line", { lazy: true, points });const points2 = [-1, 1, 0, 1, 1, 0];CreateGreasedLine("line", { instance: line, lazy: true, points: points2 });const points3 = [-1, -1, 0, 1, -1, 0];CreateGreasedLine("line", { instance: line, lazy: true, points: points3 });line.updateLazy();Dashed line
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, 1, 0, 0];const line = CreateGreasedLine("line", { points }, { useDash: true, dashCount: 4, dashRatio: 0.5 });Line visibility
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, 1, 0, 0];const line = CreateGreasedLine("line", { points }, { visibility: 0.5 });Offsets
You can offset the vertices of the line. Keep in mind that there are 2 vertices per point and the line must be updatable. If your line disappears after calling this function, it means you haven't provided enough offsets. There is a function BABYLON.GreasedLineTools.GetPointsCountInfo(points: number[][]): { total: number; counts: number[] } that will tell you the exact counts. Just pass your line's points option to this function.
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, 1, 0, 0];const line = CreateGreasedLine("line", { points, updatable: true });const offsets = [-0.3, -0.3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];line.offsets = offsets;Adding/setting points to an existing GreasedLine instance
You can add points to an existing GreasedLine instance. The width table is extended automatically to match the vertex count, and the new widths are set to 1. You have to replace these values manually after the points are added, if needed. You can do this by setting the values on the line.widths array.
The color table, if useColors is true, must be extended manually. Please pay attention to the code in the PG and the comments on how to correctly extend the color table.
The line must be created with the updatable: true option.
Have a look at the PG called Adding and setting points on an existing instance at the end of the page.
Line transformations
import { Vector3 } from "@babylonjs/core/Maths/math.vector";import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, 1, 0, 0];const line = CreateGreasedLine("line", { points });line.position.x = 2;line.rotation.z = Math.PI / 2;line.scaling = new Vector3(2, 2, 2);Drawing arcs
import { Curve3 } from "@babylonjs/core/Maths/math.path";import { Vector3 } from "@babylonjs/core/Maths/math.vector";import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const f = new Vector3(-0.5 + Math.random(), -0.5 + Math.random(), -0.5 + Math.random()).scale(20);const s = new Vector3(-0.5 + Math.random(), -0.5 + Math.random(), -0.5 + Math.random()).scale(20);const t = new Vector3(-0.5 + Math.random(), -0.5 + Math.random(), -0.5 + Math.random()).scale(20);const arc = Curve3.ArcThru3Points(f, s, t);const arcLine = CreateGreasedLine("arc", { points: arc.getPoints() });Line with texture
import { GreasedLineMeshColorMode } from "@babylonjs/core/Materials/GreasedLine/greasedLineMaterialInterfaces";import { Texture } from "@babylonjs/core/Materials/Textures/texture";import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points1 = [-6, 0, 0, 6, 0, 0];const line1 = CreateGreasedLine("line1", { points: points1 }, { width: 1, colorMode: GreasedLineMeshColorMode.COLOR_MODE_MULTIPLY });const texture = new Texture("/textures/amiga.jpg", scene);texture.uScale = 10;line1.material.emissiveTexture = texture;The default color is white and the default colorMode is BABYLON.GreasedLineMeshColorMode.COLOR_MODE_SET so you need to set colorMode to BABYLON.GreasedLineMeshColorMode.COLOR_MODE_MULTIPLY to render the texture visible or you can remove the color by setting its value to null if you don't want to do color blending at all. Setting the color from null to a value or setting from a value to null will recompile the shader.
import { Texture } from "@babylonjs/core/Materials/Textures/texture";import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points1 = [-6, 0, 0, 6, 0, 0];const line1 = CreateGreasedLine("line1", { points: points1 }, { width: 1 });line1.greasedLineMaterial.color = null;const texture = new Texture("/textures/amiga.jpg", scene);texture.uScale = 10;line1.material.emissiveTexture = texture;Setting line color using its material
You have to set a colorMode option or set the color to null. Setting the color from null to a value or setting from a value to null will recompile the shader.
import { Color3 } from "@babylonjs/core/Maths/math.color";import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points1 = [-6, 0, 0, 6, 0, 0];const line1 = CreateGreasedLine("line1", { points: points1 }, { width: 1 });line1.greasedLineMaterial.color = null;line1.material.emissiveColor = Color3.Red();Glowing line
You have to set a colorMode option or set the color to null. Setting the color from null to a value or setting from a value to null will recompile the shader.
import { GlowLayer } from "@babylonjs/core/Layers/glowLayer";import { Color3 } from "@babylonjs/core/Maths/math.color";import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points1 = [-6, 0, 0, 6, 0, 0];const line1 = CreateGreasedLine("line1", { points: points1 }, { width: 1 });line1.greasedLineMaterial.color = null;line1.material.emissiveColor = Color3.Red();const gl = new GlowLayer("glow", scene, { blurKernelSize: 32,});gl.intensity = 1.8;gl.referenceMeshToUseItsOwnMaterial(line1);Line using PBRMaterial
All you have to do is set the materialType to BABYLON.GreasedLineMeshMaterialType.MATERIAL_TYPE_PBR and set the colorMode to BABYLON.GreasedLineMeshColorMode.COLOR_MODE_MULTIPLY. Do not set the color to null as it was the case with StandardMaterial unless you set the base color of the line another way, for example by setting a texture on PBRMaterial.
import { GreasedLineMeshColorMode, GreasedLineMeshMaterialType } from "@babylonjs/core/Materials/GreasedLine/greasedLineMaterialInterfaces";import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";const points = [-1, 0, 0, 1, 0, 0];const line = CreateGreasedLine("line", { points }, { materialType: GreasedLineMeshMaterialType.MATERIAL_TYPE_PBR, colorMode: GreasedLineMeshColorMode.COLOR_MODE_MULTIPLY,});const pbrMaterial = line.material;Text using GreasedLine
You can draw text with Greased Line as well.
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";import { GreasedLineTools } from "@babylonjs/core/Misc/greasedLineTools";const fontData = await(await fetch("https://assets.babylonjs.com/fonts/Droid Sans_Regular.json")).json();const points = GreasedLineTools.GetPointsFromText("BabylonJS", 16, // size16, // resolutionfontData);const textLines = CreateGreasedLine("textLines", { points });Read more about the GetPointsFromText function below and check out the example PG.
GreasedLineTools
GreasedLineTools contains useful helper functions that will help you easily handle common tasks when using GreasedLine. Refer to the API for details.
Meshes to lines
You can easily draw a wireframe of a mesh like this:
import { CreateGreasedLine } from "@babylonjs/core/Meshes/Builders/greasedLineBuilder";import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder";import { GreasedLineTools } from "@babylonjs/core/Misc/greasedLineTools";const sphere = MeshBuilder.CreateSphere("sphere", { segments: 32, diameter: 2 }, scene);const sphereLines = CreateGreasedLine("sphereLines", { points: GreasedLineTools.MeshesToLines([sphere]) });You can use a predicate as the second parameter of this function to modify the line points returned from this function. The predicate is called once for a face (once for every third index).
import { GreasedLineTools } from "@babylonjs/core/Misc/greasedLineTools";predicate?: ( p1: Vector3, p2: Vector3, p3: Vector3, indiceIndex: number, vertexIndex: number, mesh: AbstractMesh, meshIndex: number, vertices: FloatArray, indices: IndicesArray) => Vector3[]
const predicate = (p1, p2, p3, ix, vx) => { if (vx % 4 === 0) { return [p1, p2, p3, p1] } return false}
const points = GreasedLineTools.MeshesToLines([sphere], predicate)Convert number[] to Vector3[] and vice versa
You will often face situations where you need to convert your point coordinates, mainly when using GreasedLineTools functions. There are two helper functions for that:
import { GreasedLineTools } from "@babylonjs/core/Misc/greasedLineTools";GreasedLineTools.ToVector3Array(points: number[])GreasedLineTools.ToNumberArray(array: Vector3[])Getting the count of points in your line instance
You will face certain tasks, such as creating color textures or offset buffers, and you will need to know how many points the line instance was created from. This is especially true if you use the functions below, which divide and segmentize your lines, because you can easily lose track of the exact counts. You get the total number of points and the number of points in each line in the line instance.
import { GreasedLineTools } from "@babylonjs/core/Misc/greasedLineTools";GreasedLineTools.GetPointsCountInfo(points: number[][]): { total: number; counts: number[] }is here to help.
Dividing a line to smaller segments
You may want to divide your line to smaller pieces (to segments) for example for assigning different colors to the segments or setting different width on the segment or manipulating the offset of that smaller segment.
import { GreasedLineTools } from "@babylonjs/core/Misc/greasedLineTools";const pointsOriginal = GreasedLineTools.ToVector3Array([0, 0, 0, 1, 0, 0]);const points = GreasedLineTools.SegmentizeLineBySegmentLength(pointsOriginal, 0.25);const points2 = GreasedLineTools.SegmentizeLineBySegmentCount(pointsOriginal, 4);The line will be divided into 4 pieces because the line length is 1 and we asked for 0.25-long segments when using the first function, or you can provide the number of segments using the second function. Check the playgrounds for real-life examples.
Finding the last visible position on the line when using the visibility option
The visibility option allows you to render only part of the line. You can use this option to reveal your line by incrementing its value. Remember, the value of this option must be normalized so it must be between 0 and 1. For example you may want to display a marker where the line ends. You can use the BABYLON.GreasedLineTools.GetPositionOnLineByVisibility(lineSegments: { point1: Vector3; point2: Vector3; length: number }[], lineLength: number, visbility: number, localSpace = false) function for this. Examine the example Playground how to deal with this function.
Getting points from text and a typeface.js font - the GetPointsFromText function
You can draw texts using GreasedLine. See the example code snippet above and the PG below.
GreasedLineTools.GetPointsFromText(text: string, size: number, resolution: number, fontData: IFontData, z = 0, includeInner = true): number[][]The size is the height of the text in BabylonJS units.
Keep the resolution as low as possible without losing details. Start at low values such as 4 and go up to 32-64 (or you can use 1 to get a cool low-resolution vector font).
fontData is the same object you would use with BABYLON.MeshBuilder.CreateText. You can generate your typeface.js font here.
Other functions
There are other useful functions like getting points for drawing a circle/oval, an arc, drawing arrows, getting line length, etc. Check the source code, the API and/or the playgrounds.
As an overall rule, always cache your parameters when calling functions. These functions located in GreasedLineTools may be CPU-intensive, so avoid using them in the render loop, or cache as much as possible. For example, convert your number coordinates to Vector3 coordinates once and store the result. Get the line length only once and buffer the value, etc.
Picking and intersections
You can use the findAllIntersections(ray) function on a GreasedLineMesh object to find the intersections of the ray and the line. You can fine-tune the intersection sensitivity by altering the value of the public property intersectionTreshold.

