Search Unity

[OLD-FORUM-THREAD] Ultimate Terrains 1.0

Discussion in 'Assets and Asset Store' started by Amandin-E, Feb 28, 2015.

Thread Status:
Not open for further replies.
  1. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    What I meant is that the included uTerrains shaders can only handle 5 different textures. So if you need more than 5 different textures on the terrain and if you use the included shader, you'll need multiple materials. Of course, if you use your own shader this can be completely different.
    I really think what's missing for your case is the possibility to affect your own UV coordinates. I'm going to add a new function in Voxel-type functions to allow you to set UV of a vertex from its position and normal. This way you'll be able to make what you want ;)

    I know what you mean. This *could* be fine for the first generation, but as soon as player moves I need the chunks LODs to be updated at same time otherwise there would have a lot of temporary holes in the terrain which isn't acceptable of course.

    Thanks a lot! :) Some big things are coming, don't worry ;)

    I'll make it possible to have only one LOD in a future update.

    I see, but what would you need?
     
  2. kaamos

    kaamos

    Joined:
    Aug 6, 2013
    Posts:
    48
    Impressive looking for sure! The grass draw distance looks a bit short though, is there a way to increase that or is it hardcoded into the system?
     
  3. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    This can be adjusted. You can choose on what LODs the grass will be generated and then adjust grass material properties to increase the draw distance. Be careful though: grass can have a big performance cost if you generate too much of it (ie. on too many LODs).
     
  4. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    For me, I would only need colliders as far as the player is able to place blocks. And for me, that would probably be about 10 blocks out. So I don't need nearly as many of them. Of course, though, colliders would have to exist around AI characters as well that could get added. This really isn't a big issue to me in either case, I'm sure there are more important things to work on :).
     
  5. Recon03

    Recon03

    Joined:
    Aug 5, 2013
    Posts:
    845
    how well does this perform for Android??? Also does this work with Skyshop?? Thanks.
     
  6. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Hmm, I don't think you need to do this for my sake since it won't be enough for my usage anyway.

    I wish it was that simple but I do need control over generation of individual chunks. :/ There are other special requirements I didn't mention. For example, since my game is a side-scrolling game with the camera always pointing in roughly the same direction, I need chunks close to the camera plane in a small radius only (for performance), but chunks further away in a larger radius (since with a perspective camera, you can see more further away). Basically within cone-like bounds. Furthermore, there can be more than one focus point. Imagine two characters you can switch between instantaneously with no delay, that can be completely different places in the world. I have handled all this, as well as dependencies between different types of chunks in my own chunk generation system, and I would need the same from the terrain.

    All right. This is no rush for me (many other aspects of the game needs attention too) so I'll keep waiting for a voxel solution that does provide that kind of low level API.

    For now, thanks for the clarifications! I appreciate it. And it does sound like uTerrains will be an excellent solution for most regular use cases.
     
    boysenberry likes this.
  7. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    I'd still appreciate those three functions being added if it's not an issue, as I plan to add teleportation to my game.
     
  8. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    Mobile devices aren't officially supported for now (because of lack of tests). I'm sorry, I haven't tested Skyshop and I'm not sure how it works so I can't answer this question.

    @runevision
    I'm sorry for that. Maybe in the future I'll have more time to think of a low level API without the risk of compromising the internal job, but for now I still prefer to keep it simple in order to be able to add new features quickly.

    @JasonBricco
    All right I'll add needed controls to allow teleportation ;)
     
    JasonBricco likes this.
  9. gracks

    gracks

    Joined:
    Aug 4, 2014
    Posts:
    8
    If I understood you correctly, that sounds non-authoritative. The clients would be sending updates to the server on what they're doing and the server wouldn't be able to verify what has actually been generated around the player. Clients could change the generation parameters at will without the server knowing.

    For example, say a client receives a message from the server telling it to generate terrain with seed #4387. The client could instead generate terrain off a different seed to create completely different world geometry. The server would then ask the client "what seed did you generate your terrain with?" and the client would lie by saying "the one you gave me, seed #4387", and the server would say "ok, sounds fine". Meanwhile, the cheating client's player would be passing through geometry and floating in the air from both the server and a non-cheating player's perspective.

    The server needs to know the full details of the terrain so that it can verify where a player collides with the world, etc. If it just tells the client an initial seed and then trusts the client to do the generation, the server won't be able to keep track of things like which entities have generated where, where collision should happen, and so on.

    Cheating isn't the only big concern, there's also the fact that if your networking is non-authoritative, you have to reconcile disagreements about the state of the world between clients.
     
    boysenberry likes this.
  10. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Not sure what happened, but now every time I try to generate terrain (both by hitting play and in the editor), it just crashes Unity. It gets to the "initialization done, generating terrain, please wait" part and then crashes after that. I am not sure what has caused this. I did delete uTerrains entirely and re-import it at one point because I had messed up the folder structure. And apparently it needs to have a specific structure, so I deleted and reimported it. Then these problems started happening.

    Deleted, and re-imported every single part of the package... still happening. I have no idea what would cause it.

    Edit: Weirdly, when I hit clear to clear the terrain first, it lasted a few seconds longer before crashing. It still ultimately crashed.

    I don't think that it's an error with the settings I've specified... I've specified:

    -0 on all errors and coefficients, for blocky terrain.
    -seams.
    -duplicate vertices.
    -dist to surface = 0.001
    -lod count: 2
    -dist from LOD 2 to 1: 8 (8 on the rest too even though I don't use those).
    -chunks for LOD1/2: 512
    -max LOD with cache/colliders/etc: 1
    -no dynamic/resource loading
    -voxel size: 1
    -threads: 4
    -player is set, chunk layer is set
    -no mesh tangents
    -1 post-build per frame.
    -1 block type: GrassBlock, using a triplanar shader material with three filled, green blue and alpha are empty.
    -1 biome with 2D simplex and 3D simplex, and mountains combiner.
    -unique biome selector for now, only have one.
    -Y capped between 0 and 128.

    And the only code I have is player movement code, camera control code, and block adding/removing so far.
     
    Last edited: May 14, 2015
  11. ghostboxer

    ghostboxer

    Joined:
    Dec 19, 2012
    Posts:
    8
    So first off I would like to say that I am thoroughly pleased with this purchasing this asset. It is simple, and effective.
    I just have one problem though... Biomes... I am kind of lost. What I want to accomplish is to have several biomes, ie: plains, desert, mountain, forest, ect. I tried writing my my own selector.
    Basically I make a vector4 for each biome, with the values used as min and max temperature and humidity
    ie: ( tempMin, tempMax, humidMin, humidMax ).

    I add 2 new 2DGenerators, one for temperature and one for humidity.
    I look at the values2D[1] for temperature and values2D[2] for humidity.
    If the values passed in to GetBiomeId() are between a given biome's climate vector, then it returns that biome's ID.

    all this seems to work fine, but the problem is in generating mountains and plains. I tried making all voxels above a certain y value(150) to be mountainBiome, but this just creates mountains randomly floating in the air.
    and with certain values even the plains biome will create a floating mass over the default example underwater biome.
    I also tried something like this
    Code (CSharp):
    1.    return values2D [0] < plainsThreshold ? defaultBiomeId : mountainBiomeId;
    That gives a little closer to the result Im looking for, but where plain and mountain meet its a sheer drop off.
    I also tried just playing with generators to try and generate mountains and plains in one biome, but I have not found the right combination for it, and It will also require me to write a custom combiner if I want to use different blocks for the plains and mountains. I guess my question is how can I get big plains with sparce mountain ranges, and keep the plains' shoreline at the edge of the underwater biome?
     
    boysenberry likes this.
  12. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Alright, this asset, in its current state, is completely unusable to me. I will wait for a future version before playing around with it some more.
     
  13. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    @gracks
    Ok I understand. I don't see how the server could have a better control over generation though. But I'm not sure if I 100% understand what is an authoritative server. In any game, the client can modify the map to cheat. Let's say with Call of Duty, what would prevent me from having a fake map and telling the server that I'm running a true map? So for example I could remove all walls or whatever.

    To my mind (unless I'm missing something), the server can only check that, for example, when the player shoots he actually doesn't shoot through a wall, by performing a raycast on the server side. And you could do that with uTerrains too. The server could generate the terrain and perform raycasts.

    @JasonBricco
    Most of the time if your terrain makes Unity crash it's because it needs too much memory. Could you send me your scene file so I'll get a look at all settings?

    @ghostboxer
    In the example scenes you'll see that both mountains and 'under water' biomes have the same main noise frequency to have a continuous relief.
    It's hard to give a general rule, but when you define several biomes that depend on vertical coordinate (Y) they should have some parameters in common to generate a continuous terrain (like in the included scenes). Note that this isn't necessarily needed for biomes depending on X/Z coordinates.
    In other words, you should have a 'main' noise that is the same for all biomes and that you'll use to control the main shape of the terrain.
    I'm not sure it's very clear. It's hard to explain.
    It's on my TODO list to add more scene examples and stuff like this in future updates because I agree this can be difficult to combine everything.
     
    boysenberry likes this.
  14. gracks

    gracks

    Joined:
    Aug 4, 2014
    Posts:
    8
    The idea is that the server generates the terrain and authoritatively handles operations on all user inputs sent by the client. If the server can't generate terrain around a non-host player, then it won't have what it requires to act on user input. If the client presses forward and there's a wall in front of him, and you want the server to be in charge of allowing the client's player to move forward, then the server has to know about the geometry that's generated around every player connected to it. The geometry that the client generates around itself is happening in parallel, but all of the input handling happens on the server.

    Yes, that's what I'd like to do, but as far as I can tell, uTerrains can currently only generate around the host player, so it can't handle and validate a connected client's user input because it doesn't know about that geometry -- it has passed the generation seed to the client and left it to do all the generating.

    When I open up a uTerrains scene, inside the uTerrain object there's a reference to a "Player Object" that's set to "First Person Controller". To have authoritative networking, I believe the server would need to be able to generate terrain around multiple Player Objects so that it has all the information it needs to perform validations.

     
  15. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    Thanks for explaining, it's more clear for me.
    Based on that, it seems hard to make an authoritative server for a procedurally generate world as it would need the server to do too many computations for the different players. The only way I see it could be done would be to bake the all terrain (assuming it's not infinite) on the server side in a single big mesh, but you would loose the ability to alter the terrain during the game (ie. it would become static).
     
  16. blueivy

    blueivy

    Joined:
    Mar 4, 2013
    Posts:
    633
    How does Minecraft do it? It seems like they solved the procedural world with multiple players, even though I'm not sure if the world on multiplayer servers is procedural..
     
  17. boysenberry

    boysenberry

    Joined:
    Jul 28, 2014
    Posts:
    365
    I know you're getting a lot of requests for different features, I've even offered a few suggestions already, so I hope this isn't overwhelming.
    Having made a few of my own generators and biome selectors now (still need to get into operators) I am thinking there needs to be something similar for the detail object creation if possible.
    Having the ability to control say the placement and/or other behavioral aspects of voxel details will go along way for bridging the gap to integrating with other assets, imo. In particular having script access at the detail creation point would allow runtime integration with waypoints and EasyRoads3D. It might also allow for splatmap usage and much more.

    I am not sure the technical debt for doing something like that would be for you in uTerrains, but I would imagine opening up that part would be a great ROI freeing you up to focus on developing the terrain, while others work on what they're good at.
    I am having a lot of fun with Ultimate Terrains though making it one of the best Unity assets I own, so thank you again!
     
    Revolution3D and Amandin-E like this.
  18. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    I'm not sure Minecraft servers are authoritative.

    @boysenberry
    I totally agree with you. Details objects system is something I want to improve. ;) I will think of a way to do this.
     
    boysenberry likes this.
  19. boysenberry

    boysenberry

    Joined:
    Jul 28, 2014
    Posts:
    365
    Also, when you're working on crafting more demonstrations, my vote is for two types of demonstrations. The first being both an example of what was already requested, namely use of a base noise that biomes share (maybe using a heightmap for the base 2D/3D map?), and for me, ideally underground as a cave system with entrances (or exits, hehe) leading to the surface, using sane noise settings, of course. And second, even coupled maybe with the example above, good usage of the terrain limits.

    That's my 2 cents :)
     
  20. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    If it helps, it seems the crashing happens when you pair Simplex2D generator with MountainsCombiner, with or without a 3D generator.

    Also, am I not understanding how Simplex 2D works? I figured if I put in a simplex 2D generator with no 3D, I'd just get a 2D simplex heightmap style terrain without caves/overhangs/anything fancy.

    But it seems that things work quite differently in this engine than what I'm used to, because what I instead get is no terrain at all.
     
  21. gracks

    gracks

    Joined:
    Aug 4, 2014
    Posts:
    8
    Minecraft's networking model is authoritative:
    "Minecraft is built using the standard client/server model. The client displays graphical updates to the player, and takes input from the player and passes it to the server. The server maintains the state of the world, and updates with each tick. Without some form of communication, the client has no clue what is happening on the server, and the client goes out of sync." (source: http://www.minecraftforge.net/wiki/Packet_Handling#Why_Use_Packets.3F )

    I modified the TerraVol voxel engine to use an authoritative networking model (using it with the Bolt networking engine asset). It was fairly easy. I decided to not use TerraVol because it wasn't performant enough, both before and after I implemented the authoritative networking. TerraVol also uses Marching Cubes, which does not handle visible poly edge art styles well. uTerrains appears to be the solution I'm looking for, but being able to set up an authoritative server with it is a must in my case, as well as for many others I would expect.

    There are optimizations that dramatically reduce the number of server computations and make the authoritative model performant. For example, you can have the server only keep world chunks immediately around the player in its memory, have the game design reduce the distance at which a player can modify a voxel so that fewer chunks need to stay in memory (which Minecraft does), and adjust the size of a voxel as appropriate (Minecraft had very big voxels but it was also coded in Java and made for older machines).

    Do you think you would be able to implement terrain generation for multiple players? If not, is there a possibility of opening up the dll so I can implement this myself in uTerrains? The asset is so promising and impressive, but without authoritative networking I can't use it for multiplayer.
     
    boysenberry likes this.
  22. blueivy

    blueivy

    Joined:
    Mar 4, 2013
    Posts:
    633
    I plan to have procedural building/structures. is this possible with uterrains?
     
  23. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    @boysenberry
    Copy that ;)

    @JasonBricco
    Get a look at the combiner script and you'll see it needs both 2D and 3D noises for input. However you can make your own combiner that only takes a 2D noise for input (something like: return y - values2D[0] * verticalScale; )

    @gracks
    If I understand well, all you actually need is the possibility to generate small parts of terrain around several players. Sounds possible to me. The only thing is that to keep it simple you'll be able to generate only LOD 1 around players, but in your case this is enough.

    @blueivy
    Yes it is. Theoretically Dual Contouring can render any shape. Nothing prevents you from making a module that generates a building. If you want to create them through the editor (ie. with operations), you may find it quite difficult with the current version, but I'm working on adding more operations to make it a lot simpler ;)
     
  24. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Ah, I was just missing that * verticalScale part there... I really have to get used to this. Thanks.

    If you don't mind, I have another question: let's say I want the generator to place blocky trees. As in, I tell it how to generate a tree out of cubes, but I want this tree to be randomly placed throughout the terrain during generation.

    Is this something I can do? I mean, I don't have access to the generator, so I would have to do it after somehow I would think.
     
  25. blueivy

    blueivy

    Joined:
    Mar 4, 2013
    Posts:
    633
    Last edited: May 17, 2015
  26. ghostboxer

    ghostboxer

    Joined:
    Dec 19, 2012
    Posts:
    8
    Would it be possible to to somehow expose the block's depth in its Y column?
    it would be very useful for layering voxel types, and for making sure caves only generate so many blocks below the terrain surface.
     
  27. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    You mean you'll generate cubical trees out from Ultimate Terrains and then place them on the terrain (like normal trees)? Or do you want to generate voxel trees that will be part of the terrain shape?

    For now there's only the details objects system (the one which is in charge of placing trees). I think it's a bit too basic for what you want to do, but improving the details object system is a priority.

    It isn't possible out of the box because uTerrains doesn't generate voxels by columns. I'll think of a way to add more information like that on voxels but this won't be in the next release (but more probably in the one after the next one).
    However you can determine the approximate depth in modules if you're making mountains thanks to a 2D noise (like in the included scenes) by using the 2D noise value.
     
    blueivy likes this.
  28. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Shouldn't matter, should it? As long as the player can break the individual blocks that make it, and as long as it generates with the terrain without having to be placed by the player, that's all that matters.
     
  29. blueivy

    blueivy

    Joined:
    Mar 4, 2013
    Posts:
    633
    I'm glad you are looking to make the detail object system better! I love this asset so much and you as well @AmandineEntertainment for being so responsive :D
     
    Amandin-E likes this.
  30. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    @JasonBricco
    Given the fact you know how to generate a tree, you can place them a some position by using, for example, a 2D noise. You could generate a tree if the noise value is greater to some value.
     
    JasonBricco likes this.
  31. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    One thing I'd like to understand better is what determines the height of the terrain. For example, I'm trying to make a simple 2D Simplex combiner to keep it simple for the moment using:

    Code (CSharp):
    1. public void Combine(int x, int y, int z, float[] values2D, float[] values3D, out float voxelValue, out VoxelType voxelType)
    2. {
    3.     voxelValue = y - values2D[0] * 100;
    4.     voxelType = mainVoxelType;
    5. }
    However, this leaves open areas:

    Gaps.jpg

    What I realize is that I don't understand what determines the highest point and what determine the lowest point of the terrain.

    I'm used to the column generation method where you just stack blocks up until a height is reached. Obviously, dual contouring is a different thing entirely and I'm not very familiar with it.

    If I understood that sort of thing, I think I could work with this much more easily.
     
  32. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    Your combiner is correct.
    This should not leave open areas, unless you set some terrain limits (in this case, HasMinY and MinY). Did you?

    Sure! Don't worry you'll get used to it and you'll be able to do what you want. I know this can be hard to think this way at the beginning.
     
  33. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Ah, that's it. I set the minimum to 0 and max to 128, again because I'm used to having the world confined to that space. But that's me thinking about it wrongly again. I read that I should set those for performance reasons, but I'm not really sure what to set them to since I don't know how high or low the terrain would go if they weren't set.
     
  34. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    With this combiner:
    Code (CSharp):
    1.     public void Combine(int x, int y, int z, float[] values2D, float[] values3D, out float voxelValue, out VoxelType voxelType)
    2.     {
    3.         voxelValue = y - values2D[0] * 100;
    4.         voxelType = mainVoxelType;
    5.     }
    6.  
    if the values2D[0] comes from a noise like simplex it means it's between -1 and 1, so if you multiply by 100, your terrain is between -100 and 100. Take a little margin though. Let's say -128 to 128.
     
    JasonBricco likes this.
  35. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Alright. Sorry about all the questions; just trying to figure it out. I have two more I have to ask:

    1. Why are we always using values2D[0] or values3D[0], instead of values2D[1] or values2D[2], etc. What does that 0 represent? I noticed in the combiner with two voxel types, [1] is used. Does it relate to different voxel types?

    Edit: I'm guessing it's actually for each module that produces noise. So, say I have this:

    2DModules.jpg

    Then I would use values2D[0] for the 0.005 frequency one, values2D[1] for 0.01 frequency, and values2D[2] for 0.05 frequency? Is that right? It seems that the results I'm getting under that assumption don't seem quite right, though..

    2. How would I go about getting overhangs/caves? I am trying to make a combiner for it, but really am not sure how to go about that with this type of system. The way I'm used to, I would have done some sort of 3D density check like Minecraft does, where if the value of the 3D noise is within a certain range, put air, otherwise put a block.

    Would I have to actually make a generator, not just a combiner?

    Thanks as always.
     
    Last edited: May 19, 2015
    boysenberry likes this.
  36. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Okay, even more to add...

    So, I started trying this and I quickly realized: I have no idea how to set a block somewhere through code. There's a GetVoxelAt function, but is there a SetVoxelAt function? I suppose there's the AddCube operation I could use, although it seems to be rather slow due to not being multithreaded. Just wondering if that's the way I should go or if there's something I'm missing.

    And, one more thing:

    If I walk 1000ish units outward, the shadows start getting jittery and I see gray flashiness on the ground.

    Edit: About those trees...

    So, here's what I did:

    I made a Tree generator, which has this GetValue, which returns a value between 0 and 1 rather than -1 to 1.

    Code (CSharp):
    1. public float GetValue(int x, int z)
    2. {
    3.     float treeVal = (simplex.GetValue((float)x * 0.1f, (float)z * 0.1f) + 1) * 0.5f;
    4.     return treeVal < 0.1f ? 0 : 1;
    5. }
    Low frequency, and I say that if the value is less than 0.1 then return 0, otherwise 1. I did this because I thought that 0 means on the surface.

    Then, I have this tree combiner:

    Code (CSharp):
    1. public void Combine(int x, int y, int z, float[] values2D, float[] values3D, out float voxelValue, out VoxelType voxelType)
    2. {
    3.     float value = ((values2D[0] + 1) * 0.5f) * ((values2D[1] + 1) * 0.5f);
    4.  
    5.     if (values2D[2] == 0)
    6.         StructureGenerator.GenerateTree(x, 0, z);
    7.  
    8.     voxelValue = values3D[0] + (y - ((value * 50) + 40.0f));
    9.     voxelType = mainVoxelType;
    10. }
    I check to see if the value from that tree module is 0, and if it is I call GenerateTree, which generates a very simple boxy tree for the moment:

    Code (CSharp):
    1. int treeHeight = 6;
    2.  
    3. for (int i = 0; i < treeHeight; i++)
    4.     TerrainUtils.SetBlock(x, y + i, z, trunk);
    5.  
    6. for (int i = treeHeight - 1; i < treeHeight + 3; i++)
    7. {
    8.     for (float j = x - 2; j <= x + 2; j++)
    9.     {
    10.         for (float k = z - 2; k <= z + 2; k++)
    11.             TerrainUtils.SetBlock(j, y + i, k, leaf);
    12.     }
    13. }
    And TerrainUtils.SetBlock just calls:

    Code (CSharp):
    1. World.Terrain.OperationsManager.Add(new AddCube(World.Terrain, pos, Vector3.one, voxel)).PerformAll();
    And the result? It tries to generate nearly 7000 trees and crashes Unity with a Stack Overflow exception or something.

    I don't understand why it's trying to generate 7000, though (nor do I understand if I'm even going to get a tree on the surface this way). But when I did this same type of 2D noise with low frequency in my old engine I made, it made far fewer trees than that.

    This leads me to believe I have something seriously wrong in here...

    [Another] Edit: I see that I should queue up all voxel adds first and then call PerformAll() after, whoops. But that doesn't solve the problem of figuring out how to get them to appear only on the surface of the terrain and ... fewer than 7,000.
     
    Last edited: May 20, 2015
  37. Conan-Morris

    Conan-Morris

    Joined:
    Apr 5, 2015
    Posts:
    26
    @AmandineEntertainment

    I know you've been talking about flushing out the details system. Was wondering if you have a timeline for performing operations on details.

    Right now the details generation works great, but once you have a detail in the game you can never remove it. Currently I can chop a tree down, but as soon as the chunk gets regenerated (EG I dig a hole in the same chunk as the tree.) the tree comes back.

    Also, I was wondering if you could explain a bit about how details are placed. Will they only appear on the originally generated surface, or do all voxels potentially have a detail on them, and once they become a "surface" voxel will the detail appear? Just want to make sure trees aren't going to appear in caves I'm digging.

    I noticed that if you dig a whole underneath a tree, the tree follows the terrain down, so I'm assuming the detail only has X and Z coordinates. Is this the case?
     
  38. blueivy

    blueivy

    Joined:
    Mar 4, 2013
    Posts:
    633
    Hey @AmandineEntertainment Some suggestions

    • Ability to tie things to biomes, like ambient sounds, different color grading (ex. jungle biome has one color profile and desert biome has another, i want to be able to blend between them) , time of day change, and vegetation (say one species of tree is found in one biome and another species can be found in another biome) , and also spawning of a certain type of enemy/wildlife.
    • Second is procedural placement w/ some random offset,scaling,and rotation like this asset MegaScatter does.
    • This kind of ties into procedural placement but deeper. The ability to create instances within instances like TerrainComposer. Quote from what I'm talking about
    • But maybe instead of manually placing those instances like the quote describes, have the instances be procedurally placed like you're walking and a house from a pre selected list of houses is placed, and inside different rooms that are procedurally placed. And in those rooms the layout of everything is procedural. The variety here would be HUGE with the right amount of base objects! :D
     
  39. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    Yes that's right.

    You need to use a 3D generator for that purpose. Look at the included scenes and try changing some values in the combiner such as Mountain power / coef.

    That may be a floating point precision issue. I will treat this issue in the future (it's on my road map) but not right now (because of other stuff with higher priority).

    There are only two ways of setting a voxel:
    1. From the combiner. (called during generation - multithreaded)
    2. Through operations. (called on PerformAll - not multithreaded)
    You should never add operations during the generation process (ie. in the combiner like you did).
    I think the best way to generate your trees would be adapt your tree generator so it would work just like the combiner: you set voxel values depending on its position (and noises), but you don't touch to nearby voxels (because you just can't).
    This is another way of thinking and that might not be intuitive, but basically you would have to replace "for" by "if". Could be something like that (not tested):
    Code (CSharp):
    1. if (values2D[2] == 0) {
    2.     // y coordinate must be near the ground, otherwise some trees will float in the air
    3.     Vector3i treePos = new Vector3i(((int)(x / treeDensity)) * treeDensity, (value * 50) + 40.0f, ((int)(z / treeDensity)) * treeDensity);
    4.  
    5.     if (y > treePos.y && y < treePos.y + treeHeight) {
    6.         voxelType = trunk;
    7.     } else if (y >= treePos.y + treeHeight && y < treePos.y + treeHeight + 3) {
    8.         if (x > treePos.x - 2 && x < treePos.x + 2) {
    9.             if (z > treePos.z - 2 && z < treePos.z + 2) {
    10.                 voxelType = leaf;
    11.             }
    12.         }
    13.     }
    14. }
    Also you can see I've also truncated tree positions using "treeDensity" to avoid having too much trees.

    Yes you're right the current implementation only uses X and Z coordinates.

    All voxels can potentially have a detail once they become surface (which is intended). If you want to make sure your caves won't contain any tree, you must use a specific voxel-type when digging on which details are disabled.

    It would be hard to make everyone happy by integrating all this stuff directly in uTerrains. You should actually use specific voxel-types for the different biomes and then use GetVoxelAt at player position to get its voxel-type. From that, you would know on which biome your are and do whatever you want.
    About vegetation, this is already possible by using different voxel-types.

    Very interesting! It gives me some ideas. I don't know if I will have time to release the new details system in the next version but this will come soon enough, don't worry.
     
    JasonBricco and blueivy like this.
  40. blueivy

    blueivy

    Joined:
    Mar 4, 2013
    Posts:
    633
    Oh ok GetVoxelAt will solve my first problem :D and I'm glad I could spur some ideas. The new details system will be awesome I can already tell! :)
     
  41. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Thanks for the info! I'll play around with that.

    Also, because it seems my in-code world setting isn't working, I'm wondering: would it be possible to save prefabs of the terrain types with different settings and instantiate the one I want in order to load it in?
     
  42. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    I am having major issues with the tree generating. The problem is that it will never run this:

    Code (CSharp):
    1. else if (y >= treePos.y + treeHeight && y < treePos.y + treeHeight + 3)
    2. {
    3.         if (x > treePos.x - 2 && x < treePos.x + 2)
    4.         {
    5.             if (z > treePos.z - 2 && z < treePos.z + 2)
    6.             {
    7.                 voxelType = leaf;
    8.             }
    9.         }
    10. }
    for the leaves that branch out into other columns, because values2D[2] won't be 0 there. If it is, it will generate a trunk there as well.

    And I can't find an easy way around this. I even tried hacky things such as setting positions to a hash set, checking to see if they were in there, and if so, place a leaf block like this (full combiner code):

    Code (CSharp):
    1.  
    2. public void Combine(int x, int y, int z, float[] values2D, float[] values3D, out float voxelValue, out VoxelType voxelType)
    3. {
    4.     float value = ((values2D[0] + 1) * 0.5f) * ((values2D[1] + 1) * 0.5f);
    5.     float height = (value * 50) + 40.0f;
    6.  
    7.     voxelValue = values3D[0] + (y - height);
    8.  
    9.     // Still need to make use of the treeDensity values.
    10.     Vector3i treePos = new Vector3i(x, height, z);
    11.     int limit = treePos.y + treeHeight;
    12.  
    13.     if (values2D[2] == 0) // Place a tree if 0.
    14.     {
    15.         if (y > treePos.y && y < limit)
    16.         {
    17.             voxelType = trunkType;
    18.             voxelValue = -1; // I put -1 here because otherwise, it seems that it takes it as being in air and doesn't draw it.
    19.             return;
    20.         }
    21.         else if (y == limit) // Check against limit, so we only run this 1 time.
    22.         {
    23.             // Loop through positions and put them in 'leafSpots' hash set.
    24.             for (int i = x - 2; i < x + 2; i++)
    25.             {
    26.                 for (int j = z - 2; j < z + 2; j++)
    27.                     leafSpots.Add(new Vector2i(i, j));
    28.             }
    29.         }
    30.     }
    31.  
    32.     if (y >= limit && y < limit + 3)
    33.     {
    34.         Vector2i pos = new Vector2i(x, z);
    35.         if (leafSpots.Contains(pos)) // If the leaf is in the hash set, then put a leaf here.
    36.         {
    37.             voxelType = leafType;
    38.             voxelValue = -1;
    39.  
    40.             if (y == limit + 3)
    41.                 leafSpots.Remove(pos);
    42.  
    43.             return;
    44.         }
    45.     }
    46.  
    47.     voxelType = groundType;
    48. }
    Very hacky, and it doesn't work quite right. I get this kind of thing with missing block faces (filler prototype textures):

    TreeProblems.jpg
     
  43. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    Yes it should work like any other prefab. Honestly I've never tested to make a prefab from a terrain but I don't see why it would not work. Please let me know if there is any issue. I'll look at your in-code setting issue very soon.

    You're right! My mistake.
    Your other approach is interesting but you can't be sure on which voxel will be generated first, so that might not always work and I think this is why you're having empty faces.

    I think what you need is your values2D[2] to be the same in some little areas where you place trees. If values2D[2] had a granularity greater than the size of a tree, that would solve the problem.
    In order to do that, you have to make your own 2D generator such as this:

    EDIT: wrong! see message below!
    Code (CSharp):
    1.  
    2. public float GetValue (int x, int z)
    3. {
    4.    float treeVal = (simplex.GetValue(((int)System.Math.Round((float)x / treeDensity)) * 0.1f, ((int)System.Math.Round((float)x / treeDensity)) * 0.1f) + 1) * 0.5f;
    5.   return treeVal < 0.1f ? 0 : 1;
    6. }
    7.  
    And your combiner would look like this:
    Code (CSharp):
    1. if (values2D[2] == 0) {
    2.     // y coordinate must be near the ground, otherwise some trees will float in the air
    3.     Vector3i treePos = new Vector3i(((int)System.Math.Round(x / treeDensity)) * treeDensity, (value * 50) + 40.0f, ((int)System.Math.Round(z / treeDensity)) * treeDensity);
    4.     if (y > treePos.y && y < treePos.y + treeHeight) {
    5.         voxelType = trunk;
    6.     } else if (y >= treePos.y + treeHeight && y < treePos.y + treeHeight + 3) {
    7.         if (x > treePos.x - 2 && x < treePos.x + 2) {
    8.             if (z > treePos.z - 2 && z < treePos.z + 2) {
    9.                 voxelType = leaf;
    10.             }
    11.         }
    12.     }
    13. }
    Again, I haven't tested but I think that's the right way :)
     
    Last edited: May 20, 2015
  44. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    Wait. No, that won't work.

    This will certainly be better:
    2D module:
    Code (CSharp):
    1. public float GetValue (int x, int z)
    2. {
    3.     int rx =(int)System.Math.Round((float)x / treeDensity);
    4.     int rz =(int)System.Math.Round((float)z / treeDensity);
    5.    
    6.     // add some irregularity (uncomment these lines)
    7.     //int displacement = (int)simplex.GetValue(rx * 0.1f, ry * 0.1f) * 5; // trees won't be aligned thanks to that. You can change '5' to some other value but always lower than treeDensity
    8.     //rx += displacement;
    9.     //rz += displacement;
    10.    
    11.     if (x == rx && z == rz) {
    12.         return 0; // trunk
    13.     } else if (x >= rx-2 && rx <= rx+2 && z >= rz-2 && rz <= rz+2) {
    14.         return 1; // leaf
    15.     }
    16.     return -1; // nothing
    17. }
    In the Combiner:
    Code (CSharp):
    1. if (values2D[2] == 0) {
    2.     if (y > height && y < height + treeHeight) {
    3.         voxelType = trunk;
    4.     }
    5. } else if (values2D[2] == 1) {
    6.     if (y >= height + treeHeight && y < height + treeHeight + 3) {
    7.         voxelType = leaf;
    8.     }
    9. }
     
    boysenberry likes this.
  45. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    That created a whole lot of leaves and no trunks, using the exact code:

    Monosnap 2015-05-20 13-41-53.jpg

    This is quite difficult!
     
  46. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    @JasonBricco
    Hm.. what's your treeDensity value? Try to change with this in the 2D module:
    Code (CSharp):
    1. int rx =(int)(System.Math.Round((float)x / treeDensity) * treeDensity);
    2. int rz =(int)(System.Math.Round((float)z / treeDensity) * treeDensity);
    And also, use Mathf.Approximately instead of == 0 or == 1 like this:
    Code (CSharp):
    1.     if (Mathf.Approximately(values2D[2], 0)) {
    2.         if (y > height && y < height + treeHeight) {
    3.             voxelType = trunk;
    4.         }
    5.     } else if (Mathf.Approximately(values2D[2], 1)) {
    6.         if (y >= height + treeHeight && y < height + treeHeight + 3) {
    7.             voxelType = leaf;
    8.         }
    9.     }
    10.  
    I agree this is quite difficult. I've never thought about generating specific things like this so I'm experimenting just like you :)
     
    boysenberry likes this.
  47. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Using that and a lower tree density value got it much closer to being correct, although there are still errors - sometimes some missing leaves, or the trunk not lining up quite right.

    This also brings up the question of: what if I want to do other types of things? I may want to generate all kinds of types of structures automatically during the generation process, depending on the biome.

    And this is quite tricky. Is there any way this type of thing could be made a bit easier to work with?
     
  48. Amandin-E

    Amandin-E

    Joined:
    Feb 4, 2015
    Posts:
    451
    @JasonBricco
    I was thinking about a more generic way of adding arbitrary voxels through combiners and I ended up with something like this:
    Code (CSharp):
    1. public class MyCombiner : IFinalCombiner
    2. {
    3.     struct ArbitraryVoxel {
    4.         public float Value;
    5.         public VoxelType VoxelType;
    6.     }
    7.     Dictionary<Vector3i, ArbitraryVoxel> arbitraryVoxels;
    8.     float density;
    9.  
    10.     /// <inheritdoc/>
    11.     public void Combine (int x, int y, int z, float[] values2D, float[] values3D, out float voxelValue, out VoxelType voxelType)
    12.     {
    13.         height = ...
    14.      
    15.         // rx, ry, and rz may be set the way you want. That could be predefined values...
    16.         int rx =(int)(System.Math.Round((float)x / density) * density);
    17.         int ry = height;
    18.         int rz =(int)(System.Math.Round((float)z / density) * density);
    19.      
    20.         ArbitraryVoxel vox;
    21.         if (arbitraryVoxels.TryGetValue(new Vector3i(x - rx, y - ry, z - rz), out vox)) {
    22.             voxelValue = vox.Value;
    23.             voxelType = vox.VoxelType;
    24.         } else {
    25.             // do as usual
    26.         }
    27.     }
    28. }
    You don't even need a 2D module anymore. You simply make a list of arbitrary voxels to make a tree and you use this list each time you want to add a tree. I haven't tested it and I hope the Dictionary won't make it slow but this could be a good generic solution.
    Of course you have to fill the dictionary in the constructor, not during generation.

    In your case you could fill it this way:
    Code (CSharp):
    1. int treeHeight = 6;
    2.    
    3.     for (int i = 0; i < treeHeight; i++)
    4.         arbitraryVoxels.Add (new Vector3i(x, y + i, z), trunk);
    5.    
    6.     for (int i = treeHeight - 1; i < treeHeight + 3; i++)
    7.     {
    8.         for (float j = x - 2; j <= x + 2; j++)
    9.         {
    10.             for (float k = z - 2; k <= z + 2; k++)
    11.                 arbitraryVoxels.Add (new Vector3i(j, y + i, k), leaf);
    12.         }
    13.     }
     
    JasonBricco likes this.
  49. JasonBricco

    JasonBricco

    Joined:
    Jul 15, 2013
    Posts:
    956
    Still working on figuring out the trees, but that seems like the right direction for now.

    Next question: do I have the ability to say that I don't want a particular voxel type to provide a collision mesh, so the player can't collide with it? Example: a flower block, water/lava/etc block, cloud block. I can't think of how given the engine puts the collision mesh on the voxels and I don't have access to that.
     
  50. ghostboxer

    ghostboxer

    Joined:
    Dec 19, 2012
    Posts:
    8
    So I am attempting to make a cave generating setup using something like perlin worms but with simplex. but I am hitting some snags. For the most part this generator works fine, it will produce a small tunnel of an arbitrary length and radius, but the simplex noise I am using to offset the position of the next tunnel segment always returns 0. Basically it finds a starting point, makes a list of vector3i, where each vector increases by 1 on the x axis, and the y and z pull from an offset function that should return 0,1, or -1. But it always returns 0. any suggestions? Im sure the problem is in the offx and offy functions..

    Code (CSharp):
    1. using UNoise.Graphics.Tools.Noise;
    2. using System.Collections.Generic;
    3.  
    4. public class PerlinWorm3DGenerator : I3DGenerator
    5. {
    6.     float frequency;
    7.     int wormLength = 10;
    8.     int wormWidth = 4;
    9.     List<Vector3i> wormShape = new List<Vector3i>();
    10.     SimplexPerlin simplex1;
    11.     SimplexPerlin simplex2;
    12.     SimplexPerlin simplex3;
    13.     bool getNewWorm = true;
    14.  
    15.  
    16.     public PerlinWorm3DGenerator (float frequency, int wormLength, int wormWidth, int seed1, int seed2, int seed3)
    17.     {
    18.         this.frequency = frequency;
    19.         this.wormLength = wormLength;
    20.         this.wormWidth = wormWidth;
    21.  
    22.         simplex1 = new SimplexPerlin (seed1, PrimitiveModule.DEFAULT_QUALITY);
    23.         simplex2 = new SimplexPerlin (seed2, PrimitiveModule.DEFAULT_QUALITY);
    24.         simplex3 = new SimplexPerlin (seed3, PrimitiveModule.DEFAULT_QUALITY);
    25.  
    26.         this.wormShape = new List<Vector3i> (wormLength);
    27.         this.getNewWorm = true;
    28.         GetNewWorm (0,0,0);
    29.  
    30.     }
    31.  
    32.     /// <inheritdoc/>
    33.     public float GetValue (int x, int y, int z, float[] values2D)
    34.     {
    35.         Vector3i inVox = new Vector3i (x, y, z);
    36.         float dist = 0;
    37.  
    38.         if(getNewWorm){
    39.             GetNewWorm (x,y,z);
    40.         }
    41.  
    42.         if(isOnWorm (inVox, out dist)) {
    43.             return dist;
    44.         }else{
    45.             return -1;
    46.         }
    47.  
    48.  
    49. //        return simplex1.GetValue ((float)x * frequency, (float)(y * frequency)*2, (float)z * frequency);
    50.     }
    51.  
    52.     int offy(int x, int y, int z){
    53. //        return 1;
    54.         float fy = simplex2.GetValue (x * frequency, y * frequency, z * frequency);
    55.           if( fy <= 1f && fy >= 0   ){return 1;}
    56.           if( fy < 0.33f && fy > -0.33f ){return 0;}
    57.           if( fy <= 0 && fy >= -1f ){return -1;}
    58.         UDebug.Log ("offy = " +fy);
    59.         return 0;
    60.     }
    61.  
    62.     int offz(int x, int y, int z){
    63. //        return -1;
    64.         float fy = simplex3.GetValue (x * frequency, y * frequency, z * frequency);
    65.          if( fy <= 1f && fy >= 0   ){return 1;}
    66.          if( fy < 0.33f && fy > -0.33f ){return 0;}
    67.          if( fy <= 0 && fy >= -1f ){return -1;}
    68.         UDebug.Log ("offz = " +fy);
    69.         return 0;
    70.     }
    71.  
    72.     public void GetNewWorm(int x, int y, int z){
    73. //        UDebug.Log ("getting new worm.....");
    74.         int lastY = 0;
    75.         int lastZ = 0;
    76.         this.wormShape.Clear();
    77.         if (true) {
    78.             for (int i=0;i<wormLength;i++){
    79.                 this.wormShape.Add (new Vector3i(x+i, y+lastY+offy (x,y,z), z+lastZ+offz (x,y,z)));
    80.                 lastY = y + lastY + offy (x, y, z);
    81.                 lastZ = z + lastZ + offz (x, y, z);
    82.                 UDebug.Log ("added vector " +wormShape[i].ToString ());
    83.             }
    84.         }
    85.  
    86.         getNewWorm = false;
    87.     }
    88.  
    89.     bool isOnWorm(Vector3i v, out float dist){
    90. //        UDebug.Log ("wormShape.count = " + wormShape.Count.ToString ());
    91.         if (wormShape.Count == wormLength) {
    92.             for (int i = 0; i < wormShape.Count; i++) {
    93.                 if (wormShape [i].x == v.x) {
    94. //                if(i==wormLength-1){getNewWorm = true;}
    95.                     dist = v.Distance (wormShape [i]) < wormWidth ? 1 : -1;
    96.                     return true;
    97.                 }
    98.             }
    99.         }
    100.         dist = -1;
    101.         return false;
    102.     }
    103.  
    104. }
    105.  
     
    Last edited: May 23, 2015
Thread Status:
Not open for further replies.