Ephenation is a MMORPG in an adventure setting that supports player defined additions.
This is a blog where I show the progress from making the game. Main focus is on the application of OpenGL. I hope this will help others to benefit from my mistakes and experiences.
Any bitcoin donations are welcome to 18JGunpjKBiJ4gVbwP2d9UHaX8z2RPBrL7.

4 januari 2014

A wet surface will reflect some of the light, but reflections are computationally expensive. Using a deferred shader, it is possible to simulate this reflection (fresnel reflection) to the second stage. The basic idea is simple: If a pixel should reflect, a ray tracing algorithm is used to compute where the reflected ray will hit the background.

We don't want to trace the ray through the real geometry, which would be expensive. Instead, it is computed what pixel it corresponds to from the G-buffer of the deferred shader. The data we need from the defered shader is: World position, normals and colors.

To do the actual ray tracing, an iterative algorithm is needed. The reflected vector is first computed, and then incrementally added to the world position of the point we start with. This is repeated as long as needed.

There are a couple of problems that limit the use of this technology:

The reflected ray can point backward to the camera and hit the near cutting plane of the view frustum.

The reflected ray can point sideways, and go outside of the screen.

The reflected ray can hit a pixel that is hidden behind a near object.

The increment used in the algorithm should be small to get a good resolution of the eventual target point, which will force the use of many iterations and high evaluation costs.

These all sound like severe limitations, but it turns out that wet surface reflection can still be done effectively:

The Fresnel reflection has the effect of reflecting most for incoming light at large angles to the normal. That means that light reflecting backward toward the camera can be ignored.

Wet surfaces are typically rough. This can be simulated with some random noise, which can hide the effect where some ray reflections couldn't be determined.

The iteration can start out with a small delta, and increase it exponentially. That way, it can be possible to get good resolution on short distances, while still being possible to compute long distances.

The following is an example fragment shader to help calibrate the constants:

The shader doesn't implement the actual reflection, but will show color coded information. White is used to indicate a reflection going back to the camera, yellow indicates a pixel hidden behind another object, black indicates we got outside of the screen. Finally, a rainbow code is used to indicate the number of iterations needed to find the target. Red is 1, then green and finally blue for maximum.

The example code will do at max 20 iterations (increment i with 0.05). Notice how the delta gradually is increased (incr is increased by 30% every iteration at line 50). Starting with a color texture as follows:

Original

And then applying the shader above, the result is:

Calibration mode

Please ignore the red and yellow sky, and look at the big block in the foreground. Much of it is white, because that reflects mostly back to the camera. The left side, however, has several colors. Black indicates a ray that goes outside of the picture, but the spectrum from red to blue indicates successful ray tracing. The bottom is red, which is logical as the reflection will immediately hit the near ground. The trees are found at median distance, indicated by green. And the sky is blue, which means a maximum number of iterations was needed to hit the sky pixel.

Notice that the single monster is reflected twice, at two different iterations. This is an effect of iterating in big steps.

Next is a picture from inside a cave, with no reflections enabled:

Caves without reflections

The same view, but with reflections enabled:

Caves with reflections

In this picture, the normals were manipulated randomly, and the original pixel color is blended with the reflected color depending on the angle. The final fragment shader source code for this is: