Skip to content

240. WoT – Adding scenery

October 19, 2015

In this post, I add scenery for my tanks to move around in

I am hoping to get to a hilly terrain with trees, but I’ll keep it simple to start with, and make it flat.

Surface

I chose a grassy texture and made a flat surface, tiling it with the texture.

Tank Changes

I modified the camouflage colour on the tanks so it fits in better with the grass colours, and also made the pattern different for each tank, simply by making the texture positions start at different places on the camouflage image.

Doing this means that for some tanks, the texture positions go past the end of the image, but I used the same tiling shader as for the surface (see link above) to make it wrap around to the start of the image again.This means you may see the join between the end and the start, because the image is not “seamless”. So I used my code from this post to make the camouflage image seamless so you can’t see the join when it wraps around.

Finally, the tanks seem to glide over the ground, whereas in real life, they bump up and down. I used the same code as in my World of Warships project to make the tanks rock a little as they moved.

function Tank.Wobble()
    local f=.1
    local a,b=ElapsedTime*f,ElapsedTime*math.pi*f
    rotate(10*noise(a,b),1,0,0)
    rotate(3*noise(b,a),0,0,1)
end

I will just need to adjust this so the wobble is different for each tank, and to vary the speed of the wobble based on the speed of the tank.

Basic scene

So here is a little tank parade, with all of the above changes.

Spritesheet

I am going to need to store the grass image, the seamless camouflage image, and images for trees and bushes. For now I’ll keep them as separate images (I already have a lot of tree images from previous projects), but I will put them all on one image eventually, to keep things tidy.

Trees and bushes

Now I’m ready to add some trees and bushes for the tanks to hide behind.

You can imagine how complicated it would be to draw realistic looking trees using mesh triangles – and how many triangles you would need. So I’m going to use flat 2D images, rotating them so they always face the camera, and you can’t see they are flat. This is called billboarding, and is good for messy objects like trees and bushes, because our eyes don’t see patterns, and so if you go round a tree, you don’t notice that it is rotating – unless of course it has an odd shape.

However, there is a problem with billboarding.

Transparent pixels

The tree images are rectangular meshes, with an image in the middle and transparent pixels all around.

When OpenGL draws a 3D scene, it colours each pixel, and if more than one object is drawing to the same pixel, OpenGL keeps the one that is in front, which is logical. But suppose we have a 2D “billboard” tree in front of a tank, and there is a transparent tree pixel in front of a tank pixel. We want to see the tank pixel because the tree pixel is transparent, but OpenGL simply keeps the closer pixel, ie the transparent tree pixel (as described in this post).

This means that if you draw the tree before the tank, you won’t see the tank through the transparent tree pixels – as shown using two trees, below.

treesThere is no simple way round this, except to draw the billboard images last, and to draw them in order from furthest to nearest.

 

 

This is a nuisance, because it would be most efficient to put all the billboards on a single mesh using addRect, and then use setRect to change the angle of each image to face the camera each frame. Having to sort them means keeping them in individual meshes, and this has a performance penalty.

There is one alternative, which is to use a shader to discard transparent pixels. When you do this, OpenGL ignores them and they don’t block objects behind them, which means we wouldn’t need to worry about the order we drew them in, so we could use a single mesh. However, discarding pixels hurts performance, and can lead to a blocky effect, which I tested – and it doesn’t look good, so I’ll stick with individual meshes. I won’t sort them every frame – every 0.5 seconds should be often enough.

So I’ve put a number of trees into the scene, and now it looks like this.

You’ll notice the tanks drive straight through trees – in World of Tanks, trees get knocked down and disappear, and maybe I’ll do that later.

And if you’re peeking through the branches of a tree, it looks like this.

It looks very nice, except for one thing. I am down to 35 frames per second, on a very fast iPad, so I need to speed things up.

Making it faster

Mist

One way to do this is to cut down the amount of stuff that needs to be drawn, and a good way to do this is with mist, like this.

However, this will make the tank battles very short range, and take out a lot of the skill in playing (and the fun of long range sniping from behind a bush).

Culling

Another possible speed fix is to only draw the trees which are in front of the camera. OpenGL does a good job of “culling” vertices that won’t be drawn, but it does this for individual vertices, one at a time. You probably can’t improve on the way it does this, but we can do tests for whole objects with lots of vertices, and this may increase speed significantly. In other words, our testing may not be as fast as OpenGL, but if we can do just one test that avoids drawing (say) 100 vertices, that is faster than letting OpenGL test each of those 100 vertices. So the more vertices we can cull with a single test, the better this is going to work.

In our case, each of our trees has only 6 vertices, so I’m not sure if this is going to help. So I tested, and it added 15 frames per second, which is fantastic. The method requires some explaining, so I’ll describe it in a separate post.

Tuning the code

I also changed the way I rotated the trees. I was using the same algorithm used by the camera function to point the camera, but this is overkill, because it is rotating in three dimensions, and we are just rotating in one (left/right). So I did it using simple trigonometry, as I did in this post, and it made quite a difference.

I’m almost back up to 60 frames a second, even though I have 20 tanks and 400 trees on my map.

Bushes

I’m also thinking that I really need to get big bushes rather than trees, because you can see under the branches of trees, making it harder to be hidden by them. That’s a shame, I had some nice tree images, and it’s hard to find good bush images.

But maybe if I cut the trunks off some of those trees, they would make good bushes, like this .. looks pretty good for a first try.

Now I need to put them in groups to make good ambush spots.

But first I need a rest!

Finally – I say this often, but it’s important. You’ll see that in my projects, I use a lot of different techniques that I have learned (and posted about) over the past few years. And I’m sure I could do it better if I knew more.

As with anything, the more you learn, the more choices you have, and the better the result – and it is especially true of 3D. If you are just starting out, you shouldn’t be put off by the apparent complexity, because I began by knowing nothing at all, and I am just a hobby programmer – but you do need to be patient and be prepared to put in the time, and actively look for useful techniques. It isn’t going to be easy, and it won’t happen overnight, but if you want to do this stuff, I’m sure you can.

Just don’t expect to build tanks on day 1.

 

 

Advertisements
Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: