BabylonJS MeshLine - a port of THREE.MeshLine

last one for the road : https://playground.babylonjs.com/#LQVB2Y#14

5 Likes

Cool stuff buddy :slight_smile: I am creating showcases for GreasedLine. Can I add your creations to the demo? Credits will be given of course. If you have any other ideas they’re very welcome! :slight_smile:
Thanks :slight_smile:
:vulcan_salute:

Hey @Deltakosh!

I was working on optimalizations of the whole stuff and it got a full rewrite of the CPU part. Now the code is cleaner, faster and you can draw multiple lines with different widths in one draw call. I’d like to add support for different colors for the lines ofcourse in 1 draw call and it is missing positioning/rotation/scaling. Some GPU fragments needs to be added, depth buffer(?), fog(?)… I hope I can do the multicolor part and the pos/rot/scl part today. Maybe you can guys have a look at the code after I finish these tasks and review it.

I also added some SVG drawing capabilities to a separate utility class. I also created helper functions for drawing circles (ovals), arcs, grids, stuff to make the line more hires or lowres… However still tweaking them. I think full SVG support would be absolutely cool :slight_smile:

I hope (I have a shitload of regular work) I can manage all of this (wo full SVG support) this week, so please stand by :slight_smile:

Thanks!

r.

:vulcan_salute:

6 Likes

Starting to happen :muscle:

2 Likes

Multicoloring ready, at insane speeds…

Playing with widths and different z-offset for each country and the camera is rotated…

EDIT:

Translation - Rotation - Scaling added as well.

5 Likes

@roland , of course.

1 Like

@roland this is so coool !!!

1 Like

Thanks! Yes, it’s starting to be a really cool and powerful tool! There are so many use cases for it. I am preparing some demos and debugging the line routine at once. Just wait for it :sunglasses:

2 Likes

some ā€œinspirationā€ :slight_smile:
.GitHub - rreusser/regl-gpu-lines: Pure GPU, instanced, screen-projected lines for regl
.GitHub - gl-vis/regl-line2d: Draw 2d polyline with regl

3 Likes

I’m so looking forward to this! I keep refreshing the page :crazy_face:

2 Likes

Guys, I’ve added PBR support (95% ready) and I am playing with the stuff. I’ve realized there is quite much left to do. The separate line coloring requires the color tables and the color pointers at creation time and it should be quite challenging for beginners to create them correctly so I decided to create a builder classs which will allow to draw lines using a syntax like this:

const line = GreasedLineBuilder.createLine(params: GreasedLineParameters)
GreasedLineBuilder.addPoints(line: GreasedLine, points: Vector3[], colorStart: Color3, sizeStart: number, colorEnd?: Color3, sizeEnd?: number)
line.draw()

Different colors, different widths along the lines, 1 draw call.

Line thickness can be set for the upper part and the lower part of the line separatelly:

Supports glowing:

@inteja Thanks for your interest buddy! :slight_smile: You can already play with it if you want, however a lot will change (and need to tide up code), so really just play with it and don’t use in your project yet. (I will rename the repo to babylonjs-greasedline soon)

There is a demos folder:
image

In main.ts you need to call which demo you want to display:
image

@sebavan I need your help :slight_smile:

const colorPointersBuffer = new Buffer(engine, this.colorPointers, true, 1)
this.setVerticesBuffer(colorPointersBuffer.createVertexBuffer('colorPointers', 0, 1))

colorPointersBuffer.update(array) // this is not updating the buffer

Do I need some additional steps to get the new buffer in the shader?

5 Likes

Looks superb @roland! Actually it’s way more feature rich than I need for my use case! But no doubt all the extras you’re putting in will be great to have.

1 Like

@roland I think your code should work. You should try to make a minimal repro with the code above.

Just to be sure: you add ā€œcolorPointersā€ in the list of attributes when creating the shader?

1 Like

@Evgeni_Popov Hello!
Yes, it works for the first time, but I can’t update it afterwards, no error, but nothing changes.

Are you sure array has updated data? If yes, a repro will probably be needed to help further.

2 Likes

As expected :smiley: It’s working. The amount of changes was so small that I couldn’t catch the changes with my eyes… :eyes: Thank you!

1 Like

Hi @roland in the other thread you say:

I wrote some support functions to properly stretch the UVs through the line

I’ve been playing around with these a bit and they have the capacity to generate a lot of extra geometry. I realise the draw calls remain the same so maybe not such a big problem, but for optimal performance I was thinking it should be possible instead just to set or pass in UVs (based on segment length) while keeping vertex count the same, then using texture u and v scale to achieve desired repetition?

Hello, you can draw the whole stuff in one draw call. I’ll make it clear how to use when it’s done :slight_smile:

1 Like

Hello!

I’m tweaking the LINE everyday and I’ve recently added offsets so you can offset your points without recalculating and redrawing the whole line.

