// Render - render this model (only) //----------------------------------------------------------------------------- void CPUTModelDX11::RenderShadow(CPUTRenderParameters &renderParams) { CPUTRenderParametersDX *pParams = (CPUTRenderParametersDX*)&renderParams; CPUTCamera *pCamera = pParams->mpCamera; #ifdef SUPPORT_DRAWING_BOUNDING_BOXES if( renderParams.mShowBoundingBoxes && (!pCamera || pCamera->mFrustum.IsVisible( mBoundingBoxCenterWorldSpace, mBoundingBoxHalfWorldSpace ))) { DrawBoundingBox( renderParams ); } #endif if( !renderParams.mDrawModels ) { return; } // TODO: add world-space bounding box to model so we don't need to do that work every frame if( !pParams->mRenderOnlyVisibleModels || !pCamera || pCamera->mFrustum.IsVisible( mBoundingBoxCenterWorldSpace, mBoundingBoxHalfWorldSpace ) ) { // Update the model's render states only once (and then iterate over materials) UpdateShaderConstants(renderParams); CPUTMaterialDX11 *pMaterial = (CPUTMaterialDX11*)(mpShadowCastMaterial); pMaterial->SetRenderStates(renderParams); // loop over all meshes in this model and draw them for(UINT ii=0; ii<mMeshCount; ii++) { ((CPUTMeshDX11*)mpMesh[ii])->DrawShadow(renderParams, this); } } }
//----------------------------------------------------------------------------- CPUTMaterial *CPUTMaterialDX11::CloneMaterial(const cString &fileName, const CPUTModel *pModel, int meshIndex) { CPUTMaterialDX11 *pMaterial = new CPUTMaterialDX11(); // TODO: move texture to base class. All APIs have textures. pMaterial->mpPixelShader = mpPixelShader; if(mpPixelShader) mpPixelShader->AddRef(); pMaterial->mpComputeShader = mpComputeShader; if(mpComputeShader) mpComputeShader->AddRef(); pMaterial->mpVertexShader = mpVertexShader; if(mpVertexShader) mpVertexShader->AddRef(); pMaterial->mpGeometryShader = mpGeometryShader; if(mpGeometryShader) mpGeometryShader->AddRef(); pMaterial->mpHullShader = mpHullShader; if(mpHullShader) mpHullShader->AddRef(); pMaterial->mpDomainShader = mpDomainShader; if(mpDomainShader) mpDomainShader->AddRef(); mPixelShaderParameters.CloneShaderParameters( &pMaterial->mPixelShaderParameters ); mComputeShaderParameters.CloneShaderParameters( &pMaterial->mComputeShaderParameters ); mVertexShaderParameters.CloneShaderParameters( &pMaterial->mVertexShaderParameters ); mGeometryShaderParameters.CloneShaderParameters( &pMaterial->mGeometryShaderParameters ); mHullShaderParameters.CloneShaderParameters( &pMaterial->mHullShaderParameters ); mDomainShaderParameters.CloneShaderParameters( &pMaterial->mDomainShaderParameters ); pMaterial->mpShaderParametersList[0] = &pMaterial->mPixelShaderParameters, pMaterial->mpShaderParametersList[1] = &pMaterial->mComputeShaderParameters, pMaterial->mpShaderParametersList[2] = &pMaterial->mVertexShaderParameters, pMaterial->mpShaderParametersList[3] = &pMaterial->mGeometryShaderParameters, pMaterial->mpShaderParametersList[4] = &pMaterial->mHullShaderParameters, pMaterial->mpShaderParametersList[5] = &pMaterial->mDomainShaderParameters, pMaterial->mpShaderParametersList[6] = NULL; pMaterial->mpRenderStateBlock = mpRenderStateBlock; if( mpRenderStateBlock ) mpRenderStateBlock->AddRef(); pMaterial->mMaterialName = mMaterialName + ptoc(pModel) + itoc(meshIndex); pMaterial->mMaterialNameHash = CPUTComputeHash(pMaterial->mMaterialName); pMaterial->mConfigBlock = mConfigBlock; pMaterial->mBufferCount = mBufferCount; // For each of the shader stages, bind shaders and buffers for( CPUTShaderParameters **pCur = pMaterial->mpShaderParametersList; *pCur; pCur++ ) // Bind textures and buffersfor each shader stage { pMaterial->BindTextures( **pCur, pModel, meshIndex ); pMaterial->BindBuffers( **pCur, pModel, meshIndex ); pMaterial->BindUAVs( **pCur, pModel, meshIndex ); pMaterial->BindConstantBuffers( **pCur, pModel, meshIndex ); } // Append this clone to our clone list if( mpMaterialNextClone ) { // Already have a list, so add to the end of it. ((CPUTMaterialDX11*)mpMaterialLastClone)->mpMaterialNextClone = pMaterial; } else { // No list yet, so start it with this material. mpMaterialNextClone = pMaterial; mpMaterialLastClone = pMaterial; } pMaterial->mpModel = pModel; pMaterial->mMeshIndex = meshIndex; return pMaterial; }
//----------------------------------------------------------------------------- void CPUTModelDX11::DrawBoundingBox(CPUTRenderParameters &renderParams) { CPUTRenderParametersDX *pParams = (CPUTRenderParametersDX*)&renderParams; UpdateShaderConstants(renderParams); CPUTMaterialDX11 *pMaterial = (CPUTMaterialDX11*)mpBoundingBoxMaterial; pMaterial->SetRenderStates(renderParams); ((CPUTMeshDX11*)mpBoundingBoxMesh)->Draw(renderParams, this); }
//----------------------------------------------------------------------------- void CPUTModelDX11::DrawBoundingBox(CPUTRenderParameters &renderParams) { UpdateShaderConstants(renderParams); UINT index = mpSubMaterialCount[0] + CPUT_MATERIAL_INDEX_BOUNDING_BOX; CPUTMaterialDX11 *pMaterial = (CPUTMaterialDX11*)(mpMaterial[0][index]); pMaterial->SetRenderStates(renderParams); ((CPUTMeshDX11*)mpBoundingBoxMesh)->Draw(renderParams, mpInputLayout[0][index]); }
// Render this model. Render only this model, not its children or siblings. //----------------------------------------------------------------------------- void CPUTModelDX11::Render(CPUTRenderParameters &renderParams, int materialIndex) { CPUTRenderParametersDX *pParams = (CPUTRenderParametersDX*)&renderParams; CPUTCamera *pCamera = pParams->mpCamera; // TODO: Move bboxDirty to member and set only when model moves. bool bboxDirty = true; if( bboxDirty ) { UpdateBoundsWorldSpace(); } #ifdef SUPPORT_DRAWING_BOUNDING_BOXES if( renderParams.mShowBoundingBoxes && (!pCamera || pCamera->mFrustum.IsVisible( mBoundingBoxCenterWorldSpace, mBoundingBoxHalfWorldSpace ))) { DrawBoundingBox( renderParams ); } #endif if( !renderParams.mDrawModels ) { return; } if( !pParams->mRenderOnlyVisibleModels || !pCamera || pCamera->mFrustum.IsVisible( mBoundingBoxCenterWorldSpace, mBoundingBoxHalfWorldSpace ) ) { // Update the model's constant buffer. // Note that the materials reference this, so we need to do it only once for all of the model's meshes. UpdateShaderConstants(renderParams); // loop over all meshes in this model and draw them for(UINT ii=0; ii<mMeshCount; ii++) { UINT finalMaterialIndex = GetMaterialIndex(ii, materialIndex); ASSERT( finalMaterialIndex < mpSubMaterialCount[ii], _L("material index out of range.")); CPUTMaterialDX11 *pMaterial = (CPUTMaterialDX11*)(mpMaterial[ii][finalMaterialIndex]); pMaterial->SetRenderStates(renderParams); ((CPUTMeshDX11*)mpMesh[ii])->Draw(renderParams, mpInputLayout[ii][finalMaterialIndex]); } } }
//----------------------------------------------------------------------------- CPUTResult CPUTModelDX11::LoadModel(CPUTConfigBlock *pBlock, int *pParentID, CPUTModel *pMasterModel) { CPUTResult result = CPUT_SUCCESS; CPUTAssetLibraryDX11 *pAssetLibrary = (CPUTAssetLibraryDX11*)CPUTAssetLibrary::GetAssetLibrary(); cString modelSuffix = ptoc(this); // set the model's name mName = pBlock->GetValueByName(_L("name"))->ValueAsString(); mName = mName + _L(".mdl"); // resolve the full path name cString modelLocation; cString resolvedPathAndFile; modelLocation = ((CPUTAssetLibraryDX11*)CPUTAssetLibrary::GetAssetLibrary())->GetModelDirectory(); modelLocation = modelLocation+mName; CPUTOSServices::GetOSServices()->ResolveAbsolutePathAndFilename(modelLocation, &resolvedPathAndFile); // Get the parent ID. Note: the caller will use this to set the parent. *pParentID = pBlock->GetValueByName(_L("parent"))->ValueAsInt(); LoadParentMatrixFromParameterBlock( pBlock ); // Get the bounding box information float3 center(0.0f), half(0.0f); pBlock->GetValueByName(_L("BoundingBoxCenter"))->ValueAsFloatArray(center.f, 3); pBlock->GetValueByName(_L("BoundingBoxHalf"))->ValueAsFloatArray(half.f, 3); mBoundingBoxCenterObjectSpace = center; mBoundingBoxHalfObjectSpace = half; mMeshCount = pBlock->GetValueByName(_L("meshcount"))->ValueAsInt(); mpMesh = new CPUTMesh*[mMeshCount]; mpMaterial = new CPUTMaterial*[mMeshCount]; memset( mpMaterial, 0, mMeshCount * sizeof(CPUTMaterial*) ); cString materialName; char pNumber[4]; cString materialValueName; CPUTModelDX11 *pMasterModelDX = (CPUTModelDX11*)pMasterModel; for(UINT ii=0; ii<mMeshCount; ii++) { if(pMasterModelDX) { // Reference the master model's mesh. Don't create a new one. mpMesh[ii] = pMasterModelDX->mpMesh[ii]; mpMesh[ii]->AddRef(); } else { mpMesh[ii] = new CPUTMeshDX11(); } } if( !pMasterModelDX ) { // Not a clone/instance. So, load the model's binary payload (i.e., vertex and index buffers) // TODO: Change to use GetModel() result = LoadModelPayload(resolvedPathAndFile); ASSERT( CPUTSUCCESS(result), _L("Failed loading model") ); } #if 0 cString assetSetDirectoryName = pAssetLibrary->GetAssetSetDirectoryName(); cString modelDirectory = pAssetLibrary->GetModelDirectory(); cString materialDirectory = pAssetLibrary->GetMaterialDirectory(); cString textureDirectory = pAssetLibrary->GetTextureDirectory(); cString shaderDirectory = pAssetLibrary->GetShaderDirectory(); cString fontDirectory = pAssetLibrary->GetFontDirectory(); cString up2MediaDirName = assetSetDirectoryName + _L("..\\..\\"); pAssetLibrary->SetMediaDirectoryName( up2MediaDirName ); mpShadowCastMaterial = pAssetLibrary->GetMaterial( _L("shadowCast"), false, this, -2 ); // -2 signifies shadow material. TODO: find a clearer way (e.g., enum?) pAssetLibrary->SetAssetSetDirectoryName( assetSetDirectoryName ); pAssetLibrary->SetModelDirectoryName( modelDirectory ); pAssetLibrary->SetMaterialDirectoryName( materialDirectory ); pAssetLibrary->SetTextureDirectoryName( textureDirectory ); pAssetLibrary->SetShaderDirectoryName( shaderDirectory ); pAssetLibrary->SetFontDirectoryName( fontDirectory ); #endif for(UINT ii=0; ii<mMeshCount; ii++) { // get the right material number ('material0', 'material1', 'material2', etc) materialValueName = _L("material"); _itoa_s(ii, pNumber, 4, 10); materialValueName.append(s2ws(pNumber)); materialName = pBlock->GetValueByName(materialValueName)->ValueAsString(); // Get/load material for this mesh CPUTMaterialDX11 *pMaterial = (CPUTMaterialDX11*)pAssetLibrary->GetMaterial(materialName, false, this, ii); ASSERT( pMaterial, _L("Couldn't find material.") ); // set the material on this mesh // TODO: Model owns the materials. That allows different models to share meshes (aka instancing) that have different materials SetMaterial(ii, pMaterial); // Release the extra refcount we're holding from the GetMaterial operation earlier // now the asset library, and this model have the only refcounts on that material pMaterial->Release(); // Create two ID3D11InputLayout objects, one for each material. mpMesh[ii]->BindVertexShaderLayout( mpMaterial[ii], mpShadowCastMaterial); // mpShadowCastMaterial->Release() } return result; }
// Load the set file definition of this object // 1. Parse the block of name/parent/transform info for model block // 2. Load the model's binary payload (i.e., the meshes) // 3. Assert the # of meshes matches # of materials // 4. Load each mesh's material //----------------------------------------------------------------------------- CPUTResult CPUTModelDX11::LoadModel(CPUTConfigBlock *pBlock, int *pParentID, CPUTModel *pMasterModel, int numSystemMaterials, cString *pSystemMaterialNames) { CPUTResult result = CPUT_SUCCESS; CPUTAssetLibraryDX11 *pAssetLibrary = (CPUTAssetLibraryDX11*)CPUTAssetLibrary::GetAssetLibrary(); cString modelSuffix = ptoc(this); // set the model's name mName = pBlock->GetValueByName(_L("name"))->ValueAsString(); mName = mName + _L(".mdl"); // resolve the full path name cString modelLocation; cString resolvedPathAndFile; modelLocation = ((CPUTAssetLibraryDX11*)CPUTAssetLibrary::GetAssetLibrary())->GetModelDirectoryName(); modelLocation = modelLocation+mName; CPUTOSServices::GetOSServices()->ResolveAbsolutePathAndFilename(modelLocation, &resolvedPathAndFile); // Get the parent ID. Note: the caller will use this to set the parent. *pParentID = pBlock->GetValueByName(_L("parent"))->ValueAsInt(); LoadParentMatrixFromParameterBlock( pBlock ); // Get the bounding box information float3 center(0.0f), half(0.0f); pBlock->GetValueByName(_L("BoundingBoxCenter"))->ValueAsFloatArray(center.f, 3); pBlock->GetValueByName(_L("BoundingBoxHalf"))->ValueAsFloatArray(half.f, 3); mBoundingBoxCenterObjectSpace = center; mBoundingBoxHalfObjectSpace = half; mMeshCount = pBlock->GetValueByName(_L("meshcount"))->ValueAsInt(); mpMesh = new CPUTMesh*[mMeshCount]; mpSubMaterialCount = new UINT[mMeshCount]; mpMaterial = new CPUTMaterial**[mMeshCount]; memset( mpMaterial, 0, mMeshCount * sizeof(CPUTMaterial*) ); mpInputLayout = new ID3D11InputLayout**[mMeshCount]; memset( mpInputLayout, 0, mMeshCount * sizeof(ID3D11InputLayout**) ); cString materialName; char pNumber[4]; cString materialValueName; CPUTModelDX11 *pMasterModelDX = (CPUTModelDX11*)pMasterModel; for(UINT ii=0; ii<mMeshCount; ii++) { if(pMasterModelDX) { // Reference the master model's mesh. Don't create a new one. mpMesh[ii] = pMasterModelDX->mpMesh[ii]; mpMesh[ii]->AddRef(); } else { mpMesh[ii] = new CPUTMeshDX11(); } } if( !pMasterModelDX ) { // Not a clone/instance. So, load the model's binary payload (i.e., vertex and index buffers) // TODO: Change to use GetModel() result = LoadModelPayload(resolvedPathAndFile); ASSERT( CPUTSUCCESS(result), _L("Failed loading model") ); } for(UINT ii=0; ii<mMeshCount; ii++) { // get the right material number ('material0', 'material1', 'material2', etc) materialValueName = _L("material"); _itoa_s(ii, pNumber, 4, 10); materialValueName.append(s2ws(pNumber)); materialName = pBlock->GetValueByName(materialValueName)->ValueAsString(); // Get/load material for this mesh cString meshSuffix = itoc(ii); #if GENERATE_BILLBOARD_TEXTURES cString *pFinalSystemNames = new cString[numSystemMaterials+2]; pFinalSystemNames[1] = materialName + _L("Color"); pFinalSystemNames[0] = materialName + _L("ColorNormal"); int finalNumSystemMaterials = 2; #else UINT totalNameCount = numSystemMaterials + NUM_GLOBAL_SYSTEM_MATERIALS; cString *pFinalSystemNames = new cString[totalNameCount]; // Copy "global" system materials to caller-supplied list for( int jj=0; jj<numSystemMaterials; jj++ ) { pFinalSystemNames[jj] = pSystemMaterialNames[jj]; } pFinalSystemNames[totalNameCount + CPUT_MATERIAL_INDEX_SHADOW_CAST] = _L("..\\..\\Material\\ShadowCast"); pFinalSystemNames[totalNameCount + CPUT_MATERIAL_INDEX_AMBIENT_SHADOW_CAST] = _L("..\\..\\Material\\AmbientShadowCast"); pFinalSystemNames[totalNameCount + CPUT_MATERIAL_INDEX_HEIGHT_FIELD] = _L("..\\..\\Material\\HeightField"); pFinalSystemNames[totalNameCount + CPUT_MATERIAL_INDEX_BOUNDING_BOX] = _L("..\\..\\Material\\BoundingBox"); pFinalSystemNames[totalNameCount + CPUT_MATERIAL_INDEX_TERRAIN_LIGHT_MAP] = _L("..\\..\\Material\\TerrainLightMap"); pFinalSystemNames[totalNameCount + CPUT_MATERIAL_INDEX_TERRAIN_AND_TREES_LIGHT_MAP] = _L("..\\..\\Material\\TerrainAndTreesLightMap"); int finalNumSystemMaterials = numSystemMaterials + NUM_GLOBAL_SYSTEM_MATERIALS; #endif CPUTMaterialDX11 *pMaterial = (CPUTMaterialDX11*)pAssetLibrary->GetMaterial(materialName, false, modelSuffix, meshSuffix, NULL, finalNumSystemMaterials, pFinalSystemNames); ASSERT( pMaterial, _L("Couldn't find material.") ); delete []pFinalSystemNames; mpSubMaterialCount[ii] = pMaterial->GetSubMaterialCount(); HEAPCHECK; SetSubMaterials(ii, pMaterial->GetSubMaterials()); HEAPCHECK; // Release the extra refcount we're holding from the GetMaterial operation earlier // now the asset library, and this model have the only refcounts on that material pMaterial->Release(); } return result; }