Skip to content
This repository has been archived by the owner on Aug 4, 2024. It is now read-only.

Set up a custom scene with a custom USV

edvart-ros edited this page Jun 4, 2024 · 12 revisions

In this tutorial, we walk through the process of setting up a custom ocean scene with a custom USV!

Create a new scene

In the project viewer, add a new scene in a directory of your choice:

image

Add and customize the ocean

After opening your new scene, add an HDRP ocean in the scene Hierarchy:

image

Your scene should now contain a beautiful, vast ocean:

Customize the ocean by changing the colors, distant wind speed etc. It's a good idea to turn the distant wind speed down.

Make sure Script Interactions is ticked in the object inspector. This is required for the Submersion and Buyoancy scripts to work, which will allow our custom USV to float in the water:

image

Next, add a "Sky and Fog Global Volume" to the scene. This is not required, but is a key feature in the High Definition Rendering Pipeline which allows for fine-tuning of the physically-based visual environment. It also lets u add things like volumetric clouds, fog, bloom and other post-processing. Read more about it here.

In this scene, I added some volumetric clouds and fog:

Add your custom USV model

It's time to add our custom vehicle. For this section, you need a 3D mesh which represents the geometry of your vessel. The format of this mesh must be one that is supported by Unity, like .dae (Collada), .fbx or .obj. In most cases, meshes can be exported to one of these formats through CAD software or other 3D modelling software like Blender.

Setting up the visual mesh

In this case, I'm using a boat mesh from free3d. Place the mesh file somewhere in your project and create a new Empty game object in the scene hierarchy.

image

Next, add a Mesh Filter and a Mesh Renderer component to your custom USV game object. Set the mesh filter Mesh to your custom vehicle mesh and select a suitable material for the Mesh Renderer component. In this case, I am just using a default unity material, but you could create your own custom material in third party modelling software.

image

Clearly, the orientation of the mesh is not what we expect. The Transform of the object is set to the world origin, but the mesh is not aligned with the world axes (x-right, y-up, z-forward). This can happen when exporting meshes between software with different conventions. These issues can cause headaches in the future, and there are hacky ways to fix it, like using dummy gameobjects to "undo" the conversion error.

image

By inspecting the mesh file, we can see that the model consists of 69 332 vertices. This is okay for real-time rendering, but its not something we want to iterate over on the CPU, which handles physics. For this reason, it's a good idea to prepare a secondary, low-resolution physics mesh.

Fixing the mesh orientation and preparing the physics mesh

To align the orientation of the mesh with the Unity coordinate system convention, we can use Blender.

After importing your mesh into blender, rotate the object such that it aligns with Blender's coordinate convention (X-right, Y-forward, Z-up): image

This will be our new visual mesh. Export the object, and make sure to set the forward and up axes to Unity's convention (Y-up, Z-forward):

image

Place your new visual mesh somewhere in the unity project, and assign it to your game object. It should now be correctly aligned with the world axes: image

Preparing the physics mesh

To calculate submersion and buoyancy, we need a simpler representation of the 3D object. This can also be done in Blender.

For this particular mesh, I chose to first take its convex hull:

image

We can then use the Decimate modifier to further simplify the geometry:

image

The mesh now consists of 1 553 faces instead of 126 680! Export the mesh and store it in your Unity project. This will be the mesh used for intensive physics calculations.

In Unity, add a mesh collider and assign the custom physics mesh to it. For whatever reason, Unity recognized the mesh as concave, not convex. To fix this, we can check the "Convex" checkbox in the Mesh Collider component. Enable Gizmos to visualize it:

image

If we now place a Cube with a Rigidbody component above the USV and hit Play, we should see the cube fall and collide with the USV:

collision.mp4

This mesh is still quite complex, so unless you need very good collision checking, it's recommended that you create an even simpler mesh. This mesh will also be used to automatically calculate the inertia tensor of the boat.

Enabling physics

Currently, the USV acts as an immovable object. Let's enable physics by attaching a Rigidbody component to our USV game object! After adding the Rigidbody component, set some reasonable mass value and add some linear and angular damping. Also, check the "Automatic Tensor" box, unless you have informed data about the physical parameters of your custom vessel:

image

Hit play, and the vessel should start falling straight down. This is because have not added any components that take water physics into account yet.

Next, add a "Submersion" component. This is a custom script which determines which parts of the mesh are submerged in water based on the ocean state and a given triangle mesh. Assign your water surface to the "Water Surface" parameter and assign your physics mesh to the "Simplified Mesh" parameter . The "Patch Size" parameter determines the size of the patch used to approximate the water height around the vessel. This patch will follow the boat, and it's size must be large enough such that the simplified mesh is always contained within it. The USV I'm using here is about 5 meters long, so I choose to set the patch size to 7. The "patch resolution" determines the accuracy of the submersion approximation. Here, i set it to 6, but you can play around with different values. The higher the value, the slower the simulation will run.

image

To visualize the submersion script, check "Draw Patch" and "Draw Submerged". To temporarily stop the boat from falling, disable physics by checking "Is Kinematic" in its rigidbody component. Also, make sure that "Read/Write" is enabled on your physics mesh. Otherwise, the submersion script wont be able to read the mesh geometry. Start the simulation and make sure Gizmos are enabled.

submersion.mp4

As we can see, the submersion script is correctly determining the submerged parts of the vessel geometry, visualized by the green wireframe. The red grid represents the water patch used to approximate the water surface. All credit for this technique to Jacques Kerner.

The final step is to add the Buoyancy component. This is a custom script that uses the result of the Submersion component to compute and apply a buoyancy force to the object. Simply add the buoyancy component, and start the simulation. Make sure to uncheck "Is Kinematic" in the rigidbody component.

floating.mp4

Voila! Our custom USV floats! You might need to play with the mass, drag and center of gravity parameters to achieve an acceptable result. For this model, I ended up with the following rigidbody parameters: image

What's next?

You should now have a floating vessel which reacts to the ocean state, but it's not quite ready for ASV development. What's missing is a suite of sensors, a propulsion system, and a way to communicate data to and from the simulator (with ROS!).