How to update tubeGeometry geometry based in lineCurve modifications?

I would like to know how I can update the geometry of my tubeGeometry object when I modify the points of my LineCurve3 object. I see that when I call getPoints on my lineCurve object, that the changes have successfully came through. But the geometry is not updated. When I replace the mesh.geometry object by a new TubeGeometry instance, the changes are being reflected successfully. But I’d rather like to update the existing TubeGeometry instance with the modified line curve. How can I do that?

// Dummy code for context

const point =  {
    start: new THREE.Vector3(0,0,0),
    end: new THREE.Vector3(0,1,0)
}
const line = new THREE.LineCurve3( point.start,   point.end)
const mesh = new THREE.Mesh(  new THREE.TubeGeometry(line, <parameters>));
console.log(line.getPoints())
/*
[
    {
        "x": 0,
        "y": 0,
        "z": 0
    },
    {...},
    {
        "x": 0,
        "y": 1,
        "z": 0
    }
]
*/
point.end.y = 2;

console.log(line.getPoints())
/*
[
    {
        "x": 0,
        "y": 0,
        "z": 0
    },
    {...},
    {
        "x": 0,
        "y": 2,
        "z": 0
    }
]
*/

For dynamic changes of the geometry, the vertices must have an update.

.attributes.position.needsUpdate = true;

Thank you very much for your reply and the associated resources. Unfortunately the proposed solution is not working.

What I understand from your reply is that I will need to add .attributes.position.needsUpdate = true to mesh.geometry in order that the geometry positions will be updated according the changed LineCurve properties. Unfortunately that does not work. In the resources that you’ve had provided I also noticed computeVertexNormals(), which I tried to add that as well. But with no succes neither.

How are the LineCurve3 object and the TubeGeometry related? Maybe that helps me better understanding of what I am doing wrong.

.attributes.position.needsUpdate is not enough, of course.

You have to calculate the new positions beforehand.TubeGeometry is a static geometry. You can’t just add a command and it becomes dynamic!

But you can look into the code ( three.js/src/geometries/TubeGeometry.js at e22cb060cc91283d250e704f886528e1be593f45 · mrdoob/three.js · GitHub ) and apply the calculation accordingly.

In my example ( threejsResources/Curved2Geometry/Curved2Geometry.html at e00468a7649a3c5583f016b0ef9c03f76d4195b0 · hofk/threejsResources · GitHub ) you can see the connection.

line 454
g.morph = function( pts ) { ...

line Calculation: 467 … 488
.attributes.position.setXYZ( idx ++, v3b.x, v3b.y, v3b.z );

used:
line 335 function animate( ) {...

.morph( geo.cPts[ ...  ] ); 
.attributes.position.needsUpdate = true;

Thank you for the response, I was kinda hoping/expecting some behind the scenes magic :sweat_smile:, rather than making the calculations myself.

If I understand it correctly, I will need to update the geometry by changing the x,y & z coordinates of all the individual vertices. I can do that with the setXYZ method, where the first property is the id of the vertex, and the next three parameters are the new x, y & z of the vertex. So I just need to add the proper x,y & z values.

In your code I see that you are using the center points of the (CatmullRomCurve3) curve, which you got with the getSpacedPoints function. After that point it becomes a black box to me, and I can’t figure out how it continues.

But it does help me to understand what I need to do (sort-of). I would need to create two loops, the outer one would loop through the spacedPoints (or getPoints). The inner one should create <radialSegments> amount of vertices, with a diameter of given <radius>. In order to get the right angles and such, I seem to be able to use computeFrenetFrames. This function creates binormals, normals & tangents. And it seems that, that contains the data in combination with the points to create the circles (segments) as it is being done in the TubeGeometry’s generateSegment function .

I’m going to try to get this to work, but it seems like I’ve got a proper plan over here :slightly_smiling_face:

It does make me wonder though, if this is really that much cheaper than just recreating the model via the original TubeGeometry method

1 Like

I think you got it🙂. So you can do.

Recreating ist the better way if ist ist not really dynamic and changes only from time to time.

You can also look at Multi Form Geometry

UPDATE:
Also, these posts might be interesting for you to understand.
[Solved] Help with wrong position meshes along a curve

I’d like to thank you for all the resources you have shared. I postponed the final execution of this one eventually. Because by better understanding what had to be done, I understood how this would not resolve the performance issue I intended to solve with it. Will definitely come back to it some day, cause with these resources I should also be able to add caps to the tubes :wink:

I have quickly extracted some things from the example MultiFormGeometry and adapted them. Without caps yet.

Is that what you want to achieve?
DynamicTubeGeometry

1 Like

Yes, that would be the most exciting version of what I’d like to achieve. But the basis for it would in essence be a straight line moving from a to b. I currently have achieved the desired effect by stretching and rotating cubes to form lines. The next step is to animate these lines, the more control I would have over the mesh, the more fancy it could be animated. In a demo I have made, I see already an unstable framerate with ~50 tubes. Because in practice I’d like to use over 200 tubes to be animated, I don’t see this as the path to go.

I’m not quite clear what you mean by that statement.

If it is only different positions of similar geometry and material, then three.js docs offers itself.

For flat geometry I have already created variants with shaders. This is also more performant.
CircleDynamicallyFormable
CircleDynamicallyFormableShader

More sophisticated for tubes.

Basically I am looking for the most easiest method to draw lines from a to b in a 3D space. I like these lines to have a geometric volume so I can export the results as STL files. Currently I have done it by stretching box geometries. This is quite a complicated and limited method to achieve a desired result (see desired result). Having a method where I could appoint one point of the line to X1,Y1,Z1 and the other point to other X2,Y2,Z2 coordinates, would significantly ease this proces.

Using this approach I am unable to use cilinders though, because the would overlap in the corners & the meshes should therefor manually need to be sliced off in a 45 degree angle. Which is not impossible, but animating the meshes seem to be to resource intensive.

With only non-curved geometry, this is quite easy to achieve.
I use this approach because I only create a base geometry without calculating the XYZ coordinates and then use the method

g.morph = function( points ) { // sets the coordinate of all vertices


  ... for( let j = 0; j <= g.radialSegments; j ++ ) { ...
         ...  g.attributes.position.setXYZ( idx ++, v3b.x, v3b.y, v3b.z );

For blocks you will have a few values, for cylinders a little more.
This can be realized for cylinders similar to this example:
BendCylinderToKnee

To test the performance you can use my examples CustomCylinderAndKnee and CustomCylinderAndSphereKnee for example.

Just take more segments or several such geometries.

Somewhat late the variant with caps.
2022-10-11 20.53.32

DynamicTubeGeometryCaps