Mesh in Godot – Complete Guide

Mastering the Mesh class in Godot 4 can seem like a winding road to newcomers, but it’s a journey well worth embarking on. As we delve into the fine-grained controls and creative freedoms granted by understanding meshes, your toolkit for game creation expands exponentially. Whether you’re aiming to build immersive 3D worlds or engaging 2D platforms, a profound grasp of the Mesh class unlocks a myriad of opportunities. Embark on this adventure and learn to sculpt the digital clay of your game’s universe to your will.

What is a Mesh?

A Mesh is a fundamental piece in the 3D graphics puzzle. In the world of Godot, a Mesh is a type of Resource that represents geometric shapes using vertices (points in 3D space), edges (lines connecting vertices), and faces (flat surfaces bound by edges). These elements come together to form the visible surfaces of everything you see in a 3D environment.

What is it for?

Meshes are the building blocks of 3D models in Godot. They are used to create characters, objects, terrain, and any other visual elements within your game. With the ability to hold multiple surfaces, each potentially utilizing a different material or texture, meshes are versatile tools for game developers to represent complex geometry efficiently.

Why Should I Learn It?

Understanding how the Mesh class works is critical for anyone interested in 3D game development. It allows you to:

  • Create optimized game assets with multiple materials.
  • Manipulate geometries programmatically for dynamic effects.
  • Integrate advanced graphical features such as collision detection and physics simulations.

By learning about meshes, you gain the ability to control and enhance the graphical fidelity of your game, ensuring your creative vision is not limited by technical constraints.

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Creating a Basic Mesh

To begin with, let’s create a simple mesh in Godot. We’ll start with a QuadMesh which is a simple rectangle. This mesh will be a flat surface that we can display onscreen.

var mesh_instance = MeshInstance.new()
var quad_mesh = QuadMesh.new()
quad_mesh.size = Vector2(2, 2)
mesh_instance.mesh = quad_mesh
add_child(mesh_instance)

This script creates a new MeshInstance, sets up a QuadMesh, defines its size, attaches the mesh to the MeshInstance, and finally adds it to the scene tree.

Material Assignment

Now, let’s apply a material to the mesh to give it some color. In Godot, the SpatialMaterial is often used to define how 3D surfaces appear.

var material = SpatialMaterial.new()
material.albedo_color = Color(1, 0, 0) # Red color
quad_mesh.material = material

In this example, we create a SpatialMaterial, set its albedo color to red, and apply it to the quad mesh.

Manipulating Vertices Programmatically

Beyond static shapes, you can manipulate vertices to dynamically change the mesh’s form. Below we’ll adjust the vertices of an ArrayMesh to create a simple triangle:

var array_mesh = ArrayMesh.new()
var vertices = PoolVector3Array([
    Vector3(0, 1, 0), # Top vertex
    Vector3(-1, -1, 0), # Bottom left vertex
    Vector3(1, -1, 0) # Bottom right vertex
])

var arr_mesh_arrays = []
arr_mesh_arrays.resize(ArrayMesh.ARRAY_MAX)
arr_mesh_arrays[ArrayMesh.ARRAY_VERTEX] = vertices

array_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr_mesh_arrays)
mesh_instance.mesh = array_mesh

This code snippet dynamically builds a triangle by specifying its three vertices and adding them to the ArrayMesh.

Adding Texture to a Mesh

A texture can bring a mesh to life with detail. Let’s add a texture to our existing QuadMesh:

var texture = ImageTexture.new()
texture.create_from_image(load("res://path_to_your_image.png"))
material.albedo_texture = texture
quad_mesh.material = material

This sets up a texture from an image file and applies it to the SpatialMaterial, which is then used by the QuadMesh.

3D Transformations

Positioning, rotating, and scaling the mesh are common 3D transformations. The following example demonstrates how to rotate our mesh instance around the Y-axis:

mesh_instance.rotate_y(deg2rad(45)) # Rotate 45 degrees

This rotates the mesh instance by 45 degrees. The deg2rad() function converts degrees to radians, which is the unit Godot uses for rotation.

Using Surfaces in ArrayMesh

ArrayMesh allows for intricate control over the different surfaces of a mesh. Here’s how you can create an ArrayMesh with two surfaces, each with a different material:

// Surface 1
var surface_1_material = SpatialMaterial.new()
surface_1_material.albedo_color = Color(0, 1, 0) # Green color
var vertices_1 = PoolVector3Array([
    ...
])
var arrays_1 = []
arrays_1.resize(ArrayMesh.ARRAY_MAX)
arrays_1[ArrayMesh.ARRAY_VERTEX] = vertices_1
array_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays_1, [], surface_1_material)

// Surface 2
var surface_2_material = SpatialMaterial.new()
surface_2_material.albedo_color = Color(0, 0, 1) # Blue color
var vertices_2 = PoolVector3Array([
    ...
])
var arrays_2 = []
arrays_2.resize(ArrayMesh.ARRAY_MAX)
arrays_2[ArrayMesh.ARRAY_VERTEX] = vertices_2
array_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays_2, [], surface_2_material)

