Difference between revisions of "GAM670/DPS905 Weekly Schedule 20121"

From CDOT Wiki
Jump to: navigation, search
(This Week)
(This Week)
 
(57 intermediate revisions by 2 users not shown)
Line 145: Line 145:
 
*: Custom Mesh
 
*: Custom Mesh
 
*:: Create a Mesh
 
*:: Create a Mesh
*:: FVF settings
+
*:: APIGraphic.h code
*:: DrawSubset
+
<syntaxhighlight lang="cpp">
 +
template <class T = Vertex, class I = Index>
 +
class APICustomMesh : public iAPIGraphic, public APIBase {
 +
 
 +
    unsigned  nSubsets;    // number of subsets
 +
    unsigned  nPrimitives; // number of primitives
 +
    unsigned*  attribute;  // points to mesh's attribute list
 +
    I*        index;      // points to mesh's array of indices
 +
    unsigned  iIndex;      // number of indices currently saved
 +
    unsigned  nIndices;    // number of indices in the mesh
 +
    T*        vertex;      // points to mesh's array of vertices
 +
    unsigned  iVertex;    // number of vertices currently saved
 +
    unsigned  nVertices;  // number of vertices in the mesh
 +
    LPD3DXMESH apiMesh;    // set of vertices, indices
 +
 
 +
  protected:
 +
    virtual ~APICustomMesh();
 +
    void setup();
 +
 
 +
  public:
 +
    APICustomMesh(unsigned*, int, int, int, int);
 +
    APICustomMesh(const APICustomMesh& v);         
 +
    APICustomMesh& operator=(const APICustomMesh& v);
 +
    APICustomMesh* clone() const { return new APICustomMesh(*this); }
 +
    unsigned add(const T& v);
 +
    void    add(unsigned);
 +
    void    draw(unsigned);
 +
    void    suspend();
 +
    void    release()          { suspend(); }
 +
    void    Delete() const      { delete this; }
 +
};
 +
</syntaxhighlight>
 +
*:: APIGraphic.cpp - APIGraphic
 +
<syntaxhighlight lang="cpp">
 +
template <class T, class I>
 +
APICustomMesh<T, I>::APICustomMesh(unsigned* a, int np, int ni, int nv, int ns)
 +
: nSubsets(ns), nPrimitives(np), nIndices(ni), nVertices(nv), iIndex(0),
 +
iVertex(0) {
 +
 
 +
    attribute = new unsigned[nPrimitives];
 +
    for (unsigned i = 0; i < nPrimitives; i++)
 +
        attribute[i] = a[i];
 +
 
 +
    index  = new I[nIndices];
 +
    vertex  = new T[nVertices];
 +
 
 +
    apiMesh = nullptr;
 +
}
 +
</syntaxhighlight>
 +
*:: APIGraphic.cpp - add()
 +
<syntaxhighlight lang="cpp">
 +
template <class T, class I>
 +
unsigned APICustomMesh<T, I>::add(const T& v) {
 +
 
 +
    unsigned i = iVertex;
 +
 
 +
    if (vertex && iVertex < nVertices)
 +
        vertex[iVertex++] = v;
 +
 
 +
    return i;
 +
}
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="cpp">
 +
template <class T, class I>
 +
void APICustomMesh<T, I>::add(unsigned v) {
 +
 
 +
    if (index && iIndex < nIndices)
 +
        index[iIndex++] = v;
 +
}
 +
</syntaxhighlight>
 +
*:: APIGraphic.cpp - setup()
 +
<syntaxhighlight lang="cpp">
 +
template <class T, class I>
 +
void APICustomMesh<T, I>::setup() {
 +
 
 +
    T *pv;
 +
    I *pi;
 +
    DWORD *pa;
 +
    nIndices  = iIndex;
 +
    nVertices = iVertex;
 +
 
 +
    // create an empty mesh and lock its buffers
 +
    if (FAILED(D3DXCreateMesh(nPrimitives, nVertices, 0,
 +
    APIVertexDeclaration<T>::format(), d3dd, &apiMesh))) {
 +
        error(L"APIMesh::14 Couldn\'t create the empty mesh");
 +
        apiMesh = nullptr;
 +
    }
 +
    else if (FAILED(apiMesh->LockVertexBuffer(0, (void**)&pv))) {
 +
        error(L"APIMesh::15 Couldn\'t lock vertex buffer");
 +
        release();
 +
    }
 +
    else if (FAILED(apiMesh->LockIndexBuffer(0, (void**)&pi))) {
 +
        error(L"APIMesh::16 Couldn\'t lock index buffer");
 +
        release();
 +
    }
 +
    else if (FAILED(apiMesh->LockAttributeBuffer(0, &pa))) {
 +
        error(L"APIMesh::17 Couldn\'t lock attribute buffer");
 +
        release();
 +
    }
 +
    else {
 +
        // populate the newly created Vertex Buffer
 +
        for (unsigned i = 0; i < nVertices; i++)
 +
            vertex[i].populate((void**)&pv);
 +
        apiMesh->UnlockVertexBuffer();
 +
        // populate the newly created Index Buffer
 +
        for (unsigned i = 0; i < nIndices; i++)
 +
            pi[i] = index[i];
 +
        apiMesh->UnlockIndexBuffer();
 +
        // Populate the newly created Attribute Buffer
 +
        for (unsigned i = 0; i < nPrimitives; i++)
 +
            pa[i] = attribute[i];
 +
        apiMesh->UnlockAttributeBuffer();
 +
    }
 +
}</syntaxhighlight>
 +
*:: APIGraphic.cpp - DrawSubset()
 +
<syntaxhighlight lang="cpp">
 +
template <class T, class I>
 +
void APICustomMesh<T, I>::draw(unsigned iSubset) {
 +
 
 +
    // if mesh doesn't exist, set it up first
 +
    if (!apiMesh) setup();
 +
 
 +
    if (apiMesh)
 +
        apiMesh->DrawSubset(iSubset);
 +
}
 +
</syntaxhighlight>
 
*::: DrawIndexedPrimitive parameters
 
*::: DrawIndexedPrimitive parameters
*:: APIGraphic.h code
+
*:: APIGraphic.cpp - suspend()
 +
<syntaxhighlight lang="cpp">
 +
template <class T, class I>
 +
void APICustomMesh<T, I>::suspend() {
 +
 
 +
    // release the interface to the mesh
 +
    if (apiMesh) {
 +
        apiMesh->Release();
 +
        apiMesh = nullptr;
 +
    }
 +
}
 +
</syntaxhighlight>
 +
*:: APIGraphic.cpp - ~APIGraphic
 +
<syntaxhighlight lang="cpp">
 +
template <class T, class I>
 +
APICustomMesh<T, I>::~APICustomMesh() {
 +
 
 +
    release();
 +
    if (attribute)
 +
        delete [] attribute;
 +
    if (index)
 +
        delete [] index;
 +
    if (vertex)
 +
        delete [] vertex;
 +
}
 +
</syntaxhighlight>
 
*: X File
 
*: X File
 
*:: Create Mesh from File
 
*:: Create Mesh from File
Line 160: Line 310:
 
* Billboards
 
* Billboards
 
*: definition, purpose of a billboard
 
*: definition, purpose of a billboard
 +
<syntaxhighlight lang="cpp">
 +
void Billboard::render(unsigned) {
 +
 +
    Vector h, u, r, p = position();
 +
    Camera* camera = *(Camera**)(Camera::getCurrent());
 +
    Vector cameraPosition = camera->position();
 +
    Vector cameraHeading  = ::normal(camera->orientation('z'));
 +
    Vector cameraUp      = ::normal(camera->orientation('y'));
 +
    switch (type) {
 +
    // ... see below
 +
    }
 +
    Matrix rot(r.x, r.y, r.z, 0,
 +
              u.x, u.y, u.z, 0,
 +
              h.x, h.y, h.z, 0,
 +
                0,  0,  0, 1);
 +
    orient(rot);
 +
 +
    Object::render(0);
 +
}
 +
</syntaxhighlight>
 
*: types of billboards
 
*: types of billboards
 
*:: screen-aligned - useful for annotation text, lens flares
 
*:: screen-aligned - useful for annotation text, lens flares
 
*::: normal is opposite to camera heading
 
*::: normal is opposite to camera heading
 
*::: up is camera->up
 
*::: up is camera->up
 +
<syntaxhighlight lang="cpp">
 +
        case SCREEN:
 +
            h = cameraHeading; // fixed
 +
            u = cameraUp;      // up is fixed 
 +
            r = cross(u, h);
 +
            break;
 +
</syntaxhighlight>
 
*:: axial - useful for cylindrical symmetry - trees (textured object does not face straight on)
 
*:: axial - useful for cylindrical symmetry - trees (textured object does not face straight on)
 
*::: up is fixed
 
*::: up is fixed
 
*::: normal faces the viewer as much as possible
 
*::: normal faces the viewer as much as possible
 +
<syntaxhighlight lang="cpp">
 +
        case AXIAL:
 +
            h = ::normal(position() - cameraPosition); // heading is open to change
 +
            u = Vector(0, 1, 0); // up axis is fixed
 +
            r = cross(u, h);
 +
            h = cross(u, r);
 +
            break;
 +
</syntaxhighlight>
 
*:: view_plane - no distortion - useful for
 
*:: view_plane - no distortion - useful for
 
*::: normal is fixed (opposite to camera heading)
 
*::: normal is fixed (opposite to camera heading)
 
*::: up is open to change
 
*::: up is open to change
 +
<syntaxhighlight lang="cpp">
 +
        case VIEW_PLANE:
 +
            h = cameraHeading;  // heading is fixed
 +
            u = Vector(0, 1, 0); // up is open to change
 +
            r = cross(u, h);
 +
            u = cross(h, r);
 +
            break;
 +
</syntaxhighlight>
 
*:: viewpoint - simulates distortion due to perspective projection - useful for clouds
 
*:: viewpoint - simulates distortion due to perspective projection - useful for clouds
 
*::: normal is fixed (difference between viewpoint position and camera heading)
 
*::: normal is fixed (difference between viewpoint position and camera heading)
 
*::: up is open to change
 
*::: up is open to change
 +
<syntaxhighlight lang="cpp">
 +
        case VIEWPOINT:
 +
            h = ::normal(position() - cameraPosition); // heading is fixed
 +
            u = Vector(0, 1, 0); // up is open to change
 +
            r = cross(u, h);
 +
            u = cross(h, r);
 +
            break;
 +
</syntaxhighlight>
 
*: Object.h and Object.cpp code
 
*: Object.h and Object.cpp code
 
* Texture Filtering
 
* Texture Filtering
Line 179: Line 380:
 
*:: texture creation
 
*:: texture creation
 
*:: APITexture::SetSamplerState()
 
*:: APITexture::SetSamplerState()
 +
<syntaxhighlight lang="cpp">
 +
    // mipmap filtering
 +
    if (flags & TEX_MIPMAP)
 +
        d3dd->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
 +
    else
 +
        d3dd->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
 +
</syntaxhighlight>
 
* DirectX Errors
 
* DirectX Errors
 
*: DirectX Utilities - Lookup Tool
 
*: DirectX Utilities - Lookup Tool
 
*: APIDisplay::restore() example
 
*: APIDisplay::restore() example
 +
<syntaxhighlight lang="cpp">
 +
bool APIDisplay::restore() {
 +
 +
    bool rc = false;
 +
 +
    if (d3dd) {
 +
        HRESULT hr;
 +
        hr = d3dd->TestCooperativeLevel();
 +
        if (hr == D3DERR_DEVICENOTRESET)
 +
            // reset the APIDisplay device
 +
            rc = d3dd->Reset(&d3dpp) == D3D_OK;
 +
        else if (hr == S_OK)
 +
            rc = true;
 +
    }
 +
    if (rc) {
 +
        // reacquire sprite manager references to video memory
 +
        if (manager)
 +
            manager->OnResetDevice();
 +
    }
 +
 +
    // complete the restoration
 +
    if (rc) {
 +
        setupLighting();
 +
        setupBlending();
 +
    }
 +
 +
    return rc;
 +
}
 +
</syntaxhighlight>
  
 
=== To Do ===
 
=== To Do ===
Line 190: Line 427:
 
* [http://www.digitalrune.com/Products/GameEngine/Particles.aspx DigitalRune]
 
* [http://www.digitalrune.com/Products/GameEngine/Particles.aspx DigitalRune]
 
* [http://en.wikipedia.org/wiki/Mipmap Wikipedia on Texture Filtering]
 
* [http://en.wikipedia.org/wiki/Mipmap Wikipedia on Texture Filtering]
 
+
* [http://www.directxtutorial.com/Tutorial9/B-Direct3DBasics/dx9B7.aspx D3D 9 tutorial on modeling with an Index list]
  
 
== Week 5 - Feb 6 ==
 
== Week 5 - Feb 6 ==
 
=== This Week ===
 
=== This Week ===
 +
* Vertex Declarations
 +
*: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb172559%28v=vs.85%29.aspx FVF Codes]
 +
<syntaxhighlight lang="cpp">
 +
template <class T = Vertex>
 +
class APIVertexDeclaration {
 +
 +
    static D3DVERTEXELEMENT9 fmt[MAXD3DDECLLENGTH + 1];
 +
    static unsigned vertexSize;
 +
 +
public:
 +
    static D3DVERTEXELEMENT9* format() { return fmt; }
 +
    static unsigned size()            { return vertexSize; }
 +
};
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="cpp">
 +
template <>
 +
D3DVERTEXELEMENT9 APIVertexDeclaration<Vertex>::fmt[MAXD3DDECLLENGTH + 1]
 +
= {
 +
{ 0,  0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
 +
D3DDECLUSAGE_POSITION, 0},
 +
{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
 +
D3DDECLUSAGE_NORMAL, 0},
 +
{ 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
 +
D3DDECLUSAGE_TEXCOORD, 0},     
 +
D3DDECL_END()};
 +
 +
template<>
 +
unsigned APIVertexDeclaration<Vertex>::vertexSize = 32;
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="cpp">
 +
 +
template <>
 +
D3DVERTEXELEMENT9 APIVertexDeclaration<LitVertex>::fmt[MAXD3DDECLLENGTH + 1]
 +
= {
 +
{ 0,  0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
 +
D3DDECLUSAGE_POSITION, 0},
 +
{ 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
 +
D3DDECLUSAGE_COLOR, 0},
 +
D3DDECL_END()};
 +
 +
template <>
 +
unsigned APIVertexDeclaration<LitVertex>::vertexSize = 16;
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb172630%28v=vs.85%29.aspx D3DVERTEXELEMENT9 struct]
 
* The Pipeline
 
* The Pipeline
 
*: [http://en.wikipedia.org/wiki/Instruction_pipeline What is a pipeline]
 
*: [http://en.wikipedia.org/wiki/Instruction_pipeline What is a pipeline]
Line 219: Line 500:
 
* Pixel Shaders
 
* Pixel Shaders
 
* effect of skybox and point light on frame rate
 
* 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 - select between fixed function and programmable pipelines here
 +
<syntaxhighlight lang="cpp">
 +
// shader file data
 +
#define VERTEX_SHADER_FILE        L"vertexShader.hlsl"
 +
#define VERTEX_SHADER_ENTRY_POINT "vertexShader"
 +
</syntaxhighlight>
 +
: APIBase.h - pointers into the shader - APIBase is the base class for the graphics API classes
 +
<syntaxhighlight lang="cpp">
 +
    static IDirect3DVertexShader9* vertexShader; // vertex shader
 +
    static ID3DXConstantTable*    uniformVS;    // for vertex shader
 +
</syntaxhighlight>
 +
: APIBase.cpp - initialize the shader pointers
 +
<syntaxhighlight lang="cpp">
 +
IDirect3DVertexShader9* APIBase::vertexShader  = nullptr; // vertex shader
 +
ID3DXConstantTable*    APIBase::uniformVS      = nullptr; // for vertex shader
 +
</syntaxhighlight>
 +
: APIDisplay.h - keeps track of the current projection matrix
 +
<syntaxhighlight lang="cpp">
 +
    Matrix  projection;      // projection transformation
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - setup() - checks the shader version
 +
<syntaxhighlight lang="cpp">
 +
    // points to compiled shader code
 +
    LPD3DXBUFFER compiledCodeVS = nullptr;
 +
 +
    // check for minimum vertex shader version required
 +
    if (caps.VertexShaderVersion < D3DVS_VERSION(2,0))
 +
        error(L"APIDisplay::09 Device does not support vertex shader 2_0");
 +
</syntaxhighlight>
 +
compiles the shader hlsl code, retrieves address of constant memory and vertex shader
 +
<syntaxhighlight lang="cpp">
 +
    // 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();
 +
</syntaxhighlight>
 +
sets the current vertex shader
 +
<syntaxhighlight lang="cpp">
 +
        d3dd->SetVertexShader(vertexShader);
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - setProjection() - stores the projection matrix
 +
<syntaxhighlight lang="cpp">
 +
    this->projection = *((Matrix*)projection);
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - beginDrawFrame() - copies the view matrix and the camera heading to constant memory
 +
<syntaxhighlight lang="cpp">
 +
    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);
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="cpp">
 +
        Colour colour(red, green, blue);
 +
        uniformVS->SetFloatArray(d3dd, "ambient", (FLOAT*)&colour, 4);
 +
        uniformVS->SetInt(d3dd, "noLights", 4);
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - set() - copies the lighting state to constant memory
 +
<syntaxhighlight lang="cpp">
 +
                uniformVS->SetBool(d3dd, "lighting", b);
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - setWorld() - copies the world matrix to constant memory
 +
<syntaxhighlight lang="cpp">
 +
        uniformVS->SetMatrix(d3dd, "world", (D3DXMATRIX*)world);
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - setReflectivity() - copies the reflectivity to constant memory
 +
<syntaxhighlight lang="cpp">
 +
        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);
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - release() - releases constant memory and the vertex shader
 +
<syntaxhighlight lang="cpp">
 +
    // release the shader COM objects
 +
    if (uniformVS) {
 +
        uniformVS->Release();
 +
        uniformVS = nullptr;
 +
    }
 +
    if (vertexShader) {
 +
        vertexShader->Release();
 +
        vertexShader = nullptr;
 +
    }
 +
</syntaxhighlight>
 +
: APILight.cpp - setup() - copies the light properties to constant memory
 +
<syntaxhighlight lang="cpp">
 +
        // 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;
 +
</syntaxhighlight>
 +
: APILight.cpp - turnOn() - repositions the light and turns it on
 +
<syntaxhighlight lang="cpp">
 +
        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);
 +
</syntaxhighlight>
 +
: APILight.cpp - update() - repositions the light
 +
<syntaxhighlight lang="cpp">
 +
        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);
 +
</syntaxhighlight>
 +
: APILight.cpp - turnOff() - turns off the light
 +
<syntaxhighlight lang="cpp">
 +
        char constantLightOn[] = "lightOn[0]";
 +
        constantLightOn[8] = index + '0';
 +
        uniformVS->SetBool(d3dd, constantLightOn, false);
 +
</syntaxhighlight>
 +
: APIGraphic.h - class APIXMesh - processes an X file mesh
 +
<syntaxhighlight lang="cpp">
 +
    D3DXCOLOR*          ambient;
 +
    D3DXCOLOR*          diffuse;
 +
    D3DXCOLOR*          specular;
 +
    FLOAT*              power;
 +
</syntaxhighlight>
 +
: APIGraphic.cpp - APIXMesh() - constructor
 +
<syntaxhighlight lang="cpp">
 +
    ambient  = nullptr;
 +
    diffuse  = nullptr;
 +
    specular = nullptr;
 +
    power    = nullptr;
 +
</syntaxhighlight>
 +
: APIGraphic.cpp - APIXMesh() - copy constructor
 +
<syntaxhighlight lang="cpp">
 +
    ambient  = nullptr;
 +
    diffuse  = nullptr;
 +
    specular = nullptr;
 +
    power    = nullptr;
 +
</syntaxhighlight>
 +
: APIGraphic.cpp - operator=() = assignment operator
 +
<syntaxhighlight lang="cpp">
 +
        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];
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="cpp">
 +
        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];
 +
        }
 +
