понедельник, 6 июня 2016 г.

Creating Custom Anamorpic Lens Flare in Unreal Engine

Unreal Engine doesn't have any built-in features for create highly-customized lens flares. By default, lens flares are implemented as a image-based effect, so we deal with engine rendering system. In our game we need custom lens flares that can be blocked by other objects. For example, if we have a light source that shine in camera on a background plane and some object, that blocking this light, lens flare should be blocked. This is the main problem. 

In this tutorial, I described a solution of this problem. Note, that the material, described below works correctly only for cameras without fixed aspect ratio (fixed aspect crops image and mask cropped areas with blackbars) and with fov equals 90. You can get the complex solution, that works correctly for all cases from unreal marketplace: https://www.unrealengine.com/marketplace/custom-lens-flares-material

The solution:

There is many solutions of this problem. The most popular is to make lens flare as a particle system and control its visibility from a component which casts a ray into camera. If ray is blocked, particle system doesn't visible and vice versa. Using particles is a good idea, but component it's not a good solution because of a many reasons: it's expensive, doesn't work in editor mode, doesn't work for split-screens, doesn't work for multiplayer. You can fix some of that problems by set-up proper replication settings for some methods of that component, but this is still not a good solution.

The other solution is to write a shader that controls the opacity of a particles. In this case, we need one particle with a special material, to simulate a flare. To check visibility of lens flare we are using information about center of a particle, that simulates a lens flare, from the DepthBuffer in a shader, and comparing it with distance between center of the particle and camera world position. If distance in the DepthBuffer is less than the distance between camera and the center of the particle than we consider, that lens flare is invisible because its was blocked by some object in front of the particle. It's pretty clear, how to get PixelDepth, CameraWordlPosition and the particle center, but doesn't obvious how to transform particle center into screen space coordinates to get a pixel depth value and this is a key.

Shader Overview


This is the shader, that I've made. I use additive material to simulate flares. The shader have three main blocks : (from up to down) The World To Screen function at the top, the comparing block at the middle and pretty simple lens flare block at the bottom. Don't forget to Disable Depth Test in material settings.

Next, create new particle system and set-up it this way: