Tag: Support Generation

Overhang and Support Structures in L-PBF (SLM) using PySLM: (Part II)

Following on from the previous post looking at methods for identifying overhang regions for use in support structures, the ray projection method approached felt unsatisfactory, especially from a performance perspective. This is used as part of the support generation module when determining self-intersecting support structures with the part and for generating the initial 3D conformal volumetric block supports alongside the boolean operations.

The depth projection map is used to firstly identify the unsupported regions, using the selecting overhang angle. These regions are then intersected with the existing part to detect self-intersection and those regions that are only attached to the build-plate. This is later determined by seperate support volumes by identifying large differences between the region. This will be later explained in greater detail in a following post.

The in-built ray projection method used by Trimesh used the RTree library internally. Alternatively, PyEmbree, based on Intel’s Embree library can be used, although extremely efficient for purposes of RayTracing application, it unfortunatly cannot provide an accurate ray intersection for the purposes of generating support structures. The Rtree method unfortunately is not particularly high performance, even using a spatial tree-index structure for the acceleration structure and is also not multi-threaded. Increasing the resolution spatially has a performance cost O(\Delta x^2) and this is ultimately linear based on the number of ray search. Increasing the complexity of the mesh and throwing more triangles into the mix, further compounds the computational effort. Anecdotally, this mirrors the same issue with some voxelisation methods based on ray-tracing methods such as the one proposed by A. Aitkenhead .

The previous solution worked, especially on relatively simple geometries, but was unsatisfactory even with a boolean intersection with the a mesh created projecting the support surface downwards.

Following a foray into learning about GPU computing using GLSL shaders and also OpenCL and two years ago, there seemed a practical approach to solving this. This similar approach has also been recently used for generating signed-distance fields for meshes for use in Deep Learning geometries in PyTorch3D, shared on their Github repo. Their approach projects points close to the mesh and then using the surface normals and native depth occlusion tests available in OpenGL can project an approximate signed distance field – this has now become abbreviated (SDF) in literature.


For illustrating the method, the existing geometry of a topology optimised bracket to demonstrate a relatively dense triangular mesh, the part is orientated in the following fashion.

Topology optimised bracket used as an example for identifying support regions using a ray projection method.

Like the previous method, we do not necessarily have to work with the overhang region mesh.

Overhang Mesh of the Topology Optimised Bracket
The extracted overhang mesh obtained from a Topology Optimised Bracket

In the method, one simply needs to rasterise the Z-position of the surface of the mesh and discard hidden surfaces in order to emulate a single-hit ray projection approach. Using OpenGL GLSL fragment shaders this can be done by taking the orthographic projection of the model and then rasterising the Z position of each fragment (pixel) across each triangle.

The occlusion test is natively built into the standard 3D Graphics pipeline, which essentially emulates the ray-tracing approach. As trivial as it may sound, programming this in Python didn’t come easy. It required changing the framebuffer object (images that the triangles are rendered). Another subtle trick required is defining the the vertex colour Vertex Buffer Object (VBO) with the z-coordinates for its corresponding triangle vertex. The Z ‘colour’ value is then natively interpolated across each triangle during rasterisation and based on the depth-test performed automatically by OpenGL, only the most closest value remains, with other fragments in discarded. The GLSL fragment shader is shared below:

# Vertex shader

/ Uniforms
// ------------------------------------
uniform   mat4 u_model;
uniform   mat4 u_view;
uniform   mat4 u_projection;
uniform   vec4 u_color;

// Attributes
// ------------------------------------
attribute vec3 a_position;
attribute vec4 a_color;
attribute vec3 a_normal;

varying vec4 v_color;

void main()
    v_color = a_color;// * u_color;
    gl_Position = u_projection * u_view * u_model * vec4(a_position,1.0);

# Fragment shader
varying vec4 v_color;
out vec4 fragColor;

void main()
    fragColor = vec4(v_color.z,v_color.z,v_color.z,1.0);

