Jump to content
  • Advertisement

Low poly terrain

thecheeselover

3371 views

Subscribe to our subreddit to get all the updates from the team!

Recently I've been tackling with more organic low poly terrains. The default way of creating indices for a 3D geometry is the following (credits) :

Image result for opengl shared vertices

 

A way to create simple differences that makes the geometry slightly more complicated and thus more organic is to vertically swap the indices of each adjacent quad. In other words, each adjacent quad to a centered quad is its vertical mirror.

MirrorIndices.thumb.png.adfc5555cdd3e9bff0595a830f893eb8.png

 

Finally, by not sharing the vertices and hence by creating two triangles per quad, this is the result with a coherent noise generator (joise) :

It is called flat shading.



15 Comments


Recommended Comments

I did something similar to this using a ridged-multifractal but I was subdividing roughly equilateral triangles because I was generating a planet based on an icosahedron.  It looked pretty cool from a distance but after ran to the top of mountains I noticed this problem.....When I generated a ridge line, the top would sometimes end up being jagged, like the teeth of a saw, depending on which way the ridge was running relative to the mesh. Subdividing further just made the saw-teeth smaller so it didn't really fix anything.  The way I solved it was as a final subdivision  I would check the values at each corner and the values at their midpoints of the edges and and do a special custom final subdivision based on this information.  If you run into this problem you could try it. 

Share this comment


Link to comment
10 hours ago, Gnollrunner said:

I did something similar to this using a ridged-multifractal but I was subdividing roughly equilateral triangles because I was generating a planet based on an icosahedron.  It looked pretty cool from a distance but after ran to the top of mountains I noticed this problem.....When I generated a ridge line, the top would sometimes end up being jagged, like the teeth of a saw, depending on which way the ridge was running relative to the mesh. Subdividing further just made the saw-teeth smaller so it didn't really fix anything.  The way I solved it was as a final subdivision  I would check the values at each corner and the values at their midpoints of the edges and and do a special custom final subdivision based on this information.  If you run into this problem you could try it. 

It's quite complicated, at least it seems so with words and the paragraph being in English. Any chance of you making a blog post about this so I could understand it more?

Share this comment


Link to comment

This terrain looks amazing. Fantastic work.

I am wondering how you will be resolving collisions for this type of terrain?

Share this comment


Link to comment
2 minutes ago, Scouting Ninja said:

This terrain looks amazing. Fantastic work.

I am wondering how you will be resolving collisions for this type of terrain?

Thanks! :)

 

Hmmm heightmap collision detection already exists, not with the heightmap geometry itself but with the heightmap data. However, it's true that it's for smoother terrain. I guess if you could use that algorithm and modify it to lerp correcly according to the geometry, it would work like a charm.

 

Also, if you have a lot of memory and CPU to spare, you could create triangles for the physics engine for each triangle in the geometry.

Share this comment


Link to comment
54 minutes ago, thecheeselover said:

it to lerp correcly according to the geometry, it would work like a charm.

I would really like to see the implementation when you do it. I do wonder if a character will be able to move safely on the terrain.

I would be really grateful if you can share your finds.

Share this comment


Link to comment
1 hour ago, thecheeselover said:

It's quite complicated, at least it seems so with words and the paragraph being in English. Any chance of you making a blog post about this so I could understand it more?

Here's what I was talking about, but now that I think about it It may not be such a big problem for you since you are using more of a standard mesh than I was.  If I remember when you subdivide, you split the triangles into two halfs and so you can have edges at any 45 degree angle if you subdivide enough.  I was subdividing into 4 parts to keep triangles equilateral.  However on the the final subdivision I had to do something special.  I've kind of abandoned height maps now and have gone to voxels so it's not a big deal any more.

Ridgeline problem.jpg

Share this comment


Link to comment

You should use sinus to get rid of the spikes.

I made terrain the same, with adjustable height only per vertex, not position, the texture will look a bit stretched.

I also made the collision code for the 2 triangles ( note that directX might handle this different then others with different triangle rotation ).

Try making a plane with only 1 vertex point higher then you can see 1 flat triangle and 1 not flat.

Share this comment


Link to comment
1 hour ago, thecheeselover said:

 

Also, if you have a lot of memory and CPU to spare, you could create triangles for the physics engine for each triangle in the geometry.

