154
edits
Changes
→Week 7 - Feb 20
}
</syntaxhighlight>
: effects.fx - Constant Memory
<syntaxhighlight lang="cpp">
#define MLIGHTS 4
#define POINT_LIGHT 0
#define SPOT_LIGHT 1
#define DIRECTIONAL_LIGHT 2
// Types
//
// Light holds the data for a single static light in world space
//
struct Light {
int type; // POINT_LIGHT, SPOT_LIGHT, DIRECTIONAL_LIGHT
float3 ambient;
float3 diffuse;
float3 specular;
float3 direction; // in world space
float3 position; // in world space
float3 attenuation; // .xyz for 1.0f/ (.x + .y * d + .z * d * d)
float3 spot; // .x = cos(phi/2), .y = cos(theta/2), .z = falloff
float range; // where attenuation becomes 0
};
// Material holds the reflectivity properties of the material
//
struct Material {
float4 ambient;
float4 diffuse;
float4 specular;
float power;
};
// RawPixel holds the data for a single fragment of the stream
//
struct RawPixel {
float2 texcoord : TEXCOORD0; // texture coordinate at this fragment
float3 position : TEXCOORD1; // fragment position in world space
float3 normal : TEXCOORD2; // lighting normal in world space
float3 toViewer : TEXCOORD3; // direction to viewer in world space
};
// Uniform Data (constant for a stream of fragments)
//
float4 ambient; // global ambient light - always on
int noLights; // no of static lights
Light light[MLIGHTS]; // static lights
bool lightOn[MLIGHTS]; // light switch
Material material; // material reflectivity
bool texOn; // texture switch
sampler2D tex; // set by the application
// Types
//
// RawVertex holds the original data for a vertex in the stream
//
struct RawVertex {
float3 position : POSITION; // position in local space
float3 normal : NORMAL; // normal in local space
float2 texCoord : TEXCOORD0; // texture coordinates
};
// TransformedVertex holds the transformed data for the vertex
//
struct TransformedVertex {
float4 position : POSITION; // position in homogeneous clip space
float2 texCoord : TEXCOORD; // texture coordinates
float3 worldPos : TEXCOORD1; // position in world space
float3 worldNor : TEXCOORD2; // lighting normal in world space
float3 toViewer : TEXCOORD3; // direction to viewer in world space
};
// Uniform Data (constant for the stream of vertices)
//
// Geometry
float4x4 viewProjection; // view * projection transformation
float4x4 world; // world transformation
float4 viewPoint; // camera viewpoint for specular calcs
// Geometry
float3 heading; // camera heading for specular calcs
// Lit Vertex
bool litVertex; // omit lighting calculations - already lit
</syntaxhighlight>
: effects.fx - VertexShader
<syntaxhighlight lang="cpp">
// vertexShader receives a raw data for a vertex and transforms that data
//
TransformedVertex vertexShader(RawVertex raw) {
TransformedVertex transformed; // result returned by this function
float4 worldPosition; // world position of the vertex
float3 worldNormal; // vertex normal in world space
// Transform the vertex to homogeneous clip coordinates
//
// A more efficient algorithm would accept the world*view*projection
// tranformation as one uniform matrix and avoid the 2-stage product
// This will require a bit of restructuring of the application code.
//
worldPosition = mul(float4(raw.position, 1.0), world); // local to world
transformed.position = mul(worldPosition, viewProjection); //... to clip
transformed.worldPos = worldPosition.xyz;
// Transform the vertex normal to world space. Only the rotation-scaling
// part of the world transformation is used. Since the world
// transformation may contain scaling, the result of this multiplication
// needs to be normalized.
//
worldNormal = mul(raw.normal, (float3x3)world);
worldNormal = normalize(worldNormal);
transformed.worldNor = worldNormal;
// Determine the direction from the camera's viewpoint to this vertex for
// subsequent lighting calculations
//
transformed.toViewer = normalize(viewPoint - worldPosition.xyz);
// pass the texture coordinates along unaltered
//
transformed.texCoord = raw.texCoord;
return transformed;
}
</syntaxhighlight>
: effects.fx - FragmentShader
<syntaxhighlight lang="cpp">
// The fragment shader receives raw fragment data and returns a pixel colour
//
float4 fragmentShader(RawPixel raw) : COLOR {
float4 colour; // result returned by this function
float3 normal; // normal to the fragment
float3 toViewer; // from fragment to the camera
float3 toLightSource; // from fragment to current light source
// lighting contribution accumulators
float3 ambientLight = ambient.xyz;
float3 diffuseLight = (float3)0;
float3 specularLight = (float3)0;
// lighting calculation factors
float diffuseFactor, reflectFactor, distance;
float attenuationFactor, spotFactor, rho;
// normalize the fragment data
normal = normalize(raw.normal);
toViewer = normalize(raw.toViewer);
// perform calculations for each light in turn
for (int i = 0; i < noLights && i < MLIGHTS; i++) {
if (lightOn[i]) {
float diffuseFactor, reflectFactor, factor;
// diffuse and reflection factors
toLightSource = normalize((light[i].type == POINT_LIGHT)?
light[i].position - raw.position : - light[i].direction);
diffuseFactor = saturate(dot(normal, toLightSource));
reflectFactor = saturate(dot(normalize(2 * diffuseFactor *
normal - toLightSource), toViewer));
attenuationFactor = 1.0f;
spotFactor = 1.0f;
if (light[i].type == POINT_LIGHT ||
light[i].type == SPOT_LIGHT) {
// detail calcs for attenuationFactor and spotFactor
distance = length(raw.position - light[i].position);
if (distance < light[i].range) {
attenuationFactor = light[i].attenuation.x +
light[i].attenuation.y * distance +
light[i].attenuation.z * distance * distance;
attenuationFactor = 1.0f / attenuationFactor;
if (light[i].type == SPOT_LIGHT) {
rho = saturate(dot(normalize(light[i].position -
float3(raw.position.x, raw.position.y,
raw.position.z)),
normalize(-light[i].direction)));
if (rho <= light[i].spot.x)
spotFactor = 0.0f;
else if (rho <= light[i].spot.y)
spotFactor = pow(abs(
(rho - light[i].spot.x)/
(light[i].spot.y - light[i].spot.x)),
light[i].spot.z);
}
}
else
attenuationFactor = 0.0f;
}
// accumulate ambient, diffuse, and specular elements of light
//
ambientLight += attenuationFactor * spotFactor *
light[i].ambient.xyz;
diffuseLight += attenuationFactor * spotFactor * diffuseFactor *
light[i].diffuse.xyz;
specularLight += attenuationFactor * spotFactor *
light[i].specular.xyz * pow(reflectFactor, material.power);
}
}
// apply material reflectivity to each accumulated element of light
// to obtain the colour of the lit fragment
//
colour.xyz =
saturate(material.ambient.xyz * ambientLight) +
saturate(material.diffuse.xyz * diffuseLight) +
saturate(material.specular.xyz * specularLight);
colour.w = material.diffuse.w;
// apply texture
//
if (texOn)
colour *= tex2D(tex, raw.texcoord);
return colour;
}
</syntaxhighlight>
: effects.fx - technique opaque
<syntaxhighlight lang="cpp">
technique opaque {
pass {
VertexShader = compile vs_3_0 vertexShader();
PixelShader = compile ps_3_0 fragmentShader();
}
}
</syntaxhighlight>
: effects.fx - technique translucent
<syntaxhighlight lang="cpp">
technique translucent {
pass {
VertexShader = compile vs_3_0 vertexShader();
PixelShader = compile ps_3_0 fragmentShader();
}
}
</syntaxhighlight>
<syntaxhighlight lang="cpp">