Round Egg 5: Spheres!

2023-09-01

Pedro Burgos, Dominykas Jogela

# Switching to Bevy "full time"

Creating our own render loop was an interesting learning process. However at this point we realized how much effort it would take to work with it. For the purpose of the project, we decided to switch to Bevy's render loop. This in practice means discarding a lot of our previous code, but with the knowledge we now held and we felt it was time to move to a different endeavour.

From now onward the rendering code will be more similar to a traditional Bevy app. If you are not familiar with Bevy, we recommend reading through some of the official examples.

We even made a cube spin to demonstrate that the new code worked.

A spinning cube using purely Bevy
A spinning cube using purely Bevy

# Choosing the Sphere

As it is explained in Sebastian Lague's exceptional video, there are many different algorithms to create a sphere. For our case though, the focus is on achieving an even distribution of points, that we will later displace.

In a traditional UV Sphere, the point density is higher at the poles than at the equator. Another alternative is extruding a cube into a sphere, this gives us marginally better results, but not good enough.

UV Sphere
UV Sphere
Quad Sphere
Quad Sphere

The type of Sphere we ended up deciding on is an Icosphere, which is based on recursively subdividing an icosahedron into smaller triangles. While this is a bit more limited in the adjustment of the sphere's resolution, it provides an adequate distribution of points.

Icosphere
Icosphere

The images above are from this article by Daniel Sieger explains perfectly the difference between all aforementioned kinds of spheres.

# Implementing the Sphere

We can define our sphere as a simple struct with a resolution attribute, the algorithm for generating the points is commonly available so we will not detail it here further.

pub struct Sphere {
    resolution: u32,
}

However, the important part is that we need to implement Mesh for our sphere, so that Bevy can manipulate and display it.

impl From<Sphere> for Mesh {     
    fn from(s: Sphere) -> Self {
        let (positions, normals, indices) = generate_mesh(s.resolution);

        let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
        // The position of the vertex in the world
        mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions);
        // Vertex normals 
        mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
        // Vertex indices
        mesh.set_indices(Some(Indices::U32(indices)));

        mesh
    }
}

If everything is correct, we should have turned our cube into an icosphere!

Our procedurally generated icosphere
Our procedurally generated icosphere