With my old code I implemented JIT (Just in Time) Terrain for the physics. It' worked pretty well and I simply did ball to mesh collision.  I had to write it myself because I used the quadtree that the fractal functions placed everything in at run time.  I figure for any real game you will need it anyway because you need to hit trees and stuff.  Here's a very old screenshot. I just shaded it with a raw simplex nose that's implemented in HLSL. As such it has horrible aliasing problems, but I kind of fixed it later by playing with the amplitude as you go far away from the camera.  In any case this world was about 1000km in diameter and you could run all over it with these three collision balls, which where were a stand-in for a character....... Not that there was much to see since there was no real shading yet, but it was kind of cool that you could never hit a wall so you could go forever.  It did have a moon and the sun though, and everything orbited. I'm recording all this stuff now for my voxel engine.

NorthPoll-1.JPG

Share this comment


Link to comment
1 hour ago, Scouting Ninja said:

I would really like to see the implementation when you do it. I do wonder if a character will be able to move safely on the terrain.

I would be really grateful if you can share your finds.

I'll add this to my long term todo list.

 

17 minutes ago, the incredible smoker said:

You should use sinus to get rid of the spikes.

I made terrain the same, with adjustable height only per vertex, not position, the texture will look a bit stretched.

I also made the collision code for the 2 triangles ( note that directX might handle this different then others with different triangle rotation ).

Try making a plane with only 1 vertex point higher then you can see 1 flat triangle and 1 not flat.

It was intended to look like a crumpled piece of paper but thanks for the tip. By your last sentence, do you mean 1 shared vertex of a plane that is made of two triangles?

19 minutes ago, Gnollrunner said:

With my old code I implemented JIT (Just in Time) Terrain for the physics.

Do you mean that you added a physics library through JIT or that you created triangles for the terrain's physics on the fly?

 

Nice by the way :)

Share this comment


Link to comment
8 minutes ago, thecheeselover said:

Do you mean that you added a physics library through JIT or that you created triangles for the terrain's physics on the fly?

 

JIT Terrain is just what I called it. It's written in C++ and Direct X.  The thing is, there is no way to store planet sized mesh data on disk, it's just too big. So all the terrain is generated as you move by the fractal functions.  There are actually 2 different sets of data. One for the graphics and one for the physics. The reason is that the graphics model can update a lot slower, say every second or so. Note this is not the frame rate, which is fast because there was not much GPU stuff.  It just means the model of the terrain (i.e. Level of Detail).  If I tried to use it for collision there is the possibly that if something lags you would be building terrain under your feet which is bad news for collision. On the other hand I can update the physics terrain just right around the player and not worry about stuff that he can't touch, so I can do it very fast.   The way it's written there are no race conditions.  It has to update the terrain before you get there, so yes the collision is safe, albeit slightly complex to implement.  There is a system of nested bounding spheres.

Share this comment


Link to comment
5 minutes ago, Gnollrunner said:

On the other hand I can update the physics terrain just right around the player and not worry about stuff that he can't touch, so I can do it very fast.

Cool, I actually never thought that games could do this in a performant way.

Share this comment


Link to comment
2 minutes ago, thecheeselover said:

Cool, I actually never thought that games could do this in a performant way.

I'm not sure which games if any use run-time procedural generation. I assume some do, perhaps No Man's Sky, however from what I gather the planets aren't that large so maybe not.  But there are a lot of space games in the works and some may use it. 

Share this comment


Link to comment

@ Cheeselover : no, just that all planes exist of 2 triangles,

once you have the collision you can add plants and trees.

All very basic stuff

 

Make a GetY( x,y ); function to get the ground position to add things.

Also make a horizontal GetCollision function for if you going to add walls.

Make all level blocks in zones and handle zone changing, so you can have fast collision algorithm

remember to not add items you can grab close to the zone borders, items are also added per zone.

 

Also you can add a water plane for pools.

That is how i made the most basic thing.

 

Making a edittor for this also aint difficult.

I wanto improve it also with the ability to add bridges, very nice.

Only i gave up on all this ( i dont wanto demotivate you ),

it cost to much work while i like to release a simple game first, maybe later i will rewrite everything.

Share this comment


Link to comment

Here is the collision code to get the ground level ( y position )

You have to make 4 lists of weedfields :

Normal weedfield is totally flat, all vertices has the same Y position.

WeedfieldX is exactly the same Y position for all left vertices, also for all right vertices.

WeedfieldY is exactly the same Y position for all front vertices and same for all back vertices.

WeedfieldZ has 3 or 4 vertices with different Y positions.

