#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" // src: DirectX Samples #define MESH2 L"Media\\Objects\\column.x" #define MESH3 L"Media\\Objects\\teapot.x" // src: DirectX Samples #define MESH4 L"Media\\Objects\\ring.x" // src: DirectX Samples #define MESH5 L"Media\\Objects\\lamp01.x" // src: 3dcafe #define MESH6 L"Media\\Objects\\happy.x" // src: Stanford Repository #define MESH7 L"Media\\Objects\\dragon.x" // src: Stanford Repository #define MESH8 L"Media\\Objects\\bunny.x" // src: Stanford Repository #define MESH9 L"Media\\Objects\\skullocc.x" // src: DirectX Samples #define TEX0 L"Media\\Maps\\white.png" #define TEX1 L"Media\\Maps\\pixel-grid-gy.png" #define TEX2 L"Media\\Maps\\fire.jpg" // src: astronomy.swin.edu.au/~pbourke/texture/fire #define ROOM_TEXTURE L"Media\\Maps\\pixel-grid-b.png" //-------------------------------------------------------------------------------------- // 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 int LR_CUBEMAP_SIZE = 2; /// Number of samples when precomputing geometric factors. //#define M 25 // for production #define M 10 // for runtime extern Parameters pp; bool bPreproc = false; float eval( float cos_theta, float dw ); float evaluate( float dx, float dy ) { return eval( 2*dx-1, dy*2*3.14159f ) / 3; } /// Called by ::OnCreateDevice() (Main.cpp) to perform app-specific tasks. void EnvMap::OnCreateDevice( IDirect3DDevice9* pd3dDevice, ID3DXEffect* g_pEffect ) { this->pd3dDevice = pd3dDevice; this->g_pEffect = g_pEffect; // init centralMesh array meshCount = 0; // room meshes[meshCount++] = new Mesh(MESH0, TEX0, 0, D3DXVECTOR3(0,0,0)); // room // meshes[meshCount++] = new Mesh(MESH1, TEX2, 0.6, D3DXVECTOR3(0,-1.7,0)); // 1 fireball meshes[meshCount++] = new Mesh(MESH1, TEX2, 0.6, D3DXVECTOR3(1.5,0,1.5)); // fireballs meshes[meshCount++] = new Mesh(MESH1, TEX2, 0.6, D3DXVECTOR3(1.5,0,-1.5)); meshes[meshCount++] = new Mesh(MESH1, TEX2, 0.6, D3DXVECTOR3(-1.5,0,1.5)); meshes[meshCount++] = new Mesh(MESH1, TEX2, 0.6, D3DXVECTOR3(-1.5,0,-1.5)); // central centralMesh centralMesh = new Mesh(MESH0, TEX0, pp.Get( fMeshScale )*2, D3DXVECTOR3(0,0,0)); centralMesh->SetContainerSize( D3DXVECTOR3(roomSize,roomSize,roomSize) ); centralMesh->SetMeshPosition( D3DXVECTOR3(-roomSize*2/3,0,0) ); ChooseMesh( pp.GetInt( iWhichMesh )); bCubeMapIsValid = false; } /// Called by ::OnDestroyDevice() (Main.cpp) to perform app-specific tasks. void EnvMap::OnDestroyDevice() { // central centralMesh delete centralMesh; // destroy centralMesh array for (int i=0; iDestroy(); delete cube; bCubeMapIsValid = false; } /// Called when the resolution of the cube maps is to change. /// To re-generate all resources, the DirectX device is simply reseted. void EnvMap::InvalidateResolution() { if (!bCubeMapIsValid) return; // don't do anything during GUI initialization // rebuild textures OnLostDevice(); // !!!!! OnResetDevice(); // !!!!! } /// Loads the specified mesh. void EnvMap::ChooseMesh(int whichMesh) { if (centralMesh == NULL) return; // redirect call from keyboard to parameter class if ( pp.GetInt( iWhichMesh ) != whichMesh) { pp.SetInt( iWhichMesh, whichMesh ); return; } switch (whichMesh) { case 0: centralMesh->Load(MESH0); break; case 1: centralMesh->Load(MESH1); break; case 2: centralMesh->Load(MESH2); break; case 3: centralMesh->Load(MESH3); break; case 4: centralMesh->Load(MESH4); break; case 5: centralMesh->Load(MESH5); break; case 6: centralMesh->Load(MESH6); break; case 7: centralMesh->Load(MESH7); break; case 8: centralMesh->Load(MESH8); break; case 9: centralMesh->Load(MESH9); break; } bCubeMapIsValid = false; // ask for cubemap redraw } /// Handles keystroke messages. void EnvMap::KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown ) { if( bKeyDown ) { bool b = pp.Get( bConfineToRoom ); float step = 0.1f; //float max = roomSize-1.02f; if ( nChar >= '0' && nChar <= '9' ) { int whichMesh = nChar-'0'; ChooseMesh(whichMesh); // load centralMesh } else switch( nChar ) { case VK_RIGHT: centralMesh->Move( D3DXVECTOR3( step,0,0), b ); break; case VK_LEFT: centralMesh->Move( D3DXVECTOR3(-step,0,0), b ); break; case VK_UP: centralMesh->Move( D3DXVECTOR3(0, step,0), b ); break; case VK_DOWN: centralMesh->Move( D3DXVECTOR3(0,-step,0), b ); break; case VK_PRIOR: centralMesh->Move( D3DXVECTOR3(0,0, step), b ); break; case VK_NEXT: centralMesh->Move( D3DXVECTOR3(0,0,-step), b ); break; case 32: bCubeMapIsValid = false; break; } // switch } } /// Performs prepocessing steps if necessary and then renders the scene. 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 // regenerate if: // - centralMesh changes // - resolution changes if ( !bCubeMapIsValid ) { long clock1 = clock(); // (to avoid warnings) V( g_pEffect->SetTexture( "EnvironmentMap", NULL ) ); D3DXVECTOR3 p = centralMesh->GetMeshPosition(); centralMesh->SetMeshPosition( D3DXVECTOR3(0,0,0) ); // 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 centralMesh->SetMeshPosition( p ); V( g_pEffect->SetFloat( "texel_size", 0 ) ); ReduceCubeMapSize( pCubeTexture, pCubeTextureSmall); bShininessIsValid = false; bCubeMapIsValid = true; } if ( !bShininessIsValid ) // refresh cos texture { if ( pp.GetInt( iWhichMethod ) == DIFFUSE_SPECULAR_CLASSIC ) { // prepare preconvolved cubemap PreConvolve(pCubeTextureSmall, pCubeTexturePreConvolved); } else { // load precomputed reflectivity integral values // or generate them if not found GenerateCosTextureIfNotFound( L"cos\\cos_s", &evaluate ); } bShininessIsValid = true; } // Render the scene DoRendering(mView, mProj); } /// Render the scene. 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", pCubeTexture ) ); V( g_pEffect->SetTexture( "SmallEnvironmentMap", pCubeTextureSmall ) ); V( g_pEffect->SetTexture( "Decoration", pCosValuesTexture ) ); V( g_pEffect->SetVector ( "eyePos", &eyePos ) ); V( g_pEffect->SetVector ( "reference_pos", &refPos ) ); V( g_pEffect->SetFloat ( "intensity", pp.Get( fIntensity ) )); V( g_pEffect->SetFloat ( "shininess", (float)pp.GetInt( iShininess ))); V( g_pEffect->SetInt ( "LR_CUBEMAP_SIZE", LR_CUBEMAP_SIZE )); // ------------------------- choose technique ------------------------- switch (pp.GetInt( iWhichMethod )) { case DIFFUSE_SPECULAR_CLASSIC: V( g_pEffect->SetTechnique( "EnvMapDiffuseClassic" ) ); V( g_pEffect->SetTexture( "PreconvolvedEnvironmentMap", pCubeTexturePreConvolved ) ); break; case DIFFUSE_SPECULAR_LOCALIZED: //V( g_pEffect->SetTechnique( "EnvMapDiffuseLocalized" ) ); char techniqueName[100]; sprintf(techniqueName, "EnvMapDiffuseLocalized%i", LR_CUBEMAP_SIZE ); V( g_pEffect->SetTechnique( techniqueName ) ); break; case DIFFUSE_SPECULAR_LOCALIZED_NEW: V( g_pEffect->SetTechnique( "EnvMapDiffuseLocalizedNew" ) ); break; case DIFFUSE_SPECULAR_LOCALIZED_P2P: V( g_pEffect->SetTechnique( "EnvMapDiffuseP2P" ) ); break; case DIFFUSE_SPECULAR_LOCALIZED_5TEX: V( g_pEffect->SetTechnique( "EnvMapDiffuseLocalized5Tex" ) ); break; case DIFFUSE_SPECULAR_LOCALIZED_ADAPT: V( g_pEffect->SetTechnique( "EnvMapDiffuseAdapt" ) ); break; } // ------------------------ end choose technique ------------------------ V( g_pEffect->Begin( &uPasses, 0 ) ); V( g_pEffect->BeginPass( 0 ) ); // csak 1 db PASS wan DrawCenterObjects( mView, mProj ); if (pp.Get( bMultipleObjects )) // draw two more object instances { double offset=1.3; D3DXVECTOR3 pos = centralMesh->GetMeshPosition(); centralMesh->SetMeshPosition( pos + D3DXVECTOR3(0,offset,0)); DrawCenterObjects( mView, mProj ); centralMesh->SetMeshPosition( pos + D3DXVECTOR3(0,-offset,0)); DrawCenterObjects( mView, mProj ); centralMesh->SetMeshPosition( pos ); } V( g_pEffect->EndPass() ); V( g_pEffect->End() ); if (pp.GetInt( iShowCubeMap ) == 3 && pp.GetInt( iWhichMethod ) != DIFFUSE_SPECULAR_CLASSIC ) pp.SetInt( iShowCubeMap, 0 ); switch (pp.GetInt( iShowCubeMap )) { case 0: break; case 1: V( g_pEffect->SetTexture( "EnvironmentMap", 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 the central diffuse/glossy object. 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 = centralMesh->GetMeshScale(); D3DXVECTOR3 offset = centralMesh->GetMeshPosition(); D3DXMATRIXA16 w, rot; D3DXMatrixRotationY( &rot, - 3.14159f / 2); if ( pp.GetInt( iWhichMesh ) == 8) // rotate the bunny for better look { D3DXMatrixRotationY( &rot, - 3.14159f); w = rot * ScaleAndOffset( scale, offset ); } else if ( pp.GetInt( iWhichMesh ) == 9) // rotate the skull for better look { D3DXMatrixRotationY( &rot, - 3.14159f / 2); w = rot * ScaleAndOffset( scale, offset ); } else w = ScaleAndOffset( scale, offset ); SetWorldViewProj( w, mView, mProj ); centralMesh->Draw(); } /// Draw environment objects. void EnvMap::DrawEnvObjects( D3DXMATRIXA16& mView, D3DXMATRIXA16& mProj ) { D3DXVECTOR4 objColor(3,3,3,1); if (bPreproc) objColor *= 5; g_pEffect->SetVector( "objColor", &objColor ); V( g_pEffect->SetFloat( "brightness", 0.0f )); g_pEffect->CommitChanges(); // meshes of the environment if (pp.Get( bShowFireballs )) { 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 ) ); // ---------------------------------------- // draw a room of size [-roomSize..roomSize] // ---------------------------------------- cube->PrepareDrawing(); D3DXVECTOR3 scale = D3DXVECTOR3(roomSize,roomSize,roomSize); SetWorldViewProj( ScaleAndOffset( scale, 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 ) )); D3DXVECTOR4 facecolors[]={D3DXVECTOR4(1,0,0,1), D3DXVECTOR4(1,0,1,1), D3DXVECTOR4(1,1,0,1), D3DXVECTOR4(0,0,1,1), D3DXVECTOR4(0,1,0,1), D3DXVECTOR4(0,1,1,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 if (i==3) objColor += D3DXVECTOR4(0.05, 0.05, 0, 1); //objColor = facecolors[i]; 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 ) ); /*// térelválasztó fal rajzolása SetWorldViewProj( ScaleAndOffset( D3DXVECTOR3(0.01,roomSizeCurr*2/3,roomSizeCurr*0.3), D3DXVECTOR3(1,-roomSizeCurr/3,0) ), mView, mProj ); objColor = D3DXVECTOR4(1.3,0,0.8, 1); g_pEffect->SetVector( "objColor", &objColor ); for( int i=0; i<6; i++ ) { cube->DrawFace(i); }*/ 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 = centralMesh->GetMeshScale(); //D3DXVECTOR3 offset = centralMesh->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 = centralMesh->GetMeshPosition(); vecEye += reference_pos; vecAt += reference_pos; D3DXMatrixLookAtLH(&mView, &vecEye, &vecAt, &vecUp); D3DXMatrixPerspectiveFovLH( &mProj, D3DX_PI/2, 1, 0.1, 100 ); bPreproc = true; DrawEnvObjects(mView, mProj); // boost lightness of the environment bPreproc = false; 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 ); } /// Downsample a cube map to resolution LR_CUBEMAP_SIZE void EnvMap::ReduceCubeMapSize(IDirect3DCubeTexture9* pSourceCube, IDirect3DCubeTexture9* pDestCube) { // get the descriptor of the source cubemap IDirect3DSurface9* pSourceFace; pSourceCube->GetCubeMapSurface((D3DCUBEMAP_FACES)0, 0, &pSourceFace); D3DSURFACE_DESC sourceDesc; pSourceFace->GetDesc( &sourceDesc ); SAFE_RELEASE( pSourceFace ); // pTexture : copy of the source cubemap's face IDirect3DTexture9* pTexture = NULL; V( D3DXCreateTexture( pd3dDevice, sourceDesc.Width, sourceDesc.Height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &pTexture ) ); IDirect3DSurface9* m_backBuffer=NULL; pd3dDevice->GetRenderTarget(0, &m_backBuffer); for(int i=0; i<6; i++) { IDirect3DSurface9* pFace; IDirect3DSurface9* pSurface; // a forrás cubemap akt. lapjának átmásolása pTexture-be V( pSourceCube->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &pFace) ); V( pTexture->GetSurfaceLevel( 0, &pSurface ) ); V( pd3dDevice->StretchRect(pFace, NULL, pSurface, NULL, D3DTEXF_NONE) ); // pTexture átadása a shadernek V( g_pEffect->SetTexture( "Decoration", pTexture ) ); // rendertarget: a cél lap IDirect3DSurface9* pDestCubeFace; V( pDestCube->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &pDestCubeFace) ); V( pd3dDevice->SetRenderTarget(0, pDestCubeFace) ); // begin drawing //V( g_pEffect->SetTechnique( "ReduceTexture" ) ); char techniqueName[100]; sprintf(techniqueName, "ReduceTexture%i", LR_CUBEMAP_SIZE ); V( g_pEffect->SetTechnique( techniqueName ) ); 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( pSurface ); SAFE_RELEASE( pFace ); SAFE_RELEASE( pDestCubeFace ); } pd3dDevice->SetRenderTarget(0,m_backBuffer); SAFE_RELEASE( pTexture ); SAFE_RELEASE( m_backBuffer ); } /// \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" ) ); char techniqueName[100]; sprintf(techniqueName, "Convolution%i", LR_CUBEMAP_SIZE ); V( g_pEffect->SetTechnique( techniqueName ) ); 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::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( wchar_t* fileName, eval_fn evaluator ) // precomputing geometric factors { wchar_t wCosTextureName[100]; swprintf( wCosTextureName, L"%s%02i.png", fileName, pp.GetInt( iShininess ) ); // try to open hr = D3DXCreateTextureFromFile( pd3dDevice, wCosTextureName, &pCosValuesTexture); if ( FAILED( hr ) ) { wchar_t buf[ 400 ]; swprintf( buf, L"Preprocessed texture not found!\n" L"The program will generate the following texture:\n" L"Texture name: %s\n" L"Shininess: %i\n" L"Iterations: %i (%i%% of the original texture quality).", wCosTextureName, pp.GetInt( iShininess ), M*M, 100 * M*M/25/25 ); MessageBox( NULL, buf, L"Texture not found!", MB_ICONINFORMATION ); // show message // generate pCosValuesTexture = GenerateCosTexture( evaluator ); // save IDirect3DSurface9* pSurface = NULL; V( pCosValuesTexture->GetSurfaceLevel( 0, &pSurface ) ); hr = D3DXSaveSurfaceToFile( wCosTextureName, D3DXIFF_PNG, pSurface, NULL,NULL); if ( FAILED( hr ) ) { swprintf( buf, L"Failed to save texture %s!", wCosTextureName ); MessageBox( NULL, buf, L"Texture saving failed!", MB_ICONERROR ); } SAFE_RELEASE( pSurface ); } } /// Generates precomputed texture to store values for the reflectivity integral. Uses the eval() function. IDirect3DTexture9* EnvMap::GenerateCosTexture( eval_fn evaluator ) { const int X = 128; 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 ) ); D3DLOCKED_RECT Rect; V( texTemp->LockRect(0, &Rect, 0, 0) ); int u, v; float dx, dy, I; float* pBits; FILE* f = fopen( ".progress_bar", "wt"); fprintf(f, ""); fclose( f ); long clock1 = clock(); 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++) = eval( 2*dx-1, dy*2*3.14159f ) / 3; // old: intensity //*(pBits++) = values[ v*X + u ] / 50; // intensity float result = evaluator( dx, dy ); *(pBits++) = result; // intensity *(pBits++) = result; // intensity *(pBits++) = result; // intensity *(pBits++) = 0; // intensity } if ( v > 0 && v % (Y/10) == 0) { FILE* f = fopen( ".progress_bar", "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( ".progress_bar", "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 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; }