mesh_instance.mesh = array_mesh

In this example, we have created two sets of vertices, arranged them into separate array structures, and assigned a different material to each surface. The ArrayMesh now has two surfaces with unique properties.

Godot offers a multitude of ways to fine-tune your game visuals. Diving deeper into the Mesh class lets you explore advanced techniques, such as morphing shapes and crafting multipurpose mesh instances. These examples provide a window into the possibilities at your fingertips.

Mesh Morphing

Morphing, also known as blend shapes, allows you to interpolate between different meshes. This is useful for animations such as facial expressions or smoothly transforming objects:

var blend_shape_mesh = ArrayMesh.new()
blend_shape_mesh.add_blend_shape("morph_1")
blend_shape_mesh.set_blend_shape_mode(Mesh.BLEND_SHAPE_MODE_NORMALIZED)

var basis_vertices = PoolVector3Array([
    Vector3(0, 0, 0),
    Vector3(1, 0, 0),
    Vector3(0, 1, 0)
])

var morphed_vertices = PoolVector3Array([
    Vector3(0, 0.5, 0.5),
    Vector3(1, 0.5, 0.5),
    Vector3(0, 1, 0)
])

var arrays_basis = []
arrays_basis.resize(ArrayMesh.ARRAY_MAX)
arrays_basis[ArrayMesh.ARRAY_VERTEX] = basis_vertices
blend_shape_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays_basis)

var arrays_morph = []
arrays_morph.resize(ArrayMesh.ARRAY_MAX)
arrays_morph[ArrayMesh.ARRAY_VERTEX] = morphed_vertices
blend_shape_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays_morph)

blend_shape_mesh.set_blend_shape_array(0, arrays_morph)
mesh_instance.mesh = blend_shape_mesh

Here, we created a mesh with a blend shape, added two surfaces for the base and the morphed state, and then used set_blend_shape_array() to define the morphing effect.

To animate between the base shape and the morphed shape, we can adjust the blend amount:

mesh_instance.set("blend_shapes/morph_1", 0.5) # Sets a 50% blend

This will result in a mesh that has morphed halfway between the base and morphed vertices.

Manipulating MeshInstance

Manipulating a MeshInstance directly can provide a versatile way to adjust individual attributes. Here’s how you might scale a mesh at runtime:

mesh_instance.scale = Vector3(2, 2, 2) # Doubles the size of the mesh

This line scales the MeshInstance to twice its original size on all axes.

To move a MeshInstance, we use the translate() method:

mesh_instance.translate(Vector3(5, 0, 0)) # Moves the mesh 5 units to the right

The mesh is now moved 5 units along the X-axis.

Creating Convex Collision Shapes

Collision shapes are essential for physics interactions. Convex collision shapes approximate the mesh shape for physics calculations. Here’s how to create one from a mesh:

var shape = ConvexPolygonShape.new()
var collision_mesh = mesh_instance.mesh
shape.create_from_points(collision_mesh.surface_get_arrays(0)[ArrayMesh.ARRAY_VERTEX])
var shape_owner = get_world().create_shape_owner(self)
add_shape_owner(shape_owner)
shape_owner_add_shape(shape_owner, shape)

Here, you use the surface_get_arrays() method to retrieve vertex data from the mesh, creating a ConvexPolygonShape that can then be used for collision detection.

Utilizing MeshDataTool

For even more control, Godot’s MeshDataTool provides a way to inspect and modify mesh data at the vertex level. Below is an example of how to flip all the vertices along the X-axis:

var mesh_data_tool = MeshDataTool.new()
var mesh_data_mesh = mesh_instance.mesh
mesh_data_tool.create_from_surface(mesh_data_mesh, 0)

for i in range(mesh_data_tool.get_vertex_count()):
    var vertex = mesh_data_tool.get_vertex(i)
    mesh_data_tool.set_vertex(i, Vector3(-vertex.x, vertex.y, vertex.z))

mesh_instance.mesh = mesh_data_tool.commit_to_surface(mesh_data_mesh)

By iterating over all vertices, we’re able to invert their X value, effectively mirroring the mesh along the YZ-plane.

Leveraging the Mesh class and its related tools in Godot is essential for creating visually stunning and interactive environments. Whether it’s through direct manipulation, blend shapes, or the MeshDataTool, the ability to mold meshes is a powerful skill in your game development repertoire. Continue experimenting with these examples as a foundation, and explore the creative potential of Godot’s Mesh class in your own projects.

As we further explore the realm of the Mesh class in Godot, let’s delve into more complex operations. These advanced techniques can elevate your game by adding a layer of dynamism and detail to your 3D models.

Let’s start with subdividing a mesh to increase its vertex count, which is a common technique to increase detail:

var mesh_data_tool = MeshDataTool.new()
mesh_data_tool.create_from_surface(mesh_instance.mesh, 0)

