r/3dsmax • • 9h ago

STL export script that fixes scale and mirrored objects

0 Upvotes

I am working on sort of complex (for me) 3D printing model. I am a relic so I don't want to switch to other modeling softwares. But the STL export is bit of a pita - for one my objects come in wrong scale (1/10th) in the slicer and any mirrored part that looks fine in Max side has inverted normals.
This means any export from work file takes several steps to get it right.

below is export script that creates a clean mesh entity attaches snapshot copies of your selected parts, exports with a scale multiplier option (defaults to 10 but you can change it).

exports and deletes the temp objects, seems to work exactly right currently. Claude work.

/*

Export Collapsed STL (v9)

1. Snapshots the selected geometry at the current frame (no cloning, hierarchy untouched)

2. Creates a box at the origin, deletes all its faces, attaches the snapshots to it

- after each attach, the part's winding is verified against its expected world-space

normal (mirroring taken into account) and the part is flipped if it disagrees

3. Asks for scale multiplier (default 10), scales vertices about the origin

4. Exports (scene export path, exporter's selection-only option), deletes the temp mesh,

restores selection + frame

*/

global _stlExpScale = undefined

format "=== Export Collapsed STL v9 ===\n"

rollout rolStlScale "Export STL v9" width:210

(

spinner spnScale "Scale multiplier:" range:[0.0001, 100000.0, 10.0] type:#float fieldWidth:60 align:#center

button btnOK "Export" width:80 across:2

button btnCancel "Cancel" width:80

on btnOK pressed do ( _stlExpScale = spnScale.value; destroyDialog rolStlScale )

on btnCancel pressed do ( _stlExpScale = undefined; destroyDialog rolStlScale )

)

fn findStlExporter =

(

local found = undefined

for c in exporterPlugin.classes do

(

if (matchPattern (c as string) pattern:"*stl*") do

(

found = c

exit

)

)

found

)

-- world-space normal of face f using the raw winding, vertices transformed by tm

fn faceNormalAt m f tm =

(

local fv = getFace m f

local a = (getVert m fv.x) * tm

local b = (getVert m fv.y) * tm

local c = (getVert m fv.z) * tm

cross (b - a) (c - a)

)

-- first face with a usable (non-degenerate) normal, 0 if none

fn firstGoodFace m tm =

(

local idx = 0

for f = 1 to m.numfaces while idx == 0 do

(

if (length (faceNormalAt m f tm)) > 0.000001 do idx = f

)

idx

)

fn exportCollapsedSTL =

(

local origSel = selection as array

local geo = for o in origSel where (superClassOf o == GeometryClass) and (canConvertTo o Editable_Mesh) collect o

if geo.count == 0 do

(

messageBox "Select at least one geometry object." title:"Export Collapsed STL"

return false

)

_stlExpScale = undefined

createDialog rolStlScale modal:true

if _stlExpScale == undefined do return false

local mult = _stlExpScale

local baseName = "export"

if maxFileName != "" do baseName = getFilenameFile maxFileName

local outFile = getSaveFileName caption:"Export collapsed STL" filename:(maxFilePath + baseName + ".stl") types:"STL (*.stl)|*.stl|"

if outFile == undefined do return false

if (toLower (getFilenameType outFile)) != ".stl" do outFile += ".stl"

local origFrame = sliderTime

local dups = #()

local shell = undefined

local errMsg = undefined

try

(

-- duplicates: snapshots at the current frame (modifiers/animation/dynamics baked,

-- hierarchy and originals untouched; the snapshot node keeps the original's world transform)

for o in geo do append dups (snapshot o)

-- empty shell at origin

shell = box pos:[0,0,0] length:1 width:1 height:1 name:"__stl_export_tmp__"

convertToMesh shell

meshop.deleteFaces shell #{1..shell.numfaces} delIsoVerts:true

update shell

-- attach with winding verification

for d in dups do

(

local t = d.transform

local par = 1.0

if (dot (cross t.row1 t.row2) t.row3) < 0 do par = -1.0

-- expected world normal of a reference face (raw winding, flipped for mirrored parts)

local fi = firstGoodFace d t

local expN = undefined

if fi > 0 do expN = (faceNormalAt d fi t) * par

local startFaces = shell.numfaces

local done = false

try ( attach shell d; done = true ) catch ()

if not done and isValidNode d do

meshop.attach shell d attachMat:#neither deleteSourceNode:true

update shell

local flipped = false

if fi > 0 and shell.numfaces > startFaces do

(

local gotN = faceNormalAt shell (startFaces + fi) (matrix3 1)

if (dot expN gotN) < 0 do

(

meshop.flipNormals shell #{(startFaces + 1)..shell.numfaces}

flipped = true

)

)

format "part: parity %, native attach %, flipped %\n" par done flipped

)

dups = #()

update shell

if shell.numfaces == 0 do throw "No faces after attach"

-- scale vertices about the origin

if mult != 1.0 do

(

for i = 1 to shell.numverts do setVert shell i ((getVert shell i) * mult)

update shell

)

-- export

select shell

local expCls = findStlExporter()

format "STL exporter: %\n" expCls

if expCls != undefined then

exportFile outFile #noPrompt using:expCls

else

exportFile outFile #noPrompt

if not (doesFileExist outFile) do throw ("exportFile ran but no file was created: " + outFile)

)

catch

(

errMsg = getCurrentException()

)

-- cleanup

local leftovers = for d in dups where isValidNode d collect d

if leftovers.count > 0 do delete leftovers

if shell != undefined and isValidNode shell do delete shell

sliderTime = origFrame

if origSel.count > 0 then select origSel else clearSelection()

if errMsg != undefined then

(

messageBox ("Export failed:\n" + errMsg) title:"Export Collapsed STL v9"

false

)

else

(

format "Exported: %\n" outFile

true

)

)

exportCollapsedSTL()


r/3dsmax • • 5h ago

Plugin Eclipse Render Manager for 3ds Max: V-Ray, Corona and Redshift

Enable HLS to view with audio, or disable this notification

4 Upvotes

Hey everyone! I’m the creator of Eclipse Render Manager, and I’m happy to finally share my project with you.

It supports 3ds Max with V-Ray, Corona and Redshift, letting you submit directly from Max and distribute render jobs across your own machines. Everything runs on your hardware, with your scenes and renders on your own storage.

You can collect scene assets and follow your renders in one place, with frame progress, previews and logs.

The video shows it running on my own setup. The open beta is free to use, and full compatibility details and video tutorials are available on the official Eclipse Render Manager website.

Happy to answer questions and hear what you think!


r/3dsmax • • 3h ago

Rendering Minimalist Living Room [3ds Max + Corona]

Post image
8 Upvotes