#include "dxstdafx.h" #include "resource.h" #include #include "Cube.h" #include "Mesh.h" #include "Parameters.h" #include "EnvMap.h" //-------------------------------------------------------------------------------------- // Media //-------------------------------------------------------------------------------------- #define MESH0 L"Media\\Objects\\room.x" #define MESH1 L"Media\\Objects\\sphere.x" #define MESH2 L"Media\\Objects\\column.x" #define MESH3 L"Media\\Objects\\teapot.x" #define MESH4 L"Media\\Objects\\lamp01.x" #define MESH5 L"Media\\Objects\\chair29.x" #define MESH6 L"Media\\Objects\\couch01.x" #define MESH7 L"Media\\Objects\\tiger.x" #define MESH8 L"Media\\Objects\\bunny.x" #define MESH9 L"Media\\Objects\\skullocc.x" #define TEX0 L"Media\\Maps\\white.png" #define TEX1 L"Media\\Maps\\pixel-grid-gy.png" #define TEX2 L"Media\\Maps\\column.png" #define ROOM_TEXTURE L"Media\\Maps\\pixel-grid-b.png" //#define ROOM_TEXTURE L"Media\\Maps\\checker1.png" // checker //-------------------------------------------------------------------------------------- // Constants //-------------------------------------------------------------------------------------- // size of the cube map taken from the reference point of the object #define CUBEMAP_SIZE 128 // 256 // size of the cube map for diffuse/glossy reflections #define LR_CUBEMAP_SIZE 4 #define M 10 //25 // number of samples when precomputing geometric factors extern Parameters pp; void EnvMap::OnCreateDevice( IDirect3DDevice9* pd3dDevice, ID3DXEffect* g_pEffect ) { this->pd3dDevice = pd3dDevice; this->g_pEffect = g_pEffect; // init mesh array meshCount = 0; // room meshes[meshCount++] = new Mesh(MESH0, TEX0, 0, D3DXVECTOR3(0,0,0)); // room /*meshes[meshCount++] = new Mesh(MESH2, TEX2, 0.7, D3DXVECTOR3(1.5,-1.3,1.5)); // columns meshes[meshCount++] = new Mesh(MESH2, TEX2, 0.7, D3DXVECTOR3(1.5,-1.3,-1.5)); meshes[meshCount++] = new Mesh(MESH2, TEX2, 0.7, D3DXVECTOR3(-1.5,-1.3,1.5)); meshes[meshCount++] = new Mesh(MESH2, TEX2, 0.7, D3DXVECTOR3(-1.5,-1.3,-1.5));*/ // central mesh mesh = new Mesh(MESH1, TEX0, 1, D3DXVECTOR3(0,0,0)); bCubeMapIsValid = false; //ChooseMesh(whichMesh); } void EnvMap::OnDestroyDevice() { // central mesh delete mesh; // destroy mesh array for (int i=0; iDestroy(); delete cube; bCubeMapIsValid = false; } void EnvMap::ChooseMesh(int whichMesh) { switch (whichMesh) { case 0: mesh->Load(MESH0); break; case 1: mesh->Load(MESH1); break; case 2: mesh->Load(MESH2); break; case 3: mesh->Load(MESH3); break; case 4: mesh->Load(MESH4); break; case 5: mesh->Load(MESH5); break; case 6: mesh->Load(MESH6); break; case 7: mesh->Load(MESH7); break; case 8: mesh->Load(MESH8); break; case 9: mesh->Load(MESH9); break; } bCubeMapIsValid = false; // ask for cubemap redraw } void EnvMap::KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown ) { if( bKeyDown ) { float step = 0.2f; //float max = roomSize-1.02f; if ( nChar >= '0' && nChar <= '9' ) { whichMesh = nChar-'0'; ChooseMesh(whichMesh); // load mesh } else switch( nChar ) { case VK_RIGHT: mesh->Move( D3DXVECTOR3( step,0,0) ); break; case VK_LEFT: mesh->Move( D3DXVECTOR3(-step,0,0) ); break; case VK_UP: mesh->Move( D3DXVECTOR3(0, step,0) ); break; case VK_DOWN: mesh->Move( D3DXVECTOR3(0,-step,0) ); break; case VK_PRIOR: mesh->Move( D3DXVECTOR3(0,0, step) ); break; case VK_NEXT: mesh->Move( D3DXVECTOR3(0,0,-step) ); break; case 32: bCubeMapIsValid = false; break; } // switch } } void EnvMap::OnFrameRender( IDirect3DDevice9* pd3dDevice, D3DXMATRIXA16& mView, D3DXMATRIXA16& mProj ) { if (pp.Get( bAutoGenCubeMap )) // calculate cube maps for each frame { bCubeMapIsValid = false; } // regenerate cube maps if necessary if ( !bCubeMapIsValid ) { long clock1 = clock(); // (to avoid warnings) V( g_pEffect->SetTexture( "EnvironmentMap", NULL ) ); if ( !pp.Get( bCubeMapFromFile ) ) { // to be precise: offsetting to the center of the (DirectX) texel V( g_pEffect->SetFloat( "texel_size", 1 / (float)CUBEMAP_SIZE ) ); // I had to call it 2 times to render the environment completely RenderCubeMap( pCubeTexture ); RenderCubeMap( pCubeTexture ); // don't ask why } //V( g_pEffect->SetFloat( "texel_size", 0 ) ); if ( pp.GetInt( iWhichMethod ) == DIFFUSE_SPECULAR || pp.GetInt( iWhichMethod ) == DIFFUSE_SPECULAR_LOCALIZED || pp.GetInt( iWhichMethod ) == DIFFUSE_SPECULAR_LOCALIZED_COSTEX ) { ReduceCubeMapSize( pp.Get( bCubeMapFromFile ) ? pCubeTextureFromFile : pCubeTexture, pCubeTextureSmall); bShininessIsValid = false; } long clock2 = clock(); float tb = (float)(clock2-clock1)/CLOCKS_PER_SEC; bCubeMapIsValid = true; } if ( !bShininessIsValid ) // refresh cos texture { if ( pp.GetInt( iWhichMethod ) == DIFFUSE_SPECULAR || pp.GetInt( iWhichMethod ) == DIFFUSE_SPECULAR_LOCALIZED ) PreConvolve(pCubeTextureSmall, pCubeTexturePreConvolved); else if ( pp.GetInt( iWhichMethod ) == DIFFUSE_SPECULAR_LOCALIZED_COSTEX ) GenerateCosTextureIfNotFound(); bShininessIsValid = true; } // Render the scene DoRendering(mView, mProj); } void EnvMap::DoRendering(D3DXMATRIXA16& mView, D3DXMATRIXA16& mProj) { UINT uPasses; D3DCOLOR backgroundColor = D3DCOLOR_ARGB(0, 66, 75, 121); V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, backgroundColor, 1.0f, 0) ); D3DXVECTOR3 eye = *camera->GetEyePt(); D3DXVECTOR4 eyePos(eye.x, eye.y, eye.z, 1); D3DXVECTOR4 refPos(reference_pos.x, reference_pos.y, reference_pos.z, 1); V( g_pEffect->SetTexture( "EnvironmentMap", pp.Get( bCubeMapFromFile ) ? pCubeTextureFromFile : pCubeTexture ) ); V( g_pEffect->SetTexture( "SmallEnvironmentMap", pCubeTextureSmall ) ); //V( g_pEffect->SetTexture( "Decoration", pBoxTexture ) ); // crate texture V( g_pEffect->SetVector ( "eyePos", &eyePos ) ); V( g_pEffect->SetVector ( "reference_pos", &refPos ) ); //V( g_pEffect->SetFloat ( "roomSize", roomSize )); V( g_pEffect->SetFloat ( "refractionIndex", pp.Get( refractionIndex ))); V( g_pEffect->SetFloat ( "intensity", pp.Get( fIntensity ) )); V( g_pEffect->SetFloat ( "sFresnel", pp.Get( sFresnel ))); // Fresnel refraction param. //metal: D3DXVECTOR4 n, k; // R 700 nm, G 550 nm, B 435 nm if (pp.GetInt( iWhichMetal ) == 1) { // copper n = D3DXVECTOR4(0.21f, 0.96f, 1.17f, 1); k = D3DXVECTOR4(4.16f, 2.57f, 2.32f, 1); } else if (pp.GetInt( iWhichMetal ) == 2) { // gold n = D3DXVECTOR4(0.16f, 0.35f, 1.6f, 1); k = D3DXVECTOR4(3.98f, 2.71f, 1.92f, 1); } else if (pp.GetInt( iWhichMetal ) == 3) { // silver n = D3DXVECTOR4(0.142f, 0.124f, 0.158f, 1); k = D3DXVECTOR4(4.52f, 3.33f, 2.32f, 1); } else if (pp.GetInt( iWhichMetal ) == 4) { // alu n = D3DXVECTOR4(1.83f, 0.96f, 0.577f, 1); k = D3DXVECTOR4(8.31f, 6.69f, 5.288f, 1); } V( g_pEffect->SetVector( "nMetal", &n )); V( g_pEffect->SetVector( "kMetal", &k )); //V( g_pEffect->SetInt ( "iWhichMetal", pp.GetInt( iWhichMetal )) ); //if (pp.GetInt( iWhichMethod ) == DIFFUSE_SPECULAR || //pp.GetInt( iWhichMethod ) == DIFFUSE_SPECULAR_LOCALIZED ) float s = (float)pp.GetInt( iShininess ); V( g_pEffect->SetFloat ( "shininess", s)); // ------------------------- choose technique ------------------------- switch (pp.GetInt( iWhichMethod )) { case IDEAL: case IDEAL_LOCALIZED: if (pp.GetInt( iWhichMethod ) == IDEAL || pp.Get( bCubeMapFromFile) ) // no localization chosen // or no depth info is available since the env is loaded from a DDS file { if ( pp.GetInt( iWhichMetal ) > 0 ) { V( g_pEffect->SetTechnique( "EnvMapClassicMetal" ) ); } else { V( g_pEffect->SetTechnique( "EnvMapClassic" ) ); } } else { if ( pp.GetInt( iWhichMetal ) > 0 ) { V( g_pEffect->SetTechnique( "EnvMapImpostorMetal" ) ); } else { V( g_pEffect->SetTechnique( "EnvMapImpostor" ) ); } } break; case DIFFUSE_SPECULAR: V( g_pEffect->SetTechnique( "EnvMapDiffuse" ) ); V( g_pEffect->SetTexture( "PreconvolvedEnvironmentMap", pCubeTexturePreConvolved ) ); break; case DIFFUSE_SPECULAR_LOCALIZED: V( g_pEffect->SetTechnique( "EnvMapDiffuseLocalized" ) ); break; case DIFFUSE_SPECULAR_LOCALIZED_COSTEX: V( g_pEffect->SetTechnique( "EnvMapDiffuseLocalizedWithCosLookup" ) ); V( g_pEffect->SetTexture( "Decoration", pCosValuesTexture ) ); break; } // ------------------------ end choose technique ------------------------ V( g_pEffect->Begin( &uPasses, 0 ) ); V( g_pEffect->BeginPass( 0 ) ); // csak 1 db PASS wan DrawCenterObjects( mView, mProj ); V( g_pEffect->EndPass() ); V( g_pEffect->End() ); switch (pp.GetInt( iShowCubeMap )) { case 0: case 1: V( g_pEffect->SetTexture( "EnvironmentMap", pp.Get( bCubeMapFromFile ) ? pCubeTextureFromFile : pCubeTexture ) ); break; case 2: V( g_pEffect->SetTexture( "EnvironmentMap", pCubeTextureSmall ) ); break; case 3: V( g_pEffect->SetTexture( "EnvironmentMap", pCubeTexturePreConvolved) ); break; } // draw environment objects (room) V( g_pEffect->SetTechnique( "IlluminatedScene" ) ); V( g_pEffect->Begin( &uPasses, 0 ) ); V( g_pEffect->BeginPass( 0 ) ); DrawEnvObjects( mView, mProj ); V( g_pEffect->EndPass() ); V( g_pEffect->End() ); V( g_pEffect->SetInt ( "iShowCubeMap", 0 )); } // ------------------------------------------------------------------------ // DRAW CENTRAL OBJECTS (SPHERE, ETC.) // ------------------------------------------------------------------------ void EnvMap::DrawCenterObjects( D3DXMATRIXA16& mView, D3DXMATRIXA16& mProj ) { D3DXVECTOR4 objColor(1,1,0,1); objColor = D3DXVECTOR4(1,1,1,1); V( g_pEffect->SetVector( "objColor", &objColor ) ); float scale = mesh->GetMeshScale(); D3DXVECTOR3 offset = mesh->GetMeshPosition(); SetWorldViewProj( ScaleAndOffset( scale, offset ), mView, mProj ); mesh->Draw(); } // ------------------------------------------------------------------------ // DRAW OBJECTS IN THE ENVIRONMENT (BOX, LAMP, ETC.) // ------------------------------------------------------------------------ void EnvMap::DrawEnvObjects( D3DXMATRIXA16& mView, D3DXMATRIXA16& mProj ) { if (!pp.Get( bCubeMapFromFile )) { for (int i=1; iSetTexture( "Decoration", meshes[i]->GetTexture() ) ); float scale = meshes[i]->GetMeshScale(); D3DXVECTOR3 offset = meshes[i]->GetMeshPosition(); SetWorldViewProj( ScaleAndOffset( scale, offset ), mView, mProj ); meshes[i]->Draw(); } } V( g_pEffect->SetTexture( "Decoration", pRoomTexture ) ); D3DXVECTOR4 objColor(1,1,0,1); // ---------------------------------------- // draw a room of size [-roomSize..roomSize] // ---------------------------------------- bool bLargeEnvCube = pp.Get( bCubeMapFromFile ) && pp.Get( iShowCubeMap ) == 0; float roomSizeCurr = bLargeEnvCube ? roomSize*5 : roomSize; cube->PrepareDrawing(); SetWorldViewProj( ScaleAndOffset( roomSizeCurr, D3DXVECTOR3(0,0,0) ), mView, mProj ); // flip normals so that the room is visible from its inside V( pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW) ); V( g_pEffect->SetTexture( "Decoration", pRoomTexture ) ); V( g_pEffect->SetFloat( "brightness", 2.8f )); V( g_pEffect->SetInt ( "iShowCubeMap", 0 )); // decide if the room should visualize one of the cube maps if ( bCubeMapIsValid && pp.GetInt( iShowCubeMap ) > 0) V( g_pEffect->SetInt ( "iShowCubeMap", pp.GetInt( iShowCubeMap ) )); if ( bCubeMapIsValid && pp.GetInt( iShowCubeMap ) == 0 && pp.Get( bCubeMapFromFile )) V( g_pEffect->SetInt ( "iShowCubeMap", 1 )); for( int i=0; i<6; i++ ) { objColor = D3DXVECTOR4(0.4f-i*0.1f, i*0.1f, (i%2)*0.4f, 1); // a colorful room g_pEffect->SetVector( "objColor", &objColor ); g_pEffect->CommitChanges(); cube->DrawFace(i); } pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); V( g_pEffect->SetInt ( "iShowCubeMap", 0 )); //V( g_pEffect->SetInt( "shininess", 2)); V( g_pEffect->SetFloat( "brightness", 1.0f )); //V( g_pEffect->SetTexture( "Decoration", pBoxTexture ) ); objColor = D3DXVECTOR4(1, 1, 1, 1); V( g_pEffect->SetVector( "objColor", &objColor )); g_pEffect->CommitChanges(); } /** Sets the given scaling and offset. @return The resulting world transformation matrix. */ D3DXMATRIXA16 EnvMap::ScaleAndOffset(D3DXVECTOR3 vScale, D3DXVECTOR3 vOffset) { D3DXMATRIXA16 mScale, mOffset; D3DXMatrixIdentity(&mScale); D3DXMatrixIdentity(&mOffset); D3DXMatrixTranslation( &mOffset, vOffset.x, vOffset.y, vOffset.z ); D3DXMatrixScaling( &mScale, vScale.x, vScale.y, vScale.z ); return mScale * mOffset; } /** Sets the given uniform scaling and an offset. @return The resulting world transformation matrix. */ D3DXMATRIXA16 EnvMap::ScaleAndOffset(float fScale, D3DXVECTOR3 vOffset) { return ScaleAndOffset( D3DXVECTOR3(fScale,fScale,fScale), vOffset ); } /** \brief Uploads the specified world/view/projection transformation matrices to the GPU. */ void EnvMap::SetWorldViewProj(D3DXMATRIXA16& mWorld, D3DXMATRIXA16& mView, D3DXMATRIXA16& mProj ) { D3DXMATRIXA16 mWorldView = mWorld * mView; D3DXMATRIXA16 mWorldViewProjection = mWorldView * mProj; D3DXMATRIXA16 mWorldViewI, mWorldViewIT, mWorldI, mWorldIT; D3DXMatrixInverse(&mWorldViewI, NULL, &mWorldView); D3DXMatrixTranspose(&mWorldViewIT, &mWorldViewI); D3DXMatrixInverse(&mWorldI, NULL, &mWorld); D3DXMatrixTranspose(&mWorldIT, &mWorldI); V( g_pEffect->SetMatrix( "World", &mWorld ) ); V( g_pEffect->SetMatrix( "WorldIT", &mWorldIT ) ); V( g_pEffect->SetMatrix( "WorldView", &mWorldView ) ); //V( g_pEffect->SetMatrix( "WorldViewIT", &mWorldViewIT ) ); V( g_pEffect->SetMatrix( "WorldViewProjection", &mWorldViewProjection ) ); V( g_pEffect->CommitChanges() ); } /// \brief Renders the environment into the specified cubemap. /// /// The camera is placed into #reference_pos. Uses technique IlluminatedScenePS() for rendering. void EnvMap::RenderCubeMap(IDirect3DCubeTexture9* pCubeTexture) { IDirect3DSurface9* oldRenderTarget; IDirect3DSurface9* oldDepthStencil; IDirect3DSurface9* newDepthStencil; // create a CUBEMAP_SIZE x CUBEMAP_SIZE size depth buffer pd3dDevice->CreateDepthStencilSurface(CUBEMAP_SIZE, CUBEMAP_SIZE, D3DFMT_D16, D3DMULTISAMPLE_NONE, 0, true, &newDepthStencil, NULL); // replace old depth buffer pd3dDevice->GetDepthStencilSurface(&oldDepthStencil); pd3dDevice->SetDepthStencilSurface(newDepthStencil); pd3dDevice->GetRenderTarget(0,&oldRenderTarget); UINT uPasses; for (int i = 0; i < 6; i++) { IDirect3DSurface9* pFace; V( pCubeTexture->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &pFace) ); V( pd3dDevice->SetRenderTarget(0, pFace) ); V( g_pEffect->SetTechnique( "IlluminatedScene" ) ); V( g_pEffect->SetTexture( "Decoration", pRoomTexture ) ); V( g_pEffect->Begin( &uPasses, 0 ) ); V( g_pEffect->BeginPass( 0 ) ); V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0,/*i==0 ? 255 : */0,0,0), 1.0f, 0) ); // mView D3DXMATRIXA16 mView, mProj; // looking toward the cube map faces _from the origin_ // mView = DXUTGetCubeMapViewMatrix( i ); //float scale = mesh->GetMeshScale(); //D3DXVECTOR3 offset = mesh->GetMeshPosition(); D3DXVECTOR3 vecEye(0,0,0); D3DXVECTOR3 vecAt(0.0f, 0.0f, 0.0f); D3DXVECTOR3 vecUp(0.0f, 0.0f, 0.0f); switch( i ) { case D3DCUBEMAP_FACE_POSITIVE_X: vecAt = D3DXVECTOR3( 1, 0, 0 ); vecUp = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); break; case D3DCUBEMAP_FACE_NEGATIVE_X: vecAt = D3DXVECTOR3(-1.0f, 0.0f, 0.0f ); vecUp = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); break; case D3DCUBEMAP_FACE_POSITIVE_Y: vecAt = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); vecUp = D3DXVECTOR3( 0.0f, 0.0f,-1.0f ); break; case D3DCUBEMAP_FACE_NEGATIVE_Y: vecAt = D3DXVECTOR3( 0.0f,-1.0f, 0.0f ); vecUp = D3DXVECTOR3( 0.0f, 0.0f, 1.0f ); break; case D3DCUBEMAP_FACE_POSITIVE_Z: vecAt = D3DXVECTOR3( 0.0f, 0.0f, 1.0f ); vecUp = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); break; case D3DCUBEMAP_FACE_NEGATIVE_Z: vecAt = D3DXVECTOR3( 0.0f, 0.0f,-1.0f ); vecUp = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); break; } // reference point is the current object position reference_pos = mesh->GetMeshPosition(); vecEye += reference_pos; vecAt += reference_pos; D3DXMatrixLookAtLH(&mView, &vecEye, &vecAt, &vecUp); D3DXMatrixPerspectiveFovLH( &mProj, D3DX_PI/2, 1, 0.1, 100 ); DrawEnvObjects(mView, mProj); V( g_pEffect->EndPass() ); V( g_pEffect->End() ); SAFE_RELEASE( pFace ); } // restore old rendertarget & depth buffer pd3dDevice->SetRenderTarget(0, oldRenderTarget); pd3dDevice->SetDepthStencilSurface(oldDepthStencil); SAFE_RELEASE( oldDepthStencil ); SAFE_RELEASE( oldRenderTarget ); SAFE_RELEASE( newDepthStencil ); } void EnvMap::ReduceCubeMapSize(IDirect3DCubeTexture9* pSourceCube, IDirect3DCubeTexture9* pDestCube) { IDirect3DSurface9* oldRenderTarget; IDirect3DSurface9* oldDepthStencil; IDirect3DSurface9* newDepthStencil; // create a LR_CUBEMAP_SIZE x LR_CUBEMAP_SIZE size depth buffer V( pd3dDevice->CreateDepthStencilSurface(LR_CUBEMAP_SIZE, LR_CUBEMAP_SIZE, D3DFMT_D16, D3DMULTISAMPLE_NONE, 0, true, &newDepthStencil, NULL)); // replace old depth buffer pd3dDevice->GetDepthStencilSurface(&oldDepthStencil); pd3dDevice->SetDepthStencilSurface(newDepthStencil); pd3dDevice->GetRenderTarget(0, &oldRenderTarget); for(int i=0; i<6; i++) { V( g_pEffect->SetTexture( "EnvironmentMap", pSourceCube ) ); V( g_pEffect->SetInt( "nFace", i ) ); // set a face of 'pDestCube' as rendertarget IDirect3DSurface9* pDestCubeFace; V( pDestCube->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &pDestCubeFace) ); V( pd3dDevice->SetRenderTarget(0, pDestCubeFace) ); // begin drawing V( g_pEffect->SetTechnique( "ReduceTexture" ) ); UINT uPasses; V( g_pEffect->Begin( &uPasses, 0 ) ); V( g_pEffect->BeginPass( 0 ) ); V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0,255,0,0), 1.0f, 0) ); // draw a square DrawFullScreenQuad(); V( g_pEffect->EndPass() ); V( g_pEffect->End() ); SAFE_RELEASE( pDestCubeFace ); } // restore old rendertarget & depth buffer pd3dDevice->SetRenderTarget(0, oldRenderTarget); pd3dDevice->SetDepthStencilSurface(oldDepthStencil); SAFE_RELEASE( oldDepthStencil ); SAFE_RELEASE( oldRenderTarget ); SAFE_RELEASE( newDepthStencil ); } /// \brief Calculates the irradiance map by convolution. /// /// Convolves data from the source cubemap and stores the result in the target cubemap. Uses ConvolutionPS(). void EnvMap::PreConvolve(IDirect3DCubeTexture9* pSourceCube, IDirect3DCubeTexture9* pDestCube) { IDirect3DSurface9* oldRenderTarget; IDirect3DSurface9* oldDepthStencil; IDirect3DSurface9* newDepthStencil; // create a LR_CUBEMAP_SIZE x LR_CUBEMAP_SIZE size depth buffer pd3dDevice->CreateDepthStencilSurface(LR_CUBEMAP_SIZE, LR_CUBEMAP_SIZE, D3DFMT_D16, D3DMULTISAMPLE_NONE, 0, true, &newDepthStencil, NULL); // replace old depth buffer pd3dDevice->GetDepthStencilSurface(&oldDepthStencil); pd3dDevice->SetDepthStencilSurface(newDepthStencil); pd3dDevice->GetRenderTarget(0, &oldRenderTarget); V( g_pEffect->SetTexture( "SmallEnvironmentMap", pSourceCube ) ); float s = (float)pp.GetInt( iShininess ); V( g_pEffect->SetFloat ( "shininess", s)); for(int i=0; i<6; i++) { V( g_pEffect->SetInt( "nFace", i ) ); // set a face of 'pDestCube' as rendertarget IDirect3DSurface9* pDestCubeFace; V( pDestCube->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &pDestCubeFace) ); V( pd3dDevice->SetRenderTarget(0, pDestCubeFace) ); // begin drawing V( g_pEffect->SetTechnique( "Convolution" ) ); UINT uPasses; V( g_pEffect->Begin( &uPasses, 0 ) ); V( g_pEffect->BeginPass( 0 ) ); V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0,255,255,255), 1.0f, 0) ); // draw a square DrawFullScreenQuad(); V( g_pEffect->EndPass() ); V( g_pEffect->End() ); SAFE_RELEASE( pDestCubeFace ); } //SaveCubeMap( pDestCube, "ha", ""); // restore old rendertarget & depth buffer pd3dDevice->SetRenderTarget(0, oldRenderTarget); pd3dDevice->SetDepthStencilSurface(oldDepthStencil); SAFE_RELEASE( oldDepthStencil ); SAFE_RELEASE( oldRenderTarget ); SAFE_RELEASE( newDepthStencil ); } /*void EnvMap::RenderToCubeTexture(IDirect3DCubeTexture9* pDestCube) { IDirect3DSurface9* m_backBuffer=NULL; pd3dDevice->GetRenderTarget(0, &m_backBuffer); for(int i=0; i<6; i++) { V( g_pEffect->SetInt( "nFace", i ) ); // set a face of 'pDestCube' as rendertarget IDirect3DSurface9* pDestCubeFace; V( pDestCube->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &pDestCubeFace) ); V( pd3dDevice->SetRenderTarget(0, pDestCubeFace) ); // begin drawing UINT uPasses; V( g_pEffect->Begin( &uPasses, 0 ) ); V( g_pEffect->BeginPass( 0 ) ); V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0,255,255,0), 1.0f, 0) ); // draw a square DrawFullScreenQuad(); V( g_pEffect->EndPass() ); V( g_pEffect->End() ); SAFE_RELEASE( pDestCubeFace ); } pd3dDevice->SetRenderTarget(0,m_backBuffer); }*/ void EnvMap::SaveCubeMap(IDirect3DCubeTexture9* pCubeTexture, char* FileNamePrefix, char* FileNameSuffix) { char buf[100]; wchar_t wbuf[100]; for(int i=0;i<6;i++) { sprintf(buf, "%s%i%s.png", FileNamePrefix, i, FileNameSuffix); mbstowcs( wbuf, buf, 100 ); IDirect3DSurface9* pFace; V( pCubeTexture->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &pFace) ); D3DXSaveSurfaceToFile(wbuf, D3DXIFF_PNG, pFace, NULL,NULL); } } /// \brief Calls GenerateCosTexture() if the specified texture is not yet calculated /// and stored as a texture in the cos subdirectory. void EnvMap::GenerateCosTextureIfNotFound() // precomputing geometric factors { wchar_t wCosTextureName[100]; swprintf( wCosTextureName, L"cos\\cos_s%02i.png", pp.GetInt( iShininess ) ); // try to open hr = D3DXCreateTextureFromFile( pd3dDevice, wCosTextureName, &pCosValuesTexture); if ( FAILED( hr ) ) { // generate pCosValuesTexture = GenerateCosTexture(); // save IDirect3DSurface9* pSurface = NULL; V( pCosValuesTexture->GetSurfaceLevel( 0, &pSurface ) ); D3DXSaveSurfaceToFile( wCosTextureName, D3DXIFF_PNG, pSurface, NULL,NULL); SAFE_RELEASE( pSurface ); } } /// Generates precomputed texture to store values for the reflectivity integral. Uses the eval() function. IDirect3DTexture9* EnvMap::GenerateCosTexture() { const int X = 64; const int Y = 128; IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice(); // Create a temporary texture LPDIRECT3DTEXTURE9 texTemp; V( pd3dDevice->CreateTexture( X, Y, 1, D3DUSAGE_DYNAMIC, D3DFMT_A32B32G32R32F, D3DPOOL_DEFAULT, &texTemp, NULL ) ); // Fill in the gaussian texture data D3DLOCKED_RECT Rect; V( texTemp->LockRect(0, &Rect, 0, 0) ); int u, v; float dx, dy, I; float* pBits; FILE* f = fopen( "cos_progress", "wt"); fprintf(f, ""); fclose( f ); long clock1 = clock(); //int multiplier = getMultiplier(); //float values[X*Y]; //evalAll( values ); for( v=0; v < Y; ++v ) { pBits = (float*)((char*)(Rect.pBits)+v*Rect.Pitch); for( u=0; u < X; ++u ) { dx = u/(float)X; // 0..1 dy = v/(float)Y; // 0..1 *(pBits++) = 0; // intensity *(pBits++) = eval( 2*dx-1, dy*2*3.14159f ) / 3; // old: intensity //*(pBits++) = values[ v*X + u ] / 50; // intensity *(pBits++) = 0; // intensity *(pBits++) = 0; // intensity } if ( v > 0 && v % (Y/10) == 0) { FILE* f = fopen( "cos_progress", "at"); // some silly progress bar: fprintf(f, "#"); // write a # for each 10% done fclose( f ); } } long clock2 = clock(); float time = (float)(clock2-clock1)/CLOCKS_PER_SEC; f = fopen( "cos_progress", "at"); fprintf(f, "\ntime:%.3g secs", time); fclose( f ); texTemp->UnlockRect(0); return texTemp; } /// \brief Calculates the reflectivity integral for a given texel. /// /// The angle between the surface normal and texel center is described by cos_theta /// and the solid angle occupied by the texel is denoted by dw. /// /// Instead of evaluating the reflectivity integral with only one sample belongig to the texel center /// (that would give us a result of cos_theta x dw), we use 2 #M x 2 #M x #M regulary spaced samples, and /// discard those that lie outside the unit hemisphere. The remaining samples are regulary distributed over the /// hemisphere. /// /// For each sample, we check if it lies inside the cone of the specified solid angle. /// If yes, its contribution is considered. float EnvMap::eval( float cos_theta, float dw ) { const float PI = 3.14159f; float sum = 0; int counter = 0; int shininess = pp.GetInt( iShininess ); float sin_theta = sqrt(1-cos_theta*cos_theta); D3DXVECTOR3 center( sin_theta, 0, cos_theta ); D3DXVECTOR3 up( 0, 0, 1 ); float cos_min = 1 - dw / 2 / PI; for (int x = -M; x <= M; x++) for (int y = -M; y <= M; y++) for (int z = /*-M*/ 0; z <= M; z++) // z == up { D3DXVECTOR3 w(0,0,0); w.x = x / (float)M; // -1..1 w.y = y / (float)M; // -1..1 w.z = z / (float)M; // 0..1 float len = D3DXVec3Length( &w ); if ( len > 0 && len <= 1 ) // inside the hemisphere { w /= len; // normalize float cos_curr = D3DXVec3Dot( &w, ¢er ); if ( cos_curr >= cos_min ) // w is inside the 'cone' of the given solid angle { sum += pow( D3DXVec3Dot( &w, &up ), shininess ); //sum += D3DXVec3Dot( &w, &up ); } counter++; // number of samples } } return sum * (2*PI / counter) * ((shininess+2) / PI); //return dx; }