Procedural Asteroid Maxscript :: UE4 Pipeline PG.S

**I wrote this quick script to pump out large libraries of random asteroid meshes for use in various scenes / settings. This script handles all of the heavy lifting and allows the user to generate well over 10,000 meshes every 25 minutes. The ProcGen Script also handles all exporting, pivot alignment, etc. **

Please feel free to use it in it’s entirety, or strip parts out of it for your own personal project.

Script Download: http://www.jeremybaldwin3d.com/#!code/c1mn9

Direct Download Link

For those without 3DS Max but would still like access to the script, here is a raw text format:


-- // Developed By: Jeremy Baldwin

try (destroyDialog MainWindow) Catch()

Rollout MainWindow "Proc-Asteroid Generator'"
(
	------------------------------  Open / Close Max Files Start ]] ------------------------------------------------------------------------------------------------------
	button openScene "||||||     Open Max Scene     ||||||" pos:[2,2] width:175 height:24
	button saveScene "||||||  Save Max Scene As   ||||||" pos:[178,2] width:172 height:24 
	
	on openScene pressed do
		(
			-- activate Open Command
			actionMan.executeAction 0 "40003"
		)
	
	on saveScene pressed do
		(
			-- activate Save Command
			actionMan.executeAction 0 "40007"
		)
	------------------------------  Open / Close Max Files End ]] ------------------------------------------------------------------------------------------------------
		
	------------------------------  Procedural Generation Start ]] ----------------------------------------------------------------------------------------------------
	subRollout subRoll01 width:352 height:800 pos:[1,28]
		Rollout Menu01 "Procedural Asteroid(s) :: Characteristics" 
			(
				button genMeshes "Generate Mesh Field" pos:[9,10] width:320 height:40
				spinner genSizeMin "Min Size = " pos:[11,56] fieldwidth:80 type:#integer range:[50,100000,120]
				spinner genSizeMax "Max Size = " pos:[11,76] fieldwidth:76 type:#integer range:[100,100000,200]
				spinner genRotMin "Min Rotation = " pos:[162,56] fieldwidth:80 type:#integer range:[0,360,0]
				spinner genRotMax "Max Rotation = " pos:[162,76] fieldwidth:76 type:#integer range:[0,360,360]
				spinner genAmount "Resolution :: Number of Meshes Within Field Row = " pos:[11,96] fieldwidth:56 type:#integer range:[5,400,20]
				label txt1 "Simulation :: --------------- ::" pos:[11,118]
				progressbar gTracker "" pos:[146,118] width:182
				checkbutton eMode "Edit Mode" pos:[11,136] width:96 height:22 enabled:false
				button resetScene "Reset Simulation" pos:[108,136] width:123 height:22 enabled:false
				button toggleMode "Toggle Widgets" pos:[232,136] width:96 height:22 enabled:false
				groupbox GS "" pos:[4,-1] width:330 height:164
	------------------------------  SGroup-Split ]] ----------------------------------------------------------------------------------------------------------------------
				spinner n1Size "N1 Size: " pos:[8,184] fieldwidth:134 range:[0.001,100000,6.2] enabled: false
				spinner n1Spread "N1 Spread: " pos:[8,204] fieldwidth:119 range:[0.001,100000,1.3] enabled: false
				spinner n1Iterations "N1 Iterations: " pos:[8,224] fieldwidth:106 range:[1,20,20] enabled: false
				button mapRender "" pos:[200,182] width:62 height:58 enabled: false
				button mapRenderResetN1 "Reset N1" pos:[264,182] width:64 height:58 enabled: false
				groupbox GE "Noise Algorithm" pos:[4,166] width:330 height:80
	------------------------------  SGroup-Split ]] ----------------------------------------------------------------------------------------------------------------------
				button procDecimation "Process" pos:[11,268] width:100 height: 26 enabled: false
				button doDecimation "Decimate" pos:[11,296] width:100 height:28 enabled: false
				label vPercent "Optimize % :: 100" pos:[120,268] 
				label vCount "Current Vertex Count :: " pos:[120,282]
				label numCount "000000" pos:[240,282]
				spinner optimizePercent "Optimize: " pos:[220,268] fieldwidth:48 range:[0,1,1] enabled: false
				progressbar dProgress "" pos:[120,298] width:208 height:26 
				groupbox GB "Decimation [Resolution] Tools" pos:[4,250] width:330 height:80
				
				global asteroidArray = #()
				
				on genSizeMin changed val do
					(
						genSizeMin.range = [50,genSizeMax.value,val]
					)
					
				on genSizeMax changed val do
					(
						genSizeMax.range=[genSizeMin.value,100000,val]
						gd = $Temp_Grid
						gd.length = (genSizeMax.value)*genAmount.value
						gd.width = (genSizeMax.value)*genAmount.value
						$FieldInfo_Y.pos.x = (((gd.width/2)+100)*-1)
							$FieldInfo_Y.text = ("Field Resolution Y = " + (genAmount.value as string))
						$FieldInfo_X.pos.y = (((gd.length/2)+100)*-1)
							$FieldInfo_X.text = ("Field Resolution X = " + (genAmount.value as string))
					)
				
				on genAmount changed val do
					(
						gd = $Temp_Grid
						gd.lengthsegs = val
						gd.widthsegs = val
						gd.length = genSizeMax.value*val
						gd.width = genSizeMax.value*val
						$FieldInfo_Y.pos.x = (((gd.width/2)+100)*-1)
							$FieldInfo_Y.text = ("Field Resolution Y = " + (genAmount.value as string))
						$FieldInfo_X.pos.y = (((gd.length/2)+100)*-1)
							$FieldInfo_X.text = ("Field Resolution X = " + (genAmount.value as string))
					)
				
				on genMeshes pressed do
					(
						emode.enabled = true
						resetScene.enabled = true
						toggleMode.enabled = true
						genMeshes.enabled = false
						genSizeMin.enabled = false
						genSizeMax.enabled = false
						genRotMin.enabled = false
						genRotMax.enabled = false
						genAmount.enabled = false
						dG = $Temp_Grid
						uGD = genAmount.value
						uMesh = Box lengthsegs:1 widthsegs:1 heightsegs:1 length:100 width:100 height:100 mapcoords:on pos:[0,0,0] isSelected:On
						uMesh.pivot = uMesh.center
						uMesh.pos = (((genSizeMax.value*genAmount.value)*-1)+(dG.width/2)),(((genSizeMax.value*genAmount.value)*1)-(dG.width/2)),0]
						uMesh.wirecolor = color 28 28 177
						--//Smoothing
							tSmooth = (TurboSmooth())
							addModifier uMesh tSmooth
							uMesh.modifiers#TurboSmooth].iterations = 3
							--//
						for n = 1 to uGD do
						(
							for u = 1 to uGD do
								(
									gTracker.color = color 151 135 100
									gTracker.value = (100*u)/uGD
									maxOps.cloneNodes uMesh cloneType:#copy newNodes:&nnl #nodialog
									aName = (nnl.name = uniquename "55787Asteroid")
									append asteroidArray aName
									nnl.pos = $.pos.x+genSizeMax.value, $.pos.y, 0]
									select nnl
									$.width = (random genSizeMin.value genSizeMax.value)
									$.length = (random genSizeMin.value genSizeMax.value)
									$.height = (random genSizeMin.value genSizeMax.value)
									$.widthsegs = (random 1 1)
									$.lengthsegs = (random 1 2)
									$.heightsegs = (random 1 1)
									$.pivot = $.center
									rotate $ (angleaxis 90 (random genRotMin.value genRotMax.value), (random genRotMin.value genRotMax.value), (random genRotMin.value genRotMax.value)])
									--//Displacement
										tDisplace = (Displace ())
										addModifier $ tDisplace
										$.modifiers#Displace].strength = -45
										$.modifiers#Displace].maptype = 2
										$.modifiers#Displace].map = meditMaterials[24]
										$.modifiers#Displace].U_Tile = (random 0.75 2)
										$.modifiers#Displace].V_Tile = (random 0.75 2)
								)
							uMesh.pos.y = (uMesh.pos.y-genSizeMax.value*genAmount.value/genAmount.value)
							select uMesh
						)
						delete uMesh
							--//setup Map Rendering Preview
									noiseT = rm = renderMap meditMaterials[24] size:[128,58] 
									mapRender.images = #(noiseT, undefined, 1,1,1,1,1 )
						procDecimation.enabled = true
					)
					
				on eMode changed state do
					(
						if state then
							(
								procDecimation.enabled = false
								n1Size.enabled = true
								n1Spread.enabled = true
								n1Iterations.enabled = true
								mapRenderResetN1.enabled = true
								select $55787Asteroid001
									-- // Isolation
											macros.run "Tools" "Isolate_Selection"
								Max select none
							)
						else
							(
								procDecimation.enabled = true
								n1Size.enabled = false
								n1Spread.enabled = false
								n1Iterations.enabled = false
								mapRenderResetN1.enabled = false
								Iso2Roll.C2Iso.changed true
							)
					)
					
				on resetScene pressed do
					(
						gTracker.value = 0
						emode.enabled = false
						resetScene.enabled = false
						toggleMode.enabled = false
						genMeshes.enabled = true
						genSizeMin.enabled = true
						genSizeMax.enabled = true
						genRotMin.enabled = true
						genRotMax.enabled = true
						genAmount.enabled = true
						procDecimation.enabled = false
						doDecimation.enabled = false
						optimizePercent.enabled = false
						for k in asteroidArray do
							(
								for m in geometry where m.name == k do
								(
									select m
									max delete
								)
							)
					)
					
				on n1Size changed val do
					(
						noiseT = meditMaterials[24]
						noiseT.size = val
						noiseT = rm = renderMap meditMaterials[24] size:[128,58] 
						mapRender.images = #(noiseT, undefined, 1,1,1,1,1 )
					)
					
				on n1Spread changed val do
					(
						noiseT = meditMaterials[24]
						noiseT.spread = val
						noiseT = rm = renderMap meditMaterials[24] size:[128,58] 
						mapRender.images = #(noiseT, undefined, 1,1,1,1,1 )
					)
					
				on n1Iterations changed val do
					(
						noiseT = meditMaterials[24]
						noiseT.iterations = val
						noiseT = rm = renderMap meditMaterials[24] size:[128,58] 
						mapRender.images = #(noiseT, undefined, 1,1,1,1,1 )
					)
					
				on procDecimation pressed do
					(
						procDecimation.enabled = false
						doDecimation.enabled = true
						optimizePercent.enabled = true
						emode.enabled = false
						resetScene.enabled = false
						toggleMode.enabled = false
						genMeshes.enabled = false
						genSizeMin.enabled = false
						genSizeMax.enabled = false
						genRotMin.enabled = false
						genRotMax.enabled = false
						genAmount.enabled = false
						n1Size.enabled = false
						n1Spread.enabled = false
						n1Iterations.enabled = false
						mapRenderResetN1.enabled = false
						delete $Temp_Grid
						delete $FieldInfo_X
						delete $FieldInfo_Y
							-- // conversion
								decI = (ProOptimizer ())
									for mData in geometry do
										(
											dProgress.color = color 151 135 100
											dProgress.value = 100
											select mData
											macros.run "Modifier Stack" "Convert_to_Poly"
											addModifier mData decI
											mData.modifiers#ProOptimizer].Calculate = true
										)
								max select none
					)
					
				on optimizePercent changed val do
					(
						select $55787Asteroid001
						aObj = $
						$.modifiers#ProOptimizer].VertexPercent = (val*100)
						max select none
						vPercent.text = ("Optimize % :: "+(val as string))
						numCount.text = ((val*642) as string)
					)
					
				on doDecimation pressed do
					(
						doDecimation.enabled = false
						optimizePercent.enabled = false
						for tmp in geometry do
							(
								select tmp
								macros.run "Modifier Stack" "Convert_to_Poly"
								resetXform tmp
								macros.run "Modifier Stack" "Convert_to_Poly"
							)
						max select none
					)
				
				on Menu01 rolledUp bState do
				(
					if (bState == true) then
					(
						MainWindow.height += Menu01.height
						MainWindow.height += 0
					)
					else
					(
						MainWindow.height -= Menu01.height
						MainWindow.height -= 0
					)
				)
			)
		
			Rollout Menu02 "Export Field :: Unreal Engine 4" 
			(
				button exportData "Export" pos:[11,12]
				edittext folderName "" pos:[60,12] width:268 height:22
				listbox lb "" pos:[11,36] width:318 height:10
				label statusLabel "Export Status: " pos:[13,178]
				groupbox GUL "" pos:[4,-1] width:330 height:200
				------------------------------  SGroup-Split ]] ----------------------------------------------------------------------------------------------------------------------
				
				on exportData pressed do
					(
						newFolder = (getSavePath caption:"Choose Folder Location" + "/")
						makeDir (newFolder + folderName.text)
						newFolder = (newFolder + folderName.text + "/")
						for i in geometry do
							(
								if classof i == Editable_Poly or classof i == Editable_Mesh then
								(
									select i
									j = i.transform
									i.pos = [0,0,0]
									theFile= (i.name) as string
									exportFile (newFolder + "/" + theFile)  #noPrompt selectedOnly:true 
									i.transform = j
									lb.items = append lb.items (i.name as string)
								)
							)
							max select none
							messagebox "Successful!"
					)
				
				on Menu02 rolledUp bState do
				(
					if (bState == true) then
					(
						MainWindow.height += Menu02.height
						MainWindow.height += 0
					)
					else
					(
						MainWindow.height -= Menu02.height
						MainWindow.height -= 0
					)
				)
			)

