Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

After playing minecraft...

Discussion in 'General Discussion' started by jc_lvngstn, Oct 8, 2010.

Thread Status:
Not open for further replies.
  1. KiwyVoxel

    KiwyVoxel

    Joined:
    Jan 14, 2015
    Posts:
    64
    Hello everyone,

    A quick post to notice you that i am starting a guide on voxel and procedural meshes in Unity. It is still at the beginning, but my goal is to talk about every topic used in my project. It is in english and french.

    You can see it on my blog and on the forum.
     
  2. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    Hey folks,

    I'm currently trying to implement a 2d overhead map of my procedurally generated world. I already managed to do it with the old GUI system (via OnGUI), where I just cycled through the x and z tiles of the player's current y level and the one below it, and used GUI.DrawTexture to draw the upper textures of each block.

    However, I have since then switched to using the new UI system, and I obviously can't just iterate through all the cells to draw textures anymore since everything is RectTransform-based. So I now create a big Texture2D via script and fill it with the cell top faces, using GetPixel, SetPixel and so on. It is slow and also creates a memory leak because every time the player adds & destroys blocks in the level, the map texture has to be accessed and updated (RAM usage goes as high as 3.5 gb).

    tl;dr: How are you people doing the overhead maps?
     
  3. Zuntatos

    Zuntatos

    Joined:
    Nov 18, 2012
    Posts:
    612
    @Cherno No idea on the proper way to do that besides a secondary ortho camera, but your leaky memory should be easily fixed by keeping the color[] array after setting it, and re-using it when you update the map instead of pulling a new array in via GetPixels(). Performance can be improved by using the SetRawData methods as well, but they require byte-wise editing of pixels which may not strike your fancy.
     
  4. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    Thanks for the suggestion. I already started improving the performance of my map generating script through re-use of variables and using GetPixels instead of GetPixel. It has cut down on the generation time.
     
  5. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    @Cherno
    As far as i know there really is only two ways to go about it.
    1) The way you are doing it, with some obvious care to avoid memory leaks and such. But sounds like you are on a solid path to what you want.

    2) As Zuntatos said, a secondary camera place overhead looking down. Does not have to be orthographic, though im my opinion ortho does look batter for a directly top down view. Though 3d looks nice if instead of straight down you are offset by about 30-45 degrees based on preference.
     
  6. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    I'm currently experimenting with an overhead camera for the map, I'm planning to use RenderToTexture with a ReplacementShader. The reason I originally went for the bitmap route was because I want to draw blocks that have walls different than how they would appear from the camera's perspective (which would be either their topside texture or not at all, if the face is not rendered).
     
  7. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    Hey @Cherno

    Below are two images of what it a minimap with a secondary camera can look like. The first is a smaller "minimap" version, and the second is the enlarged map version just to give you an idea.


    minimap.png largemap.png
     
    GibTreaty likes this.
  8. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,472
    Incredible thread. I wish I should participated more earlier. I want to join this and create own world like minecraft.

    So, unity is suitable engine for this purpose? I read someone pointed out that unity's mesh system store values by float type, rather than byte which is enough for block's mesh data, is this solved at Unity 5?

    Any comments on this problem?
     
  9. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    I can't comment on this problem but Unity is definitively capable of a Minecraft-like procedural mesh generation. We have to keep in mind that Minecraft is optimized and written speicifically for that game, while Unity is a one-size-fits-all game engine, so some things might be a little bit slower, but at the same time you have many more features on your hands.
     
  10. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    Hey,

    Ok, so lately I have been thinking about how I am storing my BLOCK_DATA. Right now its in a circular flat array.
    This works really great.... but i was thinking of a twist on how to handle things.

    Right now the way I figure out a pointer to a block in a flat array, is like pretty much how everyone else i have seen does it.
    Code (CSharp):
    1. wx &= _viewWidthMask;
    2.         wz &= _viewWidthMask;
    3.         wy &= _viewHeightMask;
    4.  
    5.         return (((wx << _viewWidthShift) + wz) << _viewHeightShift) + wy;
    Doing it like this fragments the data for a chunk across the array (except on the Y axis, these are grouped up together for the x,z location).

    This isn't a problem generally, no bottle neck or nothing, and it works rather well. However with a chunk being fragmented across an array you can not use Array functions to grab/alter/etc anything other then a range of Y blocks.

    So what if instead you did something like this.
    Code (CSharp):
    1.     int getPointer(int x, int y, int z)
    2.     {
    3.         int cx = (x >> _chunkWidthShift) & _viewChunksWidthMask;
    4.         int cy = (y >> _chunkHeightShift) & _viewChunksHeightMask;
    5.         int cz = (z >> _chunkWidthShift)& _viewChunksWidthMask;
    6.         x &= _chunkWidthMask;
    7.         z &= _chunkWidthMask;
    8.         y &= _chunkHeightMask;
    9.      
    10.         int chunkPTR = ((((cx << _viewChunksWidthShift) + cz) << _viewChunksHeightShift) + cy);
    11.         int blockPointer = (chunkPTR << _chunkSizeShift) + ((((x << _chunkWidthShift) + z) << _chunkHeightShift) + y);
    12.         return blockPointer;
    13.     }
    Now i have not tested this yet, so maybe it makes calculating a chunk pointer to slow... but outside of chunk generation Im not finding individual access to blocks to be a slow point, at all.

    Yes, it does add some additional calculations to calculating a pointer to a block, but it should now put blocks in the array grouped initially by chunk, which would allow you to use Array functions to copy, clear, etc entire chunks at a time. You could also thin this function down a little more but i wrote it this way to make it easier to follow.



    Why would this be useful? Mainly for my fluid simulations. In order to properly simulate the fluid movement i need to have a second array where i store all the changes from fluids, and then apply those changes back to the main array. Being able to move chunk segments in and out of a larger array makes this trivial.

    Doing it this way also has a few added benefits.
    • Using a blockPointer you can fairly quickly calculate a chunkPointer (I keep my list of chunks in a flat array as well). Previously you would have to work the block pointer back to get the block coordinates, then use those to calculate the pointer to a block. Now you can simply do a simple bit operation
      chunkPos = blockPos & chunkSizeMask;
    • Given Two Block Pointers you can tell if they are in the same chunk or different chunks quicker as well using the approach above to get the Pointer to the chunk they are in and comparing them.
    • Given the BlockPointer you can calculate the upper and lower bounds of the block belonging to a chunk in the world array quicker as well by using some bit math.
      LowerBounds = (blockPos & chunkSizeMask) << _chunkWidthShift;
      UpperBounds = ((blockPos & chunkSizeMask) + 1) << _chunkWidthShift;
      Note: Technically upper bounds is the first block in the next chunk. The intent is to use < UpperBounds
      not <= UpperBounds in loops.
    I also see having the blockArray ordered this way potentially useful when saving chunks to file, though I haven't fully thought it through yet. But the basic idea is it could make serialization of chunk data simpler if you choose to go that route.


    So has anyone done this, or does anyone have any thoughts on this? I'm about to go and do it now to see what sort of change it has on performance, and ill post back shortly.

    [Edit] Code was wrong for calculating Pointer. I have updated it. I will update the shortened version soon.
     
    Last edited: Nov 11, 2015
  11. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    Ok, So I went and made the changes, and did some simple testing between the two, and the results are not exactly what I expected.


    The test. I simply change my function to get a block pointer as mentioned above. Im using the PerformanceTimer scode (or something like that) that someone posted awhile back for timing. Both test were done on actual builds (non developmental).
    System Specs:
    Pentium Core 2 Quad Core 2.6
    4 GB Ram
    64 Bit Processor & OS (Windows 8)
    Older (dx10) nvidia graphics card 1 gig of ram.

    Standard block Array ordering (x,z,y)
    ---------------------Avg. in ms---Numer of Runs
    Build Mesh:----------26.24-------2665
    Generate Chunk----18.29-------2405
    Generate Feature-----.10-------2056
    Lighting---------------18.17-------2179


    New block Array ordering (chunk, x,z,y)
    ---------------------Avg. in ms---Numer of Runs
    Build Mesh:----------22.51-------2631
    Generate Chunk----13.20-------2411
    Generate Feature-----0.13-------2033
    Lighting---------------12.56-------2185



    As you can see, changing it so that blocks are grouped by chunk, and then x,z,y position seems to of actually made everything FASTER. Now I wasn't expecting this at first due to the increased number of calculation involved in getting a blocks position, but the numbers don't lie. I would assume that this speed increase happens because most of the time you are accessing multiple blocks you are accessing them within the same chunk, or within a neighbor chunk. Which when you order the array the way i have now it means there is less time running around getting memory from the various locations all over? I dont know. Just a shot in the dark.
    Anyone else care to test this?
     
  12. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,472
  13. Techgeek1

    Techgeek1

    Joined:
    Dec 3, 2014
    Posts:
    3
    Been lurking here for awhile now and figured I'd join in on the fun!

    @RuinsOfFeyrin
    I'm quite interested in your results too. Currently I'm using 3D arrays stored in the chunk and throw my chunks in a dictionary (I was kinda lazy on that part). I want to switch over to a single array of blocks. Only reason I haven't is because adding and removing chunks from the array seemed like a pain.

    I really like your idea of chunks being in contiguous sections of the block array. It would make saving and sending new chunks of terrain over the network much simpler.

    I'll see if I can implement something similar after I finish and test my rendering system. I'm currently experimenting with using Graphics.DrawMesh(), frustum culling, and occlusion culling for rendering to see if I can squeeze out better performance and memory usage. Hopefully it will let me have really far view distances (^^).
     
  14. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    @leegod

    The before and after code is in the post that is two above yours. Im using the "standard" way to calculate an block index ID which orders the blocks based on x,z,y positioning in that order. This way puts them "logically" in the giant world array similar to how they would be if the array was actually a 3-dimensional array.

    The "after" code is also in the post two above yours. It still sorts blocks in an x,z,y order, but before doing that takes that is arranging things in chunk order. This is what made the speed improvement.

    @Techgeek1
    Yes, i was really surprised by the outcome, and im hoping someone else can test to see if they have similar results cause my "new" way of calculating a pointer adds in several additional operations, so i assumed it would be a tad slower. Like i said, i can only assume the speed increase is because the data for a chunk is not fragmented across the array, and thus its not running around like a chicken with its head cut off to access the memory.

    I also had my chunks in a dictionary at one point. Seemed like a "good enough" solution at the time. However it occurred to me that it was probably faster to keep chunks in a flat array, just like i was with my blocks. Turned out it was. This then is the basis for re-arranging the ordering of the blocks to be chunk,x,z,y in the block array as well since i could now reference chunks by a pointer similar to accessing blocks, and a chunk pointer * chunk_size allowed me to define the offset in the array.

    Switching blocks over to being in a single flat array was probably one of the BIGGEST speed improvements (tied with bit math for calculating pointer to block). It does seem daunting at first, but it is well worth it.

    Let me know how your tests with Graphics.DrawMesh() are working out. That is my constant struggle is to increase the view distance without KILLING the memory. I'm debating about trying to come up with some sort of hybrid system that use RLE and a circular flat array to accomplish this. Realistically you only need fast access to the voxel data within a certain range of the character. This data i would hold in the array. Beyond that range i was thinking of using RLE to store the data. Slightly slower access to the data, but there should not be many reasons to be modifying individual blocks after generation.


    @ EVERYONE
    So, after doing a lot of reading lately, I've come to find out that one of the presumptions that I, and I assume others took for granted when designing their data structures is actually wrong!

    It is recommended several places out there that your BLOCK_DATA is actually a struct not a class, because structures are allocated on the stack, and not the heap, thus being quicker to search. This is normally true, but there are some exceptions, and the use of a structure in an array is one of them.

    If a structure is in an object that would be allocated on the heap, the structure is also allocated on the heap. This applies to arrays. Arrays are ALWAYS generated on the heap, thus an array of structures are generated on the heap. This also means that structures that are properties of classes are also allocated on the heap.
    Reference: http://stackoverflow.com/questions/...s-stack-allocated-or-sometimes-heap-allocated

    What does this mean? It means that switching from a structure to a class for your BLOCK_DATA "should" have no impact on speed of access. I have not tested this yet, though I intend to later today. What it would have an impact on is memory overhead, since classes have 4-8 bytes allocated for the reference. The slightly additional memory might be a worth the trade off for being able to directly access a block and modify its values.... idk
     
  15. Techgeek1

    Techgeek1

    Joined:
    Dec 3, 2014
    Posts:
    3
    I'm finally up to the testing phase for my new rendering but I've hit a snag... I'm using a compute shader to do the occlusion culling and every time I run it I get "SUCCEEDED(hr)" errors in the console. From what I found online it's the compute shader returning an error code but unity is not giving me the actual error code...

    I narrowed the problem down the lines that allocate the input and output buffers but that's about it. The constants buffer works great though so should be fixable.

    Anyway when I was digging around I noticed something, I can't find any way to debug the actual shader code. Does anyone have experience debugging compute shaders? I can't find much about it.
     
    Monstermash28425R1 likes this.
  16. Zuntatos

    Zuntatos

    Joined:
    Nov 18, 2012
    Posts:
    612
    @RuinsOfFeyrin

    An array of 4000 structs of 12 bytes is one memory area of 48000 bytes plus some bytes overhead from .net objectness.
    An array of 4000 classes of 12 bytes is one memory area of 16000 bytes on 32 bit or 32000 bytes on 64 bit containing pointers to 4000 memory areas of 12 bytes + some bytes overhead per class.

    Small structs (say <=16 bytes, maybe more) in an array will probably always outperform classes when you're iterating over them, as they can be cached (all one area) while the classes can't (up to 4000 possibly random positions in ram).

    Edit: complete rewrite.
     
    Last edited: Nov 18, 2015
  17. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    @Zuntatos

    Hey, thank you for doing the math there, i was to lazy. So it seems the additional memory from switching to a class might actually be substantial, and out weight the benefit of switching them to be a class.

    Im aware it is quicker to search an array of structures than an array of classes, if for no other reason then for a class you have additional look ups to actually get the data. I was just pondering if the slight loss of speed might be worth the trade off for being able to directly edit a blocks data instead of re-assigning structures every time.

    @Techgeek1

    Hey, sorry to hear about your issue with compute shaders. I have not used them, so i have no guidance to give you there. However if they function in the same way normal shaders due (in terms of talking to unity) there is no way to debug them like you would an application through unity or mono.

    Now, i could be wrong, and my brain may be pulling some non-sense it read somewhere and twisting it with something else it read somewhere else, but i think, THINK, that there is a way to debug shaders with Visual Studio.
     
  18. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    Hey,

    I was wondering if anyone had tried storing their block_data strictly using RLE as opposed to a virtual paging system?

    Im wondering what the performance impact is. I would really like to be able to increase my viewable world size beyond what it is now (512x128x512) without taking such a memory hit. My BLOCK_DATA structure is a little on the heavy side (4 BYTES and an Integer).

    Any thoughts?
     
  19. richard-biely

    richard-biely

    Joined:
    Nov 11, 2012
    Posts:
    1
    Hello, I started an open source voxel framework Voxe. If there is anybody interested and would like to check it out / contribute / voxelize, you can find it here: https://github.com/richardbiely/Voxe.

    It sports a lock-free event-driven chunk generation and can really make use of all the power your CPU has to offer.
    The framework is still rather simple and buggy, though :) However, if you help, we will all benefit from it.
     
    JasonBricco likes this.
  20. Master-Frog

    Master-Frog

    Joined:
    Jun 22, 2015
    Posts:
    2,302
    I tried playing Minecraft today and it was boring. Can't explain why. I always liked it before. Seems like the game was more fun when I was more stressed out. Now that I am doing alright, it doesn't appeal to me.

    Also, kinda seems pointless to figure out a way to program your own little Minecraft when there's already Minecraft.
     
  21. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Maybe that's because people aren't programming Minecraft but a different game of the same genre that's inspired by Minecraft. Or they're doing it for coding experience - coding it covers lots of useful areas of programming (math, graphics programming, various algorithms, optimization for example on top of the more standard things: controlling characters, animation, and general gameplay/design.)
     
    Last edited: Dec 21, 2015
    Zuntatos and GibTreaty like this.
  22. GibTreaty

    GibTreaty

    Joined:
    Aug 25, 2010
    Posts:
    792
    I tried making my own voxel engine (posted about it in this thread) to make my own game(s) from it. Although I never completely finished it, I've learned so much about C# like structs and multi-threading.
     
  23. OffThHeezay91

    OffThHeezay91

    Joined:
    Feb 23, 2013
    Posts:
    45
    wow can't believe this thread is still active :D
     
    GibTreaty likes this.
  24. N1warhead

    N1warhead

    Joined:
    Mar 12, 2014
    Posts:
    3,884
    Yeah this is like the longest thread in history I've ever seen in my life (literally).
     
    GibTreaty likes this.
  25. Farelle

    Farelle

    Joined:
    Feb 20, 2015
    Posts:
    504
    I think most here are not programming it to make a game or minecraft :) like seen in this tutorial: http://alexstv.com/index.php/category/voxel-tutorial , which is more about creating terrain algorithms and learning how to work with voxels and creating 3D objects from code aswell as how to apply texture to code generated 3d objects etc.
     
  26. Zuntatos

    Zuntatos

    Joined:
    Nov 18, 2012
    Posts:
    612
    It's definitely a great learning experience to make a voxel engine. Especially proper generating-treeing-loading-saving of chunks in an infinite world combined with actual ingame elements is rather complex. And the optimizing =).
     
  27. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    So this seemed like a good place to get some help with optimizing a cube based building system I've got.

    So this is a system for digging under unity terrain. I use mostly standard cubes. I'm optimizing with a combination of dynamic mesh combining and using a spatial grid to completely disable meshes out of visual range. The mesh combining saves a ton of batching but not on vert/tri counts.

    I also use a higher vert/tri count cube for the top layer, as I deform that to fit the terrain and without the higher resolution it won't fit well and starts to show on top of the terrain.

    The attached pic shows what a combined mesh looks like in the system. I'm looking for a good way to remove all the unnecessary tris from this. If I can do that then this scales pretty well. Currently it's actually good enough for a lot of use cases, this isn't something I'm even trying to make work on mobile anyways and as long as the batch counts are kept low I've found the gpu is pretty good at pushing a lot of tris. Some creative approaches to using the spatial grid and fogging the horizon underground have worked well also. But I'd still like to find ways to get the tri count down.
     

    Attached Files:

    • mesh.png
      mesh.png
      File size:
      392.3 KB
      Views:
      1,104
  28. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    @snacktime
    You have the same image repeated several times across multiple squares. This could be achieved with a single square and having the texture repeat. Depending on your situation this can be achieved with either existing shaders, or you may have to write your own.
     
  29. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Not sure I follow. The selected mesh in the scene is a single mesh, created from combining the individual cubes at runtime. Optimizing the mesh structure at runtime so that it doesn't retain all the tris from the individual cubes is what I'm trying to do. Either by using an algorithm to create the mesh from scratch,or combining first and then reducing the resulting combined mesh.
     
  30. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    @snacktime
    Ill try again. You have multiple faces that are identical. By combining these faces and setting the texture to repeat you will achieve what you want. This is what you are asking about i suppose.

    As far as how to combine them is entirely up to you, and how you have your data stored. It sounds like you know exactly what you need to do. Reduce vertex count by combining similar faces..then use a shader to tile the needed texture across the mesh.

    Look in to greedy mesh algorithm, that could help you, but really it all depends on how you have your data stored.

    Have you tried unities built in Mesh.optimize() ? Im not exactly sure what it does or how well it works, but i know its there.
     
  31. CorWilson

    CorWilson

    Joined:
    Oct 3, 2012
    Posts:
    95
    So on a low cpu performing device, how did you guys deal with updating chunks frequently with as little choppy framerate as possible? For instance, when putting down a block or removing one, with a thread for building behind the scenes, the game lags for a bit while the mesh is applied to the new chunks since you can only apply them upon the main thread. I assume this is just something I have to deal with forever.
     
  32. KiwyVoxel

    KiwyVoxel

    Joined:
    Jan 14, 2015
    Posts:
    64
    This question can be very hard to answer.

    First :
    What kind of meshing technic are you using ? How low of cpu are you talking about ?

    Second :
    The thing is with voxel is that you have to process a huge amount of data. So to have a good framerate you need to do some -or more likely all- of the following things :
    1. Have an efficient meshing technics (ie fast enough and faithful enough for your goal).
    2. Storing voxel value (and probably hermite Data). This is a huge deal in real time modification as you dont want to call your density function every time. But managing your data structure can be a huge bottle neck.
    3. How are your managing your working load ? From the experience i gather in my project. I believe that a real time and realistic voxel based engine is very hard to do with a decente frame rate (ie with enough frame left to actually do game's mechanics after). There is a lot to talk on this subject so i will stop there and answer directly to you question.
    On a low cpu you probably need a quick meshing technique like Boxel. You need to try and choose the best data structure for your case (remember you dont have to have one). Then the easiest choice is probably to use multi-threading as 1 thread for 1 core (wich you may not be able to do if your low cpu is not multi core). On that subject I think that Direct Computing on the GPU is probably the strongest option.

    So why am I talking about all of that when you are directly asking about chunk update ?
    Well the answer is that you have to try multiple technics to choose your best option.
    For my project I dont use any data structure anymore. I raycast the chunks -in a dictionary- to be updated or from player position. And I have nb of cpu -1 threads available to work (i keep 1 for the main thread).
    But there is not only one good option it depends on what you want to do and with what.

    I hope it is helping you. Your question can lead to many others so i tryed to be as abstract as possible.
     
  33. CorWilson

    CorWilson

    Joined:
    Oct 3, 2012
    Posts:
    95
    The cpu has three cores, one that I dedicate solely to the main thread just like you. Process power is 1.2 GHZ per core.

    I guess that's a good enough answer as any. I build my collision mesh using the greedy mesh algorithm, which is why making that is insanely fast, yet doing the same technique for the render mesh is a whole different ball game due to different textures being possible and thus having to dedicate one face to one texture regardless. No matter what, the ideal situation would not ever happen where a chunk that a player is updating will have similar textures, so there's no benefit in implementing that kind of technique. So I suppose finding some technique to make the mesh application process faster is the best bet.
     
  34. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    Pro Hint: We sub divide the world in to chunks because processing the entire world would take to long...
    If building a mesh takes to long...what can we take from how we handle processing the world and apply it to chunks?

    If you cant figure it out don't worry, I will post the answer tomorrow at some point, just consider this a critical thinking exercise.
     
    voltage and Zuntatos like this.
  35. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    Really, no one got it? Sorry i didnt post yesterday i got busy.


    @CorWilson
    Ok, first lets start off by pointing something out. There are actually two separate load times when it comes to rendering a voxel world. Your initial first render of everything, then the subsequent rendering of new/updated chunks.

    You can trade a slightly longer initial render for a faster new/updated render. This is acceptable because the amount of time you will spend at the intial load is far less then the amount of time you will spend loading new/modified chunks.


    So how do we speed things up? Sub divide your chunks even further, and only build the render data for a 16x16x16 region at a time and keep the mesh information stored with the chunk. Then when its time to render the chunk you combine all the sub-chunk mesh information for a given chunk in order to render the mesh. This can be done on a background thread as well.

    For for example say you have a 16x128x16 area. There is 8 sets of sub-chunk data you are storing... Do not store this as a mesh, simply as a List with the valid information. When it is time to render the list of sub-chunks you simply check the length of all sub chunk lists, make a new array of that length, then copy the data from the lists in to the array. This array is now what you need to generate the mesh.

    When you do your initial build it will take slightly longer because you are generating mesh data in 16x16x16 areas instead of the full 16x128x16. However the trade off is when you are updating an area. You only have to run through and update a 16x16x16 area, the rest of the chunk has remained the same and you have your list of data for the other sub-chunks still, so no need to re-process.

    You should see some rather fast updates by changing to this method.

    Also depending on how you have your engine set up to handle chunks being updated, make sure it is always checking the chunk the player is in first, and spiraling out from there. You could in theory have chunks that are loading updating farther away from the player, and in you simply are using an un-ordered que for processing this it could be waiting to process chunks farther away before it modifies the immediate area you changed.




    Hope that helps
     
  36. codeman_nz

    codeman_nz

    Joined:
    Jul 30, 2015
    Posts:
    11
    So does everyone have a block class or block data structure? I found data structures quicker to create so i'm thinking of using them but i like using class references. The issue with classes is that they take too long even if I break the chunk up into sections.
     
  37. codeman_nz

    codeman_nz

    Joined:
    Jul 30, 2015
    Posts:
    11
    Is this thread still going?
     
  38. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    Does 5.4 improve voxel/chunk rendering with Instancing?
     
  39. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Well, since Instancing deals with rendering the same mesh many times, no. Each chunk must be a unique mesh, therefore it will not benefit from mesh instancing as far as I can tell.
     
  40. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,472
    yes
     
  41. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    This thread actually covers that exact answer. The common answer is to use a structure, however if you go back a few pages I was playing around with a class over structures and posted some results.
     
  42. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    What about instancing specific block meshes? As in, you have 1 grass block mesh and use instancing to display that everywhere in the loaded area. You have 1 dirt block mesh, and use instancing for that. Would you achieve 1 draw call per single block type in the world? Would you even need chunks?

    I have absolutely no experience with instancing and with how it works, so I don't know if there would be limitations that wouldn't allow this to work or other technical reasons, nor do I even know if it's possible to do that.
     
  43. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    I thought of that too, but I don't think that's a terribly efficient way to draw chunks, even with instancing. Drawing chunk meshes is very efficient, it's just that *generating* those chunk meshes that can be problematic (on the CPU), though not impossible obviously.
     
  44. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    The only really resource-intensive part is applying the generated mesh to the MeshCollider, and there's not much that can be done to make it faster except using a mesh that is as simple as possible (greedy mesh etc.).
     
  45. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    Or you could do away wish mesh colliders all together and roll your own collision detection which is MUCH faster.
     
  46. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    True. Actually even though it sounds difficult custom physics are actually not that hard, especially if you make simplifications (such as not taking rotation into consideration, meaning you just have to deal with linear velocity).
    There's a wealth of information on the subject, such as this tutorial on writing a 2D physics engine (same concepts apply to 3D physics).
     
  47. RuinsOfFeyrin

    RuinsOfFeyrin

    Joined:
    Feb 22, 2014
    Posts:
    785
    Somewhere in this LONG LONG thread there was some discussion over rolling your own collision detection as well. It has been awhile since i have went over the whole thread so i could not even begin to tell you where it is, but it is there. GOes over swept AABB collision if im not mistaken, and i feel like if you search for Goldbug (was that his name?) in this thread you will find the related information.
     
  48. codeman_nz

    codeman_nz

    Joined:
    Jul 30, 2015
    Posts:
    11
    I need help. Currently I have an infinite terrain but when new meshes are generated it causes a lag. It is very brief but it is there.

    I have broken up the chunk into sections and each chunk and section has a game object. Each section game object has a mesh renderer and they are children of the chunk game object. If a player moves forward into a new chunk then it will move the back chunk game objects to the front and start a thread to generate new vertices. There is a coroutine which is always running and checking the chunk generator thread for sections that have finished generating their mesh data. It then generates the mesh:

    Meshmesh=GetComponent<MeshFilter>().mesh;

    mesh.Clear();
    mesh.MarkDynamic();

    mesh.vertices=Vertices;
    mesh.triangles=TriangleIndices;
    mesh.RecalculateNormals();
    mesh.Optimize();

    Any help would be appreciated.
     
  49. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    I'd say use the Profiler to narrow down where exactly the slowdown occurs (esp. now that the Profiler is available on Personal edition)
     
  50. codeman_nz

    codeman_nz

    Joined:
    Jul 30, 2015
    Posts:
    11
    Thanks. I've used it and it looks like there is a spike in Gfx.WaitForPresent.
     
Thread Status:
Not open for further replies.