Friday, September 13, 2019

xna - Rendering collections of light sources



I have a small test environment where small point lights are scattered. Players should able to collect them.


The collectible lights are rendered using a simple billboard technique where two triangles with a uniform color are rendered facing the camera and a gaussian is used as an alpha-map.


0/1     1/1
+---------+
¦ /¦
¦ / ¦
¦ / ¦ u/v texture coordinates for alpha map (gaussian)
¦ / ¦ every vertex has same color rgb(1, 1, 1)
¦/ ¦
+---------+

0/0 1/0

When a player collects a light, the idea is that the collected light is merged with the lights he already has collected. The players are currently rendered with the same method as the collectible lights, the collected light has influence when the lighting is calculated => higher light intensity.


Light as it looks now


What I'm looking to do is to visualize the lights better. They look really boring the way they are rendered currently. Only good thing about them is that they do not influence the performance :-)


The process of the light merge could for example be visualized in a way where all collected lights circle around as small pulsating glowing particles - sticking together to some extent - maybe some nice lines which travel with them - you know, like such a thing should look like if it is a central part of a game.


The problem is that I don't really find many resources over advanced shader effects. Most information found is over the basics (diffuse / specular shader - maybe some blurring) or does not involve the HLSL language which I use in XNA 4.0.


I would appreciate any links to resources which could help me making more awesome light effects which could actually run on the xbox without running into performance issues. Basically, any techniques which involve rendering cool light orbs / beams etc. would be fine for the moment if the result i visually appealing.



Answer



Neat idea for the game. The problem is that light really doesn't look like this. Light decay is NOT gausian :). That's for the begining. What i want to propose is adding simple (but relatively physicaly correct) fog or dust. Mean volumetric effect. You will have to implement volumetric raycasting on the gpu. Don't panic. It is not that hard as it might sound.



I have created this in our engine for you as a example how it might look like. It is realtime. And can be realtime for few lights with cube map shadow map. (low fps is caused by output)


enter image description here


What do you see here is fog (or dust) containing lights. Lights are represented only by their position, color and intensity. They have cubic decay, which looks natural and fits to the definition of the Radiance. Lights has different intensity, exactly what you wanted.


Volumetric raycasting casts ray for every pixel and samples through the volume. It is usualy used for smoke, dust or fire on offline rendering, but can be done on gpu in realtime. You dont have actual volume, but you have to sample for the shadows contained in the shadow maps. If you want only fog, it can be done with O(1) complexity (per pixel shader)



You sample on ray like this:


//pseudo ugly pixel shader code
samplePoint = zNear; //position on zNear (in worldSpace)
color = 0;
until(z-buffur_value || zFar)

{
lightDecay = getLightDecay(samplePoint,lightPosition);
shadow = getShadow(samplePoint); //like regular shadow mapping, you have world space position and want to know if there is shadow or not.
color.rgb += (1 - color.a) * (lightColor * lightIntensity * lightDecay * shadow);
color.a += (1 - color.a) * (1 - opacity); //opacity is the same in your case. If rendering something like clouds it is loaded from the 3D texture. I suggest value like 0.01 or similar..
samplePoint += direction * step;
}

It is not hard actually and can be done as a pixel shader (offscreen). You have to stop sampling rays at z-buffer value (so it has to be applied after the opaque scene render). And alpha blended with opaque scene render.


It is pretty solution to this. It also attenuates lights which are far from player, solves the intensity correctly and i think it looks cool.



For more info you maybe like read my paper about implementation of volumetric effects into game engine (well something similar to game engine :)).


There is also awesome book about volumetric rendering. I'm in love with it. Also this site contains pdf tutorials which are quite good introduction to the volume graphics.


Improvement: Adding colors to lights and perlin noise to the volume to look more natural (left without perlin|right with perlin)


enter image description hereenter image description here
(hmm those gifs are too low quality that there is no significant difference).


edit (some performance notes): it can be done as one pass per light, which is usefull if lights has lots of aditional textures (light color - projective texturing, intensity curves etc.). But this is frame rate killer, it can (and should) be done in one pass for all lights if you have enough texture units available (i think you have in your game). Than it can have about 45-60fps i hope.


Sampling doesn't have to be linear. You can make sampling logartmic (or similar function).


makeEveryStepALittleBigger = 1.05;
samplePoint += direction * step;
step *= makeEveryStepALittleBigger; //this should be actualy based on camera FOV


This however destroy physical correctness and "opacity correction" has to be done. Which is:


curentAlpha = 1 - pow((1 - opacity), delta);

where delta is difference between step1 and step2.


And if you dont mind little noise, you can add depth jittering which allows you to use much lower number of samples (that is pretty good and easier solution).


That was fun...


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...