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. Dinrae

    Dinrae

    Joined:
    Dec 19, 2012
    Posts:
    29
    For multiplayer, when a player connect, send the seed block modifications (like you would do with saving), and then, only send block modifications.
    Speaking about saving, anyone got an example of how it would work? I know how to do it theoricaly, but my C# skill prevent me from doing it :/
    The part concerning writing chunks in files really bug me ...
     
  2. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    I keep all of my block info in an integer for now (one byte is block type, remaining three are general-purpose data), so I can very easily serialize what basically amounts to an integer array.
    I also organize my saves with folders, so for chunks it goes:
    saves/world_id/chunks/chunk.x.y.z.dat

    It's pretty easy to write raw byte arrays files, I just use Application.persistentDataPath and File.WriteAllBytes
     
  3. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    938
    Personally, I'd think it is easier to just runlength-compress the chunks and send them over the network this way. I think it is the way how minecraft does it. Keeping track of only the changed voxel could work, but is a lot of housekeeping and when you change something to the world generator, it "corrupts" everyone's world (since you will have a different noise function). In minecraft, I can still visit my world which was generated in the alpha version, but there are no real corrupted things to notice (except the biomes which have been added through development)
     
  4. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    I was planning on having the server be responsible for generating chunks anyway (the client will not generate chunks, but rather wait for the server to serialize chunks to it), so there's very little housekeeping actually (server first says "here's a chunk" and then later says "change this block").

    I have a question, though. It's unrelated. Has anybody else run into major performance issues in rebuilding chunks?
    I'm having a hell of a time trying to optimize my chunk rendering code and it's got me pretty stressed.
    My architecture involves a dictionary of BlockRenderers, so a BlockRenderer is associated with a block type.
    A chunk iterates through every block, looking up the appropriate BlockRenderer and telling it to render that block (and passing the render buffer to render the block into)
    The SolidBlockRenderer basically just goes through each direction, checking whether or not to render the face and copies the face into the render buffer.
    There really isn't much going on here, and yet I've got it taking 20ms per chunk which drops my framerate to 1 FPS (entire columns generate at once, so I've got one column taking upwards of 100ms)

    I'm really hoping there are some stupid mistakes I'm making somewhere.

    I've uploaded the project zip in case anyone wants to take a crack at this - lots of unused cruft, I apologize. Don't want to deal with cleaning it out until I get performance solved.
    https://docs.google.com/file/d/0Bz8yJFw4-_07bkd5LVVBUXBHWXc/edit?usp=sharing
     
  5. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Well, I made some optimizations (turns out the main culprit was Map.GetBlock - so I optimized how chunks are stored), so now it chugs a bit when generating new columns but it's still WAY faster (it dips down to 30FPS when generating new chunks)
     
  6. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    938
    so you are backculling the faces manually? I'd just let the shader handle all that. I think you shouldn't really bother about the rendering when using unity. The only thing (as far as I can see) you should think about is whether you want to use a single material with a texture atlas (the minecraft way) or use a different material for every block type (and maybe use triplanar texturing)
     
  7. Captain Morgan

    Captain Morgan

    Joined:
    May 12, 2013
    Posts:
    144
    Hi guys, i'm currently working on water simulation described in this article http://w-shadow.com/blog/2009/09/01/simple-fluid-simulation/

    My system work fine except case when the water on the plane. Sorry for my English. Here's a screenshot's

    All ok
    https://www.dropbox.com/s/lx8v5gm36373scx/Allok.JPG

    BAD
    https://www.dropbox.com/s/yuh1h3w9hc2d6og/bad.JPG

    As you can see there is some water at the top of block.
    I think i can add some repeat-able jobs like a dirt2grass convertor, and remove the water from the top of block if water value <= minimalStoredWater, and minimalStoredWater should be ~0.002
     

    Attached Files:

  8. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    If you're talking to me, no I'm not backface culling. That would truly be a micro-optimization (and actually, it most definitely wouldn't be an optimization, as constructing the mesh right now takes a lot longer than just rendering the mesh).
    I am still worried about draw calls though, for a semi-reasonably sized draw distance I get upwards of 100 draw calls which trashes my performance on mobile. I'm seriously debating on switching over to a manual GL system though, maybe with some kind of simple wrapper similar to Graphics.DrawMesh, just so I can draw most of the world in a single draw call.

    I'm doing kind of a hybrid approach as far as atlasing. I have one texture atlas, and different materials for different rendering styles. All opaque blocks are drawn with one material, all transparent blocks are drawn with another material, etc.
     
  9. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    I guess you could basically "evaporate" water if the density is less than some threshold, which you could probably do from inside your CA (just remove the water block). Notice that in Minecraft, when you place a block of water, let it spread out, then remove that block, the remaining water quickly disappears, so it's probably doing something similar.
     
  10. Captain Morgan

    Captain Morgan

    Joined:
    May 12, 2013
    Posts:
    144
  11. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Hm... toying around with the idea of porting over the TechCraft engine from XNA. I've looked into it and even got a few classes ported over to Unity (Region and Lighting classes are fully ported over including all supporting classes and structs, and World is partially ported). The only trouble I foresee is rendering, since Unity's rendering doesn't match up well with XNA's rendering, but from what I can tell if I could get it ported it would be a nice step up from what I have already. Seems a lot smoother rendering-wise anyway.
     
  12. Captain Morgan

    Captain Morgan

    Joined:
    May 12, 2013
    Posts:
    144
    Since i use AABB collision detection i think i should add box collider to the solid (not air or water) block around the destroyed block, so that the block particles do not move through neighborhood blocks, but i actualy don't know how to do with block lightning, i think i can combate it by using custom shader
     
  13. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Well, the porting of TechCraft went a lot smoother than I thought it would. Some issues here and there, but I now have a terrain being rendered, so that's something.
    It's got plenty of lighting bugs though, which so far as I can tell were already inherent in TechCraft (judging from the discussions on the CodePlex page). It also is most definitely not set up to generate infinite or even large paged terrain - at the moment everything is generated right at the start.
    I also seem to have grabbed the wrong version of the source code - mine seems to be old. Woops!
     
  14. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Meh, spent a long time trying to make TechCraft support infinite terrain generation.
    Long story short, it's not worth the hassle. I ended up with 10 FPS while generating new terrain, and constant out of memory errors (TechCraft was not even remotely designed to work with infinite terrain, it was designed for small pregenerated areas like Guncraft)

    The good news is I found the Block Engine Demystified articles from Block Story, and will be following those in an attempt to write my own engine (especially helpful since Block Story runs on mobile, and I'm trying to find a solution fast enough for mobile).
     
  15. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Hm, Goldbug, are you there?
    You did the Block Engine Demystified stuff right?

    I'm using your chunks of 32x32x32, and I've run into issues where generating the currently visible world drops my FPS down to 20 (on my PC, I have no doubts it will be even slower on mobile). The chunks are generated on another thread (using ThreadPool.QueueUserWorkItem) so it must be the chunk re-meshing code. Did you encounter any issues with speed of regenerating chunks meshes? Any optimizations for me to consider? Thanks.

    EDIT: Never mind, I think I've got it figured out! Threads to the rescue once again. Basically, I modified my code to allow meshes to be generated on other threads. My mesh buffer class basically just has a flag indicating when mesh data is ready to be copied to the final Mesh. So my chunk generation code first generates the chunk, then generates the mesh data, then sets the flag to true so the main thread performs the final step of copying the lists to the Unity Mesh. My FPS seems to hover anywhere between 30 and 50 FPS now while generating new chunks.
     
    Last edited: Sep 17, 2013
  16. mimminito

    mimminito

    Joined:
    Feb 10, 2010
    Posts:
    780
    Interested in your developments @PhobixGunner, its great to see you are making progress and trying out so many different engines/approaches!

    Ive been using a pre-made Minecraft Package someone developed and posted on YouTube, which is working great so far but needs some optimizations and additions to enhance it further.

    Are you planning on open-sourcing anything?

    Also, this may be of interest:
    http://gamecoderbr.blogspot.com.br/2013/03/voxel-engine-part-3-final.html
     
  17. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    I might open source it... if I do that I'll have to make an effort to keep the code clean though XD

    In other news, looks like I'll be making my own thread pool. I'm getting the occasional slowdown (every second or so) from the thread pool spinning up new threads, so I'll probably make my own that spins up a set number of threads at startup and just uses those from then on.

    EDIT: Hm, I just found something very useful that others may want to know.
    In the creation of my custom thread queue, I found out that the number of threads you have to perform work is very important!
    Actually, the best value will be one less than the number of cores your CPU has (one of those cores is already busy processing your main thread). For instance, I have a dual-core CPU, so for my machine the most optimal setup is one single worker thread. Beyond that, and the CPU must perform task-switching, which definitely has an impact on performance (I get framerate dips, most likely because the main thread has to share a core with the other threads). If I have one single worker thread, I have constant 60 FPS while generating terrain. More than that, and I get progressively bigger framerate dips (at 5 threads, I got dips down to 30 FPS).
    That said, I have changed my thread pool implementation to use SystemInfo.processorCount minus 1 (to a minimum of 1 thread), that way it's optimal for all multicore machines (single core machines will have to settle for task switching, unfortunately)

    EDIT 2: If anybody is curious, here's my custom thread pool implementation. It creates a number of worker threads based on how many cores are reported by the OS, to a minimum of 1 thread. So on my dual core, it creates 1 worker thread. On a quad core (such as a Tegra 3), it would create 3 worker threads.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using System.Threading;
    7.  
    8.  
    9. public static class CustomThreadPool
    10. {
    11.     private static List<Thread> workerThreads = new List<Thread>();
    12.  
    13.  
    14.     private static Queue<Action> workQueue = new Queue<Action>();
    15.  
    16.  
    17.     public static void Initialize()
    18.     {
    19.         int threadCount = SystemInfo.processorCount - 1;
    20.         if( threadCount < 1 )
    21.             threadCount = 1;
    22.  
    23.  
    24.          Debug.Log( "Starting up " + threadCount + " thread(s)" );
    25.  
    26.  
    27.         for( int i = 0; i < threadCount; i++ )
    28.         {
    29.             Thread thread = new Thread( doWork );
    30.             thread.Start();
    31.             workerThreads.Add( thread );
    32.         }
    33.     }
    34.  
    35.  
    36.     public static void Cleanup()
    37.     {
    38.         for( int i = 0; i < workerThreads.Count; i++ )
    39.         {
    40.             workerThreads[ i ].Abort();
    41.         }
    42.         workerThreads.Clear();
    43.     }
    44.  
    45.  
    46.     public static void QueueWork( Action task )
    47.     {
    48.         lock( workQueue )
    49.         {
    50.             workQueue.Enqueue( task );
    51.         }
    52.     }
    53.  
    54.  
    55.     private static void doWork()
    56.     {
    57.         while( true )
    58.         {
    59.             Action action = null;
    60.  
    61.  
    62.             lock( workQueue )
    63.             {
    64.                 if( workQueue.Count > 0 )
    65.                 {
    66.                     action = workQueue.Dequeue();
    67.                 }
    68.             }
    69.  
    70.  
    71.             if( action != null )
    72.                 action();
    73.  
    74.  
    75.             Thread.Sleep( 1 );
    76.         }
    77.     }
    78. }
    79.  
     
    Last edited: Sep 17, 2013
  18. mimminito

    mimminito

    Joined:
    Feb 10, 2010
    Posts:
    780
    Sounds good. Id be very interested to see how your project unfolds. I will open source my modifications once I have completed them, incase others fund them useful.

    Thanks for the Threading code. I will look into using threads soon, the project I am working on uses co-routines only, and there are a few frame dips here and there.

    Adam
     
  19. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Well, yesterday and today I've been dealing with a <sarcasm strength=11>FUN</sarcasm> problem where my chunk generation code eventually just quit working (or rather, it got stuck on one chunk and because I've only got one core for it to run on = 1 worker thread, it never got around to processing any other chunks).
    After some experimentation, I figured it might somehow be due to the code trying to process a chunk that no longer exists (chunk was unloaded).
    I quickly wired up the delete key to delete all currently loaded chunks (forcing chunks around the player to be rebuilt).
    Sure enough, reproducible 100% of the time I could hit the delete key while the chunks were in the middle of loading and suddenly no chunks would load ever again.

    So I made some modifications to my thread pool. Now it takes IEnumerators.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using System.Threading;
    7.  
    8.  
    9. public static class CustomThreadPool
    10. {
    11.     private static List<Thread> workerThreads = new List<Thread>();
    12.  
    13.  
    14.     private static Queue<IEnumerator> workQueue = new Queue<IEnumerator>();
    15.  
    16.  
    17.     private static bool abort = false;
    18.  
    19.  
    20.     public static void Initialize()
    21.     {
    22.         workerThreads.Clear();
    23.  
    24.  
    25.         int threadCount = SystemInfo.processorCount - 1;
    26.         if( threadCount < 1 )
    27.             threadCount = 1;
    28.  
    29.  
    30.         Debug.Log( "Starting up " + threadCount + " thread(s)" );
    31.  
    32.  
    33.         for( int i = 0; i < threadCount; i++ )
    34.         {
    35.             Thread thread = new Thread( doWork );
    36.             thread.Start();
    37.             workerThreads.Add( thread );
    38.         }
    39.     }
    40.  
    41.     public static void Cleanup()
    42.     {
    43.         abort = true;
    44.         workerThreads.Clear();
    45.         workQueue.Clear();
    46.     }
    47.  
    48.  
    49.     public static void QueueWork( IEnumerator task )
    50.     {
    51.         lock( workQueue )
    52.         {
    53.             workQueue.Enqueue( task );
    54.         }
    55.     }
    56.  
    57.  
    58.     private static void doWork()
    59.     {
    60.         while( !abort )
    61.         {
    62.             IEnumerator action = null;
    63.  
    64.  
    65.             lock( workQueue )
    66.             {
    67.                 if( workQueue.Count > 0 )
    68.                 {
    69.                     action = workQueue.Dequeue();
    70.                 }
    71.             }
    72.  
    73.  
    74.             if( action != null )
    75.             {
    76.                 while( action.MoveNext()  !abort )
    77.                 {
    78.                 }
    79.             }
    80.  
    81.  
    82.             Thread.Sleep( 1 );
    83.         }
    84.     }
    85. }
    86.  
    The reason for this is because now I can abort by breaking out of the MoveNext while loop (setting abort to true does this). Cleanup is much more reliable, as it breaks out of both while loops (first breaks out of the MoveNext loop, then out of the while true loop). Before, it sure didn't do a good job of cleaning up threads, as the thread which was stuck on the invalid chunk continued chugging on even though I had stopped the game and called Abort on the thread.

    I then basically did a hacked workaround on my chunks, where the chunk has an Invalid flag. When a chunk is unloaded, the world sets Invalid to true. In all of my multithreaded functions on the chunk, I basically just check if Invalid is true and if so yield break (another benefit of IEnumerators). Now the aforementioned delete key test works as expected: the chunks simply regenerate from scratch, no hangups.

    EDIT: I could also cobble together my own form of task-switching to make things more efficient. The worker thread could grab up to a certain number of tasks, interleaving the processing of each task (calling MoveNext on each one in sequence). Pretty much a similar thing to task-switching, except with less overhead (the CPU doesn't have to save its entire state to switch to another task) and the main thread is left untouched.
     
    Last edited: Sep 19, 2013
  20. Captain Morgan

    Captain Morgan

    Joined:
    May 12, 2013
    Posts:
    144
    I just have 2 function: first function - MainUpdate - call from MonoBehaviour.Update, and second function - BackGroundUpdate - started in background, inside - "while (started)" loop. In each function i get 1 job from separate list (backgroundJobsList, mainJobsList) and execute it. When chunk is destroing, i call ClearAllJobsForChunk function, which remove all matches (compare by chunk position) from this two lists.
     
  21. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Youtube to the rescue!
    I was getting worried about my game's draw calls - was starting to hit the 50s and 60s as my terrain got more complicated (which spells a death sentence on my OUYA as far as performance). I was somewhat mystified because Block Story is using 32x32x32 chunks same as me, and in the articles he mentions that each of those is a draw call - so they couldn't be getting fewer draw calls at the same draw distance. Then I watched Youtube and noticed that the draw distance in Block Story is hardly more than a chunk or two in front of you.
    I didn't want to go that short previously, but seems I'll have to and I'm a lot less worried about it now - heck, the players in Block Story can put up with it, so can my players ;)
     
  22. kenlem

    kenlem

    Joined:
    Oct 16, 2008
    Posts:
    1,630
    I believe the draw distance in MineCraft PE is just a block or two as well.
     
  23. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Just fired up PE to check. This doesn't appear to be the case on my Nexus 7 tablet. Seems to render quite a fair bit farther than Block Story. That said, I'm willing to bet that having low level GL access allows them to manually batch the whole scene together into just a few draw calls.
     
  24. kenlem

    kenlem

    Joined:
    Oct 16, 2008
    Posts:
    1,630
    Interesting... As I recall, I was looking at it on a 4S. I could be wrong. Also, it could adjust the blocks drawn based on frame rate.
     
  25. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Wouldn't be surprised, actually. It does other things like that as well. For instance on my Nexus the tree leaves are transparent, and on my friend's IPhone they are opaque.
     
  26. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Working on lighting now, it's getting there :)
    I have a question about this. I have lighting, and it works for chunks in a given column, but lighting is not continuous between more than one column. Any tips on how to implement this? I thought about going about it like this:

    1.) When light from a column expands beyond the column's boundaries, notify the neighboring column to update its lighting.
    2.) When recalculating lighting, grab and scatter lighting from neighboring columns.

    Does that sound right? Is there a more efficient way to go about this?

    EDIT: Grr, after hacking at this myself I now have a very, very broken lighting system which I'll probably delete. Sigh. This is always the point that I get hung up on the most, I can NEVER seem to create a proper lighting system. It either isn't continuous between chunks, blows up when I try to multithread it, or is the slowest piece of code anyone has ever written. Or a combination of those.
     
    Last edited: Sep 20, 2013
  27. goldbug

    goldbug

    Joined:
    Oct 12, 2011
    Posts:
    766
    The draw distance is configurable. We default it to very short to make sure it works on smaller phones. If you have a nexus 7, you can crank it up all the way, then it is a few hundred blocks.
     
  28. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Couple questions.
    One, how many draw calls is "cranked all the way up", on average? I seem to be topping out at around 50-60, it starts diving down to 20-30 FPS on a Tegra 3, becoming nearly unplayable at 70 draw calls and up.

    For another, I need advice on lighting. I rolled back my lighting engine, so what I have right now is essentially "Minecraft Classic", just straight hard shadows with no light propagation. I have support in there for propagation, but it's disabled right now because I'm trying to figure out the best way to make this work across several columns. How does Block Story handle this?
     
  29. goldbug

    goldbug

    Joined:
    Oct 12, 2011
    Posts:
    766
    On my ipad I move up the view distance to 200 blocks and I get 200-240 draw calls. I don't know how many FPS I can get with that because I have it capped at 30 fps to save battery, which for mobile is very fluid.
     
  30. Captain Morgan

    Captain Morgan

    Joined:
    May 12, 2013
    Posts:
    144
    Hmmm, i have 1234 draw call, and 410 - saved by batching for 1024 chunks, 3 gameobject per chunk (water, decoration, blocks)
     
  31. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Well that's kind of frustrating. I can't seem to get anywhere even close to that on a Nexus 7.

    And what about lighting? Are you going to release an article on that any time soon? :)
     
  32. Captain Morgan

    Captain Morgan

    Joined:
    May 12, 2013
    Posts:
    144
    I have an idea about how to reduce draw calls twice. Since each my mesh has vertexCount < 5000 i can combine N chunks into single chunk, , for example N = 2.
    Each chunk_go has renderer component, but each second chunk is disabled. When i build should draw mesh i inspect my chunk: if chunk is second one, then i get chunk_go from neighborhood chunk, if no - from themselves.

    I have 1024 gameobject, each N go of them is disabled => drawcall_count = prevDrawCall / N;
     
  33. Captain Morgan

    Captain Morgan

    Joined:
    May 12, 2013
    Posts:
    144
    I switch chunk block width from 16 to 32, and switch chunks width from 32 to 16, and now i have the same blocks count, but drawcall decreased 4 times

    Prev: 1234 draw call, and 410 - saved by batching for 1024 chunks, 3 gameobject per chunk (water, decoration, blocks)
    Now: 392 draw call, and 158 - saved by batching for 1024 chunks, 3 gameobject per chunk (water, decoration, blocks)

    Also render time also was decreased from 5.8ms to 1.7ms, that also increase fps from 50 to 210 (looking from Y: 550 down)
     
  34. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Well, I seem to have lighting figured out, finally. No doubt there's some insidious bug hidden in there waiting to rear it's ugly head, but heck Minecraft's got its fair share of those too ;)

    I eventually did this:

    My Scatter function takes a boolean indicating whether or not it's allowed to expand into neighboring columns (I do this to avoid infinite loops of chunks rebuilding each others' lighting)

    When a new chunk generates and calculates its lighting, it will first fill each light cell with either max light if it is touched by sunlight, or min light otherwise. It then initializes the scatter list with each cell (as an optimization, a cell is only added to the scatter list if it has a neighbor with less light than it). It also checks the immediate neighboring light cells on each side belonging to other columns, and adds those to the scatter list.
    It then scatters its lighting (recursively scatters the light list until it has no more cells to scatter). If any cell is scattered into neighboring columns, that neighbor is added to a queue of columns that need to have their light recalculated.
    As I mentioned before, when the neighbor has its lighting recalculated, it performs the same scatter function, except it does not notify neighboring columns to recalculate lighting (otherwise I got infinite loops where two columns kept infinitely notifying each other to recalculate lighting).

    At the moment it appears to be working perfectly. Initial chunks take some time to load, but afterwards they seem to keep up just fine with a pretty fast camera moving through the world, without a single hitch in the framerate.
     
  35. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    938
    I think you are considering the columns a bit too much isolated. What you could try is generate your lighting world-wide (that is, your view distance and loaded pieces of the world) and keep track of what column/chunk meshes need to be update to show the lighting changes. This way, you dont tell a chunk to recalculate it's lighting, but you tell specific lightsources to recalculate their influence. Might save you some headaches, but I'm not entirely sure. I haven't reached that part quite yet.
     
  36. Captain Morgan

    Captain Morgan

    Joined:
    May 12, 2013
    Posts:
    144
    PhobicGunner, i read your post, thought for a bit about it and after that i made some tests. I fill all blocks by 1above some Y point. And i was impressed.
    Before, my lighting generator takes 15 seconds to generate lighting for 256 chunks, 32*32*128 blocks each. After, it take only 4.5 seconds, huge difference, and there is no visible bugs with lighting
     
  37. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    The main problem is that I need to isolate columns to some extent because recalculating lighting is not a very fast process, so I need to recalculate as few columns as possible. I did just make a change where, because I'm recalculating lighting on another thread anyway, I just immediately recalculate lighting for neighbors that need it. Which means lighting bugs fix themselves immediately rather than whenever my worker thead(s) get around to it.
     
  38. Captain Morgan

    Captain Morgan

    Joined:
    May 12, 2013
    Posts:
    144
  39. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Pretty much done with the rendering, terrain generation, world management, etc in my game at this point. Have terrain generation, rendering, loading/unloading (chunks aren't actually loaded or unloaded yet, just dumped from memory and generated from scratch, but save/load won't be hard to add), and lighting (complete with fancy smooth lighting! yay) There are things I can add, but they are unimportant at this point (such as trees and structures)

    Next I'm going to start working on physics. Mesh colliders are too slow, so I'm going to have to go with a self-rolled physics system, probably just basic tile-based physics (separating axes most likely). Won't be that hard, these are not much more complicated than NES-era physics.
     
  40. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Eesh, this physics stuff is getting really complicated.
    I originally just did the simplest thing I could think of: just tried moving separately in X, Y, and Z directions and checking for collision (if collision occurs, don't move in that direction).

    I then scrapped this and tried writing something more robust. I ended up following an article on writing a 2D axis-aligned physics engine (with contact resolution, impulses, friction, etc) here: http://gamedev.tutsplus.com/tutoria...hysics-engine-aabb-circle-impulse-resolution/

    It works fairly well, except I represent each voxel as a separate AABB (for speed, I only test a certain number of voxels around the bounding shape)

    One problem: it's fairly common for the character bounds to get "caught" due to penetration - it penetrates one voxel within some threshold, and ends up catching/sticking on another voxel.
    This seems to happen in other physics engines as well (Box2D I think?). Very annoying.

    I think I might end up with some kind of separate physics system as Unity does - I have my general-purpose Rigidbody component (already done), and then my CharacterController (specialized physics designed specially for characters - probably just simple NES-style physics like I had before)
     
  41. darkhog

    darkhog

    Joined:
    Dec 4, 2012
    Posts:
    2,218
    Anyone has barebones voxel engine? I don't need any generation/chunk management (my game will take place on maps of limited size anyway), just one that does all heavy lifting like CSG of level mesh, etc. Just something where I can set up blocks that can be placed and have setBlockAt(blockID, Vector3 position) function.

    Also function to find out which block and which side of it was clicked.

    //edit: Plus option to set specific block ID as light and set its color.
     
    Last edited: Sep 24, 2013
  42. Captain Morgan

    Captain Morgan

    Joined:
    May 12, 2013
    Posts:
    144
    I just use AABB collision detection, easy to implement and use
     
  43. darkhog

    darkhog

    Joined:
    Dec 4, 2012
    Posts:
    2,218
    How it is related to my question/request? I seriously wonder...

    Also that still doesn't solve mesh optimization of map. Obviously if I do 100x100x100 array of cubes it will lag as hell. But some CSG to remove unneeded faces would help it.

    However I can't do it myself, tried in the past but it always ended in failure - problem is that runtime mesh creation isn't easy in Unity. There are no magic "recalculate normals outside" function (like one in Blender) that would position normals to point outward mesh so you won't get mesh with holes.

    So my head hurt every time I've tried to comprehend it.
     
  44. DavidWilliams

    DavidWilliams

    Joined:
    Apr 28, 2013
    Posts:
    522
    You might be interested in our Cubiquity engine: https://bitbucket.org/volumesoffun/cubiquity-for-unity3d

    Blocks are simply colors rather than material ids though, so it depends how much that matters to you. It's also free but Windows only at the moment. Volume size is limited to 256x256x256. We've got a pretty cool physics demonstration here: http://youtu.be/rhV2dcM4IkE
     
  45. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,350
  46. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Once you get the hang of things it's not that hard. I loop through each solid voxel in my chunk, checking each neighbor (up, down, left, right, forward, backward). For each of these directions, I add a face if the neighbor is air (or transparent). Here is where you would add the normals - if you're constructing the face for Up, for instance, you would just add Vector3.up as the normals for each vertex.
    You do have to watch for winding order - always make sure your triangles are defined counter clockwise (for backface culling, they ignore normals - it's winding order that's important here) - that tripped me up on my first attempt, obvious as it may sound to some...
     
    Last edited: Sep 24, 2013
  47. Captain Morgan

    Captain Morgan

    Joined:
    May 12, 2013
    Posts:
    144
    PhobicGunner, what's about mesh creating time? And what dimension of your chunk?
    I have 1100ms to generate 256 chunks, each have 32*32*128 blocks
     
  48. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    I have 32x32x32, and chunk generation time just for mesh generation seems to be about 20-30ms
     
  49. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    I think I fixed my physics engine :)
    The problem was objects continuously got "caught" between blocks.
    The solution I learned from an article on 2D platformer physics. The idea is to store the surface area of the intersection for the contact (in 3d this is volume rather than area). When solving a rigidbody, you run through each contact and pick the contact with the highest intersection area (volume). You only process that contact.
    Seems to have completely solved my problem - my rigidbody slides around as normal, not catching on anything. Hooray! Now to apply this to create a character controller...
     
  50. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    938
    DavidWilliams I have seen some screenshots you posted lately on the multi material marching cubes terrain. You say you only use voxel colors, no ID's, can you explain a bit more in depth? I currently have a marching cubes algorithm implemented, but I can't get the multi-material part to work properly. I only get half cut-off triangles (depending on how the vertices are positioned) and not such smooth results as yours.
     
Thread Status:
Not open for further replies.