GAM670/DPS905 Weekly Schedule 20121
GAM670/DPS905 | Weekly Schedule | Student List | Project Requirements | Teams and their Projects | Student Resources
Contents
GAM670/DPS905 -- Weekly Schedule 20121
Week 1 - Jan 8
This Week
- Assignment Discussion
- Suggested Enhancements
- Review of the Base Code
- Definition of a Framework
- Modularity through stable interfaces
- Re-usability through generic components
- Extensibility through hook methods
- Inversion of control - determines which application methods to invoke in response to external events
- Framework Architecture
- Modelling Layer
- API Translation Layer
- Notable Features of the Base Code
- camera, sound, and light are also derived from the Frame class
- textures attach at the object level
- texture connection is uncoupled from drawing of the graphics primitives
- reference frames are relative
- very simple collision detection
- Definition of a Framework
To Do
- add your name to the student list
- create a team page that includes the semester number 20121
- describe the game that you intend to develop
- list the topics of interest to your team in developing its game
- list the other topics of interest
Resources
Week 2 - Jan 16
This Week
- Relative Reference Frames
- Recursive calls
- Vector Frame::position()
- Matrix Frame::rotation()
- Matrix Frame::world()
- Detaching from and attaching to a parent frame
- Frame::attachTo()
- Recursive calls
- Geometry
- Plane
- normal + constant - examples
- equation of a plane: dot(n, x) + D = 0
- positive side of a plane dot(n, x) + D > 0
- Plane
- Collision Detection
- types of colliders
- spheres
- planes
- axis-aligned bounding boxes
- oriented bounding boxes
- types of colliders
To Do
- Research the feature that you are going to add and prepare a plan of action
- Prepare a team page for your team so that repos can be ordered
- Add a section to your team page to track your project and solicit commentary
Resources
Week 3 - Jan 23
This Week
- Collision Detection (cont'd)
- Shape
- Shape : Frame
- Shape::setRadius()
- Shape::getRadius()
- Shape::setRadius(float r);
- Shape::setRadius(float x, float y, float z);
- Shape::getRadius() const { return radius; }
- Shape::setPlane(Vector n, float d);
- Shape::setAxisAligned(Vector min, Vector max);
- Shape
- Comprehensive Camerawork
- rotation about an axis
- order of rotation matters
- Euler angles
- gimbal lock
- complex numbers
- solution of cubic equations 16th century
- two-dimensional representation
- matrix representation
- quaternions
- extension of complex numbers
- four-dimensional representation
- matrix representation
- geometric algebra (more abstract)
- Visibility Determination
- test a point for presence within a set of planes
- normal calculations - general rotation matrix - vector and angle
- ViewFrustum
- parameter - view * projection
- 6 planes
- near and far planes
- left and right planes
- top and bottom planes
- coding
- constructor
- ViewFrustum::contains()
- Finite Size of Objects
- Expansion of the View Frustum
- Index Buffers
- amount of storage needed for vertex data
- duplication of vertex data
- indexing
- indexed primitives
To Do
Resources
- Wikipedia on Complex Numbers
- Wikipedia on Quaternions
- Wikipedia on quaternions and Spatial Rotations
- Wolfram on Quaternions
- CProgramming.com on Quaternions
- Ogre intro on Quaternions
- collision sample
- indexBuffering sample
Week 4 - Jan 30
This Week
- Meshes
- What is a mesh?
- vertex list -> vertex buffer
- index list -> index buffer
- attribute list -> subset to which primitives belong
- pyramid sample
- Stock Objects
- Sphere
- slices and partitions
- Cylinder
- Torus
- Utah Teapot
- APIGraphic.h and .cpp code
- Sphere
- Custom Mesh
- Create a Mesh
- FVF settings
- DrawSubset
- DrawIndexedPrimitive parameters
- APIGraphic.h code
- X File
- Create Mesh from File
- What is a mesh?
- SkyBox
- definition of a skybox
- attachment to camera
- inverted coordinates
- skybox textures
- Graphic.cpp code
- more complicated forms - skydome
- definition of a skybox
- Billboards
- definition, purpose of a billboard
- types of billboards
- screen-aligned - useful for annotation text, lens flares
- normal is opposite to camera heading
- up is camera->up
- axial - useful for cylindrical symmetry - trees (textured object does not face straight on)
- up is fixed
- normal faces the viewer as much as possible
- view_plane - no distortion - useful for
- normal is fixed (opposite to camera heading)
- up is open to change
- viewpoint - simulates distortion due to perspective projection - useful for clouds
- normal is fixed (difference between viewpoint position and camera heading)
- up is open to change
- screen-aligned - useful for annotation text, lens flares
- Object.h and Object.cpp code
- Texture Filtering
- mip maps
- multum in parvo
- texture creation
- APITexture::SetSamplerState()
- mip maps
- DirectX Errors
- DirectX Utilities - Lookup Tool
- APIDisplay::restore() example
To Do
Resources
- meshes sample
- Rob Whitaker on Skyboxes
- Image Based Rendering - Suman Nadella on Billboarding and Imposters
- DigitalRune
- Wikipedia on Texture Filtering
- D3D 9 tutorial on modeling with an Index list
Week 5 - Feb 6
This Week
- Vertex Declarations
- The Pipeline
- The GPU
- nVidia
- AMD (previously ATI)
- Shader Languages
- what is a shader
- dedicated shaders
- unified shaders
- how does a shader work
- Vertex Shaders
- Pixel Shaders
- effect of skybox and point light on frame rate
To Do
Week 6 - Feb 13
This Week
- Vertex Shader Programming
- Host
- APIPlatformSettings.h - Vertex Shader Identification
// shader file data #define VERTEX_SHADER_FILE L"vertexShader.hlsl" #define VERTEX_SHADER_ENTRY_POINT "vertexShader"
- APIBase.h - pointers into the shader
static IDirect3DVertexShader9* vertexShader; // vertex shader static ID3DXConstantTable* uniformVS; // for vertex shader
- APIBase.cpp - initialize pointers
IDirect3DVertexShader9* APIBase::vertexShader = nullptr; // vertex shader ID3DXConstantTable* APIBase::uniformVS = nullptr; // for vertex shader
- APIDisplay.h
Matrix projection; // projection transformation
- APIDisplay.cpp - setup()
// points to compiled shader code LPD3DXBUFFER compiledCodeVS = nullptr; // check for minimum vertex shader version required if (caps.VertexShaderVersion < D3DVS_VERSION(2,0)) error(L"Display::09 Device does not support vertex shader 2_0");
// compile the vertex shader source code else if (FAILED(D3DXCompileShaderFromFile(VERTEX_SHADER_FILE, NULL, NULL, VERTEX_SHADER_ENTRY_POINT, D3DXGetVertexShaderProfile(d3dd), D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, &compiledCodeVS, NULL, &uniformVS))) { release(); error(L"APIDisplay::13 Unable to compile vertex shader"); } // create the vertex shader object else if (FAILED(d3dd->CreateVertexShader( (DWORD*)compiledCodeVS->GetBufferPointer(), &vertexShader))) { compiledCodeVS->Release(); release(); error(L"APIDisplay::14 Unable to create vertex shader object"); } else { compiledCodeVS->Release();
d3dd->SetVertexShader(vertexShader);
- APIDisplay.cpp - setProjection()
this->projection = *((Matrix*)projection);
- APIDisplay.cpp - beginDrawFrame()
Matrix& v = *((Matrix*)view); Matrix viewProjection = v * projection; uniformVS->SetMatrix(d3dd, "viewProjection", (D3DXMATRIX*)&viewProjection); Vector heading(v.m13, v.m23, v.m33); // Required for specular lighting calculations uniformVS->SetFloatArray(d3dd, "heading", (FLOAT*)&heading, 3);
Colour colour(red, green, blue); uniformVS->SetFloatArray(d3dd, "ambient", (FLOAT*)&colour, 4); uniformVS->SetInt(d3dd, "noLights", 4);
- APIDisplay.cpp - set()
uniformVS->SetBool(d3dd, "lighting", b);
- APIDisplay.cpp - setWorld()
uniformVS->SetMatrix(d3dd, "world", (D3DXMATRIX*)world);
- APIDisplay.cpp - setReflectivity()
uniformVS->SetFloatArray(d3dd, "material.ambient", (FLOAT*)&r.ambient, 4); uniformVS->SetFloatArray(d3dd, "material.diffuse", (FLOAT*)&r.diffuse, 4); uniformVS->SetFloatArray(d3dd, "material.specular", (FLOAT*)&r.specular, 4); uniformVS->SetFloat (d3dd, "material.power", (FLOAT)r.power);
- APIDisplay.cpp - release()
// release the shader COM objects if (uniformVS) { uniformVS->Release(); uniformVS = nullptr; } if (vertexShader) { vertexShader->Release(); vertexShader = nullptr; }
- APILight.cpp - setup()
// Populate the vertex shader constant table // // Light descriptors within the vertex shader char typ[] = "light[0].type"; char amb[] = "light[0].ambient"; char dif[] = "light[0].diffuse"; char spe[] = "light[0].specular"; char pos[] = "light[0].position"; char dir[] = "light[0].direction"; char spt[] = "light[0].spot"; char att[] = "light[0].attenuation"; char ran[] = "light[0].range"; // // Reset index in light descriptor typ[6] = index + '0'; amb[6] = index + '0'; dif[6] = index + '0'; spe[6] = index + '0'; pos[6] = index + '0'; dir[6] = index + '0'; spt[6] = index + '0'; att[6] = index + '0'; ran[6] = index + '0'; // Populate the vertex shader constant table Vector attenuation(attenuation0, attenuation1, attenuation2); Vector spot(cosf(phi/2), cosf(theta/2), falloff); Vector zero; uniformVS->SetInt(d3dd, typ, type); uniformVS->SetFloatArray(d3dd, amb, (FLOAT*)&ambient, 4); uniformVS->SetFloatArray(d3dd, dif, (FLOAT*)&diffuse, 4); uniformVS->SetFloatArray(d3dd, spe, (FLOAT*)&specular, 4); uniformVS->SetFloatArray(d3dd, pos, (FLOAT*)&zero, 3); uniformVS->SetFloatArray(d3dd, dir, (FLOAT*)&zero, 3); uniformVS->SetFloatArray(d3dd, att, (FLOAT*)&attenuation, 3); uniformVS->SetFloatArray(d3dd, spt, (FLOAT*)&spot, 3); uniformVS->SetFloat(d3dd, ran, range); rc = true;
- APILight.cpp - turnOn()
char constantLightOn[] = "lightOn[0]"; constantLightOn[8] = index + '0'; char pos[] = "light[0].position"; char dir[] = "light[0].direction"; pos[6] = index + '0'; dir[6] = index + '0'; uniformVS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3); uniformVS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3); uniformVS->SetBool(d3dd, constantLightOn, true);
- APILight.cpp - update()
char constantLightOn[] = "lightOn[0]"; constantLightOn[8] = index + '0'; char pos[] = "light[0].position"; char dir[] = "light[0].direction"; pos[6] = index + '0'; dir[6] = index + '0'; uniformVS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3); uniformVS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3); uniformVS->SetBool(d3dd, constantLightOn, true);
- APILight.cpp - turnOff()
char constantLightOn[] = "lightOn[0]"; constantLightOn[8] = index + '0'; uniformVS->SetBool(d3dd, constantLightOn, false);
- APIGraphic.h - class APIXMesh
D3DXCOLOR* ambient; D3DXCOLOR* diffuse; D3DXCOLOR* specular; FLOAT* power;
- APIGraphic.cpp - APIXMesh()
ambient = nullptr; diffuse = nullptr; specular = nullptr; power = nullptr;
- APIGraphic.cpp - APIXMesh()
ambient = nullptr; diffuse = nullptr; specular = nullptr; power = nullptr;
- APIGraphic.cpp - operator=()
if (ambient) delete [] ambient; if (diffuse) delete [] diffuse; if (specular) delete [] specular; if (power) delete [] power; ambient = new D3DXCOLOR[src.nSubsets]; diffuse = new D3DXCOLOR[src.nSubsets]; specular = new D3DXCOLOR[src.nSubsets]; power = new FLOAT[src.nSubsets];
for (unsigned i = 0; i < nSubsets; i++) { ambient[i] = src.ambient[i]; diffuse[i] = src.diffuse[i]; specular[i] = src.specular[i]; power[i] = src.power[i]; }
- APIGraphic.cpp - setup()
ambient = new D3DXCOLOR[nSubsets]; diffuse = new D3DXCOLOR[nSubsets]; specular = new D3DXCOLOR[nSubsets]; power = new FLOAT[nSubsets];
ambient[i].r = matl[i].MatD3D.Diffuse.r * 0.7f; ambient[i].g = matl[i].MatD3D.Diffuse.g * 0.7f; ambient[i].b = matl[i].MatD3D.Diffuse.b * 0.7f; ambient[i].a = matl[i].MatD3D.Diffuse.a; diffuse[i] = matl[i].MatD3D.Diffuse; // reflected from lights specular[i] = matl[i].MatD3D.Specular; // shine from lights power[i] = matl[i].MatD3D.Power; // 0 if it shouldn't be shiny
- APIGraphic.cpp - draw()
uniformVS->SetFloatArray(d3dd, "material.ambient", (FLOAT*)&ambient[i], 4); uniformVS->SetFloatArray(d3dd, "material.diffuse", (FLOAT*)&diffuse[i], 4); uniformVS->SetFloatArray(d3dd, "material.specular", (FLOAT*)&specular[i], 4); uniformVS->SetFloat(d3dd, "material.power", (FLOAT)power[i]);
- APIGraphic.cpp - suspend()
if (ambient) delete [] ambient; if (diffuse) delete [] diffuse; if (specular) delete [] specular; if (power) delete [] power;
- Device
- vertexShader.hlsl - Constant Memory
#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
- vertexShader.hlsl - vertexShader()
// 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; }
- Fragment Shader
- Host
- APIPlatformSettings.h
#define FRAGMENT_SHADER_FILE L"fragmentShader.hlsl" #define FRAGMENT_SHADER_ENTRY_POINT "fragmentShader"
- APIBase.h
// Fragment Shader Support static IDirect3DPixelShader9* fragmentShader; // fragment shader static ID3DXConstantTable* uniformFS; // for fragment shader
- APIBase.cpp
IDirect3DPixelShader9* APIBase::fragmentShader = nullptr; // fragment shader ID3DXConstantTable* APIBase::uniformFS = nullptr; // for fragment shader
- APIDisplay.cpp - setup()
LPD3DXBUFFER compiledCodeFS = nullptr; // checks for minimum pixel shader version required else if (caps.PixelShaderVersion < D3DPS_VERSION(3,0)) error(L"Display::10 Device does not support pixel shader 3_0");
// compile the fragment shader source code else if (FAILED(D3DXCompileShaderFromFile(FRAGMENT_SHADER_FILE, NULL, NULL, FRAGMENT_SHADER_ENTRY_POINT, D3DXGetPixelShaderProfile(d3dd), 0, &compiledCodeFS, NULL, &uniformFS))) { release(); error(L"APIDisplay::15 Unable to compile the fragment shader code"); } // create the pixel shader object else if (FAILED(d3dd->CreatePixelShader( (DWORD*)compiledCodeFS->GetBufferPointer(), &fragmentShader))) { compiledCodeFS->Release(); release(); error(L"APIDisplay::16 Unable to create fragment shader object"); } else { compiledCodeFS->Release();
d3dd->SetPixelShader(fragmentShader);
- APIDisplay.cpp - beginDrawFrame()
Colour colour(red, green, blue); uniformFS->SetFloatArray(d3dd, "ambient", (FLOAT*)&colour, 4); uniformFS->SetInt(d3dd, "noLights", 4);
- APIDisplay.cpp - set()
uniformFS->SetBool(d3dd, "lighting", b);
- APIDisplay.cpp - setReflectivity()
uniformFS->SetFloatArray(d3dd, "material.ambient", (FLOAT*)&r.ambient, 4); uniformFS->SetFloatArray(d3dd, "material.diffuse", (FLOAT*)&r.diffuse, 4); uniformFS->SetFloatArray(d3dd, "material.specular", (FLOAT*)&r.specular, 4); uniformFS->SetFloat (d3dd, "material.power", (FLOAT)r.power);
- APIDisplay.cpp - release()
} if (uniformFS) { uniformFS->Release(); uniformFS = nullptr; } if (fragmentShader) { fragmentShader->Release(); fragmentShader = nullptr; }
- APIGraphic.cpp - APIXMesh::draw()
uniformFS->SetFloatArray(d3dd, "material.ambient", (FLOAT*)&ambient[i], 4); uniformFS->SetFloatArray(d3dd, "material.diffuse", (FLOAT*)&diffuse[i], 4); uniformFS->SetFloatArray(d3dd, "material.specular", (FLOAT*)&specular[i], 4); uniformFS->SetFloat(d3dd, "material.power", (FLOAT)power[i]);
- APILight.cpp - setup()
uniformFS->SetInt(d3dd, typ, type); uniformFS->SetFloatArray(d3dd, amb, (FLOAT*)&ambient, 4); uniformFS->SetFloatArray(d3dd, dif, (FLOAT*)&diffuse, 4); uniformFS->SetFloatArray(d3dd, spe, (FLOAT*)&specular, 4); uniformFS->SetFloatArray(d3dd, pos, (FLOAT*)&zero, 3); uniformFS->SetFloatArray(d3dd, dir, (FLOAT*)&zero, 3); uniformFS->SetFloatArray(d3dd, att, (FLOAT*)&attenuation, 3); uniformFS->SetFloatArray(d3dd, spt, (FLOAT*)&spot, 3); uniformFS->SetFloat(d3dd, ran, range);
- APILight.cpp - turnOn()
uniformFS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3); uniformFS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3); uniformFS->SetBool(d3dd, constantLightOn, true);
uniformFS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3); uniformFS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3); uniformFS->SetBool(d3dd, constantLightOn, true);
- APILight.cpp - update()
uniformFS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3); uniformFS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3); uniformFS->SetBool(d3dd, constantLightOn, true);
- APILight.cpp - turnOff()
uniformFS->SetBool(d3dd, constantLightOn, false);
- APITexture.cpp - attach()
char str[] = "texOn"; uniformFS->SetBool(d3dd, str, true);
- APITexture.cpp - detach()
char str[] = "texOn"; uniformFS->SetBool(d3dd, str, false);
- Device
- fragmentShader.hlsl - Constant Memory
#define MLIGHTS 4 #define MTEXTURES 2 #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 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; }; // 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 active lights Light light[MLIGHTS]; // static lights bool lightOn[MLIGHTS]; // light switch Material material; // material reflectivity bool lighting; // lighting calculations on? bool texOn; // texture switch sampler2D tex; // set by the application
- fragmentShader.hlsl - fragmentShader()
// 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; }
To Do
- reorganize framework code so that vertex shader receives product of world, view, and projection matrices
- store viewProjection matrix as an instance variable in Display
- pre-multiply viewProjection by world to obtain composite matrix to pass to vertex shader
- add composite matrix to the constant table in the vertex shader
- reorganize framework code to minimize duplication of heading normalization
- perform normalization of heading in APIDisplay::beginDrawFrame()