1

I have been trying to figure out a way of adding thickness to lines that can receive shadows and look like solid objects using Three.js but the best result I managed to get so far is just thicker lines that do not look like 3D geometry.

The application is for an online 3D printing platform so I am trying to visualise the sliced geometry that is comprised of lines, similar to how other slicing software handles this, such as cura, as shown in the image below.

cura slicing view

Generating mesh geometry from these lines would be most probably problematic as in some cases there are thousands of a lines in a single model so it will be too heavy.

Any suggestions on how to achieve the desired result in either three.js or another javascript library would be greatly appreciated!

leonidasarch
  • 85
  • 1
  • 9
  • For what it's worth, the image you shared looks like it's using full shaded geometry, not lines. `Cura` is a desktop application, and memory is generally less of a concern in that realm, so you're comparing apples and oranges. If you could modify [`TubeGeometry`](https://threejs.org/docs/#api/en/geometries/TubeGeometry) to create fewer nodes on straight paths, you might find it's very suitable for the job. – TheJim01 Jul 17 '20 at 20:11
  • these are not shadows but shading ... its just a matter of enabling light and passing surface normal. You can create [tube geometry](https://stackoverflow.com/a/35055911/2521214) however that would be extremly slow. Instead you can render simple polylines, in geometry shader convert to BBOX and in Fragment based on distance to line render thick line with [normal shading](https://stackoverflow.com/a/31913542/2521214). This is very similar (but much easier) to [Draw Quadratic Curve on GPU](https://stackoverflow.com/a/31423105/2521214) – Spektre Jul 20 '20 at 08:07
  • I had tried using tube geometry but in most cases it was too heavy indeed, even with simplified polylines with reduced number of vertices. At the moment I am using line geometry with thickness like this example https://threejs.org/examples/webgl_lines_fat but it's not ideal. I am not really clear about the approach that you suggested. Could you explain the steps a bit? Thanks! – leonidasarch Jul 20 '20 at 10:17

1 Answers1

2

So the idea is to render primitive covering your thick line area and in fragment decide if fragment is inside or outside the thick line compute 3D position and normal and render or discard; if not.

The idea is to pass polyline geometry for rendering to OpenGL that would produce just thin lines and use shaders to do the rest.

  1. Vertex shader

    will just pass stuff into geometry shader

  2. Geometry shader

    will take in 2 vertexes (line) and output 2 triangles (quad) covering line BBOX (line enlarged by line half thickness). This is relatively easy. Simply shift the line endpoints by perpendicular vector to the line of size equal to the half thickness. This must be done in plane parallel with camera screen plane (using basis vectors extracted from direct camera matrix). Do not forget to pass both vertexes in world and camera coordinates.

  3. Fragment shader

    simply from world coordinates test if point is inside your thick line:

    perpendicular distance

    so simply compute P' and compute distance between P,P'. That is called perpendicular distance between point and line. Its doable exploiting dot product IIRC:

     t = dot(P-P0,P1-P0)
     P' = P0 + t*(P1-P0)
     d = |P'-P0|
    

    from that you just compute the 3D coordinate (depth of the fragment), normal and either render with some directional light or discard;...

Take a look at full example of this technique for 2D cubic curves:

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Reopening this topic after a few years because I never got to implement it and just started looking at it again. While learning about webgl and opengl I realised that there is no geometry shader in webgl. With that in mind, what workaround could work to manipulate the vertices in the vertex shader instead? – leonidasarch Aug 31 '23 at 15:53
  • @leonidasarch without geometry shader you have to pass BBOX and control points instead of just polyline something like this: [Draw Quadratic Curve on GPU](https://stackoverflow.com/a/31423105/2521214) so you can make a triangle/quad (or other primitive) BBOX that is computed from curve control points in a way that they can be infered back ... after that the fragment is the same choosing if render or discard fragment based on distance from curve ... – Spektre Aug 31 '23 at 18:49