I’ve continued working at a good pace. Having got the model loading working I made the scene more interesting. I removed the spinning cubes and put the icosahedron in the middle as a planet. I updated the ship’s position and orientation over time so that it appears to be flying a path around the planet while doing barrel rolls. This immediately gave the scene a lot more life and the project a bit of direction towards something that actually could be a game, even if the motion is a function of time rather than force and time.
Now the scene was dynamic but without a frame of reference it was hard to tell whether the camera was moving or the planet was spinning. I’ve thought about how I would approach the skybox for a while. I know that I want to generate it somehow in keeping with the “everything must be made on the iPad” constraint, so downloading from the internet is out. Similarly generating one in Blender is off the table as I can’t run Blender on the iPad. One approach that I find very interesting is to draw a fullscreen quad and then procedurally generate the skybox in the fragment shader based on the view transformation. This is a bit beyond my mathematical ability to reason about and I suspect there might be performance issues with it. I decided to start with a simpler approach but to revisit the fullscreen quad idea later. Restricting the scope to stars, the approach I opted for was to use instanced rendering to draw billboarded stars. These stars would be randomly distributed on the surface of a sphere which would be positioned with the camera and everything else in the scene drawn on to, just as with a skybox. This gives the effect of the stars being very far away.
I implemented this initially using a cylinder instead of a sphere, and rows of stars instead of a random distribution. This was to test the concept of the skybox with a simpler set of constraints.
With this basic approach working, I read about arc4random and used this to generate random positions for the stars on the surface of the cylinder. I also refined the generated star texture that I’d been using and made the background transparent. As the camera rotation was fixed on a plane the fact that I was still using a cylinder for the skybox didn’t matter at this stage as it wasn’t possible to look up or down.
The scene now looked interesting but the ship was not very convincing. I figured engine trails would be a great way to give it some life. I had initially planned to do this by creating a series of line segments to allow for curvature. However to get a proof of concept running, I used a sequence of icosahedra instead with these decreasing in size and offset by an amount of time compared to the ship when calculating the rotation. The icosahedra are transparent and not affected by the scene’s lighting to give them a glowing science fiction feel. I added a periodic “pulse” down the trail where each segment would be enlarged for a short amount of time to make it feel less static.
Although this was a proof of concept I really liked the approach. When I refine it further it may be more efficient to replace the icosahedra with a simpler mesh, since they’re indistinguishable from billboarded octagons for example.
One thing I like about procedurally generating the skybox is that it allows for the possibility of stars to be universally consistent - for example you could see a particular star or constellation from one location in the right place on the sky. Alternatively, if I don’t want this I can generate the stars to a skybox texture that I can use to improve performance.
This entry is part of a series on writing a Metal Renderer in Swift Playgrounds.