Sunday, April 20, 2008

Destroyer

This is my very 1st game I've created. I know its long overdue to post it now but I've just done the video a few days back.

More details can be found at Destroyer

Saturday, April 12, 2008


08968: Advanced Rendering for Games
Battlefield Game Effects
Danielle Cheah
4/11/2008

Online Doc: Battlefield_Game_Effect

To design, develop and implement graphics effects used in a battlefield game by programming the GPU pipeline. Effects are implemented as a set of shader programs in GLSL.

Battlefield Game Effects Left image shows a global view while the right image shows the internal environment view of the scene.


Basic Effects
Textured Terrain with desert illusion is done by creating a sand like noise,
noisy.x = texture3D(sNoise, noiseRate * vPosition).x;
noisy.y = texture3D(sNoise, noiseRate * vPosition + 0.5).x;
combining it with a soft diffuse lighting colour,
float diffuse = 0.3 + 0.5 * dot(vNormal.xy, vNormal.xy);
a grid pattern,
vec2 fp = fract(patternRate * vPosition.xy + noiseScale * (2.0 * noisy - 1.0));
and a little of the environment map,
vec4 color = textureCube(skyBox, vec3(vTexCoord.xy, 1.0)) * fEnvIntensity;


Combat vehicle; Military tank movement is set by
int iTime = fTime0_X;
int modTime = iTime % 10;
float fTime = modTime + (fTime0_X - iTime);
position.x += fSpeed * fTime;
Military tank texture is determined by the density and the noise texture
vTexCoord.xy = fDensity * gl_MultiTexCoord0.xy;
vec4 vColor = texture2D(sNoise, vTexCoord);


Military equipments (grenade, guns, bomb, Barrels) are textured and per pixel lighted.


Flying Shiny air-plane uses basic illuminated reflective surface,
vec3 reflVec = reflect(-viewDir, N);
vec4 reflection = textureCube(sSkyBox, reflVec.xyz);
vec4 refl = fReflScale * reflection;
and rotation matrix for circular movement,
position.xyz = Rotate(x, y, z, fSpeed * fTime0_X, position.xyz);


An animated, semi transparent, reflective water surface. Wave movement (animation) is calculated by combining the wave speed and noise periodic with time
vec3 texCoord = vTexCoord;
texCoord.x += waveSpeed * fTime0_X;
texCoord.z += noiseSpeed * fTime0_X;
vec4 noisy = texture3D(sNoise, texCoord);
vBump = normalize(vNormal + vBump);
Transparent effect is created by using the Blending function. Reflection vector is calculated from the view direction vector
vec3 reflVec = reflect(vViewDir, vBump);
vec4 refl = textureCube(skyBox, reflVec.xzy);
float lrp = 1.0 - dot(-normalize(vViewDir), vBump);


Sky and mountains are done by environment sphere / cube mapping technique by applying the cube map image in the fragment shader,
gl_FragColor = textureCube(skyBox, vTexCoord);


Bumpy brick walls rendered with bump mapping and parallax mapping technique. Left wall is a bump mapped brick wall. Bump mapping is done by perturbing the pixel to the surface normal based on the heightmap.
vec3 N = normalize(2.0*texture2D(sBumpMap, fBumpDensity * vTexCoord).xyz - 1.0);
While the right wall is a parallax mapped brick wall. Parallax mapping has more realism compared to bump mapping due to the displacement of the texture coordinate from the view direction in tangent space. The tangent matrix,
mat3(vTangent.x, vBinormal.x, vNormal.x,
vTangent.y, vBinormal.y, vNormal.y,
vTangent.z, vBinormal.z, vNormal.z);
Finding the displacement,
vec3 V = normalize(vViewDirection);
float Height = scale * texture2D(sWallHeight, vTexCoord).x - bias;
vec2 TexCorrected = Height * V.xy + vTexCoord;