Once you have this sorted you can use this code :

 

	
//-----------------------------------------------------------------------------------------
float LevelMesh::getGroundLevel( float x , float z )
{
// WeedField ground level
sWeedField*nextwf = firstwf;
while( nextwf )
     {
     if( x >= nextwf->l && x <= nextwf->r &&
         z >= nextwf->f && z <= nextwf->b )
       {
       return nextwf->y;
       }
     
     nextwf = nextwf->next;
     }
	// WeedFieldX ground level
sWeedFieldX*nextwfx = firstwfx;
while( nextwfx )
     {
     if( x >= nextwfx->l && x <= nextwfx->r &&
         z >= nextwfx->f && z <= nextwfx->b )
       {
       float fTempBalance = ( ( x - nextwfx->r ) - ( nextwfx->l - nextwfx->r ) ) * nextwfx->fAbsRScale;
       return XFade( nextwfx->y1 , nextwfx->y2 , fTempBalance );
       }
     
     nextwfx = nextwfx->next;
     }
	// WeedFieldY ground level
sWeedFieldY*nextwfy = firstwfy;
while( nextwfy )
     {
     if( x >= nextwfy->l && x <= nextwfy->r &&
         z >= nextwfy->f && z <= nextwfy->b )
       {
       float fTempBalance = ( ( z - nextwfy->b ) - ( nextwfy->f - nextwfy->b ) ) * nextwfy->fAbsBScale;
       return XFade( nextwfy->y1 , nextwfy->y2 , fTempBalance );
       }
     
     nextwfy = nextwfy->next;
     }
	// WeedFieldZ ground level
sWeedFieldZ*nextwfz = firstwfz;
while( nextwfz )
     {
     if( x >= nextwfz->l && x <= nextwfz->r &&
         z >= nextwfz->f && z <= nextwfz->b )
       {
       float fTempBalanceFB = ( ( z - nextwfz->b ) - ( nextwfz->f - nextwfz->b ) ) * nextwfz->fAbsBScale;
       float fTempBalanceLR = ( ( x - nextwfz->r ) - ( nextwfz->l - nextwfz->r ) ) * nextwfz->fAbsRScale;
       
       if( fTempBalanceFB > fTempBalanceLR ) // Driehoek 1
         {
         float y1 = nextwfz->y3 - ( nextwfz->y4 - nextwfz->y2 );
         
         float fXFadeLFB = XFade( nextwfz->y2 , nextwfz->y4 , fTempBalanceFB );
         float fXFadeRFB = XFade( y1 , nextwfz->y3 , fTempBalanceFB );
         
         return XFade( fXFadeLFB , fXFadeRFB , fTempBalanceLR );
         }else // Driehoek 2
         {
         float y4 = nextwfz->y2 - ( nextwfz->y1 - nextwfz->y3 );
         
         float fXFadeFLR = XFade( nextwfz->y2 , nextwfz->y1 , fTempBalanceLR );
         float fXFadeBLR = XFade( y4 , nextwfz->y3 , fTempBalanceLR );
         
         return XFade( fXFadeFLR, fXFadeBLR , fTempBalanceFB );
         }
       
       }
     
     nextwfz = nextwfz->next;
     }
	return fEndOfLevel; // end of level
}
	 
	

Xfade is something like a + fade * ( b - a );

Driehoek = dutch for triangle.

Share this comment


Link to comment
3 hours ago, the incredible smoker said:

Only i gave up on all this ( i dont wanto demotivate you ),

it cost to much work while i like to release a simple game first, maybe later i will rewrite everything.

This is actually an old blog post from me that was reordered because of a problem with gamedev.net. I'm a actually making a game with a friend. Even though it is ambitious, we try to simplify it down so it can be achieved with the both of us.

 

We're not trying to make an engine, just a rogue-lite procedural vaporwave game. Consider looking at our subreddit if you're interested.

 

