Sundog's SilverLining skies & Triton ocean in VT-Mak's VR-Vantage image generator.The SilverLining Sky, 3D Cloud, and Weather SDK and the Triton Ocean SDK both render real-time environmental effects that take the simulated direct and ambient sunlight into account. But, sometimes you have your own effects that you want to integrate into our water or clouds. Perhaps you have your own scheme for handling additional dynamic light sources, or shadows, that you’d like applied to our objects.

This can be done – we’ve had customers integrate artificial light sources, forward-plus lighting, and real-time shadows into SilverLining and Triton. Both SDK’s are designed so you can do this without modifying any of our source code – your extra shader logic for your own effects just gets linked in at runtime. So, you can maintain your own effects separately from SilverLining and Triton.

Seen here is a screenshot of VT-Mak’s VR-Vantage product, which incorporates additional light sources from spotlights and explosions onto Triton’s water surface. We’ve had other customers do similar work to illuminate clouds with plane landing lights, and JRM Technologies has also used our extensible shader capability to integrate their sensor effects into SilverLining and Triton.

Note the techniques described below are specific to OpenGL, and you will need to know what you’re doing with GLSL in order to be successful. If you’re using DirectX, you’ll have to modify our .fx shader files directly instead.

Extending Triton’s Water Shaders

Have a look inside the Resources folder, and open up the user-functions.glsl file in a text editor of some sort. This file is the key – it contains hooks into Triton’s shaders at key points, that let you extend or override its lighting.

The idea is to keep all of your modifications to Triton’s shaders in the user-functions.glsl file, so you may continue to update Triton without needing to merge in your custom shaders going forward.

For example, the user_lighting function looks like this:

// Light, view, and normal vectors are all in world space.
// This function may be used to modify the ambient, diffuse, and 
// specular light computed by Triton's fragment shaders.
void user_lighting(in vec3 L
 , in vec3 vVertex_World_Space, in vec3 vNormal_World_Space
 , in vec4 vVertex_Projection_Space
 , inout vec3 ambient, inout vec3 diffuse, inout vec3 specular)
{
}

Using this function, you can add in your own light sources by adding them into the ambient, diffuse, and specular light components that will be used to light each water fragment. All of the vectors you’ll need to apply lighting for this fragment are provided.

However, you won’t be able to do anything interesting unless you can also pass your own uniform values into this shader. To do that, you need Triton’s internal OpenGL program ID’s to bind to.

That’s what Triton::Ocean::GetShaderObject() is for. It will return the program handle for the currently active water surface, spray, or wake spray shaders. Note there are two different programs for the water surface: WATER_SURFACE is used when the camera is high above the water, and WATER_SURFACE_PATCH is used when the camera is near the surface. Be sure to set your uniforms on both programs.

It is also possible to link your own pre-compiled shaders into Triton’s shader programs. There is an alternate version of Triton::Ocean::Create() that takes in a vector of your own shader ID’s to link into Triton’s programs. This may be useful if you don’t want to distribute your own shader code in plain text within our user-functions.glsl file. It is also possible to tell Triton to reload all of its shader programs at runtime with a new list of user-provided shaders with Triton::Ocean::ReloadShaders().

Extending SilverLining’s Cloud and Sky Shaders

Things work very much the same way in SilverLining, but there are more shaders involved. Inside the Resources/shaders folder, look for the UserFunctions.glsl and UserFunctions-frag.glsl files. These define hooks into SilverLining’s vertex and fragment programs, respectively. If you’re using SilverLining’s OpenGL 3.2 renderer, you’ll want the .glsl15 versions of these files instead.

Let’s say you want to add spotlights onto cumulus clouds. The relevant function is overrideBillboardColor() in UserFunctions.glsl:

// Cloud puffs are drawn additively, so dark = more transparent.
// This allows you to influence the color used for a given
// puff. This color is multiplied with the puff texture in the 
// fragment shader, and nothing more.
// By default the fogged color is multiplied by the cloudFade, 
// voxelFade, and fogFade, which apply alpha effects on the
// cloud layer as a whole, on the individual puff (ie while 
// clouds are growing in real time,) and from fog (we simulate 
// atmospheric scattering by blending the puff into the sky 
// behind it based on distance.)
void overrideBillboardColor(in vec4 foggedColor, in float cloudFade, 
        in float voxelFade, in float fogFade, inout vec4 finalColor)
{

}

This function is called by Billboard.glsl, so all of its uniforms are available to you if you declare them at the top of UserFunctions.glsl. For example, you can add

uniform mat4 modelView;

in order to gain access to the matrix needed to transform gl_Vertex into view space.

To set your own uniforms, you’ll need the OpenGL program ID to bind to. In this example, you would use SilverLining::Atmosphere::GetBillboardShader() for this. Similar methods exist to access the program ID’s for the sky and stars. Atmosphere::GetActivePlanarCloudShaders() may be used to obtain the shader programs used for other cloud types, such as stratus and cirrus.

Like Triton, it is also possible to link in your own pre-compiled shaders into SilverLining’s shader programs. There is a special version of SilverLining::Atmosphere::Initialize() that takes in a vector of your own compiled shader ID’s for this purpose. SilverLining::Atmosphere::ReloadShaders() may be used to re-link SilverLining’s shader programs with a new set of user-supplied shaders at runtime.

Extending SilverLining and Triton’s shaders is an advanced topic, but it gives you a lot of flexibility when integrating our environmental effects into your own rendering pipelines and advanced effects. Feel free to contact us if you have any questions.

Update: See a complete example of adding a spotlight to SilverLining’s clouds.