This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.
The scene is lit entirely by two lights-one infinite (directional) light and one spotlight casting from the lighthouse. The infinite light is calculated simply by dot lighting with the light's direction and the vertex normals. The spotlight also uses dot lighting, but in addition takes into account a light frustum and falloff.
The stored information for the spotlight includes position, direction, and frustum. For surface lighting, we first determined whether a point lies within the spotlight frustum. Next we calculated falloff, and finally we applied the same dot lighting as used in the infinite light. For the first step, we found a vector from the vertex point to the camera, and then calculated the angle between that vector and the spotlight's direction vector, using a dot product rule and solving for the angle
V1 • V2 = | V1 | | V2| cos θ
where V1, V2 = vectors and θ = angle between. If the angle between the two vectors is within the frustum angle, we know that the point is illuminated by the spotlight. We then used this same angle to apply a gradual falloff for the spotlight. The difference between the calculated angle and the frustum angle determines how far away from the center of the frustum the point lies, so the falloff can be determined by the expression
| θfrustum / θ | - 1
where θ = angle between. As you can see, the expression is undefined at θ = 0 and less than or equal to 0 at θ > θfrustum. The undefined value computes to an infinitely large number during runtime, so we have exactly what we want-most intensity at the center of the frustum and no intensity at the edge. With this result, we used the HLSL saturate function to clamp these values between 0 and 1 and multiplied the spotlight intensity by this final number.
Because of this, we can translate the cone to the spotlight position, rotate to match the spotlight direction, and ensure that the cones cover the frustum completely. The shader code for the cones simply calculates their appropriate world-space fog coefficients as we explained earlier.
We blended those with a surface color of zero alpha and amplified that value by the spotlight intensity times the spotlight color. Because we were using zero alpha to indicate no amplification, we used an alpha blend state, with an additional blending function. The volumetric frustum falloff was approximated by using multiple cones, so the blending addition created a higher amplification in the center of the frustum.
Modern low-cost graphics solutions have come quite a way in recent years. The projected grid port provided an excellent chance to test performance on both low-cost and high-cost graphics systems. It also gave us a good opportunity to determine how to scale content for both types of systems and was a great way to contribute to the graphics community.
The top two areas of performance improvement that impacted the low-cost graphics target were in the Perlin fog and the ocean grid computations. The latter renders only in the camera's view frustum and was easy to control given the original algorithm.
Through that we could easily reduce mesh complexity and in doing so reduce the scene overhead. We also gained even more performance on both integrated and discrete graphics by combining terrain and building meshes.
We came close to doubling our frame rates by pre-computing the Perlin textures on the CPU and using the GPU only for blending and animating the texture. Additional performance gains were also made by tuning down the ocean grid complexity and using only the necessary reflection and refraction computations.
Finally, the Intel Compiler was instrumental in auto-vectorizing our code, which boosted our performance even further (~10%) for CPU-side computations (Perlin computations for Fog and Ocean motion).