#! /usr/bin/env python

# Uniform Values (Fog)

This tutorial builds on the previous tutorial by:
• defining uniform values in shaders
• passing values to uniform values from Python
• doing some basic calculations during the vertex shader, including defining local variables and using some simple functions
• creating a "depth cue" via a simple "fog" function which alters the colour of each vertex according the the vertex' distance from the eye.
Note: the shader in this example comes (loosely) from the OpenGL Shading Language (Orange Book) Chapter 9.
Our imports are by now quite familiar...
from OpenGLContext import testingcontext BaseContext = testingcontext.getInteractive() from OpenGL.GL import * from OpenGL.arrays import vbo from OpenGL.GL import shaders from OpenGLContext.arrays import * class TestContext( BaseContext ): """This shader adds a simple linear fog to the shader Shows use of uniforms, and a few simple calculations within the vertex shader... """ def OnInit( self ):
Much like the "varying" values which can be used to pass values between vertex and fragment shaders, "uniform" values allow us to pass values into our shaders from our code. You can think of a uniform value as being used to specify something which is "uniform" (the same) for an entire rendering call.
We'll define two uniforms here:
• end_fog -- distance from the camera at which the fog colour will completely obscure the vertex colour
• fog_color -- the colour of the fog that will be mixed into the (vertex) colour
We'll also define 2 local variables within the main function, these variables are simple floating-point values in this case, but could be any supported type.
We replace our "first principles" approach to calculating the vertex position with the optimized built-in function ftransform() which has certain performance and repeatability guarantees that the matrix multiplication doesn't necessarily provide. As with the raw operation, once we have performed the ftransform(), gl_Position is the eye-space coordinate of this particular vertex.
The "z" coordinate of the vertex in eye-space represents the "depth into the screen". We perform a few basic math operations on the distance value, including one which uses our end_fog distance. We then use the resulting floating-point value to control a "mix" of the uniform fog_color and the current vertex' gl_Color value.
vertex = shaders.compileShader(""" uniform float end_fog; uniform vec4 fog_color; void main() { float fog; // amount of fog to apply float fog_coord; // distance for fog calculation... // This function is generally faster and is guaranteed // to produce the same result on each run... // gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; gl_Position = ftransform(); fog_coord = abs(gl_Position.z); fog_coord = clamp( fog_coord, 0.0, end_fog); fog = (end_fog - fog_coord)/end_fog; fog = clamp( fog, 0.0, 1.0); gl_FrontColor = mix(fog_color, gl_Color, fog); }""",GL_VERTEX_SHADER)
Instead of defining a custom varying value to communicate the vertex colours, we have used the built-in (legacy) varying value "gl_FrontColor" in the vertex shader. The value of gl_FrontColor appears (with interpolation) in the similarly built-in (legacy) value gl_Color within our fragment shader.
Because we altered the colour of each vertex in the vertex shader, the fog is already "baked into" the interpolated colours we receive. We could, instead, have done the distance calculation in the fragment shader, potentially using, for instance, a texture lookup to provide more realistic "wisps" of fog, but the fragment shader is called far more than the vertex shader (normally), which means it is normally a good idea of do as much of your calculation as possible in the vertex shader.