To create soft shadows we first need to modify the shadow shader. Instead of using the shader to render the shadowed scene with lighting as it previously did it ...
Tutorial42:SoftShadows
ThistutorialwillcoverhowtoimplementsoftshadowsinDirectX11usingHLSLandC++.
Thecodeinthistutorialisbasedontheshadowmappingtutorial.
Oneoftheissueswithshadowmapsisthelackofprecisioninthetextureusedfortheshadowmap.
Evenhighresolutiontexturessuchas1024x1024(aswasusedintheshadowmappingtutorial)stillcreateshadowswithjaggededges.
Forexamplelookingattheedgeoftheshadowforthespherewegetthefollowingvisualartifact:
Withthatsaidoneofthemainadvantagesofusingshadowmapsisthatwecaneasilyproducesoftshadowstofixthejaggedshadowedges.
Tocreatesoftshadowswefirstneedtomodifytheshadowshader.
Insteadofusingtheshadertorendertheshadowedscenewithlightingasitpreviouslydiditwillnowinsteadjustrender
shadowareasaspureblackandtheilluminatedareasaspurewhite.
Sorenderingourscenewillnowproduceablackandwhiteimageasfollows:
Alsowerendertheblackandwhitescenetoarendertotextureinsteadoftothebackbuffer.
Thereasonwerendertoatextureissothatwecanperformthenextstepwhichistoblurtheblackandwhiteimage.
Forthistutorialwewillperformaregularblurlikewedidintheblurtutorial(Tutorial36).
Withtheblackandwhitetextureblurredwenowhavethefollowingtextureresult:
Asyoucanseetheshadowedgesarenowblurredcreatingthesoftshadows.
Toapplythesoftshadowstothefinalsceneweusejustaregularlightingshaderexceptthatittakesasinputtheblurredimage
andattheendofthepixelshaderwemultiplethecolorresultbytheprojectedblurimagetogetsoftshadows.
Weprojecttheblurredimagefromthecamera'sviewpoint.
Doingsogivesusthefollowingsoftshadowscene:
Wewillstartthecodesectionofthetutorialbylookingatthemodifiedshadowshader.
Shadow.vs
Thevertexshadercanremainthesame.
////////////////////////////////////////////////////////////////////////////////
//Filename:shadow.vs
////////////////////////////////////////////////////////////////////////////////
/////////////
//GLOBALS//
/////////////
cbufferMatrixBuffer
{
matrixworldMatrix;
matrixviewMatrix;
matrixprojectionMatrix;
matrixlightViewMatrix;
matrixlightProjectionMatrix;
};
//////////////////////
//CONSTANTBUFFERS//
//////////////////////
cbufferLightBuffer2
{
float3lightPosition;
floatpadding;
};
//////////////
//TYPEDEFS//
//////////////
structVertexInputType
{
float4position:POSITION;
float2tex:TEXCOORD0;
float3normal:NORMAL;
};
structPixelInputType
{
float4position:SV_POSITION;
float2tex:TEXCOORD0;
float3normal:NORMAL;
float4lightViewPosition:TEXCOORD1;
float3lightPos:TEXCOORD2;
};
////////////////////////////////////////////////////////////////////////////////
//VertexShader
////////////////////////////////////////////////////////////////////////////////
PixelInputTypeShadowVertexShader(VertexInputTypeinput)
{
PixelInputTypeoutput;
float4worldPosition;
//Changethepositionvectortobe4unitsforpropermatrixcalculations.
input.position.w=1.0f;
//Calculatethepositionofthevertexagainsttheworld,view,andprojectionmatrices.
output.position=mul(input.position,worldMatrix);
output.position=mul(output.position,viewMatrix);
output.position=mul(output.position,projectionMatrix);
//Calculatethepositionoftheverticeasviewedbythelightsource.
output.lightViewPosition=mul(input.position,worldMatrix);
output.lightViewPosition=mul(output.lightViewPosition,lightViewMatrix);
output.lightViewPosition=mul(output.lightViewPosition,lightProjectionMatrix);
//Storethetexturecoordinatesforthepixelshader.
output.tex=input.tex;
//Calculatethenormalvectoragainsttheworldmatrixonly.
output.normal=mul(input.normal,(float3x3)worldMatrix);
//Normalizethenormalvector.
output.normal=normalize(output.normal);
//Calculatethepositionofthevertexintheworld.
worldPosition=mul(input.position,worldMatrix);
//Determinethelightpositionbasedonthepositionofthelightandthepositionofthevertexintheworld.
output.lightPos=lightPosition.xyz-worldPosition.xyz;
//Normalizethelightpositionvector.
output.lightPos=normalize(output.lightPos);
returnoutput;
}
Shadow.ps
Inthepixelshaderwehaveremovedanumberoftheinputsaslightingandtexturingarenolongerneededtoproducetheblackandwhiteshadowimage.
////////////////////////////////////////////////////////////////////////////////
//Filename:shadow.ps
////////////////////////////////////////////////////////////////////////////////
//////////////
//TEXTURES//
//////////////
Texture2DdepthMapTexture:register(t0);
///////////////////
//SAMPLESTATES//
///////////////////
SamplerStateSampleTypeClamp:register(s0);
//////////////
//TYPEDEFS//
//////////////
structPixelInputType
{
float4position:SV_POSITION;
float2tex:TEXCOORD0;
float3normal:NORMAL;
float4lightViewPosition:TEXCOORD1;
float3lightPos:TEXCOORD2;
};
////////////////////////////////////////////////////////////////////////////////
//PixelShader
////////////////////////////////////////////////////////////////////////////////
float4ShadowPixelShader(PixelInputTypeinput):SV_TARGET
{
floatbias;
float4color;
float2projectTexCoord;
floatdepthValue;
floatlightDepthValue;
floatlightIntensity;
//Setthebiasvalueforfixingthefloatingpointprecisionissues.
bias=0.001f;
Nowinthepixelshaderwesetthedefaultcolortobeblack(shadowed).
//Setthedefaultoutputcolortobeblack(shadow).
color=float4(0.0f,0.0f,0.0f,1.0f);
//Calculatetheprojectedtexturecoordinates.
projectTexCoord.x=input.lightViewPosition.x/input.lightViewPosition.w/2.0f+0.5f;
projectTexCoord.y=-input.lightViewPosition.y/input.lightViewPosition.w/2.0f+0.5f;
//Determineiftheprojectedcoordinatesareinthe0to1range.Ifsothenthispixelisintheviewofthelight.
if((saturate(projectTexCoord.x)==projectTexCoord.x)&&(saturate(projectTexCoord.y)==projectTexCoord.y))
{
//Sampletheshadowmapdepthvaluefromthedepthtextureusingthesamplerattheprojectedtexturecoordinatelocation.
depthValue=depthMapTexture.Sample(SampleTypeClamp,projectTexCoord).r;
//Calculatethedepthofthelight.
lightDepthValue=input.lightViewPosition.z/input.lightViewPosition.w;
//SubtractthebiasfromthelightDepthValue.
lightDepthValue=lightDepthValue-bias;
//Comparethedepthoftheshadowmapvalueandthedepthofthelighttodeterminewhethertoshadowortolightthispixel.
//Ifthelightisinfrontoftheobjectthenlightthepixel,ifnotthenshadowthispixelsinceanobject(occluder)iscastingashadowonit.
if(lightDepthValue0.0f)
{
Andifwedetermineapixelisilluminatedthenitiscoloredpurewhite.
color=float4(1.0f,1.0f,1.0f,1.0f);
}
}
}
Thiswillreturnablackandwhiteimageoftheshadowedscenesowecanuseitasinputtotheblurringshader.
returncolor;
}
Shadowshaderclass.h
TheShadowShaderClasshashadjustthetexturingandlightingcolorelementsremovedfromitsinceitonlyneedstoproduceanun-texturedblackandwhiteimage.
Otherwiseitremainsthesame.
////////////////////////////////////////////////////////////////////////////////
//Filename:shadowshaderclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef_SHADOWSHADERCLASS_H_
#define_SHADOWSHADERCLASS_H_
//////////////
//INCLUDES//
//////////////
#include
#include
#include
#include
usingnamespacestd;
////////////////////////////////////////////////////////////////////////////////
//Classname:ShadowShaderClass
////////////////////////////////////////////////////////////////////////////////
classShadowShaderClass
{
private:
structMatrixBufferType
{
D3DXMATRIXworld;
D3DXMATRIXview;
D3DXMATRIXprojection;
D3DXMATRIXlightView;
D3DXMATRIXlightProjection;
};
structLightBufferType2
{
D3DXVECTOR3lightPosition;
floatpadding;
};
public:
ShadowShaderClass();
ShadowShaderClass(constShadowShaderClass&);
~ShadowShaderClass();
boolInitialize(ID3D11Device*,HWND);
voidShutdown();
boolRender(ID3D11DeviceContext*,int,D3DXMATRIX,D3DXMATRIX,D3DXMATRIX,D3DXMATRIX,D3DXMATRIX,ID3D11ShaderResourceView*,D3DXVECTOR3);
private:
boolInitializeShader(ID3D11Device*,HWND,WCHAR*,WCHAR*);
voidShutdownShader();
voidOutputShaderErrorMessage(ID3D10Blob*,HWND,WCHAR*);
boolSetShaderParameters(ID3D11DeviceContext*,D3DXMATRIX,D3DXMATRIX,D3DXMATRIX,D3DXMATRIX,D3DXMATRIX,ID3D11ShaderResourceView*,D3DXVECTOR3);
voidRenderShader(ID3D11DeviceContext*,int);
private:
ID3D11VertexShader*m_vertexShader;
ID3D11PixelShader*m_pixelShader;
ID3D11InputLayout*m_layout;
ID3D11SamplerState*m_sampleStateClamp;
ID3D11Buffer*m_matrixBuffer;
ID3D11Buffer*m_lightBuffer2;
};
#endif
Shadowshaderclass.cpp
////////////////////////////////////////////////////////////////////////////////
//Filename:shadowshaderclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include"shadowshaderclass.h"
ShadowShaderClass::ShadowShaderClass()
{
m_vertexShader=0;
m_pixelShader=0;
m_layout=0;
m_sampleStateClamp=0;
m_matrixBuffer=0;
m_lightBuffer2=0;
}
ShadowShaderClass::ShadowShaderClass(constShadowShaderClass&other)
{
}
ShadowShaderClass::~ShadowShaderClass()
{
}
boolShadowShaderClass::Initialize(ID3D11Device*device,HWNDhwnd)
{
boolresult;
//Initializethevertexandpixelshaders.
result=InitializeShader(device,hwnd,L"../Engine/shadow.vs",L"../Engine/shadow.ps");
if(!result)
{
returnfalse;
}
returntrue;
}
voidShadowShaderClass::Shutdown()
{
//Shutdownthevertexandpixelshadersaswellastherelatedobjects.
ShutdownShader();
return;
}
boolShadowShaderClass::Render(ID3D11DeviceContext*deviceContext,intindexCount,D3DXMATRIXworldMatrix,D3DXMATRIXviewMatrix,
D3DXMATRIXprojectionMatrix,D3DXMATRIXlightViewMatrix,D3DXMATRIXlightProjectionMatrix,
ID3D11ShaderResourceView*depthMapTexture,D3DXVECTOR3lightPosition)
{
boolresult;
//Settheshaderparametersthatitwilluseforrendering.
result=SetShaderParameters(deviceContext,worldMatrix,viewMatrix,projectionMatrix,lightViewMatrix,lightProjectionMatrix,depthMapTexture,
lightPosition);
if(!result)
{
returnfalse;
}
//Nowrenderthepreparedbufferswiththeshader.
RenderShader(deviceContext,indexCount);
returntrue;
}
boolShadowShaderClass::InitializeShader(ID3D11Device*device,HWNDhwnd,WCHAR*vsFilename,WCHAR*psFilename)
{
HRESULTresult;
ID3D10Blob*errorMessage;
ID3D10Blob*vertexShaderBuffer;
ID3D10Blob*pixelShaderBuffer;
D3D11_INPUT_ELEMENT_DESCpolygonLayout[3];
unsignedintnumElements;
D3D11_SAMPLER_DESCsamplerDesc;
D3D11_BUFFER_DESCmatrixBufferDesc;
D3D11_BUFFER_DESClightBufferDesc2;
//Initializethepointersthisfunctionwillusetonull.
errorMessage=0;
vertexShaderBuffer=0;
pixelShaderBuffer=0;
//Compilethevertexshadercode.
result=D3DX11CompileFromFile(vsFilename,NULL,NULL,"ShadowVertexShader","vs_5_0",D3D10_SHADER_ENABLE_STRICTNESS,0,NULL,
&vertexShaderBuffer,&errorMessage,NULL);
if(FAILED(result))
{
//Iftheshaderfailedtocompileitshouldhavewritensomethingtotheerrormessage.
if(errorMessage)
{
OutputShaderErrorMessage(errorMessage,hwnd,vsFilename);
}
//Iftherewasnothingintheerrormessagethenitsimplycouldnotfindtheshaderfileitself.
else
{
MessageBox(hwnd,vsFilename,L"MissingShaderFile",MB_OK);
}
returnfalse;
}
//Compilethepixelshadercode.
result=D3DX11CompileFromFile(psFilename,NULL,NULL,"ShadowPixelShader","ps_5_0",D3D10_SHADER_ENABLE_STRICTNESS,0,NULL,
&pixelShaderBuffer,&errorMessage,NULL);
if(FAILED(result))
{
//Iftheshaderfailedtocompileitshouldhavewritensomethingtotheerrormessage.
if(errorMessage)
{
OutputShaderErrorMessage(errorMessage,hwnd,psFilename);
}
//Iftherewasnothingintheerrormessagethenitsimplycouldnotfindthefileitself.
else
{
MessageBox(hwnd,psFilename,L"MissingShaderFile",MB_OK);
}
returnfalse;
}
//Createthevertexshaderfromthebuffer.
result=device->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(),vertexShaderBuffer->GetBufferSize(),NULL,&m_vertexShader);
if(FAILED(result))
{
returnfalse;
}
//Createthepixelshaderfromthebuffer.
result=device->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(),pixelShaderBuffer->GetBufferSize(),NULL,&m_pixelShader);
if(FAILED(result))
{
returnfalse;
}
//Createthevertexinputlayoutdescription.
polygonLayout[0].SemanticName="POSITION";
polygonLayout[0].SemanticIndex=0;
polygonLayout[0].Format=DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[0].InputSlot=0;
polygonLayout[0].AlignedByteOffset=0;
polygonLayout[0].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[0].InstanceDataStepRate=0;
polygonLayout[1].SemanticName="TEXCOORD";
polygonLayout[1].SemanticIndex=0;
polygonLayout[1].Format=DXGI_FORMAT_R32G32_FLOAT;
polygonLayout[1].InputSlot=0;
polygonLayout[1].AlignedByteOffset=D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[1].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[1].InstanceDataStepRate=0;
polygonLayout[2].SemanticName="NORMAL";
polygonLayout[2].SemanticIndex=0;
polygonLayout[2].Format=DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[2].InputSlot=0;
polygonLayout[2].AlignedByteOffset=D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[2].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[2].InstanceDataStepRate=0;
//Getacountoftheelementsinthelayout.
numElements=sizeof(polygonLayout)/sizeof(polygonLayout[0]);
//Createthevertexinputlayout.
result=device->CreateInputLayout(polygonLayout,numElements,vertexShaderBuffer->GetBufferPointer(),vertexShaderBuffer->GetBufferSize(),
&m_layout);
if(FAILED(result))
{
returnfalse;
}
//Releasethevertexshaderbufferandpixelshaderbuffersincetheyarenolongerneeded.
vertexShaderBuffer->Release();
vertexShaderBuffer=0;
pixelShaderBuffer->Release();
pixelShaderBuffer=0;
//Createaclamptexturesamplerstatedescription.
samplerDesc.Filter=D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU=D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV=D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW=D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.MipLODBias=0.0f;
samplerDesc.MaxAnisotropy=1;
samplerDesc.ComparisonFunc=D3D11_COMPARISON_ALWAYS;
samplerDesc.BorderColor[0]=0;
samplerDesc.BorderColor[1]=0;
samplerDesc.BorderColor[2]=0;
samplerDesc.BorderColor[3]=0;
samplerDesc.MinLOD=0;
samplerDesc.MaxLOD=D3D11_FLOAT32_MAX;
//Createthetexturesamplerstate.
result=device->CreateSamplerState(&samplerDesc,&m_sampleStateClamp);
if(FAILED(result))
{
returnfalse;
}
//Setupthedescriptionofthedynamicmatrixconstantbufferthatisinthevertexshader.
matrixBufferDesc.Usage=D3D11_USAGE_DYNAMIC;
matrixBufferDesc.ByteWidth=sizeof(MatrixBufferType);
matrixBufferDesc.BindFlags=D3D11_BIND_CONSTANT_BUFFER;
matrixBufferDesc.CPUAccessFlags=D3D11_CPU_ACCESS_WRITE;
matrixBufferDesc.MiscFlags=0;
matrixBufferDesc.StructureByteStride=0;
//Createtheconstantbufferpointersowecanaccessthevertexshaderconstantbufferfromwithinthisclass.
result=device->CreateBuffer(&matrixBufferDesc,NULL,&m_matrixBuffer);
if(FAILED(result))
{
returnfalse;
}
//Setupthedescriptionofthelightdynamicconstantbufferthatisinthevertexshader.
lightBufferDesc2.Usage=D3D11_USAGE_DYNAMIC;
lightBufferDesc2.ByteWidth=sizeof(LightBufferType2);
lightBufferDesc2.BindFlags=D3D11_BIND_CONSTANT_BUFFER;
lightBufferDesc2.CPUAccessFlags=D3D11_CPU_ACCESS_WRITE;
lightBufferDesc2.MiscFlags=0;
lightBufferDesc2.StructureByteStride=0;
//Createtheconstantbufferpointersowecanaccessthevertexshaderconstantbufferfromwithinthisclass.
result=device->CreateBuffer(&lightBufferDesc2,NULL,&m_lightBuffer2);
if(FAILED(result))
{
returnfalse;
}
returntrue;
}
voidShadowShaderClass::ShutdownShader()
{
//Releasethelightconstantbuffer.
if(m_lightBuffer2)
{
m_lightBuffer2->Release();
m_lightBuffer2=0;
}
//Releasethematrixconstantbuffer.
if(m_matrixBuffer)
{
m_matrixBuffer->Release();
m_matrixBuffer=0;
}
//Releasethesamplerstate.
if(m_sampleStateClamp)
{
m_sampleStateClamp->Release();
m_sampleStateClamp=0;
}
//Releasethelayout.
if(m_layout)
{
m_layout->Release();
m_layout=0;
}
//Releasethepixelshader.
if(m_pixelShader)
{
m_pixelShader->Release();
m_pixelShader=0;
}
//Releasethevertexshader.
if(m_vertexShader)
{
m_vertexShader->Release();
m_vertexShader=0;
}
return;
}
voidShadowShaderClass::OutputShaderErrorMessage(ID3D10Blob*errorMessage,HWNDhwnd,WCHAR*shaderFilename)
{
char*compileErrors;
unsignedlongbufferSize,i;
ofstreamfout;
//Getapointertotheerrormessagetextbuffer.
compileErrors=(char*)(errorMessage->GetBufferPointer());
//Getthelengthofthemessage.
bufferSize=errorMessage->GetBufferSize();
//Openafiletowritetheerrormessageto.
fout.open("shader-error.txt");
//Writeouttheerrormessage.
for(i=0;iRelease();
errorMessage=0;
//Popamessageuponthescreentonotifytheusertocheckthetextfileforcompileerrors.
MessageBox(hwnd,L"Errorcompilingshader.Checkshader-error.txtformessage.",shaderFilename,MB_OK);
return;
}
boolShadowShaderClass::SetShaderParameters(ID3D11DeviceContext*deviceContext,D3DXMATRIXworldMatrix,D3DXMATRIXviewMatrix,
D3DXMATRIXprojectionMatrix,D3DXMATRIXlightViewMatrix,D3DXMATRIXlightProjectionMatrix,
ID3D11ShaderResourceView*depthMapTexture,D3DXVECTOR3lightPosition)
{
HRESULTresult;
D3D11_MAPPED_SUBRESOURCEmappedResource;
unsignedintbufferNumber;
MatrixBufferType*dataPtr;
LightBufferType2*dataPtr3;
//Transposethematricestopreparethemfortheshader.
D3DXMatrixTranspose(&worldMatrix,&worldMatrix);
D3DXMatrixTranspose(&viewMatrix,&viewMatrix);
D3DXMatrixTranspose(&projectionMatrix,&projectionMatrix);
D3DXMatrixTranspose(&lightViewMatrix,&lightViewMatrix);
D3DXMatrixTranspose(&lightProjectionMatrix,&lightProjectionMatrix);
//Locktheconstantbuffersoitcanbewrittento.
result=deviceContext->Map(m_matrixBuffer,0,D3D11_MAP_WRITE_DISCARD,0,&mappedResource);
if(FAILED(result))
{
returnfalse;
}
//Getapointertothedataintheconstantbuffer.
dataPtr=(MatrixBufferType*)mappedResource.pData;
//Copythematricesintotheconstantbuffer.
dataPtr->world=worldMatrix;
dataPtr->view=viewMatrix;
dataPtr->projection=projectionMatrix;
dataPtr->lightView=lightViewMatrix;
dataPtr->lightProjection=lightProjectionMatrix;
//Unlocktheconstantbuffer.
deviceContext->Unmap(m_matrixBuffer,0);
//Setthepositionoftheconstantbufferinthevertexshader.
bufferNumber=0;
//Nowsettheconstantbufferinthevertexshaderwiththeupdatedvalues.
deviceContext->VSSetConstantBuffers(bufferNumber,1,&m_matrixBuffer);
//Setshadertextureresourceinthepixelshader.
deviceContext->PSSetShaderResources(0,1,&depthMapTexture);
//Lockthesecondlightconstantbuffersoitcanbewrittento.
result=deviceContext->Map(m_lightBuffer2,0,D3D11_MAP_WRITE_DISCARD,0,&mappedResource);
if(FAILED(result))
{
returnfalse;
}
//Getapointertothedataintheconstantbuffer.
dataPtr3=(LightBufferType2*)mappedResource.pData;
//Copythelightingvariablesintotheconstantbuffer.
dataPtr3->lightPosition=lightPosition;
dataPtr3->padding=0.0f;
//Unlocktheconstantbuffer.
deviceContext->Unmap(m_lightBuffer2,0);
//Setthepositionofthelightconstantbufferinthevertexshader.
bufferNumber=1;
//Finallysetthelightconstantbufferinthepixelshaderwiththeupdatedvalues.
deviceContext->VSSetConstantBuffers(bufferNumber,1,&m_lightBuffer2);
returntrue;
}
voidShadowShaderClass::RenderShader(ID3D11DeviceContext*deviceContext,intindexCount)
{
//Setthevertexinputlayout.
deviceContext->IASetInputLayout(m_layout);
//Setthevertexandpixelshadersthatwillbeusedtorenderthistriangle.
deviceContext->VSSetShader(m_vertexShader,NULL,0);
deviceContext->PSSetShader(m_pixelShader,NULL,0);
//Setthesamplerstatesinthepixelshader.
deviceContext->PSSetSamplers(0,1,&m_sampleStateClamp);
//Renderthetriangle.
deviceContext->DrawIndexed(indexCount,0,0);
return;
}
Softshadow.vs
Thesoftshadowshadersarewherewelightthesceneasnormalbutthenprojecttheblurredblackandwhiteshadow
textureontothescenetocompletethesoftshadoweffect.
////////////////////////////////////////////////////////////////////////////////
//Filename:softshadow.vs
////////////////////////////////////////////////////////////////////////////////
/////////////
//GLOBALS//
/////////////
cbufferMatrixBuffer
{
matrixworldMatrix;
matrixviewMatrix;
matrixprojectionMatrix;
};
//////////////////////
//CONSTANTBUFFERS//
//////////////////////
cbufferLightBuffer2
{
float3lightPosition;
floatpadding;
};
//////////////
//TYPEDEFS//
//////////////
structVertexInputType
{
float4position:POSITION;
float2tex:TEXCOORD0;
float3normal:NORMAL;
};
structPixelInputType
{
float4position:SV_POSITION;
float2tex:TEXCOORD0;
float3normal:NORMAL;
float4viewPosition:TEXCOORD1;
float3lightPos:TEXCOORD2;
};
////////////////////////////////////////////////////////////////////////////////
//VertexShader
////////////////////////////////////////////////////////////////////////////////
PixelInputTypeSoftShadowVertexShader(VertexInputTypeinput)
{
PixelInputTypeoutput;
float4worldPosition;
//Changethepositionvectortobe4unitsforpropermatrixcalculations.
input.position.w=1.0f;
//Calculatethepositionofthevertexagainsttheworld,view,andprojectionmatrices.
output.position=mul(input.position,worldMatrix);
output.position=mul(output.position,viewMatrix);
output.position=mul(output.position,projectionMatrix);
TheviewPositionwillbeusedtocalculatetheprojectioncoordinatestoprojectthesoftshadowsontothescene.
//Storethepositionoftheverticeasviewedbythecamerainaseparatevariable.
output.viewPosition=output.position;
//Storethetexturecoordinatesforthepixelshader.
output.tex=input.tex;
//Calculatethenormalvectoragainsttheworldmatrixonly.
output.normal=mul(input.normal,(float3x3)worldMatrix);
//Normalizethenormalvector.
output.normal=normalize(output.normal);
//Calculatethepositionofthevertexintheworld.
worldPosition=mul(input.position,worldMatrix);
//Determinethelightpositionbasedonthepositionofthelightandthepositionofthevertexintheworld.
output.lightPos=lightPosition.xyz-worldPosition.xyz;
//Normalizethelightpositionvector.
output.lightPos=normalize(output.lightPos);
returnoutput;
}
Softshadow.ps
////////////////////////////////////////////////////////////////////////////////
//Filename:softshadow.ps
////////////////////////////////////////////////////////////////////////////////
//////////////
//TEXTURES//
//////////////
Texture2DshaderTexture:register(t0);
TheshadowTextureistheblackandwhiteblurredimagethatcontainsthesoftshadows.Wewillprojectthistextureontothescene.
Texture2DshadowTexture:register(t1);
///////////////////
//SAMPLESTATES//
///////////////////
SamplerStateSampleTypeClamp:register(s0);
SamplerStateSampleTypeWrap:register(s1);
//////////////////////
//CONSTANTBUFFERS//
//////////////////////
cbufferLightBuffer
{
float4ambientColor;
float4diffuseColor;
};
//////////////
//TYPEDEFS//
//////////////
structPixelInputType
{
float4position:SV_POSITION;
float2tex:TEXCOORD0;
float3normal:NORMAL;
float4viewPosition:TEXCOORD1;
float3lightPos:TEXCOORD2;
};
////////////////////////////////////////////////////////////////////////////////
//PixelShader
////////////////////////////////////////////////////////////////////////////////
float4SoftShadowPixelShader(PixelInputTypeinput):SV_TARGET
{
float4color;
floatlightIntensity;
float4textureColor;
float2projectTexCoord;
floatshadowValue;
Calculatethelightingandtexturingasnormal.
//Setthedefaultoutputcolortotheambientlightvalueforallpixels.
color=ambientColor;
//Calculatetheamountoflightonthispixel.
lightIntensity=saturate(dot(input.normal,input.lightPos));
if(lightIntensity>0.0f)
{
//Determinethelightcolorbasedonthediffusecolorandtheamountoflightintensity.
color+=(diffuseColor*lightIntensity);
//Saturatethelightcolor.
color=saturate(color);
}
//Samplethepixelcolorfromthetextureusingthesampleratthistexturecoordinatelocation.
textureColor=shaderTexture.Sample(SampleTypeWrap,input.tex);
//Combinethelightandtexturecolor.
color=color*textureColor;
Nowcalculatetheprojectedcoordinatestosampletheblurredblackandwhiteimagefrombasedonthecamera'sviewpoint.
//Calculatetheprojectedtexturecoordinatestobeusedwiththeshadowtexture.
projectTexCoord.x=input.viewPosition.x/input.viewPosition.w/2.0f+0.5f;
projectTexCoord.y=-input.viewPosition.y/input.viewPosition.w/2.0f+0.5f;
Samplethesoftshadowimageusingtheprojectedcoordinatesandthenmultipleitinthesamefashionasalightmaptothefinalcolortogetthesoftshadoweffect.
//Sampletheshadowvaluefromtheshadowtextureusingthesamplerattheprojectedtexturecoordinatelocation.
shadowValue=shadowTexture.Sample(SampleTypeClamp,projectTexCoord).r;
//Combinetheshadowswiththefinalcolor.
color=color*shadowValue;
returncolor;
}
Softshadowshaderclass.h
TheSoftShadowShaderClassisthesameastheLightShaderClassexceptthatwealsoprovideablurredblackand
whitesoftshadowtextureasinputtotheRenderfunction.
////////////////////////////////////////////////////////////////////////////////
//Filename:softshadowshaderclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef_SOFTSHADOWSHADERCLASS_H_
#define_SOFTSHADOWSHADERCLASS_H_
//////////////
//INCLUDES//
//////////////
#include
#include
#include
#include
usingnamespacestd;
////////////////////////////////////////////////////////////////////////////////
//Classname:SoftShadowShaderClass
////////////////////////////////////////////////////////////////////////////////
classSoftShadowShaderClass
{
private:
structMatrixBufferType
{
D3DXMATRIXworld;
D3DXMATRIXview;
D3DXMATRIXprojection;
};
structLightBufferType
{
D3DXVECTOR4ambientColor;
D3DXVECTOR4diffuseColor;
};
structLightBufferType2
{
D3DXVECTOR3lightPosition;
floatpadding;
};
public:
SoftShadowShaderClass();
SoftShadowShaderClass(constSoftShadowShaderClass&);
~SoftShadowShaderClass();
boolInitialize(ID3D11Device*,HWND);
voidShutdown();
boolRender(ID3D11DeviceContext*,int,D3DXMATRIX,D3DXMATRIX,D3DXMATRIX,ID3D11ShaderResourceView*,ID3D11ShaderResourceView*,D3DXVECTOR3,
D3DXVECTOR4,D3DXVECTOR4);
private:
boolInitializeShader(ID3D11Device*,HWND,WCHAR*,WCHAR*);
voidShutdownShader();
voidOutputShaderErrorMessage(ID3D10Blob*,HWND,WCHAR*);
boolSetShaderParameters(ID3D11DeviceContext*,D3DXMATRIX,D3DXMATRIX,D3DXMATRIX,ID3D11ShaderResourceView*,ID3D11ShaderResourceView*,D3DXVECTOR3,
D3DXVECTOR4,D3DXVECTOR4);
voidRenderShader(ID3D11DeviceContext*,int);
private:
ID3D11VertexShader*m_vertexShader;
ID3D11PixelShader*m_pixelShader;
ID3D11InputLayout*m_layout;
ID3D11SamplerState*m_sampleStateWrap;
ID3D11SamplerState*m_sampleStateClamp;
ID3D11Buffer*m_matrixBuffer;
ID3D11Buffer*m_lightBuffer;
ID3D11Buffer*m_lightBuffer2;
};
#endif
Softshadowshaderclass.cpp
////////////////////////////////////////////////////////////////////////////////
//Filename:softshadowshaderclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include"softshadowshaderclass.h"
SoftShadowShaderClass::SoftShadowShaderClass()
{
m_vertexShader=0;
m_pixelShader=0;
m_layout=0;
m_sampleStateWrap=0;
m_sampleStateClamp=0;
m_matrixBuffer=0;
m_lightBuffer=0;
m_lightBuffer2=0;
}
SoftShadowShaderClass::SoftShadowShaderClass(constSoftShadowShaderClass&other)
{
}
SoftShadowShaderClass::~SoftShadowShaderClass()
{
}
boolSoftShadowShaderClass::Initialize(ID3D11Device*device,HWNDhwnd)
{
boolresult;
LoadthesoftshadowHLSLprograms.
//Initializethevertexandpixelshaders.
result=InitializeShader(device,hwnd,L"../Engine/softshadow.vs",L"../Engine/softshadow.ps");
if(!result)
{
returnfalse;
}
returntrue;
}
voidSoftShadowShaderClass::Shutdown()
{
//Shutdownthevertexandpixelshadersaswellastherelatedobjects.
ShutdownShader();
return;
}
boolSoftShadowShaderClass::Render(ID3D11DeviceContext*deviceContext,intindexCount,D3DXMATRIXworldMatrix,D3DXMATRIXviewMatrix,
D3DXMATRIXprojectionMatrix,ID3D11ShaderResourceView*texture,ID3D11ShaderResourceView*shadowTexture,
D3DXVECTOR3lightPosition,D3DXVECTOR4ambientColor,D3DXVECTOR4diffuseColor)
{
boolresult;
//Settheshaderparametersthatitwilluseforrendering.
result=SetShaderParameters(deviceContext,worldMatrix,viewMatrix,projectionMatrix,texture,shadowTexture,lightPosition,ambientColor,
diffuseColor);
if(!result)
{
returnfalse;
}
//Nowrenderthepreparedbufferswiththeshader.
RenderShader(deviceContext,indexCount);
returntrue;
}
boolSoftShadowShaderClass::InitializeShader(ID3D11Device*device,HWNDhwnd,WCHAR*vsFilename,WCHAR*psFilename)
{
HRESULTresult;
ID3D10Blob*errorMessage;
ID3D10Blob*vertexShaderBuffer;
ID3D10Blob*pixelShaderBuffer;
D3D11_INPUT_ELEMENT_DESCpolygonLayout[3];
unsignedintnumElements;
D3D11_SAMPLER_DESCsamplerDesc;
D3D11_BUFFER_DESCmatrixBufferDesc;
D3D11_BUFFER_DESClightBufferDesc;
D3D11_BUFFER_DESClightBufferDesc2;
//Initializethepointersthisfunctionwillusetonull.
errorMessage=0;
vertexShaderBuffer=0;
pixelShaderBuffer=0;
CompileandloadthesoftshadowHLSLprograms.
//Compilethevertexshadercode.
result=D3DX11CompileFromFile(vsFilename,NULL,NULL,"SoftShadowVertexShader","vs_5_0",D3D10_SHADER_ENABLE_STRICTNESS,0,NULL,
&vertexShaderBuffer,&errorMessage,NULL);
if(FAILED(result))
{
//Iftheshaderfailedtocompileitshouldhavewritensomethingtotheerrormessage.
if(errorMessage)
{
OutputShaderErrorMessage(errorMessage,hwnd,vsFilename);
}
//Iftherewasnothingintheerrormessagethenitsimplycouldnotfindtheshaderfileitself.
else
{
MessageBox(hwnd,vsFilename,L"MissingShaderFile",MB_OK);
}
returnfalse;
}
//Compilethepixelshadercode.
result=D3DX11CompileFromFile(psFilename,NULL,NULL,"SoftShadowPixelShader","ps_5_0",D3D10_SHADER_ENABLE_STRICTNESS,0,NULL,
&pixelShaderBuffer,&errorMessage,NULL);
if(FAILED(result))
{
//Iftheshaderfailedtocompileitshouldhavewritensomethingtotheerrormessage.
if(errorMessage)
{
OutputShaderErrorMessage(errorMessage,hwnd,psFilename);
}
//Iftherewasnothingintheerrormessagethenitsimplycouldnotfindthefileitself.
else
{
MessageBox(hwnd,psFilename,L"MissingShaderFile",MB_OK);
}
returnfalse;
}
//Createthevertexshaderfromthebuffer.
result=device->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(),vertexShaderBuffer->GetBufferSize(),NULL,&m_vertexShader);
if(FAILED(result))
{
returnfalse;
}
//Createthepixelshaderfromthebuffer.
result=device->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(),pixelShaderBuffer->GetBufferSize(),NULL,&m_pixelShader);
if(FAILED(result))
{
returnfalse;
}
//Createthevertexinputlayoutdescription.
polygonLayout[0].SemanticName="POSITION";
polygonLayout[0].SemanticIndex=0;
polygonLayout[0].Format=DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[0].InputSlot=0;
polygonLayout[0].AlignedByteOffset=0;
polygonLayout[0].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[0].InstanceDataStepRate=0;
polygonLayout[1].SemanticName="TEXCOORD";
polygonLayout[1].SemanticIndex=0;
polygonLayout[1].Format=DXGI_FORMAT_R32G32_FLOAT;
polygonLayout[1].InputSlot=0;
polygonLayout[1].AlignedByteOffset=D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[1].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[1].InstanceDataStepRate=0;
polygonLayout[2].SemanticName="NORMAL";
polygonLayout[2].SemanticIndex=0;
polygonLayout[2].Format=DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[2].InputSlot=0;
polygonLayout[2].AlignedByteOffset=D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[2].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[2].InstanceDataStepRate=0;
//Getacountoftheelementsinthelayout.
numElements=sizeof(polygonLayout)/sizeof(polygonLayout[0]);
//Createthevertexinputlayout.
result=device->CreateInputLayout(polygonLayout,numElements,vertexShaderBuffer->GetBufferPointer(),vertexShaderBuffer->GetBufferSize(),
&m_layout);
if(FAILED(result))
{
returnfalse;
}
//Releasethevertexshaderbufferandpixelshaderbuffersincetheyarenolongerneeded.
vertexShaderBuffer->Release();
vertexShaderBuffer=0;
pixelShaderBuffer->Release();
pixelShaderBuffer=0;
//Createawraptexturesamplerstatedescription.
samplerDesc.Filter=D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU=D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV=D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW=D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.MipLODBias=0.0f;
samplerDesc.MaxAnisotropy=1;
samplerDesc.ComparisonFunc=D3D11_COMPARISON_ALWAYS;
samplerDesc.BorderColor[0]=0;
samplerDesc.BorderColor[1]=0;
samplerDesc.BorderColor[2]=0;
samplerDesc.BorderColor[3]=0;
samplerDesc.MinLOD=0;
samplerDesc.MaxLOD=D3D11_FLOAT32_MAX;
//Createthetexturesamplerstate.
result=device->CreateSamplerState(&samplerDesc,&m_sampleStateWrap);
if(FAILED(result))
{
returnfalse;
}
//Createaclamptexturesamplerstatedescription.
samplerDesc.AddressU=D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV=D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW=D3D11_TEXTURE_ADDRESS_CLAMP;
//Createthetexturesamplerstate.
result=device->CreateSamplerState(&samplerDesc,&m_sampleStateClamp);
if(FAILED(result))
{
returnfalse;
}
//Setupthedescriptionofthedynamicmatrixconstantbufferthatisinthevertexshader.
matrixBufferDesc.Usage=D3D11_USAGE_DYNAMIC;
matrixBufferDesc.ByteWidth=sizeof(MatrixBufferType);
matrixBufferDesc.BindFlags=D3D11_BIND_CONSTANT_BUFFER;
matrixBufferDesc.CPUAccessFlags=D3D11_CPU_ACCESS_WRITE;
matrixBufferDesc.MiscFlags=0;
matrixBufferDesc.StructureByteStride=0;
//Createtheconstantbufferpointersowecanaccessthevertexshaderconstantbufferfromwithinthisclass.
result=device->CreateBuffer(&matrixBufferDesc,NULL,&m_matrixBuffer);
if(FAILED(result))
{
returnfalse;
}
//Setupthedescriptionofthelightdynamicconstantbufferthatisinthepixelshader.
lightBufferDesc.Usage=D3D11_USAGE_DYNAMIC;
lightBufferDesc.ByteWidth=sizeof(LightBufferType);
lightBufferDesc.BindFlags=D3D11_BIND_CONSTANT_BUFFER;
lightBufferDesc.CPUAccessFlags=D3D11_CPU_ACCESS_WRITE;
lightBufferDesc.MiscFlags=0;
lightBufferDesc.StructureByteStride=0;
//Createtheconstantbufferpointersowecanaccessthepixelshaderconstantbufferfromwithinthisclass.
result=device->CreateBuffer(&lightBufferDesc,NULL,&m_lightBuffer);
if(FAILED(result))
{
returnfalse;
}
//Setupthedescriptionofthelightdynamicconstantbufferthatisinthevertexshader.
lightBufferDesc2.Usage=D3D11_USAGE_DYNAMIC;
lightBufferDesc2.ByteWidth=sizeof(LightBufferType2);
lightBufferDesc2.BindFlags=D3D11_BIND_CONSTANT_BUFFER;
lightBufferDesc2.CPUAccessFlags=D3D11_CPU_ACCESS_WRITE;
lightBufferDesc2.MiscFlags=0;
lightBufferDesc2.StructureByteStride=0;
//Createtheconstantbufferpointersowecanaccessthevertexshaderconstantbufferfromwithinthisclass.
result=device->CreateBuffer(&lightBufferDesc2,NULL,&m_lightBuffer2);
if(FAILED(result))
{
returnfalse;
}
returntrue;
}
voidSoftShadowShaderClass::ShutdownShader()
{
//Releasethelightconstantbuffers.
if(m_lightBuffer)
{
m_lightBuffer->Release();
m_lightBuffer=0;
}
if(m_lightBuffer2)
{
m_lightBuffer2->Release();
m_lightBuffer2=0;
}
//Releasethematrixconstantbuffer.
if(m_matrixBuffer)
{
m_matrixBuffer->Release();
m_matrixBuffer=0;
}
//Releasethesamplerstates.
if(m_sampleStateWrap)
{
m_sampleStateWrap->Release();
m_sampleStateWrap=0;
}
if(m_sampleStateClamp)
{
m_sampleStateClamp->Release();
m_sampleStateClamp=0;
}
//Releasethelayout.
if(m_layout)
{
m_layout->Release();
m_layout=0;
}
//Releasethepixelshader.
if(m_pixelShader)
{
m_pixelShader->Release();
m_pixelShader=0;
}
//Releasethevertexshader.
if(m_vertexShader)
{
m_vertexShader->Release();
m_vertexShader=0;
}
return;
}
voidSoftShadowShaderClass::OutputShaderErrorMessage(ID3D10Blob*errorMessage,HWNDhwnd,WCHAR*shaderFilename)
{
char*compileErrors;
unsignedlongbufferSize,i;
ofstreamfout;
//Getapointertotheerrormessagetextbuffer.
compileErrors=(char*)(errorMessage->GetBufferPointer());
//Getthelengthofthemessage.
bufferSize=errorMessage->GetBufferSize();
//Openafiletowritetheerrormessageto.
fout.open("shader-error.txt");
//Writeouttheerrormessage.
for(i=0;iRelease();
errorMessage=0;
//Popamessageuponthescreentonotifytheusertocheckthetextfileforcompileerrors.
MessageBox(hwnd,L"Errorcompilingshader.Checkshader-error.txtformessage.",shaderFilename,MB_OK);
return;
}
boolSoftShadowShaderClass::SetShaderParameters(ID3D11DeviceContext*deviceContext,D3DXMATRIXworldMatrix,D3DXMATRIXviewMatrix,
D3DXMATRIXprojectionMatrix,ID3D11ShaderResourceView*texture,ID3D11ShaderResourceView*shadowTexture,
D3DXVECTOR3lightPosition,D3DXVECTOR4ambientColor,D3DXVECTOR4diffuseColor)
{
HRESULTresult;
D3D11_MAPPED_SUBRESOURCEmappedResource;
unsignedintbufferNumber;
MatrixBufferType*dataPtr;
LightBufferType*dataPtr2;
LightBufferType2*dataPtr3;
//Transposethematricestopreparethemfortheshader.
D3DXMatrixTranspose(&worldMatrix,&worldMatrix);
D3DXMatrixTranspose(&viewMatrix,&viewMatrix);
D3DXMatrixTranspose(&projectionMatrix,&projectionMatrix);
//Locktheconstantbuffersoitcanbewrittento.
result=deviceContext->Map(m_matrixBuffer,0,D3D11_MAP_WRITE_DISCARD,0,&mappedResource);
if(FAILED(result))
{
returnfalse;
}
//Getapointertothedataintheconstantbuffer.
dataPtr=(MatrixBufferType*)mappedResource.pData;
//Copythematricesintotheconstantbuffer.
dataPtr->world=worldMatrix;
dataPtr->view=viewMatrix;
dataPtr->projection=projectionMatrix;
//Unlocktheconstantbuffer.
deviceContext->Unmap(m_matrixBuffer,0);
//Setthepositionoftheconstantbufferinthevertexshader.
bufferNumber=0;
//Nowsettheconstantbufferinthevertexshaderwiththeupdatedvalues.
deviceContext->VSSetConstantBuffers(bufferNumber,1,&m_matrixBuffer);
//Setshadertextureresourceinthepixelshader.
deviceContext->PSSetShaderResources(0,1,&texture);
Bindtheblurredblackandwhitesoftshadowtexturehere.
deviceContext->PSSetShaderResources(1,1,&shadowTexture);
//Lockthelightconstantbuffersoitcanbewrittento.
result=deviceContext->Map(m_lightBuffer,0,D3D11_MAP_WRITE_DISCARD,0,&mappedResource);
if(FAILED(result))
{
returnfalse;
}
//Getapointertothedataintheconstantbuffer.
dataPtr2=(LightBufferType*)mappedResource.pData;
//Copythelightingvariablesintotheconstantbuffer.
dataPtr2->ambientColor=ambientColor;
dataPtr2->diffuseColor=diffuseColor;
//Unlocktheconstantbuffer.
deviceContext->Unmap(m_lightBuffer,0);
//Setthepositionofthelightconstantbufferinthepixelshader.
bufferNumber=0;
//Finallysetthelightconstantbufferinthepixelshaderwiththeupdatedvalues.
deviceContext->PSSetConstantBuffers(bufferNumber,1,&m_lightBuffer);
//Lockthesecondlightconstantbuffersoitcanbewrittento.
result=deviceContext->Map(m_lightBuffer2,0,D3D11_MAP_WRITE_DISCARD,0,&mappedResource);
if(FAILED(result))
{
returnfalse;
}
//Getapointertothedataintheconstantbuffer.
dataPtr3=(LightBufferType2*)mappedResource.pData;
//Copythelightingvariablesintotheconstantbuffer.
dataPtr3->lightPosition=lightPosition;
dataPtr3->padding=0.0f;
//Unlocktheconstantbuffer.
deviceContext->Unmap(m_lightBuffer2,0);
//Setthepositionofthelightconstantbufferinthevertexshader.
bufferNumber=1;
//Finallysetthelightconstantbufferinthepixelshaderwiththeupdatedvalues.
deviceContext->VSSetConstantBuffers(bufferNumber,1,&m_lightBuffer2);
returntrue;
}
voidSoftShadowShaderClass::RenderShader(ID3D11DeviceContext*deviceContext,intindexCount)
{
//Setthevertexinputlayout.
deviceContext->IASetInputLayout(m_layout);
//Setthevertexandpixelshadersthatwillbeusedtorenderthistriangle.
deviceContext->VSSetShader(m_vertexShader,NULL,0);
deviceContext->PSSetShader(m_pixelShader,NULL,0);
//Setthesamplerstatesinthepixelshader.
deviceContext->PSSetSamplers(0,1,&m_sampleStateClamp);
deviceContext->PSSetSamplers(1,1,&m_sampleStateWrap);
//Renderthetriangle.
deviceContext->DrawIndexed(indexCount,0,0);
return;
}
Graphicsclass.h
TheGraphicsClasswillrequireanumberofobjectssinceweareperformingablurandseparatingthealgorithmintoindividualstepsforclaritypurposes.
Thisisnotthemostefficientwaytoperformsoftshadowingbutforthepurposesofthetutorialitmakesiteasiertodebugandlearnthedifferentstepsinvolved.
Youcanalsorefertotutorial36asthisisprettymuchacopyofthattutorialwithshadowingadded.
////////////////////////////////////////////////////////////////////////////////
//Filename:graphicsclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef_GRAPHICSCLASS_H_
#define_GRAPHICSCLASS_H_
///////////////////////
//MYCLASSINCLUDES//
///////////////////////
#include"d3dclass.h"
#include"cameraclass.h"
#include"modelclass.h"
#include"lightclass.h"
#include"rendertextureclass.h"
#include"depthshaderclass.h"
#include"shadowshaderclass.h"
Addthenewheadersrequiredforblurringandsoftshadowing.
#include"orthowindowclass.h"
#include"textureshaderclass.h"
#include"horizontalblurshaderclass.h"
#include"verticalblurshaderclass.h"
#include"softshadowshaderclass.h"
/////////////
//GLOBALS//
/////////////
constboolFULL_SCREEN=true;
constboolVSYNC_ENABLED=true;
constfloatSCREEN_DEPTH=100.0f;
constfloatSCREEN_NEAR=1.0f;
constintSHADOWMAP_WIDTH=1024;
constintSHADOWMAP_HEIGHT=1024;
////////////////////////////////////////////////////////////////////////////////
//Classname:GraphicsClass
////////////////////////////////////////////////////////////////////////////////
classGraphicsClass
{
public:
GraphicsClass();
GraphicsClass(constGraphicsClass&);
~GraphicsClass();
boolInitialize(int,int,HWND);
voidShutdown();
boolFrame(float,float,float,float,float,float);
private:
boolRenderSceneToTexture();
boolRenderBlackAndWhiteShadows();
boolDownSampleTexture();
boolRenderHorizontalBlurToTexture();
boolRenderVerticalBlurToTexture();
boolUpSampleTexture();
boolRender();
private:
D3DClass*m_D3D;
CameraClass*m_Camera;
ModelClass*m_CubeModel,*m_GroundModel,*m_SphereModel;
LightClass*m_Light;
RenderTextureClass*m_RenderTexture,*m_BlackWhiteRenderTexture,*m_DownSampleTexure;
RenderTextureClass*m_HorizontalBlurTexture,*m_VerticalBlurTexture,*m_UpSampleTexure;
DepthShaderClass*m_DepthShader;
ShadowShaderClass*m_ShadowShader;
OrthoWindowClass*m_SmallWindow,*m_FullScreenWindow;
TextureShaderClass*m_TextureShader;
HorizontalBlurShaderClass*m_HorizontalBlurShader;
VerticalBlurShaderClass*m_VerticalBlurShader;
SoftShadowShaderClass*m_SoftShadowShader;
};
#endif
Graphicsclass.cpp
////////////////////////////////////////////////////////////////////////////////
//Filename:graphicsclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include"graphicsclass.h"
GraphicsClass::GraphicsClass()
{
m_D3D=0;
m_Camera=0;
m_CubeModel=0;
m_GroundModel=0;
m_SphereModel=0;
m_Light=0;
m_RenderTexture=0;
m_DepthShader=0;
m_BlackWhiteRenderTexture=0;
m_ShadowShader=0;
m_DownSampleTexure=0;
m_SmallWindow=0;
m_TextureShader=0;
m_HorizontalBlurTexture=0;
m_HorizontalBlurShader=0;
m_VerticalBlurTexture=0;
m_VerticalBlurShader=0;
m_UpSampleTexure=0;
m_FullScreenWindow=0;
m_SoftShadowShader=0;
}
GraphicsClass::GraphicsClass(constGraphicsClass&other)
{
}
GraphicsClass::~GraphicsClass()
{
}
boolGraphicsClass::Initialize(intscreenWidth,intscreenHeight,HWNDhwnd)
{
boolresult;
intdownSampleWidth,downSampleHeight;
//CreatetheDirect3Dobject.
m_D3D=newD3DClass;
if(!m_D3D)
{
returnfalse;
}
//InitializetheDirect3Dobject.
result=m_D3D->Initialize(screenWidth,screenHeight,VSYNC_ENABLED,hwnd,FULL_SCREEN,SCREEN_DEPTH,SCREEN_NEAR);
if(!result)
{
MessageBox(hwnd,L"CouldnotinitializeDirect3D.",L"Error",MB_OK);
returnfalse;
}
//Createthecameraobject.
m_Camera=newCameraClass;
if(!m_Camera)
{
returnfalse;
}
//Settheinitialpositionofthecamera.
m_Camera->SetPosition(0.0f,0.0f,-10.0f);
m_Camera->RenderBaseViewMatrix();
//Createthecubemodelobject.
m_CubeModel=newModelClass;
if(!m_CubeModel)
{
returnfalse;
}
//Initializethecubemodelobject.
result=m_CubeModel->Initialize(m_D3D->GetDevice(),"../Engine/data/cube.txt",L"../Engine/data/wall01.dds");
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializethecubemodelobject.",L"Error",MB_OK);
returnfalse;
}
//Setthepositionforthecubemodel.
m_CubeModel->SetPosition(-2.0f,2.0f,0.0f);
//Createthespheremodelobject.
m_SphereModel=newModelClass;
if(!m_SphereModel)
{
returnfalse;
}
//Initializethespheremodelobject.
result=m_SphereModel->Initialize(m_D3D->GetDevice(),"../Engine/data/sphere.txt",L"../Engine/data/ice.dds");
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializethespheremodelobject.",L"Error",MB_OK);
returnfalse;
}
//Setthepositionforthespheremodel.
m_SphereModel->SetPosition(2.0f,2.0f,0.0f);
//Createthegroundmodelobject.
m_GroundModel=newModelClass;
if(!m_GroundModel)
{
returnfalse;
}
//Initializethegroundmodelobject.
result=m_GroundModel->Initialize(m_D3D->GetDevice(),"../Engine/data/plane01.txt",L"../Engine/data/metal001.dds");
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializethegroundmodelobject.",L"Error",MB_OK);
returnfalse;
}
//Setthepositionforthegroundmodel.
m_GroundModel->SetPosition(0.0f,1.0f,0.0f);
//Createthelightobject.
m_Light=newLightClass;
if(!m_Light)
{
returnfalse;
}
//Initializethelightobject.
m_Light->SetAmbientColor(0.15f,0.15f,0.15f,1.0f);
m_Light->SetDiffuseColor(1.0f,1.0f,1.0f,1.0f);
m_Light->SetLookAt(0.0f,0.0f,0.0f);
m_Light->GenerateProjectionMatrix(SCREEN_DEPTH,SCREEN_NEAR);
//Createtherendertotextureobject.
m_RenderTexture=newRenderTextureClass;
if(!m_RenderTexture)
{
returnfalse;
}
//Initializetherendertotextureobject.
result=m_RenderTexture->Initialize(m_D3D->GetDevice(),SHADOWMAP_WIDTH,SHADOWMAP_HEIGHT,SCREEN_DEPTH,SCREEN_NEAR);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializetherendertotextureobject.",L"Error",MB_OK);
returnfalse;
}
//Createthedepthshaderobject.
m_DepthShader=newDepthShaderClass;
if(!m_DepthShader)
{
returnfalse;
}
//Initializethedepthshaderobject.
result=m_DepthShader->Initialize(m_D3D->GetDevice(),hwnd);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializethedepthshaderobject.",L"Error",MB_OK);
returnfalse;
}
//Createtherendertotextureobject.
m_BlackWhiteRenderTexture=newRenderTextureClass;
if(!m_BlackWhiteRenderTexture)
{
returnfalse;
}
//Initializetheblackandwhiterendertotextureobject.
result=m_BlackWhiteRenderTexture->Initialize(m_D3D->GetDevice(),SHADOWMAP_WIDTH,SHADOWMAP_HEIGHT,SCREEN_DEPTH,SCREEN_NEAR);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializetheblackandwhiterendertotextureobject.",L"Error",MB_OK);
returnfalse;
}
//Createtheshadowshaderobject.
m_ShadowShader=newShadowShaderClass;
if(!m_ShadowShader)
{
returnfalse;
}
//Initializetheshadowshaderobject.
result=m_ShadowShader->Initialize(m_D3D->GetDevice(),hwnd);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializetheshadowshaderobject.",L"Error",MB_OK);
returnfalse;
}
//Setthesizetosampledownto.
downSampleWidth=SHADOWMAP_WIDTH/2;
downSampleHeight=SHADOWMAP_HEIGHT/2;
//Createthedownsamplerendertotextureobject.
m_DownSampleTexure=newRenderTextureClass;
if(!m_DownSampleTexure)
{
returnfalse;
}
//Initializethedownsamplerendertotextureobject.
result=m_DownSampleTexure->Initialize(m_D3D->GetDevice(),downSampleWidth,downSampleHeight,100.0f,1.0f);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializethedownsamplerendertotextureobject.",L"Error",MB_OK);
returnfalse;
}
//Createthesmallorthowindowobject.
m_SmallWindow=newOrthoWindowClass;
if(!m_SmallWindow)
{
returnfalse;
}
//Initializethesmallorthowindowobject.
result=m_SmallWindow->Initialize(m_D3D->GetDevice(),downSampleWidth,downSampleHeight);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializethesmallorthowindowobject.",L"Error",MB_OK);
returnfalse;
}
//Createthetextureshaderobject.
m_TextureShader=newTextureShaderClass;
if(!m_TextureShader)
{
returnfalse;
}
//Initializethetextureshaderobject.
result=m_TextureShader->Initialize(m_D3D->GetDevice(),hwnd);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializethetextureshaderobject.",L"Error",MB_OK);
returnfalse;
}
//Createthehorizontalblurrendertotextureobject.
m_HorizontalBlurTexture=newRenderTextureClass;
if(!m_HorizontalBlurTexture)
{
returnfalse;
}
//Initializethehorizontalblurrendertotextureobject.
result=m_HorizontalBlurTexture->Initialize(m_D3D->GetDevice(),downSampleWidth,downSampleHeight,SCREEN_DEPTH,0.1f);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializethehorizontalblurrendertotextureobject.",L"Error",MB_OK);
returnfalse;
}
//Createthehorizontalblurshaderobject.
m_HorizontalBlurShader=newHorizontalBlurShaderClass;
if(!m_HorizontalBlurShader)
{
returnfalse;
}
//Initializethehorizontalblurshaderobject.
result=m_HorizontalBlurShader->Initialize(m_D3D->GetDevice(),hwnd);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializethehorizontalblurshaderobject.",L"Error",MB_OK);
returnfalse;
}
//Createtheverticalblurrendertotextureobject.
m_VerticalBlurTexture=newRenderTextureClass;
if(!m_VerticalBlurTexture)
{
returnfalse;
}
//Initializetheverticalblurrendertotextureobject.
result=m_VerticalBlurTexture->Initialize(m_D3D->GetDevice(),downSampleWidth,downSampleHeight,SCREEN_DEPTH,0.1f);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializetheverticalblurrendertotextureobject.",L"Error",MB_OK);
returnfalse;
}
//Createtheverticalblurshaderobject.
m_VerticalBlurShader=newVerticalBlurShaderClass;
if(!m_VerticalBlurShader)
{
returnfalse;
}
//Initializetheverticalblurshaderobject.
result=m_VerticalBlurShader->Initialize(m_D3D->GetDevice(),hwnd);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializetheverticalblurshaderobject.",L"Error",MB_OK);
returnfalse;
}
//Createtheupsamplerendertotextureobject.
m_UpSampleTexure=newRenderTextureClass;
if(!m_UpSampleTexure)
{
returnfalse;
}
//Initializetheupsamplerendertotextureobject.
result=m_UpSampleTexure->Initialize(m_D3D->GetDevice(),SHADOWMAP_WIDTH,SHADOWMAP_HEIGHT,SCREEN_DEPTH,0.1f);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializetheupsamplerendertotextureobject.",L"Error",MB_OK);
returnfalse;
}
//Createthefullscreenorthowindowobject.
m_FullScreenWindow=newOrthoWindowClass;
if(!m_FullScreenWindow)
{
returnfalse;
}
//Initializethefullscreenorthowindowobject.
result=m_FullScreenWindow->Initialize(m_D3D->GetDevice(),SHADOWMAP_WIDTH,SHADOWMAP_HEIGHT);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializethefullscreenorthowindowobject.",L"Error",MB_OK);
returnfalse;
}
//Createthesoftshadowshaderobject.
m_SoftShadowShader=newSoftShadowShaderClass;
if(!m_SoftShadowShader)
{
returnfalse;
}
//Initializethesoftshadowshaderobject.
result=m_SoftShadowShader->Initialize(m_D3D->GetDevice(),hwnd);
if(!result)
{
MessageBox(hwnd,L"Couldnotinitializethesoftshadowshaderobject.",L"Error",MB_OK);
returnfalse;
}
returntrue;
}
voidGraphicsClass::Shutdown()
{
//Releasethesoftshadowshaderobject.
if(m_SoftShadowShader)
{
m_SoftShadowShader->Shutdown();
deletem_SoftShadowShader;
m_SoftShadowShader=0;
}
//Releasethefullscreenorthowindowobject.
if(m_FullScreenWindow)
{
m_FullScreenWindow->Shutdown();
deletem_FullScreenWindow;
m_FullScreenWindow=0;
}
//Releasetheupsamplerendertotextureobject.
if(m_UpSampleTexure)
{
m_UpSampleTexure->Shutdown();
deletem_UpSampleTexure;
m_UpSampleTexure=0;
}
//Releasetheverticalblurshaderobject.
if(m_VerticalBlurShader)
{
m_VerticalBlurShader->Shutdown();
deletem_VerticalBlurShader;
m_VerticalBlurShader=0;
}
//Releasetheverticalblurrendertotextureobject.
if(m_VerticalBlurTexture)
{
m_VerticalBlurTexture->Shutdown();
deletem_VerticalBlurTexture;
m_VerticalBlurTexture=0;
}
//Releasethehorizontalblurshaderobject.
if(m_HorizontalBlurShader)
{
m_HorizontalBlurShader->Shutdown();
deletem_HorizontalBlurShader;
m_HorizontalBlurShader=0;
}
//Releasethehorizontalblurrendertotextureobject.
if(m_HorizontalBlurTexture)
{
m_HorizontalBlurTexture->Shutdown();
deletem_HorizontalBlurTexture;
m_HorizontalBlurTexture=0;
}
//Releasethetextureshaderobject.
if(m_TextureShader)
{
m_TextureShader->Shutdown();
deletem_TextureShader;
m_TextureShader=0;
}
//Releasethesmallorthowindowobject.
if(m_SmallWindow)
{
m_SmallWindow->Shutdown();
deletem_SmallWindow;
m_SmallWindow=0;
}
//Releasethedownsamplerendertotextureobject.
if(m_DownSampleTexure)
{
m_DownSampleTexure->Shutdown();
deletem_DownSampleTexure;
m_DownSampleTexure=0;
}
//Releasetheshadowshaderobject.
if(m_ShadowShader)
{
m_ShadowShader->Shutdown();
deletem_ShadowShader;
m_ShadowShader=0;
}
//Releasetheblackandwhiterendertotexture.
if(m_BlackWhiteRenderTexture)
{
m_BlackWhiteRenderTexture->Shutdown();
deletem_BlackWhiteRenderTexture;
m_BlackWhiteRenderTexture=0;
}
//Releasethedepthshaderobject.
if(m_DepthShader)
{
m_DepthShader->Shutdown();
deletem_DepthShader;
m_DepthShader=0;
}
//Releasetherendertotextureobject.
if(m_RenderTexture)
{
m_RenderTexture->Shutdown();
deletem_RenderTexture;
m_RenderTexture=0;
}
//Releasethelightobject.
if(m_Light)
{
deletem_Light;
m_Light=0;
}
//Releasethegroundmodelobject.
if(m_GroundModel)
{
m_GroundModel->Shutdown();
deletem_GroundModel;
m_GroundModel=0;
}
//Releasethespheremodelobject.
if(m_SphereModel)
{
m_SphereModel->Shutdown();
deletem_SphereModel;
m_SphereModel=0;
}
//Releasethecubemodelobject.
if(m_CubeModel)
{
m_CubeModel->Shutdown();
deletem_CubeModel;
m_CubeModel=0;
}
//Releasethecameraobject.
if(m_Camera)
{
deletem_Camera;
m_Camera=0;
}
//ReleasetheD3Dobject.
if(m_D3D)
{
m_D3D->Shutdown();
deletem_D3D;
m_D3D=0;
}
return;
}
boolGraphicsClass::Frame(floatposX,floatposY,floatposZ,floatrotX,floatrotY,floatrotZ)
{
boolresult;
staticfloatlightPositionX=-5.0f;
//Setthepositionofthecamera.
m_Camera->SetPosition(posX,posY,posZ);
m_Camera->SetRotation(rotX,rotY,rotZ);
//Updatethepositionofthelighteachframe.
lightPositionX+=0.05f;
if(lightPositionX>5.0f)
{
lightPositionX=-5.0f;
}
//Updatethepositionofthelight.
m_Light->SetPosition(lightPositionX,8.0f,-5.0f);
//Renderthegraphicsscene.
result=Render();
if(!result)
{
returnfalse;
}
returntrue;
}
Thisfunctioniswherewerenderthescenetotexturetoperformthebasicshadowing.
boolGraphicsClass::RenderSceneToTexture()
{
D3DXMATRIXworldMatrix,lightViewMatrix,lightProjectionMatrix,translateMatrix;
floatposX,posY,posZ;
boolresult;
//Settherendertargettobetherendertotexture.
m_RenderTexture->SetRenderTarget(m_D3D->GetDeviceContext());
//Cleartherendertotexture.
m_RenderTexture->ClearRenderTarget(m_D3D->GetDeviceContext(),0.0f,0.0f,0.0f,1.0f);
//Generatethelightviewmatrixbasedonthelight'sposition.
m_Light->GenerateViewMatrix();
//Gettheworldmatrixfromthed3dobject.
m_D3D->GetWorldMatrix(worldMatrix);
//Gettheviewandorthographicmatricesfromthelightobject.
m_Light->GetViewMatrix(lightViewMatrix);
m_Light->GetProjectionMatrix(lightProjectionMatrix);
//Setupthetranslationmatrixforthecubemodel.
m_CubeModel->GetPosition(posX,posY,posZ);
D3DXMatrixTranslation(&worldMatrix,posX,posY,posZ);
//Renderthecubemodelwiththedepthshader.
m_CubeModel->Render(m_D3D->GetDeviceContext());
result=m_DepthShader->Render(m_D3D->GetDeviceContext(),m_CubeModel->GetIndexCount(),worldMatrix,lightViewMatrix,lightProjectionMatrix);
if(!result)
{
returnfalse;
}
//Resettheworldmatrix.
m_D3D->GetWorldMatrix(worldMatrix);
//Setupthetranslationmatrixforthespheremodel.
m_SphereModel->GetPosition(posX,posY,posZ);
D3DXMatrixTranslation(&worldMatrix,posX,posY,posZ);
//Renderthespheremodelwiththedepthshader.
m_SphereModel->Render(m_D3D->GetDeviceContext());
result=m_DepthShader->Render(m_D3D->GetDeviceContext(),m_SphereModel->GetIndexCount(),worldMatrix,lightViewMatrix,lightProjectionMatrix);
if(!result)
{
returnfalse;
}
//Resettheworldmatrix.
m_D3D->GetWorldMatrix(worldMatrix);
//Setupthetranslationmatrixforthegroundmodel.
m_GroundModel->GetPosition(posX,posY,posZ);
D3DXMatrixTranslation(&worldMatrix,posX,posY,posZ);
//Renderthegroundmodelwiththedepthshader.
m_GroundModel->Render(m_D3D->GetDeviceContext());
result=m_DepthShader->Render(m_D3D->GetDeviceContext(),m_GroundModel->GetIndexCount(),worldMatrix,lightViewMatrix,lightProjectionMatrix);
if(!result)
{
returnfalse;
}
//Resettherendertargetbacktotheoriginalbackbufferandnottherendertotextureanymore.
m_D3D->SetBackBufferRenderTarget();
//Resettheviewportbacktotheoriginal.
m_D3D->ResetViewport();
returntrue;
}
Thisnextfunctioniswherewerendertheshadowsbutasablackandwhiteonlyimagetoanotherrendertotexture.
boolGraphicsClass::RenderBlackAndWhiteShadows()
{
D3DXMATRIXworldMatrix,viewMatrix,projectionMatrix,translateMatrix;
D3DXMATRIXlightViewMatrix,lightProjectionMatrix;
floatposX,posY,posZ;
boolresult;
//Settherendertargettobetherendertotexture.
m_BlackWhiteRenderTexture->SetRenderTarget(m_D3D->GetDeviceContext());
//Cleartherendertotexture.
m_BlackWhiteRenderTexture->ClearRenderTarget(m_D3D->GetDeviceContext(),0.0f,0.0f,0.0f,1.0f);
//Generatetheviewmatrixbasedonthecamera'sposition.
m_Camera->Render();
//Generatethelightviewmatrixbasedonthelight'sposition.
m_Light->GenerateViewMatrix();
//Gettheworld,view,andprojectionmatricesfromthecameraandd3dobjects.
m_Camera->GetViewMatrix(viewMatrix);
m_D3D->GetWorldMatrix(worldMatrix);
m_D3D->GetProjectionMatrix(projectionMatrix);
//Getthelight'sviewandprojectionmatricesfromthelightobject.
m_Light->GetViewMatrix(lightViewMatrix);
m_Light->GetProjectionMatrix(lightProjectionMatrix);
//Setupthetranslationmatrixforthecubemodel.
m_CubeModel->GetPosition(posX,posY,posZ);
D3DXMatrixTranslation(&worldMatrix,posX,posY,posZ);
//Renderthecubemodelusingtheshadowshader.
m_CubeModel->Render(m_D3D->GetDeviceContext());
result=m_ShadowShader->Render(m_D3D->GetDeviceContext(),m_CubeModel->GetIndexCount(),worldMatrix,viewMatrix,projectionMatrix,lightViewMatrix,
lightProjectionMatrix,m_RenderTexture->GetShaderResourceView(),m_Light->GetPosition());
if(!result)
{
returnfalse;
}
//Resettheworldmatrix.
m_D3D->GetWorldMatrix(worldMatrix);
//Setupthetranslationmatrixforthespheremodel.
m_SphereModel->GetPosition(posX,posY,posZ);
D3DXMatrixTranslation(&worldMatrix,posX,posY,posZ);
//Renderthespheremodelusingtheshadowshader.
m_SphereModel->Render(m_D3D->GetDeviceContext());
result=m_ShadowShader->Render(m_D3D->GetDeviceContext(),m_SphereModel->GetIndexCount(),worldMatrix,viewMatrix,projectionMatrix,lightViewMatrix,
lightProjectionMatrix,m_RenderTexture->GetShaderResourceView(),m_Light->GetPosition());
if(!result)
{
returnfalse;
}
//Resettheworldmatrix.
m_D3D->GetWorldMatrix(worldMatrix);
//Setupthetranslationmatrixforthegroundmodel.
m_GroundModel->GetPosition(posX,posY,posZ);
D3DXMatrixTranslation(&worldMatrix,posX,posY,posZ);
//Renderthegroundmodelusingtheshadowshader.
m_GroundModel->Render(m_D3D->GetDeviceContext());
result=m_ShadowShader->Render(m_D3D->GetDeviceContext(),m_GroundModel->GetIndexCount(),worldMatrix,viewMatrix,projectionMatrix,lightViewMatrix,
lightProjectionMatrix,m_RenderTexture->GetShaderResourceView(),m_Light->GetPosition());
if(!result)
{
returnfalse;
}
//Resettherendertargetbacktotheoriginalbackbufferandnottherendertotextureanymore.
m_D3D->SetBackBufferRenderTarget();
//Resettheviewportbacktotheoriginal.
m_D3D->ResetViewport();
returntrue;
}
Thisfunctioniswherewedownsampletheblackandwhiteshadowimagetobegintheblurprocess.
boolGraphicsClass::DownSampleTexture()
{
D3DXMATRIXworldMatrix,baseViewMatrix,orthoMatrix;
boolresult;
//Settherendertargettobetherendertotexture.
m_DownSampleTexure->SetRenderTarget(m_D3D->GetDeviceContext());
//Cleartherendertotexture.
m_DownSampleTexure->ClearRenderTarget(m_D3D->GetDeviceContext(),0.0f,0.0f,0.0f,1.0f);
//Generatetheviewmatrixbasedonthecamera'sposition.
m_Camera->Render();
//Gettheworldandviewmatricesfromthecameraandd3dobjects.
m_D3D->GetWorldMatrix(worldMatrix);
m_Camera->GetBaseViewMatrix(baseViewMatrix);
//Gettheorthomatrixfromtherendertotexturesincetexturehasdifferentdimensionsbeingthatitissmaller.
m_DownSampleTexure->GetOrthoMatrix(orthoMatrix);
//TurnofftheZbuffertobeginall2Drendering.
m_D3D->TurnZBufferOff();
//Putthesmallorthowindowvertexandindexbuffersonthegraphicspipelinetopreparethemfordrawing.
m_SmallWindow->Render(m_D3D->GetDeviceContext());
//Renderthesmallorthowindowusingthetextureshaderandtherendertotextureofthesceneasthetextureresource.
result=m_TextureShader->Render(m_D3D->GetDeviceContext(),m_SmallWindow->GetIndexCount(),worldMatrix,baseViewMatrix,orthoMatrix,
m_BlackWhiteRenderTexture->GetShaderResourceView());
if(!result)
{
returnfalse;
}
//TurntheZbufferbackonnowthatall2Drenderinghascompleted.
m_D3D->TurnZBufferOn();
//Resettherendertargetbacktotheoriginalbackbufferandnottherendertotextureanymore.
m_D3D->SetBackBufferRenderTarget();
//Resettheviewportbacktotheoriginal.
m_D3D->ResetViewport();
returntrue;
}
Thisfunctioniswhereperformthehorizontalbluronthedownsampledblackandwhiteshadowimage.
boolGraphicsClass::RenderHorizontalBlurToTexture()
{
D3DXMATRIXworldMatrix,baseViewMatrix,orthoMatrix;
floatscreenSizeX;
boolresult;
//Storethescreenwidthinafloatthatwillbeusedinthehorizontalblurshader.
screenSizeX=(float)(SHADOWMAP_WIDTH/2);
//Settherendertargettobetherendertotexture.
m_HorizontalBlurTexture->SetRenderTarget(m_D3D->GetDeviceContext());
//Cleartherendertotexture.
m_HorizontalBlurTexture->ClearRenderTarget(m_D3D->GetDeviceContext(),0.0f,0.0f,0.0f,1.0f);
//Generatetheviewmatrixbasedonthecamera'sposition.
m_Camera->Render();
//Gettheworldandviewmatricesfromthecameraandd3dobjects.
m_Camera->GetBaseViewMatrix(baseViewMatrix);
m_D3D->GetWorldMatrix(worldMatrix);
//Gettheorthomatrixfromtherendertotexturesincetexturehasdifferentdimensions.
m_HorizontalBlurTexture->GetOrthoMatrix(orthoMatrix);
//TurnofftheZbuffertobeginall2Drendering.
m_D3D->TurnZBufferOff();
//Putthesmallorthowindowvertexandindexbuffersonthegraphicspipelinetopreparethemfordrawing.
m_SmallWindow->Render(m_D3D->GetDeviceContext());
//Renderthesmallorthowindowusingthehorizontalblurshaderandthedownsampledrendertotextureresource.
result=m_HorizontalBlurShader->Render(m_D3D->GetDeviceContext(),m_SmallWindow->GetIndexCount(),worldMatrix,baseViewMatrix,orthoMatrix,
m_DownSampleTexure->GetShaderResourceView(),screenSizeX);
if(!result)
{
returnfalse;
}
//TurntheZbufferbackonnowthatall2Drenderinghascompleted.
m_D3D->TurnZBufferOn();
//Resettherendertargetbacktotheoriginalbackbufferandnottherendertotextureanymore.
m_D3D->SetBackBufferRenderTarget();
//Resettheviewportbacktotheoriginal.
m_D3D->ResetViewport();
returntrue;
}
Thisfunctioniswhereperformtheverticalbluronthehorizontallyblurredblackandwhiteshadowimage.
boolGraphicsClass::RenderVerticalBlurToTexture()
{
D3DXMATRIXworldMatrix,baseViewMatrix,orthoMatrix;
floatscreenSizeY;
boolresult;
//Storethescreenheightinafloatthatwillbeusedintheverticalblurshader.
screenSizeY=(float)(SHADOWMAP_HEIGHT/2);
//Settherendertargettobetherendertotexture.
m_VerticalBlurTexture->SetRenderTarget(m_D3D->GetDeviceContext());
//Cleartherendertotexture.
m_VerticalBlurTexture->ClearRenderTarget(m_D3D->GetDeviceContext(),0.0f,0.0f,0.0f,1.0f);
//Generatetheviewmatrixbasedonthecamera'sposition.
m_Camera->Render();
//Gettheworldandviewmatricesfromthecameraandd3dobjects.
m_Camera->GetBaseViewMatrix(baseViewMatrix);
m_D3D->GetWorldMatrix(worldMatrix);
//Gettheorthomatrixfromtherendertotexturesincetexturehasdifferentdimensions.
m_VerticalBlurTexture->GetOrthoMatrix(orthoMatrix);
//TurnofftheZbuffertobeginall2Drendering.
m_D3D->TurnZBufferOff();
//Putthesmallorthowindowvertexandindexbuffersonthegraphicspipelinetopreparethemfordrawing.
m_SmallWindow->Render(m_D3D->GetDeviceContext());
//Renderthesmallorthowindowusingtheverticalblurshaderandthehorizontalblurredrendertotextureresource.
result=m_VerticalBlurShader->Render(m_D3D->GetDeviceContext(),m_SmallWindow->GetIndexCount(),worldMatrix,baseViewMatrix,orthoMatrix,
m_HorizontalBlurTexture->GetShaderResourceView(),screenSizeY);
if(!result)
{
returnfalse;
}
//TurntheZbufferbackonnowthatall2Drenderinghascompleted.
m_D3D->TurnZBufferOn();
//Resettherendertargetbacktotheoriginalbackbufferandnottherendertotextureanymore.
m_D3D->SetBackBufferRenderTarget();
//Resettheviewportbacktotheoriginal.
m_D3D->ResetViewport();
returntrue;
}
Andthisfunctioniswhereperformtheupsampleoftheblurredblackandwhiteshadowimage.
boolGraphicsClass::UpSampleTexture()
{
D3DXMATRIXworldMatrix,baseViewMatrix,orthoMatrix;
boolresult;
//Settherendertargettobetherendertotexture.
m_UpSampleTexure->SetRenderTarget(m_D3D->GetDeviceContext());
//Cleartherendertotexture.
m_UpSampleTexure->ClearRenderTarget(m_D3D->GetDeviceContext(),0.0f,0.0f,0.0f,1.0f);
//Generatetheviewmatrixbasedonthecamera'sposition.
m_Camera->Render();
//Gettheworldandviewmatricesfromthecameraandd3dobjects.
m_Camera->GetBaseViewMatrix(baseViewMatrix);
m_D3D->GetWorldMatrix(worldMatrix);
//Gettheorthomatrixfromtherendertotexturesincetexturehasdifferentdimensions.
m_UpSampleTexure->GetOrthoMatrix(orthoMatrix);
//TurnofftheZbuffertobeginall2Drendering.
m_D3D->TurnZBufferOff();
//Putthefullscreenorthowindowvertexandindexbuffersonthegraphicspipelinetopreparethemfordrawing.
m_FullScreenWindow->Render(m_D3D->GetDeviceContext());
//Renderthefullscreenorthowindowusingthetextureshaderandthesmallsizedfinalblurredrendertotextureresource.
result=m_TextureShader->Render(m_D3D->GetDeviceContext(),m_FullScreenWindow->GetIndexCount(),worldMatrix,baseViewMatrix,orthoMatrix,
m_VerticalBlurTexture->GetShaderResourceView());
if(!result)
{
returnfalse;
}
//TurntheZbufferbackonnowthatall2Drenderinghascompleted.
m_D3D->TurnZBufferOn();
//Resettherendertargetbacktotheoriginalbackbufferandnottherendertotextureanymore.
m_D3D->SetBackBufferRenderTarget();
//Resettheviewportbacktotheoriginal.
m_D3D->ResetViewport();
returntrue;
}
TheRenderfunctioncallsalltheabovefunctionsinthecorrectorderandthenusestheupsampledblurredimagetoperformthesoftshadowrendering.
boolGraphicsClass::Render()
{
boolresult;
D3DXMATRIXworldMatrix,viewMatrix,projectionMatrix,translateMatrix;
floatposX,posY,posZ;
//Firstrenderthescenetoatexture.
result=RenderSceneToTexture();
if(!result)
{
returnfalse;
}
//Nextrendertheshadowedsceneinblackandwhite.
result=RenderBlackAndWhiteShadows();
if(!result)
{
returnfalse;
}
//Thendownsampletheblackandwhitescenetexture.
result=DownSampleTexture();
if(!result)
{
returnfalse;
}
//Performahorizontalbluronthedownsampledtexture.
result=RenderHorizontalBlurToTexture();
if(!result)
{
returnfalse;
}
//Nowperformaverticalbluronthetexture.
result=RenderVerticalBlurToTexture();
if(!result)
{
returnfalse;
}
//Finallyupsamplethefinalblurredrendertotexturethatcannowbeusedinthesoftshadowshader.
result=UpSampleTexture();
if(!result)
{
returnfalse;
}
//Clearthebufferstobeginthescene.
m_D3D->BeginScene(0.0f,0.0f,0.0f,1.0f);
//Generatetheviewmatrixbasedonthecamera'sposition.
m_Camera->Render();
//Gettheworld,view,andprojectionmatricesfromthecameraandd3dobjects.
m_Camera->GetViewMatrix(viewMatrix);
m_D3D->GetWorldMatrix(worldMatrix);
m_D3D->GetProjectionMatrix(projectionMatrix);
//Setupthetranslationmatrixforthecubemodel.
m_CubeModel->GetPosition(posX,posY,posZ);
D3DXMatrixTranslation(&worldMatrix,posX,posY,posZ);
//Renderthecubemodelusingthesoftshadowshader.
m_CubeModel->Render(m_D3D->GetDeviceContext());
result=m_SoftShadowShader->Render(m_D3D->GetDeviceContext(),m_CubeModel->GetIndexCount(),worldMatrix,viewMatrix,projectionMatrix,
m_CubeModel->GetTexture(),m_UpSampleTexure->GetShaderResourceView(),m_Light->GetPosition(),
m_Light->GetAmbientColor(),m_Light->GetDiffuseColor());
if(!result)
{
returnfalse;
}
//Resettheworldmatrix.
m_D3D->GetWorldMatrix(worldMatrix);
//Setupthetranslationmatrixforthespheremodel.
m_SphereModel->GetPosition(posX,posY,posZ);
D3DXMatrixTranslation(&worldMatrix,posX,posY,posZ);
//Renderthespheremodelusingthesoftshadowshader.
m_SphereModel->Render(m_D3D->GetDeviceContext());
result=m_SoftShadowShader->Render(m_D3D->GetDeviceContext(),m_SphereModel->GetIndexCount(),worldMatrix,viewMatrix,projectionMatrix,
m_SphereModel->GetTexture(),m_UpSampleTexure->GetShaderResourceView(),m_Light->GetPosition(),
m_Light->GetAmbientColor(),m_Light->GetDiffuseColor());
if(!result)
{
returnfalse;
}
//Resettheworldmatrix.
m_D3D->GetWorldMatrix(worldMatrix);
//Setupthetranslationmatrixforthegroundmodel.
m_GroundModel->GetPosition(posX,posY,posZ);
D3DXMatrixTranslation(&worldMatrix,posX,posY,posZ);
//Renderthegroundmodelusingthesoftshadowshader.
m_GroundModel->Render(m_D3D->GetDeviceContext());
result=m_SoftShadowShader->Render(m_D3D->GetDeviceContext(),m_GroundModel->GetIndexCount(),worldMatrix,viewMatrix,projectionMatrix,
m_GroundModel->GetTexture(),m_UpSampleTexure->GetShaderResourceView(),m_Light->GetPosition(),
m_Light->GetAmbientColor(),m_Light->GetDiffuseColor());
if(!result)
{
returnfalse;
}
//Presenttherenderedscenetothescreen.
m_D3D->EndScene();
returntrue;
}
Summary
Theshadowsnowhavesoftedgescreatingamorerealisticshadowingeffect.
ToDoExercises
1.Compileandruntheprogram.Usethearrowkeys,A,Z,PgUp,andPgDntonavigatethroughthescene.
2.Changetheblureffecttoafasterperformingblur.Therearequiteafewoptimizedtechniquesthatcanbefoundonthenet.
SourceCode
SourceCodeandDataFiles:dx11src42.zip
Executable:dx11exe42.zip
BacktoTutorialIndex