Anyway, generation wise, we're doing ok but thank you for the tips :)

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
  • Advertisement
  • Blog Entries

  • Similar Content

    • By Nilmani Gautam
      In this video we will learn to change the blender layout
       
    • By _Flame_
      Hello.
      I'm tring to implement opencl/opengl interop via clCreateFromGLTexture (texture sharing)
          glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
      With such texture I expected that write_imagei and write_imageui would work but they don't. Only write_imagef works. This behaviour is same for intel and nvidia gpus on my laptop. Why is it and why there is no such information in any documentation and in the entire internet? This pitfall cost me several hours and probaly same for many developers.
       
       
    • By Hashbrown
      When importing sprites in Unity, we get a Pixels Per Unit option. The smaller the value, the larger it looks on screen. This is great for very small (50x32px) sprites I download.
      My question is, how can I accomplish this with OpenGL? Should I make the sprite larger in the frag shader? I don't want to scale the game object, I'd like the image to be rendered at the size I need without changing the scale, similar to Unity.
      No code needed, just some suggestions that put me in the right direction. Thanks!
    • By Michael Barth
      Hello there!
      So I want to understand this better. With OpenGL 4.6, support was added to be able to run SPIR-V compiled shaders. I've messed around with it, gotten it to work. It's a little bit more complicated to have to use UBOs for most things now. What I mainly want to know is what the benefits are. So I understand SPIR-V is bytecode, and that it's used by Vulkan and that because it's bytecode, there isn't any worry about wild inconsistencies across GPU vendors. When OpenGL is using SPIR-V, does it also benefit from this?
      Also, does this deal with micro-stutter that's caused by shaders being loaded for the first time using traditional GLSL and shader caching?
      I have some application that uses some really old version of GLSL, like GLSL 120, and I'd been thinking about updating it and properly supporting GLSL 460 compiled to SPIR-V. The application also uses DX9, so I was just curious how updating and using these new techniques with OpenGL 4.6 would stack up against the old GLSL or DX9 methods. I'm not expecting some magic performance benefit, I'm just legitimately curious if it'd be worth it to try.
    • By lawnjelly
      After spending many hours painstakingly attempting to model creatures entirely by hand, I finally discovered (a couple of years ago) the skin modifier in Blender, which is a fantastic quick way to build organic creatures and shapes, especially for the artistically challenged like myself, and also makes rigging a breeze. I thought I would write a quick description for those unfamiliar.
      If you want ultimate control, particularly for a low poly creature, there is no substitute for manually creating polys. However, this can be very time consuming and tedious. If you are instead in a position where you are willing to trade off speed of creation against 'perfect rendering efficiency', or are making medium/high poly models, or models for later sculpting, then one of the options available is the skin modifier.
      Using the skin modifier, instead of modelling the skin by hand you place the joints (as vertices) of a creature to build a kind of skeleton, and allow the skin modifier to automagically generate a skin around this skeleton.
       
      Process
      Typically I start off by creating a plane, then go into edit mode, and merge the vertices to 1 in the centre. Next set up the modifier stack to create the skin. At the top of the stack goes a mirror modifier, because most animals are symmetrical bilaterally. Next goes the skin modifier, which creates a simple box-like skin around the skeleton. Finally add a subsurface modifier to smooth the skin, and make it more organic.
      Once the modifier stack is ready you can begin modelling. In the case of this bird, I started with a top-down view. Select the start vertex (there should now be a 'blob' around the single merged vertex), and create the skeleton by pressing 'e' to extrude and place a new vertex. I did this to place several vertices to create a backbone for the bird. You can then create wings and legs by picking one of the vertices in the backbone and extruding to the side.
      If you follow this process you can form a rough top-down skeleton, it doesn't have to be exact because it is easy to adjust, that is one of the beauties of skin modifier. I find it useful to google pictures of the skeleton of the animal for reference. Next look at side views and adjust the up-down position of the vertices (joints). The legs needed to be going downwards, and the head slightly up. Once I am happy with the basics of the structure, I start to fill it out. You do this by selecting a vertex, then pressing 'ctrl-a' then dragging with the mouse. You can make the skin thicker or thinner at each vertex.
      This can quickly give you a reasonable shape. You can further refine the shape by pressing 'ctrl-a' then limiting to either the x or y axis by pressing 'x' or 'y' before dragging. I used this to give a broad flat tail and wings.  
      Conclusion
      Pretty soon you can build a pretty good model. You can tweak a few things in the skin modifier, especially set a root vertex (e.g. pelvis) can make it easier for later animation.

       
      Skin modifier also makes rigging easy. Once you are happy with your skeleton, make a copy of the whole thing (so you don't lose the original), then choose 'create armature' from the skin modifier. This will create an armature and link it to the mesh so it is ready for posing and animating!
      I also typically choose smooth shading in the skin modifier, then manually add hard edges in mesh edit mode (ctrl-e, hard edge, and use in combination with the edge-split modifier). I also use this to select seams for uv mapping. Note that once I finish the skin modifier version I usually have to do a little tweaking of the polys manually, because there are some things it is not good at.
      Anyway, this has been a brief introduction to this method, I would encourage trying it and following some youtube tutorials.
       
      After some decimating and very rough texturing (~640 tris)

       
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!