The desired resolution of the ray-projection map is simply changed by setting the Window size or the underlying framebuffer size. The implementation is based on Vispy library, which provides access to many low-level building-blocks for creating OpenGL applications via its supporting library Glumpy. In this implementation, the vispy.app.Canvas is redefined , including the GLSL Shader Programs, OpenGL transformation matrices (Model-View-Projection MVP matrices) and also the framebuffer properties and OpenGL states required for rendering the mesh.

class Canvas(app.Canvas):

    def __enter__(self):
        return self

    def __init__(self, rasterResolution  = 0.02):

        self.vertices, self.filled, self.verticesColor, part = meshPart()

        vertex_data = np.zeros(self.vertices.shape[0], dtype=[('a_position', np.float32, 3),
                                                              ('a_color', np.float32, 3)])

        vertex_data['a_position'] = self.vertices.astype(np.float32)
        vertex_data['a_color'] = self.vertices.astype(np.float32)

        meshbbox = part.geometry.bounds
        self.box = meshbbox
        meshExtents = np.diff(meshbbox, axis=0)

        resolution = 0.05
        visSize = (meshExtents / resolution).flatten()
        self.visSize = visSize

        app.Canvas.__init__(self, 'interactive',  show=False, autoswap=False, size=(visSize[0], visSize[1]))

        self.filled = self.filled.astype(np.uint32).flatten()
        self.filled_buf = gloo.IndexBuffer(self.filled)

        self.program = gloo.Program(vert, frag)

        avg = np.mean(self.box, axis=0)

        self.view = rotate(0, [1,0,0]) #translate([0,0,0])
        self.model = np.eye(4, dtype=np.float32)

        print('Physical size:', self.physical_size)

        shape = self.physical_size[1], self.physical_size[0]

        self._rendertex = gloo.Texture2D((shape + (4,)), format='rgba', internalformat='rgba32f')
        self._depthRenderBuffer = gloo.RenderBuffer(shape, format='depth')
        self._depthRenderBuffer.resize(shape, format=gloo.gl.GL_DEPTH_COMPONENT16)

        # Create FBO, attach the color buffer and depth buffer
        self._fbo = gloo.FrameBuffer(self._rendertex, self._depthRenderBuffer)

        gloo.set_viewport(0, 0, self.physical_size[0], self.physical_size[1])
        self.projection = perspective(45.0, self.size[0] /
                                      float(self.size[1]), 2.0, 10.0)

        self.projection = ortho(self.box[1, 0], self.box[0, 0], self.box[1, 1], self.box[0, 1], 2, 40)

        self.program['u_projection'] = self.projection

        self.program['u_model'] = self.model
        self.program['u_view'] = self.view

        self.theta = 0
        self.phi = 0

        gloo.set_polygon_offset(1, 1)


    def on_timer(self, event):
        self.theta += .5
        self.phi += .5
        self.model = np.dot(rotate(self.theta, (0, 1, 0)),
                            rotate(self.phi, (0, 0, 1)))
        self.program['u_model'] = self.model

    def setModelMatrix(self, model):
        self.model = np.dot(rotate(self.theta, (0, 1, 0)),
                            rotate(self.phi, (0, 0, 1)))
        self.program['u_model'] = self.model

    def on_resize(self, event):
        from vispy.util.transforms import perspective, translate, rotate, ortho

        gloo.set_viewport(0, 0, event.physical_size[0], event.physical_size[1])
        # Create the orthographic projection
        self.projection = ortho(self.box[1, 0], self.box[0, 0],
                                self.box[1,1], self.box[0, 1],
                                -self.box[1, 2], self.box[0, 2])
        self.program['u_projection'] = self.projection

    def on_draw(self, event):

        from vispy.util.transforms import perspective, translate, rotate, ortho
        from vispy.gloo.util import _screenshot

        with self._fbo:
            gloo.set_clear_color((0.0, 0.0, 0.0, 0.0))
            gloo.set_viewport(0, 0, *self.physical_size)
            gloo.set_state(blend=False, depth_test=True, polygon_offset_fill=False)
            self.program['u_color'] = 1, 1, 1, 1
            self.program.draw('triangles', self.filled_buf)
            #self.rgb = np.copy(self._fbo.read('color')) #_screenshot((0, 0, self.size[0], self.size[1]))  #self._fbo.read('color')
            #self.rgb =     gloo.read_pixels((0, 0, *self.physical_size), True)
            self.rgb  = _screenshot((0, 0, *self.physical_size))

