Tutorial 4: Buffers, Shaders, and HLSL - RasterTek

文章推薦指數: 80 %
投票人數:10人

fx HLSL shader program through the technique pointer. The first step in this function is to set our input layout to active in the input assembler. This lets the ... Tutorial4:Buffers,Shaders,andHLSL ThistutorialwillbetheintroductiontowritingvertexandpixelshadersinDirectX10. ItwillalsobetheintroductiontousingvertexandindexbuffersinDirectX10. Thesearethemostfundamentalconceptsthatyouneedtounderstandandutilizetorender3Dgraphics. VertexBuffers Thefirstconcepttounderstandisvertexbuffers.Toillustratethisconceptletustaketheexampleofa3Dmodelofasphere: The3Dspheremodelisactuallycomposedofhundredsoftriangles: Eachofthetrianglesinthespheremodelhasthreepointstoit,wecalleachpointavertex. Soforustorenderthespheremodelweneedtoputalltheverticesthatformthesphereintoaspecialdataarraythatwecallavertexbuffer. OnceallthepointsofthespheremodelareinthevertexbufferwecanthensendthevertexbuffertotheGPUsothatitcanrenderthemodel. IndexBuffers Indexbuffersarerelatedtovertexbuffers.Theirpurposeistorecordthelocationofeachvertexthatisinthevertexbuffer. TheGPUthenusestheindexbuffertoquicklyfindspecificverticesinthevertexbuffer. Theconceptofanindexbufferissimilartotheconceptusinganindexinabook,ithelpsfindthetopicyouarelookingforatamuchhigherspeed. TheDirectXSDKdocumentationsaysthatusingindexbufferscanalsoincreasethepossibilityofcachingthevertexdatainfasterlocationsinvideomemory. Soitishighlyadvisedtousetheseforperformancereasonsaswell. VertexShaders Vertexshadersaresmallprogramsthatarewrittenmainlyfortransformingtheverticesfromthevertexbufferinto3Dspace. Thereareothercalculationsthatcanbedonesuchascalculatingnormalsforeachvertex. ThevertexshaderprogramwillbecalledbytheGPUforeachvertexitneedstoprocess. Forexamplea5,000polygonmodelwillrunyourvertexshaderprogram15,000timeseachframejusttodrawthatsinglemodel. Soifyoulockyourgraphicsprogramto60fpsitwillcallyourvertexshader900,000timesasecondtodrawjust5,000triangles. Asyoucantellwritingefficientvertexshadersisimportant. PixelShaders Pixelshadersaresmallprogramsthatarewrittenfordoingthecoloringofthepolygonsthatwedraw. TheyarerunbytheGPUforeveryvisiblepixelthatwillbedrawntothescreen. Coloring,texturing,lighting,andmostothereffectsyouplantodotoyourpolygonfacesarehandledbythepixelshaderprogram. PixelshadersmustbeefficientlywrittenduetothenumberoftimestheywillbecalledbytheGPU. HLSL HLSListhelanguageweuseinDirectX10tocodethesesmallvertexandpixelshaderprograms. ThesyntaxisprettymuchidenticaltotheClanguagewithsomepre-definedtypes. HLSLprogramfilesarecomposedofglobalvariables,typedefines,vertexshaders,pixelshaders,andgeometryshaders. AsthisisthefirstHLSLtutorialwewilldoaverysimpleHLSLprogramusingDirectX10togetstarted. UpdatedFramework Theframeworkhasbeenupdatedforthistutorial.UnderGraphicsClasswehaveaddedthreenewclassescalledCameraClass,ModelClass,andColorShaderClass. CameraClasswilltakecareofourviewmatrixwetalkedaboutpreviously.Itwillhandlethelocationofthecameraintheworldandpassit toshaderswhentheyneedtodrawandfigureoutwherewearelookingatthescenefrom. TheModelClasswillhandlethegeometryofour3Dmodels,inthistutorialthe3Dmodelwilljustbeasingletriangleforsimplicityreasons. AndfinallyColorShaderClasswillberesponsibleforrenderingthemodeltothescreeninvokingourHLSLshader. WewillbeginthetutorialcodebylookingattheHLSLshaderprogramfirst. Color.fx Thiswillbeourfirstshaderprogram. Shadersaresmallprogramsthatdotheactualrenderingofmodels. ThisshaderiswritteninHLSLandstoredinasourcefilecalledcolor.fx. Iplacedthefilewiththe.cppand.hfilesintheenginefornow. ThepurposeofthisshaderisjusttodrawcoloredtrianglesasIamkeepingthingssimpleaspossibleinthisfirstHLSLtutorial. Hereisthecode: //////////////////////////////////////////////////////////////////////////////// //Filename:color.fx //////////////////////////////////////////////////////////////////////////////// Globalvariablesinsidetheshaderallowustohaveexternalaccesstomodifytheinternalshadervariables. ForexamplewiththesethreematriceswewillsetthemintheGraphicsClassandthenpassthemintothisshader sotheycanbeusedbytheColorVertexShaderbelow. Youcanusemanytypesofvariablessuchasintorfloatandthensetthemexternallyfortheshaderprogramtouse. ///////////// //GLOBALS// ///////////// matrixworldMatrix; matrixviewMatrix; matrixprojectionMatrix; SimilartoCwecancreateourowntypedefinitions. Wewillusedifferenttypessuchasfloat4thatareavailabletoHLSLwhichmakeprogrammingshaderseasierandreadable. Inthisexamplewearecreatingtypesthathavex,y,z,wpositionvectorsandred,green,blue,alphacolors. ThePOSITION,COLOR,andSV_POSITIONaresemanticsthatconveytotheGPUtheuseofthevariable. Ihavetocreatetwodifferentstructuresheresincethesemanticsaredifferentforvertexandpixelshaderseventhoughthestructuresarethesameotherwise. POSITIONworksforvertexshadersandSV_POSITIONworksforpixelshaderswhileCOLORworksforboth. IfyouwantmorethanoneofthesametypethenyouhavetoaddanumbertotheendsuchasCOLOR0,COLOR1,andsoforth. ////////////// //TYPEDEFS// ////////////// structVertexInputType { float4position:POSITION; float4color:COLOR; }; structPixelInputType { float4position:SV_POSITION; float4color:COLOR; }; ThevertexshaderiscalledbytheGPUwhenitisprocessingdatafromthevertexbuffersthathavebeensenttoit. ThisfunctionwhichInamedColorVertexShaderwillbecalledforeverysinglevertexinthevertexbuffer. Theinputtothevertexshadermustmatchthedataformatinthevertexbufferaswellasthetypedefinitionintheshadersourcefilewhich inthiscaseisVertexInputType. Theoutputofthevertexshaderwillbesenttothepixelshader. InthiscasetheoutputtypeiscalledPixelInputTypewhichisdefinedaboveaswell. WiththatinmindyouseethatthevertexshadercreatesanoutputvariablethatisofthePixelInputTypetype. Itthentakesthepositionoftheinputvertexandmultipliesitbytheworld,view,andthenprojectionmatrices. Thiswillplacethevertexinthecorrectlocationforrenderingin3Dspaceaccordingtoourview. Afterthattheoutputvariabletakesacopyoftheinputcolorandthenreturnstheoutputwhichwillbeusedasinputtothepixelshader. AlsonotethatIdosettheWvalueoftheinputpositionto1.0otherwiseitisundefinedsinceweonlyreadinaXYZvectorforposition. //////////////////////////////////////////////////////////////////////////////// //VertexShader //////////////////////////////////////////////////////////////////////////////// PixelInputTypeColorVertexShader(VertexInputTypeinput) { PixelInputTypeoutput; //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); //Storetheinputcolorforthepixelshadertouse. output.color=input.color; returnoutput; } Thepixelshaderdrawseachpixelonthepolygonsthatwillberenderedtothescreen. InthispixelshaderitusesPixelInputTypeasinputandreturnsafloat4asoutputwhichrepresentsthefinalpixelcolor. Inthispixelshaderwejusttellittocolorthepixelthesameastheinputvalueofthecolor. Notethatthepixelshadergetsitsinputfromthevertexshaderoutput. //////////////////////////////////////////////////////////////////////////////// //PixelShader //////////////////////////////////////////////////////////////////////////////// float4ColorPixelShader(PixelInputTypeinput):SV_Target { returninput.color; } Thetechniqueistheactual"shader". Thisiswhatisusedtorenderourpolygonsandcallthevertexandpixelshaders,youcanconsideritasthemain()functionoftheHLSLshader. Youcansetituptodomultiplepassesandcallallsortsofdifferentpixelandvertexshaderstocreateadesiredeffect. Inthisexamplewewillonlyuseasinglepassandonlycallthevertexandpixelshaderwedefinedearlier. Wewon'tbecallingageometryshadereitherasitisn'trequiredforourpurposesrightnow. Onethingtonoteisthatwesetourvertexshadertoversion4.0byusingthevs_4_0asthefirstargumentinSetVertexShader. ThisgivesusaccesstotheDirectX10HLSLfunctionalitythatcorrespondstovertexshader4.0. Aswellwealsosetthepixelshadertoversion4.0usingps_4_0intheSetPixelShaderfunction. Youcansetthistobeoldervertexandpixelshaderversionsbutwewanttoworkwiththelatestandgreatest. //////////////////////////////////////////////////////////////////////////////// //Technique //////////////////////////////////////////////////////////////////////////////// technique10ColorTechnique { passpass0 { SetVertexShader(CompileShader(vs_4_0,ColorVertexShader())); SetPixelShader(CompileShader(ps_4_0,ColorPixelShader())); SetGeometryShader(NULL); } } Modelclass.h AsstatedpreviouslytheModelClassisresponsibleforencapsulatingthegeometryfor3Dmodels. Inthistutorialwewillmanuallysetupthedataforasinglegreentriangle. Wewillalsocreateavertexandindexbufferforthetrianglesothatitcanberendered. //////////////////////////////////////////////////////////////////////////////// //Filename:modelclass.h //////////////////////////////////////////////////////////////////////////////// #ifndef_MODELCLASS_H_ #define_MODELCLASS_H_ ////////////// //INCLUDES// ////////////// #include #include //////////////////////////////////////////////////////////////////////////////// //Classname:ModelClass //////////////////////////////////////////////////////////////////////////////// classModelClass { private: HereisthedefinitionofourvertextypethatwillbeusedwiththevertexbufferinthisModelClass. AlsotakenotethatthistypedefmustmatchthelayoutintheColorShaderClassthatwillbelookedatlaterinthetutorial. structVertexType { D3DXVECTOR3position; D3DXVECTOR4color; }; public: ModelClass(); ModelClass(constModelClass&); ~ModelClass(); Thefunctionsherehandleinitializingandshutdownofthemodel'svertexandindexbuffers. TheRenderfunctionputsthemodelgeometryonthevideocardtoprepareitfordrawingbythecolorshader. boolInitialize(ID3D10Device*); voidShutdown(); voidRender(ID3D10Device*); intGetIndexCount(); private: boolInitializeBuffers(ID3D10Device*); voidShutdownBuffers(); voidRenderBuffers(ID3D10Device*); TheprivatevariablesintheModelClassarethevertexandindexbufferaswellastwointegerstokeeptrackofthesizeofeachbuffer. NotethatallDirectX10buffersgenerallyusethegenericID3D10Buffertypeandaremoreclearlyidentifiedbyabufferdescriptionwhentheyarefirstcreated. private: ID3D10Buffer*m_vertexBuffer,*m_indexBuffer; intm_vertexCount,m_indexCount; }; #endif Modelclass.cpp //////////////////////////////////////////////////////////////////////////////// //Filename:modelclass.cpp //////////////////////////////////////////////////////////////////////////////// #include"modelclass.h" Theclassconstructorinitializesthevertexandindexbufferpointerstonull. ModelClass::ModelClass() { m_vertexBuffer=0; m_indexBuffer=0; } ModelClass::ModelClass(constModelClass&other) { } ModelClass::~ModelClass() { } TheInitializefunctionwillcalltheinitializationfunctionsforthevertexandindexbuffers. boolModelClass::Initialize(ID3D10Device*device) { boolresult; //Initializethevertexandindexbufferthatholdthegeometryforthetriangle. result=InitializeBuffers(device); if(!result) { returnfalse; } returntrue; } TheShutdownfunctionwillcalltheshutdownfunctionsforthevertexandindexbuffers. voidModelClass::Shutdown() { //Releasethevertexandindexbuffers. ShutdownBuffers(); return; } RenderiscalledfromtheGraphicsClass::Renderfunction. ThisfunctioncallsRenderBufferstoputthevertexandindexbuffersonthegraphicspipelinesothecolorshaderwillbeabletorenderthem. voidModelClass::Render(ID3D10Device*device) { //Putthevertexandindexbuffersonthegraphicspipelinetopreparethemfordrawing. RenderBuffers(device); return; } GetIndexCountreturnsthenumberofindexesinthemodel. Thecolorshaderwillneedthisinformationtodrawthismodel. intModelClass::GetIndexCount() { returnm_indexCount; } TheInitializeBuffersfunctioniswherewehandlecreatingthevertexandindexbuffers. Usuallyyouwouldreadinamodelandcreatethebuffersfromthatdatafile. Forthistutorialwewilljustsetthethreepointsinthevertexandindexbuffermanuallysinceitisonlyasingletriangle. boolModelClass::InitializeBuffers(ID3D10Device*device) { VertexType*vertices; unsignedlong*indices; D3D10_BUFFER_DESCvertexBufferDesc,indexBufferDesc; D3D10_SUBRESOURCE_DATAvertexData,indexData; HRESULTresult; Firstcreatetwotemporaryarraystoholdthevertexandindexdatathatwewilluselatertopopulatethefinalbufferswith. //Setthenumberofverticesinthevertexarray. m_vertexCount=3; //Setthenumberofindicesintheindexarray. m_indexCount=3; //Createthevertexarray. vertices=newVertexType[m_vertexCount]; if(!vertices) { returnfalse; } //Createtheindexarray. indices=newunsignedlong[m_indexCount]; if(!indices) { returnfalse; } Nowfillboththevertexandindexarraywiththethreepointsofthetriangleaswellastheindextoeachofthepoints. PleasenotethatIcreatethepointsintheclockwiseorderofdrawingthem. Ifyoudothiscounterclockwiseitwillthinkthetriangleisfacingtheoppositedirectionandnotdrawitduetobackfaceculling. AlwaysrememberthattheorderinwhichyousendyourverticestotheGPUisveryimportant! Thecolorissethereaswellsinceitispartofthevertexdescription. Isetthecolortogreen. //Loadthevertexarraywithdata. vertices[0].position=D3DXVECTOR3(-1.0f,-1.0f,0.0f);//Bottomleft. vertices[0].color=D3DXVECTOR4(0.0f,1.0f,0.0f,1.0f); vertices[1].position=D3DXVECTOR3(0.0f,1.0f,0.0f);//Topmiddle. vertices[1].color=D3DXVECTOR4(0.0f,1.0f,0.0f,1.0f); vertices[2].position=D3DXVECTOR3(1.0f,-1.0f,0.0f);//Bottomright. vertices[2].color=D3DXVECTOR4(0.0f,1.0f,0.0f,1.0f); //Loadtheindexarraywithdata. indices[0]=0;//Bottomleft. indices[1]=1;//Topmiddle. indices[2]=2;//Bottomright. Withthevertexarrayandindexarrayfilledoutwecannowusethosetocreatethevertexbufferandindexbuffer. Creatingbothbuffersisdoneinthesamefashion. Firstfilloutadescriptionofthebuffer. InthedescriptiontheByteWidth(sizeofthebuffer)andtheBindFlags(typeofbuffer)arewhatyouneedtoensurearefilledoutcorrectly. Afterthedescriptionisfilledoutyouneedtoalsofilloutasubresourcepointerwhichwillpointtoeitheryourvertexorindexarrayyoupreviouslycreated. WiththedescriptionandsubresourcepointeryoucancallCreateBufferusingtheD3Ddeviceanditwillreturnapointertoyournewbuffer. //Setupthedescriptionofthevertexbuffer. vertexBufferDesc.Usage=D3D10_USAGE_DEFAULT; vertexBufferDesc.ByteWidth=sizeof(VertexType)*m_vertexCount; vertexBufferDesc.BindFlags=D3D10_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags=0; vertexBufferDesc.MiscFlags=0; //Givethesubresourcestructureapointertothevertexdata. vertexData.pSysMem=vertices; //Nowfinallycreatethevertexbuffer. result=device->CreateBuffer(&vertexBufferDesc,&vertexData,&m_vertexBuffer); if(FAILED(result)) { returnfalse; } //Setupthedescriptionoftheindexbuffer. indexBufferDesc.Usage=D3D10_USAGE_DEFAULT; indexBufferDesc.ByteWidth=sizeof(unsignedlong)*m_indexCount; indexBufferDesc.BindFlags=D3D10_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags=0; indexBufferDesc.MiscFlags=0; //Givethesubresourcestructureapointertotheindexdata. indexData.pSysMem=indices; //Createtheindexbuffer. result=device->CreateBuffer(&indexBufferDesc,&indexData,&m_indexBuffer); if(FAILED(result)) { returnfalse; } Afterthevertexbufferandindexbufferhavebeencreatedyoucandeletethevertexandindexarraysastheyarenolonger neededsincethedatawascopiedintothebuffers. //Releasethearraysnowthatthevertexandindexbuffershavebeencreatedandloaded. delete[]vertices; vertices=0; delete[]indices; indices=0; returntrue; } TheShutdownBuffersfunctionjustreleasesthevertexbufferandindexbufferthatwerecreatedintheInitializeBuffersfunction. voidModelClass::ShutdownBuffers() { //Releasetheindexbuffer. if(m_indexBuffer) { m_indexBuffer->Release(); m_indexBuffer=0; } //Releasethevertexbuffer. if(m_vertexBuffer) { m_vertexBuffer->Release(); m_vertexBuffer=0; } return; } RenderBuffersiscalledfromtheRenderfunction. ThepurposeofthisfunctionistosetthevertexbufferandindexbufferasactiveontheinputassemblerintheGPU. OncetheGPUhasanactivevertexbufferitcanthenusetheHLSLshaderwewrotetorenderthatbuffer. Thisfunctionalsodefineshowthosebuffersshouldbedrawnsuchastriangles,lines,fans,andsoforth. InthistutorialwesetthevertexbufferandindexbufferasactiveontheinputassemblerandtelltheGPUthatthe buffersshouldbedrawnastrianglesusingtheIASetPrimitiveTopologyDirectXfunction. voidModelClass::RenderBuffers(ID3D10Device*device) { unsignedintstride; unsignedintoffset; //Setvertexbufferstrideandoffset. stride=sizeof(VertexType); offset=0; //Setthevertexbuffertoactiveintheinputassemblersoitcanberendered. device->IASetVertexBuffers(0,1,&m_vertexBuffer,&stride,&offset); //Settheindexbuffertoactiveintheinputassemblersoitcanberendered. device->IASetIndexBuffer(m_indexBuffer,DXGI_FORMAT_R32_UINT,0); //Setthetypeofprimitivethatshouldberenderedfromthisvertexbuffer,inthiscasetriangles. device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); return; } Colorshaderclass.h TheColorShaderClassiswhatwewillusetoinvokeourHLSLshaderfordrawingthe3DmodelsthatareontheGPU. //////////////////////////////////////////////////////////////////////////////// //Filename:colorshaderclass.h //////////////////////////////////////////////////////////////////////////////// #ifndef_COLORSHADERCLASS_H_ #define_COLORSHADERCLASS_H_ ////////////// //INCLUDES// ////////////// #include #include #include usingnamespacestd; //////////////////////////////////////////////////////////////////////////////// //Classname:ColorShaderClass //////////////////////////////////////////////////////////////////////////////// classColorShaderClass { public: ColorShaderClass(); ColorShaderClass(constColorShaderClass&); ~ColorShaderClass(); Thefunctionsherehandleinitializingandshutdownoftheshader. Therenderfunctionsetstheshaderparametersandthendrawsthepreparedmodelverticesusingtheshader. boolInitialize(ID3D10Device*,HWND); voidShutdown(); voidRender(ID3D10Device*,int,D3DXMATRIX,D3DXMATRIX,D3DXMATRIX); private: boolInitializeShader(ID3D10Device*,HWND,WCHAR*); voidShutdownShader(); voidOutputShaderErrorMessage(ID3D10Blob*,HWND,WCHAR*); voidSetShaderParameters(D3DXMATRIX,D3DXMATRIX,D3DXMATRIX); voidRenderShader(ID3D10Device*,int); private: ID3D10Effect*m_effect; ID3D10EffectTechnique*m_technique; ID3D10InputLayout*m_layout; ID3D10EffectMatrixVariable*m_worldMatrixPtr; ID3D10EffectMatrixVariable*m_viewMatrixPtr; ID3D10EffectMatrixVariable*m_projectionMatrixPtr; }; #endif Colorshaderclass.cpp //////////////////////////////////////////////////////////////////////////////// //Filename:colorshaderclass.cpp //////////////////////////////////////////////////////////////////////////////// #include"colorshaderclass.h" Asusualtheclassconstructorinitializesalltheprivatepointersintheclasstonull. ColorShaderClass::ColorShaderClass() { m_effect=0; m_technique=0; m_layout=0; m_worldMatrixPtr=0; m_viewMatrixPtr=0; m_projectionMatrixPtr=0; } ColorShaderClass::ColorShaderClass(constColorShaderClass&other) { } ColorShaderClass::~ColorShaderClass() { } TheInitializefunctionwillcalltheinitializationfunctionfortheshader.WepassinthenameoftheHLSLshaderfile, inthistutorialitisnamedcolor.fx. boolColorShaderClass::Initialize(ID3D10Device*device,HWNDhwnd) { boolresult; //Initializetheshaderthatwillbeusedtodrawthetriangle. result=InitializeShader(device,hwnd,L"../Engine/color.fx"); if(!result) { returnfalse; } returntrue; } TheShutdownfunctionwillcalltheshutdownoftheshader. voidColorShaderClass::Shutdown() { //Shutdowntheshadereffect. ShutdownShader(); return; } RenderwillfirstsettheparametersinsidetheshaderusingtheSetShaderParametersfunction. OncetheparametersaresetitthencallsRenderShadertodrawthegreentriangleusingtheHLSLshader. voidColorShaderClass::Render(ID3D10Device*device,intindexCount,D3DXMATRIXworldMatrix,D3DXMATRIXviewMatrix,D3DXMATRIXprojectionMatrix) { //Settheshaderparametersthatitwilluseforrendering. SetShaderParameters(worldMatrix,viewMatrix,projectionMatrix); //Nowrenderthepreparedbufferswiththeshader. RenderShader(device,indexCount); return; } NowwewillstartwithoneofthemoreimportantfunctionstothistutorialwhichiscalledInitializeShader. ThisfunctioniswhatactuallyloadstheshaderfileandmakesitusabletoDirectXandtheGPU. YouwillalsoseethesetupofthelayoutandhowthevertexbufferdataisgoingtolookonthegraphicspipelineintheGPU. ThelayoutwillneedthematchtheVertexTypeinthemodelclass.hfileaswellastheonedefinedinthecolor.fxfile. boolColorShaderClass::InitializeShader(ID3D10Device*device,HWNDhwnd,WCHAR*filename) { HRESULTresult; ID3D10Blob*errorMessage; D3D10_INPUT_ELEMENT_DESCpolygonLayout[2]; unsignedintnumElements; D3D10_PASS_DESCpassDesc; //Initializetheerrormessage. errorMessage=0; Hereiswherewecompiletheshaderprogramintoaneffect. Wegiveitthenameoftheshaderfile,theshaderversion(4.0inDirectX10),andtheeffecttocompiletheshaderinto. IfitfailscompilingtheshaderitwillputanerrormessageinsidetheerrorMessagestringwhichwesendtoanotherfunctiontowriteouttheerror. IfitstillfailsandthereisnoerrorMessagestringthenitmeansitcouldnotfindtheshaderfileinwhichcasewepopupadialogboxsayingso. //Loadtheshaderinfromthefile. result=D3DX10CreateEffectFromFile(filename,NULL,NULL,"fx_4_0",D3D10_SHADER_ENABLE_STRICTNESS,0, device,NULL,NULL,&m_effect,&errorMessage,NULL); if(FAILED(result)) { //Iftheshaderfailedtocompileitshouldhavewritensomethingtotheerrormessage. if(errorMessage) { OutputShaderErrorMessage(errorMessage,hwnd,filename); } //Iftherewasnothingintheerrormessagethenitsimplycouldnotfindtheshaderfileitself. else { MessageBox(hwnd,filename,L"MissingShaderFile",MB_OK); } returnfalse; } Oncetheshadercodehassuccessfullycompiledintoaneffectwethenusethateffecttogetthetechniqueinsidetheshader. Wewillusethetechniquetodrawwiththeshaderfromthispointforward. //Getapointertothetechniqueinsidetheshader. m_technique=m_effect->GetTechniqueByName("ColorTechnique"); if(!m_technique) { returnfalse; } Thenextstepistocreatethelayoutofthevertexdatathatwillbeprocessedbytheshader. Asthisshaderusesapositionandcolorvectorweneedtocreatebothinthelayoutspecifyingthesizeofboth. Thesemanticnameisthefirstthingtofilloutinthelayout,thisallowstheshadertodeterminetheusageofthiselementofthelayout. AswehavetwodifferentelementsweusePOSITIONforthefirstoneandCOLORforthesecond. ThenextimportantpartofthelayoutistheFormat. ForthepositionvectorweuseDXGI_FORMAT_R32G32B32_FLOATandforthecolorweuseDXGI_FORMAT_R32G32B32A32_FLOAT. ThefinalthingyouneedtopayattentiontoistheAlignedByteOffsetwhichindicateshowthedataisspacedinthebuffer. Forthislayoutwearetellingitthefirst12bytesarepositionandthenext16byteswillbecolor,AlignedByteOffsetshowswhereeachelementbegins. YoucanuseD3D10_APPEND_ALIGNED_ELEMENTinsteadofplacingyourownvaluesinAlignedByteOffsetanditwillfigureoutthespacingforyou. TheothersettingsI'vemadedefaultfornowastheyarenotneededinthistutorial. //Nowsetupthelayoutofthedatathatgoesintotheshader. //ThissetupneedstomatchtheVertexTypestuctureintheModelClassandintheshader. 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=D3D10_INPUT_PER_VERTEX_DATA; polygonLayout[0].InstanceDataStepRate=0; polygonLayout[1].SemanticName="COLOR"; polygonLayout[1].SemanticIndex=0; polygonLayout[1].Format=DXGI_FORMAT_R32G32B32A32_FLOAT; polygonLayout[1].InputSlot=0; polygonLayout[1].AlignedByteOffset=D3D10_APPEND_ALIGNED_ELEMENT; polygonLayout[1].InputSlotClass=D3D10_INPUT_PER_VERTEX_DATA; polygonLayout[1].InstanceDataStepRate=0; OncethelayoutdescriptionhasbeensetupwecangetthesizeofitandthencreatetheinputlayoutusingtheD3Ddevice. //Getacountoftheelementsinthelayout. numElements=sizeof(polygonLayout)/sizeof(polygonLayout[0]); //Getthedescriptionofthefirstpassdescribedintheshadertechnique. m_technique->GetPassByIndex(0)->GetDesc(&passDesc); //Createtheinputlayout. result=device->CreateInputLayout(polygonLayout,numElements,passDesc.pIAInputSignature,passDesc.IAInputSignatureSize, &m_layout); if(FAILED(result)) { returnfalse; } Wewillalsograbpointerstotheglobalmatricesthatareinsidetheshaderfile. ThiswaywhenwesetamatrixfromtheGraphicsClassinsidetheshadereasilybyjustusingthesepointers. //Getpointerstothethreematricesinsidetheshadersowecanupdatethemfromthisclass. m_worldMatrixPtr=m_effect->GetVariableByName("worldMatrix")->AsMatrix(); m_viewMatrixPtr=m_effect->GetVariableByName("viewMatrix")->AsMatrix(); m_projectionMatrixPtr=m_effect->GetVariableByName("projectionMatrix")->AsMatrix(); returntrue; } ShutdownShaderreleasestheinterfacesandpointersthatweresetupintheInitializeShaderfunction. voidColorShaderClass::ShutdownShader() { //Releasethepointerstothematricesinsidetheshader. m_worldMatrixPtr=0; m_viewMatrixPtr=0; m_projectionMatrixPtr=0; //Releasethepointertotheshaderlayout. if(m_layout) { m_layout->Release(); m_layout=0; } //Releasethepointertotheshadertechnique. m_technique=0; //Releasethepointertotheshader. if(m_effect) { m_effect->Release(); m_effect=0; } return; } TheOutputShaderErrorMessagewritesouterrormessagesthataregeneratingwhencompilingeithervertexshadersorpixelshaders. voidColorShaderClass::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; } TheSetShaderVariablesfunctionexiststomakesettingtheglobalvariablesintheshadereasier. ThematricesusedinthisfunctionarecreatedinsidetheGraphicsClass,afterwhichthisfunctioniscalledtosendthemfromthere intotheshaderduringtheRenderfunctioncall. voidColorShaderClass::SetShaderParameters(D3DXMATRIXworldMatrix,D3DXMATRIXviewMatrix,D3DXMATRIXprojectionMatrix) { //Settheworldmatrixvariableinsidetheshader. m_worldMatrixPtr->SetMatrix((float*)&worldMatrix); //Settheviewmatrixvariableinsidetheshader. m_viewMatrixPtr->SetMatrix((float*)&viewMatrix); //Settheprojectionmatrixvariableinsidetheshader. m_projectionMatrixPtr->SetMatrix((float*)&projectionMatrix); return; } RenderShaderisthesecondfunctioncalledfromtheColorShaderClass::Renderfunction. SetShaderParametersiscalledbeforethistoensuretheshaderparametersaresetupcorrectlybeforeinvokingtheHLSLprogram. RenderShaderwillinvokethecolor.fxHLSLshaderprogramthroughthetechniquepointer. Thefirststepinthisfunctionistosetourinputlayouttoactiveintheinputassembler. ThisletstheGPUknowtheformatofthedatainthevertexbuffer. Thesecondstepistogetthedescriptionofthetechniquefromtheshader. ThetechniqueiswhattellstheGPUwhichpixelandvertexshaderfunctionstocalltodrawthevertexbuffer. InthiscasewearegettingthedescriptionofColorTechniquefromourcolor.fxfile. OncewehavethetechniquewethenloopthrougheachpassinthetechniqueandrenderthetrianglebycallingtheDrawIndexedDirectXfunctionusingtheD3Ddevice. Notethattheshaderonlyhasasinglepasscurrently(pass0)butIhavesetuptherenderfunctiontohandlemultiplepassesforfuturetutorials. Oncethisfunctioniscalleditwillrenderthegreentriangle. voidColorShaderClass::RenderShader(ID3D10Device*device,intindexCount) { D3D10_TECHNIQUE_DESCtechniqueDesc; unsignedinti; //Settheinputlayout. device->IASetInputLayout(m_layout); //Getthedescriptionstructureofthetechniquefrominsidetheshadersoitcanbeusedforrendering. m_technique->GetDesc(&techniqueDesc); //Gothrougheachpassinthetechnique(shouldbejustonecurrently)andrenderthetriangles. for(i=0;iGetPassByIndex(i)->Apply(0); device->DrawIndexed(indexCount,0,0); } return; } Cameraclass.h WehaveexaminedhowtocodeaHLSLshader,howtosetupvertexandindexbuffers,andhowtoinvoketheHLSL shadertodrawthosebuffersusingtheColorShaderClass. Theonethingwearemissinghoweveristheviewpointtodrawthemfrom. ForthiswewillrequireacameraclasstoletDirectX10knowfromwhereandalsohowweareviewingthescene. Thecameraclasswillkeeptrackofwherethecameraisanditscurrentrotation. ItwillusethepositionandrotationinformationtogenerateaviewmatrixwhichwillbepassedintotheHLSLshaderforrendering. //////////////////////////////////////////////////////////////////////////////// //Filename:cameraclass.h //////////////////////////////////////////////////////////////////////////////// #ifndef_CAMERACLASS_H_ #define_CAMERACLASS_H_ ////////////// //INCLUDES// ////////////// #include //////////////////////////////////////////////////////////////////////////////// //Classname:CameraClass //////////////////////////////////////////////////////////////////////////////// classCameraClass { public: CameraClass(); CameraClass(constCameraClass&); ~CameraClass(); voidSetPosition(float,float,float); voidSetRotation(float,float,float); D3DXVECTOR3GetPosition(); D3DXVECTOR3GetRotation(); voidRender(); voidGetViewMatrix(D3DXMATRIX&); private: floatm_positionX,m_positionY,m_positionZ; floatm_rotationX,m_rotationY,m_rotationZ; D3DXMATRIXm_viewMatrix; }; #endif TheCameraClassheaderisquitesimplewithjustfourfunctionsthatwillbeused. TheSetPositionandSetRotationfunctionswillbeusedtosetthepositionandrotationofthecameraobject. Renderwillbeusedtocreatetheviewmatrixbasedonthepositionandrotationofthecamera. AndfinallyGetViewMatrixwillbeusedtoretrievetheviewmatrixfromthecameraobjectsothattheshaderscanuseitforrendering. Cameraclass.cpp //////////////////////////////////////////////////////////////////////////////// //Filename:cameraclass.cpp //////////////////////////////////////////////////////////////////////////////// #include"cameraclass.h" Theclassconstructorwillinitializethepositionandrotationofthecameratobeattheoriginofthescene. CameraClass::CameraClass() { m_positionX=0.0f; m_positionY=0.0f; m_positionZ=0.0f; m_rotationX=0.0f; m_rotationY=0.0f; m_rotationZ=0.0f; } CameraClass::CameraClass(constCameraClass&other) { } CameraClass::~CameraClass() { } TheSetPositionandSetRotationfunctionsareusedforsettingupthepositionandrotationofthecamera. voidCameraClass::SetPosition(floatx,floaty,floatz) { m_positionX=x; m_positionY=y; m_positionZ=z; return; } voidCameraClass::SetRotation(floatx,floaty,floatz) { m_rotationX=x; m_rotationY=y; m_rotationZ=z; return; } TheGetPositionandGetRotationfunctionsreturnthelocationandrotationofthecameratocallingfunctions. D3DXVECTOR3CameraClass::GetPosition() { returnD3DXVECTOR3(m_positionX,m_positionY,m_positionZ); } D3DXVECTOR3CameraClass::GetRotation() { returnD3DXVECTOR3(m_rotationX,m_rotationY,m_rotationZ); } TheRenderfunctionusesthepositionandrotationofthecameratobuildandupdatetheviewmatrix. Wefirstsetupourvariablesforup,position,rotation,andsoforth. Thenattheoriginofthescenewefirstrotatethecamerabasedonthex,y,andzrotationofthecamera. Onceitisproperlyrotatedwhenthentranslatethecameratothepositionin3Dspace. Withthecorrectvaluesintheposition,lookAt,andupwecanthenusetheD3DXMatrixLookAtLHfunctiontocreatetheviewmatrixtorepresent thecurrentcamerarotationandtranslation. voidCameraClass::Render() { D3DXVECTOR3up,position,lookAt; floatyaw,pitch,roll; D3DXMATRIXrotationMatrix; //Setupthevectorthatpointsupwards. up.x=0.0f; up.y=1.0f; up.z=0.0f; //Setupthepositionofthecameraintheworld. position.x=m_positionX; position.y=m_positionY; position.z=m_positionZ; //Setupwherethecameraislookingbydefault. lookAt.x=0.0f; lookAt.y=0.0f; lookAt.z=1.0f; //Settheyaw(Yaxis),pitch(Xaxis),androll(Zaxis)rotationsinradians. pitch=m_rotationX*0.0174532925f; yaw=m_rotationY*0.0174532925f; roll=m_rotationZ*0.0174532925f; //Createtherotationmatrixfromtheyaw,pitch,androllvalues. D3DXMatrixRotationYawPitchRoll(&rotationMatrix,yaw,pitch,roll); //TransformthelookAtandupvectorbytherotationmatrixsotheviewiscorrectlyrotatedattheorigin. D3DXVec3TransformCoord(&lookAt,&lookAt,&rotationMatrix); D3DXVec3TransformCoord(&up,&up,&rotationMatrix); //Translatetherotatedcamerapositiontothelocationoftheviewer. lookAt=position+lookAt; //Finallycreatetheviewmatrixfromthethreeupdatedvectors. D3DXMatrixLookAtLH(&m_viewMatrix,&position,&lookAt,&up); return; } AftertheRenderfunctionhasbeencalledtocreatetheviewmatrixwecanprovidetheupdateviewmatrixtocallingfunctionsusingthisGetViewMatrixfunction. TheviewmatrixwillbeoneofthethreemainmatricesusedintheHLSLshader. voidCameraClass::GetViewMatrix(D3DXMATRIX&viewMatrix) { viewMatrix=m_viewMatrix; return; } Graphicsclass.h GraphicsClassnowhasthethreenewclassesaddedtoit. CameraClass,ModelClass,andColorShaderClasshaveheadersaddedhereaswellasprivatemembervariables. RememberthatGraphicsClassisthemainclassthatisusedtorenderthescenebyinvokingalltheneededclassobjectsfortheproject. //////////////////////////////////////////////////////////////////////////////// //Filename:graphicsclass.h //////////////////////////////////////////////////////////////////////////////// #ifndef_GRAPHICSCLASS_H_ #define_GRAPHICSCLASS_H_ /////////////////////// //MYCLASSINCLUDES// /////////////////////// #include"d3dclass.h" #include"cameraclass.h" #include"modelclass.h" #include"colorshaderclass.h" ///////////// //GLOBALS// ///////////// constboolFULL_SCREEN=true; constboolVSYNC_ENABLED=true; constfloatSCREEN_DEPTH=1000.0f; constfloatSCREEN_NEAR=0.1f; //////////////////////////////////////////////////////////////////////////////// //Classname:GraphicsClass //////////////////////////////////////////////////////////////////////////////// classGraphicsClass { public: GraphicsClass(); GraphicsClass(constGraphicsClass&); ~GraphicsClass(); boolInitialize(int,int,HWND); voidShutdown(); boolFrame(); private: boolRender(); private: D3DClass*m_D3D; CameraClass*m_Camera; ModelClass*m_Model; ColorShaderClass*m_ColorShader; }; #endif Graphicsclass.cpp //////////////////////////////////////////////////////////////////////////////// //Filename:graphicsclass.cpp //////////////////////////////////////////////////////////////////////////////// #include"graphicsclass.h" ThefirstchangetoGraphicsClassisinitializingthecamera,model,andcolorshaderobjectsintheclassconstructortonull. GraphicsClass::GraphicsClass() { m_D3D=0; m_Camera=0; m_Model=0; m_ColorShader=0; } TheInitializefunctionhasalsobeenupdatedtocreateandinitializethethreenewobjects. boolGraphicsClass::Initialize(intscreenWidth,intscreenHeight,HWNDhwnd) { boolresult; //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); //Createthemodelobject. m_Model=newModelClass; if(!m_Model) { returnfalse; } //Initializethemodelobject. result=m_Model->Initialize(m_D3D->GetDevice()); if(!result) { MessageBox(hwnd,L"Couldnotinitializethemodelobject.",L"Error",MB_OK); returnfalse; } //Createthecolorshaderobject. m_ColorShader=newColorShaderClass; if(!m_ColorShader) { returnfalse; } //Initializethecolorshaderobject. result=m_ColorShader->Initialize(m_D3D->GetDevice(),hwnd); if(!result) { MessageBox(hwnd,L"Couldnotinitializethecolorshaderobject.",L"Error",MB_OK); returnfalse; } returntrue; } Shutdownisalsoupdatedtoshutdownandreleasethethreenewobjects. voidGraphicsClass::Shutdown() { //Releasethecolorshaderobject. if(m_ColorShader) { m_ColorShader->Shutdown(); deletem_ColorShader; m_ColorShader=0; } //Releasethemodelobject. if(m_Model) { m_Model->Shutdown(); deletem_Model; m_Model=0; } //Releasethecameraobject. if(m_Camera) { deletem_Camera; m_Camera=0; } //ReleasetheDirect3Dobject. if(m_D3D) { m_D3D->Shutdown(); deletem_D3D; m_D3D=0; } return; } TheFramefunctionhasremainedthesameastheprevioustutorial. boolGraphicsClass::Frame() { boolresult; //Renderthegraphicsscene. result=Render(); if(!result) { returnfalse; } returntrue; } AsyouwouldexpecttheRenderfunctionhadthemostchangestoit. Itstillbeginswithclearingthesceneexceptthatitisclearedtoblack. AfterthatitcallstheRenderfunctionforthecameraobjecttocreateaviewmatrixbasedonthecamera'slocationthatwassetintheInitializefunction. Oncetheviewmatrixiscreatedwegetacopyofitfromthecameraclass. WealsogetcopiesoftheworldandprojectionmatrixfromtheD3DClassobject. WethencalltheModelClass::Renderfunctiontoputthegreentrianglemodelgeometryonthegraphicspipeline. Withtheverticesnowpreparedwecallthecolorshadertodrawtheverticesusingthemodelinformationandthethreematricesforpositioningeachvertex. Thegreentriangleisnowdrawntothebackbuffer. WiththatthesceneiscompleteandwecallEndScenetodisplayittothescreen. boolGraphicsClass::Render() { D3DXMATRIXviewMatrix,projectionMatrix,worldMatrix; //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); //Putthemodelvertexandindexbuffersonthegraphicspipelinetopreparethemfordrawing. m_Model->Render(m_D3D->GetDevice()); //Renderthemodelusingthecolorshader. m_ColorShader->Render(m_D3D->GetDevice(),m_Model->GetIndexCount(),worldMatrix,viewMatrix,projectionMatrix); //Presenttherenderedscenetothescreen. m_D3D->EndScene(); returntrue; } Summary Soinsummaryyoushouldhavelearnedthebasicsabouthowvertexandindexbufferswork. YoushouldhavealsolearnedthebasicsofvertexandpixelshadersandhowtowritethemusingHLSL. Andfinallyyoushouldunderstandhowwe'veincorporatedthesenewconceptsintoourframeworktoproduceagreentrianglethatrenderstothescreen. IalsowanttomentionthatIrealizethecodeisfairlylongjusttodrawasingletriangleanditcouldhaveallbeenstuckinsideasinglemain()function. HoweverIdiditthiswaywithaproperframeworksothatthecomingtutorialsrequireveryfewchangesinthecodetodofarmorecomplexgraphics. ToDoExercises 1.Compileandrunthetutorial.Ensureitdrawsagreentriangletothescreen.Pressescapetoquitonceitdoes. 2.Changethecolorofthetriangletored. 3.Changethetriangletoasquare. 4.Movethecameraback10moreunits. 5.Changethepixelshadertooutputthecolorhalfasbright.(hugehint:multiplysomethinginColorPixelShaderby0.5f) SourceCode VisualStudio2010Project:dx10tut04.zip SourceOnly:dx10src04.zip ExecutableOnly:dx10exe04.zip BacktoTutorialIndex



請為這篇文章評分?