Introduction
This module builds directly on Module 4: Using an Object Manager to Subscribe to Multiple Instances. You will need to complete that module before performing this module. In this module we will expand the capabilities of our visualization to include additional shapes.
Tetrahedrons are not native 3D objects in Unity®. The tetrahedron we used in this project is dynamically created from code found on this blog.
Step 1: Creating the New Prefabs
Since we want to include reading the Circle and Triangle topics, we need to create new prefabs based upon the Cube prefab we already have. Here we create the Sphere and Pyramid prefabs.
- Create the Sphere prefab the same way we created the cube prefab.
- Right-click in your Hierarchy and choose 3D Object»Sphere.
- Click on the Sphere component in the Hierarchy and in the Inspector, click Add Component. Add a RigidBody.
- Under Constraints, select X, Y, and Z for Freeze Rotation.
- Drag the Sphere from your Hierarchy into your Prefabs folder in your Project.
- In this project we will be dynamically creating our Pyramids.
- Start by creating an Empty Object in your Hierarchy by right-clicking and choosing Create Empty.
- Change the name of the GameObject to Pyramid.
- Add the following components to your Object:
- Mesh Filter
- Mesh Renderer
- Rigidbody
- Mesh Collider
- Set the Material of the Mesh Renderer to Default-Material.
- In the Rigidbody, under Constraints, select X, Y, and Z for Freeze Rotation.
- In the Mesh Collider, check Convex.
- Drag the PyramidMeshGenerator script from your Scripts/Shapes folder into the Pyramid Inspector.
- Drag the Pyramid into your Prefabs folder.
- Open the PyramidMeshGenerator script and add the following code to your Start function:
Mesh mesh = new Mesh();
Vector3 p0 = new Vector3(0, 0, 0);
Vector3 p1 = new Vector3(1, 0, 0);
Vector3 p2 = new Vector3(0.5f, 0, Mathf.Sqrt(0.75f));
Vector3 p3 = new Vector3(0.5f, Mathf.Sqrt(0.75f), Mathf.Sqrt(0.75f) / 3);
mesh.Clear();
mesh.vertices = new Vector3[]{
p0,p1,p2,
p0,p2,p3,
p2,p1,p3,
p0,p3,p1};
mesh.triangles = new int[]{
0,1,2,
3,4,5,
6,7,8,
9,10,11};
Vector2 uv3a = new Vector2(0, 0);
Vector2 uv1 = new Vector2(0.5f, 0);
Vector2 uv0 = new Vector2(0.25f, Mathf.Sqrt(0.75f) / 2);
Vector2 uv2 = new Vector2(0.75f, Mathf.Sqrt(0.75f) / 2);
Vector2 uv3b = new Vector2(0.5f, Mathf.Sqrt(0.75f));
Vector2 uv3c = new Vector2(1, 0);
mesh.uv = new Vector2[]{
uv0,uv1,uv2,
uv0,uv2,uv3b,
uv0,uv1,uv3a,
uv1,uv2,uv3c};
mesh.RecalculateNormals();
mesh.RecalculateBounds();
mesh.Optimize();
GetComponent<MeshFilter>().mesh = mesh;
GetComponent<MeshCollider>().sharedMesh = mesh; - Delete the Update function.
- Save the script.
Step 2: Updating the Comms Scripts
The comms scripts are currently only handling the Square reader and writer. Circle and Triangle are already configured in the XML, we only need to add support within DDSHandler and ShapeComms.
- We will start in the DDSHandler, adding additional members and initialization functions within the base class. This is all based on the DDS configuration that is already defined within the XML file.
- In DDSHandler, add the properties for the Circle and Triangle Data Readers and Data Writers.
protected DataReader<DynamicData> DataReaderSphere { get; private set; }
protected DataReader<DynamicData> DataReaderCube { get; private set; }
protected DataReader<DynamicData> DataReaderPyramid { get; private set; }
protected DataWriter<DynamicData> DataWriterSphere { get; private set; }
protected DataWriter<DynamicData> DataWriterCube { get; private set; }
protected DataWriter<DynamicData> DataWriterPyramid { get; private set; } - Now add the initialization code for these Data Readers and Data Writers in the DDSHandler Constructor.
DataReaderSphere = (DataReader<DynamicData>)subscriber.LookupDataReaderByName("SphereReader");
DataReaderCube = (DataReader<DynamicData>)subscriber.LookupDataReaderByName("CubeReader");
DataReaderPyramid = (DataReader<DynamicData>)subscriber.LookupDataReaderByName("PyramidReader");
DataWriterSphere = (DataWriter<DynamicData>)publisher.LookupDataWriterByName("SphereWriter");
DataWriterCube = (DataWriter<DynamicData>)publisher.LookupDataWriterByName("CubeWriter");
DataWriterPyramid = (DataWriter<DynamicData>)publisher.LookupDataWriterByName("PyramidWriter"); - Save the file.
- In the ShapeComms class, we will add additional functions for reading and writing to these new Data Readers and Data Writers. This will be simplified by the fact that we already created generic functions that we will be able to reuse.
- Add the following members to the ShapeComms class.
private DynamicData d_SphereData;
private DynamicData d_PyramidData; - We also need to initialize these members within the constructor.
d_SphereData = DataWriterSphere.CreateData();
d_PyramidData = DataWriterPyramid.CreateData(); - Now, add the following Write functions for the Sphere and Pyramid.
public void WriteSphere(Shape shape, String color)
{
SetShapeData(ref d_CubeData, shape, color);
DataWriterSphere.Write(d_SphereData);
}
public void WritePyramid(Shape shape, String color)
{
SetShapeData(ref d_CubeData, shape, color);
DataWriterPyramid.Write(d_PyramidData);
} - Finally, add the following Get functions for the Sphere and Pyramid.
public List<Shape> GetPyramids()
{
return ParseShapes(DataReaderPyramid.Take());
}
public List<Shape> GetSpheres()
{
return ParseShapes(DataReaderSphere.Take());
} - Save the file.
Step 3: Creating New Object Managers
Since these new shapes use different data readers, data writers, and topics, we will also use separate object managers to handle each shape.
- The Pyramid Manager and Sphere Manager will be very similar to the Cube Manager. Make the following changes to the two scripts.
- Change the inheritance from MonoBehavior to ShapeManager.
- Copy the Awake function from the Cube Manager into the scripts.
- Delete the Start functions.
- Copy the Update function from the Cube Manager and change the called function from GetCubes to GetPyramids for the Pyramid Manager and GetSpheres for the Sphere Manager.
Step 4: Integrating New Object Managers
All that needs to be done at this point is to add the new object manager scripts to the scene and call them from our GameManager.
- Setting up the Unity environment is relatively straightforward.
- Create two new Empty GameObjects within the Hierarchy and call them PyramidManager and SphereManager.
- Drag the appropriate manager scripts onto their corresponding GameObjects.
- Drag the appropriate prefabs onto the Shape Prefab box for each script.
- Save the scene.
- Open the GameManager script and make the following additions.
- Add new public GameObjects for the PyramidManager and SphereManager.
public GameObject m_PyramidManager;
public GameObject m_SphereManager; - Add Initialization code in the Start function for the new Managers.
m_PyramidManager.SetActive(true);
m_PyramidManager.GetComponent<PyramidManager>().Setup(m_DDS);
m_SphereManager.SetActive(true);
m_SphereManager.GetComponent<SphereManager>().Setup(m_DDS); - Save the file.
- Now connect the Pyramid and Sphere GameObjects to the GameManager.
- In Unity click on the GameManager GameObject in the Hierarchy subpanel.
- Drag the Pyramid Manager and Sphere Manager GameObjects from the Hierarchy subpanel into their corresponding boxes in the Inspector subpanel.
- Save the scene.
Step 5: Testing New Application Features
Here we are using the RTI Shapes Demo shipped with RTI Connext to test our new application.
- Launch the RTI Shapes demo from the RTI Launcher.
- Publish to the Square, Triangle, and Circle topics in the RTI Shapes demo.
- Click OK to use the default settings.
- Run the Unity application. You should see shapes moving across the screen.
If a shape does not appear, check the debug log within Unity to see if there are any problems within your application. Common problems include a missing license or XML file, along with misspellings of references within the XML file.
Also make sure that you didn’t make any mistakes in the copying process, for example not changing a reference to a Cube function to a Pyramid or Sphere function.
Module 5 Demo
This video covers the steps for Module 5.