c = Canvas()

Once complete, the output from the framebuffer can then be transferred to a numpy array for further processing. Very large resolutions may be achieved with little performance impact using GPU computation. These high resolution ray-projection maps are extremely important for accurately capturing the overhang regions and ensuring that each support structure is correctly attached and conforming to the part’s geometry.

Output generated from Vispy to rasterise the Z-position to emulate the ray-projection method. Note the high resolution attainable using this approach. The only limitation is the size of the GPU framebuffer.

Another advantage of capturing the effective ray projection using this means, is the background is clearly identified easing segmentation. Upon obtainingt the ray-projection method, the overhang regions can be identified as using the gradient of the ray project map, as discussed in the previous post. Gaussian convolution kernel may be applied on the thresholded image, so that the boundaries can be smoothed before extracting boundaries.

Overhang support regions identified using a ray-projection approach
Overhang angles obtained based on the gradient across the depth image and a threshold.

The boundaries may then be obtained using by extracting the isolevel from the thresholded image accordingly using

import skimage.measure
import skimage.filters
import pyslm.visualise

# The background is masked using the alpha channel from the framebuffer. A gaussian blur is applied onto the overhang image to smoothen boundaries
ov = overhang * c.rgb[:,:,3]
ov = skimage.filters.gaussian(ov, sigma=8)

plt.imshow(ov > 0.5)

# Locate the boundaries using marching-squares algorithm
contours = skimage.measure.find_contours(ov.T, 0.5)

# Create the paths for manipulation later
fig = plt.figure()
triPath = pyslm.support.createPath2DfromPaths(contours)

The resultant boundaries are shown below.

Overhang regions and boundaries identified
Boundaries extracted from the overhang regions. The boundaries may be simplified later.


Despite the simplicity of this method, it is not readily used in many areas despite its advantages. The problem with the method is often setting up a suitable OpenGL environment and back-end in Windows and Linux environments, especially in conjunction with using Python. This resulted in many delays in the release of PySLM v0.5, but these have been resolved across all platforms.

This approach provides a very fast and efficient method for performing ray-projection tests especially resolving this at high resolutions for complex meshes harnessing the power of GPUs. Having a complete rasterised image with polygon boundaries provides the ability to offset and generate smoother support regions later.

See the Next Post in the Series

Overhang and Support Structures in L-PBF (SLM) using PySLM (Part I)

A key focus of the release of PySLM 0.5 was the introduction of support structure generation targeted for powder-bed fusion (PBF) processes such as Selective Laser Melting (SLM) and also Electron Beam Melting (EBM). The basic infrastructure for generating support structures was developed including overhang analysis, support projection maps and the calculating precise conforming volumes, that leads to demonstration of block ‘truss’ based supports.

It is a particularly exciting release, because it is the first implementation both open source but also explicitly documents in practice a potential method for generating support structures for these specific PBF processes that have commercially (albeit few choices) been available for over a decade.

The challenge of this specific problem was to provide a robust solution covering the majority of engineering cases – which led to the length of time taken to develop this feature. This included having to develop many additional functions, support routines and workarounds for the limited availability of a boolean CSG library for triangular meshes in Python whilst providing reasonable performance.

In the Support Structure, the geometry constructed consists of a grid and a boundary which features a polygon derived truss structure in order to support powder removal and control the stiffness of the structure. Below highlights the capability for generated truss-based support structure suitable for PBF process. Carefully observe that individual support blocks are separated when self-intersecting and precisely conform to the original geometry. The support volumes themselves interface with the original part, by performing an exact boolean intersection.

