Appendix A: Predefined Shader Functions

You'll have noticed that most of the shader code is always the same - transforming the position, calculating the tangent matrix, and so on. In A7 those tasks are collected in a small library of predefined shader functions. It's located in in a file named default.fx that sits in the code subfolder. You can use the #include statement for including sections from default.fx that make shader code shorter and cleaner. Details can be found in the shader chapter of the Gamestudio manual. Using includes, our normalmapping shader now looks like this (normalmapping2.fx):

// includes
#include <transform>
#include <fog>
#include <pos>
#include <tangent>
#include <reflect>

// Tweakables:
static const float AmbientIntensity = 1.0f; // The intensity of the ambient light.
static const float DiffuseIntensity = 1.0f; // The intensity of the diffuse light.
static const float SpecularIntensity = 1.0f; // The intensity of the specular light.
static const float SpecularPower = 8.0f; // The specular power. Used as 'glossyness' factor.
static const float4 SunColor = {0.9f, 0.9f, 0.5f, 1.0f}; // Color vector of the sunlight.

// Application fed data:
const float4 vecAmbient; // Ambient color.
const float4 vecSunDir; // The sun light direction vector.

texture entSkin1; // Color map.
sampler ColorMapSampler = sampler_state // Color map sampler.
{
   Texture = <entSkin1>;
   MipFilter = Linear;   // required for mipmapping
}; texture entSkin2; // Normal map. sampler NormalMapSampler = sampler_state // Normal map sampler. { Texture = <entSkin2>; MipFilter = None; // no mipmapping
}; // Vertex Shader: void NormalMapVS( in float4 InPos: POSITION, in float3 InNormal: NORMAL, in float2 InTex: TEXCOORD0, in float4 InTangent: TEXCOORD2, out float4 OutPos: POSITION, out float OutFog: FOG, out float2 OutTex: TEXCOORD0, out float3 OutViewDir: TEXCOORD1, out float3 OutLightDir: TEXCOORD2) { // Transform the vertex from object space to clip space: OutPos = DoTransform(InPos); // set the fog value in case fog is activated OutFog = DoFog(InPos); // Pass the texture coordinate to the pixel shader: OutTex = InTex; // Compute 3x3 matrix to transform from world space to tangent space: CreateTangents(InNormal,InTangent); // Calculate the view direction vector in tangent space: OutViewDir = DoTangent(vecViewPos - DoPos(InPos)); // Calculate the light direction vector in tangent space: OutLightDir = DoTangent(-vecSunDir); } // Pixel Shader: float4 NormalMapPS( in float2 InTex: TEXCOORD0, in float3 InViewDir: TEXCOORD1, in float3 InLightDir: TEXCOORD2) : COLOR { // Read the normal from the normal map and convert from [0..1] to [-1..1] range float3 BumpNormal = 2 * tex2D(NormalMapSampler, InTex) - 1; // Calculate the ambient term: float4 Ambient = AmbientIntensity * vecAmbient; // Calculate the diffuse term: float4 Diffuse = DiffuseIntensity * SunColor * saturate(dot(InLightDir, BumpNormal)); // Calculate the reflection vector: float3 R = DoReflect(BumpNormal, InLightDir); // Calculate the specular term: float Specular = pow(saturate(dot(R, normalize(InViewDir))), SpecularPower) * SpecularIntensity; // Fetch the pixel color from the color map: float4 Color = tex2D(ColorMapSampler, InTex); // Calculate final color: return (Ambient + Diffuse + Specular) * Color; }

Alternatively to writing a script, you can alternatively assing effect files to a part of a model in MED. Go to Edit / Manage Skins. If there is a skin already, click [Skin Settings], otherwise click [New Skin]. Check the [Effect Setup] and [Texture] Boxes and choose an effect file (.fx) and a texture file. Do the same for another skin assigned to another part of the model. This feature is especially useful when you want different parts of the model use different shaders. Close the skin editor and save the model. Done!