3ds Max Object Placement Scripts

It can be a bit easier to place objects using 3ds Max than it would be to place things in UE4, but there’s currently no way to get those positions from 3ds Max to UE4 and try to maintain instancing. So here are a couple Maxscripts to help with that.

The first script is for unique objects–so anything that doesn’t have multiple copies of the object.

https://imagizer.imageshack.us/v2/244x226q90/854/qw2v.jpg




rollout test "Copy to UE4"
(

	label packagelabel "Folder Path" style_sunkenedge:false width:180 height:20
	edittext packagename "" width:180
	label objectlabel "Prefix" style_sunkenedge:false width:180 height:20
	edittext prefix "" width:180

	button btnCopy "Copy" width:180

	fn round_to val =
	(
	(floor (val + 0.5))
	)
	on btnCopy pressed do 	
	(
		
		clipboardstring=""

		clipboardstring += ("Begin Map")
		clipboardstring += ("
"+"   Begin Level")
		
		for obj in selection do
			
		(


			clipboardstring += ("
"+"      Begin Actor Class=StaticMeshActor Name=" + prefix.text + obj.name + " Archetype=StaticMeshActor'/Script/Engine.Default__StaticMeshActor'")
			clipboardstring += ("
"+"         Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0 ObjName=StaticMeshComponent0 Archetype=StaticMeshComponent'/Script/Engine.Default__StaticMeshActor:StaticMeshComponent0'")
			clipboardstring += ("
"+"         End Object")
			clipboardstring += ("
"+"         Begin Object Name=StaticMeshComponent0")
			clipboardstring += ("
"+"            StaticMesh=StaticMesh'" + packagename.text + prefix.text + obj.name + "." + prefix.text + obj.name + "'")
			clipboardstring += ("
"+"            StaticMeshDerivedDataKey=\"STATICMESH_34081786561B425A9523C94540EA599D_359a029847e84730ba516769d0f19427_08B81D3F4753513B93E720832A7E9708000000000100000001000000000000000000803F0000803F00000000000000000000344203030300000000\"")
			clipboardstring += ("
"+"            RelativeLocation=(X=" + obj.transform.position.x as string)
			clipboardstring += (",Y=" + ((obj.transform.position.y) - (obj.transform.position.y) - (obj.transform.position.y)) as string)
			clipboardstring += (",Z=" + obj.transform.position.z as string)
			clipboardstring += (")")
			clipboardstring += ("
"+"            RelativeRotation=(Pitch=" + (round_to (obj.rotation.x_rotation) as integer) as string)
			clipboardstring += (",Yaw=" + (round_to ((obj.rotation.z_rotation * -1)) as integer) as string)
			clipboardstring += (",Roll=" + (round_to (obj.rotation.y_rotation) as integer) as string)
			clipboardstring += (")")
			clipboardstring += ("
"+"            RelativeScale3D=(X=" + obj.transform.scale.x as string)
			clipboardstring += (",Y=" + obj.transform.scale.y as string)
			clipboardstring += (",Z=" + obj.transform.scale.z as string)
			clipboardstring += (")")
			clipboardstring += ("
"+"         End Object")
			clipboardstring += ("
"+"         StaticMeshComponent=StaticMeshComponent0")
			clipboardstring += ("
"+"         RootComponent=StaticMeshComponent0")

			clipboardstring += ("
"+"         ActorLabel=\"" + prefix.text + obj.name + "\"")
			clipboardstring += ("
"+"      End Actor")

		)
			clipboardstring += ("
"+"   End Level")
			clipboardstring += ("
"+"Begin Surface")
			clipboardstring += ("
"+"End Surface")
			clipboardstring += ("
"+"End Map")
			SetClipBoardText (clipboardstring as string)
		)


)
createDialog test 200 160 fgcolor:Black

Copy the Code and save as UE4-Copy.ms

To use it in 3ds Max you can just drag it into your 3ds Max window and it will run the script.

-Instructions
Under Folder Path, put the path where the file is located in the UDK Content Browser, notice the formatting example.
Under Prefix put in the prefix for the object name. In my case, I had exported the meshes to a file name 787_chairs.fbx so every object ended up with a prefix of 787_chairs_

Make sure that your objects are selected and click Copy
It will copy the object information to the clipboard, just go to UE4 and paste. This currently supports position, rotation, and scale.

Second script is for instanced objects, so you would do this for each object that is used multiple times.

http://imageshack.com/a/img824/4978/2te9.jpg



rollout test "Copy to UE4"
(

	label packagelabel "Folder Path" style_sunkenedge:false width:180 height:20
	edittext packagename "" width:180
	label objectlabel "Object Name" style_sunkenedge:false width:180 height:20
	edittext objectname "" width:180

	button btnCopy "Copy" width:180

	fn round_to val =
	(
	(floor (val + 0.5))
	)
	on btnCopy pressed do 	
	(
		
		clipboardstring=""

		clipboardstring += ("Begin Map")
		clipboardstring += ("
"+"   Begin Level")
		
		for obj in selection do
			
		(


			clipboardstring += ("
"+"      Begin Actor Class=StaticMeshActor Name=" + objectname.text + "_30" + " Archetype=StaticMeshActor'/Script/Engine.Default__StaticMeshActor'")
			clipboardstring += ("
"+"         Begin Object Class=StaticMeshComponent Name=\"" + "StaticMeshComponent0" + "\"" + " Archetype=StaticMeshComponent'Default__StaticMeshActor:StaticMeshComponent0'")
			clipboardstring += ("
"+"         End Object")
			clipboardstring += ("
"+"         Begin Object Name=\"" + "StaticMeshComponent0" + "\"")
			clipboardstring += ("
"+"            StaticMesh=StaticMesh'" + packagename.text + objectname.text + "." + objectname.text + "'")
			clipboardstring += ("
"+"            StaticMeshDerivedDataKey=\"STATICMESH_46A8778361B442A9523C54440EA1E9D_2C1BC8F50A7A43818AFE266EB43D9060_D159F6D649D49C94FF855A98AD20AC5F0000000001000000010000000100000000000000000000004000000000000000010000000000803F0000803F0000803F0000803F000000000000803F00000000000000000000344203030300000000\"")
			clipboardstring += ("
"+"            RelativeLocation=(X=" + obj.transform.position.x as string)
			clipboardstring += (",Y=" + ((obj.transform.position.y) - (obj.transform.position.y) - (obj.transform.position.y)) as string)
			clipboardstring += (",Z=" + obj.transform.position.z as string)
			clipboardstring += (")")
			clipboardstring += ("
"+"            RelativeRotation=(Pitch=" + (round_to (obj.rotation.x_rotation) as integer) as string)
			clipboardstring += (",Yaw=" + (round_to ((obj.rotation.z_rotation * -1)) as integer) as string)
			clipboardstring += (",Roll=" + (round_to (obj.rotation.y_rotation) as integer) as string)
			clipboardstring += (")")
			clipboardstring += ("
"+"            RelativeScale3D=(X=" + obj.transform.scale.x as string)
			clipboardstring += (",Y=" + obj.transform.scale.y as string)
			clipboardstring += (",Z=" + obj.transform.scale.z as string)
			clipboardstring += (")")
			clipboardstring += ("
"+"         End Object")
			clipboardstring += ("
"+"         StaticMeshComponent=StaticMeshComponent0")
			clipboardstring += ("
"+"         RootComponent=StaticMeshComponent0")

			clipboardstring += ("
"+"         ActorLabel=\"" + objectname.text + "\"")
			clipboardstring += ("
"+"      End Actor")

		)
			clipboardstring += ("
"+"   End Level")
			clipboardstring += ("
"+"Begin Surface")
			clipboardstring += ("
"+"End Surface")
			clipboardstring += ("
"+"End Map")
			SetClipBoardText (clipboardstring as string)
		)


)
createDialog test 200 160 fgcolor:Black

Copy the Code and save as UE4-Copy Instanced.ms

To use it in 3ds Max you can just drag it into your 3ds Max window and it will run the script.

-Instructions
Folder path is the same as before
Under name, put the actual name of the object as it appears in the Content Browser

Make sure that only the instances of one object are selected, and click Copy
It will copy the information of all the selected objects to the clipboard, go to UE4 and paste.

Workflow for instancing–so for this example I have lots of chairs to place, so in 3ds Max I take one chair and place it at the origin and then export that as FBX to UE4. The object comes up as 787_chair_economy in the content browser. Back in 3ds Max I select all the instances of that type of chair and use the script, and then I can paste it back to UE4 and it will have the same positions. For the objects in 3ds Max they don’t actually have to be instances of the object or even the same object, all it’s doing is copying the transform information of the selections.

NOTE: This will not work with UDK. UDK uses a different formatting when you copy something to the clipboard.

I don’t know that much about scripting, I just learned enough to make these scripts. So if anyone wants to improve on them you are welcome to.

This script is great.

thank u very much

Hi, thanks for your scripts.

I had to place a ton of lights lately and thus took your instance-placer script as a base to create a light-instance-placer.

As it is made from the foundations of your tool, i thought it would be a good idea, to share it here:



rollout InstancePlacer "LightPlacer to UE4"
(

	label objectlabel "Object Name" style_sunkenedge:false width:180 height:20
	edittext objectname "" width:180
	
	label radiusLabel "Light Source Radius" style_sunkenedge:false width:180 height:20
	edittext lightRadius "" width:180
	
	label lengthLabel "Light Source Length" style_sunkenedge:false width:180 height:20
	edittext lightLength "" width:180

	button btnCopy "Copy" width:180

	fn round_to val =
	(
	(floor (val + 0.5))
	)
	on btnCopy pressed do 	
	(
		
		clipboardstring=""

		clipboardstring += ("Begin Map")
		clipboardstring += ("
"+"   Begin Level")
		
		objNum = 1
		
		for obj in selection do
			
		(
			

			clipboardstring += ("
"+"      Begin Actor Class=PointLight Name=PointLight_1 Archetype=PointLight'/Script/Engine.Default__PointLight'")
			clipboardstring += ("
"+"         Begin Object Class=PointLightComponent Name=\"LightComponent0\" Archetype=PointLightComponent'/Script/Engine.Default__PointLight:LightComponent0'")
			clipboardstring += ("
"+"         End Object")
			clipboardstring += ("
"+"          Begin Object Name=\"LightComponent0\"")
			clipboardstring += ("
"+"            SourceRadius=" + lightRadius.text)
			clipboardstring += ("
"+"            SourceLength=" + lightLength.text)
			clipboardstring += ("
"+"            LightGuid=451962E5407D0FABD1ACFCB456EE9F0C")
			clipboardstring += ("
"+"            Intensity=500.000000")
			clipboardstring += ("
"+"            bPrecomputedLightingIsValid=False")
			clipboardstring += ("
"+"            Mobility=Static")
			clipboardstring += ("
"+"            RelativeLocation=(X=" + obj.transform.position.x as string)
			clipboardstring += (",Y=" + ((obj.transform.position.y) - (obj.transform.position.y) - (obj.transform.position.y)) as string)
			clipboardstring += (",Z=" + obj.transform.position.z as string)
			clipboardstring += (")")
			clipboardstring += ("
"+"            RelativeRotation=(Pitch=" + (round_to (obj.rotation.x_rotation) as integer) as string)
			clipboardstring += (",Yaw=" + (round_to ((obj.rotation.z_rotation * -1)) as integer) as string)
			clipboardstring += (",Roll=" + (round_to (obj.rotation.y_rotation) as integer) as string)
			clipboardstring += (")")
			clipboardstring += ("
"+"            RelativeScale3D=(X=" + obj.transform.scale.x as string)
			clipboardstring += (",Y=" + obj.transform.scale.y as string)
			clipboardstring += (",Z=" + obj.transform.scale.z as string)
			clipboardstring += (")")
			clipboardstring += ("
"+"         End Object")
			clipboardstring += ("
"+"         PointLightComponent=LightComponent0")
			clipboardstring += ("
"+"         LightComponent=LightComponent0")
			clipboardstring += ("
"+"         RootComponent=LightComponent0")

			clipboardstring += ("
"+"         ActorLabel=\"" + objectname.text + objNum as string + "\"")
			clipboardstring += ("
"+"      End Actor")
			
			objNum += 1

		)
			clipboardstring += ("
"+"   End Level")
			clipboardstring += ("
"+"Begin Surface")
			clipboardstring += ("
"+"End Surface")
			clipboardstring += ("
"+"End Map")
			SetClipBoardText (clipboardstring as string)
		)


)
createDialog InstancePlacer 200 200 fgcolor:Black


It currently only places instances of Point-Lights and gives you the possibility to set the radius and length of them.
I found it usefull to create boxes of the specific size in max and for example place them along splines (spacing tool)
Then you can just go in and pick all the instances of those boxes, push the copy-button in the script (set radius and length to the according sizes, pick a name, the script automatically iterates this name with numbers) and then just paste it into unreal…et voila! ;()

This script brings in the objects, but the editor crashes when I play my level.


LongPackageNameToFilename failed to convert 'Box001//UEDPIE_0_Box001'. Path does not map to any roots.

I’ve tried doing a full build, converting the actor type, and several other things, before play testing. It still crashes.

Saving the project before playing, just after import corrupts the project. I won’t load at all. I wish the T3D import function was documented better. I could really use a utility like this.

I have Editor 4.4.3. The project was created with this version. I assume the script did work with earlier versions.

It looks like something in the scene has the wrong location put in for the static mesh

You might try this tool: Introducing 3ds MAX to UE4 FBX and t3d Exporter MaxScript - Community Content, Tools and Tutorials - Unreal Engine Forums
Which is a bit more fully featured.

Thanks for your prompt reply.

I tried Tom’s script. It still crashes. As you wrote above, I think the project has something corrupt at a level that is not accessible to the editor. I will start a new fresh project and see what happens. If it still crashes, I will ask Tom about it.

[Edit: I think I found my problem. I was trying to import the positions by going File>Import then selecting a .T3D file I had pasted the script results into. Edit>Paste works just fine. I hope this helps someone.]