UnityLink Hands-On

Charles Pooh, Alec Shedelbower,
 Yan Zhuang, Jaebum Jung
Wolfram Research

Join the Conversation #WolframTechConf

Overview of the Talk

1. Setup

2. Quick Start

3. UnityLink

4. Assets

4. Unity Primitives

Setup: Install Unity

•  Go to https://store.unity.com

Needs["UnityLink`"]
InstallUnity[]

•  Download Personal Edition, Version 2017.2

Quick Start: Loading UnityLink

Load the UnityLink package.

Needs["UnityLink`"]

Open the Unity project selection window.

UnityOpen[]

Quick Start: Unity Interface

Note: The position of the windows may vary.

Quick Start: Basic Physics

Create a game object called Spikey.

spikey=CreateUnityGameObject["Spikey",PolyhedronData["Spikey"]]

Set its material color to red.

SetProperty[spikey["Material"],"Color"-> Red]

Change its position.

SetProperty[spikey,"Position"-> {0,20,10}]

Give it a rigidbody component so it is affected by physics.

rigidbody=CreateUnityRigidbody[spikey]

Set the “Convex” property on its Mesh Collider to be True.
(Required for non-static game objects with meshes)

meshCollider=UnityGameObjectComponents[spikey,"MeshCollider"];
SetProperty[meshCollider,"Convex"-> True]

Create a platform using the default Unity plane primitive.

platform=CreateUnityPlane["Platform"]

Increase the size of the platform.

SetProperty[platform,"LocalScale"-> {3,1,3}]

Change the rotation of the platform so it is tilted toward the camera.

SetProperty[platform,"EulerAngles"-> {-25,0,0}]

Quick Start: More Spikeys with Lights

Delete the existing Spikey.

DeleteUnityGameObject["Spikey"]

Turn the light down.

light=UnityGameObjectComponents["Directional Light","Light"];
SetProperty[light,"Intensity"-> 0.25]

Create a spikey mesh that we will reuse for multiple game objects.

mesh=CreateUnityMesh["spikey_mesh",PolyhedronData["Spikey"]]

Create multiple spikey game objects.

count=10;

Do[
(* Create the spikey object at a random position with smaller scale and random color. *)
go=CreateUnityGameObject["Spikey ("<>ToString[i]<>")",mesh,Properties-> {"Position"-> {RandomReal[{-8,8}],20+i*10,10},"LocalScale"-> {0.5,0.5,0.5},"Material"-> CreateUnityMaterial["material",RandomColor[Hue[_]]]}];

(* Set the Mesh Collider to be convex. *)
SetProperty[UnityGameObjectComponents[go,"MeshCollider"],"Convex"-> True];

(* Create the Rigidbody. Make the collision detection more accurate and add drag. *)
CreateUnityRigidbody[go,Properties-> {"CollisionDetection"-> "Continuous","Drag"-> 0.25}];

(* Attach a point light to the spikey and set its color to the same as the material. *)
CreateUnityLight[go,Properties-> {"Type"-> "Point","Color"-> go["Material"]["Color"],"Intensity"-> 3,"Range"-> 5,"RenderMode"-> "ForcePixel"}];

,{i,count}];

UnityLink: Roll-A-Ball

Close the current project.

CloseUnity[]

Open the roll-a-ball example.

UnityOpen["ExampleData/roll-a-ball"]

UnityLink: Run the Game

Click the Play button in the upper center of the project window to run the game.

UnityLink: Scenes

Find the current scene.

FindUnityScene[]

View hierarchy of all game objects in the current scene.

UnityHierarchyGraph[PlotTheme->"Minimal"]

On the Unity side:

UnityLink: Finding Object Positions

Get the position of a game object.

ball=FindUnityGameObject["Ball"]

ball["Position"]

View the positions of all game objects.