Here is a small demo using variable widths and offset and using dashArray for the red line:

https://demos.babylonjs.xyz/greased-line/sound-analyzer/

Don’t forget to enable the audio.

I have more ideas to add but I’ll release the current version and will implement those ideas later.

Click on the canvas and press shift + ctrl + I to open the Inspector.

R.

:vulcan_salute:

import {
  Analyser,
  ArcRotateCamera,
  Color3,
  Color4,
  Engine,
  RawTexture,
  Scene,
  Sound,
  Vector2,
  Vector3,
} from '@babylonjs/core'
import { GreasedLineMaterial } from './../GreasedLineMaterial'
import { GreasedLine } from './../GreasedLine'

export function spectrumAnalyzer(scene: Scene, camera: ArcRotateCamera) {
  const engine = scene.getEngine()

  scene.clearColor = new Color4(0, 0, 0, 1)

  const numOfBars = 256
  const barWidth = 3

  const analyzerPoints = []
  const offsets = []
  for (let i = 0; i < numOfBars; i++) {
    analyzerPoints.push(new Vector3(i * barWidth, 0, 0))
    offsets.push(0, 0, 0, 0, 0, 0)
  }
  const wavePoints = [...analyzerPoints]

  const analyzerLine = new GreasedLine(
    'analyzer-line',
    scene,
    {
      points: analyzerPoints,
    },
    true,
  )

  const waveLine = new GreasedLine(
    'wave-line',
    scene,
    {
      points: wavePoints,
      offsets,
    },
    true,
  )
  waveLine.position = new Vector3(0, 30, 0)

  const textureColors = new Uint8Array([255, 0, 0, 255, 255, 0, 0, 255, 0])
  const texture = new RawTexture(
    textureColors,
    textureColors.length / 3,
    1,
    Engine.TEXTUREFORMAT_RGB,
    scene,
    false,
    true,
    Engine.TEXTURE_LINEAR_NEAREST
  )
  texture.wrapU = RawTexture.WRAP_ADDRESSMODE
  texture.name = "analyzer-texture"

  const analyzerMaterial = new GreasedLineMaterial('analyzerMaterial', scene, {
    useMap: true,
    map: texture,
    opacity: 1,
    sizeAttenuation: false,
    lineWidth: 14,
  })

  const waveMaterial = new GreasedLineMaterial('waveMaterial', scene, {
    color: Color3.Red(),
    sizeAttenuation: true,
    lineWidth: 14,
    dashArray: 1 / numOfBars,
    dashOffset: 0,
    dashRatio: 0.4,
    useDash: true,
    alphaTest: 1,
  })

  analyzerLine.material = analyzerMaterial
  waveLine.material = waveMaterial

  camera.zoomOn([analyzerLine])
  camera.radius = 530
  camera.detachControl()

  _drawGrid()
  _startAudio()
  _createAnalyzer()

  function _startAudio() {
    const music = new Sound('Music', 'mp3/glitch-flight-track.mp3', scene, null, {
      loop: true,
      autoplay: true,
    })
  }

  function _drawGrid() {
    const points:Vector3[][] = []
    for(let i=0;i<numOfBars;i+=4) {
      points.push([new Vector3(i*barWidth,-200,0), new Vector3(i*barWidth,200,0)])
    }
    for(let i=0;i<numOfBars;i+=2) {
      points.push([new Vector3(0,i*barWidth-200,0), new Vector3(barWidth * numOfBars,i*barWidth-200,0)])
    }

    const grid = new GreasedLine("grid", scene, {
      points
    })

    const gridMaterial = new GreasedLineMaterial("gridMaterail", scene, {
      color: new Color3(0, 0, 0.6)
    })

    grid.material = gridMaterial

  }

  function _createAnalyzer() {
    if (Engine.audioEngine) {
      const analyser = new Analyser(scene)
      Engine.audioEngine.connectToAnalyser(analyser)
      analyser.BARGRAPHAMPLITUDE = 256
      analyser.FFT_SIZE = 512
      analyser.SMOOTHING = 0.7

      const uvOffset = new Vector2(0, 0)
      
      scene.onBeforeRenderObservable.add(() => {
        const frequencies = analyser.getByteFrequencyData()
        const widths = []
        const offsets = []
        for (let i = 0; i < numOfBars; i++) {
          const normalizedFrequency = frequencies[i]
          widths.push(normalizedFrequency, normalizedFrequency / 2)
          offsets.push(0, normalizedFrequency, 0, 0, normalizedFrequency, 0)
        }
        analyzerLine.setWidth(widths)
        waveLine.setOffsets(offsets)

        analyzerMaterial.setParameters({
          uvOffset,
        })
        uvOffset.x += 0.01 * scene.getAnimationRatio()
      })
    } else {
      console.error('No audio engine.')
    }
  }
}

6 Likes

@roland

Nice work :clap:

Does the new update respond to picking / raycast?