Fire and smoke with particle systems, bill-boarding techniques, and alpha blending. Particles are crated, looped and changes color it a timely fashion
float t = fract(gl_Vertex.z + particleSpeed * fTime0_X);
vColor = 1.0 – t;
Particles are randomly positioned based on the particle system attributes of particleSpread, particleSystemShape, and particleSystemHeight. Bill-boarding is done by transforming the position based on the ViewMatrix
position += particleSize * (gl_Vertex.x * matViewTranspose[0] + gl_Vertex.y
* matViewTranspose[1]).xyz;
Alpha blending is done by introducing a fade coefficient to the gl_FragColor
float fade = pow(dot(vTexCoord, vTexCoord), particleShape);


Explosions rendered with particle systems and bill-boarding techniques. Explosion effect has additional attribute in terms of a latitude distribution of the particles
float theta = asin(vel.z / radius);
vel.x = particleSpeed * radius * cos(theta) * cos(phi);
vel.y = particleSpeed * 2.0 + abs(particleSpeed * radius * cos(theta) * sin(phi));
and a longitude gravity pull of the particles
pos.y -= (0.5 * fGravity * dTime * dTime);
also the explosion is time controlled to explode at certain periods.


Animated battle flags rendered using some advanced anisotropic illumination technique. Flag animation is by translating the z value of pixels with sin(y) and sin(x) functions
position.z += sin(position.x / 4.0 + angle) * fWaveScale;
position.z += sin(position.y / 4.0 + angle) * fWaveScale / 4.0;
Multiplying again with x value will fix one side of the flag in position
position.z *= (position.x - 14.0) * 0.02;
The normals are calculated by using the same formula applied to x and y values. Anisotropic lighting is used to express micro-faceted surface like cloth fibres. The method used is the Heidrich-Seidel anisotropic distribution based on the Phong reflection model.
Where n is the specular coefficient, L is the light direction, V is the view direction, and T is the tangent space normal. Similar in shader code,
float specular = pow(clamp((cs * cl + sn * sl), 0.0, 1.0), fSpecular);
Getting the tangent space normal
vec3 tang = sinA * vTangent + cosA * vBinormal;


Animated tongue of fire jetted from the tail of a flying fighter plane. Air-plane’s tongues use a particle system, bill-boarding technique, alpha blending, and rotation matrix for circular movement.


Sand clouds generated from vehicle wheels. The sand cloud uses a particle system, bill-boarding technique, and alpha blending techniques. The sand cloud movement is following the tank's time and speed. An additional face coefficient is introduced to produce a finer blend colour.
float fade2 = vPosition.y / particleSystemHeight;


Optional Effects
Shadow effects.
Self casting shadow effect on oil tank. Using the projected vector to create the shadow map
vProjShadow = gl_TextureMatrix[1] * position;
color *= shadow2DProj(sShadowMap, vProjShadow).r;
A blend coefficient is introduced to determine the weight factor for the shadow intensity and blending.


Shadow mapping of air-plane onto terrain. An air-plane image is rendered to a Renderable Texture Target and is combined with the terrain colour. vec4 shadowColor = texture2D(sShadowMap, vTexCoord);
gl_FragColor = finalColor * shadowColor;
The top-left image shows direct blending of the shadow map onto the terrain. The top-right images shows the shadow map blended onto the terrain through the transparent water. The bottom image shows the movement of the shadow following the shiny air-plane.


Ray traced reflection (change in vector direction between two different media so that it returns to the media it originates) and refraction (change in vector direction to a change in speed between two different media) effects from shiny and transparent objects in the battle field, such as glass balls (surveillance balls). Two rotating surveillance balls, one yellow transparent surveillance ball and one solid orange surveillance ball; Left image shows both surveillance balls with reflective attributes and the right image shows the yellow transparent surveillance ball with refractive attribute. Both balls are shaded using the Phong Lighting Model and shadow rayed. A ray is used for reflection and refraction each. Both rays are cast forward in world space to get the 1st hit point of the sphere. For solid objects, the reflection ray is cast forward again from the hit point using the new direction vector. For transparent objects, the reflection and refraction rays are both cast forward again from the hit point using the new direction vector. Direction vectors are found using the reflect() and refract() functions. Three passes are conducted. Each pass will check the object it is currently rendering to set the respective transparency value.


Additional Features (Other novel effects added to increase the realism of the battlefield)

