Low poly terrain

Published October 02, 2018
Advertisement

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.

Previous Entry Voxels
Next Entry Marching cubes
1 likes 15 comments

Comments

Gnollrunner

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. 

May 30, 2018 03:32 AM
bdubreuil
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?

May 30, 2018 02:12 PM
Scouting Ninja

This terrain looks amazing. Fantastic work.

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

May 30, 2018 03:04 PM
bdubreuil
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.

May 30, 2018 03:12 PM
Scouting Ninja
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.

May 30, 2018 04:10 PM
Gnollrunner
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

May 30, 2018 04:54 PM
the incredible smoker

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.

May 30, 2018 05:10 PM
Gnollrunner
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

May 30, 2018 05:12 PM
bdubreuil
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 :)

May 30, 2018 05:29 PM
Gnollrunner
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.

May 30, 2018 05:55 PM
bdubreuil
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.

May 30, 2018 06:01 PM
Gnollrunner
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. 

May 30, 2018 06:08 PM
the incredible smoker

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

May 31, 2018 11:03 AM
the incredible smoker

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.

May 31, 2018 11:30 AM
bdubreuil
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 :)

May 31, 2018 02:16 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement