- Home /
How could I create those two meshes by creating procedural quads
I need to create 2 meshes procedurally and I don't know very well what order to give the vertices to show them correctly, is there any app/utility to help me establish those points?
Images:
Sapling:
I need to cross the two quads, but they are parallel. I need to show this:
Button:
I need to scale the cube correctly in order to show this:
Doing this on paper is complicated, so I ask for some utility to help me mark the positions of the vertices and the names of the faces to take care of the references I need to use.
This is my code:
MeshData.cs
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityCraft.Voxel3D
{
[Serializable]
public class MeshData
{
[SerializeField]
protected List<Vector3> vertices = new List<Vector3>();
[SerializeField]
protected List<List<int>> triangles = new List<List<int>>();
[SerializeField]
protected List<Vector2> uv = new List<Vector2>();
public virtual int SubMeshCount
{
get => triangles.Count;
set
{
if (value > triangles.Count)
{
int difference = value - triangles.Count;
for (int i = 0; i < difference; i++)
{
triangles.Add(new List<int>());
}
}
else if (triangles.Count > value)
{
int difference = triangles.Count - value;
for (int i = 0; i < difference; i++)
{
triangles.RemoveAt(triangles.Count - i);
}
}
}
}
public virtual List<Vector3> Vertices => vertices;
public virtual List<List<int>> Triangles => triangles;
public virtual List<Vector2> UV => uv;
public MeshData() : this(1)
{
}
public MeshData(int subMeshCount)
{
SubMeshCount = subMeshCount;
}
public virtual void AddVertex(Vector3 vertex)
{
vertices.Add(vertex);
}
public virtual void AddTriangle(int subMesh, int triangle)
{
if (subMesh >= triangles.Count)
{
return;
}
triangles[subMesh].Add(triangle);
}
public virtual void AddUV(Vector2 uv)
{
this.uv.Add(uv);
}
public virtual void AddCube(Vector3 position, Rect[] uvs)
{
AddCube(position, 0, uvs);
}
public virtual void AddCube(Vector3 position, int subMesh, Rect[] uvs)
{
AddQuad(position, subMesh, VoxelDirection.Forward, uvs[0]);
AddQuad(position, subMesh, VoxelDirection.Back, uvs[1]);
AddQuad(position, subMesh, VoxelDirection.Right, uvs[2]);
AddQuad(position, subMesh, VoxelDirection.Left, uvs[3]);
AddQuad(position, subMesh, VoxelDirection.Up, uvs[4]);
AddQuad(position, subMesh, VoxelDirection.Down, uvs[5]);
}
public virtual void AddScaledCube(Vector3 position, int subMesh, Rect[] uvs, Vector3 scale)
{
AddQuad(position, subMesh, VoxelDirection.Forward, uvs[0], scale);
AddQuad(position, subMesh, VoxelDirection.Back, uvs[1], scale);
AddQuad(position, subMesh, VoxelDirection.Right, uvs[2], scale);
AddQuad(position, subMesh, VoxelDirection.Left, uvs[3], scale);
AddQuad(position, subMesh, VoxelDirection.Up, uvs[4], scale);
AddQuad(position, subMesh, VoxelDirection.Down, uvs[5], scale);
}
public virtual void AddScaledCube(Vector3 position, int subMesh, Rect[] uvs, Vector3[] scales)
{
AddQuad(position, subMesh, VoxelDirection.Forward, uvs[0], scales[0]);
AddQuad(position, subMesh, VoxelDirection.Back, uvs[1], scales[1]);
AddQuad(position, subMesh, VoxelDirection.Right, uvs[2], scales[2]);
AddQuad(position, subMesh, VoxelDirection.Left, uvs[3], scales[3]);
AddQuad(position, subMesh, VoxelDirection.Up, uvs[4], scales[4]);
AddQuad(position, subMesh, VoxelDirection.Down, uvs[5], scales[5]);
}
public virtual void AddCross(Vector3 position, int subMesh, params Rect[] uvs)
{
AddQuad(position, VoxelDirection.Diagonal1, uvs[0]);
AddQuad(position, VoxelDirection.Diagonal2, uvs[1]);
}
public virtual void AddQuad(Vector3 position, VoxelDirection direction, Rect uv)
{
AddQuad(position, 0, direction, uv);
}
public virtual void AddQuad(Vector3 position, int subMesh, VoxelDirection direction, Rect uv, Vector3 scale = default)
{
if (scale == default)
scale = Vector3.one;
switch (direction)
{
case VoxelDirection.Forward:
vertices.Add((position + Vector3.forward + Vector3.left) * scale.z);
vertices.Add((position + Vector3.forward) * scale.z);
vertices.Add((position + Vector3.forward + Vector3.left + Vector3.up) * scale.z);
vertices.Add((position + Vector3.forward + Vector3.up) * scale.z);
break;
case VoxelDirection.Back:
vertices.Add(position * scale.z);
vertices.Add((position + Vector3.left) * scale.x);
vertices.Add((position + Vector3.up) * scale.x);
vertices.Add((position + Vector3.left + Vector3.up) * scale.x);
break;
case VoxelDirection.Right:
vertices.Add((position + Vector3.forward) * scale.x);
vertices.Add(position * scale.x);
vertices.Add((position + Vector3.forward + Vector3.up) * scale.x);
vertices.Add((position + Vector3.up) * scale.x);
break;
case VoxelDirection.Left:
vertices.Add((position + Vector3.left) * scale.x);
vertices.Add((position + Vector3.left + Vector3.forward) * scale.x);
vertices.Add((position + Vector3.left + Vector3.up) * scale.x);
vertices.Add((position + Vector3.left + Vector3.forward + Vector3.up) * scale.x);
break;
case VoxelDirection.Up:
vertices.Add((position + Vector3.up) * scale.y);
vertices.Add((position + Vector3.up + Vector3.left) * scale.y);
vertices.Add((position + Vector3.up + Vector3.forward) * scale.y);
vertices.Add((position + Vector3.up + Vector3.forward + Vector3.left) * scale.y);
break;
case VoxelDirection.Down:
vertices.Add((position + Vector3.forward) * scale.y);
vertices.Add((position + Vector3.forward + Vector3.left) * scale.y);
vertices.Add(position * scale.y);
vertices.Add((position + Vector3.left) * scale.y);
break;
case VoxelDirection.Diagonal1:
vertices.Add(position);
vertices.Add(position + Vector3.up);
vertices.Add(position + Vector3.right + Vector3.forward);
vertices.Add(position + Vector3.one);
break;
case VoxelDirection.Diagonal2:
vertices.Add(position + Vector3.forward);
vertices.Add(position + Vector3.forward + Vector3.up);
vertices.Add(position + Vector3.left);
vertices.Add(position + Vector3.left + Vector3.up);
break;
}
triangles[subMesh].Add(vertices.Count - 4);
triangles[subMesh].Add(vertices.Count - 3);
triangles[subMesh].Add(vertices.Count - 2);
triangles[subMesh].Add(vertices.Count - 3);
triangles[subMesh].Add(vertices.Count - 1);
triangles[subMesh].Add(vertices.Count - 2);
this.uv.Add(new Vector2(uv.x + uv.width, uv.y));
this.uv.Add(new Vector2(uv.x, uv.y));
this.uv.Add(new Vector2(uv.x + uv.width, uv.y + uv.height));
this.uv.Add(new Vector2(uv.x, uv.y + uv.height));
}
public virtual Mesh BuildMesh(string name = "")
{
// Debug.Log($"Creating mesh {name}! (Reviewing stacktrace)");
Mesh mesh = new Mesh
{
subMeshCount = triangles.Count,
vertices = vertices.ToArray(),
name = name
};
for (int i = 0; i < triangles.Count; i++)
{
mesh.SetTriangles(triangles[i], i, true);
}
mesh.uv = uv.ToArray();
mesh.RecalculateBounds();
mesh.RecalculateNormals();
mesh.RecalculateTangents();
return mesh;
}
}
}
CustomRenderer.cs
using System.Collections;
using System.Collections.Generic;
using BayatGames.Frameworks.Voxel3D;
using UnityEngine;
namespace UnityCraft.Tests
{
public class CustomRenderers : MonoBehaviour
{
private MeshData saplingMeshData;
private MeshData buttonMeshData;
private MeshData levelMeshData;
private static Rect[] NullRects => new[]
{
Rect.zero,
Rect.zero,
Rect.zero,
Rect.zero,
Rect.zero,
Rect.zero
};
// Start is called before the first frame update
private void Start()
{
saplingMeshData = new MeshData();
buttonMeshData = new MeshData();
levelMeshData = new MeshData();
saplingMeshData.AddCross(Vector3.zero, 0, Rect.zero, Rect.zero);
buttonMeshData.AddScaledCube(Vector3.zero, 0, NullRects, new Vector3(.4f, .2f, .3f));
saplingMeshData.CreateGameObject("Sapling");
buttonMeshData.CreateGameObject("Button");
//levelMeshData.CreateGameObject("Level");
}
// Update is called once per frame
private void Update()
{
}
}
public static class F
{
public static GameObject CreateGameObject(this MeshData data, string name)
{
var mesh = data.BuildMesh(name);
var gameObject = new GameObject(name);
var meshFilter = gameObject.AddComponent<MeshFilter>();
meshFilter.mesh = mesh;
var meshRenderer = gameObject.AddComponent<MeshRenderer>();
return gameObject;
}
}
}
Answer by Bunny83 · Oct 29, 2019 at 10:36 AM
I'm not sure what you're asking here. If your voxel tools are lacking a feature you need frequently you have to create it. Anyways your screenshot is misleading as the two quads are already diagonal at an angle of 45° but you created both cases parallel. Specifically the case "Diagonal2" is wrong. It looks like that you defined each voxel origin as the corner with the lower coordinates. That means the block goes forward, up and right. However in case Diagonal2 you move left, out of the usual cube bounds.
It should be something like:
case VoxelDirection.Diagonal2:
vertices.Add(position + Vector3.forward);
vertices.Add(position + Vector3.forward + Vector3.up);
vertices.Add(position + Vector3.right);
vertices.Add(position + Vector3.right + Vector3.up);
break;
Note that as far as I can see you use a single-sided shader (which is ok). However for a cross plant to render properly you need to render both sides of both quads. The simplest solution is to add 4 quads (2 per case) where one is flipped around.
Back then I didn't dig too deep into the code of MC, however the meshing helper class that MC uses works directly with boxes and quads in a subdivision of 16. So actual local integer coordinates 0-15 are used to specify a certain location within a block. When defining a "box" mesh you could actually pass informations like left, right, top, bottom, front, back to specify where the box should be created. This is equal to pass the lower most and the upper most corner of the box and the box is axis aligned.
Your concept of passing a scale vector is very limited as you do not have an offset build into your logic. So whatever you try to create with "AddScaledCube" it will always have it's first corner at the lower most corner of the enclosing block.
ps: Please keep in $$anonymous$$d that taking the idea of an algorithm and creating your own is fine. Taking assets (textures, audio, models, ....) from other games is not allowed without having a license which allows this.
Thanks Bunny for your answer, it worked I will analyze your answer. And don't worry, I'm not "taking" or "coyping" textures, I'm just reading textures.
How could I create the 2 remaining quads in order to make it visible on all directions?
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Making a bubble level (not a game but work tool) 1 Answer
Problems Generate a Chunk blocks (Space Game Infinity) 0 Answers