Specular glitter on bomb is done by creating a grid pattern and perturbing it with a 3D noise texture and the view direction for directional glitter effect.
vec3 fp = fract(0.7 * vTexCoord + 9.0 * noisy + 0.1 * vViewDirection);
fp *= 0.5 * (1.0 – fp);
float glitter = clamp(1.0 - 7.0 * (fp.x + fp.y + fp.z), 0.0, 1.0) * 10.0;
Glitter only appears around the specular highlighted and spreads out based on the spread coefficient.


Anisotropic brush metal effect for water tower uses two light direction vectors (original light direction and a –x light direction) to determine if the isotropic highlight occurs. The actual anisotropic direction vector is determined from the dot product between the normal and the ring properties in texture space coordinates. Strand Pair Lighting Model is used to merge both light diffuse and specular colours. For each light direction, the specular colour is power two of the corresponding y value of the 2D texture. The diffuse colour is the corresponding x value of the 2D texture. The (x, y) from the 2D texture is determined from, float LdA = dot(light, dirAniso);
float VdA = dot(view, dirAniso);
vec2 fnLookup = texture2D(sStrand, vec2(LdA, VdA) * 0.5 + vec2(0.5,0.5)).xy;
This lighting model also has self shadowing based on the light direction and vertices normal,
float selfShadow = clamp(dot(normal, light), 0.0, 1.0);


Noise and pattern generation on objects like the wood grain pattern on the saw horse shown in the left image; and the molded grid pattern on the camouflaged gate shown in the right image. The wood grain pattern is created using three different matrixes (three different texture coordinates) to generate three different noise values. The Noise values are added to a frequency scale and blended into the 2D texture.
vec2 scaledDistFromZAxis = vec2(sqrt(dot(vNoisy.xy, vNoisy.xy)) * fFrequency, 0.5); float fBlend = texture2D(sPattern, scaledDistFromZAxis).x;
The grid pattern is created using the fract() function to combine the noise value from a 3D texture with the pattern frequency.
vec2 fp = fract(fPatternRate * vPosition.xy + fNoiseScale * (2.0 * noisy - 1.0)); fp *= (1.0 - fp);


Multi-texturing masking mapped metal bridge uses a mask texture r value to discard the vertice of the original textured surface.
vec4 TexCol = texture2D(sBridgeBase, vTexCoord);
float maskVal = texture2D(sBridgeMask, vTexCoord).r;
if (maskVal < 0.6)
gl_FragColor = (vAmbi + vDiff + vSpec) * TexCol;
else
discard;


Polynomial texture map lighting for tablet wall. The light direction is dependent on the tangent and binormal values and extending the light depth of z direction. From the higher order term, x² + y² + xy, get the two alpha values from two different alpha representation textures.
vec3 lu2_lv2_lulv = nLight.xyx * nLight.xyy;
Merge the colours and discard any out of range values.
vec4 color = vec4(dot(lu2_lv2_lulv, a1) + dot(nLight.xyz, a2));
color = color * texture2D(sBase, vTexCoord);
vec4 maskVal = texture2D(sBase, vTexCoord);
if (maskVal.r>0.2 && maskVal.g>0.2 && maskVal.b>0.2) gl_FragColor = color * 2.0 + + 0.1 * texture2D(sTerrain, vTexCoord);
else
discard;


Combat helicopter with Mandelbrot fractal effect. Fractal is a repetitive smaller representation of an original pattern, a property of self-similarity. Using the superset of “C” is the subset to be colored as part of the Mandelbrot pattern. Mandelbrot has a cardioid region in the center, “c”, each has a bulb attached to it. Each bulb consist of the “C” parameter for which the hyperbolic components, maps to another P component. Implementation include getting the real and imaginary values from the fractal zoom view and the center point, “c”.
float real = vPosition.x * fZoom + vCenter.x;
float imag = vPosition.y * fZoom + vCenter.y;
Loop to populate the Mandelbrot,
for (iter = 0; iter < 15; ++iter)
{
float tempreal = real;
real = (tempreal * tempreal) - (imag * imag) + cReal;
imag = 2.0 * tempreal * imag + cImag;
r2 = (real * real) + (imag * imag);
}
The Mandelbrot, “C”, is colored based on the loop iteration (either foreground or background color).