</syntaxhighlight>
 +
: APIGraphic.cpp - setup() -
 +
<syntaxhighlight lang="cpp">
 +
        ambient  = new D3DXCOLOR[nSubsets];
 +
        diffuse  = new D3DXCOLOR[nSubsets];
 +
        specular = new D3DXCOLOR[nSubsets];
 +
        power    = new FLOAT[nSubsets];
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="cpp">
 +
            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
 +
</syntaxhighlight>
 +
: APIGraphic.cpp - draw()
 +
<syntaxhighlight lang="cpp">
 +
            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]);
 +
</syntaxhighlight>
 +
: APIGraphic.cpp - suspend()
 +
<syntaxhighlight lang="cpp">
 +
    if (ambient)
 +
        delete [] ambient;
 +
    if (diffuse)
 +
        delete [] diffuse;
 +
    if (specular)
 +
        delete [] specular;
 +
    if (power)
 +
        delete [] power;
 +
</syntaxhighlight>
 +
* Device
 +
: vertexShader.hlsl - 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 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
 +
 +
</syntaxhighlight>
 +
: vertexShader.hlsl - vertexShader()
 +
<syntaxhighlight lang="cpp">
 +
// 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;
 +
}
 +
</syntaxhighlight>
 +
 +
==== Fragment Shader ====
 +
* Host
 +
: APIPlatformSettings.h
 +
<syntaxhighlight lang="cpp">
 +
#define FRAGMENT_SHADER_FILE        L"fragmentShader.hlsl"
 +
#define FRAGMENT_SHADER_ENTRY_POINT "fragmentShader"
 +
</syntaxhighlight>
 +
: APIBase.h
 +
<syntaxhighlight lang="cpp">
 +
    // Fragment Shader Support
 +
    static IDirect3DPixelShader9* fragmentShader; // fragment shader
 +
    static ID3DXConstantTable*    uniformFS;      // for fragment shader
 +
</syntaxhighlight>
 +
: APIBase.cpp
 +
<syntaxhighlight lang="cpp">
 +
IDirect3DPixelShader9*  APIBase::fragmentShader = nullptr; // fragment shader
 +
ID3DXConstantTable*    APIBase::uniformFS      = nullptr; // for fragment shader
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - setup()
 +
<syntaxhighlight lang="cpp">
 +
    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");
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="cpp">
 +
    // 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();
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb172732%28v=vs.85%29.aspx D3DXCompileShaderFromFile()]
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb172870%28v=vs.85%29.aspx D3DXGetPixelShaderProfile()]
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb174450%28v=vs.85%29.aspx IDirect3DDevice9::CreatePixelShader()]
 +
<syntaxhighlight lang="cpp">
 +
        d3dd->SetPixelShader(fragmentShader);
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb174450%28v=vs.85%29.aspx IDirect3DDevice9::SetPixelShader()]
 +
: APIDisplay.cpp - beginDrawFrame()
 +
<syntaxhighlight lang="cpp">
 +
        Colour colour(red, green, blue);
 +
        uniformFS->SetFloatArray(d3dd, "ambient", (FLOAT*)&colour, 4);
 +
        uniformFS->SetInt(d3dd, "noLights", 4);
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205775%28v=vs.85%29.aspx ID3DXConstantTable::SetFloatArray()]
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205776%28v=vs.85%29.aspx ID3DXConstantTable::SetInt()]
 +
: APIDisplay.cpp - set()
 +
<syntaxhighlight lang="cpp">
 +
                uniformFS->SetBool(d3dd, "lighting", b);
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205771%28v=vs.85%29.aspx ID3DXConstantTable::SetBool()]
 +
: APIDisplay.cpp - setReflectivity()
 +
<syntaxhighlight lang="cpp">
 +
        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);
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - release()
 +
<syntaxhighlight lang="cpp">
 +
    }
 +
    if (uniformFS) {
 +
        uniformFS->Release();
 +
        uniformFS = nullptr;
 +
    }
 +
    if (fragmentShader) {
 +
        fragmentShader->Release();
 +
        fragmentShader = nullptr;
 +
    }
 +
</syntaxhighlight>
 +
: APIGraphic.cpp - APIXMesh::draw()
 +
<syntaxhighlight lang="cpp">
 +
            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]);
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205774%28v=vs.85%29.aspx ID3DXConstantTable::SetFloat()]
 +
: APILight.cpp - setup()
 +
<syntaxhighlight lang="cpp">
 +
        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);
 +
</syntaxhighlight>
 +
: APILight.cpp - turnOn()
 +
<syntaxhighlight lang="cpp">
 +
        uniformFS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3);
 +
        uniformFS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3);
 +
        uniformFS->SetBool(d3dd, constantLightOn, true);
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="cpp">
 +
        uniformFS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3);
 +
        uniformFS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3);
 +
        uniformFS->SetBool(d3dd, constantLightOn, true);
 +
</syntaxhighlight>
 +
: APILight.cpp - update()
 +
<syntaxhighlight lang="cpp">
 +
        uniformFS->SetFloatArray(d3dd, pos, (FLOAT*)&p, 3);
 +
        uniformFS->SetFloatArray(d3dd, dir, (FLOAT*)&o, 3);
 +
        uniformFS->SetBool(d3dd, constantLightOn, true);
 +
</syntaxhighlight>
 +
: APILight.cpp - turnOff()
 +
<syntaxhighlight lang="cpp">
 +
        uniformFS->SetBool(d3dd, constantLightOn, false);
 +
</syntaxhighlight>
 +
: APITexture.cpp - attach()
 +
<syntaxhighlight lang="cpp">
 +
        char str[] = "texOn";
 +
        uniformFS->SetBool(d3dd, str, true);
 +
</syntaxhighlight>
 +
: APITexture.cpp - detach()
 +
<syntaxhighlight lang="cpp">
 +
        char str[] = "texOn";
 +
        uniformFS->SetBool(d3dd, str, false);
 +
</syntaxhighlight>
 +
* Device
 +
: vertexShader.hlsl - Constant Memory
 +
<syntaxhighlight lang="cpp">
 +
// 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
 +
float3  viewPoint;        // camera viewpoint for specular calcs
 +
// Lit Vertex
 +
bool    litVertex;        // omit lighting calculations - already lit
 +
 +
</syntaxhighlight>
 +
: vertexShader.hlsl - 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>
 +
: fragmentShader.hlsl - Constant Memory
 +
<syntaxhighlight lang="cpp">
 +
#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
 +
 +
</syntaxhighlight>
 +
: fragmentShader.hlsl - 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>
  
 
=== To Do ===
 
=== To Do ===
 
* reorganize framework code so that vertex shader receives product of world, view, and projection matrices
 
* reorganize framework code so that vertex shader receives product of world, view, and projection matrices
** store viewProjection matrix as an instance variable in Display
+
** store viewProjection matrix as an instance variable in APIDisplay
** add viewProjection query to Display to extract product of view and projection matrices
 
** retrieve viewProjection in *::draw() method
 
 
** pre-multiply viewProjection by world to obtain composite matrix to pass to vertex shader
 
** 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
 
** add composite matrix to the constant table in the vertex shader
 
* reorganize framework code to minimize duplication of heading normalization
 
* reorganize framework code to minimize duplication of heading normalization
** perform normalization of heading in Display::beginDraw()
+
** perform normalization of heading in APIDisplay::beginDrawFrame()
 +
 
 +
=== Resources ===
  
<!--
+
== Week 7 - Feb 20 ==
== Week 6 - Feb 13 ==
 
 
=== This Week ===
 
=== This Week ===
 
* Effects Framework
 
* Effects Framework
 +
** techniques
 +
*: passes
 +
* Source Code
 +
: APIBase.h
 +
<syntaxhighlight lang="cpp">
 +
    static ID3DXEffect*          effect;        // points to effects framework
 +
</syntaxhighlight>
 +
: APIBase.cpp
 +
<syntaxhighlight lang="cpp">
 +
ID3DXEffect*            APIBase::effect        = nullptr; // effects framework
 +
</syntaxhighlight>
 +
: APIDisplay.h
 +
<syntaxhighlight lang="cpp">
 +
    // Effects Framework handles
 +
    D3DXHANDLE  viewProjection;  // view * projection
 +
    D3DXHANDLE  viewPoint;        // camera viewpoint
 +
    D3DXHANDLE  ambient;          // global ambient color
 +
    D3DXHANDLE  ambientHandle;    // current ambient reflectivity
 +
    D3DXHANDLE  diffuseHandle;    // current diffuse reflectivity
 +
    D3DXHANDLE  specularHandle;  // current specular reflectivity
 +
    D3DXHANDLE  powerHandle;      // current shininess coefficient
 +
    D3DXHANDLE  worldHandle;      // current world transformation
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="cpp">
 +
    void beginEffect(const char*, unsigned&);
 +
    void beginPass(unsigned);
 +
    void endPass();
 +
    void endEffect();
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - APIDisplay()
 +
<syntaxhighlight lang="cpp">
 +
    viewProjection = nullptr;
 +
    viewPoint      = nullptr;
 +
    ambient        = nullptr;
 +
    ambientHandle  = nullptr;
 +
    diffuseHandle  = nullptr;
 +
    specularHandle = nullptr;
 +
    powerHandle    = nullptr;
 +
    worldHandle    = nullptr;
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - setup()
 +
<syntaxhighlight lang="cpp">
 +
    LPD3DXBUFFER errorBuffer = NULL;
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="cpp">
 +
    // create the effects framework
 +
    else if (FAILED(D3DXCreateEffectFromFile(d3dd, EFFECT_FILE, 0,
 +
    0, D3DXSHADER_DEBUG, 0, &effect, &errorBuffer))) {
 +
        release();
 +
        error(L"APIDisplay::17 Unable to create the effects framework");
 +
    }
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb172768%28v=vs.85%29.aspx D3DXCreateEffectFromFile()]
 +
<syntaxhighlight lang="cpp">
 +
        if (errorBuffer) errorBuffer->Release();
 +
        viewProjection = effect->GetParameterByName(0, "viewProjection");
 +
        viewPoint      = effect->GetParameterByName(0, "viewPoint");
 +
        ambient        = effect->GetParameterByName(0, "ambient");
 +
        worldHandle    = effect->GetParameterByName(0, "world");
 +
        ambientHandle  = effect->GetParameterByName(0, "material.ambient");
 +
        diffuseHandle  = effect->GetParameterByName(0, "material.diffuse");
 +
        specularHandle = effect->GetParameterByName(0, "material.specular");
 +
        powerHandle    = effect->GetParameterByName(0, "material.power");
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205696%28v=vs.85%29.aspx GetParameterByName()]
 +
: APIDisplay.cpp - beginDrawFrame()
 +
<syntaxhighlight lang="cpp">
 +
    Matrix& v = *((Matrix*)view);
 +
    Matrix viewprojection = v * projection;
 +
    Vector heading(v.m13, v.m23, v.m33);
 +
    effect->SetMatrix(viewProjection, (D3DXMATRIX*)&viewprojection);
 +
    effect->SetVector(viewPoint,      (D3DXVECTOR4*)&heading);
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205720%28v=vs.85%29.aspx SetMatrix()]
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205729%28v=vs.85%29.aspx SetVector()]
 +
<syntaxhighlight lang="cpp">
 +
        Colour colour(red, green, blue);
 +
        effect->SetVector(ambient, (D3DXVECTOR4*)&colour);
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - beginEffect()
 +
<syntaxhighlight lang="cpp">
 +
void APIDisplay::beginEffect(const char* technique, unsigned& nPasses) {
 +
 +
    D3DXHANDLE techniqueHandle = effect->GetTechniqueByName(technique);
 +
    effect->SetTechnique(techniqueHandle);
 +
    effect->Begin(&nPasses, 0);
 +
}
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205706%28v=vs.85%29.aspx GetTechniqueByName()]
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205834%28v=vs.85%29.aspx SetTechnique()]
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205815%28v=vs.85%29.aspx Begin()]
 +
: APIDisplay.cpp - beginPass()
 +
<syntaxhighlight lang="cpp">
 +
void APIDisplay::beginPass(unsigned i) {
 +
 +
    effect->BeginPass(i);
 +
}
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205817%28v=vs.85%29.aspx BeginPass()]
 +
: APIDisplay.cpp - endPass()
 +
<syntaxhighlight lang="cpp">
 +
void APIDisplay::endPass() {
 +
 +
    effect->EndPass();
 +
}
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205823%28v=vs.85%29.aspx EndPass()]
 +
: APIDisplay.cpp - endEffect()
 +
<syntaxhighlight lang="cpp">
 +
void APIDisplay::endEffect() {
 +
 +
    effect->End();
 +
}
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205821%28v=vs.85%29.aspx End()]
 +
: APIDisplay.cpp - setWorld()
 +
<syntaxhighlight lang="cpp">
 +
        effect->SetMatrix(worldHandle, (D3DXMATRIX*)world);
 +
</syntaxhighlight>
 +
: APIDisplay.cpp - setReflectivity()
 +
<syntaxhighlight lang="cpp">
 +
        effect->SetVector(ambientHandle,  (D3DXVECTOR4*)&r.ambient);
 +
        effect->SetVector(diffuseHandle,  (D3DXVECTOR4*)&r.diffuse);
 +
        effect->SetVector(specularHandle, (D3DXVECTOR4*)&r.specular);
 +
        effect->SetFloat(powerHandle,    r.power);
 +
        effect->CommitChanges();
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb205819%28v=vs.85%29.aspx CommitChanges()]
 +
: APIDisplay.cpp - release()
 +
<syntaxhighlight lang="cpp">
 +
    if (effect) {
 +
        effect->Release();
 +
        effect = NULL;
 +
    }
 +
</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">
 +
</syntaxhighlight>
 
=== To Do ===
 
=== To Do ===
 
=== Resources ===
 
=== Resources ===
  
== Week 7 - Feb 20 ==
+
== Week 8 - Mar 4 ==
 
=== This Week ===
 
=== This Week ===
 +
