Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Slymatt · May 02, 2015 at 11:06 PM · vertexprocedural meshvoxelmesh verticeshole

Procedural Mesh random faces generated

Hello, my issue is my mesh is created, but some of the faces on the top layer are sometimes missing and there are always extra faces all the way down the chunk, there shouldnt be as the verts should have been deleted but i just cant put my finger on it.

This issue only started when i added threading.

heres images of what i mean to make it clear:

alt text

alt text

Heres the code:

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;
 using SimplexNoise;
 using System.Threading;
 
 [RequireComponent (typeof(MeshRenderer))]
 [RequireComponent (typeof(MeshCollider))]
 [RequireComponent (typeof(MeshFilter))]
 public class Chunk : MonoBehaviour {
 
     public const float TEXTURE_TILE_SIZE = 32f;
     public const float ATLAS_SIZE = 128f;
     public const float TEXTURE_PADDING_SIZE = 0f;
     
     public static List<Chunk> chunksWaiting = new List<Chunk>();
     public static List<Chunk> chunks = new List<Chunk>();
     public static int width {
         get { return World.currentWorld.chunkWidth; }
     }
     public static int height {
         get { return World.currentWorld.chunkHeight; }
     }
     public static float brickHeight {
         get { return World.currentWorld.brickHeight; }
     }
 
     List<Vector3> verts = new List<Vector3>();
     List<Vector2> uvs = new List<Vector2>();
     List<int> tris = new List<int>();
 
     public Thread mythread;
 
     public byte[,,] map;
     public Mesh visualMesh;
     protected MeshRenderer meshRenderer;
     protected MeshCollider meshCollider;
     protected MeshFilter meshFilter;
     protected bool initialized = false;
     protected bool isPopulated = false;
     Vector3 myTransform;
     bool hasEnded = false;
     // Use this for initialization
     void Start () {
         
         chunks.Add(this);
         
         meshRenderer = GetComponent<MeshRenderer>();
         meshCollider = GetComponent<MeshCollider>();
         meshFilter = GetComponent<MeshFilter>();
         
         chunksWaiting.Add(this);
         myTransform = transform.position;
 
         if (chunksWaiting[0] == this)
         {
             mythread = new Thread(new ThreadStart(CalculateMapFromScratch));
             mythread.Start();
 
         }
         
     }
 
     void Update(){
         if (initialized && !isPopulated) {
             PopulateMesh ();
             isPopulated = true;
         }
     }
 
     public static byte GetTheoreticalByte(Vector3 pos) {
         System.Random rand = new System.Random (World.currentWorld.seed);
         Vector3 grain0Offset = new Vector3((float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000);
         Vector3 grain1Offset =  new Vector3((float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000);
         Vector3 grain2Offset = new Vector3((float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000);
 
         return GetTheoreticalByte(pos, grain0Offset, grain1Offset, grain2Offset);
         
     }
     
     public static byte GetTheoreticalByte(Vector3 pos, Vector3 offset0, Vector3 offset1, Vector3 offset2)
     {
         float clusterValue = CalculateNoiseValue(pos, offset2,  0.02f);        
         int biomeIndex = Mathf.FloorToInt(clusterValue * World.currentWorld.biomes.Length);
         Biome biome = World.currentWorld.biomes[biomeIndex];
     
         float heightBase = biome.minHeight;
         float maxHeight = biome.maxHeight;
         float heightSwing = maxHeight - heightBase;
         
         float blobValue = CalculateNoiseValue(pos, offset1,  0.05f);
         float mountainValue = CalculateNoiseValue(pos, offset0,  0.009f);
 
         mountainValue += biome.mountainPowerBonus;
         if (mountainValue < 0) mountainValue = 0;
         
         mountainValue = Mathf.Pow(mountainValue, biome.mountainPower);  //Mathf.Sqrt(mountainValue);
 
         byte brick = biome.GetBrick(Mathf.FloorToInt(pos.y), mountainValue, blobValue);
         
         mountainValue *= heightSwing;
         mountainValue += heightBase;
         mountainValue += (blobValue * 10) - 5f;    
                     
         if (mountainValue >= pos.y)
             return brick;
         return 0;
     }
 
     
     public virtual void CalculateMapFromScratch() {
         map = new byte[width, height, width];
         System.Random  rand = new System.Random (World.currentWorld.seed);
         Vector3 grain0Offset = new Vector3((float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000);
         Vector3 grain1Offset =  new Vector3((float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000);
         Vector3 grain2Offset = new Vector3((float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000, (float)rand.NextDouble() * 10000);
 
         for (int x = 0; x < World.currentWorld.chunkWidth; x++)
         {
             for (int y = 0; y < height; y++)
             {
                 for (int z = 0; z < width; z++)
                 {
                     map[x, y, z] = GetTheoreticalByte(new Vector3(x, y, z) + myTransform, grain0Offset, grain1Offset, grain2Offset);
                 }
             }
         }
 
         CreateVisualMesh();
         initialized = true;
 
 
 
         chunksWaiting.Remove(this);
         
         if (!hasEnded) {
             if (chunksWaiting [0] != null)
                 chunksWaiting [0].CalculateMapFromScratch ();
         }        
     }
     
     public static float CalculateNoiseValue(Vector3 pos, Vector3 offset, float scale)
     {
         float noiseX = Mathf.Abs((pos.x + offset.x) * scale);
         float noiseY = Mathf.Abs((pos.y + offset.y) * scale);
         float noiseZ = Mathf.Abs((pos.z + offset.z) * scale);
 
         return Mathf.Max(0, Noise.Generate(noiseX, noiseY, noiseZ));
     }
     
     
     public virtual void CreateVisualMesh() {
         verts.Clear ();
         uvs.Clear ();
         tris.Clear();
 
         for (int x = 0; x < width; x++)
         {
             for (int y = 0; y < height; y++)
             {
                 for (int z = 0; z < width; z++)
                 {
                     if (map[x,y,z] == 0) continue;
                     
                     byte brick = map[x,y,z];
                     // Left wall
                     if (IsTransparent(x - 1, y, z))
                         BuildFace (brick, new Vector3(x, y, z), Vector3.up, Vector3.forward, false, verts, uvs, tris, BlockSide.LEFT);
                     // Right wall
                     if (IsTransparent(x + 1, y , z))
                         BuildFace (brick, new Vector3(x + 1, y, z), Vector3.up, Vector3.forward, true, verts, uvs, tris, BlockSide.RIGHT);
                     
                     // Bottom wall
                     if (IsTransparent(x, y - 1 , z))
                         BuildFace (brick, new Vector3(x, y, z), Vector3.forward, Vector3.right, false, verts, uvs, tris, BlockSide.BOTTOM);
                     // Top wall
                     if (IsTransparent(x, y + 1, z))
                         BuildFace (brick, new Vector3(x, y + 1, z), Vector3.forward, Vector3.right, true, verts, uvs, tris, BlockSide.TOP);
                     
                     // Back
                     if (IsTransparent(x, y, z - 1))
                         BuildFace (brick, new Vector3(x, y, z), Vector3.up, Vector3.right, true, verts, uvs, tris, BlockSide.BACK);
                     // Front
                     if (IsTransparent(x, y, z + 1))
                         BuildFace (brick, new Vector3(x, y, z + 1), Vector3.up, Vector3.right, false, verts, uvs, tris, BlockSide.FRONT);
                 }
             }
         }
     }
 
     public void PopulateMesh(){
         visualMesh = new Mesh();
         visualMesh.vertices = verts.ToArray();
         visualMesh.uv = uvs.ToArray();
         visualMesh.triangles = tris.ToArray();
         visualMesh.RecalculateBounds();
         visualMesh.RecalculateNormals();
         
         meshFilter.mesh = visualMesh;
         
         
         meshCollider.sharedMesh = null;
         meshCollider.sharedMesh = visualMesh;
     }
 
     public virtual void BuildFace(byte brick, Vector3 corner, Vector3 up, Vector3 right, bool reversed, List<Vector3> verts, List<Vector2> uvs, List<int> tris, BlockSide brickSide)
     {
 
         int index = verts.Count;
                 
         verts.Add (corner);
         verts.Add (corner + up);
         verts.Add (corner + up + right);
         verts.Add (corner + right);
         
         Vector2 tileSize = CreateUVTexture((BlockType)brick, brickSide);
 
         float tileSizeOriginal = TEXTURE_TILE_SIZE / ATLAS_SIZE;
         float padding = TEXTURE_PADDING_SIZE / ATLAS_SIZE; //stops bleeding from mip map
     
         uvs.Add(new Vector2 (tileSize.x + padding, tileSize.y + padding));
         uvs.Add(new Vector2 (tileSize.x + padding, tileSize.y + tileSizeOriginal + padding));
         uvs.Add(new Vector2 (tileSize.x + tileSizeOriginal - padding, tileSize.y + tileSizeOriginal - padding));
         uvs.Add(new Vector2 (tileSize.x + tileSizeOriginal - padding, tileSize.y));
 
         if (reversed)
         {
             tris.Add(index + 0);
             tris.Add(index + 1);
             tris.Add(index + 2);
             tris.Add(index + 2);
             tris.Add(index + 3);
             tris.Add(index + 0);
         }
         else
         {
             tris.Add(index + 1);
             tris.Add(index + 0);
             tris.Add(index + 2);
             tris.Add(index + 3);
             tris.Add(index + 2);
             tris.Add(index + 0);
         }
         
     }
     public virtual bool IsTransparent (int x, int y, int z)
     {
 
         if ( y < 0) return false;
 
         byte brick = GetByte(x,y,z);
 
         switch (brick)
         {
         case 0: 
             return true;
         default:
             return false;
         }
     }
     public virtual byte GetByte (int x, int y , int z)
     {
 
         if ((y < 0) || (y >= height))
             return 0;
         
         Vector3 worldPos = new Vector3(x, y, z) + myTransform;
         if (! initialized)
             return GetTheoreticalByte(worldPos);
         
         
         if ( (x < 0) || (z < 0)  || (x >= width) || (z >= width))
         {
             
             Chunk chunk = Chunk.FindChunk(worldPos);
             if (chunk == this) return 0;
             if (chunk == null) 
             {
                 return GetTheoreticalByte(worldPos);
             }
             return chunk.GetByte (worldPos);
         }
         return map[x,y,z];
         
 
     }
     public virtual byte GetByte(Vector3 worldPos) {
         worldPos -= transform.position;
         int x = Mathf.FloorToInt(worldPos.x);
         int y = Mathf.FloorToInt(worldPos.y);
         int z = Mathf.FloorToInt(worldPos.z);
         return GetByte (x, y, z);
     }
     
     public static Chunk FindChunk(Vector3 pos) {
 
         for (int a = 0; a < chunks.Count; a++)
         {
 
             Vector3 cpos = chunks[a].transform.position;
 
             if ( ( pos.x < cpos.x) || (pos.z < cpos.z) || (pos.x >= cpos.x + width) || (pos.z >= cpos.z + width) ) continue;
             return chunks[a];
             
         }
         return null;
         
     }
     
     public bool SetBrick (byte brick, Vector3 worldPos)
     {
         worldPos -= transform.position;
         return SetBrick(brick, Mathf.FloorToInt(worldPos.x),Mathf.FloorToInt(worldPos.y),Mathf.FloorToInt(worldPos.z));
     }
 
     public bool SetBrick (byte brick, int x, int y, int z)
     {
         if ( ( x < 0) || (y < 0) || (z < 0) || (x >= width) || (y >= height) || (z >= width) )
         {
             return false;
         }
         
         if (map[x,y,z] == brick) return false;
         map[x,y,z] = brick;
         CreateVisualMesh();        
         
         if (x == 0)
         {
             Chunk chunk = FindChunk( new Vector3(x - 2, y, z) + transform.position);
             if (chunk != null)
             chunk.CreateVisualMesh();        
         }
         if (x == width - 1)
         {
             Chunk chunk = FindChunk( new Vector3(x + 2, y, z) + transform.position);
             if (chunk != null)
                 chunk.CreateVisualMesh();        
         }
         if (z == 0)
         {
             Chunk chunk = FindChunk( new Vector3(x, y, z - 2) + transform.position);
             if (chunk != null)
                 chunk.CreateVisualMesh();        
         }
         if (z == width - 1)
         {
             Chunk chunk = FindChunk( new Vector3(x, y, z + 2) + transform.position);
             if (chunk != null)
                 chunk.CreateVisualMesh();        
         }
         
         return true;
     }
 
     public Vector2 CreateUVTexture(BlockType blocktype, BlockSide brickSide){
         Vector2 tileSize =  new Vector2(TEXTURE_TILE_SIZE / ATLAS_SIZE, TEXTURE_TILE_SIZE / ATLAS_SIZE) ;
 
         Vector2 tileSizeTemp = GetCoord(blocktype, brickSide);
         
         tileSize.x *= tileSizeTemp.x;
         tileSize.y *= tileSizeTemp.y;
         
         return tileSize;
         
     }
     
     
     Vector2 GetCoord(BlockType brickType, BlockSide brickSide){
         Vector2 tileCoords = new Vector2 ();
         
         
         switch (brickType) {
         case BlockType.STONE:
             tileCoords.x = 0;
             tileCoords.y = 0;
             break;
         case BlockType.DIRT:
             tileCoords.x = 1;
             tileCoords.y = 0;
             break;
         case BlockType.DIRT_GRASS:
             if(brickSide == BlockSide.TOP){
                 tileCoords.x = 2;
                 tileCoords.y = 0;
             }else if(brickSide == BlockSide.BOTTOM){
                 tileCoords.x = 1;
                 tileCoords.y = 0;
             }else{
                 tileCoords.x = 3;
                 tileCoords.y = 0;
             }
 
             break;
         case BlockType.REDSTONE:
             tileCoords.x = 0;
             tileCoords.y = 2;
             break;
         case BlockType.SILVER:
             tileCoords.x = 1;
             tileCoords.y = 2;
             break;
         case BlockType.IRON:
             tileCoords.x = 2;
             tileCoords.y = 2;
             break;
         case BlockType.COAL:
             tileCoords.x = 0;
             tileCoords.y = 3;
             break;
         case BlockType.LAPIS:
             tileCoords.x = 1;
             tileCoords.y = 3;
             break;
         case BlockType.EMERALD:
             tileCoords.x = 2;
             tileCoords.y = 3;
             break;
         case BlockType.GOLD:
             tileCoords.x = 3;
             tileCoords.y = 3;
             break;
         case BlockType.BEDROCK:
             tileCoords.x = 0;
             tileCoords.y = 1;
             break;
         default:
             tileCoords.x = 0;
             tileCoords.y = 1;
             break;
         }
         
         return tileCoords;
     }
 
     void OnDestroy() {
         hasEnded = true;
     }
 }
 
 

a2015-05-02-212315313.jpg (335.8 kB)
screenshot-2015-05-02-15515.jpg (363.2 kB)
Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Slymatt · May 04, 2015 at 09:37 AM 0
Share

Still haven't found a solution cant understand why it would do this after adding threading

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by Slymatt · May 04, 2015 at 01:18 PM

Fixed it was a stupid mistake the code was looking at byte 0 which should have been enum NONE turns out i forgot to add NONE to my enum

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Slymatt · May 05, 2015 at 02:00 PM 0
Share

Well i tested the old code and it seems that i may have created this bug just before the threading was implemented so its not a threading issue, still an issue though

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

2 People are following this question.

avatar image avatar image

Related Questions

Manual culling of voxel faces? 0 Answers

Merging faces without effecting texture mapping 2 Answers

Does CombineMesh always remove unused vertecies or not? 0 Answers

Is there any way to tile a texture within a single triangle of a procedural mesh? 1 Answer

Dynamically move vertices of a mesh 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges