6
\$\begingroup\$

I'm creating a game that is similar to Tibia on its projection:

enter image description here

But I want it, under the hoods, to be 3D, and extremely dynamic - meshes generated on the fly, statues exploding and turning into smoke monsters, things like that. For that, I've created a renderer that isn't geometry based, but atom based - it takes a compact buffer of positions and colors and renders it to screen. It works extremely well and is quite fast. There is only one problem, lighting. To achieve realistic lighting, I must, for each atom on the screen, emit a ray that traces a volume, sampling among the way. If it hits something before the light, that space isn't lit. This is the end result:

enter image description here

I love that effect, but, on my machine with a low-end GPU, it can stand millions of atoms, but only 2 lights max. That is not enough, I'd need 16 lights at least. Each light requires dozens of samplings for each atom on scene, it is prohibitively expensive. Without global lighting, the ambient becomes flat and boring.

Is there any creative way to achieve the same effect, albeit less expensive?

\$\endgroup\$
  • \$\begingroup\$ Can you not apply lighting per fragment and do what modern game engines do? I suspect that even if it's atom based (like a voxel based renderer), you can still only care about lighting per fragment. opengl-tutorial.org/intermediate-tutorials/… \$\endgroup\$ – Coburn Aug 26 '16 at 17:20
1
\$\begingroup\$

The best thing you can do is to calculate all the lighting data you can beforehand and store that in the game. If none of the lights move themselves, then you have a much easier problem, as you only have to account for the entities or other moving objects. Instead of storing the floor as just one specific grey, you can use a shader function.

Another thing you can do is cull as many calculations as you can. Instead of lighting across the entire area, only do it until the light no longer has a noticeable effect the point. For instance, if a light has a brightness of one unit at one centimeter away from the source, you can stop considering it after a meter, as it will only add 0.0001 at most to the brightness of the pixel.

Finally, Coburn's suggestion in the comments is great, and you should probably use that article.

Addendum: One thing that you can do is instead of sampling each atom dozens of times is realize that light obeys an inverse square law. The formula for light on a plane is 1/(height of the light^2+distance on the ground^2), which is just a combination of the Inverse Square Law and the Pythagorean Theorem. You can then use that formula to add the amount of light to an atom that you would expect from that light. You will have to calculate ambient light beforehand. Finally, whenever a light "path" hits something, you would temporarily stop the algorithm from adding light to atoms until you reach a point where the light can shine over the object. This should take out the dozens of samples for every single atom. This basic idea, plus the earlier ideas, should significantly reduce computation time.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.