154
edits
Changes
→This Week
</pre>
** Device
:: vertexShader.hlsl - Constant Memory
<pre>
#define MLIGHTS 4
#define POINT_LIGHT 0
#define SPOT_LIGHT 1
#define DIRECTIONAL_LIGHT 2
// Types
//
// Light holds the data for a single light in world space
//
struct Light {
int type; // POINT_LIGHT, SPOT_LIGHT, DIRECTIONAL_LIGHT
float4 ambient;
float4 diffuse;
float4 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;
};
// RawVertex holds the untransformed data for a single vertex
//
struct RawVertex {
float3 position : POSITION; // position in local space
float3 normal : NORMAL; // normal in local space
float2 texCoord : TEXCOORD; // texture coordinates
};
// TransformedVertex holds the transformed data for a single vertex
//
struct TransformedVertex {
float4 position : POSITION; // position in homogeneous clip space
float4 colour : COLOR; // colour of the lit vertex
float2 texCoord0 : TEXCOORD0; // texture coordinates - stage 0
float2 texCoord1 : TEXCOORD1; // texture coordinates - stage 1
};
// Uniform Data (constant for a stream of vertices)
//
// Lighting
float4 ambient; // global ambient light - always on
Light light[MLIGHTS]; // static lights
bool lightOn[MLIGHTS]; // switches for static lights
Material material; // material reflectivity
// Geometry
float4x4 viewProjection; // view * projection transformation
float4x4 world; // world transformation
float3 heading; // camera heading for specular calcs
// Lit Vertex
bool litVertex; // omit lighting calculations - already lit
</pre>
:: vertexShader.hlsl - vertexShader()
<pre>
// vertexShader receives a raw vertex and returns the transformed vertex
//
TransformedVertex vertexShader(RawVertex raw) {
TransformedVertex transformed;
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
// not working
if (litVertex) {
transformed.colour.r = raw.normal.r;
transformed.colour.g = raw.normal.g;
transformed.colour.b = raw.normal.b;
transformed.colour.a = 1.0f;
}
else {
// 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);
// Determine the colour of the vertex from each light in turn
//
// Use the cosine of the angle between the worldNormal and the direction
// of the light to determine the amount of reflected light. The cosine
// is given by the dot product, if both vectors have been normalized. If
// the cosine is less than 0, the angle is greater than 90 degrees and
// no light is reflected. Use saturate() to implement this condition.
//
// A more efficient algorithm would supply the light direction already
// converted to the local space of the vertex (by using the inverse of
// the world transformation).
//
float diffuseFactor, reflectFactor, distance;
float attenuationFactor, spotFactor, rho;
float3 lightDirection, camera = normalize(heading);
float3 ambientLight = ambient.xyz;
float3 diffuseLight = (float3)0;
float3 specularLight = (float3)0;
for (int i = 0; i < MLIGHTS; i++) {
if (lightOn[i]) {
lightDirection = - normalize((light[i].type == POINT_LIGHT)?
float3(worldPosition.x, worldPosition.y, worldPosition.z) -
light[i].position : light[i].direction);
diffuseFactor = saturate(dot(worldNormal, lightDirection));
reflectFactor = saturate(dot(normalize(2 * diffuseFactor *
worldNormal - lightDirection), camera));
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((float3)worldPosition - 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(worldPosition.x, worldPosition.y,
worldPosition.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 vertex
//
transformed.colour.xyz =
saturate(material.ambient.xyz * ambientLight) +
saturate(material.diffuse.xyz * diffuseLight) +
saturate(material.specular.xyz * specularLight);
// pass the diffuse alpha along as the alpha component
//
transformed.colour.w = material.diffuse.w;
}
// pass the texture coordinates along unaltered
//
transformed.texCoord0 = raw.texCoord;
transformed.texCoord1 = raw.texCoord;
return transformed;
}
</pre>
* Fragment Shader
** Host