Truss based Support Structures  for Selective Laser Melting (SLM) or LPBF generated using PySLM
Support Structure Generation in PySLM 0.5 suitable for Selective Laser Melting. Separate support regions are generated for the part using a projection method and a truss based support structure is generated in a grid and along the boundary.

Within the support volumes generating a grid-truss support structure can be generated by taking 2D cross-sections and applying various polygon clipping techniques to generate the structure to create the truss. These trusses structure are particularly more efficient for scanning as these slice as individual scan vectors rather than a series of point exposure.

PySLM: Python 3D Printing support generation for selective laser melting - bottom view showing a grid truss support
A view from the bottom showing the grid truss support structure generated
PySLM: Slicing through a generated SLM Support Structure generated using PySLM.
A slice or cross-section taken through both the part and support structures. It can bee seen that the support structure is constructed from a grid which represented single linear scan vectors during scanning.

Future work intends to correctly hatch the support structure regions and integrate a multi-body slice and hatching procedure, but this is intended for inclusion in a future release, possibly PySLM 0.6.

Due to the implementation’s brevity, the proposed methodology will be split across multiple-posts. Anecdotally, work began on a support method over two years ago, intended to offer a more complete input towards deriving a cost model based on existing research in the literature – for further guidance refer to the following posts (Build time estimation).

Background on Support Structures

Support structures are a vital element to Additive Manufacturing. Despite the additional cost of post-processing support structures, these are useful and in some instances essential for successful manufacture of metal AM parts. Most 3D printed users will be very familiar with support generation: the tedious removal of additional structures in most AM processes (FDM, SLM, SLA, BJF, EBM) and the practical difficulty removing this material afterwards. SLS/HSS for polymer parts are largely immune from this manufacturing constraint and make it as a technology for every attractive and cost efficient to produce 3D printed parts without much specific knowledge from the designer. They serve a variety of purposes beyond geometrically supporting overhang surfaces, namely:

  • Anchor the part onto to the build platform before removal using Spark Erosion or Wire Electric Discharge Machining
  • Counter-act distortion in materials prone to residual stresses, when compensation factors cannot be used through AM build simulations
  • Provide a path to dissipate heat to prevent overheating of regions,
  • Provide structure to support forces exerted during post machining interfaces.

Even with the best intention for the engineer or technician to design these out, it is likely that these may need to be included. On-going development and research to adapt topology optimisation [1][2][3][4][5][6] to support ‘overhang constraints’ or specifically minimise boundaries with support angles that require support has progressed within recent years since the time of this post. Research has also considered using topology optimisation to structurally derive support structures based on an ‘inherent strain’ or distortion as an input [7]. Infact, are now available as design constraints within commercial Topology Optimisation software. However, momentarily these are currently not a complete or holistic solution. By their inclusion, there is a detriment to the overall performance of the solution optimsed. They also do not factor other objective functions such as minimising support material, overhang surfaces, part anisotropy and crucially the piece part cost [8][9]. In industrial applications, the part functionality or fundamental shape may make this challenging or penalise the algorithms. ‘Generative’ approaches, may globally optimise the part (including orientation) to minimise the requirements of support structures, but it is inevitable that some use is required. Geometrically, the quality or surface roughness of overhang or down-skin surfaces are improving through process optimisation of the laser parameters provide by the OEMs. There are indications that the choice of powder size and the layer thickness may improve the surface finish of these problematic regions.

Under some situations support structures can minimise the risk taken to manufacture parts first-time and ultimately reduce the cost of a supplier delivering the part to the customer. It also provides paths to dissipate excess heat generated which will become a further challenge to overcome with the adoption of multiple-laser SLM systems. Research has also proposed different support structures strategies for mitigating the effects of overheating and distortion in the SLM process [10], which included using topology optimisation to find thermally efficient support structures for heat transfer.

Support Structure Generation Capability in existing AM Pre-processing Software

