Search Unity

Uniblocks: cube-based infinite voxel terrain engine

Discussion in 'Assets and Asset Store' started by RawLionWorkshop, Feb 2, 2014.

  1. devilaz

    devilaz

    Joined:
    Sep 9, 2015
    Posts:
    2
    Hi there,

    Interested in purchasing this.

    Is the multiplayer well documented and explained? I saw a comment 11 months ago that it was not but I hope that would have changed by now.
     
  2. RawLionWorkshop

    RawLionWorkshop

    Joined:
    Jan 29, 2014
    Posts:
    206
    Hi, you can check out the documentation for yourself, it covers all the multiplayer features among other things:
    https://www.dropbox.com/s/p9nfjw4dalq8v66/Uniblocks 1.4 Documentation.zip?dl=0

    The multiplayer features are pretty basic, and you'll most likely want to build a more advanced custom solution on top of them if you're doing a serious multiplayer project, but they are fully documented. The code itself is also commented.
     
  3. devilaz

    devilaz

    Joined:
    Sep 9, 2015
    Posts:
    2
    Hello again,

    I'm having an issue where blocks don't seem to be generate properly in certain areas, typically on the top of mountains. There is just a transparent area and if you walk into the area you fall through the world, please see the attached screenshot. The chunks seem to load if you place a block next to the transparent area.

    I also have another question, I am new to unity so forgive me if this is obvious. But how would I go around having the server run in a separate application from the client? I'm guessing you would have the engine in a different scene but I am not entirely sure.

    Thanks.
     

    Attached Files:

  4. RawLionWorkshop

    RawLionWorkshop

    Joined:
    Jan 29, 2014
    Posts:
    206
    With the default settings the terrain will occasionally generate hills that are too tall to fit inside the vertical chunk limit - basically, chunks will not spawn above a certain height, and that's why you're seeing a hole in the world.

    You can increase the chunk height range setting (in the Engine Settings window), but that will increase the number of chunks loaded, reducing performance.
    You can also tweak the hard-coded values inside the terrain generator script to make the hills lower.
    A third solution is to increase the chunk size. Larger chunks will cover a larger vertical range with the same number of chunks, but will load slower.

    You can't run two separate instances of the application inside Unity, so you will need to make an external build of either the client or the server, and just run it normally outside of Unity.
     
  5. kr105rlz

    kr105rlz

    Joined:
    Sep 12, 2015
    Posts:
    1
    I very much want to purchase this, but on the demo video I noticed a problem where the blocks seems to deform and enlarge when you look up and down. I downloaded the demo app and tested myself and the problem is still there, I made an small video that shows the problem:




    Is this something that can be fixed? If so, I'll buy it right away.
     
    Last edited: Sep 13, 2015
  6. Endzone

    Endzone

    Joined:
    Dec 18, 2014
    Posts:
    119
    I dont belive this is a problem, this is the Main Cameras Field of view maap must have it turned up in the demo you can simply change the Fielf Of View on your main camera and they shouldent stretch :)
     
    JasonBricco likes this.
  7. Firlefanz73

    Firlefanz73

    Joined:
    Apr 2, 2015
    Posts:
    1,316
    Hi maap,

    is there a patch / fix for the colliders Problem when custom meshes are rotated?

    Thanks a lot and have a nice sunday!
     
  8. Endzone

    Endzone

    Joined:
    Dec 18, 2014
    Posts:
    119
    Hey maap so i belive i have asked this question in the past but im still a little stuck... i want to create bieomes ive tryed useing currentHeight to do bieomes but they just dont quiet feel right :l is their any other way of creating bieomes rather then current height ?
    And also if i manage to get the bieomes to work is their a way i can change the terrain generation depending on the bieome that gets generated?
     
  9. RawLionWorkshop

    RawLionWorkshop

    Joined:
    Jan 29, 2014
    Posts:
    206
    This is a side effect of the field of view of the camera being set pretty high, you can adjust it if needed.


    The patch is now pending approval on the asset store, should be available for download pretty soon!


    There are many ways to do biomes, but my answer is going to have to be the same as the last time (http://forum.unity3d.com/threads/un...xel-terrain-engine.226014/page-6#post-2074337)
    I'm really sorry, but voxel terrain generation is a topic that's just too complicated to explain in a forum post.
     
  10. Endzone

    Endzone

    Joined:
    Dec 18, 2014
    Posts:
    119
  11. Firlefanz73

    Firlefanz73

    Joined:
    Apr 2, 2015
    Posts:
    1,316
    Hello again maap,

    I need to create a new world from the menu. So all chunks should be cleared / removed, new seed with new world from the beginning, or loaded from disc.

    How do I do that? Do I need to make a public function of Engine.Awake or just create a new Engine? How do I clear the existing chunks?

    Thanks a lot,

    Firlefanz

    PS: The update is online. Thanks for that :)
     
    Last edited: Sep 15, 2015
  12. RawLionWorkshop

    RawLionWorkshop

    Joined:
    Jan 29, 2014
    Posts:
    206
    You can destroy chunks using Chunk.FlagToRemove() on all the chunks in the ChunkManager.Chunks list (just use a standard foreach loop).

    Chunks should save their data automatically before removal, but you can do an Engine.SaveWorldInstant() before deleting the chunks just in case.

    In case you do this while new chunks are still being loaded, you can interrupt the loading process by setting ChunkManager.StopSpawning to true. This will make sure that no new chunks are loaded until you actually switch to a different world.

    Once chunks are deleted, you can change the current world using Engine.SetWorldName("worldName"), and then you can start loading chunks again as normal. They will load or generate data based on the newly set world name. If the world doesn't exist yet, it will be created, and the seed will also be reset (or loaded from an already existing world).
     
  13. Firlefanz73

    Firlefanz73

    Joined:
    Apr 2, 2015
    Posts:
    1,316
    Perfect! Thanks maap :)
     
  14. Endzone

    Endzone

    Joined:
    Dec 18, 2014
    Posts:
    119
    Hey maap just wondering is their a way i can get Voxel.DestroyBlock() to only Destroy 1 block? ive made a timer and stuff so if im holding the mouse button it will count down show some breaking meshes and then i want it to destroy one block but instead it destroys what ever is in its path and not just the one like i want :l ... is their any way to stop it from destroying more then 1 block at a time ?
    Also im trying to create a different timer so i can use it on my sapplings for my trees but im having one issue how exactly would i use the timer on a block so if i place my block then the timer starts on that newly placed block i tryed to do this my self but i wasent sure how to do it considering theirs no Update function in Defaultvoxelevents :S
    Edit* So rather then use a timer for the sapplings i changed it and im now useing a Coroutine, it seems to work fine for now although im now having a different problem then before once the coroutine is finished i have no idea how to get my tree to spawn where my sappling was :l Any ideas :S ?
     
    Last edited: Sep 18, 2015
  15. Jessespike

    Jessespike

    Joined:
    Jul 9, 2012
    Posts:
    44
    Hi maap, I'm looking to implement some path-finding AI to my Uniblocks project. I've done A* in 2D games before, and have also used Unity's navmesh for simple 3D environments. But I've never tried to do path-finding in a 3D voxel terrain before, do you have any ideas or suggestions for accomplishing this?

    Edit: Ah nevermind, I was reading earlier posts on this thread and saw that this question was asked and answered already.
     
    Last edited: Sep 18, 2015
  16. TheXWolf

    TheXWolf

    Joined:
    Dec 13, 2013
    Posts:
    85
    What would be the correct way to set a vertical limit to the generation as a whole? I know we can set the vertical chunk limit, but that's just what chunks load in. Suppose I want it to be 288 (which is 18 total) chunks in size, but I only want it to load in/generate 4 at a time, thus setting a hard limit on world size. So that the very bottom of the world isn't generating beneath the player when they aren't there. Also, how would I specifically reference that in my generation script. I've tried chunk index and length which basically give's me the chunks position, but that doesn't help me with placing the blocks themselves? I'm using simplex noise for most of the terrain and I need a cap below and above, with specific blocks for the bottom most, but I can't seem to use the right methods to determine where it's currently at.
     
  17. RawLionWorkshop

    RawLionWorkshop

    Joined:
    Jan 29, 2014
    Posts:
    206
    Voxel.DestroyBlock destroys only one block, the one specified in the function parameters (the voxelInfo). I'm guessing you're somehow triggering multiple DestroyBlock functions at the same time, but that would be because of something wrong in your code, so I can't help you here...

    It's going to be difficult to have an individual timer for one block only because blocks aren't objects, so you can't have an update function or attach anything to them. Even if you use coroutines, you will probably need to keep track externally (basically, save the current timer on the hard drive) in case the chunk is destroyed or the game is shut down.

    To place a tree where the sapling was you can just store the VoxelInfo of the sapling block together with its timer and place the tree using the coordinates of the stored VoxelInfo.


    I'm not entirely sure if this is what you're asking, but... the chunk height limit is indeed the total vertical limit, so if you want the vertical chunk limit to be 18, just set the chunk height limit to 18.

    The loading of chunks will still be limited by the chunk spawn range, in the vertical as well as the horizontal directions, so if you set the chunk spawn distance to 4, only 4 chunks will load at one time.


    ( Chunk index * chunk side length ) + voxel index gives you the absolute voxel position.
    In the ExampleTerrainGenerator the int currentHeight uses this formula to get the absolute vertical position of the current voxel.
     
    TheXWolf likes this.
  18. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    I'm rewriting how trees are generated but one problem I'm running into is dealing with placing trees that don't fit within the chunk. As you have it, the tree has to fit in the chunk or it doesn't get placed. I want to generate larger trees that may include placing outside of the current chunk.

    Although slower, to begin playing around with the ExampleTerrainGeneratorWithTrees instead of using SetVoxelSimple, I'm just finding the chunk and setting the voxel to deal with voxels that might be going outside the current chunk on the terrain generator. What I've noticed though is that sometimes the chunk isn't returned with PositionToChunk (I'm guessing because that chunk doesn't exist yet) as you can see in the code below.

    Code (CSharp):
    1.  
    2. GameObject go = (GameObject)Engine.PositionToChunk(new Vector3(treeBrushPos));
    3. if (go == null)
    4. {
    5.      go = ChunkManager.SpawnChunk(treeBrushPos);
    6. }
    7. Chunk c = go.GetComponent<Chunk>();
    8. if (c != null)
    9. {
    10.      c.SetVoxel(treeBrushPos, 9, false);
    11. }
    12.  
    Do you have any suggestions on how I might overcome this? Any pointers on how you might do it or what you might think the best approach is to generate cross-chunk voxels within ExampleTerrainGenerator?

    In other words, how can I set the voxel of a chunk that isn't yet rendered or generated?
     
    Last edited: Sep 22, 2015
    nuonical likes this.
  19. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    A few other questions I'm trying to make uniblocks more efficient. I've already made several changes that improve its efficiency quite dramatically, however, I have a few questions:

    1) Why are the chunks not always being recycled? I've noticed when flying around that over the course of a minute, hundreds of chunks were marked with EndSequence which destroys the chunk GameObject rather than recycling them. This creates needless overhead. I set my map to 5 height, 16 spawn distance, and made a public "ChunksToDestroyCounter" counter which shot up to 1303 destroyed chunks in less than a minute of walking forward at a brisk pace of 1 block per second. Because you have SaveData built into removal, that is 1303 chunks saving in that 1 minute and 1303 GameObjects being destroyed. Even with your default 8 chunk view distance, that is still needless destroying of chunks rather than recycling them.


    2) Why is Resources.UnloadUnusedAssets called in EndSequence()? This creates GarbageCollection overhead and causes needless spikes in GC that spike CPU creating stuttering every time EndSequence is called. Sure with only 8 chunks distance by default you don't notice it although you can see spikes in profiler, but when you set the chunk distance to 16 - which should be the default option if you want to compete with other voxel games, you notice GC spikes because of Resources.UnloadUnusedAssets.

    3) Why are you using Lists with foreach or at all? Lists are very slow, sure in this case very arguable, but efficiency counts for everything here and every little bit helps. For example, just a for vs for each shows huge diff in performance, but even resizing an array I think after 500 items resizing an array is faster.

    Code (CSharp):
    1.           for      foreach
    2. Array : 1575ms     1575ms (+0%)
    3. List  : 1630ms     2627ms (+61%)
    4.          (+3%)     (+67%)
    4) You have a lot of if(wtv != null) called per frame which causes huge overhead. For some reason null comparison adds more overhead than other types of comparisons.
     
  20. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Lists aren't really a bad idea - they're just arrays that are dynamically resized behind the scenes anyway.

    Foreach loops, however, are a bit slow in Unity and allocate garbage. I believe that's due to a bug that will be fixed if we can ever get an upgraded Mono.

    Null checks are slow in Unity due to their behavior, covered here.

    I recommend object pooling chunks and recycling them using a queue or something. Any place you would call instantiate, just return a chunk from your queue. And if you have no chunks to return from the queue, then instantiate one. Shouldn't interfere with saving.

    You might also consider only saving the modified chunks rather than every chunk, to cut down on storage space and save calls. You would need to save the Perlin seed though so that the terrain would generate in a way that matches the saved chunks.

    I don't think there's any need for Resources.UnloadUnusedAssets - maybe it existed to prevent mesh memory leaks, but I don't think it actually does anything to prevent that... I may be wrong, but it certainly isn't helping me solve my mesh memory leaking right now :)
     
    Stone-Legion likes this.
  21. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    This is actually proving to be more difficult than it seems. Spent the past day rewriting to implement this but there are so many calls spread across several scripts, it's like a spiderweb. Essentially what I did was turned ChunksToDestroy into the recycle pool and pull from it when a chunk would have been instantiated. Where there is instantiate, it now takes from ChunksToDestroy if there are recycled chunks and only instantiates if no recycled chunks are available. Rather than destroy the chunk, I just ChunkManager.UnregisterChunk and set the gameobject to inactive. In Chunk.cs I moved the Awake() code into an Initialize() method so that Initialize() is called on awake but can also be called when a recycled chunk is being pulled to be reused. When the chunk is pulled from recycle pool, it is initialized and reregistered.

    Problems are that the chunkmeshrenderer seems to have issues with this. For some reason when the chunks are recycled, they are not redrawing some of the time. I've tried resetting the chunkmesh with mesh.Clear() when it is unregistered so when it is reused, a big chunk doesn't pop up mid-air.
     
  22. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    One other question, what is the reason for AddChunkToUpdateQueue and ProcessChunkQueue in ChunkManager.cs versus FlaggedToUpdate in LateUpdate() of Chunk.cs? Why not just use the LateUpdate -> RebuildMesh in Chunk.cs all the time when the chunk needs to be rebuilt?
     
  23. RawLionWorkshop

    RawLionWorkshop

    Joined:
    Jan 29, 2014
    Posts:
    206
    The short answer is, I don't know...
    If possible, you should try to contain all terrain generation in a single chunk, otherwise things get very messy.

    You could try to force chunks to load whenever you need them, but then these forcibly loaded chunks might possibly force other chunks to load, potentially resulting in an infinite loop.

    You could also queue up the generation to wait until the chunk is spawned, but you would need to find a way to store that queued up algorithm somewhere and make sure it will always fire correctly even when chunks are unloaded and loaded back again, etc.

    But yeah, generally I think it's going to be messy and difficult no matter what, so limiting generation to one chunk at a time is highly recommended instead.



    As for the efficiency questions, I'm not going to address every point individually, because the answer to all of them is basically the same: less efficient code is faster and easier to write and maintain, and in most cases the performance difference is just not worth the extra work.

    More efficient code also tends to be more complicated, and complicated code is harder to debug, and also harder to understand for other people who will work with it, which is also a concern.

    Of course there are many things that could be improved, but it really isn't as simple as it might seem. Making a voxel engine is already pretty complicated. Making a voxel engine and making it perfectly optimized at the same time is a lot more complicated.

    Some solutions might seem strange if looked at from an outside perspective, but it's likely that they're that way because of some non-obvious but legitimate reason. Solving some obscure problem, cutting down development time, reducing complexity of the code. Or of course they might be just simple mistakes - that happens too!


    Resources.UnloadUnusedAssets() was added because it fixed some memory leak issues. Check this post for details:
    http://forum.unity3d.com/threads/un...xel-terrain-engine.226014/page-4#post-1929320
    If it doesn't work and/or it's causing problems, you can probably just remove it.


    That might be a problem with the chunk update queue in ChunkManager. Perhaps some of the recycled chunks were already queued before and haven't been removed from the queue? That would probably cause them to update in the wrong order, like for example much later than expected.
    Could be something else entirely though. That's one example of why optimizing the code is not as simple as it seems...

    RebuildMesh is very costly and doing too many of them in one frame will freeze the game. The ChunkManager's ProcessChunkQueue distributes the load across multiple frames by controlling how many mesh rebuilds are done in a single frame. Also, the meshes have to be built in a specific order, and for that a centralized queue is needed.
     
    nuonical likes this.
  24. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    maap, I love your addon but the responses you are giving are less than stellar. It doesn't make sense that you wouldn't wnat to optimize uniblocks for the benefit of everyone. Coding it to make it "simple" hurts everyone in the end because it makes uniblocks nothing more than just a test asset for playing around with but anyone who wants to seriously use it for development is now going to have to rewrite and optimize a large portion of it.

    I'm using i7 3770k with R9 270x and I see FPS drops between 50-60 and empty chunks when just walking with default settings. In the image below it is 100% default settings and yet after walking for 5 minutes you can see chunks are missing and still loading. This is not good user experience and now anyone that buys uniblocks will have to sort though and try to optimize.

    I think you should really work on optimizing and making the chunks load faster because as it is right now, uniblocks cannot be taken as a serious addon and you just seem to not want to work on improving it. I hate to say this and sound mean because uniblocks is really a great base and I know you put a lot of hard work into it, but it would be even better if it was optimized now for everyone. I get that you are worried about making it more complex and dealing with support since ppl on here seem to ask some really easy questions (probably myself included) but you don't have to reply to answer the most basic of programming questions, some which I saw on here that are laughable and not your responsibility to teach ppl basic programming.

     
  25. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    One thing I think this engine seriously needs is threading. Honestly, you just can't ship a voxel engine without threading... it's a fantastic way to really improve the FPS. You need to take all terrain calculations, mesh calculations and saving/loading and put that on background threads.

    Unfortunately, you pretty much have to design a voxel engine with threading in mind from the start. Changing an already developed voxel engine to support threading is a bit of a nightmare. I do think it's very necessary, though. It's one thing I can safely assume all voxel engines should share.
     
    Stone-Legion likes this.
  26. nuonical

    nuonical

    Joined:
    Feb 28, 2015
    Posts:
    46
    I get what Maap is saying, as well as the call for performance improvements. The way I see it, if we can make some of these improvements ourselves, then why not contribute to the engine?

    I have personally found that digging in and actually making signifigant improvements turn out to be more difficult and less efficient to implement than at first glance. What Maap has said in his previous post absolutely rings true to me in most cases. That doesn't mean "don't make performance improvements", it just means "it's not as simple as you think it is".

    As JasonBricco mentioned, changing an existing voxel engine to support threading is a bit of a nightmare. You're essentially rewriting how chunks are managed. And right now in the Engine you need to get back to the main thread often, so you would need some sort of queueing mechanism, and that ends up throwing up its own complications into the mix (I've been down this road before with only minor improvements and unforeseen complications).

    Why not start with pooling and measure the performance improvements? Are we talking 1% or 10% improvement here? If we can get a fairly significant improvement that doesn't spaghetti the code, then maybe we can get those changes into the package and inspire some further investigation into other aspects such as threading.
     
  27. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    Last night I shifted over several components to make uniblocks multithreaded. I saw significant improvement. Threading is not a nightmare, it is just that it separates the men from the boys in programming. Threading is actually quite simple as long as you are managing your threads properly and not making cross thread operations with unsafe calls. People shouldn't be scared of threads so long as they learn to use them properly and do not use unity api calls within threads

    As for contributing, we are right now. This discussion is contribution on how to improve. So far it is met with "no we want to keep it simple". To be honest, I'm actually OK with that. I feel happy that I can get uniblocks to run a lot faster and have advantage over everyone else.

    Either way, yes uniblocks even as it is now is still a great starting platform and I thank maap for creating this even if I do rewrite half of it. I have learned a lot through this asset and I think maap is an awesome guy for making this asset. :)
     
  28. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    I didn't say that 'threading is a nightmare', I said that changing an existing engine that wasn't designed for it to support threading is a nightmare. I've tried it on many and there are always weird, very hard to explain problems - and I have to spend a great deal of time fixing all kinds of hard to debug bugs.

    I wrote my own voxel engine and it does everything in a threaded way - terrain calculations, mesh building, lighting, saving/loading, you name it. And I have very few issues with it because I designed it this way to start with.

    I've also purchased Uniblocks, so I have a good idea of its layout - but I tend to buy voxel assets just to see new perspectives, rather than to build off of them. My attempt at multithreading Uniblocks did not go nearly as well as multithreading the engine I built with threading in mind from the start, I'll say that.
     
    Stone-Legion likes this.
  29. RawLionWorkshop

    RawLionWorkshop

    Joined:
    Jan 29, 2014
    Posts:
    206
    I'm definitely not saying that I don't want to work on improving performance! In fact pretty much every major update so far has included some performance improvements, including some suggested by the users. I simply answered the questions you asked as honestly and directly as I can. Why is the engine not perfectly efficient? Mostly because writing perfect code takes a lot more time.

    I'm always open to suggestions, but please understand that actually applying them can difficult and take time, and realistically I won't be able to do huge changes such as rewriting the whole engine to support threading anytime soon (yes, ideally I should've written it that way from the start, but it's too late to worry about that now... I'm not ruling it out in the future, but it's not something that I can just do in a few weeks of my spare time).

    If you have suggestions that improve performance significantly, are easy to implement and don't make the code too messy, then you're very welcome to share them and I'll do my best to add them in.


    By the way, if your FPS drops below 60, increasing the target FPS setting (in engine settings) to something above 60 (for example, 70 or 80) should help. The actual FPS in practice is generally lower than the target FPS.
     
  30. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    If you could get RebuildMesh in the ChunkMeshCreator to be threaded and use a thread queue management setup, you will see huge performance increase. Right now you can't put that in a coroutine because it will take forever due to fps limit unless your computer is running 400fps. Just assembling those meshes before you even get to applying it to the meshfilter is a long task and cycles through 4096 items per chunk. Look at CreateFace, now multiply that by 4096 - that is a very costly operation because of the amount of times the lists are being resized with Vertices.Add, SolidColliderVertices.Add, UVs.Add, FacesList.Add, SolidColliderFaces.Add - these lists are being resized 4+ times each voxel in your current setup. All of this is happening on the main thread for every chunk and as I said, you can't really put this on coroutine unless you want to wait a long time for your chunk mesh to be ready. Hence moving these operations to a dedicated thread - but that would require a rewrite on how you check for voxels because there are some Unity API calls in there that cannot be used in a thread and your script kind of goes pretty deep from one chunk to chunk neighbour just for voxel data.

    I've put together a hack job of this, it was really fast but I have bugs to sort out because of so many cross calls creating issues and for some odd reason creating index out of bound errors. I create the UV list with a thread queue and once the thread is complete, on main thread from chunk I call UpdateMesh(Mesh mesh). For some reason " mesh.uv = UVs.ToArray();" says the uv array size is too large or out of bounds, very odd it only happens on some chunks about 40% of the time.

    Anyway, maap if you do get into threading, make sure things are thread safe. I would recommend you have a a dedicated thread manager and let the chunks add work to the thread manager queue with an option to set how many threads you want working - Unity also limits how many threads can be used. Thread manager constantly checks for new work, starting new threads within a user defined limit and removing completed jobs when they are marked IsDone. The chunk checks the job during update for IsDone on the job, if it's done it can use the data process - you can use this for terrain gen and mesh gen.
     
    Last edited: Sep 27, 2015
  31. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    If you get the message saying that one of your lists (uvs, vertices, etc) is out of bounds or too large, that usually means that multiple threads are interfering with each other and accessing the same lists for different chunks (or something similar, depending on your set up).

    I suppose you can fix it using locks, but I find that to defeat the purpose and make it a lot slower.

    The way I handled it in mine is I only allow a single thread to handle meshes. I've found that the majority of time is spent calculating terrain (3D noise) and lighting, so I put most of the threads onto that and only allow 1 background thread to do meshes since comparatively it's much cheaper.
     
  32. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    Bleh spent the last few hours trying to make ChunkMeshCreator thread safe without cross thread accessing of variables. For some reason it just doesn't want to work. I've removed all unity api functions within RebuildMesh(), made GetVoxelType() thread safe so it doesnt use Unity API anymore. The rebuilt mesh gets applied to meshfilter after the thread is done and this takes place on main thread since this is a unity api call. The rebuild mesh thread doesn't get queued until all neighbour voxeldata is also complete so that it can calculate all faces properly when checking neighbours. With these changes, still, RebuildMesh() works fine when calling on the main thread, but inside a thread I get problems like "Failed setting triangles. Some indices are referencing out of bounds vertices. IndexCount: 618, VertexCount: 404" and more as you can see in the image below.

     
  33. Endzone

    Endzone

    Joined:
    Dec 18, 2014
    Posts:
    119
    Hey maap, so i recently Updated the Asset and i got it working with my Existing project But for some unknown reason It is Extremely slow apon pressing play it takes almost 20 seconds for the game to Respond and once it does i can walk to the end of the world generation and essentially walk off the edge ..... it was 110% better before i updated it im not sure whats wrong with it or why it might be so slow but, when i imported the updated asset rather then just delete the old uniblocks and put the new one in i didnt want to loose all the blocks ect that i already have so i just replaced the main engine files and a few others that where new / important .. not sure if that was the right way to go about updating it to work with what i already had but thats what i did and as i said it works with no errors at all but its just Extremely slow.... slower then before i updated .. any ideas why this might be ?
    Edit** I have managed to sort out the issue i Ended up spending a few hours and just re-Applying all the blocks and such ...

    Also just thought i would ask im trying to get different rotations of blocks to face the player depending on how they are placed but useing the code im useing it has a whole heap of issues and this is kinda the only way ive thought of to do what it is im trying to do.. so i was just wondering is their a better way of making rotated blocks face the player when their placed ?


    Code (CSharp):
    1.         public override void OnBlockPlace ( VoxelInfo voxelInfo ) {
    2.  
    3.             Index indexmiddle = new Index (voxelInfo.index.x, voxelInfo.index.y, voxelInfo.index.z);
    4.             Index indexBack = new Index (voxelInfo.index.x, voxelInfo.index.y, voxelInfo.index.z+1);  
    5.             Index indexFront = new Index (voxelInfo.index.x, voxelInfo.index.y, voxelInfo.index.z-1);  
    6.             Index indexRight = new Index (voxelInfo.index.x+1, voxelInfo.index.y, voxelInfo.index.z);
    7.             Index indexLeft = new Index (voxelInfo.index.x-1, voxelInfo.index.y, voxelInfo.index.z);
    8.  
    9.             if (voxelInfo.GetVoxelType ().VTransparency == Transparency.semiTransparent
    10.                 && voxelInfo.chunk.GetVoxel (indexBack) != 0) {
    11.                 voxelInfo.chunk.SetVoxel(indexmiddle, 41, true);
    12.  
    13.             }
    14.  
    15.             if (voxelInfo.GetVoxelType ().VTransparency == Transparency.semiTransparent
    16.                 && voxelInfo.chunk.GetVoxel (indexLeft) != 0) {
    17.                 voxelInfo.chunk.SetVoxel(indexmiddle, 43, true);
    18.                
    19.             }
    20.  
    21.             if (voxelInfo.GetVoxelType ().VTransparency == Transparency.semiTransparent
    22.                 && voxelInfo.chunk.GetVoxel (indexRight) != 0) {
    23.                 voxelInfo.chunk.SetVoxel(indexmiddle, 42, true);
    24.                
    25.             }
    26.  
    27.             if (voxelInfo.GetVoxelType ().VTransparency == Transparency.semiTransparent
    28.                 && voxelInfo.chunk.GetVoxel (indexFront) != 0) {
    29.                 voxelInfo.chunk.SetVoxel(indexmiddle, 44, true);
    30.                
    31.             }
    32.  
    33.         }
     
    Last edited: Oct 4, 2015
  34. RawLionWorkshop

    RawLionWorkshop

    Joined:
    Jan 29, 2014
    Posts:
    206
    I had similar issues before, and if I remember correctly it had something to do with the temporary lists (of vertices/faces) not being reset properly before a mesh rebuild. In your case it could be something completely different, but I can't really help any more than that, sorry...


    I think there are some problems with the script execution order that can cause the game to freeze when you first run it, because it starts loading chunks before the target framerate settings are actually applied. It works fine most of the time but sometimes it doesn't, for some reason.

    If this happens, you should be able to fix it permanently if you change the script execution order (edit -> project settings -> script execution order) so that the Engine and ChunkManager scripts are executed before the ChunkLoader.

    Probably the easiest way would be to do a raycast from the player to the block's center whenever the block is placed.
    The raycast can return a normal, which basically tells you which direction the face that was hit is facing. You can then use that to determine which face the player was looking at and set the appropriate block (a standard 6-way if check checking all possible normal directions should be okay for this).
     
  35. RawLionWorkshop

    RawLionWorkshop

    Joined:
    Jan 29, 2014
    Posts:
    206
    IMPORTANT NOTICE
    I will be away for about a month, that is until around 6th of November. In this period I will most likely not be able to answer questions, or I will answer much later than usual. This applies to both forum posts and e-mail.

    You can of course still post questions, just please keep in mind that it might take me several weeks to answer.

    Thank you for patience and understanding.
     
  36. Endzone

    Endzone

    Joined:
    Dec 18, 2014
    Posts:
    119
    Hello, So i know maap's currently Away but i have ran into a small problem and was wondering if anyone has ever had the same problem and if so how do i go about fixing it ,
    So ive Created a script with roughly 4 Coroutines that play one after another to update a block and for some reason if i place more then 8 or so of the blocks with that script within a chunk it makes the whole chunk pretty much loose connection with its mesh collider asif their was no collider attached to it at all if i walk onto the chunk that has the error i fall though the world, Also if their is Any Semi-Transparent blocks within the area that the Error occurs such as Leaves they all Disapear.. the only way ive found to fix the error at runtime is to break the last block that updated that caused the error im not exactly sure whats going on i reproduced the problem a bunch of times and checked the mesh collider on the chunk and that seemed fine every time.. The blocks im useing are custom meshes i dont know if this matters but just thought i would let yous know just incase it does..
     
  37. Firlefanz73

    Firlefanz73

    Joined:
    Apr 2, 2015
    Posts:
    1,316
    Hello,

    did anybody find a good solution to the Problem, if you build something in your body's collider, sometimes you get stuck and cannot move, but most times you get kicked high in the air and never come back?

    Thanks and have a nice Weekend!
     
  38. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    I could try to help if I could see some code, but I don't know exactly what's going on there (assuming you haven't solved it yet).

    I make an attempt to prevent blocks from being placed within the character collider. One thing you can do is figure out which block the player's head and legs are in, and if the block position matches that of the one being placed, disallow it from being placed.

    However, you can still get stuck in some rare situations if the player is really trying to, so I put in an additional safety measure:

    If the player does end up inside of a solid block, that block will simply get destroyed. That pretty much guarantees you can't get stuck, I've found.
     
    Firlefanz73 likes this.
  39. Endzone

    Endzone

    Joined:
    Dec 18, 2014
    Posts:
    119
    Hey thanks for Help i still have not solved this problem yet i have no clue what the problem could be .. i thought it may had something to do with the Amount of Coroutines i was using but it turns out that was not the case i put everything into one Coroutine and its still doing the Exact same thing ... ive also changed my mesh just incase it had something to do with that, it was 4 submeshes joines together but ive since re-modelled it into one and that still didnt fix anything...
    Hears the code im using to do the Updates with..

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. namespace Uniblocks {
    4.    
    5.     public class CarrotGrowthEvent : DefaultVoxelEvents {
    6.  
    7.         public override void OnBlockPlace (VoxelInfo voxelInfo){
    8.  
    9.             Index indexmiddle = new Index (voxelInfo.index.x, voxelInfo.index.y, voxelInfo.index.z);
    10.             ushort voxelmiddle = voxelInfo.chunk.GetVoxel(indexmiddle); // get voxel above
    11.             VoxelInfo blockmiddle = new VoxelInfo (indexmiddle, voxelInfo.chunk);
    12.             Index indexBelow = new Index (voxelInfo.index.x, voxelInfo.index.y-1, voxelInfo.index.z); // get index below
    13.             if ( voxelInfo.chunk.GetVoxel(indexBelow) == 131 && voxelInfo.chunk.GetVoxel(indexmiddle) == 149) {
    14.  
    15.                 CarrotGrowthEvent GrowthEventSeed = Engine.EngineInstance.gameObject.AddComponent <CarrotGrowthEvent>();
    16.                 GrowthEventSeed.GrowthStageSeed(blockmiddle);
    17.             }
    18.         }
    19.  
    20.         public override void OnBlockDestroy (VoxelInfo voxelInfo)
    21.         {
    22.             Destroy (this);
    23.         }
    24.  
    25.         public void GrowthStageSeed (VoxelInfo voxelInfo) {
    26.             StartCoroutine (DoGrowthSeed (voxelInfo));
    27.         }
    28.        
    29.         private IEnumerator DoGrowthSeed( VoxelInfo voxelInfo ) {
    30.             Index indexmiddle = new Index (voxelInfo.index.x, voxelInfo.index.y, voxelInfo.index.z);
    31.             VoxelInfo blockmiddle = new VoxelInfo (indexmiddle, voxelInfo.chunk);
    32.            
    33.             yield return new WaitForSeconds (5.0f);
    34.             if (voxelInfo.chunk.GetVoxel (indexmiddle) == 0) {
    35.                 yield break;
    36.             }
    37.             voxelInfo.chunk.SetVoxel(indexmiddle, 150, true);
    38.  
    39.             yield return new WaitForSeconds (5.0f);
    40.             if (voxelInfo.chunk.GetVoxel (indexmiddle) == 0) {
    41.                 yield break;
    42.             }
    43.             voxelInfo.chunk.SetVoxel(indexmiddle, 151, true);
    44.  
    45.             yield return new WaitForSeconds (5.0f);
    46.             if (voxelInfo.chunk.GetVoxel (indexmiddle) == 0) {
    47.                 yield break;
    48.             }
    49.             voxelInfo.chunk.SetVoxel(indexmiddle, 152, true);
    50.  
    51.             yield return new WaitForSeconds (5.0f);
    52.             if (voxelInfo.chunk.GetVoxel (indexmiddle) == 0) {
    53.                 yield break;
    54.             }
    55.             voxelInfo.chunk.SetVoxel(indexmiddle, 153, true);
    56.             Destroy (this);
    57.  
    58.         }
     
  40. Firlefanz73

    Firlefanz73

    Joined:
    Apr 2, 2015
    Posts:
    1,316
    Thanks Jason!
     
  41. Firlefanz73

    Firlefanz73

    Joined:
    Apr 2, 2015
    Posts:
    1,316
    Hello,

    just an idea, I am also having Performance issues:

    Could the chunks which are far away be created without all Special meshes, so only with the Standard blocks? Would this reduce draw calls then?

    And chunks be re-build when they get closer with all the custom meshes and Special things? Do you think this could make things faster?

    Did you guys have any Progress trying to get the chunk creation into a new thread?


    Thanks a lot!

    Firlefanz
     
  42. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    Anyone who uses uniblocks for anything beyond its default out of box set up will have performance problems. Uniblocks is a great educational tool but is far from complete. If you want to get serious about making it efficient, you will have to rewrite 90% of the entire uniblocks code. Trust me, I've rewritten a huge part of it and it has been a nightmare, I should have just built my own because at this rate that is what I'm having to do.

    I should preface saying that as others have said before, uniblocks was not built with optimization in mind. It was built to be more or less easy to read in code by the novice coder. With that said, regarding threading , threading the terrain generation is not hard and took less than half a day, but threading the chunkmeshcreator and the rest of the chunk loading system is a nightmare because literally everything is so tied together and so filled with what would be cross thread calls, the only way to make it threaded and thread safe is to rewrite the entire thing from the ground up.

    Uniblocks simplicity is also sadly why it fails. It wasn't designed to be efficient in any way, shape, or form and because of this, it was written in complete disregard for unity garbagecollection and has extremely poor memory management; lists and dictionaries are used with complete ignorance of memory management, there is not even any object pooling and every chunk is literally a new game object instantiated and then destroyed. It is extremely inefficient, extremely wasteful on resources, and not a good asset to purchase if you're doing something outside of learning a basic chunk system.

    I thank maap for this asset and I appreciate his hard work and consistency in replying to support requests, but if you're looking for something you might release in your own game then get ready to spend a solid few weeks rewriting the entire uniblocks system. But of course, maybe that is maaps intention - to make this an educational resource, given that he said he would rather make things easier for people to read rather than try to optimize anything.
     
    Last edited: Oct 19, 2015
  43. Firlefanz73

    Firlefanz73

    Joined:
    Apr 2, 2015
    Posts:
    1,316
    Hi Stoney,

    did it help (some Frames) to just put the Terrain Generation into it's own thread and keeping the rest as it is now?
    At this Point I am working on other things than rewriting the Terrain engine...

    If anybody finds something useful or improves something I am willing to Exchange some stuff so not everybody has to rewrite everything on himself from the scratch :)
     
  44. pushingpandas

    pushingpandas

    Joined:
    Jan 12, 2013
    Posts:
    1,419
    Can I create a cube terrain in editor, place objects within? Or will the terrain auto-generated on game start?!?
     
  45. unity007

    unity007

    Joined:
    Jul 17, 2014
    Posts:
    3
    Hi Maap,

    would it be possible to make this plugin work in Unity 4.6 ?

    We are using a specific -very important- plugin in our project that is still not working (compatible) in Unity 5.

    I'd love to start using Uniblocks, the price is no problem, but it would have to work in U4.6. Is it a lot of work to get it going in the older 4.6? What time are we talking about?
     
  46. nuonical

    nuonical

    Joined:
    Feb 28, 2015
    Posts:
    46
    I implemented chunk pooling as well, albeit slightly differently. I spawn a fixed number of chunk objects on game start based on chunk distance, and then reuse those entirely. I removed the Awake function and call an Initialize manually on chunk recycle. And then instead of Destroying the object I UnregisterChunk() it, clear the mesh, then deactivate the GameObject. This works for a while, but after running around for a few minutes I start to get what appears to be either a memory leak, or improper deactivation of a chunk, and the chunks error out and stop spawning.

    The error tends to be around where the NeighborChunks are being assigned. For example, I'll get a null reference here :
    Code (CSharp):
    1. currentChunk.NeighborChunks[d] = neighborChunk.GetComponent<Chunk>();
    Has anyone else run into this? Has anyone successfully implemented chunk pooling? I've tried setting the NeighborChunks to null when the chunk is being recycled, but that doesn't seem to help. Calling mesh.Clear() seems to cause other memory leaks, such as a "Mesh.vertices is too large" error. Grrr. Chunk pooling should 100% already be in this package. I'm quite surprised it wasn't implemented from the start.
     
  47. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    It will help if you have more complex procedural generation outside of the unity perlin noise. I'm using a combination of perlin 3d noise, billow noise, and several other procedural techniques which consume more processing time. It would be insane to have this on the main thread so I've moved terrain gen to a thread pooling system where I can set x amount of threads to run and a manager that cycles through each thread queued to run. When a chunk needs the terrain generated, it adds to the generation thread pool. The chunk checks each Update() for the thread to be done, and when it is, continues to render the chunk with the meshcreator.

    Ah yes, that's what I did too. I have set amount of chunks and if it goes over the limit and requires more, to avoid missing chunks I set it up to instantiate more if required and recycle those as well.


    Assuming you're looking in ChunkManager.cs, if you are receiving null reference for that, make sure neighborChunk actually exists. You get this error because no neighborChunk is being returned from GetChunk(neighborIndex). Not sure if you modified something in here or not.

    Regarding pooling, I do have it working but I had to rewrite a lot and it was pretty painful. The neighborchunk concept caused me huge head aches and to call getcomponent is very wasteful to keep doing. I can only suggest that change uniblocks so you stop passing around chunks like candy and instead just store reference to their index position in a fixed array. Passing int index position uses way less memory and is more efficient. Unity is not friendly to complex data being passed from dictionaries to lists, through methods, etc. It's easier just to stick to basic data types and pass around an index position to an array of chunks in ChunkManager.

    When are you calling mesh.Clear()? You should only call it before you are about to redraw the mesh in UpdateMesh() or if you are clearing it when recycling a chunk, in which case you also want to set the meshcollider.sharedMesh = null.

    I did receive vertices count errors, it likely be a result of RebuildMesh neighbors changing during RebuildMesh. This could happen if you try to put it in a coroutine or in a thread. Because it is a single thread operation, by default RebuildMesh does all the work in one shot. If you have modified RebuildMesh to usea coroutine, when you yield during coroutine then there's the potential for voxeldata in neighboring chunks to change in size as other chunks around are built, causing your vertices list to change when the coroutine starts again and potentially giving you count errors.

    I think, sadly, Unity overall isn't friendly to voxel type procedural games. We're still stuck with .Net 2.0 mono variant with abysmal GC and huge bug list still not fixed in Unity 5.x. Meanwhile Minecraft for Windows 10 takes advantage of latest and greatest libraries, us small time game dev's using Unity get the shaft. Unity is great for pretty games, not great for anything that requires more complexity. Just look at the view distance of Minecraft for Windows 10, think you could ever get this out of Unity? Nope.

     
    Last edited: Oct 21, 2015
    nuonical likes this.
  48. Firlefanz73

    Firlefanz73

    Joined:
    Apr 2, 2015
    Posts:
    1,316
    It would be good if the perforamance would be at least a bit better. :)
    I like it very much now and solved a lot of Problems for my stuff, but Performance got the main Problem now.
     
  49. pushingpandas

    pushingpandas

    Joined:
    Jan 12, 2013
    Posts:
    1,419
    how can I place objects, e.g. NPC in the world if its generated automatic on start?!
     
  50. Firlefanz73

    Firlefanz73

    Joined:
    Apr 2, 2015
    Posts:
    1,316