on MainWindow open do
    (
		resetMaxFile #noprompt
		--//Noise Map A
			noiseT = meditMaterials[23] = Cellular ()
			noiseT.name = "Noise_Algo_A"
			noiseT.coords.coordType = 0
			noiseT.type = 1
			noiseT.fractal = on
			noiseT.size = 110
			noiseT.iteration = 2
		--//Noise Map B
			noiseT = meditMaterials[24] = Cellular ()
			noiseT.name = "Noise_Algo_B"
			noiseT.coords.coordType = 2
			noiseT.coordinates.Mapchannel = 1
			noiseT.type = 1
			noiseT.fractal = on
			noiseT.size = 6.2
			noiseT.spread = 1.3
			noiseT.iteration = 20
		--//
				--//Grid
					tempGrid = Plane length:(20*200) width:(20*200) lengthsegs:20 widthsegs:20 pos:[0,0,0] isSelected:on
					tempGrid.name = "Temp_Grid"
					iL = (lattice())
					addmodifier tempGrid iL
					tempGrid.modifiers#Lattice].Strut_Radius = 1
					tempGrid.modifiers#Lattice].Joint_Radius = 22.5
					tempGrid.wirecolor = color 88 177 27
						--//
							--//Field Info
								--XField
								xText = text size:100 kerning:0 leading:0 pos:[0,(((tempGrid.width/2)+100)*-1),-200] isSelected:on
								xText.name = "FieldInfo_X"
								rotate xText (angleaxis 90 [1,0,0])
								xText.wirecolor = color 227 153 153
								xText.text = "Field Resolution X"
									-- YField
								yText = text size:100 kerning:0 leading:0 pos:(((tempGrid.width/2)+100)*-1),0,-200] isSelected:on
								yText.name = "FieldInfo_Y"
								rotate yText (angleaxis -90 [0,0,1])
								rotate yText (angleaxis -90 [0,1,0])
								yText.wirecolor = color 227 153 153
								yText.text = "Field Resolution Y"
		max select none
        addSubRollout subRoll01 Menu01 rolledup:true
		addSubRollout subRoll01 Menu02 rolledup:true
    )
)
createDialog MainWindow 352 80

Thank you for sharing this with us Jeremy!

You are the one-stop resource for all our Interstellar UE4 needs!

:slight_smile:

Rama

No problem :slight_smile:
I hope someone gets some use out of it at one time or another.