For the specific area of interest for PySLM, it is a particular challenging requirement that remains to be overcome in selective laser melting and to a much lesser extent electron beam melting. The generation of support structures in FDM and SLA technologies is well established and available in consumer-led software for popular FDM printers such as Ultimaker Cura, Slic3r, SLA Formula’s Preform for SLA, or Chitubox for DLP . Fortunately, some of these software are opensource and provide some reference to how these are generated and successfully adopted across FDM 3D printing. Arguably, I have yet to delve into methods for how these are generated but it is expected the supports generated are similar to that used in metal AM . In metal additive manufacturing, commercial capability is available in both Materialise’s Magics SG/SG+ Module, Netfabb and to some existing OEM software. A reference and implementation of support generation for commercial or industrial led 3D printing especially in metal additive manufacturing is currently non-existent. These software are known to be relatively expensive to purchase and maintain.

Support Structure Generation in Research

In academic literature, the use of commerical software for support generation covers a couple of common research areas in the AM Literature including:

  • Part assessment: part buildability, overhang analysis
  • Process planning and optimisation: build-time prediction, build volume packing, cost modelling
  • Distortion and support minimisation: Numerical simulation to minimise distortion and support structure requirements
  • Lattice structures: minimising support structure requirements

Further overview of current work and research in Support Structures is also reported [11]. Specifically concerning about support generation in Laser PBF processes for these posts, support generation remains an outstanding challenge with the process.

Overhang Areas

Overhang areas are characterised as those prone to generate surfaces that do not conform to the intended geometry of the digital model. These usually result in with surfaces of high roughness / poor surface quality or formation of ‘dross’. These underlying regions may be susceptible to defect inclusions due to the localised overheating, due to the insulative behaviour of powder underneath the exposure zone. Fundamentally, Overhang areas correspond with the build-up of geometry inclined at shallow angles inclined against the build direction i.e. ‘overhang-angle’. It is dependent on many factors including the

  • machine system,
  • material alloy processed,
  • layer thickness,
  • optimisation of laser parameters (the down-skin parameter set).

Completely unsupported areas – those which do not have any solid material underneath, exasperate this effect. Under some situations, the support material become disconnected and dislodged by the powder spreading or re-coating mechanism, which in the extreme case may cause build-failure.

Mitigating the Effects of Distortion due to Residual stress

Some metal alloys are susceptible to the effects of residual stress generation, in particular Titanium. These stresses manifest with the manufactured part due to thermal-gradients. The effect of residual stress is that it generates internal forces causing distortion of the part. In the extreme situations, it can cause failure due of material due to stresses exceeding the material yield-point. During the build-process, it causes parts to ‘curl’ upwards. This can be somewhat mitigated to an extent using strong enough support structures in the correct place. It can be decided through the intuition the of the machine operator or now through the use of dedicated AM build simulation software. Various research has investigated the optimisation of support structures based on distortion of parts [12].

Much further could be discussed about the area of residual stress in detail but it can be further looked at within the literature. A future post may focus on this in greater detail.

Challenges Created by Support Structures

Amongst post-finishing requirements to achieve required tolerances of a manufactured part it contributes a significant cost to the end-part when they cannot be avoided.

Removal of metal supports is unpleasant and unsatisfactory stage of the manufacturing process. This is dependent on the hardness/strength of the material alloy and the type of supports utilised. They open up the myriad of variability from ‘hand-fettled‘ or ‘artisan’ finishes achieved through support – often referred as the artisanal craft of 3D printing. Even post machining the supports of is an additional process, that requires setup and also the time to prepare the part on the CNC machine. Perhaps, the utilisation of robotic CNC machining in the future will significantly reduce the cost of support removal as part of serial production. It would be fantastic to see some exploration integrating CNC machining of support removal directly from PySLM and is a move towards digital twins.

Support structure contribute the following (in)-direct intrinsic costs for a part produced by metal AM:

  • Indirect impact on functional performance by designing around overhang constraints
  • The additional time and cost for the designer to correctly generate the support – including simulation time
  • The direct cost of building the support structures on the system
  • The support removal time (machined or hand removed)
  • Direct impact on the e.g. total performance of the part due to this constraint e.g. surface roughness impacting fluid flow, fatigue performance

Aims of the PySLM Support Module for Support Structures

