218 World of Warships #1
I like watching people play World of Warships, and I thought making (a VERY simple version of) it would be fun. So here goes.
In this first post, I’ll talk about modelling a warship.
Modelling a warship
I thought I’d start with a fairly simple ship, a destroyer, so I googled some images, chose one, and pasted it into an Excel spreadsheet so I could use the gridlines as a ruler.
And this is what I ended up with
I created a set of vertices for the outline of the main deck first, which wasn’t too hard, by following the shape of the drawing above, sloping the deck upwards from the back to the front.
Then I turned the vertices into a set of triangles, connecting the centre point of the deck to each pair of neighbouring deck vertices. As you’ll see from the top diagram, the centre of the ship is at (0,1.5,0), and sea level is at height 0.
Adding the hull is easy. I added a duplicate set of vertices just underwater (ie slightly negative y value) and made a rectangle (two triangles) to join each pair to the deck vertices above, all the way round (so basically I made a box). The only exception was the very front of the ship, where I adjusted the underwater vertex, so the front is slanted.
Then I added some boxes of various sizes and shapes to make the top of the boat.The slope of the deck was a slight problem, because if I add a long block on top of it, it needs to be at the same angle. I probably could have done it more easily, but this is my code.
--v1 is height difference between -- the left and right of the block --and w is width of the block local a1=math.deg(math.atan2(v1,w)) --calc angle --create a rotation matrix using this angle local mm=matrix(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1) mm=mm:rotate(a1,0,0,1) --given a block with vertices vv, rotate them and --translate them to the point (x,y,0) for i=1,#v do vv[#vv+1]=mm*v[i]+vec3(x,y,0) end
Guns
The guns are the hard part, because I want to rotate them (left/right), and also rotate the gun barrels (up/down). I could put everything in one mesh, and modify the vertex positions when I need to, but I find that very messy. So the 4 guns are each in separate meshes.
Each of the twin barrels is a long thin rectangular box (there’s no need to make them rounded when you never see them close up), and each pair is in a separate mesh.
So I have one mesh for the ship, 4 meshes for the 4 guns, and 4 meshes for the 8 gun barrels.
Colour
I used a gray colour throughout, but varied it a bit for different boxes, to make them stand out.
Lighting
You will usually need some lighting when working in 3D. I have used extremely simple diffuse lighting (meaning that a mesh is fully lit when the light is shining straight at it, and not lit at all when the light is coming from the side or behind), plus some ambient light (meaning the object is partly lit even if there is no diffuse light). This creates shadows that help us see the shape of 3D objects, like our ship.
For those that know about these things, I created normals for each vertex. For the back and front of the ship, I wanted to soften the angular shapes, so I calculated the normal as the direction from the centre of the back (or front) of the ship. For the middle of the ship, I simply pointed the normal outwards. My lighting shader calculates everything in the vertex shader, which isn’t quite as nice as a fragment shader, but way faster.
Rotating the guns
It’s easy to rotate a gun mount (the box holding the gun) to the left and right. The barrels aren’t so easy, because we want to rotate around one end (that is attached to the gun), and not around the middle of the barrel. To keep things simple, I made the barrel twice as long as I needed, with half hidden inside the ship, and half sticking out. Then I can rotate around the centre of the barrel, and it will rotate as I want it.
Shooting flames
When a gun shoots, I want flames to come out of the barrels.
Flames are quite tricky. They are very messy things, making them difficult to model.
They are often done with particle systems (lots of little meshes) or shaders (because they work fast, and can do a lot of calculations to decide what to draw for each pixel). I wanted to make it simpler, so I started by getting Codea to draw a flame. My code for this is not pretty, but this is the result.
Then when I shoot, I draw the flame, increasing quickly from nothing to its full size (I use the scale command for this), holding still for a second, then disappearing.
There is an obvious problem, though. The image is flat, so if I’m viewing it from the side, I won’t see anything. My answer is to draw the image twice – the second time, after rotating 90 degrees (making a cross shape). Because the flame is all the same colour, without any real shape, you don’t see the cross shape – it just looks 3D from any angle – unless you are looking directly down the gun barrel, which is unlikely in this case.
You can see the effect in the video at the top above.
I’ll explain how I did the sea and islands in the next post, also the navigation. And there is still a lot more to do!
Trackbacks & Pingbacks