The following sections provide a tutorial on how to create a program to render lighting onto a rotating textured 3D cube on the Xbox One dev kit.
The tutorial demonstrates how to create a new project, add pixel and vertex shaders, and render lighting and texturing onto a 3D model.
First, create a new project for Xbox One by using a template supplied with the XDK.

This sample requires additional header and code files be added to the project.
Next, add source code for the two pixel shaders and one vertex shader.
//**************************************************************************************
// PixelShader.hlsl
//**************************************************************************************
//--------------------------------------------------------------------------------------
// Buffer Variables
//--------------------------------------------------------------------------------------
Texture2D txDiffuse : register( t0 );
SamplerState samLinear : register( s0 );
cbuffer cbChangesEveryFrame_PS : register( b0 )
{
float4 vMeshColor;
float4 vLightDir[2];
float4 vLightColor[2];
float4 vOutputColor;
};
//--------------------------------------------------------------------------------------
// Input Struct
//--------------------------------------------------------------------------------------
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
float3 Norm : TEXCOORD1;
};
//--------------------------------------------------------------------------------------
// Pixel Shader - render a lit and textured object
//--------------------------------------------------------------------------------------
float4 main( PS_INPUT input) : SV_Target
{
// Apply texture values
float4 finalColor = txDiffuse.Sample( samLinear, input.Tex ) * vMeshColor;
// Apply NdotL lighting for 2 lights, and add value to texture value
for(int i=0; i<2; i++)
{
finalColor += saturate( dot( (float3)vLightDir[i],input.Norm) * vLightColor[i] );
}
finalColor.a = 1.0f;
return finalColor;
}

//**************************************************************************************
// PixelShader1.hlsl
//**************************************************************************************
//--------------------------------------------------------------------------------------
// Constant Buffer
//--------------------------------------------------------------------------------------
cbuffer cbChangesEveryFrame_PS : register( b0 )
{
float4 vMeshColor;
float4 vLightDir[2];
float4 vLightColor[2];
float4 vOutputColor;
};
//--------------------------------------------------------------------------------------
// Input Struct
//--------------------------------------------------------------------------------------
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
float3 Norm : TEXCOORD1;
};
//--------------------------------------------------------------------------------------
// PSSolid - render a solid color
//--------------------------------------------------------------------------------------
float4 PSSolid( PS_INPUT input) : SV_Target
{
return vOutputColor;
}


