PricingDeep DiveLevel 1 - Process Deep Dives

SLA / DLP / LCM

How to price vat photopolymerisation parts (SLA, DLP, MSLA, LCM) from resin volume and machine time, including the SLA-specific cross-section scaling adjustment.

Why this process is unique

Vat photopolymerisation (SLA, DLP, LCD, LCM) cures liquid resin layer by layer using UV light. Cost has two components:

  • Resin: sold by the litre, significantly more expensive than FDM filament
  • Machine time: layer count × time per layer × cost per hour

Supports are mandatory for most prints. They consume resin and add post-processing time (removal, sanding). Unlike FDM, supports in vat processes are separate structures added by the slicer - estimate from the convex hull gap.


SLA vs DLP - the critical pricing distinction

SLA and DLP cure resin fundamentally differently. This changes how time per layer behaves and has direct consequences for pricing.

SLADLP / MSLA / LCM
How it worksLaser traces the contour and fill of each layer point by pointUV projector or masked screen exposes the entire layer simultaneously
Time per layerScales with cross-sectional area - more to scan = longerFixed exposure time regardless of layer area or part count
Packing more partsEach additional part increases cross-section to scan, so each layer takes longerNearly free - same exposure time whether 1 or 10 parts fill the plate
timePerLayer in your equationCalibrate per typical part size, or calculate from areaSet as a fixed constant for your machine and resin

For SLA: print time grows with both layer count and the amount the laser has to trace per layer. Nesting more parts on the build plate can reduce per-part machine cost, but only up to a point - each added part increases the cross-section to scan, making every layer slower. On large or dense plates the benefit of nesting shrinks significantly.

For DLP / MSLA / LCM: the projector flashes the entire layer at once. Packing more parts onto the plate does not increase time per layer at all - nesting is almost always a win.

Warning

The algorithm below uses a fixed timePerLayer - correct for DLP/MSLA/LCM. For SLA, see the note at the end of the algorithm section.


Core methodology

Resin volume: actual part volume + estimated support volume + waste

Print time: numberOfLayers × timePerLayer. The part is usually oriented at an angle (45°) to minimise layer count and support contact area.

Orientation effect: at 45°, the effective print height = longest dimension × cos(45°) ≈ longest × 0.707


Numerical example

Part: 50 × 30 × 80mm bracket, volume = 30,000 mm³, convexHullVolume = 35,000 mm³

ParameterValue
resinCostPerLiter€95
machineCostPerH€12
Layer height0.06 mm
Time per layer25 s

Resin volume:

  • Part: 30,000 mm³
  • Supports: (35,000 − 30,000) × 0.10 = 500 mm³
  • Waste: 30,000 mm² × area ≈ 0 (simplified)
  • Total: ~30,500 mm³ = 0.0305 L
  • Resin cost: 0.0305 × 95 = €2.90

Print time:

  • maxDim = 80mm, at 45°: height = 80 × 0.707 = 56.6mm
  • Layers: ceil(56.6 / 0.06) = 944
  • Time: 944 × 25 / 3600 = 6.55 hours
  • Machine cost: 6.55 × 12 = €78.60

Unit price (1 part): ~€81.50


Complete algorithm

const { material, width, height, length, volume, area, convexHullVolume } = specification
const { quantity } = requisition

// Chamber limits
const CHAMBER_LENGTH = 220
const CHAMBER_WIDTH  = 125
const CHAMBER_HEIGHT = 200

const LAYER_HEIGHT_MM = 0.06

const resinCostPerLiter = material.variables['resinCostPerLiter']
const machineCostPerH   = material.variables['machineCostPerH']

// Resin volume: part + supports + waste
const supportVolumeMm3 = (convexHullVolume - volume) * 0.10
const wasteVolumeMm3   = area * 0.05
const totalVolumeLiters = (volume + supportVolumeMm3 + wasteVolumeMm3) / 1_000_000
const materialCost = round(totalVolumeLiters * resinCostPerLiter, 2)

// Print time: parts are tilted 45° to minimise Z height
const maxDimension    = Math.max(width, height, length)
const heightAt45Deg   = maxDimension * Math.cos(45 * (Math.PI / 180))
const numberOfLayers  = Math.ceil(heightAt45Deg / LAYER_HEIGHT_MM)
const timePerLayer    = variable('timePerLayer', 25)  // seconds, override for different resins
const printTimeHours  = variable('printTime', round(numberOfLayers * timePerLayer / 3600, 2))
const machineCost     = round(printTimeHours * machineCostPerH, 2)

// Pricing
const getDiscount = createBands({ 5: 0.95, 10: 0.90, 20: 0.875, 40: 0.85, 80: 0.825 }, 1.0)
const baseCost    = (materialCost + machineCost) * getDiscount(quantity)
const unitPrice   = variable('unitPrice', round(baseCost, 2))

const oversized = length > CHAMBER_LENGTH || width > CHAMBER_WIDTH || height > CHAMBER_HEIGHT
done(unitPrice, printTimeHours, oversized)

Material variables: resinCostPerLiter, machineCostPerH

Adapting for SLA

For SLA, replace the fixed timePerLayer with one that scales with cross-sectional area. The laser scans at a fixed speed, so more area = more time.

Estimating average cross-section:

The ratio volume / minBoundingBoxVolume tells you what fraction of the bounding box is actually solid. Apply that fill ratio to the XY footprint of the bounding box and you get the average cross-section the laser has to trace per layer:

avgCrossSection = (length × width) × (volume / minBoundingBoxVolume)
               = volume / height

This simplifies neatly: average cross-sectional area = total volume ÷ effective print height. No surface area involved - surface area is the outer skin, not the per-layer slice.

// Average cross-section: fill ratio applied to XY bounding footprint
// Equivalent to volume / heightAt45Deg — derived from bbox fill ratio
const fillRatio          = volume / minBoundingBoxVolume
const avgCrossSectionMm2 = length * width * fillRatio  // = volume / height

// Laser scan speed in mm2/s — set as a material variable for your machine
const scanSpeedMm2PerSec = material.variables['scanSpeedMm2PerSec']  // e.g. 1000

const timePerLayerSLA = variable('timePerLayer', round(avgCrossSectionMm2 / scanSpeedMm2PerSec, 2))
const printTimeHours  = variable('printTime', round(numberOfLayers * timePerLayerSLA / 3600, 2))

For SLA you should also treat nesting conservatively: each additional part on the plate adds its cross-section to every shared layer, so packing many large parts can make the machine cost per part increase rather than decrease.


When to use this

All UV vat processes. For DLP / MSLA / LCM: use the main algorithm as-is with a fixed timePerLayer. For SLA: use the adapted version above with scanSpeedMm2PerSec as a material variable.

Last updated on

On this page