HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Voxel Islands - Dynamic mesh generation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
meshgenerationvoxeldynamicislands

Problem

While I can often understand the performance reasons behind using fixed-size arrays to store vertex, triangle and UV data, I've often found it annoying because it makes dynamically generating meshes somewhat difficult. In order to fix this, I've built a small helper class to make the process much easier. It currently only supports vertex, triangle and UV generation, but that's really all I need at the moment.

```
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

namespace VoxelIslands.Engine.Utilities
{
///
/// This class is simply a wrapper used to dynamically generate mesh data for
/// things like voxels and chunks. In the end, it will be converted to a normal
/// Unity3D mesh.
///
public class DynamicMesh
{
private List Vertices { get; set; }
private List Triangles { get; set; }
private List UVs { get; set; }
private List ColliderVertices { get; set; }
private List ColliderTriangles { get; set; }
private Vector3 MeshOffset { get; set; }
private bool _GenerateColliderData { get; set; }

///
/// Constructor for the DynamicMesh class.
///
/// The offset of the mesh and it's vertices.
/// Whether or not to generate collider data.
public DynamicMesh(Vector3 meshOffset, bool generateColliderData = true)
{
this.Vertices = new List() { };
this.Triangles = new List() { };
this.UVs = new List() { };
this.ColliderVertices = new List() { };
this.ColliderTriangles = new List() { };
this.MeshOffset = meshOffset;
this._GenerateColliderData = generateColliderData;
}

///
/// This function creates a new Unity3D mesh from the collider data contained in the vertex,
/// and triangle data. The mesh returned by this function is intended to be used for collisions
/// only.
///

Solution

I don't see much refactoring there, mostly just a matter of taste.

There are a lot of thisis - you can do without them, most of the time they are only code bloat.

I prefer inversing the condition in the AddQuad method to reduce nesting and remove the last else

if(this.Vertices.Count < 4)
{
    throw...
}


One of the properies begins with an _ underscore, is there a reason for that?

As you don't expose any of them publicly I'd turn them to regular fields.

You don't need to use {} for creating empty lists this new List() { } is the same as new List(). You can also initialize them together with the declaration.

It might be a good idea to prefix boolean variables with is or can if it makes sense.

You don't need to always explitly specify the type. If you define a new variable inside a method etc. you can use the var keyword to not repeat yourself.

Example:

public class DynamicMesh
{
    private List _vertices = new List();
    private List _triangles = new List();
    private List _uvs = new List();
    private List _colliderVertices = new List();
    private List _colliderTriangles = new List();
    private Vector3 _meshOffset;
    private bool _canGnerateColliderData;

    /// 
    /// Constructor for the DynamicMesh class.
    /// 
    /// The offset of the mesh and it's vertices.
    /// Whether or not to generate collider data.
    public DynamicMesh(Vector3 meshOffset, bool canGenerateColliderData = true)
    {
        _meshOffset = meshOffset;
        _canGnerateColliderData = canGenerateColliderData;
    }

    /// 
    /// This function creates a new Unity3D mesh from the collider data contained in the vertex,
    /// and triangle data. The mesh returned by this function is intended to be used for collisions
    /// only.
    /// 
    /// A newly created collider mesh.
    public Mesh CreateColliderMesh()
    {
        // using object initializer
        var colliderMesh = new Mesh
        {
            vertices = _colliderVertices.ToArray(),
            triangles = _colliderTriangles.ToArray(),
        };
        colliderMesh.RecalculateNormals();
        return colliderMesh;
    }

    /// 
    /// This function creates a new Unity3D mesh from the data contained in the vertex, triangle
    /// and UV data. The mesh returned by this function is intended to be used for rendering only.
    /// 
    /// A newly created rendering mesh.
    public Mesh CreateRenderingMesh()
    {
        var renderingMesh = new Mesh
        {
            vertices = _vertices.ToArray(),
            triangles = _triangles.ToArray(),
            uv = _uvs.ToArray(),
        };
        renderingMesh.RecalculateNormals();
        return renderingMesh;
    }

    /// 
    /// Add a new UV coordinate to the UV data.
    /// 
    /// 
    public void AddUVs(Vector2[] uvCoordinates)
    {
        _uvs.AddRange(uvCoordinates);
    }

    /// 
    /// Add two trianges to form a quad. This is based of the most recent vertex
    /// data and will not work if your vertex data is empty. Collision data is generated
    /// only if collision mesh generation is enabled. There is however an optional 
    /// parameter that allows for you to enable or disable collider generation on the fly.
    /// 
    /// Whether or not to generate collider data.
    public void AddQuad(bool canGenerateColliderData = true)
    {
        if (_vertices.Count 
    /// Add a vertex to the vertex data list. A collider vertex is generated only
    /// if collision mesh generation is enabled. There is however an optional 
    /// parameter that allows for you to enable or disable collider generation on the fly.
    /// 
    /// The position of the vertex.
    /// The offset of the vertex.
    /// Whether or not to generate collider data.
    public void AddVertex(Vector3 vertexPosition, Vector3 vertexOffset, bool canGenerateColliderData = true)
    {
        // perform calculation only once, then add its result whereever needed
        var vertexWithOffset = (vertexPosition - _meshOffset) + vertexOffset;

        _vertices.Add(vertexWithOffset);

        if (_canGnerateColliderData && canGenerateColliderData)
        {
            _colliderVertices.Add(vertexWithOffset);
        }
    }
}

Code Snippets

if(this.Vertices.Count < 4)
{
    throw...
}
public class DynamicMesh
{
    private List<Vector3> _vertices = new List<Vector3>();
    private List<int> _triangles = new List<int>();
    private List<Vector2> _uvs = new List<Vector2>();
    private List<Vector3> _colliderVertices = new List<Vector3>();
    private List<int> _colliderTriangles = new List<int>();
    private Vector3 _meshOffset;
    private bool _canGnerateColliderData;


    /// <summary>
    /// Constructor for the DynamicMesh class.
    /// </summary>
    /// <param name="meshOffset">The offset of the mesh and it's vertices.</param>
    /// <param name="generateColliderData">Whether or not to generate collider data.</param>
    public DynamicMesh(Vector3 meshOffset, bool canGenerateColliderData = true)
    {
        _meshOffset = meshOffset;
        _canGnerateColliderData = canGenerateColliderData;
    }

    /// <summary>
    /// This function creates a new Unity3D mesh from the collider data contained in the vertex,
    /// and triangle data. The mesh returned by this function is intended to be used for collisions
    /// only.
    /// </summary>
    /// <returns>A newly created collider mesh.</returns>
    public Mesh CreateColliderMesh()
    {
        // using object initializer
        var colliderMesh = new Mesh
        {
            vertices = _colliderVertices.ToArray(),
            triangles = _colliderTriangles.ToArray(),
        };
        colliderMesh.RecalculateNormals();
        return colliderMesh;
    }

    /// <summary>
    /// This function creates a new Unity3D mesh from the data contained in the vertex, triangle
    /// and UV data. The mesh returned by this function is intended to be used for rendering only.
    /// </summary>
    /// <returns>A newly created rendering mesh.</returns>
    public Mesh CreateRenderingMesh()
    {
        var renderingMesh = new Mesh
        {
            vertices = _vertices.ToArray(),
            triangles = _triangles.ToArray(),
            uv = _uvs.ToArray(),
        };
        renderingMesh.RecalculateNormals();
        return renderingMesh;
    }

    /// <summary>
    /// Add a new UV coordinate to the UV data.
    /// </summary>
    /// <param name="uvCoordinate"></param>
    public void AddUVs(Vector2[] uvCoordinates)
    {
        _uvs.AddRange(uvCoordinates);
    }

    /// <summary>
    /// Add two trianges to form a quad. This is based of the most recent vertex
    /// data and will not work if your vertex data is empty. Collision data is generated
    /// only if collision mesh generation is enabled. There is however an optional 
    /// parameter that allows for you to enable or disable collider generation on the fly.
    /// </summary>
    /// <param name="generateColliderData">Whether or not to generate collider data.</param>
    public void AddQuad(bool canGenerateColliderData = true)
    {
        if (_vertices.Count < 4)
        {
            throw new System.Exception("Rendering vertex data must contain enough vertices to generate a quad.");
      

Context

StackExchange Code Review Q#128634, answer score: 4

Revisions (0)

No revisions yet.