While working on PAParticleField, an alternative particle system for Unity for optimized looping/ambient effects (more on that later), I thought of a use for it that was out of the scope of the PAParticleField project but could use some of the work, motion blurred star fields.
With games like ‘Elite Dangerous’, ‘No Man’s Sky’ and in particular ‘Star Citizen’ receiving a lot of press coverage I’ve been seeing a lot of screens like these recently.
(Various googled images from Star Citizen)
Here the motion blur on the stars adds to the feeling of movement and realism. These games use high resource render to texture effects to create the final image, though I thought that the feeling of the effect could be achieved using far less resources by limiting it to the stars only. As often the starry skies take up a significant portion of the screen (54% of the screen on average from the images above, the second image taking about 70%) these areas sell the motion blur most, and as they are generally considered an infinite distance away they will be most affected by rotational motion blur.
So I took a couple of days to branch off PAParticleField and create a system that will complement a skybox, and give a sense of motion blur without any image effects, called PA Starfield.
At Start() time of build time the script generates a mesh of quads where each quads vertices are in the same point in space, which I’m going to called a quad singularity, arranged for form a unitized sphere of quad singularities. The script also applies UVs and randomized colors the quads.
At runtime the script monitors what cameras are rendering the Star Field and tracks their rotations. For each camera that renders it, it calculates the change in rotation from the last time it updated, converts it from a Quaternion representation to an Axis Angle representation, and passes those values to the material shader. By doing this in OnWillRenderObject() the star field will respect the movement of several camera at the same time.
The Shader then manipulates the vertex positions, first projecting each quad back to the current cameras far clip plane. I then calculating the direction to stretch based on the input Axis Angle values, the cross product of the Axis and the vertex position results in a stretch direction. Finally I stretch the quad in that direction by the dot product of the input Axis and the quads position (which was already a unitized vector), technically the stretch direction already contains the amount of stretch in its magnitude, but by using the dot product I can easily clamp the stretch to a minimum value of 1, otherwise stars would disappear if they weren’t moving.
I’m not going to go too much into the actual math and shader code here as it’s all included and commented in the source anyway, but it does the job as described above.
(Screen from web demo)
The advantage of this method is that it’s light weight as motion blur go, the resulting mesh contains a maximum to 3.3mb of data, it fits nicely into Unity’s rendering pipeline as a mobile friendly single draw call and effects can be overlaid on the results. Also there is technically an unlimited amount of stars that can be generated, each PA Star Field is limited to 16250 stars because that’s Unity’s mesh limit (65000 verts / 4 verts per quad) and this is generally an acceptable number of stars, but if there are resources spare and additional draw calls aren’t an issue then as many PA Starfields as needed can be added to the scene.