Support generation capability in PySLM aims to provide a working reference for other researchers to adopt amongst their work. Thus assist researcher’s understand and explore the generation of various types of common support structures employed in AM. Also, it will enable the entire AM ecosystem to have some capability that it can be adapted accordingly for their own wishes.

It does not intend to guarantee to provide a production ready support generation for metal AM parts without careful attention. In the future, this will expand to explore various approaches and further refine capability for PySLM to be a more comprehensive toolbox for use in AM research.

See the Next Post in the Support Structure Series


1 Serphos, M. R. (2014). Incorporating AM-specific Manufacturing Constraints into Topology Optimization. Delft University of Technology.
2 Leary, M., Merli, L., Torti, F., Mazur, M., & Brandt, M. (2014). Optimal Topology for Additive Manufacture: A method for enabling additive manufacture of support-free optimal structures. Materials & Design, 63, 678–690. https://doi.org/10.1016/j.matdes.2014.06.015
3 Gaynor, A. T., & Guest, J. K. (2016). Topology optimization considering overhang constraints: Eliminating sacrificial support material in additive manufacturing through design. Structural and Multidisciplinary Optimization, 54(5), 1157–1172. https://doi.org/10.1007/s00158-016-1551-x
4 Garaigordobil, A., Ansola, R., Santamaría, J., & Fernández de Bustos, I. (2018). A new overhang constraint for topology optimization of self-supporting structures in additive manufacturing. Structural and Multidisciplinary Optimization, 58(5), 2003–2017. https://doi.org/10.1007/s00158-018-2010-7
5 Gaynor, A. T. (2015). Topology Optimization Algorithms for Additive Manufacturing. Retrieved from https://jscholarship.library.jhu.edu/bitstream/handle/1774.2/38009/GAYNOR-DISSERTATION-2015.pdf
6 Allaire, G., Bihr, M., & Bogosel, B. (2020). Support optimization in additive manufacturing for geometric and thermo-mechanical constraints. Structural and Multidisciplinary Optimization, 61(6), 2377–2399. https://doi.org/10.1007/s00158-020-02551-1
7 Zhang, Z. D., Ibhadode, O., Ali, U., Dibia, C. F., Rahnama, P., Bonakdar, A., & Toyserkani, E. (2020). Topology optimization parallel-computing framework based on the inherent strain method for support structure design in laser powder-bed fusion additive manufacturing. International Journal of Mechanics and Materials in Design, 0123456789. https://doi.org/10.1007/s10999-020-09494-x
8 Brackett, D., Ashcroft, I., & Hague, R. (2011). Topology optimization for additive manufacturing. Solid Freeform Fabrication Symposium, 348–362. Retrieved from http://utwired.engr.utexas.edu/lff/symposium/proceedingsarchive/pubs/Manuscripts/2011/2011-27-Brackett.pdf
9 Brika, S. E., Mezzetta, J., Brochu, M., & Zhao, Y. F. (2017). Multi-Objective Build Orientation Optimization for Powder Bed Fusion by Laser. Volume 2: Additive Manufacturing; Materials, (August), V002T01A010. https://doi.org/10.1115/MSEC2017-2796
10 Paggi, U., Ranjan, R., Thijs, L., Ayas, C., Langelaar, M., van Keulen, F., & van Hooreweder, B. (2019). New support structures for reduced overheating on downfacing regions of direct metal printed parts. Solid Freeform Fabrication 2019: Proceedings of the 30th Annual International Solid Freeform Fabrication Symposium – An Additive Manufacturing Conference, SFF 2019, 1626–1640. Austin, Texas, USA.
11 Jiang, J., Xu, X., & Stringer, J. (2018). Support Structures for Additive Manufacturing: A Review. Journal of Manufacturing and Materials Processing, 2(4), 64. https://doi.org/10.3390/jmmp2040064
12 Krol, T. A., Zaeh, M. F., Seidel, C., & Muenchen, T. U. (2012). Optimization of supports in metal-based additive manufacturing by means of finite element models. SFF, 707–718.