gameObjects=FindUnityGameObject[All];
positions=Table[go["Position"],{go,gameObjects}];
Graphics3D[{Sphere[#,0.5]&/@positions}]

UnityLink: Getting Object Meshes

Get the Mesh of a Game Object

Find the game object.

wall=FindUnityGameObject["EastWall"]

Access the “Mesh” property of the game object.

umesh=wall["Mesh"]

Use Normal to convert from a UnityObject to the nearest Wolfram Language representation.

mesh=Normal[umesh]

Wait! That mesh looks like a cube!

Transforming the Mesh

We need to apply the transform of the game object.

Start by getting the transform component. Transforms are special, we can access them like properties.

transform=wall["Transform"]

Convert it into a transformation function.

tFunction=Normal[transform]

Apply the transformation function to the mesh.

TransformedRegion[mesh,tFunction]

That looks better.

Transform ALL the Meshes

gameObjects=FindUnityGameObject[All];
meshes=Table[If[go["Mesh"]=!=None,TransformedRegion[Normal[go["Mesh"]],Normal[go["Transform"]]],Nothing],{go,gameObjects}];

RegionUnion@@meshes

UnityLink: Game Object Components

Get all the components on a given game object.

ball=FindUnityGameObject["Ball"]

UnityGameObjectComponents[ball]

Get a single component.

UnityGameObjectComponents[ball,"Transform"]

You can just use the name of the game object.

UnityGameObjectComponents["Ball","Transform"]

Can use All to get all components of a certain type.

UnityGameObjectComponents[All,"Light"]

UnityLink: Properties

Discovering Properties

Get the default properties of a UnityObject.

ball=FindUnityGameObject["Ball"]

ball["Properties"]

PropertyList[ball]

Getting Property Values

Get the value of a property by name.

ball["Name"]

PropertyValue[ball,"Name"]

ball["Scene"]

Shortcut Properties

Some properties are just fast ways to do common tasks.

“Components” is short for UnityGameObjectComponents[go, All].

ball["Components"]

UnityGameObjectComponents[ball]

“Mesh” is actually a property of the MeshFitler.

ball["Mesh"]

meshFilter=UnityGameObjectComponents[ball,"MeshFilter"]
meshFilter["Mesh"]

“Material” is a property of the MeshRenderer.

ball["Material"]

meshRenderer=UnityGameObjectComponents[ball,"MeshRenderer"]
meshRenderer["Material"]

Transform properties:

ball["Position"]
ball["LocalScale"]
ball["EulerAngles"]
ball["Rotation"]

Parent-child hierarchy:

collectable=FindUnityGameObject["Collectable (1)"];
parent=collectable["Parent"]

children=parent["Children"]

UnityHierarchyGraph[VertexStyle-> Append[Table[c-> Orange,{c,children}],parent-> Red],PlotTheme-> "Minimal"]

Setting Properties

Use SetProperty to change the property of a UnityObject.

SetProperty[ball,"Name"-> "Player"]

ball["Name"]

SetProperty[ball,"Name"-> "Ball"]

ball["Name"]

Change the ball mesh.

octahedron=CreateUnityMesh["dodecahedron",PolyhedronData["Dodecahedron"]]

SetProperty[ball,"Mesh"-> octahedron]

SetProperty[ball,"LocalScale"-> {0.5,0.5,0.5}]

DeleteUnitySphereCollider[ball]

meshCollider=CreateUnityMeshCollider[ball]

SetProperty[meshCollider,"Convex"-> True]

collider=UnityGameObjectComponents[ball,"SphereCollider"]

SetProperty[collider,"Radius"-> 1.5]

UnityLink: Changing Roll-A-Ball

Change the Ball Mesh

ball=FindUnityGameObject["Ball"]

Create the mesh and set it as the ball’s mesh.

spikey=CreateUnityMesh["alpha_spikey",PolyhedronData["RhombicHexecontahedron"]]

SetProperty[ball,"Mesh"-> spikey]

Change the transform scale to be 1/4 the original size.

SetProperty[ball,"LocalScale"-> {0.25,0.25,0.25}]

Delete the existing sphere collider since we aren’t using a sphere anymore.

DeleteUnitySphereCollider[ball]

Replace it with a mesh collider.

meshCollider=CreateUnityMeshCollider[ball]

SetProperty[meshCollider,"Convex"-> True]

Test it out. Having trouble moving?

Let’s increase the strength of our ball controller.

ballController=UnityGameObjectComponents["Ball","BallController"]

ballController["Properties"]

ballController["Speed"]

SetProperty[ballController,"Speed"-> 10]

Change the Materials

Create a new material.

blueMaterial=CreateUnityMaterial["Blue",]

Set the ball’s material to be the new material.

ball=FindUnityGameObject["Ball"];
SetProperty[ball,"Material"-> blueMaterial]

Create and set the platform material.

orangeMaterial=CreateUnityMaterial["Orange",]

platform=FindUnityGameObject["Platform"]

SetProperty[platform,"Material"-> orangeMaterial]

Change color property on existing material for the walls.

greenMaterial=CreateUnityMaterial["Green",]

walls=FindUnityGameObject["Walls"]["Children"]

Do[SetProperty[wall,"Material"-> greenMaterial],{wall,walls}]

Change Lighting and Camera

Get a reference to the light.

light=UnityGameObjectComponents["Directional Light","Light"]

Change the light type from Directional to Point.

light["Type"]

SetProperty[light,"Type"-> "Point"]

Increase the light intensity.

light["Intensity"]

SetProperty[light,"Intensity"-> 2.0]

Get a reference to the camera.

camera=UnityGameObjectComponents["Main Camera","Camera"]

Set the background color to be solid black.

SetProperty[camera,"BackgroundColor"-> Black]

SetProperty[camera,"ClearFlags"-> "SolidColor"]

UnityLink: BallController

How does the BallController script work?

Here is the C# code for the BallController:

We can also get the code directly from the script asset.

scriptAsset=FindUnityAsset["Assets/Scripts/BallController.cs"]

scriptAsset["Text"]

Assets: Creating Assets

Create an asset folder.

CreateUnityAsset[File["Assets/Meshes"]]

Create an asset from certain UnityObject types.

umesh=CreateUnityMesh["Spikey",PolyhedronData["Spikey"]]

asset=CreateUnityAsset[File["Assets/Meshes/Spikey.asset"],umesh]

Create an asset directly from asset create function.

CreateUnityAudioClip[File["Assets/birds.wav"],ExampleData[{"Audio","Bird"}]]

Create materials with random colors.

CreateUnityAsset[File["Assets/Materials"]]

materials=Table[CreateUnityMaterial[File["Assets/Materials/Material("<>ToString[i]<>").mat"],RandomColor[]],{i,6}]

Assets: Finding Assets

Find all assets in the Assets folder.

FindUnityAsset[All]//Short

Find all assets of a certain type.

FindUnityAsset[All,"Mesh"]

Find an asset at a specific path.

FindUnityAsset[File["Assets/birds.wav"]]

Find all assets in a directory.

FindUnityAsset[File["Assets/Materials"]]

Get the asset being referenced by a UnityObject.

scene=FindUnityScene[]

GetUnityAsset[scene]

Assets: Deleting Assets

Delete a single asset.

DeleteUnityAsset[File["Assets/birds.wav"]];

Delete all assets of a certain type.

materials=FindUnityAsset[All,"Material"];
DeleteUnityAsset/@materials;

Delete a folder and its contents.

DeleteUnityAsset[File["Assets/Meshes"]];

Unity Primitives

Unity already has some default 3D models that can be referenced by game objects.

Why Use Primitives?

• Faster – The mesh already exists in Unity, so there is no need to transfer the mesh data.

• Less Data – No need to store extra data for different meshes.

Creating Primitives

Use no parameters to get the default Unity game object.

CreateUnitySphere[]

Add parameters to customize the primitive.

CreateUnitySphere["MySphere",{0,0,0},3]

Types of Primitives

Other primitive types:

CreateUnityCube[]

CreateUnityPlane[]

CreateUnityQuad[]

CreateUnityCylinder[]

CreateUnityCapsule[]

The main difference between the Quad and Plane is the number of triangles.

plane=FindUnityGameObject["Plane"]["Mesh"]

quad=FindUnityGameObject["Quad"]["Mesh"]

Normal[plane]

Normal[quad]