- Home /
Incorrect cube subdivision mesh
Hello I am trying from giving a cube, subdivide each face of the cube in four more. The problem is that it isn't subdiving it correctly. I have been looking at the code and debugging for hours and I can't find the solution. Now I am currently new in Unity and C#. I had also tried reseting the triangles to empty at the start of the subidivision mesh. But also it didn't work.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class esferaRota : MonoBehaviour
{
// Start is called before the first frame update
Mesh mesh;
List<Vector3> vertices = new List<Vector3>();
List<int> triangulos = new List<int>();
public int numeroSubdivisiones = 1;
static Vector3[] faceCubes = {
new Vector3(1, 1, 1), //0
new Vector3(-1, 1, 1), //1
new Vector3(-1, -1, 1), //2
new Vector3(1, -1, 1), //3
new Vector3(-1, 1, -1), //4
new Vector3(1, 1, -1), //5
new Vector3(1, -1, -1), //6
new Vector3(-1, -1, -1) //7
};
static int[][] facetriangulos = {
new int[]{0,1,2,3}, // Cara trasera
new int[]{5,0,3,6}, // Cara derecha
new int[]{4,5,6,7}, // Cara frontal
new int[]{1,4,7,2}, // Cara izquierda
new int[]{5,4,1,0}, // Cara arriba
new int[]{3,2,7,6}, // Cara abajo
};
void make_face(int dir)
{
vertices.AddRange(faceVertices(dir));
int vCount = vertices.Count;
triangulos.Add(vCount - 4);
triangulos.Add(vCount - 4 + 1);
triangulos.Add(vCount - 4 + 2);
triangulos.Add(vCount - 4);
triangulos.Add(vCount - 4 + 2);
triangulos.Add(vCount - 4 + 3);
}
void make_cube()
{
vertices = new List<Vector3>();
triangulos = new List<int>();
for (int i = 0; i < 6; i++)
{
make_face(i);
}
}
// Funcion que crea una cara de vertices
public static Vector3[] faceVertices(int dir)
{
Vector3[] fv = new Vector3[4];
for (int i = 0; i < fv.Length; i++)
{
// La direccion y la posicion del array
fv[i] = faceCubes[facetriangulos[dir][i]];
}
return fv;
}
// Modifica la lista de vertices y la actualiza
// De forma que un cuadrado da lugar a otros cuatro cuadrados
// T --> Top, D --> Down, L --> Left, R --> Right
// v --> Vertice
List<Vector3> subdividir_cuadrado(Vector3 vTL, Vector3 vTR, Vector3 vDR, Vector3 vDL)
{
List<Vector3> lista = new List<Vector3>();
Vector3 vT = Vector3.Lerp(vTR, vTL, 0.5f);
Vector3 vD = Vector3.Lerp(vDR, vDL, 0.5f);
Vector3 vR = Vector3.Lerp(vTR, vDR, 0.5f);
Vector3 vL = Vector3.Lerp(vTL, vDL, 0.5f);
Vector3 vCenter = Vector3.Lerp(vTL, vDR, 0.5f);
Debug.Log("------------------------");
Debug.Log(vTL + " " + vTR + "-->" + vT);
Debug.Log(vDR + " " + vDL + "-->" + vD);
Debug.Log(vTR + " " + vDR + "-->" + vR);
Debug.Log(vTL + " " + vDL + "-->" + vL);
Debug.Log(vTL + " " + vDR + "-->" + vCenter);
int size = vertices.Count;
lista.AddRange(new List<Vector3> { vT, vD, vL, vR, vTL, vTR, vDL, vDR, vCenter });
int tT = size + 0;
int tD = size + 1;
int tL = size + 2;
int tR = size + 3;
int tTL = size + 4;
int tTR = size + 5;
int tDL = size + 6;
int tDR = size + 7;
int tCenter = size + 8;
triangulos.AddRange(new List<int> { tL, tTL, tT });
triangulos.AddRange(new List<int> { tL, tT, tCenter });
triangulos.AddRange(new List<int> { tCenter, tT, tTR });
triangulos.AddRange(new List<int> { tCenter, tTR, tR });
triangulos.AddRange(new List<int> { tDL, tL, tCenter });
triangulos.AddRange(new List<int> { tDL, tCenter, tD });
triangulos.AddRange(new List<int> { tD, tCenter, tR });
triangulos.AddRange(new List<int> { tD, tR, tDR });
return lista;
}
void print_vertices()
{
for (int i = 0; i < vertices.Count; i += 4)
{
Debug.Log("CARA:" + i);
Debug.Log("--------------");
Debug.Log("V1: " + vertices[i]); // TR
Debug.Log("V2: " + vertices[i + 1]); // TL
Debug.Log("V3: " + vertices[i + 2]); // DL
Debug.Log("V4: " + vertices[i + 3]); // DR
}
}
void sub_cubo()
{
List<Vector3> lista = new List<Vector3>();
//print_vertices();
int n_vertices = vertices.Count;
for (int j = 0; j < numeroSubdivisiones; j++)
{
for (int i = 0; i < n_vertices; i += 4)
{
/*
Debug.Log("A----------A");
Debug.Log("V1: " + vertices[i]); // TR
Debug.Log("V2: " + vertices[i + 1]); // TL
Debug.Log("V3: " + vertices[i + 2]); // DL
Debug.Log("V4: " + vertices[i + 3]); // DR
*/
lista.AddRange(subdividir_cuadrado(vertices[i], vertices[i + 1], vertices[i + 2], vertices[i + 3]));
/*x = 0f;
y = 0f;
z = 0f;
for(int p = i; p < (i+4); p++){
Debug.Log("X:"+vertices[p]);
if(vertices[p].x != 0f)
x = vertices[p].x/(p+1);
if(vertices[p].y != 0f)
y = vertices[p].y/(p+1);
if(vertices[p].z != 0f)
z = vertices[p].z/(p+1);
vertices[p] = new Vector3(x,y,z);
Debug.Log("Z:"+vertices[p]);
}
*/
}
}
vertices = lista;
}
void Awake()
{
mesh = GetComponent<MeshFilter>().mesh;
}
void Start()
{
make_cube();
sub_cubo();
update_mesh();
}
// Update is called once per frame
void update_mesh()
{
mesh.Clear();
mesh.vertices = vertices.ToArray();
mesh.triangles = triangulos.ToArray();
mesh.RecalculateNormals();
}
}
The result of the code above is the next:
Answer by Bunny83 · Aug 17, 2021 at 11:49 PM
You have a total mess when it comes to your lists and you actually lost track which lists holds what. Inside your "subdividir_cuadrado" method you assume that the vertices list contains the currently accumulated vertices since you use the current count as basis for you indices. However that is not true. Your vertices list does not change when you call your "subdividir_cuadrado" several times. You actually accumulate your generated vertices in a local list inside your "sub_cubo" method. So your "subdividir_cuadrado" does not have any access to the current index. You have to pass that index through a parameter to that method.
Though your mixing of using member variables of your class and partially returing other things from the method is a total mess. This can be simplified by either use one list for the vertices and one list for the triangles that are both member variables and your method(s) just push the newly generated triangles into those lists, or the alternative is that you make the methods pure methods with no side effects (i.e. make them static).
ps: I've written a general purpose subdivision routine some time ago that is keeping shared edges / shared vertices. Though note that when this routine was written, Unity did not have support for 32 bit index buffers. The current code only works with 16 bit index buffers. Though you have to explicitly change the index format of your mesh to 32 bit in order to use 32 bits. The code can be adjusted to support 32 bit indices by using an ulong instead of an uint in the dictionary and also adjusting the bit-shifting from 16 to 32 bit. On the wiki there's a more complete solution for a 4 and 9 subdivision and any combination of those. So one triangle becomes either 4 triangles or 9 triangles. So an edge is either cut in half or cut in 3 parts. This solution works with any mesh and preserves shared edges where possible.
Your answer
Follow this Question
Related Questions
Adjusting strange Vector3.Normalize behaviour 2 Answers
How to set mesh normals per face? 2 Answers
highlight a portion of a mesh in runtime 1 Answer
Highmap on a cube. 0 Answers
Custom Mesh UV Problem 1 Answer