Godot Destruction: How to Create a Destructible Environment in Godot

Today we're going we are going to install and learn how to use the Destruction plugin by Jummit. This tutorial will be divided into two parts. The first part covers how to easily create a destructible object in Blender. The second part covers how to install and use the Destruction plugin in Godot.

For the purpose of this tutorial, we will start with a new project. But you can follow these steps with an existing project as well.

To create a destructible environment, we need to create destructible objects. And to create a destructible object, we need to define a "whole mesh" and a "broken mesh" for the object. Luckily it's pretty easy to do this in Blender.

How to Create a Destructible Object in Blender

Open up Blender and create a new file. The General preset is fine.

Delete the Camera and the Light.

You can use whatever mesh you want, either one you have downloaded or you one you have made yourself. For the purposes of this tutorial, we will use the default Cube.

After we have the mesh we want to use, we then need to make the "broken version" of it.

First we need to install the Cell Fracture add-on. Go to Edit > Preferences.

In the search bar type in "cell fracture". Enable the add-on.

Once your model is finished and you are ready to fracture it, make sure you are in Object Mode. The cell fracture process will error if you are not in object mode.

Press F3. Search for the cell fracture function and open it.

If you do not have the function keys on your keyboard, you can open up Preferences again and keymap Search to spacebar instead.

There are many settings. You can experiment and see how they change the result. The two settings that will affect the end result the most are Source Limit and Noise.

Source limit defines how many pieces you want the mesh divided into. It is important to conisider the performance impact of having many physics objects on screen. Jummit, the creator of the Destruction plugin, recommends choosing only 5 or 10 pieces if you plan on having multiple destructible objects in a scene. And 20 pieces for a single object in the scene. Of course it is up to you to experiment and find the balance between the quality of the effect and frame-rate performance. You can always use Ctrl + z to undo the cell fracture operation.

An Important Note About Source Limit

The cell fracture operation will generate less pieces than the source limit if the mesh is not complex enough. You can easily see the number of pieces the mesh was actually divided into by looking at the bottom right corner of Blender.

An easy to way to make your mesh more complex without changing how it looks is by subdividing it. While in Edit Mode, right click the object and select Subdivide.

You may have to subdivide several times if you want many pieces to be created by the cell fracture operation.

Export the Object as glTF 2.0

Once you are you satisfied with the cell fracture result, it's time to export the objects. We will need to export the cells and the original object seperately. Make sure you have all the cell's selected.

Go to File > Export > glTF 2.0

This is the file format recommended by the Godot developers. In the Export Settings, enable Selected Objects.

Export it somewhere you can easily find later. Name it something to indicate this is the "broken" version.

Repeat the same process of the original object in Blender.

How to Install the Godot Destruction Plugin

Now it's time to open up Godot. Create a new project or use an existing one. First, we will create a new 3D scene.

Rename the Spatial node to "Main". Press Ctrl + s to save the scene.

Let's create a floor for our scene. Add a new node. It will be of type CSGBox.

In the Inspector tab, change the dimensions to be 50 width and 50 depth. Enable "Use Collison" as well.

Open up the Godot asset library by clicking on AssetLib at the top.

Type in "Destruction" in the search bar. Select the Destruction plugin by Jummit.

Download the plugin. Once it's done downloading, press the Install button. Once it's installed, the files will be put in the "addons" folder.

Import the Models to Godot

Create a new folder in Godot.

I like naming the root folder for any files that came from outside of Godot, "assets". You can right-click it and select "Open in File Manager" to open that folder in your OS. Copy the exported files you made in Blender to this folder. After that Godot will import the files.

We need to save these models as their own scenes in Godot.

Double-click the .glb files in the FileSystem tab. We will create a new inherited scene.

Ctrl + s to save the model as a .tscn file. Save both models, the "broken" one and the "whole" one.

Open up the "whole" scene. Add a new child node of type Node. Rename it to "Destruction".

Attach a script to the Destruction node. Instead of creating a new script, we will load an existing one. Select the folder icon.

In the addons folder you can find the Destruction plugin we installed, where there is already a destruction script defined.

addons > destruction > destruction.gd

Once the script is attached, select the Destruction node again. This will reveal new properties in the Inspector tab.

The Shard Template defines how the shards (pieces) behave after they are spawned into the world. There are already a few templates you can choose from in the addons folder. The Shard Scene defines which .tscn file is the "broken" version of the mesh. The Shard Container defines which scene the shards should be added to as children.

We have set up our project so far such that we do not need to change the Shard Container. Feel free to experiment with the different Shard Templates.

Let's define our Shard Scene. Click the down arrow and load the "broken" scene.

Open the Main scene. Instance the cube scene.

Move the cube up so it's not inside the floor. Add a Camera node as a child of the Main node. Move the camera so that it can see the cube. You can check "Preview" to see what the camera sees. Enable the Current property on camera.

Attach a script to the Main node.

extends Spatial

func _input(event: InputEvent) -> void:
	if event.is_action_pressed("ui_accept"):
		get_node("cube/Destruction").destroy()

We will bind the Enter key to call the destroy() function on the cube.

Play the project. When you press the Enter key the cube should fall apart.

4 Comments

  1. Avatar
    Darius
    December 12, 2020

    Hi Diego,

    I’ve followed your tutorial, but I’m having an issue with the destroyed mesh.
    The broken mesh I am using has a material, but when it gets instanced, the material is no longer applied, and is instead a blank mesh.
    Do you have a fix/advice on fixing this issue?

    Thanks

    Reply
    1. Diego
      Diego
      December 12, 2020

      Hey Darius,

      I actually encountered the same problem. I wrote a quick and dirty solution but it can definitely be improved. Add this function to the destruction.gd file.

      func destroy() -> void:
      	var shards := DestructionUtils.create_shards(shard_scene.instance(), shard_template)
      	get_node(shard_container).add_child(shards)
      
      	set_material(shards.get_children())
      
      	shards.global_transform.origin = get_parent().global_transform.origin
      	get_parent().queue_free()
      
      func set_material(shards):
      	var mesh = get_parent().get_node("Cube")
      	var mat = mesh.get_surface_material(0)
      
      	for s in shards.size():
      		for m in shards[s].get_node("MeshInstance").get_surface_material_count():
      			shards[s].get_node("MeshInstance").set_surface_material(m, mat)
      Reply
  2. Avatar
    POISON
    February 11, 2021

    Hello,
    I get an error “attempt to call function ‘destroy’ in base ‘null instance’ on a null instance”, even if I’m 100% sure everything is ok. How do I fix this?

    Reply
    1. Diego
      Diego
      February 12, 2021

      Hey POISON,

      Null instance errors are always difficult to debug.

      You know that the object you are calling the “destroy()” function on is null, so you have to work backwards from there.

      get_node("cube/Destruction").destroy()
      

      Does the node “cube” have a child node named “Destruction”? Be mindful of the capitalization.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top