Procedural maze remove old colliders - c#

I followed a tutorial on making a procedural generated maze in unity using C# that when you click the mouse button, it generates a new maze.
However, when I generate a new maze everything looks right but the MeshCollider for the old maze mesh is still in place, in addition to the new maze MeshCollider making numerous invisible walls.
How would I clear the old MeshColliders in my script, so that they are removed and only the newly generated mesh remains?
Initial maze image
Second maze image
Each maze, after the first, has the old MeshColliders represented by the green outline and it looks like it is just making new MeshColliders and not replacing the old one with a new one. I thought I could fix this by setting the mesh and MeshCollider to null, then new mesh at the beginning of each new maze generation, but it does nothing:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Mesh_Generator : MonoBehaviour {
public SquareGrid squareGrid;
public MeshFilter walls;
public MeshFilter cave;
public bool is2D;
List<Vector3> vertices;
List<int> triangles;
Dictionary<int,List<Triangle>> triangleDictionary = new Dictionary<int, List<Triangle>> ();
List<List<int>> outlines = new List<List<int>> ();
HashSet<int> checkedVerticies = new HashSet<int> ();
public void GenerateMesh(int[,] map, float squareSize){
triangleDictionary.Clear ();
outlines.Clear ();
checkedVerticies.Clear ();
squareGrid = new SquareGrid (map, squareSize);
vertices = new List<Vector3> ();
triangles = new List<int> ();
for (int x = 0; x < squareGrid.squares.GetLength (0); x++) {
for (int y = 0; y < squareGrid.squares.GetLength (1); y++) {
TriangulateSquare (squareGrid.squares [x, y]);
}
}
Mesh mesh = null;
mesh = new Mesh ();
cave.mesh = mesh;
mesh.vertices = vertices.ToArray ();
mesh.triangles = triangles.ToArray ();
mesh.RecalculateNormals ();
if (!is2D) {
CreateWallMesh ();
}
}
void CreateWallMesh(){
CalculateMeshOutLines ();
List<Vector3> wallVerticies = new List<Vector3> ();
List<int> wallTriangles = new List<int> ();
Mesh wallMesh = new Mesh ();
float wallHeight = 5;
foreach (List<int> outline in outlines){
for (int i = 0; i < outline.Count -1; i ++){
int startIndex = wallVerticies.Count;
wallVerticies.Add (vertices [outline [i]]); // left vertex
wallVerticies.Add (vertices [outline [i+1]]); // right vertex
wallVerticies.Add (vertices [outline [i]] - Vector3.up * wallHeight); // bottom left vertex
wallVerticies.Add (vertices [outline [i+1]] - Vector3.up * wallHeight); // bottom right vertex
wallTriangles.Add (startIndex + 0); //triangle 1
wallTriangles.Add (startIndex + 2);
wallTriangles.Add (startIndex + 3);
wallTriangles.Add (startIndex + 3); //triangle 2
wallTriangles.Add (startIndex + 1);
wallTriangles.Add (startIndex + 0);
}
}
wallMesh.vertices = wallVerticies.ToArray ();
wallMesh.triangles = wallTriangles.ToArray ();
walls.mesh = wallMesh;
MeshCollider wallCollider = walls.gameObject.AddComponent<MeshCollider> ();
wallCollider = null;
wallCollider = new MeshCollider ();
wallCollider.sharedMesh = wallMesh;
}

From here, you should call Mesh.Clear "before rebuilding triangles array."
mesh = new Mesh ();
cave.mesh.Clear();
cave.mesh = mesh;

Related

Normal issues in Unity

We are trying, with a friend, to modelise a tree on unity. To do so, we want to modelise a tree trunk. We are doing it with the following code :
`
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class Frustum : MonoBehaviour
{
/*====== PUBLIC ======*/
public float height = 1;
public float top_radius = 0.9F;
public float base_radius = 1F;
public int circle_subdivisions = 30;
/*====== PRIVATE ======*/
private Mesh mesh;
private Vector3[] vao;
private int[] ibo;
// Start is called before the first frame update
void Start()
{
mesh = new Mesh();
mesh.name = "Cone";
this.GetComponent<MeshFilter>().mesh = mesh;
draw();
}
// OnValidate is called at each public input change
private void OnValidate() {
draw();
}
private void draw() {
ComputeFrustumVao();
ComputeFrustumIbo();
mesh.Clear();
mesh.vertices = vao;
mesh.triangles = ibo;
mesh.RecalculateBounds();
mesh.RecalculateTangents();
mesh.RecalculateNormals();
// mesh.Optimize();
}
private void ComputeFrustumVao()
{
// COMPUTE BASE VERTICES
List<Vector3> vertices = ComputeCircleVertices(transform.position, base_radius, circle_subdivisions);
// ADD TOP VERTICES
Vector3 top_origin = transform.position + new Vector3(0, height, 0);
vertices.AddRange(ComputeCircleVertices(top_origin, top_radius, circle_subdivisions));
vao = vertices.ToArray();
}
private List<Vector3> ComputeCircleVertices(Vector3 origin, float radius, int nb_subdivisions) {
List<Vector3> vao = new List<Vector3>();
float step_angle = (2*Mathf.PI)/nb_subdivisions;
for(int i = 0; i < nb_subdivisions; ++i){
float current_angle = step_angle * i;
Vector3 translate_vector = new Vector3(
Mathf.Cos(current_angle) * radius, // x coordinate
0, // y coordinate
Mathf.Sin(current_angle) * radius // z coordinate
);
Vector3 new_vertex = origin + translate_vector;
vao.Add(new_vertex);
}
return vao;
}
private void ComputeFrustumIbo() {
List<int> indices = new List<int>();
int nb_vertices = vao.Length;
int nb_vertices_per_circle = nb_vertices/2;
int nb_triangles = nb_vertices_per_circle - 2;
// DRAW BASE
for(int i = 0; i < nb_triangles; ++i){
indices.Add(0);
indices.Add(i + 1);
indices.Add(i + 2);
}
// DRAW TOP
for(int i = nb_vertices_per_circle; i < nb_vertices_per_circle + nb_triangles; ++i){
indices.Add(nb_vertices_per_circle);
indices.Add(i + 2);
indices.Add(i + 1);
}
// DRAW SIDES
for(int i = 0; i < nb_vertices_per_circle; ++i){
int next_index = (i + 1) % nb_vertices_per_circle;
indices.Add(i); // BOTTOM LEFT
indices.Add( nb_vertices_per_circle + next_index); // TOP RIGHT
indices.Add(next_index); // BOTTOM RIGHT
indices.Add(i); // BOTTOM LEFT
indices.Add(i + nb_vertices_per_circle); // TOP LEFT
indices.Add(nb_vertices_per_circle + next_index); // TOP RIGHT
}
ibo = indices.ToArray();
}
void OnDrawGizmosSelected() //Draw the markers, if the object is selected
{
Gizmos.color = Color.red;
for (int i=0; i< mesh.vertices.Length; i++){
Gizmos.color= new Color(((float)i)/mesh.vertices.Length,0, 0);
Vector3 worldPos = transform.TransformPoint(mesh.vertices[i]);
Gizmos.DrawCube(worldPos, Vector3.one * 0.1f);
}
}
}
`
With this code we can create a 3D shape like a cube or a cylinder but when we create our top and our base ( in DRAW TOP and DRAW BASE) it makes the normal looks weird and I dont understand why. Can you help me to understand it please ?
our Normal problem
We know that ussually people create their models in 3D software like blender but we really need to do it in unity for our project.
I've seen that if my normals are pointing to the top the face are too illuminated but when they are facing down it's too shady. To create our base and top shape, we have followed this tutorial

Remove hidden vertices and triangles of cube terrain

i am new here. I was studing procedural terrain with meshes. And i started a make a procedural terrain like Minecraft. And i don't know how i can remove the hidden vertices and triangles in the hidden blocks.
The hidden vertices and triangles
My code:
Voxel.cs:
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshCollider))]
[RequireComponent(typeof(MeshRenderer))]
public class Voxel : MonoBehaviour {
public Vector3[] vertices;
public int[] triangles;
public Vector3 pos;
public GameObject chunk;
Mesh mesh;
public bool blockSolid;
public Voxel(Vector3 position, GameObject obj)
{
pos = position;
chunk = obj;
}
void Start ()
{
mesh = new Mesh();
//Cube(0,0,0);
}
public void Cube(int x, int y, int z)
{
GameObject cube = new GameObject("Cubo");
cube.AddComponent(typeof(MeshFilter));
cube.AddComponent(typeof(MeshCollider));
cube.AddComponent(typeof(MeshRenderer));
cube.transform.parent = chunk.transform;
mesh = cube.GetComponent<MeshFilter>().mesh;
//cube.transform.position = pos;
vertices = new Vector3[]
{
new Vector3(x,y,z), // 0
new Vector3(x,y+1,z), // 1
new Vector3(x+1,y+1,z), // 2
new Vector3(x+1,y,z), // 3
new Vector3(x+1,y,z+1), // 4
new Vector3(x+1,y+1,z+1), // 5
new Vector3(x,y+1,z+1), // 6
new Vector3(x,y,z+1) // 7
};
triangles = new int[]
{
0,1,2, 0,2,3, // Face frontal
3,2,5, 3,5,4, // Face direita
0,7,6, 0,6,1, // Face esquerda
7,4,5, 7,5,6, // Face traseira
1,6,5, 1,5,2, // Face superior
0,3,4, 0,4,7 // Face inferior
};
UpdateMesh();
}
void UpdateMesh()
{
mesh.Clear();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
}
Chunk.cs:
using System.Collections.Generic;
using UnityEngine;
public class Chunk : MonoBehaviour {
public int tx, ty, tz;
public Vector3 pos;
IEnumerator BuildChunk()
{
for (int x = 0; x < tx; x++)
{
for (int y = 0; y < ty; y++)
{
for (int z = 0; z < tz; z++)
{
pos = new Vector3(x,y,z);
Voxel block = new Voxel(pos, this.gameObject);
block.Cube(x,y,z);
yield return null;
}
}
}
}
void Start ()
{
StartCoroutine(BuildChunk());
}
}
I just need to remove the hidden vertices and triangles, but i don't know how i gonna make this.
The trick is to generate only the triangles that are visible to the player. So you shouldn't be generating cubes for every voxel, but a subset of the faces of a cube.
The way you go about this, is to check all 6 sides of each voxel. If a given side borders another voxel, then ignore that side and move on. If there is no voxel bordering the side, then add the corresponding cube face to that side. This will result in a monolithic mesh encompassing your entire terrain, or the terrain you loaded in.

How to create a mesh dynamically In unity

I have vertex that have a color value.
I'd like to make a mesh using vertex with the same color values.
This picture is an example.
I took pictures with my Android Phone, and I did image segmentation on the object
So I got a color value corresponding to the coordinate value.
I succeeded in just making textures. please check the image.
But I want a mesh object.
Below is making texture code.
var pixel = await this.segmentation.SegmentAsync(rotated, scaled.width, scaled.height);
// int pixel[][]; // image segmentation using tensorflow
Color transparentColor = new Color32(255, 255, 255, 0); // transparent
for (int y = 0; y < texture.height; y++)
{
for (int x = 0; x < texture.width; x++)
{
int class_output = pixel[y][x];
texture.SetPixel(x, y, pixel[y][x] == 0 ? transparentColor : colors[class_output]);
}
}
texture.Apply();
How can I make a mesh object?
1- Set a prefab with a MeshFilter and a MeshRenderer.
2- Variables inside the script that you will need to fill.
// This first list contains every vertex of the mesh that we are going to render
public List<Vector3> newVertices = new List<Vector3>();
// The triangles tell Unity how to build each section of the mesh joining
// the vertices
public List<int> newTriangles = new List<int>();
// The UV list is unimportant right now but it tells Unity how the texture is
// aligned on each polygon
public List<Vector2> newUV = new List<Vector2>();
// A mesh is made up of the vertices, triangles and UVs we are going to define,
// after we make them up we'll save them as this mesh
private Mesh mesh;
3- Initialize the mesh
void Start () {
mesh = GetComponent<MeshFilter> ().mesh;
float x = transform.position.x;
float y = transform.position.y;
float z = transform.position.z;
newVertices.Add( new Vector3 (x , y , z ));
newVertices.Add( new Vector3 (x + 1 , y , z ));
newVertices.Add( new Vector3 (x + 1 , y-1 , z ));
newVertices.Add( new Vector3 (x , y-1 , z ));
newTriangles.Add(0);
newTriangles.Add(1);
newTriangles.Add(3);
newTriangles.Add(1);
newTriangles.Add(2);
newTriangles.Add(3);
newUV.Add(new Vector2 (tUnit * tStone.x, tUnit * tStone.y + tUnit));
newUV.Add(new Vector2 (tUnit * tStone.x + tUnit, tUnit * tStone.y + tUnit));
newUV.Add(new Vector2 (tUnit * tStone.x + tUnit, tUnit * tStone.y));
newUV.Add(new Vector2 (tUnit * tStone.x, tUnit * tStone.y));
mesh.Clear ();
mesh.vertices = newVertices.ToArray();
mesh.triangles = newTriangles.ToArray();
mesh.uv = newUV.ToArray(); // add this line to the code here
mesh.Optimize ();
mesh.RecalculateNormals ();
}
This code will draw a square at the position of the prefab, if you keep adding vertices you can generate a more complex mesh.
The source of information is a tutorial to generate mensh for a terrain like minecrat, check the link for more information.
The answer which has been selected best is, in my opinion, faulty for four reasons. First, it is deprecated. Second, it is more complex than necessary. Third, it offers little explanation, and finally, it is mostly just a copy from someone else's blog post. For that reason, I offer a new suggestion. For more info, view the documentation here.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class meshmaker : MonoBehaviour {
Mesh mesh;
MeshFilter meshFilter;
Vector3[] newVertices;
int[] newTriangles;
// Use this for initialization
void Start () {
//First, we create an array of vector3's. Each vector3 will
//represent one vertex in our mesh. Our shape will be a half
//cube (probably the simplest 3D shape we can make.
newVertices = new Vector3[4];
newVertices [0] = new Vector3 (0, 0, 0);
newVertices [1] = new Vector3 (1, 0, 0);
newVertices [2] = new Vector3 (0, 1, 0);
newVertices [3] = new Vector3 (0, 0, 1);
//Next, we create an array of integers which will represent
//triangles. Triangles are built by taking integers in groups of
//three, with each integer representing a vertex from our array of
//vertices. Note that the integers are in a certain order. The order
//of integers determines the normal of the triangle. In this case,
//connecting 021 faces the triangle out, while 012 faces the
//triangle in.
newTriangles = new int[12];
newTriangles[0] = 0;
newTriangles[1] = 2;
newTriangles[2] = 1;
newTriangles[3] = 0;
newTriangles[4] = 1;
newTriangles[5] = 3;
newTriangles[6] = 0;
newTriangles[7] = 3;
newTriangles[8] = 2;
newTriangles[9] = 1;
newTriangles[10] = 2;
newTriangles[11] = 3;
//We instantiate our mesh object and attach it to our mesh filter
mesh = new Mesh ();
meshFilter = gameObject.GetComponent<MeshFilter> ();
meshFilter.mesh = mesh;
//We assign our vertices and triangles to the mesh.
mesh.vertices = newVertices;
mesh.triangles = newTriangles;
}
Ta da! Your very own half-cube.

Map the custom triangle to Camera’s View Angle

I have make a triangle through my code. see below:
void TriangleMaker()
{
MeshFilter mf = GetComponent<MeshFilter>();
Mesh mesh = new Mesh();
mf.mesh = mesh;
//vertices
const int verticeCount = 3;//how many vertices for triangle its 3
Vector3[] vertices = new Vector3[verticeCount]{
//bottom left.orgin of the gameobject,
new Vector3(0,0,0),
new Vector3(width,0,0),
new Vector3(width, height,0)
};
//triangles
int[] tri = new int[6];
tri[0] = 0; //go clock wise always to make triangle from your vertices
tri[1] = 1;
tri[2] = 2;
//normals
//show the direction of objects
Vector3[] normals = new Vector3[3];
normals[0] = -Vector3.up;
normals[1] = -Vector3.up;
normals[2] = -Vector3.up;
mesh.vertices = vertices;
mesh.triangles = tri;
mesh.normals = normals;
}
The script is attached to child game-object of my camera and its showing the triangle but i want to map exactly my triangle to Camera’s view angle.
Also tried GeometryUtility.CalculateFrustumPlanes as Niki answer suggested and the result is not according to expectation:
2: https://docs.unity3d.com/ScriptReference/GeometryUtility.CalculateFrustumPlanes.html
Well I just found it in Unity docs:
https://docs.unity3d.com/ScriptReference/GeometryUtility.CalculateFrustumPlanes.html
P.S: I was so surprised to find this in docs. I think you are the only person in the world who needs this, finally. :D
EDIT:
Ok I edited your script. This visualizes camera's upper frustum plane. Note that this works in global space so move the camera at (0 0 0) position and (0 0 0) rotation to see the result. But I guess you can add the rest of the planes and turn this into local space yourself.
using UnityEngine;
using System.Collections;
public class FrustumScript : MonoBehaviour {
private void Start()
{
TriangleMaker();
}
void TriangleMaker()
{
MeshFilter mf = GetComponent<MeshFilter>();
Mesh mesh = new Mesh();
mf.mesh = mesh;
Camera cam = Camera.main;
//vertices
Vector3[] vertices = new Vector3[3]
{
new Vector3(0, 0, 0),
cam.ViewportToWorldPoint(new Vector3(0, 1, cam.farClipPlane)),
cam.ViewportToWorldPoint(new Vector3(1, 1, cam.farClipPlane))
};
//triangles
int[] tri = new int[6];
tri[0] = 0; //go clock wise always to make triangle from your vertices
tri[1] = 1;
tri[2] = 2;
//normals
//show the direction of objects
Vector3[] normals = new Vector3[3];
normals[0] = -Vector3.up;
normals[1] = -Vector3.up;
normals[2] = -Vector3.up;
mesh.vertices = vertices;
mesh.triangles = tri;
mesh.normals = normals;
}
}

Unity C# generated mesh is offset why is it not in the correct location?

I am attempting to generate a mesh in unity from script. The mesh is generated by raycasting out in a particular direction. Then getting the vertices from the hit point or from where the ray terminates. The mesh generates fine and is working well, however the mesh generates approximately 5 to 10 unity units above the location of the object with the attached script. I will attach me script below.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Torch : MonoBehaviour {
public GameObject lightmeshholder;
private int RaysToShoot = 128;
private float distance = 50;
private Vector3[] vertices;
private Vector2[] vertices2d;
private int[] triangles;
private Mesh mesh;
private Texture2D texture;
private int screenwidth;
private int screenheight;
private int grab = 0;
private RaycastHit hit;
// Use this for initialization
void Start () {
screenwidth = Screen.width;
screenheight = Screen.height;
texture = new Texture2D (screenwidth, screenheight, TextureFormat.RGB24, false);
vertices = new Vector3[RaysToShoot];
vertices2d = new Vector2[RaysToShoot];
triangles = new int[(RaysToShoot) +1 ];
mesh= lightmeshholder.GetComponent<MeshFilter>().mesh;
}
// Update is called once per frame
void Update () {
float angle =0;
for(int i=0;i<RaysToShoot;i++){
float x = Mathf.Sin(0);
x=-5;
if(Input.GetKey(KeyCode.P)){
x = 5;
}
float y = Mathf.Cos(angle);
if (angle <= 90){
angle += 2*Mathf.PI/RaysToShoot;
}
Vector3 dir = new Vector3(x,y,0);
if (Physics.Raycast (this.transform.position, dir,out hit, distance))
{
Debug.DrawLine (this.transform.position, hit.point,new Color(1,1,0,1));
Vector3 tmp = lightmeshholder.transform.InverseTransformPoint(hit.point);
vertices2d[i] = new Vector2(tmp.x,tmp.y);
}else{
Vector3 tmp = lightmeshholder.transform.InverseTransformPoint(this.transform.position + dir*distance);
vertices2d[i] = new Vector2(tmp.x,tmp.y);
Debug.DrawLine(this.transform.position,dir * distance,Color.red,0);
}
}
// build mesh
Vector2[] uvs = new Vector2[vertices2d.Length +1];
Vector3[] newvertices = new Vector3[vertices2d.Length+1];
for (int n = 0; n<newvertices.Length-1 ;n++)
{
if(n==0){
newvertices[0]=this.transform.position;
newvertices[1] = vertices2d[0];
uvs[0] = new Vector2(this.transform.position.x,this.transform.position.y);
uvs[1] = vertices2d[0];
}else{
newvertices[n+1] = vertices2d[n];
uvs[n+1] = vertices2d[n];
}
if(n==0){
triangles[0] = 0;
triangles[1] = 1;
triangles[2] = 2;
}else if(n<newvertices.Length/3){
triangles[n*3] = 0;
triangles[1+n*3] = n+1;
triangles[2+n*3] = n+2;
}
}
Mesh mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
mesh.Clear();
mesh.vertices = newvertices;
mesh.uv = uvs;
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
}
The hitpoints you're getting from the raycasts are global. You can either:
1) Make sure the mesh is in a gameobject that is positioned at 0,0,0. Whenever I create a dynamic mesh based on ray hitpoints I usually create a new parent-less gameobject at 0,0,0 and add the mesh to it. (instead of getting a container GameObject externally)
2) Call lightmeshholder.transform.InverseTransformPoint on the hitpoints from the raycast before building the mesh
When you are assigning vertices back to mesh they are calculated in local coordinates with respect to object root. So if you want to bring it back "where it should be" process them with .TransformPoint() call to get proper offsets. This should fix your problem with them being in different location than you expect. I had same problem.

Categories