* Frank Luna's notes for DirectX10 (page 306)
 +
:[http://books.google.ca/books?id=AyACb-t8E-MC&pg=PA306&lpg=PA306#v=onepage&q&f=false Environment Maps](Google books)
 +
:[http://libcat.senecac.on.ca/vwebv/holdingsInfo?searchId=19588&recCount=50&recPointer=2&bibId=261220 Environment Maps](Seneca ELibraray)
 +
* Design.cpp
 +
: Design::initialize() - create the skybox object
 +
<syntaxhighlight lang="cpp">
 +
// initialize initializes the general display design coordinator, creates the
 +
// primitive sets, textures, objects, lights, sounds, cameras, and text items
 +
//
 +
void Design::initialize() {
 +
 +
    // ...
 +
 +
    // create textures
 +
    iTexture* sunset  = CreateCubeTexture(L"Islands.dds");
 +
 +
    // ...
 +
 +
    iObject* skybox = CreateSkybox();
 +
    skybox->rotatex(-1.5708f);
 +
    skybox->attach(sunset);
 +
    setSkybox(skybox);
 +
 +
    // ...
 +
}
 +
</syntaxhighlight>
 +
* Coordinator.cpp
 +
: Coordinator::render() - using different techniques for different objects
 +
<syntaxhighlight lang="cpp">
 +
void Coordinator::render() {
 +
 +
    // adjust framecount and fps
 +
    if (now - lastReset <= unitsPerSec)
 +
        framecount++;
 +
    else {
 +
        // recalculate the frame rate
 +
        fps        = framecount * unitsPerSec / (now - lastReset);
 +
        framecount = 0;
 +
        lastReset  = now;
 +
        if (timerText) {
 +
            wchar_t str[MAX_DESC + 1];
 +
            sprintf(str, fps, L" fps");
 +
            timerText->set(str);
 +
        }
 +
    }
 +
    // update the user input devices
 +
    userInput->update();
 +
    Coordinator::update();
 +
    // update the model
 +
    update();
 +
    // update the audio
 +
    audio->setVolume(volume);
 +
    audio->setFrequencyRatio(frequency);
 +
    audio->update(Camera::getView());
 +
 +
    // start rendering
 +
    display->beginDrawFrame(Camera::getView());
 +
    display->setAmbientLight(ambient.r, ambient.g, ambient.b);
 +
    unsigned nPasses;
 +
    // render all of the opaque unlit objects
 +
    display->beginEffect("opaque", nPasses);
 +
    for (unsigned i = 0; i < nPasses; i++) {
 +
        display->beginPass(i);
 +
        render(OPAQUE_OBJECT);
 +
        display->endPass();
 +
    }
 +
    display->endEffect();
 +
    // render all of the translucent unlit objects
 +
    display->beginEffect("translucent", nPasses);
 +
    for (unsigned i = 0; i < nPasses; i++) {
 +
        display->beginPass(i);
 +
        render(TRANSLUCENT_OBJECT);
 +
        display->endPass();
 +
    }
 +
    display->endEffect();
 +
    // render all of the lit objects
 +
    display->beginEffect("litObjects", nPasses);
 +
    for (unsigned i = 0; i < nPasses; i++) {
 +
        display->beginPass(i);
 +
        render(LIT_OBJECT);
 +
        display->endPass();
 +
    }
 +
    display->endEffect();
 +
    //  render the skybox
 +
    display->beginEffect("skybox", nPasses);
 +
    if (background && !skybox) {
 +
        Rectf fullScreen(0, 0, 1, 1);
 +
        display->beginDrawHUD(0);
 +
        background->render(fullScreen, true);
 +
        display->endDrawHUD();
 +
    }
 +
    else if (skybox) {
 +
        for (unsigned i = 0; i < nPasses; i++) {
 +
            display->beginPass(i);
 +
            render(SKYBOX);
 +
            display->endPass();
 +
        }
 +
    }
 +
    display->endEffect();
 +
    display->set(ALPHA_BLEND, false);
 +
    display->beginDrawHUD(HUD_ALPHA);
 +
    render(ALL_HUDS);
 +
    display->endDrawHUD();
 +
    display->endDrawFrame();
 +
    render(ALL_SOUNDS);
 +
}
 +
</syntaxhighlight>
 +
: Coordinator::render(iObject*) - render a single object one subset at a time
 +
<syntaxhighlight lang="cpp">
 +
void Coordinator::render(iObject* object) {
 +
 +
    display->setWorld(&object->world());
 +
    unsigned nSubsets = object->noSubsets();
 +
    for (unsigned i = 0; i < nSubsets; i++) {
 +
        iTexture* texture = object->getTexture(i);
 +
        if (texture) texture->attach();
 +
        display->setReflectivity(object->getReflectivity(i));
 +
        object->render(i);
 +
        if (texture) texture->detach();
 +
    }
 +
}
 +
</syntaxhighlight>
 +
* Skybox class
 +
: iObject interface - CreateSkybox declaration
 +
<syntaxhighlight lang="cpp">
 +
class iObject : public Shape, public Base {
 +
  public:
 +
    // initialization
 +
    virtual void        attach(iTexture* t)                  = 0;
 +
    virtual void        attach(iTexture** t)                = 0;
 +
    // execution
 +
    virtual unsigned    noSubsets() const                    = 0;
 +
    virtual void        render(unsigned)                    = 0;
 +
    virtual void        setTextureFilter(unsigned)          = 0;
 +
    virtual iTexture*  getTexture(unsigned) const          = 0;
 +
    virtual const void* getReflectivity(unsigned) const      = 0;
 +
    virtual bool        belongsTo(Category category) const  = 0;
 +
};
 +
 +
iObject* CreateObject(iGraphic*, const Reflectivity* = nullptr, unsigned = 1u);
 +
iObject* CreateBillboard(BillboardType, iGraphic*,
 +
const Reflectivity* = nullptr);
 +
iObject* CreateSkybox();
 +
 +
iObject* Clone(const iObject*);
 +
</syntaxhighlight>
 +
: Skybox class - derived from Object
 +
<syntaxhighlight lang="cpp">
 +
//-------------------------------- Skybox -------------------------------------
 +
//
 +
// A Skybox is an inverted Object that translates with the viewpoint
 +
//
 +
class Skybox : public Object {
 +
 +
public:
 +
    Skybox();
 +
    void render(unsigned);
 +
};
 +
</syntaxhighlight>
 +
: CreateSkybox
 +
<syntaxhighlight lang="cpp">
 +
iObject* CreateSkybox() {
 +
 +
    return new Skybox();
 +
}
 +
</syntaxhighlight>
 +
: Skybox::Skybox - SKYBOX category, 2 x 2 x 2 cube
 +
<syntaxhighlight lang="cpp">
 +
Skybox::Skybox() : Object(SKYBOX, CreateIBox(-1, -1, -1 * MODEL_Z_AXIS, 1, 1,
 +
1 * MODEL_Z_AXIS)) {
 +
}
 +
</syntaxhighlight>
 +
: Skybox::render(unsigned) - move skybox centroid to current camera position
 +
<syntaxhighlight lang="cpp">
 +
void Skybox::render(unsigned) {
 +
 +
    Camera* camera = *(Camera**)(Camera::getCurrent());
 +
    Vector disp = camera->position() - position();
 +
    translate(disp.x, disp.y, disp.z);
 +
 +
    Object::render(0);
 +
}
 +
</syntaxhighlight>
 +
* Texture class
 +
: iTexture interface - CreateCubeTexture declaration
 +
<syntaxhighlight lang="cpp">
 +
class iTexture : public Base {
 +
  public:
 +
    virtual void attach() const                                        = 0;
 +
    virtual void setFilter(unsigned) const                            = 0;
 +
    virtual void detach()                                              = 0;
 +
    virtual void render(const Rectf&, bool = false)                    = 0;
 +
};
 +
 +
iTexture* CreateTexture(const wchar_t* file, unsigned filter = 0);
 +
iTexture* CreateCubeTexture(const wchar_t* file, unsigned filter = 0);
 +
 +
iTexture* Clone(const iTexture*);
 +
</syntaxhighlight>
 +
: Texture class - add the cube parameter to constructor
 +
<syntaxhighlight lang="cpp">
 +
class Texture : public iTexture {
 +
 +
    iAPITexture* apiTexture;  // points to the api texture
 +
 +
    Texture(const Texture&);
 +
    virtual ~Texture();
 +
 +
  public:
 +
    Texture(const wchar_t* file, unsigned filter = 0, bool cube = false);
 +
    Texture& operator=(const Texture&);
 +
    void* clone() const { return new Texture(*this); }
 +
    // execution
 +
    void attach() const;
 +
    void setFilter(unsigned) const;
 +
    void detach();
 +
    void render(const Rectf&, bool);
 +
    // termination
 +
    void suspend();
 +
    void release();
 +
};</syntaxhighlight>
 +
: CreateCubeTexture - call constructor with true flag for cube
 +
<syntaxhighlight lang="cpp">
 +
iTexture* CreateCubeTexture(const wchar_t* file, unsigned filter) {
 +
 +
    return new Texture(file, filter, true);
 +
}
 +
</syntaxhighlight>
 +
: Texture::Texture() - create APICubeTexture()
 +
<syntaxhighlight lang="cpp">
 +
Texture::Texture(const wchar_t* file, unsigned filter, bool cube) {
 +
 +
    coordinator->add(this);
 +
 +
    wchar_t* fileWithPath = nullptr;
 +
    if (file) {
 +
        // add the directory to create the relative filename
 +
        int len = strlen(file) + strlen(TEXTURE_DIRECTORY) + 1;
 +
        fileWithPath = new wchar_t[len + 1];
 +
        ::nameWithDir(fileWithPath, TEXTURE_DIRECTORY, file, len);
 +
    }
 +
 +
    // apiTexture on the graphics device
 +
    if (cube)
 +
        apiTexture = CreateAPICubeTexture(fileWithPath);
 +
    else
 +
        apiTexture = CreateAPITexture(fileWithPath, filter);
 +
 +
    if (fileWithPath) delete [] fileWithPath;
 +
}
 +
</syntaxhighlight>
 +
: iAPITexture interface - add CreateAPICubeTexture declaration
 +
<syntaxhighlight lang="cpp">
 +
class iAPITexture {
 +
  public:
 +
    virtual iAPITexture* clone() const                                = 0;
 +
    // execution
 +
    virtual void attach()                                            = 0;
 +
    virtual void setFilter(unsigned flags)                            = 0;
 +
    virtual void detach()                                            = 0;
 +
    virtual void render(const Rectf&, unsigned char, bool = false)    = 0;
 +
    // termination
 +
    virtual void suspend()                                            = 0;
 +
    virtual void release()                                            = 0;
 +
    virtual void Delete() const                                      = 0;
 +
};
 +
 +
iAPITexture* CreateAPITexture(const wchar_t* file, unsigned filter);
 +
iAPITexture* CreateAPICubeTexture(const wchar_t* file);
 +
</syntaxhighlight>
 +
* APITexture.h
 +
: APICubeTexture class definition
 +
<syntaxhighlight lang="cpp">
 +
class APICubeTexture : public iAPITexture, public APIBase {
 +
 +
    wchar_t*              file;  // points to file with texture image
 +
    unsigned              filter; // default texture filtering flags
 +
 +
    IDirect3DCubeTexture9* tex;    // interface to texture COM object
 +
 +
    virtual ~APICubeTexture();
 +
 +
    void setup();
 +
 +
  public:
 +
    APICubeTexture(const wchar_t* file);
 +
    APICubeTexture(const APICubeTexture&);
 +
    iAPITexture& operator=(const APICubeTexture&);
 +
    iAPITexture* clone() const { return new APICubeTexture(*this); }
 +
    // execution
 +
    void  attach();
 +
    void  setFilter(unsigned filter) {}
 +
    void  detach();
 +
    void  render(const Rectf&, unsigned char, bool) {}
 +
    // suspension
 +
    void  suspend();
 +
    // termination
 +
    void  release();
 +
    void  Delete() const { delete this; }
 +
};
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb174329%28v=vs.85%29.aspx IDirect3DCubeTexture9 interface]
 +
: APICubeTexture class implementation
 +
<syntaxhighlight lang="cpp">
 +
//-------------------------------- APICubeTexture -----------------------------
 +
//
 +
// The APICubeTexture class implements a texture at the API level
 +
//
 +
iAPITexture* CreateAPICubeTexture(const wchar_t* file) {
 +
 +
    return new APICubeTexture(file);
 +
}
 +
 +
// constructor initializes the texture identifier
 +
//
 +
APICubeTexture::APICubeTexture(const wchar_t* file) {
 +
 +
    if (file) {
 +
        int len = strlen(file);
 +
        this->file = new wchar_t[len + 1];
 +
        strcpy(this->file, file, len);
 +
    }
 +
    else
 +
        this->file = nullptr;
 +
 +
    tex = nullptr;
 +
}
 +
 +
APICubeTexture::APICubeTexture(const APICubeTexture& src) {
 +
 +
    file  = nullptr;
 +
    tex  = nullptr;
 +
    *this = src; 
 +
}
 +
 +
iAPITexture& APICubeTexture::operator=(const APICubeTexture& src) {
 +
 +
    if (this != &src) {
 +
        if (file)
 +
            delete [] file;
 +
        if (src.file) {
 +
            int len = strlen(src.file);
 +
            file = new wchar_t[len + 1];
 +
            strcpy(file, src.file, len);
 +
        }
 +
        else
 +
            file = nullptr;
 +
        suspend();
 +
        tex = nullptr;
 +
    }
 +
 +
    return *this;
 +
}
 +
 +
// setup creates the api texture from the texture file
 +
//
 +
void APICubeTexture::setup() {
 +
 +
    // create a texture COM object from the texture file
 +
    //
 +
    HRESULT hr;
 +
    if (file && FAILED(hr = D3DXCreateCubeTextureFromFileEx(d3dd, file,
 +
    0, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_DEFAULT,
 +
    D3DX_DEFAULT, 0, nullptr, nullptr, &tex))) {
 +
        error(L"APICubeTexture::11 Failed to create texture COM object from file");
 +
        tex = nullptr;
 +
    }
 +
}
 +
 +
// attach attaches the api texture to sampling stage i
 +
//
 +
void APICubeTexture::attach() {
 +
 +
    if (!tex) setup();
 +
 +
    if (tex)
 +
        d3dd->SetTexture(0, tex);
 +
}
 +
 +
// detach detaches the api texture from sampling stage 0
 +
//
 +
void APICubeTexture::detach() {
 +
 +
    if (tex)
 +
        d3dd->SetTexture(0, nullptr);
 +
}
 +
 +
// suspend releases the api texture
 +
//
 +
void APICubeTexture::suspend() {
 +
 +
    // release the Interface to the texture COM object
 +
    if (tex) {
 +
        tex->Release();
 +
        tex = nullptr;
 +
    }
 +
}
 +
 +
// releases suspends the api texture
 +
//
 +
void APICubeTexture::release() {
 +
 +
    suspend();
 +
}
 +
 +
// destructor releases the api texture
 +
//
 +
APICubeTexture::~APICubeTexture() {
 +
 +
  release();
 +
}
 +
</syntaxhighlight>
 +
:: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb172757%28v=vs.85%29.aspx D3DXCreateCubeTextureFromFileEx]
 +
* effects.fx
 +
: vertex shader outpu structure
 +
<syntaxhighlight lang="cpp">
 +
//-------------------------------- Skybox -------------------------------------
 +
//
 +
struct FS_Skybox {
 +
    float4 pos : POSITION;
 +
    float3 tex : TEXCOORD0;
 +
};
 +
</syntaxhighlight>
 +
: vertex shader
 +
<syntaxhighlight lang="cpp">
 +
FS_Skybox skyboxVertexShader(float3 pos : POSITION) {
 +
    FS_Skybox output = (FS_Skybox) 0;
 +
    output.pos = mul(float4(pos, 0), world);            // Note the 0, this so the skybox rotates, but without translation
 +
    output.pos = mul(output.pos, viewProjection).xyww;  // The z coordinate is replaced by w, so that the point is always projected at infinity
 +
    output.tex = pos.xzy;                              // Note that y and z are switched to match the texture coordinate system
 +
    return output;
 +
}
 +
</syntaxhighlight>
 +
: skybox sampler state
 +
<syntaxhighlight lang="cpp">
 +
texture skyBox;
 +
samplerCUBE skySampler = sampler_state {
 +
    texture = <skyBox>;
 +
    MagFilter = LINEAR;
 +
    Minfilter = LINEAR;
 +
    Mipfilter = LINEAR;
 +
    AddressU = MIRROR;
 +
    AddressV = MIRROR;
 +
    AddressW = MIRROR;
 +
};
 +
</syntaxhighlight>
 +
: fragment shader
 +
<syntaxhighlight lang="cpp">
 +
float4 skyboxFragmentShader(FS_Skybox input) : COLOR0 {
 +
    return texCUBE(skySampler, input.tex);
 +
}
 +
</syntaxhighlight>
 +
: skybox technique
 +
<syntaxhighlight lang="cpp">
 +