//**************************************************************************************
// VertexShader.hlsl
//**************************************************************************************
//--------------------------------------------------------------------------------------
// Constant Buffer Definitions
//--------------------------------------------------------------------------------------
cbuffer cbNeverChanges : register( b0 )
{
matrix View;
};
cbuffer cbChangeOnResize : register( b1 )
{
matrix Projection;
};
cbuffer cbChangesEveryFrame_VS : register( b2 )
{
matrix World;
};
//--------------------------------------------------------------------------------------
// Input and Output Structs
//--------------------------------------------------------------------------------------
struct VS_INPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD0;
float3 Norm : NORMAL;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
float3 Norm : TEXCOORD1;
};
//--------------------------------------------------------------------------------------
// Vertex Shader - apply model - world - viewport - projection transformations
//--------------------------------------------------------------------------------------
PS_INPUT main( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
// Apply world, view, and projection transformations to the vertex position
output.Pos = mul( input.Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
// Copy texture coordinates
output.Tex = input.Tex;
// Apply world transformation to normal vector
output.Norm = mul( float4( input.Norm, 0.0f ), World ).xyz;
return output;
}

Open Game.h in the editor.
Add the following include, using and struct statements to Game.h, after the #include “StepTimer.h” statement. You may need to build the project to get rid of compiler warnings (Build > Build Solution).
C++
#include <directxcolors.h>
#include "DDSTextureLoader.h"
#include "PixelShader.h"
#include "PixelShader1.h"
#include "VertexShader.h"
using namespace DirectX;
//--------------------------------------------------------------------------------------
// Structures
//--------------------------------------------------------------------------------------
struct SimpleVertex
{
XMFLOAT3 Pos;
XMFLOAT2 Tex;
XMFLOAT3 Normal;
};
struct CBNeverChanges
{
XMMATRIX mView;
};
struct CBChangeOnResize
{
XMMATRIX mProjection;
};
struct CBChangesEveryFrame_VS
{
XMMATRIX mWorld;
};
struct CBChangesEveryFrame_PS
{
XMFLOAT4 vMeshColor;
XMFLOAT4 vLightDir[2];
XMFLOAT4 vLightColor[2];
XMFLOAT4 vOutputColor;
};
Add the following declarations to the end of the private section of the Game class.
C++
// Declarations for drawing a lit, textured 3D cube
Microsoft::WRL::ComPtr<ID3D11InputLayout> m_InputLayout;
Microsoft::WRL::ComPtr<ID3D11Buffer> m_VertexBuffer;
Microsoft::WRL::ComPtr<ID3D11Buffer> m_IndexBuffer;
Microsoft::WRL::ComPtr<ID3D11Buffer> m_CBNeverChanges;
Microsoft::WRL::ComPtr<ID3D11Buffer> m_CBChangeOnResize;
Microsoft::WRL::ComPtr<ID3D11Buffer> m_CBChangesEveryFrame_VS;
Microsoft::WRL::ComPtr<ID3D11Buffer> m_CBChangesEveryFrame_PS;
Microsoft::WRL::ComPtr<ID3D11VertexShader> m_VertexShader;
Microsoft::WRL::ComPtr<ID3D11PixelShader> m_PixelShader;
Microsoft::WRL::ComPtr<ID3D11PixelShader> m_PixelShaderSolid;
Microsoft::WRL::ComPtr<ID3D11SamplerState> m_SamplerLinear;
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> m_TextureRV;
XMMATRIX g_World;
XMMATRIX g_View;
XMMATRIX g_Projection;
XMFLOAT4 g_vMeshColor;
Save Game.h.
Next, initialize 3D cube data by adding source code to Game.cpp.
Add the following code at the end of the function:
C++
// The compiled shader bytecodes are contained in constant buffers,
// g_vs_main, g_ps_main and g_ps_main1 defined in the auto-generated header files
DX::ThrowIfFailed( m_d3dDevice->CreateVertexShader( g_vs_main,
sizeof( g_vs_main ),
NULL,
m_VertexShader.GetAddressOf() )
);
DX::ThrowIfFailed( m_d3dDevice->CreatePixelShader( g_ps_main,
sizeof( g_ps_main ),
NULL,
m_PixelShader.GetAddressOf() )
);
// Create the second pixel shader. Object is rendered as a single solid color.
DX::ThrowIfFailed( m_d3dDevice->CreatePixelShader( g_ps_main1,
sizeof( g_ps_main1 ),
NULL,
m_PixelShaderSolid.GetAddressOf() )
);
// Create input layout (must match declaration of SimpleVertex)
const D3D11_INPUT_ELEMENT_DESC InputElementDesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
DX::ThrowIfFailed( m_d3dDevice->CreateInputLayout( InputElementDesc,
_countof( InputElementDesc ),
g_vs_main,
sizeof( g_vs_main ),
m_InputLayout.GetAddressOf() )
);
// Set the input layout
m_d3dContext->IASetInputLayout( m_InputLayout.Get() );
// Create vertex buffer
SimpleVertex vertices[] =
{
{ XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 0.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 0.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
};
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( SimpleVertex ) * 24;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = vertices;
DX::ThrowIfFailed(m_d3dDevice->CreateBuffer( &bd, &InitData, m_VertexBuffer.GetAddressOf() ));
// Set vertex buffer
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
m_d3dContext->IASetVertexBuffers( 0, 1, m_VertexBuffer.GetAddressOf(), &stride, &offset );
// Create index buffer
WORD indices[] =
{
3,1,0,
2,1,3,
6,4,5,
7,4,6,
11,9,8,
10,9,11,
14,12,13,
15,12,14,
19,17,16,
18,17,19,
22,20,21,
23,20,22
};
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( WORD ) * 36; // 36 vertices needed for 12 triangles in a triangle list
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
InitData.pSysMem = indices;
DX::ThrowIfFailed(m_d3dDevice->CreateBuffer( &bd, &InitData, m_IndexBuffer.GetAddressOf() ));
// Set index buffer
m_d3dContext->IASetIndexBuffer( m_IndexBuffer.Get(), DXGI_FORMAT_R16_UINT, 0 );
// Set primitive topology
m_d3dContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
// Create the constant buffers
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(CBNeverChanges);
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
DX::ThrowIfFailed(m_d3dDevice->CreateBuffer( &bd, nullptr, m_CBNeverChanges.GetAddressOf() ));
bd.ByteWidth = sizeof(CBChangeOnResize);
DX::ThrowIfFailed(m_d3dDevice->CreateBuffer( &bd, nullptr, m_CBChangeOnResize.GetAddressOf() ));
bd.ByteWidth = sizeof(CBChangesEveryFrame_VS);
DX::ThrowIfFailed(m_d3dDevice->CreateBuffer( &bd, nullptr, m_CBChangesEveryFrame_VS.GetAddressOf() ));
bd.ByteWidth = sizeof(CBChangesEveryFrame_PS);
DX::ThrowIfFailed(m_d3dDevice->CreateBuffer( &bd, nullptr, m_CBChangesEveryFrame_PS.GetAddressOf() ));
// Load the Texture
DX::ThrowIfFailed(CreateDDSTextureFromFile( m_d3dDevice.Get(), m_d3dContext.Get(), L"seafloor.dds", nullptr, m_TextureRV.GetAddressOf() ));
// Create the sample state
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory( &sampDesc, sizeof(sampDesc) );
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
DX::ThrowIfFailed( m_d3dDevice->CreateSamplerState( &sampDesc, m_SamplerLinear.GetAddressOf() ));
// Initialize the texture color
g_vMeshColor.x = 0.4f;
g_vMeshColor.y = 0.4f;
g_vMeshColor.z = 0.4f;
g_vMeshColor.w = 1.0f;
// Initialize the world matrices
g_World = XMMatrixIdentity();
// Initialize the view matrix
XMVECTOR Eye = XMVectorSet( 0.0f, 3.0f, -6.0f, 0.0f );
XMVECTOR At = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
XMVECTOR Up = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
g_View = XMMatrixLookAtLH( Eye, At, Up );
CBNeverChanges cbNeverChanges;
cbNeverChanges.mView = XMMatrixTranspose( g_View );
m_d3dContext->UpdateSubresource( m_CBNeverChanges.Get(), 0, nullptr, &cbNeverChanges, 0, 0 );
// Initialize the projection matrix
g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV2, 1920 / (FLOAT)1080, 0.1f, 100.0f );
CBChangeOnResize cbChangesOnResize;
cbChangesOnResize.mProjection = XMMatrixTranspose( g_Projection );
m_d3dContext->UpdateSubresource( m_CBChangeOnResize.Get(), 0, nullptr, &cbChangesOnResize, 0, 0 );
Next, add source code to Game.cpp that will render the 3D cube.
// TODO: Add your rendering code hereReplace the comment with the following code:
C++
// Animate the cube
static float t = 0.0f;
static ULONGLONG timeStart = 0;
ULONGLONG timeCur = GetTickCount64();
if( timeStart == 0 )
timeStart = timeCur;
t = ( timeCur - timeStart ) / 1000.0f;
g_World = XMMatrixRotationRollPitchYaw(t, t/2.0f, 0.0f);
//Update the spotlight color
XMFLOAT4 RotLightColor;
RotLightColor.x = ( sinf( t * 1.0f ) + 1.0f ) * 0.5f;
RotLightColor.y = ( cosf( t * 3.0f ) + 1.0f ) * 0.5f;
RotLightColor.z = ( sinf( t * 5.0f ) + 1.0f ) * 0.5f;
RotLightColor.w = 1.0f;
// Setup our lighting parameters
XMFLOAT4 vLightDirs[2] =
{
XMFLOAT4( -0.577f, 0.577f, -0.577f, 1.0f ),
XMFLOAT4( 0.0f, 0.0f, -1.0f, 1.0f ),
};
XMFLOAT4 vLightColors[2] =
{
XMFLOAT4( 0.5f, 0.5f, 0.5f, 1.0f ),
RotLightColor, //The second light gradually changes colors
};
// Rotate the second light around the origin
XMMATRIX mRotate = XMMatrixRotationY( -2.0f * t );
XMVECTOR vLightDir = XMLoadFloat4( &vLightDirs[1] );
vLightDir = XMVector3Transform( vLightDir, mRotate );
XMStoreFloat4( &vLightDirs[1], vLightDir );
// Update variables that change once per frame
CBChangesEveryFrame_VS cbVS;
cbVS.mWorld = XMMatrixTranspose( g_World );
m_d3dContext->UpdateSubresource( m_CBChangesEveryFrame_VS.Get(), 0, nullptr, &cbVS, 0, 0 );
CBChangesEveryFrame_PS cbPS;
cbPS.vMeshColor = g_vMeshColor;
cbPS.vLightDir[0] = vLightDirs[0];
cbPS.vLightDir[1] = vLightDirs[1];
cbPS.vLightColor[0] = vLightColors[0];
cbPS.vLightColor[1] = vLightColors[1];
cbPS.vOutputColor = XMFLOAT4(0, 0, 0, 0);
m_d3dContext->UpdateSubresource( m_CBChangesEveryFrame_PS.Get(), 0, nullptr, &cbPS, 0, 0 );
// Render the cube
m_d3dContext->VSSetShader( m_VertexShader.Get(), nullptr, 0 );
m_d3dContext->VSSetConstantBuffers( 0, 1, m_CBNeverChanges.GetAddressOf() );
m_d3dContext->VSSetConstantBuffers( 1, 1, m_CBChangeOnResize.GetAddressOf() );
m_d3dContext->VSSetConstantBuffers( 2, 1, m_CBChangesEveryFrame_VS.GetAddressOf() );
m_d3dContext->PSSetShader( m_PixelShader.Get(), nullptr, 0 );
m_d3dContext->PSSetConstantBuffers( 0, 1, m_CBChangesEveryFrame_PS.GetAddressOf() );
m_d3dContext->PSSetShaderResources( 0, 1, m_TextureRV.GetAddressOf() );
m_d3dContext->PSSetSamplers( 0, 1, m_SamplerLinear.GetAddressOf() );
m_d3dContext->DrawIndexed( 36, 0, 0 );
// Render light sources as colored cubes
for( int m = 0; m < 2; m++ )
{
XMMATRIX mLight = XMMatrixTranslationFromVector( 5.0f * XMLoadFloat4( &vLightDirs[m] ) );
XMMATRIX mLightScale = XMMatrixScaling( 0.2f, 0.2f, 0.2f );
mLight = mLightScale * mLight;
// Update the world variable to reflect the current light
cbVS.mWorld = XMMatrixTranspose( mLight );
m_d3dContext->UpdateSubresource( m_CBChangesEveryFrame_VS.Get(), 0, nullptr, &cbVS, 0, 0 );
cbPS.vOutputColor = vLightColors[m];
m_d3dContext->UpdateSubresource( m_CBChangesEveryFrame_PS.Get(), 0, nullptr, &cbPS, 0, 0 );
m_d3dContext->PSSetShader( m_PixelShaderSolid.Get(), nullptr, 0 ); //PixelShaderSolid does not take textures or lighting into account. renders cubes of a solid color
m_d3dContext->DrawIndexed( 36, 0, 0 );
}
In order to have a texture rendered to the surfaces of the cube, a texture file (a .dds file) should be copied to the dev kit.
If your .dds file is not called seafloor.dds then either rename it, or change the following line in your CreateResources method to match the name of the .dds file you are using.
C++
DX::ThrowIfFailed(CreateDDSTextureFromFile( m_d3dDevice.Get(), L"seafloor.dds", nullptr, m_TextureRV.GetAddressOf() ));
Note This line in your project will fail if the .dds file is not in a supported format.
If you’ve completed the preceding steps in this tutorial, you can now build and deploy your app to the dev kit.

Note The gray box in the top left shows the static light source, and a second box rotates around the central cube, broadcasting a gradually changing color.