Dynamic update of EdgesGeometry

Hello Everyone,

I am looking for some suggestions and advise. I am currently using EdgesGeometry as a way to render the contours of some geometries in my scene. It works flawlessly to begin with. However, the application is dynamic that involves updating the geometry based on user controlled parameters. Also, there are multiple instances of such geometries(mostly extrudegeometries) that are controlled based on multiple variables created dynamically (width, height, depth, holes etc). As of result of this there is a need to update the edgesgeometry.

Now the problem is that reconstruction of edgesgeometry really is processing intensive. Since it involves a good amount of dot product computations to filter linesegments to be used I understand this is not an easy task. However, I also believe my knowledge might be limited and perhaps someone has solved this problem with a different strategy. Can you please share if you can?

One strategy I tried was to just update the vertex positions using the bufferattribute of edgesgeometry and the dynamic geometries when the topology does not change. I update the edges geometry only when the topology changes and it is okay to tradeoff performance at this point. But even with changes in width, height, and depth the count of edgesgoemetry differs from the regular geometry I am regenerating using extrudegeometry. Is there something I am doing fundamentally wrong?

To better explain below is an example code

let dynamicGeometry: ExtrudeGeometry = construct geometry created with different variable controls
let edgesGeometry: EdgesGeometry = new EdgesGeometry(dynamicGeometry);

/**
Performance intensive way
**/
function widthHeightDepthChanges(){
dynamicGeometry = reconstruct extrudegeometry based on different variable controls
edgesGeometry.dispose();
edgesGeometry = new EdgesGeometry(dynamicGeometry);
}

/**
Hacky way I tried
**/

let dynamicAttrib: BufferAttribute = dyanmicGeometry.getAttribute('position') as BufferAttribute;
let edgesAttrib: BufferAttribute = edgesGeometry.getAttribute('position') as BufferAttribute;
if(dynamicAttrib.count === edgesAttrib.count){
      for(let i:number=0; i < edgesAttrib.count;i++){
               let cX: number = dynamicAttrib.getX(i);
               let cY: number = dynamicAttrib.getY(i);
               let cZ: number = dynamicAttrib.getZ(i);
              edgesAttrib.setXYZ(i, cX, cY, cZ);
      }
}
else{
    // Inherent differences in geometry perhaps some has changed in the topology
   edgesGeometry.dispose();
   edgesGeometry = new EdgesGeometry(dynamicGeometry); 
}

But the else condition is the one that is triggered everytime? Does the extrudegeometry keep changing the topology every time even when using the same shape (albeit the size difference)?
Apologies in advance if my question is not clear. I will be more than happy to explain more.

So my post is essentially about looking for an advise and a question. Thank you everyone for reading through my woes :wink:
Regards,
#0K

This might not work in some cases. EdgeGeometry removes some edges if the corresponding planes are almost parallel (depending on a threshold value). If you rescale an object, the angles between planes my change. Consider this example, where squashing the object turns an edge into non-edge:

Untitled Diagram

Would this option be OK for you: you create the edges of a mesh, if the mesh is scaled, rotated, translated, then you apply the same operation on the edges, without regenerating their geometry, and without modifying the edges vertices. Only if the modification is something more complex (e.g. you add a hole), then you regenerate the edges.


As for this observation:

The explanation is simple. When EdgesGeometry generates its buffer with vertices, it generates only vertices for line segments for some edges. Thus, the number of vertices in the original object will differ from the number of vertices generated by EdgesGeometry. So, (dynamicAttrib.count === edgesAttrib.count) is not true and as a result only the else of the the if is executed.

My expectation is that dynamicAttrib.count > edgesAttrib.count for (almost) all shapes.


If you need a demo of how edges can mimic object scaling/rotating/translating, let me know and I will prepare you some demo code.

@PavelBoytchev,

Many thanks for such an extensive explanation. I see that this is more of a coding structural strategey to be implemented to solve this problem, which I think is quite complex given my application scenario. The problem is my shapes involve curves that adapt to a different radius at runtime. Hence, maintaining a line geometry for rigid transformations is out of question. I am positive such a change in shape will be unavoidable often during runtime, if not every frame.
Since, threejs employs triangulation as opposed to ngons I think it is a better idea for me to remove the aspect of drawing edge geometry altogether.
Again, thank you for your time and explanation and it really clarified a lot of doubts.

Regards,
#0K

1 Like

There are still some other options to explore, but it all depends on the complexity of your shapes:

  • Manual edges: you construct the edges manually (i.e. procedurally) during the modification of the geometry. So, you do not reply on EdgesGeometry to evaluate where to create an edge. Instead, you explicitly define where you want an edge.
  • Textured edges: you have a texture with a border. When you construct or modify your geometry you set the UV coordinates in a way that places the border at the edge. A simple case with a cube and a thick edge texture is shown in Cube with procedurally drawn borders.
  • Shadered edges: a shader tries to identify edges and draws an edge. You may have a look at this rather long thread Edge finding and highlighting.
1 Like