technique skybox {
 +
 +
    pass {
 +
        AlphaBlendEnable = false;
 +
        ZENABLE = true;
 +
        ZWRITEENABLE = false;    // By not storing the skybox's z-buffer value, it enables objects behind the skybox to be drawn, giving a realist look (e.g. an airplane in the distance)
 +
        CullMode = None;
 +
        VertexShader = compile vs_3_0 skyboxVertexShader();
 +
        PixelShader  = compile ps_3_0 skyboxFragmentShader();
 +
    }
 +
}
 +
</syntaxhighlight>
 +
 
=== To Do ===
 
=== To Do ===
 
=== Resources ===
 
=== Resources ===
 +
* [http://rbwhitaker.wikidot.com/skyboxes-1 RB Whitaker's notes on skyboxes]
 +
* [http://knol.google.com/k/3d-skybox# Koen Samyn's knol]
 +
* [http://www.gameengineer.net/samples-graphics.html Game Engineer's demo]
 +
* [http://www.planetside.co.uk/terragen Terragen Texture Tool]
 +
* DirectX Utility - DirectX Texture Tool
  
  
== Week 8 - Mar 4 ==
+
== Week 9 - Mar 11 ==
 
=== This Week ===
 
=== This Week ===
 
* [http://msdn.microsoft.com/en-us/library/bb147178%28v=VS.85%29.aspx Mathematics of Lighting]
 
* [http://msdn.microsoft.com/en-us/library/bb147178%28v=VS.85%29.aspx Mathematics of Lighting]
Line 301: Line 2,236:
 
*** [http://msdn.microsoft.com/en-us/library/bb509617%28v=vs.85%29.aspx length()] - length of a vector
 
*** [http://msdn.microsoft.com/en-us/library/bb509617%28v=vs.85%29.aspx length()] - length of a vector
 
*** [http://msdn.microsoft.com/en-us/library/bb509645%28v=vs.85%29.aspx saturate()] - clamp scalar, vector, or matrix to [0, 1]
 
*** [http://msdn.microsoft.com/en-us/library/bb509645%28v=vs.85%29.aspx saturate()] - clamp scalar, vector, or matrix to [0, 1]
 +
* effects.fx - for unlit vertices and fragments
 +
: Uniform data
 +
<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;
 +
};
 +
 +
// 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
 +
float3  heading;          // camera heading for specular calcs
 +
int      noLights;        // no of static lights
 +
Light    light[MLIGHTS];  // static lights
 +
bool    lightOn[MLIGHTS]; // light switch
 +
 +
// Uniform Data (constant for a stream of fragments)
 +
//
 +
float4  ambient;          // global ambient light - always on
 +
Material material;        // material reflectivity
 +
 +
bool    texOn; // texture switch
 +
texture texMap;
 +
sampler2D tex = sampler_state {
 +
    texture = <texMap>;
 +
    Filter = MIN_MAG_MIP_LINEAR;
 +
    AddressU = MIRROR;
 +
    AddressV = MIRROR;
 +
};
 +
</syntaxhighlight>
 +
: Varying Data - simple unlit objects
 +
<syntaxhighlight lang="cpp">
 +
//-------------------------------- Simple Unlit Objects -----------------------
 +
//
 +
// UnlitInput holds the original data for a vertex in the stream
 +
//
 +
struct UnlitVSInput {
 +
 +
    float3 position : POSITION;  // position in local space
 +
    float3 normal  : NORMAL;    // normal in local space
 +
    float2 texCoord : TEXCOORD0;  // texture coordinates
 +
};
 +
 +
// UnlitOutput holds the transformed data for the vertex
 +
//
 +
struct UnlitVSOutput {
 +
 +
    float4 position : POSITION;  // position in homogeneous clip space
 +
    float2 texCoord : TEXCOORD;  // texture coordinates
 +
    float3 normal  : TEXCOORD1;  // lighting normal in world space
 +
    float3 toViewer : TEXCOORD2;  // direction to viewer in world space
 +
    float3 toLight[MLIGHTS] : TEXCOORD3; // light vector
 +
};
 +
 +
// UnlitFSInput holds the input data for a single fragment of the stream
 +
//
 +
struct UnlitFSInput {
 +
    float2 texCoord : TEXCOORD0;  // texture coordinate at this fragment
 +
    float3 normal  : TEXCOORD1;  // lighting normal in world space
 +
    float3 toViewer : TEXCOORD2;  // direction to viewer in world space
 +
    float3 toLight[MLIGHTS] : TEXCOORD3; // direction from fragment to light i
 +
};
 +
</syntaxhighlight>
 +
: Vertex Shader
 +
<syntaxhighlight lang="cpp">
 +
// unlitVShader transforms vertex and lighting data for simple unlit objects
 +
//
 +
UnlitVSOutput unlitVShader(UnlitVSInput input) {
 +
 +
    UnlitVSOutput output; // result returned by this function
 +
 +
    // Transform the vertex coordinates 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.
 +
    //
 +
    output.position = mul(float4(input.position, 1.0), world); // local to world
 +
    output.position = mul(output.position, viewProjection);    //... to clip
 +
 
 +
    // Determine the vector from this vertex to the viewer
 +
    output.toViewer = viewPoint.xyz - input.position;
 +
 +
    // Determine the vector from this vertex to light source i in local space
 +
    // (assumes that light position and direction are specified in local space)
 +
    for (int i = 0; i < noLights; i++)
 +
        if (light[i].type == DIRECTIONAL_LIGHT)
 +
            output.toLight[i] = - light[i].direction;
 +
        else
 +
            output.toLight[i] = light[i].position - input.position;
 +
 
 +
    // pass the normal and texture coordinates along unaltered
 +
    //
 +
    output.normal  = input.normal;
 +
    output.texCoord = input.texCoord;
 +
 +
    return output;
 +
}
 +
 +
</syntaxhighlight>
 +
: Fragment Shader
 +
<syntaxhighlight lang="cpp">
 +
// This fragment shader processes lighting for noLights lights in object space
 +
// and returns a pixel colour
 +
//
 +
float4 unlitFShader(UnlitFSInput input) : COLOR {
 +
 +
    float4 output;        // 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, factor;
 +
    float  attenuationFactor, spotFactor, rho;
 +
 
 +
    // normalize the fragment input
 +
    normal  = normalize(input.normal);
 +
    toViewer = normalize(input.toViewer);
 +
 
 +
    // perform calculations for each light in turn
 +
    for (int i = 0; i < noLights && i < MLIGHTS; i++) {
 +
        if (lightOn[i]) {
 +
            // diffuse and reflection factors
 +
            toLightSource = normalize(input.toLight[i]);
 +
            diffuseFactor = saturate(dot(normal, toLightSource));
 +
            reflectFactor = saturate(dot(normalize(2 * diffuseFactor *
 +
            normal - toLightSource), toViewer));
 +
 +
            // attenuation
 +
            if (light[i].type != DIRECTIONAL_LIGHT) {
 +
                distance = length(input.toLight[i]);
 +
                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;
 +
                }
 +
                else
 +
                    attenuationFactor = 0.0f;
 +
            }
 +
            else
 +
                attenuationFactor = 1.0f;
 +
 +
            // spot
 +
            if (light[i].type == SPOT_LIGHT) {
 +
                rho = saturate(dot(toLightSource,
 +
                    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
 +
                    spotFactor = 1.0f;
 +
            }
 +
            else
 +
                spotFactor = 1.0;
 +
 +
            factor = attenuationFactor * spotFactor;
 +
 +
            // accumulate ambient, diffuse, and specular elements of light i
 +
            ambientLight  += factor * light[i].ambient.xyz;
 +
            diffuseLight  += factor * diffuseFactor * light[i].diffuse.xyz;
 +
            specularLight += factor * 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
 +
    //
 +
    output.xyz =
 +
    saturate(material.ambient.xyz * ambientLight) +
 +
    saturate(material.diffuse.xyz * diffuseLight) +
 +
    saturate(material.specular.xyz * specularLight);
 +
    output.w = material.diffuse.w;
 +
 +
    // sample the texture
 +
    //
 +
    if (texOn)
 +
        output *= tex2D(tex, input.texCoord);
 +
 +
    return output;
 +
}
 +
</syntaxhighlight>
 +
: techniques - opaque and translucent
 +
<syntaxhighlight lang="cpp">
 +
technique opaque {
 +
 
 +
    pass {
 +
        AlphaBlendEnable = false;
 +
        VertexShader = compile vs_3_0 unlitVShader();
 +
        PixelShader  = compile ps_3_0 unlitFShader();
 +
    }
 +
}
 +
</syntaxhighlight>
 +
 +
<syntaxhighlight lang="cpp">
 +
technique translucent {
 +
     
 +
    pass {
 +
        AlphaBlendEnable = true;
 +
        VertexShader = compile vs_3_0 unlitVShader();
 +
        PixelShader  = compile ps_3_0 unlitFShader();
 +
    }
 +
}
 +
</syntaxhighlight>
 +
 +
 +
=== To Do ===
 +
=== Resources ===
 +
 +
 +
== Week 10 - Mar 18 ==
 +
=== This Week ===
 +
* Texturing - Identification
 +
: connection between Design.cpp and effects.fx
 +
** iTexture.h
 +
:: add texture and texture state identifier
 +
<syntaxhighlight lang="cpp">
 +
iTexture* CreateTexture(const wchar_t* file, const char* str,
 +
const char* isOn);
 +
</syntaxhighlight>
 +
** Texture.h
 +
:
 +
<syntaxhighlight lang="cpp">
 +
    Texture(const wchar_t*, const char*, const char*);
 +
</syntaxhighlight>
 +
** Texture.cpp
 +
:
 +
<syntaxhighlight lang="cpp">
 +
// constructor initializes the texture identifier
 +
//
 +
Texture::Texture(const wchar_t* file, const char* str,
 +
const char* isOn) : filter(0u) {
 +
 +
    if (file) {
 +
        int len = strlen(file);
 +
        this->file = new wchar_t[len + 1];
 +
        strcpy(this->file, file, len);
 +
    }
 +
    else
 +
        this->file = nullptr;
 +
 +
    tex    = nullptr;
 +
    #if  PIPELINE == FIXED_FUNCTION
 +
    #elif PIPELINE == PROGRAMMABLE
 +
    #elif PIPELINE == PROGRAMMABLE_EFFECT
 +
    textureHandle  = effect->GetParameterByName(0, str);
 +
    textureonHandle = effect->GetParameterByName(0, isOn);
 +
    #endif
 +
}
 +
</syntaxhighlight>
 +
:
 +
<syntaxhighlight lang="cpp">
 +
        effect->SetTexture(textureHandle, tex);
 +
        effect->SetBool(textureonHandle, true);
 +
</syntaxhighlight>
 +
** iAPITexture.h
 +
:: add texture and texture state identifier
 +
<syntaxhighlight lang="cpp">
 +
iAPITexture* CreateAPITexture(const wchar_t* file, const char* str,
 +
const char* isOn);
 +
</syntaxhighlight>
 +
** APITexture.h
 +
:
 +
<syntaxhighlight lang="cpp">
 +
    D3DXHANDLE textureHandle;  // points to texture
 +
    D3DXHANDLE textureonHandle; // points to texture on status
 +
public:
 +
    APITexture(const wchar_t*, const char*, const char*);
 +
</syntaxhighlight>
 +
** APITexture.cpp
 +
:
 +
<syntaxhighlight lang="cpp">
 +
// constructor initializes the texture identifier
 +
//
 +
APITexture::APITexture(const wchar_t* file, const char* str,
 +
const char* isOn, AddressMode m) : filter(0u), mode(m) {
 +
 +
    if (file) {
 +
        int len = strlen(file);
 +
        this->file = new wchar_t[len + 1];
 +
        strcpy(this->file, file, len);
 +
    }
 +
    else
 +
        this->file = nullptr;
 +
 +
    tex    = nullptr;
 +
    target = nullptr;
 +
    #if  PIPELINE == FIXED_FUNCTION
 +
    #elif PIPELINE == PROGRAMMABLE
 +
    #elif PIPELINE == PROGRAMMABLE_EFFECT
 +
    textureHandle  = effect->GetParameterByName(0, str);
 +
    textureonHandle = effect->GetParameterByName(0, isOn);
 +
    #endif
 +
}
 +
</syntaxhighlight>
 +
:
 +
<syntaxhighlight lang="cpp">
 +
        effect->SetTexture(textureHandle, tex);
 +
        effect->SetBool(textureonHandle, true);
 +
</syntaxhighlight>
 +
* Texturing - Tiling
 +
: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb206245%28v=vs.85%29.aspx Texture Coordinates]
 +
** iGraphic.h
 +
:: add u v parameters, both of which default to 1
 +
<syntaxhighlight lang="cpp">
 +
iGraphic* CreateBox(float, float, float, float, float, float,
 +
float = 1, float = 1);
 +
iGraphic* CreateIBox(float, float, float, float, float, float,
 +
float = 1, float = 1);
 +
iGraphic* CreateRectangleList(float, float, float, float,
 +
float = 1, float = 1);
 +
iGraphic* CreateIRectangleList(float, float, float, float,
 +
float = 1, float = 1);
 +
iGraphic* CreateMeshBox(float, float, float, float, float,
 +
float, float = 1, float = 1);
 +
</syntaxhighlight>
 +
** Graphic.cpp
 +
:: extend add functions to include u v parameters
 +
<syntaxhighlight lang="cpp">
 +
//-------------------------------- Graphic Structures -------------------------
 +
//
 +
// prototypes for add() function used by the Create...() functions
 +
void add(VertexList<Vertex>*, const Vector&, const Vector&, const Vector&,
 +
const Vector&, const Vector&, float = 1, float = 1);
 +
void add(IndexedList<Vertex>*, const Vector&, const Vector&, const Vector&,
 +
const Vector&, const Vector&, float = 1, float = 1);
 +
void add(CustomMesh<Vertex>*, const Vector&, const Vector&, const Vector&,
 +
const Vector&, const Vector&, float = 1, float = 1);
 +
 +
// CreateBox builds a triangle vertex list for a brick-like box from two
 +
// extreme points one face at a time with all faces having the same attributes
 +
//
 +
iGraphic* CreateBox(float minx, float miny, float minz, float maxx,
 +
float maxy, float maxz, float u, float v) {
 +
 
 +
    VertexList<Vertex>* vertexList =
 +
    (VertexList<Vertex>*)CreateVertexList<Vertex>(TRIANGLE_LIST, 12);
 +
 +
    float x = (minx + maxx) / 2;
 +
    float y = (miny + maxy) / 2;
 +
    float z = (minz + maxz) / 2;
 +
    minx -= x;
 +
    miny -= y;
 +
    minz -= z;
 +
    maxx -= x;
 +
    maxy -= y;
 +
    maxz -= z;
 +
    // bounding sphere
 +
    float max;
 +
    max = maxx > maxy ? maxx : maxy;
 +
    max = maxz > max  ? maxz : max;
 +
    vertexList->setRadius(1.73205f * max);
 +
    // locate centroid at origin
 +
    Vector p1 = Vector(minx, miny, minz),
 +
          p2 = Vector(minx, maxy, minz),
 +
          p3 = Vector(maxx, maxy, minz),
 +
          p4 = Vector(maxx, miny, minz),
 +
          p5 = Vector(minx, miny, maxz),
 +
          p6 = Vector(minx, maxy, maxz),
 +
          p7 = Vector(maxx, maxy, maxz),
 +
          p8 = Vector(maxx, miny, maxz);
 +
    add(vertexList, p1, p2, p3, p4, Vector(0, 0, -1), u, v); // front
 +
    add(vertexList, p4, p3, p7, p8, Vector(1, 0,  0), u, v); // right
 +
    add(vertexList, p8, p7, p6, p5, Vector(0, 0,  1), u, v); // back
 +
    add(vertexList, p6, p2, p1, p5, Vector(-1, 0, 0), u, v); // left
 +
    add(vertexList, p1, p4, p8, p5, Vector(0, -1, 0), u, v); // bottom
 +
    add(vertexList, p2, p6, p7, p3, Vector(0, 1,  0), u, v); // top
 +
 +
    return vertexList;
 +
}
 +
 +
iGraphic* CreateIBox(float minx, float miny, float minz, float maxx,
 +
float maxy, float maxz, float u, float v) {
 +
 
 +
    IndexedList<Vertex>* indexedList = (IndexedList<Vertex>*)
 +
    CreateIndexedList<Vertex, unsigned short>(TRIANGLE_LIST, 12);
 +
 +
    float x = (minx + maxx) / 2;
 +
    float y = (miny + maxy) / 2;
 +
    float z = (minz + maxz) / 2;
 +
    minx -= x;
 +
    miny -= y;
 +
    minz -= z;
 +
    maxx -= x;
 +
    maxy -= y;
 +
    maxz -= z;
 +
    // bounding sphere
 +
    float max;
 +
    max = maxx > maxy ? maxx : maxy;
 +
    max = maxz > max  ? maxz : max;
 +
    indexedList->setRadius(1.73205f * max);
 +
    // locate centroid at origin
 +
    Vector p1 = Vector(minx, miny, minz),
 +
          p2 = Vector(minx, maxy, minz),
 +
          p3 = Vector(maxx, maxy, minz),
 +
          p4 = Vector(maxx, miny, minz),
 +
          p5 = Vector(minx, miny, maxz),
 +
          p6 = Vector(minx, maxy, maxz),
 +
          p7 = Vector(maxx, maxy, maxz),
 +
          p8 = Vector(maxx, miny, maxz);
 +
    add(indexedList, p1, p2, p3, p4, Vector(0, 0, -1), u, v); // front
 +
    add(indexedList, p4, p3, p7, p8, Vector(1, 0,  0), u, v); // right
 +
    add(indexedList, p8, p7, p6, p5, Vector(0, 0,  1), u, v); // back
 +
    add(indexedList, p6, p2, p1, p5, Vector(-1, 0, 0), u, v); // left
 +
    add(indexedList, p1, p4, p8, p5, Vector(0, -1, 0), u, v); // bottom
 +
    add(indexedList, p2, p6, p7, p3, Vector(0, 1,  0), u, v); // top
 +
 +
    return indexedList;
 +
}
 +
 +
// CreateRectangleList builds a triangle list in the x-y plane from its two
 +
// extreme points
 +
//
 +
iGraphic* CreateRectangleList(float minx, float miny, float maxx, float maxy,
 +
float u, float v) {
 +
 
 +
    VertexList<Vertex>* vertexList =
 +
    (VertexList<Vertex>*)CreateVertexList<Vertex>(TRIANGLE_LIST, 2);
 +
 +
    float x = (minx + maxx) / 2, y = (miny + maxy) / 2;
 +
    minx -= x;
 +
    miny -= y;
 +
    maxx -= x;
 +
    maxy -= y;
 +
    // bounding sphere
 +
    float max;
 +
    max = maxx > maxy ? maxx : maxy;
 +
    vertexList->setRadius(1.73205f * max);
 +
    // locate centroid at origin
 +
    Vector p1 = Vector(minx, miny, 0),
 +
          p2 = Vector(minx, maxy, 0),
 +
          p3 = Vector(maxx, maxy, 0),
 +
          p4 = Vector(maxx, miny, 0);
 +
    add(vertexList, p1, p2, p3, p4, Vector(0, 0, -1), u, v);
 +
 
 +
    return vertexList;
 +
}
 +
 +
// CreateIRectangleList builds an indexed triangle list in the x-y plane from
 +
// its two extreme points
 +
//
 +
iGraphic* CreateIRectangleList(float minx, float miny, float maxx, float maxy,
 +
float u, float v) {
 +
 
 +
    IndexedList<Vertex>* indexedList = (IndexedList<Vertex>*)
 +
    CreateIndexedList<Vertex, unsigned short>(TRIANGLE_LIST, 2);
 +
 +
    float x = (minx + maxx) / 2, y = (miny + maxy) / 2;
 +
    minx -= x;
 +
    miny -= y;
 +
    maxx -= x;
 +
    maxy -= y;
 +
    // bounding sphere
 +
    float max;
 +
    max = maxx > maxy ? maxx : maxy;
 +
    indexedList->setRadius(1.73205f * max);
 +
    // locate centroid at origin
 +
    Vector p1 = Vector(minx, miny, 0),
 +
          p2 = Vector(minx, maxy, 0),
 +
          p3 = Vector(maxx, maxy, 0),
 +
          p4 = Vector(maxx, miny, 0);
 +
    add(indexedList, p1, p2, p3, p4, Vector(0, 0, -1), u, v);
 +
 
 +
    return indexedList;
 +
}
 +
 +
// CreateIRectangleList builds an indexed triangle list in the x-y plane from
 +
// its two extreme points
 +
//
 +
iGraphic* CreateBRectangleList(float minx, float miny, float maxx, float maxy,
 +
float u, float v) {
 +
 
 +
    IndexedList<BumpVertex>* indexedList = (IndexedList<BumpVertex>*)
 +
    CreateIndexedList<BumpVertex, unsigned short>(TRIANGLE_LIST, 2);
 +
 +
    float x = (minx + maxx) / 2, y = (miny + maxy) / 2;
 +
    minx -= x;
 +
    miny -= y;
 +
    maxx -= x;
 +
    maxy -= y;
 +
    // bounding sphere
 +
    float max;
 +
    max = maxx > maxy ? maxx : maxy;
 +
    indexedList->setRadius(1.73205f * max);
 +
    // locate centroid at origin
 +
    Vector p1 = Vector(minx, miny, 0),
 +
          p2 = Vector(minx, maxy, 0),
 +
          p3 = Vector(maxx, maxy, 0),
 +
          p4 = Vector(maxx, miny, 0);
 +
    add(indexedList, p1, p2, p3, p4, Vector(0, 0, -1), u, v);
 +
 
 +
    return indexedList;
 +
}
 +
 +
// CreateMeshBox builds a mesh for a brick-like box from two extreme points one
 +
// face at a time with each faces having distinct attributes
 +
//
 +
iGraphic* CreateMeshBox(float minx, float miny, float minz, float maxx,
 +
float maxy, float maxz, float u, float v) {
 +
 +
    unsigned attribute[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5};
 +
 +
    CustomMesh<>* mesh = (CustomMesh<>*)
 +
    CreateCustomMesh<Vertex, unsigned short>(attribute, 12, 36, 24, 6);
 +
 +
    float x = (minx + maxx) / 2, y = (miny + maxy) / 2, z = (minz + maxz) / 2;
 +
    minx -= x;
 +
    miny -= y;
 +
    minz -= z;
 +
    maxx -= x;
 +
    maxy -= y;
 +
    maxz -= z;
 +
    // bounding sphere
 +
    float max;
 +
    max = maxx > maxy ? maxx : maxy;
 +
    max = maxz > max  ? maxz : max;
 +
    mesh->setRadius(1.73205f * max);
 +
    // one face at a time
 +
    Vector p1 = Vector(minx, miny, minz),
 +
          p2 = Vector(minx, maxy, minz),
 +
          p3 = Vector(maxx, maxy, minz),
 +
          p4 = Vector(maxx, miny, minz),
 +
          p5 = Vector(minx, miny, maxz),
 +
          p6 = Vector(minx, maxy, maxz),
 +
          p7 = Vector(maxx, maxy, maxz),
 +
          p8 = Vector(maxx, miny, maxz);
 +
    add(mesh, p1, p2, p3, p4, Vector(0, 0, -1), u, v); // front
 +
    add(mesh, p4, p3, p7, p8, Vector(1, 0,  0), u, v); // right
 +
    add(mesh, p8, p7, p6, p5, Vector(0, 0,  1), u, v); // back
 +
    add(mesh, p6, p2, p1, p5, Vector(-1, 0, 0), u, v); // left
 +
    add(mesh, p1, p4, p8, p5, Vector(0, -1, 0), u, v); // bottom
 +
    add(mesh, p2, p6, p7, p3, Vector(0, 1,  0), u, v); // top
 +
 +
    return mesh;
 +
}
 +
 +
void add(VertexList<Vertex>* vertexList, const Vector& p1, const Vector& p2,
 +
const Vector& p3, const Vector& p4, const Vector& n, float u, float v) {
 +
 +
    vertexList->add(Vertex(p1, n, 0, v));
 +
    vertexList->add(Vertex(p2, n, 0, 0));
 +
    vertexList->add(Vertex(p3, n, u, 0));
 +
    vertexList->add(Vertex(p1, n, 0, v));
 +
    vertexList->add(Vertex(p3, n, u, 0));
 +
    vertexList->add(Vertex(p4, n, u, v));
 +
}
 +
 +
void add(IndexedList<Vertex>* indexedList, const Vector& p1, const Vector& p2,
 +
const Vector& p3, const Vector& p4, const Vector& n, float u, float v) {
 +
 +
    unsigned v1 = indexedList->add(Vertex(p1, n, 0, v));
 +
    unsigned v2 = indexedList->add(Vertex(p2, n, 0, 0));
 +
    unsigned v3 = indexedList->add(Vertex(p3, n, u, 0));
 +
    unsigned v4 = indexedList->add(Vertex(p4, n, u, v));
 +
    indexedList->add(v1);
 +
    indexedList->add(v2);
 +
    indexedList->add(v3);
 +
    indexedList->add(v1);
 +
    indexedList->add(v3);
 +
    indexedList->add(v4);
 +
}
 +
 +
void add(CustomMesh<Vertex>* mesh, const Vector& p1, const Vector& p2,
 +
const Vector& p3, const Vector& p4, const Vector& n, float u, float v) {
 +
 +
    unsigned v1 = mesh->add(Vertex(p1, n, 0, v));
 +
    unsigned v2 = mesh->add(Vertex(p2, n, 0, 0));
 +
    unsigned v3 = mesh->add(Vertex(p3, n, u, 0));
 +
    unsigned v4 = mesh->add(Vertex(p4, n, u, v));
 +
    mesh->add(v1);
 +
    mesh->add(v2);
 +
    mesh->add(v3);
 +
    mesh->add(v1);
 +
    mesh->add(v3);
 +
    mesh->add(v4);
 +
}
 +
 +
</syntaxhighlight>
 +
* Texturing - Address Modes
 +
: [http://msdn.microsoft.com/en-us/library/windows/desktop/bb206239%28v=vs.85%29.aspx Direct3D9 Addressing Modes]
 +
** APITexture.h
 +
:
 +
<syntaxhighlight lang="cpp">
 +
    D3DXHANDLE textureMode;    // points to texture mode
 +
</syntaxhighlight>
 +
** APITexture.cpp
 +
:
 +
<syntaxhighlight lang="cpp">
 +
        effect->SetInt(textureMode, (int)mode);
 +
</syntaxhighlight>
 +
** effects.fx - uniform variables
 +
::
 +
<syntaxhighlight lang="cpp">
 +
// Addressing Modes
 +
#define TEX_WRAP          0
 +
#define TEX_CLAMP        1
 +
#define TEX_MIRROR        2
 +
 +
//...
 +
 +
bool    tex_1_On;      // texture switch
 +
int      tex_mode;      // addressing mode
 +
texture  tex_1;
 +
 +
sampler2D tex_1_ww = sampler_state {
 +
    texture = <tex_1>;
 +
    Filter = MIN_MAG_MIP_LINEAR;
 +
    AddressU = WRAP;
 +
    AddressV = WRAP;
 +
};
 +
 +
sampler2D tex_1_mm = sampler_state {
 +
    texture = <tex_1>;
 +
    Filter = MIN_MAG_MIP_LINEAR;
 +
    AddressU = MIRROR;
 +
    AddressV = MIRROR;
 +
};
 +
 +
sampler2D tex_1_cc = sampler_state {
 +
    texture = <tex_1>;
 +
    Filter = MIN_MAG_MIP_LINEAR;
 +
    AddressU = CLAMP;
 +
    AddressV = CLAMP;
 +
};
 +
 +
</syntaxhighlight>
 +
** effects.fx - fragment shader
 +
:
 +
<syntaxhighlight lang="cpp">
 +
    // sample the texture
 +
    //
 +
    if (tex_1_On) {
 +
        if (tex_mode == TEX_CLAMP)
 +
            output *= tex2D(tex_1_cc, input.texCoord);
 +
        else if (tex_mode == TEX_WRAP)
 +
            output *= tex2D(tex_1_ww, input.texCoord);
 +
        else if (tex_mode == TEX_MIRROR)
 +
            output *= tex2D(tex_1_mm, input.texCoord);
 +
    }
 +
</syntaxhighlight>
 +
* Texturing - Multi-Texturing
 +
** effects.fx - uniform variables
 +
:
 +
<syntaxhighlight lang="cpp">
 +
bool    tex_2_On;      // texture switch
 +
texture  tex_2;
 +
 +
sampler2D tex_2_ww = sampler_state {
 +
    texture = <tex_2>;
 +
    Filter = MIN_MAG_MIP_LINEAR;
 +
    AddressU = WRAP;
 +
    AddressV = WRAP;
 +
};
 +
 +
sampler2D tex_2_mm = sampler_state {
 +
    texture = <tex_2>;
 +
    Filter = MIN_MAG_MIP_LINEAR;
 +
    AddressU = MIRROR;
 +
    AddressV = MIRROR;
 +
};
 +
 +
sampler2D tex_2_cc = sampler_state {
 +
    texture = <tex_2>;
 +
    Filter = MIN_MAG_MIP_LINEAR;
 +
    AddressU = CLAMP;
 +
    AddressV = CLAMP;
 +
};
 +
 +
</syntaxhighlight>
 +
** effects.fx - fragment shader
 +
:
 +
<syntaxhighlight lang="cpp">
 +
    if (tex_2_On) {
 +
        if (tex_mode == TEX_CLAMP)
 +
            output *= tex2D(tex_2_cc, input.texCoord);
 +
        else if (tex_mode == TEX_WRAP)
 +
            output *= tex2D(tex_2_ww, input.texCoord);
 +
        else if (tex_mode == TEX_MIRROR)
 +
            output *= tex2D(tex_2_mm, input.texCoord);
 +
    }
 +
</syntaxhighlight>
 +
 +
=== To Do ===
 +
=== Resources ===
 +
 +
 +
<!--
 +
== Week 11 - Mar 25 ==
 +
=== This Week ===
 +
 +
<syntaxhighlight lang="cpp">
 +
</syntaxhighlight>
 +
 +
=== To Do ===
 +
=== Resources ===
 +
-->
 +
<!--
 +
== Week 12 - Apr 1 ==
 +
=== This Week ===
 +
 +
<syntaxhighlight lang="cpp">
 +
</syntaxhighlight>
 +
 
=== To Do ===
 
=== To Do ===
 
=== Resources ===
 
=== Resources ===
 
-->
 
-->

Latest revision as of 08:00, 21 March 2012


GAM670/DPS905 | Weekly Schedule | Student List | Project Requirements | Teams and their Projects | Student Resources


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

To Do

  1. add your name to the student list
  2. 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()
  • Geometry
    • Plane
      normal + constant - examples
      equation of a plane: dot(n, x) + D = 0
      positive side of a plane dot(n, x) + D > 0
  • Collision Detection
    types of colliders
    spheres
    planes
    axis-aligned bounding boxes
    oriented bounding boxes

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);
  • Comprehensive Camerawork
    rotation about an axis
    order of rotation matters
    Euler angles
    3-2-1 angles
    gimbal lock
    StephenSeefeld.net
    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)
    Dorst's site
    Hitzer's site
  • 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


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
    Custom Mesh
    Create a Mesh
    APIGraphic.h code
template <class T = Vertex, class I = Index>
class APICustomMesh : public iAPIGraphic, public APIBase {

    unsigned   nSubsets;    // number of subsets
    unsigned   nPrimitives; // number of primitives
    unsigned*  attribute;   // points to mesh's attribute list
    I*         index;       // points to mesh's array of indices
    unsigned   iIndex;      // number of indices currently saved
    unsigned   nIndices;    // number of indices in the mesh
    T*         vertex;      // points to mesh's array of vertices
    unsigned   iVertex;     // number of vertices currently saved
    unsigned   nVertices;   // number of vertices in the mesh
    LPD3DXMESH apiMesh;     // set of vertices, indices

  protected:
    virtual ~APICustomMesh();
    void setup();

  public:
    APICustomMesh(unsigned*, int, int, int, int);
    APICustomMesh(const APICustomMesh& v);           
    APICustomMesh& operator=(const APICustomMesh& v);
    APICustomMesh* clone() const { return new APICustomMesh(*this); }
    unsigned add(const T& v);
    void     add(unsigned);
    void     draw(unsigned);
    void     suspend();
    void     release()           { suspend(); }
    void     Delete() const      { delete this; }
};
  • APIGraphic.cpp - APIGraphic
template <class T, class I>
APICustomMesh<T, I>::APICustomMesh(unsigned* a, int np, int ni, int nv, int ns)
 : nSubsets(ns), nPrimitives(np), nIndices(ni), nVertices(nv), iIndex(0),
 iVertex(0) {

    attribute = new unsigned[nPrimitives];
    for (unsigned i = 0; i < nPrimitives; i++)
        attribute[i] = a[i];

    index   = new I[nIndices];
    vertex  = new T[nVertices];

    apiMesh = nullptr;
}
  • APIGraphic.cpp - add()
template <class T, class I>
unsigned APICustomMesh<T, I>::add(const T& v) {

    unsigned i = iVertex;

    if (vertex && iVertex < nVertices)
        vertex[iVertex++] = v;

    return i;
}
template <class T, class I>
void APICustomMesh<T, I>::add(unsigned v) {

    if (index && iIndex < nIndices)
        index[iIndex++] = v;
}
  • APIGraphic.cpp - setup()
template <class T, class I>
void APICustomMesh<T, I>::setup() {

    T *pv;
    I *pi;
    DWORD *pa;
    nIndices  = iIndex;
    nVertices = iVertex;

    // create an empty mesh and lock its buffers
    if (FAILED(D3DXCreateMesh(nPrimitives, nVertices, 0,
     APIVertexDeclaration<T>::format(), d3dd, &apiMesh))) {
        error(L"APIMesh::14 Couldn\'t create the empty mesh");
        apiMesh = nullptr;
    }
    else if (FAILED(apiMesh->LockVertexBuffer(0, (void**)&pv))) {
        error(L"APIMesh::15 Couldn\'t lock vertex buffer");
        release();
    }
    else if (FAILED(apiMesh->LockIndexBuffer(0, (void**)&pi))) {
        error(L"APIMesh::16 Couldn\'t lock index buffer");
        release();
    }
    else if (FAILED(apiMesh->LockAttributeBuffer(0, &pa))) {
        error(L"APIMesh::17 Couldn\'t lock attribute buffer");
        release();
    }
    else {
        // populate the newly created Vertex Buffer
        for (unsigned i = 0; i < nVertices; i++)
            vertex[i].populate((void**)&pv);
        apiMesh->UnlockVertexBuffer();
        // populate the newly created Index Buffer
        for (unsigned i = 0; i < nIndices; i++)
            pi[i] = index[i];
        apiMesh->UnlockIndexBuffer();
        // Populate the newly created Attribute Buffer
        for (unsigned i = 0; i < nPrimitives; i++)
            pa[i] = attribute[i];
        apiMesh->UnlockAttributeBuffer();
    }
}
  • APIGraphic.cpp - DrawSubset()
template <class T, class I>
void APICustomMesh<T, I>::draw(unsigned iSubset) {

    // if mesh doesn't exist, set it up first
    if (!apiMesh) setup();

    if (apiMesh)
        apiMesh->DrawSubset(iSubset);
}
  • DrawIndexedPrimitive parameters
    APIGraphic.cpp - suspend()
template <class T, class I>
void APICustomMesh<T, I>::suspend() {

    // release the interface to the mesh
    if (apiMesh) {
        apiMesh->Release();
        apiMesh = nullptr;
    }
}
  • APIGraphic.cpp - ~APIGraphic
template <class T, class I>
APICustomMesh<T, I>::~APICustomMesh() {

    release();
    if (attribute)
        delete [] attribute;
    if (index)
        delete [] index;
    if (vertex)
        delete [] vertex;
}
  • X File
    Create Mesh from File
  • SkyBox
    definition of a skybox
    attachment to camera
    inverted coordinates
    skybox textures
    Graphic.cpp code
    more complicated forms - skydome
  • Billboards
    definition, purpose of a billboard
void Billboard::render(unsigned) {

    Vector h, u, r, p = position();
    Camera* camera = *(Camera**)(Camera::getCurrent());
    Vector cameraPosition = camera->position();
    Vector cameraHeading  = ::normal(camera->orientation('z'));
    Vector cameraUp       = ::normal(camera->orientation('y'));
    switch (type) {
    // ... see below
    }
    Matrix rot(r.x, r.y, r.z, 0,
               u.x, u.y, u.z, 0,
               h.x, h.y, h.z, 0,
                 0,   0,   0, 1);
    orient(rot);

    Object::render(0);
}
  • types of billboards
    screen-aligned - useful for annotation text, lens flares
    normal is opposite to camera heading
    up is camera->up
        case SCREEN:
            h = cameraHeading; // fixed
            u = cameraUp;      // up is fixed   
            r = cross(u, h);
            break;
  • axial - useful for cylindrical symmetry - trees (textured object does not face straight on)
    up is fixed
    normal faces the viewer as much as possible
        case AXIAL:
            h = ::normal(position() - cameraPosition); // heading is open to change
            u = Vector(0, 1, 0); // up axis is fixed
            r = cross(u, h);
            h = cross(u, r);
            break;
  • view_plane - no distortion - useful for
    normal is fixed (opposite to camera heading)
    up is open to change
        case VIEW_PLANE:
            h = cameraHeading;   // heading is fixed
            u = Vector(0, 1, 0); // up is open to change
            r = cross(u, h);
            u = cross(h, r);
            break;
  • 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
        case VIEWPOINT:
            h = ::normal(position() - cameraPosition); // heading is fixed
            u = Vector(0, 1, 0); // up is open to change
            r = cross(u, h);
            u = cross(h, r);
            break;
  • Object.h and Object.cpp code
  • Texture Filtering
    mip maps
    multum in parvo
    texture creation
    APITexture::SetSamplerState()
    // mipmap filtering
    if (flags & TEX_MIPMAP)
        d3dd->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
    else
        d3dd->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
  • DirectX Errors
    DirectX Utilities - Lookup Tool
    APIDisplay::restore() example
bool APIDisplay::restore() {

    bool rc = false;

    if (d3dd) {
        HRESULT hr;
        hr = d3dd->TestCooperativeLevel();
        if (hr == D3DERR_DEVICENOTRESET)
            // reset the APIDisplay device
            rc = d3dd->Reset(&d3dpp) == D3D_OK;
        else if (hr == S_OK)
            rc = true;
    }
    if (rc) {
        // reacquire sprite manager references to video memory
        if (manager)
            manager->OnResetDevice();
    }

    // complete the restoration
    if (rc) {
        setupLighting();
        setupBlending();
    }

    return rc;
}

To Do

Resources

Week 5 - Feb 6

This Week

template <class T = Vertex>
class APIVertexDeclaration {

    static D3DVERTEXELEMENT9 fmt[MAXD3DDECLLENGTH + 1];
    static unsigned vertexSize;

public:
    static D3DVERTEXELEMENT9* format() { return fmt; }
    static unsigned size()             { return vertexSize; }
};
template <>
D3DVERTEXELEMENT9 APIVertexDeclaration<Vertex>::fmt[MAXD3DDECLLENGTH + 1]
 = {
 { 0,  0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
 D3DDECLUSAGE_POSITION, 0},
 { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
 D3DDECLUSAGE_NORMAL, 0},
 { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
 D3DDECLUSAGE_TEXCOORD, 0},      
 D3DDECL_END()};

template<>
unsigned APIVertexDeclaration<Vertex>::vertexSize = 32;
template <>
D3DVERTEXELEMENT9 APIVertexDeclaration<LitVertex>::fmt[MAXD3DDECLLENGTH + 1]
 = {
 { 0,  0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
 D3DDECLUSAGE_POSITION, 0},
 { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
 D3DDECLUSAGE_COLOR, 0},
 D3DDECL_END()};

template <>
unsigned APIVertexDeclaration<LitVertex>::vertexSize = 16;
D3DVERTEXELEMENT9 struct

To Do

Week 6 - Feb 13

This Week

Vertex Shader Programming

  • Host
APIPlatformSettings.h - Vertex Shader Identification - select between fixed function and programmable pipelines here
// shader file data
#define VERTEX_SHADER_FILE        L"vertexShader.hlsl"
#define VERTEX_SHADER_ENTRY_POINT "vertexShader"
APIBase.h - pointers into the shader - APIBase is the base class for the graphics API classes
    static IDirect3DVertexShader9* vertexShader; // vertex shader
    static ID3DXConstantTable*     uniformVS;    // for vertex shader
APIBase.cpp - initialize the shader pointers
IDirect3DVertexShader9* APIBase::vertexShader   = nullptr; // vertex shader
ID3DXConstantTable*     APIBase::uniformVS      = nullptr; // for vertex shader
APIDisplay.h - keeps track of the current projection matrix
    Matrix   projection;       // projection transformation
APIDisplay.cpp - setup() - checks the shader version
    // points to compiled shader code
    LPD3DXBUFFER compiledCodeVS = nullptr;

    // check for minimum vertex shader version required
    if (caps.VertexShaderVersion < D3DVS_VERSION(2,0))
        error(L"APIDisplay::09 Device does not support vertex shader 2_0");

compiles the shader hlsl code, retrieves address of constant memory and vertex shader

    // 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();

sets the current vertex shader

        d3dd->SetVertexShader(vertexShader);
APIDisplay.cpp - setProjection() - stores the projection matrix
    this->projection = *((Matrix*)projection);
APIDisplay.cpp - beginDrawFrame() - copies the view matrix and the camera heading to constant memory
    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() - copies the lighting state to constant memory
                uniformVS->SetBool(d3dd, "lighting", b);
APIDisplay.cpp - setWorld() - copies the world matrix to constant memory
        uniformVS->SetMatrix(d3dd, "world", (D3DXMATRIX*)world);
APIDisplay.cpp - setReflectivity() - copies the reflectivity to constant memory
        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() - releases constant memory and the vertex shader
    // release the shader COM objects
    if (uniformVS) {
        uniformVS->Release();
        uniformVS = nullptr;
    }
    if (vertexShader) {
        vertexShader->Release();
        vertexShader = nullptr;
    }
APILight.cpp - setup() - copies the light properties to constant memory
        // 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() - repositions the light and turns it on
        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() - repositions the light
        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() - turns off the light
        char constantLightOn[] = "lightOn[0]";
        constantLightOn[8] = index + '0';
        uniformVS->SetBool(d3dd, constantLightOn, false);
APIGraphic.h - class APIXMesh - processes an X file mesh
    D3DXCOLOR*          ambient;
    D3DXCOLOR*          diffuse;
    D3DXCOLOR*          specular;
    FLOAT*              power;
APIGraphic.cpp - APIXMesh() - constructor
    ambient  = nullptr;
    diffuse  = nullptr;
    specular = nullptr;
    power    = nullptr;
APIGraphic.cpp - APIXMesh() - copy constructor
    ambient  = nullptr;
    diffuse  = nullptr;
    specular = nullptr;
    power    = nullptr;
APIGraphic.cpp - operator=() = assignment 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();
D3DXCompileShaderFromFile()
D3DXGetPixelShaderProfile()
IDirect3DDevice9::CreatePixelShader()
        d3dd->SetPixelShader(fragmentShader);
IDirect3DDevice9::SetPixelShader()
APIDisplay.cpp - beginDrawFrame()
        Colour colour(red, green, blue);
        uniformFS->SetFloatArray(d3dd, "ambient", (FLOAT*)&colour, 4);
        uniformFS->SetInt(d3dd, "noLights", 4);
ID3DXConstantTable::SetFloatArray()
ID3DXConstantTable::SetInt()
APIDisplay.cpp - set()
                uniformFS->SetBool(d3dd, "lighting", b);
ID3DXConstantTable::SetBool()
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]);
ID3DXConstantTable::SetFloat()
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
vertexShader.hlsl - Constant Memory
// 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
float3   viewPoint;        // camera viewpoint for specular calcs
// Lit Vertex
bool     litVertex;        // omit lighting calculations - already lit
vertexShader.hlsl - vertexShader()
// 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;
}
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 APIDisplay
    • 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()

Resources

Week 7 - Feb 20

This Week

  • Effects Framework
    • techniques
    passes
  • Source Code
APIBase.h
    static ID3DXEffect*           effect;         // points to effects framework
APIBase.cpp
ID3DXEffect*            APIBase::effect         = nullptr; // effects framework
APIDisplay.h
    // Effects Framework handles
    D3DXHANDLE   viewProjection;   // view * projection
    D3DXHANDLE   viewPoint;        // camera viewpoint
    D3DXHANDLE   ambient;          // global ambient color
    D3DXHANDLE   ambientHandle;    // current ambient reflectivity
    D3DXHANDLE   diffuseHandle;    // current diffuse reflectivity
    D3DXHANDLE   specularHandle;   // current specular reflectivity
    D3DXHANDLE   powerHandle;      // current shininess coefficient
    D3DXHANDLE   worldHandle;      // current world transformation
    void beginEffect(const char*, unsigned&);
    void beginPass(unsigned);
    void endPass();
    void endEffect();
APIDisplay.cpp - APIDisplay()
    viewProjection = nullptr;
    viewPoint      = nullptr;
    ambient        = nullptr;
    ambientHandle  = nullptr;
    diffuseHandle  = nullptr;
    specularHandle = nullptr;
    powerHandle    = nullptr;
    worldHandle    = nullptr;
APIDisplay.cpp - setup()
    LPD3DXBUFFER errorBuffer = NULL;
    // create the effects framework
    else if (FAILED(D3DXCreateEffectFromFile(d3dd, EFFECT_FILE, 0,
     0, D3DXSHADER_DEBUG, 0, &effect, &errorBuffer))) {
        release();
        error(L"APIDisplay::17 Unable to create the effects framework");
    }
D3DXCreateEffectFromFile()
        if (errorBuffer) errorBuffer->Release();
        viewProjection = effect->GetParameterByName(0, "viewProjection");
        viewPoint      = effect->GetParameterByName(0, "viewPoint");
        ambient        = effect->GetParameterByName(0, "ambient");
        worldHandle    = effect->GetParameterByName(0, "world");
        ambientHandle  = effect->GetParameterByName(0, "material.ambient");
        diffuseHandle  = effect->GetParameterByName(0, "material.diffuse");
        specularHandle = effect->GetParameterByName(0, "material.specular");
        powerHandle    = effect->GetParameterByName(0, "material.power");
GetParameterByName()
APIDisplay.cpp - beginDrawFrame()
    Matrix& v = *((Matrix*)view);
    Matrix viewprojection = v * projection;
    Vector heading(v.m13, v.m23, v.m33);
    effect->SetMatrix(viewProjection, (D3DXMATRIX*)&viewprojection);
    effect->SetVector(viewPoint,      (D3DXVECTOR4*)&heading);
SetMatrix()
SetVector()
        Colour colour(red, green, blue);
        effect->SetVector(ambient, (D3DXVECTOR4*)&colour);
APIDisplay.cpp - beginEffect()
void APIDisplay::beginEffect(const char* technique, unsigned& nPasses) {

    D3DXHANDLE techniqueHandle = effect->GetTechniqueByName(technique);
    effect->SetTechnique(techniqueHandle);
    effect->Begin(&nPasses, 0);
}
GetTechniqueByName()
SetTechnique()
Begin()
APIDisplay.cpp - beginPass()
void APIDisplay::beginPass(unsigned i) {

    effect->BeginPass(i);
}
BeginPass()
APIDisplay.cpp - endPass()
void APIDisplay::endPass() {

    effect->EndPass();
}
EndPass()
APIDisplay.cpp - endEffect()
void APIDisplay::endEffect() {

    effect->End();
}
End()
APIDisplay.cpp - setWorld()
        effect->SetMatrix(worldHandle, (D3DXMATRIX*)world);
APIDisplay.cpp - setReflectivity()
        effect->SetVector(ambientHandle,  (D3DXVECTOR4*)&r.ambient);
        effect->SetVector(diffuseHandle,  (D3DXVECTOR4*)&r.diffuse);
        effect->SetVector(specularHandle, (D3DXVECTOR4*)&r.specular);
        effect->SetFloat(powerHandle,     r.power);
        effect->CommitChanges();
CommitChanges()
APIDisplay.cpp - release()
    if (effect) {
        effect->Release();
        effect = NULL;
    }
effects.fx - 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 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
effects.fx - VertexShader
// 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;
}
effects.fx - 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;
}
effects.fx - technique opaque
technique opaque {
   
    pass {
        VertexShader = compile vs_3_0 vertexShader();
        PixelShader  = compile ps_3_0 fragmentShader();
    }
}
effects.fx - technique translucent
technique translucent {
       
    pass {
        VertexShader = compile vs_3_0 vertexShader();
        PixelShader  = compile ps_3_0 fragmentShader();
    }
}

To Do

Resources

Week 8 - Mar 4

This Week

  • Frank Luna's notes for DirectX10 (page 306)
Environment Maps(Google books)
Environment Maps(Seneca ELibraray)
  • Design.cpp
Design::initialize() - create the skybox object
// initialize initializes the general display design coordinator, creates the
// primitive sets, textures, objects, lights, sounds, cameras, and text items
//
void Design::initialize() {

    // ...

    // create textures
    iTexture* sunset   = CreateCubeTexture(L"Islands.dds");

    // ...

    iObject* skybox = CreateSkybox();
    skybox->rotatex(-1.5708f);
    skybox->attach(sunset);
    setSkybox(skybox);

    // ...
}
  • Coordinator.cpp
Coordinator::render() - using different techniques for different objects
void Coordinator::render() {

    // adjust framecount and fps
    if (now - lastReset <= unitsPerSec)
        framecount++;
    else {
        // recalculate the frame rate
        fps        = framecount * unitsPerSec / (now - lastReset);
        framecount = 0;
        lastReset  = now;
        if (timerText) {
            wchar_t str[MAX_DESC + 1];
            sprintf(str, fps, L" fps");
            timerText->set(str);
        }
    }
    // update the user input devices
    userInput->update();
    Coordinator::update();
    // update the model
    update();
    // update the audio
    audio->setVolume(volume);
    audio->setFrequencyRatio(frequency);
    audio->update(Camera::getView());

    // start rendering
    display->beginDrawFrame(Camera::getView());
    display->setAmbientLight(ambient.r, ambient.g, ambient.b);
    unsigned nPasses;
    // render all of the opaque unlit objects
    display->beginEffect("opaque", nPasses);
    for (unsigned i = 0; i < nPasses; i++) {
        display->beginPass(i);
        render(OPAQUE_OBJECT);
        display->endPass();
    }
    display->endEffect();
    // render all of the translucent unlit objects
    display->beginEffect("translucent", nPasses);
    for (unsigned i = 0; i < nPasses; i++) {
        display->beginPass(i);
        render(TRANSLUCENT_OBJECT);
        display->endPass();
    }
    display->endEffect();
    // render all of the lit objects
    display->beginEffect("litObjects", nPasses);
    for (unsigned i = 0; i < nPasses; i++) {
        display->beginPass(i);
        render(LIT_OBJECT);
        display->endPass();
    }
    display->endEffect();
    //  render the skybox
    display->beginEffect("skybox", nPasses);
    if (background && !skybox) {
        Rectf fullScreen(0, 0, 1, 1);
        display->beginDrawHUD(0);
        background->render(fullScreen, true);
        display->endDrawHUD();
    }
    else if (skybox) {
        for (unsigned i = 0; i < nPasses; i++) {
            display->beginPass(i);
            render(SKYBOX);
            display->endPass();
        }
    }
    display->endEffect();
    display->set(ALPHA_BLEND, false);
    display->beginDrawHUD(HUD_ALPHA);
    render(ALL_HUDS);
    display->endDrawHUD();
    display->endDrawFrame();
    render(ALL_SOUNDS);
}
Coordinator::render(iObject*) - render a single object one subset at a time
void Coordinator::render(iObject* object) {

    display->setWorld(&object->world());
    unsigned nSubsets = object->noSubsets();
    for (unsigned i = 0; i < nSubsets; i++) {
        iTexture* texture = object->getTexture(i);
        if (texture) texture->attach();
        display->setReflectivity(object->getReflectivity(i));
        object->render(i);
        if (texture) texture->detach();
    }
}
  • Skybox class
iObject interface - CreateSkybox declaration
class iObject : public Shape, public Base {
  public:
    // initialization
    virtual void        attach(iTexture* t)                  = 0;
    virtual void        attach(iTexture** t)                 = 0;
    // execution
    virtual unsigned    noSubsets() const                    = 0;
    virtual void        render(unsigned)                     = 0;
    virtual void        setTextureFilter(unsigned)           = 0;
    virtual iTexture*   getTexture(unsigned) const           = 0;
    virtual const void* getReflectivity(unsigned) const      = 0;
    virtual bool        belongsTo(Category category) const   = 0;
};

iObject* CreateObject(iGraphic*, const Reflectivity* = nullptr, unsigned = 1u);
iObject* CreateBillboard(BillboardType, iGraphic*,
 const Reflectivity* = nullptr);
iObject* CreateSkybox();

iObject* Clone(const iObject*);
Skybox class - derived from Object
//-------------------------------- Skybox -------------------------------------
//
// A Skybox is an inverted Object that translates with the viewpoint
//
class Skybox : public Object {

public:
    Skybox();
    void render(unsigned);
};
CreateSkybox
iObject* CreateSkybox() {

    return new Skybox();
}
Skybox::Skybox - SKYBOX category, 2 x 2 x 2 cube
Skybox::Skybox() : Object(SKYBOX, CreateIBox(-1, -1, -1 * MODEL_Z_AXIS, 1, 1,
 1 * MODEL_Z_AXIS)) {
}
Skybox::render(unsigned) - move skybox centroid to current camera position
void Skybox::render(unsigned) {

    Camera* camera = *(Camera**)(Camera::getCurrent());
    Vector disp = camera->position() - position();
    translate(disp.x, disp.y, disp.z);

    Object::render(0);
}
  • Texture class
iTexture interface - CreateCubeTexture declaration
class iTexture : public Base {
  public:
    virtual void attach() const                                        = 0;
    virtual void setFilter(unsigned) const                             = 0;
    virtual void detach()                                              = 0;
    virtual void render(const Rectf&, bool = false)                    = 0;
};

iTexture* CreateTexture(const wchar_t* file, unsigned filter = 0);
iTexture* CreateCubeTexture(const wchar_t* file, unsigned filter = 0);

iTexture* Clone(const iTexture*);
Texture class - add the cube parameter to constructor
class Texture : public iTexture {

    iAPITexture* apiTexture;   // points to the api texture

    Texture(const Texture&);
    virtual ~Texture();

  public:
    Texture(const wchar_t* file, unsigned filter = 0, bool cube = false);
    Texture& operator=(const Texture&);
    void* clone() const { return new Texture(*this); }
    // execution
    void attach() const;
    void setFilter(unsigned) const;
    void detach();
    void render(const Rectf&, bool);
    // termination
    void suspend();
    void release();
};
CreateCubeTexture - call constructor with true flag for cube
iTexture* CreateCubeTexture(const wchar_t* file, unsigned filter) {

    return new Texture(file, filter, true);
}
Texture::Texture() - create APICubeTexture()
Texture::Texture(const wchar_t* file, unsigned filter, bool cube) {

    coordinator->add(this);

    wchar_t* fileWithPath = nullptr;
    if (file) {
        // add the directory to create the relative filename
        int len = strlen(file) + strlen(TEXTURE_DIRECTORY) + 1;
        fileWithPath = new wchar_t[len + 1];
        ::nameWithDir(fileWithPath, TEXTURE_DIRECTORY, file, len);
    }

    // apiTexture on the graphics device
    if (cube)
        apiTexture = CreateAPICubeTexture(fileWithPath);
    else
        apiTexture = CreateAPITexture(fileWithPath, filter);

    if (fileWithPath) delete [] fileWithPath;
}
iAPITexture interface - add CreateAPICubeTexture declaration
class iAPITexture {
  public:
    virtual iAPITexture* clone() const                                = 0;
    // execution
    virtual void attach()                                             = 0;
    virtual void setFilter(unsigned flags)                            = 0;
    virtual void detach()                                             = 0;
    virtual void render(const Rectf&, unsigned char, bool = false)    = 0;
    // termination
    virtual void suspend()                                            = 0;
    virtual void release()                                            = 0;
    virtual void Delete() const                                       = 0;
};

iAPITexture* CreateAPITexture(const wchar_t* file, unsigned filter);
iAPITexture* CreateAPICubeTexture(const wchar_t* file);
  • APITexture.h
APICubeTexture class definition
class APICubeTexture : public iAPITexture, public APIBase {

    wchar_t*               file;   // points to file with texture image
    unsigned               filter; // default texture filtering flags

    IDirect3DCubeTexture9* tex;    // interface to texture COM object

    virtual ~APICubeTexture();

    void setup();

  public:
    APICubeTexture(const wchar_t* file);
    APICubeTexture(const APICubeTexture&);
    iAPITexture& operator=(const APICubeTexture&);
    iAPITexture* clone() const { return new APICubeTexture(*this); }
    // execution
    void   attach();
    void   setFilter(unsigned filter) {}
    void   detach();
    void   render(const Rectf&, unsigned char, bool) {}
    // suspension
    void   suspend();
    // termination
    void   release();
    void   Delete() const { delete this; }
};
IDirect3DCubeTexture9 interface
APICubeTexture class implementation
//-------------------------------- APICubeTexture -----------------------------
//
// The APICubeTexture class implements a texture at the API level
//
iAPITexture* CreateAPICubeTexture(const wchar_t* file) {

    return new APICubeTexture(file);
}

// constructor initializes the texture identifier
//
APICubeTexture::APICubeTexture(const wchar_t* file) {

    if (file) {
        int len = strlen(file);
        this->file = new wchar_t[len + 1];
        strcpy(this->file, file, len);
    }
    else
        this->file = nullptr;

    tex = nullptr;
}

APICubeTexture::APICubeTexture(const APICubeTexture& src) {

    file  = nullptr;
    tex   = nullptr;
    *this = src;   
}

iAPITexture& APICubeTexture::operator=(const APICubeTexture& src) {

    if (this != &src) {
        if (file)
            delete [] file;
        if (src.file) {
            int len = strlen(src.file);
            file = new wchar_t[len + 1];
            strcpy(file, src.file, len);
        }
        else
            file = nullptr;
        suspend();
        tex = nullptr;
    }

    return *this;
}

// setup creates the api texture from the texture file
//
void APICubeTexture::setup() {

    // create a texture COM object from the texture file
    //
    HRESULT hr;
    if (file && FAILED(hr = D3DXCreateCubeTextureFromFileEx(d3dd, file,
     0, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_DEFAULT,
     D3DX_DEFAULT, 0, nullptr, nullptr, &tex))) {
        error(L"APICubeTexture::11 Failed to create texture COM object from file");
        tex = nullptr;
    }
}

// attach attaches the api texture to sampling stage i
//
void APICubeTexture::attach() {

    if (!tex) setup();

    if (tex)
        d3dd->SetTexture(0, tex);
}

// detach detaches the api texture from sampling stage 0
//
void APICubeTexture::detach() {

    if (tex)
        d3dd->SetTexture(0, nullptr);
}

// suspend releases the api texture
//
void APICubeTexture::suspend() {

    // release the Interface to the texture COM object
    if (tex) {
        tex->Release();
        tex = nullptr;
    }
}

// releases suspends the api texture
//
void APICubeTexture::release() {

    suspend();
}

// destructor releases the api texture
//
APICubeTexture::~APICubeTexture() {

   release();
}
D3DXCreateCubeTextureFromFileEx
  • effects.fx
vertex shader outpu structure
//-------------------------------- Skybox -------------------------------------
//
struct FS_Skybox {
    float4 pos : POSITION;
    float3 tex : TEXCOORD0;
};
vertex shader
FS_Skybox skyboxVertexShader(float3 pos : POSITION) {
    FS_Skybox output = (FS_Skybox) 0;
    output.pos = mul(float4(pos, 0), world);            // Note the 0, this so the skybox rotates, but without translation
    output.pos = mul(output.pos, viewProjection).xyww;  // The z coordinate is replaced by w, so that the point is always projected at infinity
    output.tex = pos.xzy;                               // Note that y and z are switched to match the texture coordinate system
    return output;
}
skybox sampler state
texture skyBox;
samplerCUBE skySampler = sampler_state {
    texture = <skyBox>;
    MagFilter = LINEAR;
    Minfilter = LINEAR;
    Mipfilter = LINEAR;
    AddressU = MIRROR;
    AddressV = MIRROR;
    AddressW = MIRROR;
};
fragment shader
float4 skyboxFragmentShader(FS_Skybox input) : COLOR0 {
    return texCUBE(skySampler, input.tex);
}
skybox technique
technique skybox {

    pass {
        AlphaBlendEnable = false;
        ZENABLE = true;
        ZWRITEENABLE = false;    // By not storing the skybox's z-buffer value, it enables objects behind the skybox to be drawn, giving a realist look (e.g. an airplane in the distance)
        CullMode = None;
        VertexShader = compile vs_3_0 skyboxVertexShader();
        PixelShader  = compile ps_3_0 skyboxFragmentShader();
    }
}

To Do

Resources


Week 9 - Mar 11

This Week

  • Mathematics of Lighting
  • Lighting in Vertex Shaders
    • Notation
      Ga - global ambient color
      Ca - material ambient color
      Cd - material diffuse color
      Cs - material specular color
      Lai - ambient color of light i
      Ldi - diffuse color of light i
      Lsi - specular color of light i
      Ldiri - direction vector of light i
      N - normal to the surface at the vertex
      • Attenuation and Spotlight Factors
        • Atteni - attenuation of light i
        di - distance from light i
        di = |Ldiri|
        a0 - constant attenuation factor
        a1 - linear attenuation factor
        a2 - quadratic attenuation factor
        Atteni = 1/(a0 + a1 di + a2 di2)
        Atteni = [0, 1]
        • Spoti - spot factor of light i
        Spoti = {[ri - cos(phii/2)]/[cos(thetai/2) - cos(phii/2)]}fi
        ri - cosine of angle from axis of spotlighti
        ri = norm(- light direction in camera space) . norm(Ldiri)
        phii - penumbra (exterior cone) angle of spotlighti
        thetai - umbra (interior cone) angle of spotlighti
        fi - falloff factor of spotlighti
    • Blinn-Phong and Phong
      V - viewpoint vector
      V = norm(Cameraposition - Vertexposition)
    • Phong - account accurately for position of viewer
      Specular reflectance = (Ri . V)pi
      Ri - reflection vector
      Ri = 2 * (N . Ldiri) N - Ldiri
      pi - true specular power of light i
    • Blinn-Phong - use halfway vector instead of reflection vector - adjust power to compensate
      Specular reflectance = (N . Hi)p'i
      Hi - halfway vector
      Hi = norm(V + Ldiri)
      Hi = norm([0,0,1] + Ldiri) - less computationally intensive - assumes that camera is at infinity along z axis
      p'i - adjusted specular power of light i
    • Ambient
      Ca * ( Ga + sum [Lai * Atteni * Spoti] )
    • Diffuse
      Cd * sum [ Ldi * (N . Ldiri) * Atteni * Spoti ]
    • Specular
      Cs * sum [ Lsi * (N . Hi)p'i * Atteni * Spoti ] - Blinn-Phong
      Cs * sum [ Lsi * (Ri . V)pi * Atteni * Spoti ] - Phong
    • HLSL Intrinsic Functions
  • effects.fx - for unlit vertices and fragments
Uniform data
#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;
};

// 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
float3   heading;          // camera heading for specular calcs
int      noLights;         // no of static lights
Light    light[MLIGHTS];   // static lights
bool     lightOn[MLIGHTS]; // light switch

// Uniform Data (constant for a stream of fragments)
//
float4   ambient;          // global ambient light - always on
Material material;         // material reflectivity

bool     texOn; // texture switch
texture texMap;
sampler2D tex = sampler_state {
    texture = <texMap>;
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = MIRROR;
    AddressV = MIRROR;
};
Varying Data - simple unlit objects
//-------------------------------- Simple Unlit Objects -----------------------
//
// UnlitInput holds the original data for a vertex in the stream
//
struct UnlitVSInput {

    float3 position : POSITION;  // position in local space
    float3 normal   : NORMAL;    // normal in local space
    float2 texCoord : TEXCOORD0;  // texture coordinates
};

// UnlitOutput holds the transformed data for the vertex
//
struct UnlitVSOutput {

    float4 position : POSITION;   // position in homogeneous clip space
    float2 texCoord : TEXCOORD;   // texture coordinates
    float3 normal   : TEXCOORD1;  // lighting normal in world space
    float3 toViewer : TEXCOORD2;  // direction to viewer in world space
    float3 toLight[MLIGHTS] : TEXCOORD3; // light vector
};

// UnlitFSInput holds the input data for a single fragment of the stream
//
struct UnlitFSInput {
    float2 texCoord : TEXCOORD0;  // texture coordinate at this fragment
    float3 normal   : TEXCOORD1;  // lighting normal in world space
    float3 toViewer : TEXCOORD2;  // direction to viewer in world space
    float3 toLight[MLIGHTS] : TEXCOORD3; // direction from fragment to light i
};
Vertex Shader
// unlitVShader transforms vertex and lighting data for simple unlit objects
//
UnlitVSOutput unlitVShader(UnlitVSInput input) {

    UnlitVSOutput output; // result returned by this function

    // Transform the vertex coordinates 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.
    //
    output.position = mul(float4(input.position, 1.0), world); // local to world
    output.position = mul(output.position, viewProjection);    //... to clip
   
    // Determine the vector from this vertex to the viewer
    output.toViewer = viewPoint.xyz - input.position;

    // Determine the vector from this vertex to light source i in local space
    // (assumes that light position and direction are specified in local space)
    for (int i = 0; i < noLights; i++)
        if (light[i].type == DIRECTIONAL_LIGHT)
            output.toLight[i] = - light[i].direction;
        else
            output.toLight[i] = light[i].position - input.position;
   
    // pass the normal and texture coordinates along unaltered
    //
    output.normal   = input.normal;
    output.texCoord = input.texCoord;

    return output;
}
Fragment Shader
// This fragment shader processes lighting for noLights lights in object space
// and returns a pixel colour
//
float4 unlitFShader(UnlitFSInput input) : COLOR {

    float4 output;        // 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, factor;
    float  attenuationFactor, spotFactor, rho;
   
    // normalize the fragment input
    normal   = normalize(input.normal);
    toViewer = normalize(input.toViewer);
   
    // perform calculations for each light in turn
    for (int i = 0; i < noLights && i < MLIGHTS; i++) {
        if (lightOn[i]) {
            // diffuse and reflection factors
            toLightSource = normalize(input.toLight[i]);
            diffuseFactor = saturate(dot(normal, toLightSource));
            reflectFactor = saturate(dot(normalize(2 * diffuseFactor *
             normal - toLightSource), toViewer));

            // attenuation
            if (light[i].type != DIRECTIONAL_LIGHT) {
                distance = length(input.toLight[i]);
                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;
                }
                else
                    attenuationFactor = 0.0f;
            }
            else
                attenuationFactor = 1.0f;

            // spot
            if (light[i].type == SPOT_LIGHT) {
                rho = saturate(dot(toLightSource,
                    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
                    spotFactor = 1.0f;
            }
            else
                spotFactor = 1.0;

            factor = attenuationFactor * spotFactor;

            // accumulate ambient, diffuse, and specular elements of light i
            ambientLight  += factor * light[i].ambient.xyz;
            diffuseLight  += factor * diffuseFactor * light[i].diffuse.xyz;
            specularLight += factor * 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
    //
    output.xyz =
     saturate(material.ambient.xyz * ambientLight) +
     saturate(material.diffuse.xyz * diffuseLight) +
     saturate(material.specular.xyz * specularLight);
    output.w = material.diffuse.w;

    // sample the texture
    //
    if (texOn)
        output *= tex2D(tex, input.texCoord);

    return output;
}
techniques - opaque and translucent
technique opaque {
   
    pass {
        AlphaBlendEnable = false;
        VertexShader = compile vs_3_0 unlitVShader();
        PixelShader  = compile ps_3_0 unlitFShader();
    }
}
technique translucent {
       
    pass {
        AlphaBlendEnable = true;
        VertexShader = compile vs_3_0 unlitVShader();
        PixelShader  = compile ps_3_0 unlitFShader();
    }
}


To Do

Resources

Week 10 - Mar 18

This Week

  • Texturing - Identification
connection between Design.cpp and effects.fx
    • iTexture.h
add texture and texture state identifier
iTexture* CreateTexture(const wchar_t* file, const char* str,
 const char* isOn);
    • Texture.h
    Texture(const wchar_t*, const char*, const char*);
    • Texture.cpp
// constructor initializes the texture identifier
//
Texture::Texture(const wchar_t* file, const char* str,
 const char* isOn) : filter(0u) {

    if (file) {
        int len = strlen(file);
        this->file = new wchar_t[len + 1];
        strcpy(this->file, file, len);
    }
    else
        this->file = nullptr;

    tex    = nullptr;
    #if   PIPELINE == FIXED_FUNCTION
    #elif PIPELINE == PROGRAMMABLE
    #elif PIPELINE == PROGRAMMABLE_EFFECT
    textureHandle   = effect->GetParameterByName(0, str);
    textureonHandle = effect->GetParameterByName(0, isOn);
    #endif
}
        effect->SetTexture(textureHandle, tex);
        effect->SetBool(textureonHandle, true);
    • iAPITexture.h
add texture and texture state identifier
iAPITexture* CreateAPITexture(const wchar_t* file, const char* str,
 const char* isOn);
    • APITexture.h
    D3DXHANDLE textureHandle;   // points to texture
    D3DXHANDLE textureonHandle; // points to texture on status
public:
    APITexture(const wchar_t*, const char*, const char*);
    • APITexture.cpp
// constructor initializes the texture identifier
//
APITexture::APITexture(const wchar_t* file, const char* str,
 const char* isOn, AddressMode m) : filter(0u), mode(m) {

    if (file) {
        int len = strlen(file);
        this->file = new wchar_t[len + 1];
        strcpy(this->file, file, len);
    }
    else
        this->file = nullptr;

    tex    = nullptr;
    target = nullptr;
    #if   PIPELINE == FIXED_FUNCTION
    #elif PIPELINE == PROGRAMMABLE
    #elif PIPELINE == PROGRAMMABLE_EFFECT
    textureHandle   = effect->GetParameterByName(0, str);
    textureonHandle = effect->GetParameterByName(0, isOn);
    #endif
}
        effect->SetTexture(textureHandle, tex);
        effect->SetBool(textureonHandle, true);
  • Texturing - Tiling
Texture Coordinates
    • iGraphic.h
add u v parameters, both of which default to 1
iGraphic* CreateBox(float, float, float, float, float, float,
 float = 1, float = 1);
iGraphic* CreateIBox(float, float, float, float, float, float,
 float = 1, float = 1);
iGraphic* CreateRectangleList(float, float, float, float,
 float = 1, float = 1);
iGraphic* CreateIRectangleList(float, float, float, float,
 float = 1, float = 1);
iGraphic* CreateMeshBox(float, float, float, float, float,
 float, float = 1, float = 1);
    • Graphic.cpp
extend add functions to include u v parameters
//-------------------------------- Graphic Structures -------------------------
//
// prototypes for add() function used by the Create...() functions
void add(VertexList<Vertex>*, const Vector&, const Vector&, const Vector&, 
 const Vector&, const Vector&, float = 1, float = 1);
void add(IndexedList<Vertex>*, const Vector&, const Vector&, const Vector&,
 const Vector&, const Vector&, float = 1, float = 1);
void add(CustomMesh<Vertex>*, const Vector&, const Vector&, const Vector&,
 const Vector&, const Vector&, float = 1, float = 1);

// CreateBox builds a triangle vertex list for a brick-like box from two
// extreme points one face at a time with all faces having the same attributes
//
iGraphic* CreateBox(float minx, float miny, float minz, float maxx,
 float maxy, float maxz, float u, float v) {
   
    VertexList<Vertex>* vertexList =
     (VertexList<Vertex>*)CreateVertexList<Vertex>(TRIANGLE_LIST, 12);

    float x = (minx + maxx) / 2;
    float y = (miny + maxy) / 2;
    float z = (minz + maxz) / 2;
    minx -= x;
    miny -= y;
    minz -= z;
    maxx -= x;
    maxy -= y;
    maxz -= z;
    // bounding sphere
    float max;
    max = maxx > maxy ? maxx : maxy;
    max = maxz > max  ? maxz : max;
    vertexList->setRadius(1.73205f * max);
    // locate centroid at origin
    Vector p1 = Vector(minx, miny, minz),
           p2 = Vector(minx, maxy, minz),
           p3 = Vector(maxx, maxy, minz),
           p4 = Vector(maxx, miny, minz),
           p5 = Vector(minx, miny, maxz),
           p6 = Vector(minx, maxy, maxz),
           p7 = Vector(maxx, maxy, maxz),
           p8 = Vector(maxx, miny, maxz);
    add(vertexList, p1, p2, p3, p4, Vector(0, 0, -1), u, v); // front
    add(vertexList, p4, p3, p7, p8, Vector(1, 0,  0), u, v); // right
    add(vertexList, p8, p7, p6, p5, Vector(0, 0,  1), u, v); // back
    add(vertexList, p6, p2, p1, p5, Vector(-1, 0, 0), u, v); // left
    add(vertexList, p1, p4, p8, p5, Vector(0, -1, 0), u, v); // bottom
    add(vertexList, p2, p6, p7, p3, Vector(0, 1,  0), u, v); // top

    return vertexList;
}

iGraphic* CreateIBox(float minx, float miny, float minz, float maxx,
 float maxy, float maxz, float u, float v) {
   
    IndexedList<Vertex>* indexedList = (IndexedList<Vertex>*)
     CreateIndexedList<Vertex, unsigned short>(TRIANGLE_LIST, 12);

    float x = (minx + maxx) / 2;
    float y = (miny + maxy) / 2;
    float z = (minz + maxz) / 2;
    minx -= x;
    miny -= y;
    minz -= z;
    maxx -= x;
    maxy -= y;
    maxz -= z;
    // bounding sphere
    float max;
    max = maxx > maxy ? maxx : maxy;
    max = maxz > max  ? maxz : max;
    indexedList->setRadius(1.73205f * max);
    // locate centroid at origin
    Vector p1 = Vector(minx, miny, minz),
           p2 = Vector(minx, maxy, minz),
           p3 = Vector(maxx, maxy, minz),
           p4 = Vector(maxx, miny, minz),
           p5 = Vector(minx, miny, maxz),
           p6 = Vector(minx, maxy, maxz),
           p7 = Vector(maxx, maxy, maxz),
           p8 = Vector(maxx, miny, maxz);
    add(indexedList, p1, p2, p3, p4, Vector(0, 0, -1), u, v); // front
    add(indexedList, p4, p3, p7, p8, Vector(1, 0,  0), u, v); // right
    add(indexedList, p8, p7, p6, p5, Vector(0, 0,  1), u, v); // back
    add(indexedList, p6, p2, p1, p5, Vector(-1, 0, 0), u, v); // left
    add(indexedList, p1, p4, p8, p5, Vector(0, -1, 0), u, v); // bottom
    add(indexedList, p2, p6, p7, p3, Vector(0, 1,  0), u, v); // top

    return indexedList;
}

// CreateRectangleList builds a triangle list in the x-y plane from its two
// extreme points
//
iGraphic* CreateRectangleList(float minx, float miny, float maxx, float maxy,
 float u, float v) {
   
    VertexList<Vertex>* vertexList =
     (VertexList<Vertex>*)CreateVertexList<Vertex>(TRIANGLE_LIST, 2);

    float x = (minx + maxx) / 2, y = (miny + maxy) / 2;
    minx -= x;
    miny -= y;
    maxx -= x;
    maxy -= y;
    // bounding sphere
    float max;
    max = maxx > maxy ? maxx : maxy;
    vertexList->setRadius(1.73205f * max);
    // locate centroid at origin
    Vector p1 = Vector(minx, miny, 0),
           p2 = Vector(minx, maxy, 0),
           p3 = Vector(maxx, maxy, 0),
           p4 = Vector(maxx, miny, 0);
    add(vertexList, p1, p2, p3, p4, Vector(0, 0, -1), u, v);
   
    return vertexList;
}

// CreateIRectangleList builds an indexed triangle list in the x-y plane from
// its two extreme points
//
iGraphic* CreateIRectangleList(float minx, float miny, float maxx, float maxy,
 float u, float v) {
   
    IndexedList<Vertex>* indexedList = (IndexedList<Vertex>*)
     CreateIndexedList<Vertex, unsigned short>(TRIANGLE_LIST, 2);

    float x = (minx + maxx) / 2, y = (miny + maxy) / 2;
    minx -= x;
    miny -= y;
    maxx -= x;
    maxy -= y;
    // bounding sphere
    float max;
    max = maxx > maxy ? maxx : maxy;
    indexedList->setRadius(1.73205f * max);
    // locate centroid at origin
    Vector p1 = Vector(minx, miny, 0),
           p2 = Vector(minx, maxy, 0),
           p3 = Vector(maxx, maxy, 0),
           p4 = Vector(maxx, miny, 0);
    add(indexedList, p1, p2, p3, p4, Vector(0, 0, -1), u, v);
   
    return indexedList;
}

// CreateIRectangleList builds an indexed triangle list in the x-y plane from
// its two extreme points
//
iGraphic* CreateBRectangleList(float minx, float miny, float maxx, float maxy,
 float u, float v) {
   
    IndexedList<BumpVertex>* indexedList = (IndexedList<BumpVertex>*)
     CreateIndexedList<BumpVertex, unsigned short>(TRIANGLE_LIST, 2);

    float x = (minx + maxx) / 2, y = (miny + maxy) / 2;
    minx -= x;
    miny -= y;
    maxx -= x;
    maxy -= y;
    // bounding sphere
    float max;
    max = maxx > maxy ? maxx : maxy;
    indexedList->setRadius(1.73205f * max);
    // locate centroid at origin
    Vector p1 = Vector(minx, miny, 0),
           p2 = Vector(minx, maxy, 0),
           p3 = Vector(maxx, maxy, 0),
           p4 = Vector(maxx, miny, 0);
    add(indexedList, p1, p2, p3, p4, Vector(0, 0, -1), u, v);
   
    return indexedList;
}

// CreateMeshBox builds a mesh for a brick-like box from two extreme points one
// face at a time with each faces having distinct attributes
//
iGraphic* CreateMeshBox(float minx, float miny, float minz, float maxx,
 float maxy, float maxz, float u, float v) {

    unsigned attribute[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5};

    CustomMesh<>* mesh = (CustomMesh<>*)
     CreateCustomMesh<Vertex, unsigned short>(attribute, 12, 36, 24, 6);

    float x = (minx + maxx) / 2, y = (miny + maxy) / 2, z = (minz + maxz) / 2;
    minx -= x;
    miny -= y;
    minz -= z;
    maxx -= x;
    maxy -= y;
    maxz -= z;
    // bounding sphere
    float max;
    max = maxx > maxy ? maxx : maxy;
    max = maxz > max  ? maxz : max;
    mesh->setRadius(1.73205f * max);
    // one face at a time
    Vector p1 = Vector(minx, miny, minz),
           p2 = Vector(minx, maxy, minz),
           p3 = Vector(maxx, maxy, minz),
           p4 = Vector(maxx, miny, minz),
           p5 = Vector(minx, miny, maxz),
           p6 = Vector(minx, maxy, maxz),
           p7 = Vector(maxx, maxy, maxz),
           p8 = Vector(maxx, miny, maxz);
    add(mesh, p1, p2, p3, p4, Vector(0, 0, -1), u, v); // front
    add(mesh, p4, p3, p7, p8, Vector(1, 0,  0), u, v); // right
    add(mesh, p8, p7, p6, p5, Vector(0, 0,  1), u, v); // back
    add(mesh, p6, p2, p1, p5, Vector(-1, 0, 0), u, v); // left
    add(mesh, p1, p4, p8, p5, Vector(0, -1, 0), u, v); // bottom
    add(mesh, p2, p6, p7, p3, Vector(0, 1,  0), u, v); // top

    return mesh;
}

void add(VertexList<Vertex>* vertexList, const Vector& p1, const Vector& p2,
 const Vector& p3, const Vector& p4, const Vector& n, float u, float v) {

    vertexList->add(Vertex(p1, n, 0, v));
    vertexList->add(Vertex(p2, n, 0, 0));
    vertexList->add(Vertex(p3, n, u, 0));
    vertexList->add(Vertex(p1, n, 0, v));
    vertexList->add(Vertex(p3, n, u, 0));
    vertexList->add(Vertex(p4, n, u, v));
}

void add(IndexedList<Vertex>* indexedList, const Vector& p1, const Vector& p2,
 const Vector& p3, const Vector& p4, const Vector& n, float u, float v) {

    unsigned v1 = indexedList->add(Vertex(p1, n, 0, v));
    unsigned v2 = indexedList->add(Vertex(p2, n, 0, 0));
    unsigned v3 = indexedList->add(Vertex(p3, n, u, 0));
    unsigned v4 = indexedList->add(Vertex(p4, n, u, v));
    indexedList->add(v1);
    indexedList->add(v2);
    indexedList->add(v3);
    indexedList->add(v1);
    indexedList->add(v3);
    indexedList->add(v4);
}

void add(CustomMesh<Vertex>* mesh, const Vector& p1, const Vector& p2,
 const Vector& p3, const Vector& p4, const Vector& n, float u, float v) {

    unsigned v1 = mesh->add(Vertex(p1, n, 0, v));
    unsigned v2 = mesh->add(Vertex(p2, n, 0, 0));
    unsigned v3 = mesh->add(Vertex(p3, n, u, 0));
    unsigned v4 = mesh->add(Vertex(p4, n, u, v));
    mesh->add(v1);
    mesh->add(v2);
    mesh->add(v3);
    mesh->add(v1);
    mesh->add(v3);
    mesh->add(v4);
}
  • Texturing - Address Modes
Direct3D9 Addressing Modes
    • APITexture.h
    D3DXHANDLE textureMode;     // points to texture mode
    • APITexture.cpp
        effect->SetInt(textureMode, (int)mode);
    • effects.fx - uniform variables
// Addressing Modes
#define TEX_WRAP          0
#define TEX_CLAMP         1
#define TEX_MIRROR        2

//...

bool     tex_1_On;       // texture switch
int      tex_mode;       // addressing mode
texture  tex_1;

sampler2D tex_1_ww = sampler_state {
    texture = <tex_1>;
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
};

sampler2D tex_1_mm = sampler_state {
    texture = <tex_1>;
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = MIRROR;
    AddressV = MIRROR;
};

sampler2D tex_1_cc = sampler_state {
    texture = <tex_1>;
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = CLAMP;
    AddressV = CLAMP;
};
    • effects.fx - fragment shader
    // sample the texture
    //
    if (tex_1_On) {
        if (tex_mode == TEX_CLAMP)
            output *= tex2D(tex_1_cc, input.texCoord);
        else if (tex_mode == TEX_WRAP)
            output *= tex2D(tex_1_ww, input.texCoord);
        else if (tex_mode == TEX_MIRROR)
            output *= tex2D(tex_1_mm, input.texCoord);
    }
  • Texturing - Multi-Texturing
    • effects.fx - uniform variables
bool     tex_2_On;       // texture switch
texture  tex_2;

sampler2D tex_2_ww = sampler_state {
    texture = <tex_2>;
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
};

sampler2D tex_2_mm = sampler_state {
    texture = <tex_2>;
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = MIRROR;
    AddressV = MIRROR;
};

sampler2D tex_2_cc = sampler_state {
    texture = <tex_2>;
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = CLAMP;
    AddressV = CLAMP;
};
    • effects.fx - fragment shader
    if (tex_2_On) {
        if (tex_mode == TEX_CLAMP)
            output *= tex2D(tex_2_cc, input.texCoord);
        else if (tex_mode == TEX_WRAP)
            output *= tex2D(tex_2_ww, input.texCoord);
        else if (tex_mode == TEX_MIRROR)
            output *= tex2D(tex_2_mm, input.texCoord);
    }

To Do

Resources