Fat Lines: Setting geometry data does not work

Hi! it’s my first question, for my first project with three.js, i hope it’s not too simple, i already researched but with no success.
So i’m creating a Line2 because i need to control the fatness, so i followed this example (https://threejs.org/examples/?q=line#webgl_lines_fat) and it was working.

But then i saw that i also need to update the points of my geometry, so made some modifications following this example: https://threejs.org/docs/index.html#manual/en/introduction/How-to-update-things

And now my mesh it’s not showing anymore, here is a relevant code, i’m inside a vue component, so it has some different syntax.

//mounted()
this.arcGeometry1 = new LineGeometry()
// set maximum size for buffer of LineGeometry,
var positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
this.arcGeometry1.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); //  the number of values of the array, not drawRange
this.matLine2 = new LineMaterial({
color: 0x000000,
linewidth: 3,
dashed: false
});
this.matLine2.resolution.set(( this.container.clientWidth, this.container.clientHeight ))
this.arcMesh = new Line2(this.arcGeometry1, this.matLine2 );
update()
init()
render()


//update()
var positions = this.arcMesh.geometry.attributes.position.array;
  for (let x = 0; x < arcPath.length; x++) {
    positions[x] = arcPath[x]
  }

  this.arcMesh.geometry.setDrawRange( 0, arcPath.length );
  this.arcMesh.geometry.computeBoundingSphere();
  //this.arcMesh.computeLineDistances();
  this.earthArcMesh.scale.set( 1, 1, 1 );

//init()
this.scene.add(this.arcMesh);

//render()
this.renderer.render(this.scene, this.camera);
this.arcMesh.geometry.computeBoundingSphere();
this.arcMesh.geometry.attributes.position.needsUpdate = true;

Since i implemented bufferGeometry the mesh is not showing in the render, but when i debug it, seems fine because the geometry points are correctly loaded

Line2 {…}
castShadow: (...)
children: (...)
frustumCulled: (...)
geometry: LineGeometry
    attributes: Object
        position: BufferAttribute
            array: Float32Array(135)
                [0 … 99]
                0: -148.2235870361328
                1: -17.804668426513672
                2: 0.0008591873338446021
                3: -147.93746948242188
                4: -20.358715057373047
                5: 0.0009825639426708221
                6: -147.60552978515625
                7: -22.92180633544922
                8: 0.0011064092395827174
                9: -147.22335815429688
                10: -25.517356872558594
                11: 0.0012318536173552275
                ...

boundingSphere: Sphere
    center: Vector3
    radius: 0

A hint may be that always in the console debugging i see that the bounding sphere has radius 0? Even if did compute it in the snippet before. Any help would be very appreciated, thanks

/cc

Is it possible for your to demonstrate the problem with a live example: three.js dev template - module - JSFiddle - Code Playground

In any event, you can’t define the geometry for LineGeometry like so:

You have to use a dedicated interface for this. Try it with LineGeometry.setPositions(). That is necessary since internally the geometry is instanced and interleaved.

Thanks, for the answer! I did use .setPositions() before and it was showing, but my problem is that i need to update the position data AND the number of points, and with setPositions() would throw this mistake, when the number of points was different from the initiated size:
On firefox:
WebGL warning: drawElementsInstanced: Instance fetch requires 14, but attribs only supply 13.
On Chrome:
GL ERROR :GL_INVALID_OPERATION : glDrawElementsInstancedANGLE: attempt to access out of range vertices in attribute 1

so i refactored following this example:
https://threejs.org/docs/index.html#manual/en/introduction/How-to-update-things

I’m having some trouble building the jsfiddle because it’ s from a big vue component but basically i’m wondering if it’s possible to modify this buffer example: http://jsfiddle.net/w67tzfhx/ by using the Line2() object from this example: https://github.com/mrdoob/three.js/blob/7c1424c5819ab622a346dd630ee4e6431388021e/examples/webgl_lines_fat.html instead of THREE.Line()

This is a general limitation of WebGL buffers since they are fixed sized. Once created you can’t just add additional elements like with an ordinary JavaScript array.

The general idea is to make buffers “large enough” for your app and then use BufferGeometry.drawRange or InstancedBufferGeometry.maxInstancedCount to control the final rendering.

Looking at your stackoverflow post, the provided answer is exactly the same like here.

I

That’s what I tried in the first post I used bufferGeometry to allocate a buffer large enough and drawRange but still it didn’t work. Now i’m trying to make a fiddle, but I’m stuck.

I want to modify this fiddle: http://jsfiddle.net/w67tzfhx/
but i can’t import three.js modules as in the same syntax as: https://jsfiddle.net/t1uwemLq/

Whenever I copy and paste the modules i need it stops rendering, any hint?

Try it with this fiddle: https://jsfiddle.net/tqkpbeh0/

When using modules, the code becomes automatically strict which can break apps like in the previous version of the fiddle.

Here i did the solutions i’m trying:
Line2() declared with LineMaterial and LineGeometry

But the Buffer set with setPositions() and drawRange()

https://jsfiddle.net/danieledep/9qk1mjht/6/
I don’t know what’s wrong…

BufferGeometry.setDrawRange() can’t be used with wide lines since it internally uses instanced rendering. Hence, you need to modulate InstancedBufferGeometry.maxInstancedCount:

https://jsfiddle.net/brLk6aud/1/

Thank you so much @Mugen87 , I made it work with your example, your help was very very very appreciated.

1 Like

There is a change with latest, use InstancedBufferGeometry.instanceCount instead of InstancedBufferGeometry.maxInstancedCount

Thank you @Mugen87 for posting this.

I have been really struggling with the fat lines. Finally, this post helped me to resolve the issue.
Rest of the code was working fine, except I was not able to get the lines displayed.

Finally, in my case I changed:
//resolution: // to be set by renderer, eventually
to the explicit command

material.resolution.set(window.innerWidth, window.innerHeight);
Don’t know why, but this seems to have resolved the issue.

2 Likes

Hi!

@Mugen87 In the case I have 50 000 lines with different coordinates and lengths and I want to change the geometry of one line during runtime. Is using .setPositions() the most efficient way? Because as I understand I have to give this function rather large amount of data (array for 50 000 lines) even though I am only changing a single line. Do you see this as a problem, is there maybe more efficient alternative?

Thanks in advance.

I’m not aware of a different solution since the API assumes single line segments are not modified over time. So you have to define the entire buffer data again.

@Mugen87 is there a reasonable way to draw fat lines, starting with an index other than zero? This is possible with setDrawRange, but InstancedBufferGeometry.instanceCount assumes that you’re always drawing from the beginning of the buffer up to instanceCount. In my case, I’d like to render a segment of a fat line and might omit part of the start and/or part of the end.

Thanks!

Sorry this is not supported. You have to rearrange the buffer data to implement this feature. Meaning the data you want to draw have to be defined first.

Ok. Thanks for the advice. I’ll have to find another way to render my lines.