# Subdivide all faces
mesh_data_tool.subdivide()

mesh_instance.mesh = mesh_data_tool.commit_to_surface(mesh_instance.mesh)

This snippet uses the subdivide() method to add vertices and faces to the mesh, resulting in a higher-poly mesh.

Creating a procedural mesh at runtime can add a unique aspect to your game. Below, we generate a simple plane:

var procedural_mesh = ArrayMesh.new()
var verts = PoolVector3Array()
var uvs = PoolVector2Array()

for i in range(10):
    for j in range(10):
        verts.push_back(Vector3(i, 0, j))
        uvs.push_back(Vector2(i/10.0, j/10.0))

var arrays = []
arrays.resize(ArrayMesh.ARRAY_MAX)
arrays[ArrayMesh.ARRAY_VERTEX] = verts
arrays[ArrayMesh.ARRAY_TEX_UV] = uvs

procedural_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
mesh_instance.mesh = procedural_mesh

In this example, we populate the vertex and UV arrays and then create the surface from these arrays, forming a procedural plane.

Godot also allows us to change the vertex colors, which can add a shading effect or be used to change the overall appearance of a mesh dynamically. Here’s how to alter vertex colors:

var colors = PoolColorArray()
for i in range(mesh_data_tool.get_vertex_count()):
    colors.push_back(Color(0.5, 1.0, 0.5)) # A greenish color

arrays[ArrayMesh.ARRAY_COLOR] = colors
procedural_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
mesh_instance.mesh = procedural_mesh

This will set a consistent greenish tint to every vertex of our procedural plane mesh.

Godot’s mesh library also allows for complex operations such as generating a normal map for dynamic lighting effects. Here’s a basic example of how to generate a normal map procedurally:

var normal_map = Image.new()
normal_map.create(256, 256, false, Image.FORMAT_RGBAF)
normal_map.lock()

for x in range(normal_map.get_width()):
    for y in range(normal_map.get_height()):
        var normal = Vector3(0.5, 1.0, 0.5) # Upwards facing normal
        # Encoding the normal vector into RGB
        var color = Color(normal.x * 0.5 + 0.5, normal.y * 0.5 + 0.5, normal.z * 0.5 + 0.5)
        normal_map.set_pixel(x, y, color)

normal_map.unlock()
var normal_map_texture = ImageTexture.new()
normal_map_texture.create_from_image(normal_map)
material.normal_texture = normal_map_texture
quad_mesh.material = material

This code generates an image representing a uniformly upwards-facing normal map, encodes the normal vectors into RGB colors, and then applies it to the material as a texture.

Finally, let’s look into removing vertices from a mesh. This can help optimize a mesh or create unique effects:

mesh_data_tool.create_from_surface(mesh_instance.mesh, 0)

# Remove the first 10 vertices
for i in range(10):
    mesh_data_tool.remove_vertex(0)

mesh_instance.mesh = mesh_data_tool.commit_to_surface(mesh_instance.mesh)

This code uses remove_vertex() to eliminate the first 10 vertices from the mesh.

These techniques showcase the breadth of Godot’s capabilities when it comes to manipulating the Mesh class. From procedural generation to dynamic effects, mastering these skills can greatly enhance the visual quality and performance of your games. Keep experimenting with these tools to discover even more ways to bring your game worlds to life.

Continue Your Godot Game Development Journey

Congratulations on exploring the depths of the Mesh class in Godot! But the journey doesn’t have to end here. Every new technique you apply or concept you understand further equips you to bring your dream games to life. For those eager to continue growing their Godot and game development expertise, we invite you to check out our comprehensive Godot Game Development Mini-Degree.

Our Mini-Degree is tailored to walk you through the nuances of Godot 4, covering everything from using 2D and 3D assets, mastering GDScript, to implementing core gameplay mechanics. Suitable for both beginners and those who’ve surpassed the basics, our courses are designed to fit your schedule, accessible at any time, on any device. As you progress, you’ll complete real projects, face engaging challenges, and build a portfolio that shines.

For a broader range of topics and to dive into more specialized areas, browse our plethora of Godot courses. Every lesson is a step forward in your game development career, so keep learning, keep creating, and keep transforming your innovative ideas into interactive realities!

Conclusion

Mastering the Mesh class within Godot is akin to wielding a powerful brush on the canvas of game development. It’s a skill that opens doors to crafting intricate worlds and characters that players will immerse themselves in. Whether it’s through bending vertices to your creative will, bringing landscapes to life with procedural content, or infusing dynamism with interactive physics, your journey in mesh manipulation is bound only by your own imagination.

Remember, this is but a glimpse into the potential held within the Godot engine, and we’ve only scratched the surface. If your passion for game development is as insatiable as ours, we encourage you to explore our Godot Game Development Mini-Degree. Step into this gateway to expertise, and let us guide you through each twist and turn on your path to creating astounding digital experiences. Game creation is an art, and with Zenva, you’ll be painting masterpieces in no time.

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.