With the help of my mentor, I followed the logic in the original game and finally, now The Longest Journey in ResidualVM shall have shadows that are calculated based on actual lights in the scene!
Below are some screenshots as demonstrations. For a better illustration, I temporarily rendered the shadow with solid green. As you can see, in location 39 00, the shadow of April will become longer and change its direction based on the lights.
As I have said in the previous blog, the game computes the shadow in a way that is not the same as the reality. Well, with the help of my mentor on reading the disassembly, the truth behind the screen was revealed. Honestly speaking, after knowing this, I really don’t think I can figure it out just by observing the game itself.
So, in general, the game first calculated an overall direction from lights. The way to compute the directional vector from lights varies based on the type of the light, but basically, it is related to the distance between the model and the light and the brightness of the light. Notice that I am saying “model” here, not vertices. It turns out that one light direction is applied to all vertices of a model.
The Calculation of the Point Light |
After that, the directions from all the lights are summed together as an overall direction. Remember the maxShadowLength I mentioned in the previous blog? It is used to clip the horizontal length of the overall light direction. It turns out that the maxShadowLength needs to be divided by 1000 before being used, that’s why its value seems to be so large.
After that, things become trivial. By passing the overall light direction to the shader, with some linear algebra, it is easy to calculate the casted position of a vertex. It is even easier if you first transform the light direction to the model space since then the plane of the shadow is just the XZ plane. You can save some of the math.
The Vertex Shader |
By the time when I wrote this blog, the PR was not merged yet, but I believe it is very close to that. So now, all the tasks scheduled for this year’s GSoC are finished. I have learnt tremendously from this project. I get more familiar with C++, I know more about game programming, and I even get some hands-on experience on CG with OpenGL! Also, I need to express my greatest gratitude to my mentor bgK. He is truly a good mentor. Without his detailed reviews and clear guidance, I would never accomplish so much. This is a truly wonderful journey and a valuable experience.
Thank you all, for you guys are truly wonderful 😀
All code snippets are generated through Carbon