#include "dxstdafx.h" #include ".\pathmapeffect.h" #include "Material.hpp" #include "TexturedMaterial.h" #include "WoodMaterial.hpp" #include "TriangleMesh.h" #include "Transformed.h" #include "shlwapi.h" #include #include #define TEST_CLUST 0 //#define GENERATE_PATH_MAPS //! D3D vector-matrix multiplication D3DVECTOR operator *(const D3DVECTOR& v, const D3DMATRIX& m) { D3DVECTOR r; r.x = v.x * m._11 + v.y * m._21 + v.z * m._31 + m._41; r.y = v.x * m._12 + v.y * m._22 + v.z * m._32 + m._42; r.z = v.x * m._13 + v.y * m._23 + v.z * m._33 + m._43; float h = v.x * m._14 + v.y * m._24 + v.z * m._34 + m._44; if(h > 0.00001f || h < 0.00001f) { r.x /= h; r.y /= h; r.z /= h; } return r; } //! method name strings to be displayed on screen const wchar_t* PathMapEffect::Method::methodNames[10] = { L"PRM", L"PRM texture", L"_", L"_" , NULL, NULL, NULL, NULL, NULL, NULL }; //! method constants const PathMapEffect::Method PathMapEffect::Method::PRM(0); const PathMapEffect::Method PathMapEffect::Method::SHOWTEX(1); const PathMapEffect::Method PathMapEffect::Method::LAST(2); //! constructor PathMapEffect::PathMapEffect(LPDIRECT3DDEVICE9 device) :method(Method::PRM) { rayId = 1; this->device = device; //first person camera allows more freedom of movement camera = new CFirstPersonCamera(); lightCamera = new CFirstPersonCamera(); HRESULT hr; DWORD effectCompileFlag=0; LPD3DXBUFFER compilationErrors; if(FAILED( hr = D3DXCreateEffectFromFile( device, L"pathMap.fx", NULL, NULL, 0, NULL, &effect, &compilationErrors) )){ MessageBoxA( NULL, (LPSTR)compilationErrors->GetBufferPointer(), "Failed to load effect file!", MB_OK); exit(-1); } //store buffers so we can reset them after rendering to texture render targets device->GetRenderTarget(0, &frameColorBuffer); device->GetDepthStencilSurface(&frameDepthStencilBuffer); //load empty texture D3DXCreateTextureFromFile(device, L"media\\empty.bmp", &emptyTexture); //set up a scene loadScene("media\\level.txt"); //load hangar mesh loadMesh( L"media\\hangar.x" ); // loadMesh( L"media\\fulltexchamber.x" ); /* //create hangar entity Entity e1; e1.owner = this; e1.renderMesh = renderMeshes.at(0); D3DXMatrixIdentity(&e1.modelWorldTransform); // D3DXMatrixScaling(&e1.modelWorldTransform, 20.0f, 20.0f, 20.0f); D3DXMatrixScaling(&e1.modelWorldTransform, 0.5f, 1.0f, 0.5f); D3DXMatrixIdentity(&e1.inverseTransposedModelWorldTransform); // D3DXMatrixScaling(&e1.inverseTransposedModelWorldTransform, 1.0f/20.0f, 1.0f/20.0f, 1.0f/20.0f); D3DXMatrixScaling(&e1.inverseTransposedModelWorldTransform, 1.0f/0.5f, 1.0f, 1.0f/0.5f); e1.createRayTraceEntity(); entities.push_back(e1); //load 'steps' mesh loadMesh( L"media\\steps.x" ); //create step entities for(int eitor=0; eitor < 4; eitor++) { D3DXMATRIX urr; D3DXMATRIX rx; D3DXMatrixRotationY(&rx, Vector::PI * 0.5f * eitor); Entity e2; e2.owner = this; e2.renderMesh = renderMeshes.at(1); D3DXMatrixTranslation(&urr, -15.0f, -14.0f, -7.0f); D3DXMatrixMultiply( &e2.modelWorldTransform, &urr, &rx); D3DXMatrixInverse(&e2.inverseTransposedModelWorldTransform, NULL, &e2.modelWorldTransform); e2.createRayTraceEntity(); entities.push_back(e2); D3DXMATRIX trasi, roti; D3DXMatrixTranslation(&trasi, -15.0f + 7.0f, 14.0f, -7.0f -7.0f); //7.25f, 13.5, -7.25); //rot 90 -90 90 trans 7.25 13.5 -7.25 D3DXMatrixRotationYawPitchRoll(&roti, -Vector::PI * 0.5, Vector::PI, 0.0); D3DXMatrixMultiply(&urr, &roti, &trasi); D3DXMatrixMultiply( &e2.modelWorldTransform, &urr, &rx); D3DXMatrixInverse(&e2.inverseTransposedModelWorldTransform, NULL, &e2.modelWorldTransform); e2.createRayTraceEntity(); entities.push_back(e2); } */ /* for(int eitor=0; eitor < 6; eitor++) { Entity e2; e2.owner = this; e2.renderMesh = renderMeshes.at(1); D3DXMatrixIdentity(&e2.modelWorldTransform); D3DXMatrixScaling(&e2.modelWorldTransform, -0.5, 0.5, -0.5); D3DXMATRIX trmx; D3DXMatrixTranslation(&trmx, -8.0 + eitor * 2.8f, -3.2f, -8.6f + eitor * 0.6f); e2.modelWorldTransform *= trmx; D3DXMatrixIdentity(&e2.inverseTransposedModelWorldTransform); D3DXMatrixScaling(&e2.inverseTransposedModelWorldTransform, -2.0, 2.0, -2.0); D3DXMatrixTranslation(&trmx, +8.0 - eitor * 2.8f, 3.2f, 8.6f - eitor * 0.6f); e2.inverseTransposedModelWorldTransform *= trmx; e2.createRayTraceEntity(); entities.push_back(e2); }*/ loadMesh( L"media\\torch.x" ); //compute the surface area of the complete geometry. useful for random sampling. sumSurfaceArea = 0.0; std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { sumSurfaceArea += entityIterator->rayTraceEntity->getSurfaceArea(); entityIterator++; } //initialize camera camera->SetViewParams( &D3DXVECTOR3(0.0f, 0.0f, 4.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f)); D3DSURFACE_DESC fbdesc; frameColorBuffer->GetDesc(&fbdesc); camera->SetProjParams( D3DX_PI/2, (float)fbdesc.Width / fbdesc.Height, 0.1f, 300.0f ); //create resources for entities createPRMTextures(); //set up spotlight lightCamera->SetViewParams( &D3DXVECTOR3(5.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f)); lightCamera->SetProjParams( D3DX_PI/1.9, 1.0f, 0.1f, 300.0f ); //create ray tracing kd-tree containing ray-traceable versions of entities Intersectable** objs = new Intersectable*[entities.size()]; for(int u=0; uCreateTexture(DEPTHMAPRES, DEPTHMAPRES, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R32F, D3DPOOL_DEFAULT, &fakeTexture, NULL); fakeTexture->GetSurfaceLevel(0, &fakeSurface); //create a depthstencil texture for depth map rendering device->CreateTexture(DEPTHMAPRES, DEPTHMAPRES, 1, D3DUSAGE_DEPTHSTENCIL, D3DFMT_D24X8, D3DPOOL_DEFAULT, &depthMapTexture, NULL); depthMapTexture->GetSurfaceLevel(0, &depthMapDepthStencilBuffer); //create a stencil surface for PRM rendering (to avoid blend-adding to the same pixel for the same lightsource muliple times) device->CreateDepthStencilSurface(128 * 32, 128 * NCLUSTERSPERENTITY / 32, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, true, &prmBlendingDepthStencilBuffer, NULL); #ifdef GENERATE_PATH_MAPS precompute(); #else loadPathMaps(); #endif //create a texture for radion data (will be used for weight computations on the GPU) device->CreateTexture(2 * NRADIONS / 4096, 4096, 1, 0, D3DFMT_A32B32G32R32F, D3DPOOL_DEFAULT, &radionTexture, NULL); radionTexture->GetSurfaceLevel(0, &radionSurface); //fill texture with data uploadRadions(); //create weights render target device->CreateTexture(4096, NRADIONS / 4096, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R32F, D3DPOOL_DEFAULT, &weightsTexture, NULL); weightsTexture->GetSurfaceLevel(0, &weightsSurface); //create a sytem memory duplicate of the weights render target to be able to read back weights data device->CreateTexture(4096, NRADIONS / 4096, 1, 0, D3DFMT_R32F, D3DPOOL_SYSTEMMEM, &sysMemWeightsTexture, NULL); sysMemWeightsTexture->GetSurfaceLevel(0, &sysMemWeightsSurface); //create a vertex buffer to be able to visualize entry radion positions device->CreateVertexBuffer(NRADIONS * sizeof(float) * 6, D3DUSAGE_WRITEONLY, D3DFVF_XYZ | D3DFVF_NORMAL, D3DPOOL_DEFAULT, &starterVertexBuffer, NULL); void* pData; starterVertexBuffer->Lock(0, 0, &pData, 0); fillRadionPosArray(pData); starterVertexBuffer->Unlock(); exportEntityData(); #ifdef GENERATE_PATH_MAPS savePathMaps(); #endif } PathMapEffect::~PathMapEffect(void) { //release all resources allocated in the constructor starterVertexBuffer->Release(); depthMapTexture->Release(); depthMapDepthStencilBuffer->Release(); fakeTexture->Release(); fakeSurface->Release(); sysMemWeightsTexture->Release(); sysMemWeightsSurface->Release(); weightsTexture->Release(); weightsSurface->Release(); radionTexture->Release(); radionSurface->Release(); prmBlendingDepthStencilBuffer->Release(); delete kdtree; emptyTexture->Release(); releaseTextures(); releaseMeshes(); releaseEntities(); frameColorBuffer->Release(); frameDepthStencilBuffer->Release(); effect->Release(); delete camera; delete lightCamera; } void PathMapEffect::loadMesh(LPCWSTR fileName) { RenderMesh* renderMesh = new RenderMesh(); if(S_OK != D3DXLoadMeshFromX( fileName, D3DXMESH_MANAGED, device, NULL, &renderMesh->materialBuffer, NULL, (DWORD*)&renderMesh->nSubsets, &renderMesh->mesh)) { MessageBox(NULL, fileName, L"Could not load mesh file!", MB_OK); return; } //convert mesh into a vertex format using a position, a normal and a texture register //this is the only data our vertex shaders will require renderMesh->setVertexFormat(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1, device); //extract the D3DXMATERIAL* pointer from the generic D3DXBUFFER renderMesh->materials = (D3DXMATERIAL*)renderMesh->materialBuffer->GetBufferPointer(); //for every material, load the specified texture renderMesh->textures = new LPDIRECT3DTEXTURE9[renderMesh->nSubsets]; for(unsigned int i=0; inSubsets; i++) { wchar_t* wideTextureFileName = NULL; if(renderMesh->materials[i].pTextureFilename) { wideTextureFileName = new wchar_t[MultiByteToWideChar(CP_ACP, 0, renderMesh->materials[i].pTextureFilename, -1, NULL, 0)]; MultiByteToWideChar(CP_ACP, 0, renderMesh->materials[i].pTextureFilename, -1, wideTextureFileName, 511); } renderMesh->textures[i] = loadTexture( wideTextureFileName ); if(wideTextureFileName) delete wideTextureFileName; } //lock the buffers and create ray tracing meshes from the data LPDIRECT3DVERTEXBUFFER9 vertexBuffer; renderMesh->mesh->GetVertexBuffer(&vertexBuffer); D3DVERTEX* vertexData; vertexBuffer->Lock(0,renderMesh->mesh->GetNumVertices()*renderMesh->mesh->GetNumBytesPerVertex(),(void**)&vertexData,0); LPDIRECT3DINDEXBUFFER9 indexBuffer; renderMesh->mesh->GetIndexBuffer(&indexBuffer); unsigned short* indexData; indexBuffer->Lock(0,renderMesh->mesh->GetNumFaces()*3*sizeof(unsigned short),(void**)&indexData,0); //create a ray-tracing Material for the texture if(renderMesh->textures[0]) { D3DLOCKED_RECT lrect; HRESULT hr = renderMesh->textures[0]->LockRect(0, &lrect, NULL, D3DLOCK_READONLY); LPDIRECT3DSURFACE9 texsurf; renderMesh->textures[0]->GetSurfaceLevel(0, &texsurf); D3DSURFACE_DESC desc; texsurf->GetDesc(&desc); renderMesh->rayTraceMaterial = new TexturedMaterial(lrect.pBits, lrect.Pitch, desc.Width); texsurf->Release(); renderMesh->textures[0]->UnlockRect(0); } else renderMesh->rayTraceMaterial = new Material(Vector(1.0f, 1.0f, 1.0f), Vector(0.0f, 0.0f, 0.0f), 1.0); //create a TriangleMesh for ray-tracing renderMesh->rayTraceMesh = new TriangleMesh(renderMesh->rayTraceMaterial, indexData, renderMesh->mesh->GetNumFaces(), vertexData, renderMesh->mesh->GetNumVertices()); vertexBuffer->Unlock(); indexBuffer->Unlock(); vertexBuffer->Release(); indexBuffer->Release(); //generate edge lines for seamless texture atlas rendering renderMesh->buildEdgeVertexBuffer(device); //store completed mesh renderMeshes.push_back(renderMesh); } LPDIRECT3DTEXTURE9 PathMapEffect::loadTexture(LPCWSTR fileName) { if(fileName == NULL || wcscmp(fileName, L"") == 0) return NULL; wchar_t* mediaFileName = new wchar_t[wcslen(fileName) + 64]; //we assume the x file was in folder .\media wcscpy(mediaFileName, L"media\\"); wcscat(mediaFileName, fileName); LPDIRECT3DTEXTURE9 tex; D3DXIMAGE_INFO bobo; if(S_OK != D3DXCreateTextureFromFileEx(device, mediaFileName, D3DX_DEFAULT, D3DX_DEFAULT, 1, 0, D3DFMT_FROM_FILE, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, &bobo, NULL, &tex )) { MessageBox(NULL, mediaFileName, L"Could not load texture file!", MB_OK); return NULL; } materialTextures.push_back(tex); return tex; } void PathMapEffect::releaseTextures() { std::vector::iterator i = materialTextures.begin(); while(i != materialTextures.end()) { (*i)->Release(); i++; } } void PathMapEffect::releaseMeshes() { std::vector::iterator i = renderMeshes.begin(); while(i != renderMeshes.end()) { (*i)->mesh->Release(); (*i)->materialBuffer->Release(); delete (*i)->rayTraceMesh; delete (*i)->rayTraceMaterial; if((*i)->edgeVertexBuffer) (*i)->edgeVertexBuffer->Release(); delete *i; i++; } } void PathMapEffect::renderWithPRM() { // first pass: render depth device->SetRenderTarget(0, fakeSurface); device->SetDepthStencilSurface(depthMapDepthStencilBuffer); device->Clear( 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(255, 0, 0, 0), 1.0f, 0 ); //no color writes device->SetRenderState(D3DRS_COLORWRITEENABLE, 0); //render back faces (avoids Z-fighting, no need for comparison bias) device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); if( SUCCEEDED( device->BeginScene() ) ) { effect->SetTechnique("Depth"); UINT nPasses; effect->Begin(&nPasses, 0); effect->BeginPass(0); //loop through all entities, all mesh subsets, set proper transformations std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { effect->SetMatrix("modelToProjMatrix", &( entityIterator->modelWorldTransform * *lightCamera->GetViewMatrix() * *lightCamera->GetProjMatrix() ) ); effect->CommitChanges(); unsigned int nSubsets = entityIterator->renderMesh->nSubsets; for(int i = 0; i< nSubsets; i++) { entityIterator->renderMesh->mesh->DrawSubset(i); } entityIterator++; } effect->EndPass(); effect->End(); device->EndScene(); } //reset front face rendering, color writes device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); HRESULT hr = S_OK; hr = device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA| D3DCOLORWRITEENABLE_BLUE| D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); // 2. pass: compute weights // simple parallel computation for all pixels: no 3D, depth, shadows, only a full-texture quad hr = device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); hr = device->SetRenderState(D3DRS_STENCILENABLE, false); hr = device->SetRenderTarget(0,weightsSurface); hr = device->SetDepthStencilSurface(NULL); D3DXVECTOR3 lightPos = *lightCamera->GetEyePt(); D3DXVECTOR3 lightDir = *lightCamera->GetWorldAhead(); lightDir /= D3DXVec3Length( &lightDir ); float ffl = parameters->Get(fLightScale) * 100.0f; D3DXVECTOR3 lightPower(ffl, ffl, ffl); device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 ); if( SUCCEEDED( device->BeginScene() ) ){ if( effect != NULL ){ D3DXHANDLE hTechnique = NULL; hTechnique = effect->GetTechniqueByName((LPSTR)"ComputeWeights"); if(hTechnique==NULL){ return; } effect->SetTechnique( hTechnique ); UINT nPasses = 0; effect->Begin( &nPasses, 0 ); for(UINT j=0;jBeginPass(j); hr = effect->SetTexture("radions", radionTexture); static float opttme[9] = {0.5f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f, 0.5f + (0.5f / DEPTHMAPRES), 0.5f + (0.5f / DEPTHMAPRES), 1.0f}; //set global params effect->SetFloatArray("occProjToTexMatrix", opttme, 9); effect->SetMatrix("occWorldToProjMatrix", &(*lightCamera->GetViewMatrix() * *lightCamera->GetProjMatrix())); effect->SetTexture("depthMap", depthMapTexture); hr = effect->SetInt("nRadionColumns", NRADIONS / 4096); hr = effect->SetFloatArray("lightPower", (float*)&lightPower, 3); hr = effect->SetFloatArray("lightPos", (float*)&lightPos, 3); hr = effect->SetFloatArray("lightDir", (float*)&lightDir, 3); effect->CommitChanges(); drawFullScreenQuad(device); effect->EndPass(); } effect->End(); } device->EndScene(); } // read the weights back D3DLOCKED_RECT rData; hr = device->GetRenderTargetData(weightsSurface, sysMemWeightsSurface); hr = sysMemWeightsSurface->LockRect(&rData, NULL, D3DLOCK_READONLY); float* allEntryWeights = (float*)rData.pBits; // average weights per cluster float sumWeightsAll = 0.0; unsigned int iRadion = 0; for(int iCluster=0; iCluster < NCLUSTERS; iCluster++) { weights[iCluster] = 0.0; float clusterrad = 0.0; for(int clusterSummer=0; clusterSummer < clusterLenghts[iCluster]; clusterSummer++, iRadion++) { float radrad = bushStarters[iRadion].radiance.sum(); weights[iCluster] += allEntryWeights[iRadion] * radrad; clusterrad += radrad; } weights[iCluster] /= clusterrad; //(double)clusterLenghts[iCluster]; // if(iCluster != TEST_CLUST) // weights[iCluster] = 0.0; // if(weights[iCluster] > 0.005) // weights[iCluster] = 0.005; sumWeightsAll += weights[iCluster]; } sysMemWeightsSurface->UnlockRect(); // 3. pass: render scene using weights to combine PRM texture atlases device->SetRenderTarget(0, frameColorBuffer); device->SetDepthStencilSurface(frameDepthStencilBuffer); // use backface culling, depth test hr = device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); hr = device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); device->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 ); if( SUCCEEDED( device->BeginScene() ) ) { effect->SetTechnique("walk"); UINT nPasses; effect->Begin(&nPasses, 0); effect->BeginPass(0); static float opttme[9] = {0.5f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f, 0.5f + (0.5f / DEPTHMAPRES), 0.5f + (0.5f / DEPTHMAPRES), 1.0f}; //set global params effect->SetFloatArray("occProjToTexMatrix", opttme, 9); effect->SetMatrix("occWorldToProjMatrix", &(*lightCamera->GetViewMatrix() * *lightCamera->GetProjMatrix())); effect->SetTexture("depthMap", depthMapTexture); //loop through entities std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { //set entity params // nearestIdx -> bushId float weightsa[NCLUSTERSPERENTITY]; for(unsigned int y=0; ynearClusterIndices[y]]; hr = effect->SetFloatArray("weightsa", weightsa, NCLUSTERSPERENTITY); effect->SetMatrix("modelToWorldMatrix", &entityIterator->modelWorldTransform); effect->SetMatrix("inverseTransposedModelToWorldMatrix", &entityIterator->inverseTransposedModelWorldTransform); D3DXMATRIX t = entityIterator->modelWorldTransform; if(parameters->Get(bLookFromLight)) effect->SetMatrix("modelToProjMatrix", &(entityIterator->modelWorldTransform * *lightCamera->GetViewMatrix() * *lightCamera->GetProjMatrix() )); else effect->SetMatrix("modelToProjMatrix", &(entityIterator->modelWorldTransform * *camera->GetViewMatrix() * *camera->GetProjMatrix() )); effect->SetTexture("filteredAtlas", entityIterator->prmTexture); hr = effect->SetFloatArray("lightPower", (float*)&lightPower, 3); hr = effect->SetFloatArray("lightPos", (float*)&lightPos, 3); hr = effect->SetFloatArray("lightDir", (float*)&lightDir, 3); unsigned int nSubsets = entityIterator->renderMesh->nSubsets; for(int i = 0; i< nSubsets; i++) { //set subset material texture if(entityIterator->renderMesh->textures[i]) effect->SetTexture("brdfMap", entityIterator->renderMesh->textures[i]); else effect->SetTexture("brdfMap", emptyTexture); effect->CommitChanges(); entityIterator->renderMesh->mesh->DrawSubset(i); } entityIterator++; } effect->EndPass(); effect->End(); device->EndScene(); } if(!parameters->Get(bLookFromLight)) if( SUCCEEDED( device->BeginScene() ) ) { effect->SetTechnique("torch"); UINT nPasses; effect->Begin(&nPasses, 0); effect->BeginPass(0); effect->SetMatrix("modelToProjMatrix", &(*lightCamera->GetWorldMatrix() * *camera->GetViewMatrix() * *camera->GetProjMatrix() )); effect->CommitChanges(); renderMeshes[renderMeshes.size()-1]->mesh->DrawSubset(0); effect->EndPass(); effect->End(); device->EndScene(); } } HRESULT PathMapEffect::RenderMesh::setVertexFormat(DWORD fvf, LPDIRECT3DDEVICE9 device) { LPD3DXMESH tempMesh; //clone the mesh to the appropriate format HRESULT hr = mesh->CloneMeshFVF( mesh->GetOptions(), fvf , device, &tempMesh ); if(hr == S_OK) { DWORD* padj = new DWORD[mesh->GetNumFaces() * 3]; mesh->GenerateAdjacency(0.00001f, padj); delete padj; //forget he old mesh mesh->Release(); //use the cloned mesh mesh = tempMesh; } return hr; } void PathMapEffect::renderFullScreen(float depth) { float fLeftU = 0.0f, fTopV = 0.0f, fRightU = 1.0f, fBottomV = 1.0f; D3DSURFACE_DESC dtdsdRT; PDIRECT3DSURFACE9 pSurfRT; // Acquire render target width and height device->GetRenderTarget(0, &pSurfRT); pSurfRT->GetDesc(&dtdsdRT); pSurfRT->Release(); // Ensure that we're directly mapping texels to pixels by offset by 0.5 // For more info see the doc page titled "Directly Mapping Texels to Pixels" FLOAT fWidth5 = (FLOAT)dtdsdRT.Width - 0.5f; FLOAT fHeight5 = (FLOAT)dtdsdRT.Height - 0.5f; // Draw the quad struct D3DVERTEX{ D3DXVECTOR3 pos; D3DXVECTOR2 tex0; }; D3DVERTEX svQuad[4]; svQuad[0].pos=D3DXVECTOR3(-1, 1, depth); svQuad[0].tex0 = D3DXVECTOR2(fLeftU, fTopV); svQuad[1].pos = D3DXVECTOR3(1, 1, depth); svQuad[1].tex0 = D3DXVECTOR2(fRightU, fTopV); svQuad[2].pos = D3DXVECTOR3(-1, -1, depth); svQuad[2].tex0 = D3DXVECTOR2(fLeftU, fBottomV); svQuad[3].pos = D3DXVECTOR3(1, -1, depth); svQuad[3].tex0 = D3DXVECTOR2(fRightU, fBottomV); device->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE); device->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)); device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, svQuad, sizeof(D3DVERTEX)); } void PathMapEffect::move(float fElapsedTime) { //apply some rotation to one of the entities if(parameters->Get(bTurbo)) { camera->FrameMove(fElapsedTime * 10.0f); lightCamera->FrameMove(fElapsedTime * 10.0f); } else { camera->FrameMove(fElapsedTime); lightCamera->FrameMove(fElapsedTime); } /* D3DXMATRIX rot; D3DXMatrixRotationY(&rot, fElapsedTime * 0.1f); D3DXMatrixMultiply( &entities.at(0).modelWorldTransform, &rot, &entities.at(0).modelWorldTransform); D3DXMatrixInverse( &entities.at(0).inverseTransposedModelWorldTransform, NULL, &entities.at(0).modelWorldTransform); D3DXMatrixTranspose( &entities.at(0).inverseTransposedModelWorldTransform, &entities.at(0).inverseTransposedModelWorldTransform); if(entities.size() > 1) { D3DXMatrixTranslation(&entities.at(1).modelWorldTransform, 0.0f, parameters->Get(fSecondModelHeight) * 5.0f , 0.0f); D3DXMatrixTranslation(&entities.at(1).inverseTransposedModelWorldTransform, 0.0f, -parameters->Get(fSecondModelHeight) * 5.0f , 0.0f); }*/ } LRESULT PathMapEffect::handleMessage( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if(parameters->Get(bMoveLight)) return lightCamera->HandleMessages(hWnd, uMsg, wParam, lParam); else return camera->HandleMessages(hWnd, uMsg, wParam, lParam); } void PathMapEffect::addUiParameters(Parameters* parameters) { PathMapEffect::parameters = parameters; parameters->Add( bLookFromLight, "Look from light", 1); parameters->Add( bMoveLight, "Move light", 1); parameters->Add( bDots, "Entry points", 1); parameters->Add( bTurbo, "Turbo", 1); parameters->Add( fLightScale, "Tone scale", 100, 'V', 'B', convert100); } void PathMapEffect::setUiParameterDefaults(Parameters* parameters) { } Parameters* PathMapEffect::parameters = NULL; void PathMapEffect::render() { if(method == Method::PRM) renderWithPRM(); else showPRMTexture(); if(parameters->Get(bDots)) { float psf = 8.0f; HRESULT hr = device->SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&psf)); hr = device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); if( SUCCEEDED( device->BeginScene() ) ) { D3DXHANDLE hTechnique = NULL; hTechnique = effect->GetTechniqueByName((LPSTR)"Dots"); effect->SetTechnique( hTechnique ); UINT nPasses = 0; effect->Begin( &nPasses, 0 ); for(UINT j=0;jBeginPass(j); hr = effect->SetTexture("depthMap",depthMapTexture); if(parameters->Get(bLookFromLight)) effect->SetMatrix("worldToProjMatrix", &(*lightCamera->GetViewMatrix() * *lightCamera->GetProjMatrix() )); else effect->SetMatrix("worldToProjMatrix", &(*camera->GetViewMatrix() * *camera->GetProjMatrix() )); static float opttme[9] = {0.5f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f, 0.5f + (0.5f / DEPTHMAPRES), 0.5f + (0.5f / DEPTHMAPRES), 1.0f}; effect->SetFloatArray("occProjToTexMatrix", opttme, 9); D3DXVECTOR3 lightPos = *lightCamera->GetEyePt(); hr = effect->SetFloatArray("lightPos", (float*)&lightPos, 3); effect->CommitChanges(); hr = device->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL); hr = device->SetStreamSource(0, starterVertexBuffer, 0, sizeof(float) * 6); UINT offset = 0; for(int iClusterDraw=0; iClusterDraw < NCLUSTERS; iClusterDraw++) { hr = effect->SetFloat("aClusterWeight", weights[iClusterDraw] * 10.0); effect->CommitChanges(); // if(iClusterDraw == TEST_CLUST) device->DrawPrimitive(D3DPT_POINTLIST, offset, clusterLenghts[iClusterDraw]); offset += clusterLenghts[iClusterDraw]; } effect->EndPass(); } effect->End(); } device->EndScene(); } } void PathMapEffect::Entity::createRayTraceEntity() { rayTraceEntity = new Transformed(renderMesh->rayTraceMesh); rayTraceEntity->setTransforms(modelWorldTransform, inverseTransposedModelWorldTransform); } void PathMapEffect::releaseEntities() { std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { delete entityIterator->rayTraceEntity; entityIterator->prmSurface->Release(); entityIterator->prmTexture->Release(); entityIterator++; } } void PathMapEffect::sampleSphereDirection(Vector& outDir) { do{ outDir = Vector(-1.0 + 2.0 * (float)rand() / RAND_MAX, -1.0 + 2.0 * (float)rand() / RAND_MAX, -1.0 + 2.0 * (float)rand() / RAND_MAX); }while(outDir.norm2() > 1.0); outDir.normalize(); } void PathMapEffect::sampleShootingDiffuseDirection(int depth, const Vector& normal, Vector& outDir) { Vector u, v; if(fabsf(normal[0]) < 0.9f) { u.set(0.0f, -normal[2], normal[1]); u *= 1.0f / sqrtf(normal[2] * normal[2] + normal[1] * normal[1]); } else { u.set(normal[2], 0.0f, -normal[0]); u *= 1.0f / sqrtf(normal[2] * normal[2] + normal[0] * normal[0]); } v.setCrossProduct(normal, u); float phi = 2.0f * 3.14159265358979323846f * (float)rand() / RAND_MAX; float xi2 = (float)rand() / RAND_MAX; float cosPhi = cos(phi); float sinPhi = sin(phi); float cosTheta = sqrtf(xi2); float sinTheta = sqrtf(1.0f - xi2); outDir.setScaled(sinTheta * cosPhi, v); outDir.addScaled(sinTheta * sinPhi, u); outDir.addScaled(cosTheta, normal); } void PathMapEffect::createPRMTextures() { std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { device->CreateTexture(128 * 32, 128 * NCLUSTERSPERENTITY / 32, 1, D3DUSAGE_RENDERTARGET,D3DFMT_A16B16G16R16F,D3DPOOL_DEFAULT,&entityIterator->prmTexture,NULL); entityIterator->prmTexture->GetSurfaceLevel(0,&entityIterator->prmSurface); entityIterator++; } } void PathMapEffect::precompute() { // generate entry points for(unsigned int cRad=0; cRad < NRADIONS; cRad++) { Radion starter; sampleSurfaceRadion(starter); //sampleSurfaceRadionUniform(starter); bushStarters.push_back(starter); } // sort entry radions into clusters Radion* entryArray = (Radion*)&*bushStarters.begin(); clusterRadions(entryArray, bushStarters.size(), 0); clusterRadionsKMeans(); // for every entity, find the most relevant clusters std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { entityIterator->findNearClusters(bushStarters, NCLUSTERS); entityIterator++; } // for every entry radion, shoot a bush of radions, and add their // contributions to all PRMs of all entities unsigned int iCluster = 0; std::vector bushRadions; for(int iStarter = 0; iStarter < NRADIONS; ) { bushRadions.clear(); for(int iric=0; iric < clusterLenghts[iCluster]; iric++, iStarter++) shootRadionBush(bushStarters[iStarter], bushRadions); std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { entityIterator->renderPRM(device, effect, bushRadions, iCluster, 1.0); entityIterator++; } iCluster++; } } int compareX(const void* a, const void* b) { if( ((const Radion*)a)->position.x < ((const Radion*)b)->position.x ) return -1; else return 1; } int compareY(const void* a, const void* b) { if( ((const Radion*)a)->position.y < ((const Radion*)b)->position.y ) return -1; else return 1; } int compareZ(const void* a, const void* b) { if( ((const Radion*)a)->position.z < ((const Radion*)b)->position.z ) return -1; else return 1; } int compareDirX(const void* a, const void* b) { if( ((const Radion*)a)->normal.x < ((const Radion*)b)->normal.x ) return -1; else return 1; } int compareDirY(const void* a, const void* b) { if( ((const Radion*)a)->normal.y < ((const Radion*)b)->normal.y ) return -1; else return 1; } int compareDirZ(const void* a, const void* b) { if( ((const Radion*)a)->normal.z < ((const Radion*)b)->normal.z ) return -1; else return 1; } void PathMapEffect::clusterRadionsKMeans() { Radion centroids[NCLUSTERS]; std::vector clusters[NCLUSTERS]; //initial clusters: uniform length for(unsigned int i=0; i> 1; clusterLenghts[i-1] -= clusterLenghts[i-1] >> 1; } } for(int i=NCLUSTERS - 1; i >= 0; i--) { if(clusterLenghts[i] == 0) { clusterLenghts[i] = clusterLenghts[i+1] >> 1; clusterLenghts[i+1] -= clusterLenghts[i+1] >> 1; } } } } int PathMapEffect::clusterRadions(Radion* partition, int psize, char axis) { /* if(psize < 2) return 1; if(axis == 0) qsort(partition, psize, sizeof(Radion), compareDirX); else if(axis == 1) qsort(partition, psize, sizeof(Radion), compareDirY); else if(axis == 2) qsort(partition, psize, sizeof(Radion), compareDirZ); else if(axis == 3) qsort(partition, psize, sizeof(Radion), compareX); else if(axis == 4) qsort(partition, psize, sizeof(Radion), compareY); else if(axis == 5) qsort(partition, psize, sizeof(Radion), compareZ); clusterRadions(partition, psize >> 1, (axis+1)%6); clusterRadions(partition + (psize >> 1), psize - (psize >> 1), (axis+1)%6); return 1; /*/ if(psize < 2) return 1; if(axis == 0) qsort(partition, psize, sizeof(Radion), compareX); else if(axis == 1) qsort(partition, psize, sizeof(Radion), compareY); else if(axis == 2) qsort(partition, psize, sizeof(Radion), compareZ); clusterRadions(partition, psize >> 1, (axis+1)%3); clusterRadions(partition + (psize >> 1), psize - (psize >> 1), (axis+1)%3); return 1;//*/ } void PathMapEffect::shootRadionBush(Radion& starter, std::vector& bushRadions) { bushRadions.push_back(starter); int nPhotonsShotForLight = 1; //branching factor for(int iPhoton = 0; iPhoton < nPhotonsShotForLight; iPhoton++) { unsigned int depth = 0; ray.id = rayId++; ray.isShadowRay = false; ray.origin = starter.position; Vector power = starter.radiance; float prob = starter.probability; prob *= nPhotonsShotForLight; power *= 1.0f / nPhotonsShotForLight; sampleShootingDiffuseDirection(depth, starter.normal, ray.dir); for(;;depth++) { kdtree->traverse(ray, hitRec, 0.0f, FLT_MAX); if(hitRec.isIntersect) { Radion nr; nr.position = hitRec.point; nr.normal = hitRec.normal; nr.radiance = power; nr.radiance %= hitRec.material->getTextureDiffuseBrdf(hitRec.texUV); nr.probability = prob; bushRadions.push_back(nr); } else break; if(depth >= 3) break; float rrRandom = (float)rand() / RAND_MAX; float diffuseAlbedo = hitRec.material->getTextureDiffuseAlbedo(hitRec.texUV); float idealAlbedo = hitRec.material->getTextureIdealAlbedo(hitRec.texUV); float refractiveAlbedo = hitRec.material->getRefractiveAlbedo(); if(rrRandom < diffuseAlbedo) { ray.id = rayId++; ray.isShadowRay = false; ray.origin = hitRec.point; power %= hitRec.material->getTextureDiffuseBrdf(hitRec.texUV); power *= 1.0f / diffuseAlbedo; prob *= diffuseAlbedo; sampleShootingDiffuseDirection(depth, hitRec.normal, ray.dir); } else { rrRandom -= diffuseAlbedo; if(rrRandom < idealAlbedo) { ray.dir.setIdealReflectedDirection(ray.dir, hitRec.normal); ray.id = rayId++; ray.isShadowRay = false; ray.origin = hitRec.point; power %= hitRec.material->getIdealBrdf(); power *= 1.0f / idealAlbedo; prob *= idealAlbedo; } else break; } } } } void PathMapEffect::sampleSurfaceRadion(Radion& starter) { float randa = ((double)rand() / RAND_MAX) * entities.size(); // float randa = ((double)rand() / RAND_MAX) * sumSurfaceArea; float uptonowSurfaceArea = 0.0; Entity* e = NULL; std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { uptonowSurfaceArea += 1.0f; // uptonowSurfaceArea += entityIterator->rayTraceEntity->getSurfaceArea(); if(uptonowSurfaceArea >= randa) { e = &*entityIterator; break; } entityIterator++; } e->rayTraceEntity->sampleSurface(starter); float surfa = starter.radiance.z; starter.radiance = e->rayTraceEntity->getMaterial()->getTextureDiffuseBrdf(starter.radiance); starter.radiance *= (surfa / NRADIONS) * entities.size(); // starter.radiance *= sumSurfaceArea / NRADIONS; starter.probability = (float)NRADIONS / (entities.size() * surfa ); } void PathMapEffect::sampleSurfaceRadionUniform(Radion& starter) { float randa = ((double)rand() / RAND_MAX) * sumSurfaceArea; float uptonowSurfaceArea = 0.0; Entity* e = NULL; std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { uptonowSurfaceArea += entityIterator->rayTraceEntity->getSurfaceArea(); if(uptonowSurfaceArea >= randa) { e = &*entityIterator; break; } entityIterator++; } e->rayTraceEntity->sampleSurface(starter); float surfa = starter.radiance.z; starter.radiance = e->rayTraceEntity->getMaterial()->getTextureDiffuseBrdf(starter.radiance); starter.radiance *= sumSurfaceArea / NRADIONS; starter.probability = NRADIONS / sumSurfaceArea; } void PathMapEffect::Entity::renderPRM(LPDIRECT3DDEVICE9 device, LPD3DXEFFECT effect, std::vector& bushRadions, unsigned int bushId, float scaleFactor ) { HRESULT hr; UINT nPasses=1; //# bushId -> nearestIdx int radinx = 0xffffff; for(int i=0; iSetRenderTarget(0, prmSurface); int tilex = radinx % 32; int tiley = radinx / 32; D3DVIEWPORT9 vp; vp.X = tilex * 128; vp.Y = tiley * 128; vp.Width = vp.Height = 128; vp.MinZ = 0.0; vp.MaxZ = 1.0; //clear everything device->SetRenderTarget(0, prmSurface); device->SetDepthStencilSurface(owner->prmBlendingDepthStencilBuffer); device->SetViewport(&vp); device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0,0,0,0), 1.0f, 0 ); unsigned int nRadions = bushRadions.size(); for(int ir=0; ir < nRadions; ir++) { // 1. pass render depth map for virtual light source device->SetRenderTarget(0, owner->fakeSurface); device->SetDepthStencilSurface(owner->depthMapDepthStencilBuffer); device->SetRenderState(D3DRS_COLORWRITEENABLE, 0); device->Clear( 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(255, 0, 0, 0), 1.0f, 0 ); CFirstPersonCamera radionCamera; radionCamera.SetViewParams((D3DXVECTOR3*)&bushRadions[ir].position, (D3DXVECTOR3*)&(bushRadions[ir].position + bushRadions[ir].normal)); radionCamera.SetProjParams( D3DX_PI/1.9, 1.0f, 0.1f, 300.0f ); // render backfaces to avoid z-fighting device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); if( SUCCEEDED( device->BeginScene() ) ) { effect->SetTechnique("Depth"); UINT nPasses; effect->Begin(&nPasses, 0); effect->BeginPass(0); //loop through all entities, all mesh subsets, set proper transformations std::vector::iterator entityIterator = owner->entities.begin(); while(entityIterator != owner->entities.end()) { effect->SetMatrix("modelToProjMatrix", &( entityIterator->modelWorldTransform * *radionCamera.GetViewMatrix() * *radionCamera.GetProjMatrix() ) ); effect->CommitChanges(); unsigned int nSubsets = entityIterator->renderMesh->nSubsets; for(int i = 0; i< nSubsets; i++) { entityIterator->renderMesh->mesh->DrawSubset(i); } entityIterator++; } effect->EndPass(); effect->End(); device->EndScene(); } device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA); // blend-add contribution of virtual light source to PRM device->SetRenderTarget(0, prmSurface); device->SetDepthStencilSurface(owner->prmBlendingDepthStencilBuffer); device->SetViewport(&vp); device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); device->SetRenderState(D3DRS_ALPHABLENDENABLE, true); device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); // use stencil to avoid adding contribution twice HRESULT hr = device->Clear( 0, NULL, D3DCLEAR_STENCIL, D3DCOLOR_RGBA(0,0,0,0), 1.0f, 0 ); if( SUCCEEDED( device->BeginScene() ) ) { Radion radion = bushRadions[ir]; if( effect != NULL ){ D3DXHANDLE hTechnique = effect->GetTechniqueByName((LPSTR)"BushToAtlas"); if(hTechnique==NULL){ return; } effect->SetTechnique( hTechnique ); effect->Begin( &nPasses, 0 ); for(UINT j=0;jBeginPass(j); Vector fakejake = bushRadions[ir].position; fakejake = bushRadions[ir].normal; fakejake = bushRadions[ir].radiance; hr=effect->SetFloatArray("lightPos", (float*)&bushRadions[ir].position, 3); hr=effect->SetFloatArray("lightDir", (float*)&bushRadions[ir].normal, 3); static float opttme[9] = {0.5f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f, 0.5f + (0.5f / DEPTHMAPRES), 0.5f + (0.5f / DEPTHMAPRES), 1.0f}; effect->SetTexture("depthMap", owner->depthMapTexture); Vector bb0 = this->rayTraceEntity->bbox.minPoint; Vector bb1 = this->rayTraceEntity->bbox.maxPoint; //effect->SetFloat("cutNearness2", (bb1 - bb0).norm2() / 200.0f); float nne = 5.0f / bushRadions[ir].probability; float onne = (bb1 - bb0).norm2() / 200.0f; effect->SetFloat("cutNearness2", nne); //effect->SetFloat("cutNearness2", 0.0f); //set global params effect->SetFloatArray("occProjToTexMatrix", opttme, 9); effect->SetMatrix("occWorldToProjMatrix", &(*radionCamera.GetViewMatrix() * *radionCamera.GetProjMatrix())); effect->SetMatrix("modelToWorldMatrix", &(this->modelWorldTransform)); effect->SetMatrix("inverseTransposedModelToWorldMatrix", &(this->inverseTransposedModelWorldTransform)); Vector scaledPower = bushRadions[ir].radiance * scaleFactor; hr=effect->SetFloatArray("lightPower", (float*)&scaledPower, 3); hr = device->SetRenderState(D3DRS_STENCILENABLE, true); hr = device->SetRenderState(D3DRS_STENCILREF, 0xffffffff); hr = device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); hr = device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); effect->CommitChanges(); renderMesh->mesh->DrawSubset(0); hr = device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL); scaledPower = bushRadions[ir].radiance * 1.0f ; hr=effect->SetFloatArray("lightPower", (float*)&scaledPower, 3); effect->CommitChanges(); if(renderMesh->nEdges) { device->SetStreamSource(0, renderMesh->edgeVertexBuffer, 0, sizeof(D3DVERTEX)); device->DrawPrimitive(D3DPT_LINELIST, 0, renderMesh->nEdges); } effect->EndPass(); } effect->End(); } device->EndScene(); device->SetRenderState(D3DRS_STENCILENABLE, false); device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); device->SetRenderState(D3DRS_ALPHABLENDENABLE, false); device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); } } } void PathMapEffect::drawFullScreenQuad(LPDIRECT3DDEVICE9 device, float depth, float fLeftU, float fTopV, float fRightU, float fBottomV) { D3DSURFACE_DESC dtdsdRT; PDIRECT3DSURFACE9 pSurfRT; // Acquire render target width and height device->GetRenderTarget(0, &pSurfRT); pSurfRT->GetDesc(&dtdsdRT); pSurfRT->Release(); // Ensure that we're directly mapping texels to pixels by offset by 0.5 // For more info see the doc page titled "Directly Mapping Texels to Pixels" FLOAT fWidth5 = (FLOAT)dtdsdRT.Width - 0.5f; FLOAT fHeight5 = (FLOAT)dtdsdRT.Height - 0.5f; // Draw the quad D3DVERTEX svQuad[4]; svQuad[0].pos=D3DXVECTOR3(-1, 1, depth); svQuad[0].normal=D3DXVECTOR3(0,0,0); svQuad[0].tex0 = D3DXVECTOR2(fLeftU, fTopV); svQuad[1].pos = D3DXVECTOR3(1, 1, depth); svQuad[1].normal = D3DXVECTOR3(0,0,0); svQuad[1].tex0 = D3DXVECTOR2(fRightU, fTopV); svQuad[2].pos = D3DXVECTOR3(-1, -1, depth); svQuad[2].normal = D3DXVECTOR3(0,0,0); svQuad[2].tex0 = D3DXVECTOR2(fLeftU, fBottomV); svQuad[3].pos = D3DXVECTOR3(1, -1, depth); svQuad[3].normal = D3DXVECTOR3(0,0,0); svQuad[3].tex0 = D3DXVECTOR2(fRightU, fBottomV); device->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE); device->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)); device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, svQuad, sizeof(D3DVERTEX)); } void PathMapEffect::showPRMTexture() { device->SetRenderTarget(0, frameColorBuffer); device->SetDepthStencilSurface(frameDepthStencilBuffer); device->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 ); if( SUCCEEDED( device->BeginScene() ) ){ if( effect != NULL ){ D3DXHANDLE hTechnique = effect->GetTechniqueByName((LPSTR)"ShowTex"); if(hTechnique==NULL){ return; } effect->SetTechnique( hTechnique ); UINT nPasses = 0; effect->Begin( &nPasses, 0 ); for(UINT j=0;jBeginPass(j); //loop through entities std::vector::iterator entityIterator = entities.begin(); //while(entityIterator != entities.end()) { //set entity params effect->SetMatrix("modelToWorldMatrix", &entityIterator->modelWorldTransform); effect->SetMatrix("inverseTransposedModelToWorldMatrix", &entityIterator->inverseTransposedModelWorldTransform); D3DXMATRIX t = entityIterator->modelWorldTransform; if(parameters->Get(bLookFromLight)) effect->SetMatrix("modelToProjMatrix", &(entityIterator->modelWorldTransform * *lightCamera->GetViewMatrix() * *lightCamera->GetProjMatrix() )); else effect->SetMatrix("modelToProjMatrix", &(entityIterator->modelWorldTransform * *camera->GetViewMatrix() * *camera->GetProjMatrix() )); effect->SetTexture("filteredAtlas", entityIterator->prmTexture); unsigned int nSubsets = entityIterator->renderMesh->nSubsets; for(int i = 0; i< nSubsets; i++) { //set subset material texture effect->SetTexture("texToShow", entityIterator->prmTexture); effect->CommitChanges(); drawFullScreenQuad(device); // effect->CommitChanges(); // entityIterator->renderMesh->mesh->DrawSubset(i); } entityIterator++; } effect->EndPass(); } effect->End(); } device->EndScene(); } } void PathMapEffect::RenderMesh::buildEdgeVertexBuffer(LPDIRECT3DDEVICE9 device) { LPD3DXMESH pMesh = this->mesh; DWORD* pAdj = new DWORD[3 * pMesh->GetNumFaces()]; for(int r=0; rGetNumFaces()*3; r++) pAdj[r] = 0xffff; pMesh->ConvertPointRepsToAdjacency(NULL, pAdj); LPDIRECT3DVERTEXBUFFER9 vertexBuffer; pMesh->GetVertexBuffer(&vertexBuffer); D3DVERTEX* vertexData; vertexBuffer->Lock(0,pMesh->GetNumVertices()*pMesh->GetNumBytesPerVertex(),(void**)&vertexData,0); LPDIRECT3DINDEXBUFFER9 indexBuffer; pMesh->GetIndexBuffer(&indexBuffer); unsigned short* indexData; indexBuffer->Lock(0,pMesh->GetNumFaces()*3*sizeof(unsigned short),(void**)&indexData,0); int countEdges = 0; for(int u=0; uGetNumFaces(); u++) for(int t=0; t<3; t++) if(pAdj[u * 3 + t] >= pMesh->GetNumFaces()) countEdges++; if(countEdges == 0) { edgeVertexBuffer = NULL; nEdges = 0; vertexBuffer->Unlock(); indexBuffer->Unlock(); SAFE_RELEASE(vertexBuffer); SAFE_RELEASE(indexBuffer); return; } device->CreateVertexBuffer(2 * countEdges * pMesh->GetNumBytesPerVertex(), D3DUSAGE_WRITEONLY, pMesh->GetFVF(), D3DPOOL_DEFAULT, &edgeVertexBuffer, NULL); D3DVERTEX* pevData; edgeVertexBuffer->Lock(0, 0, (void**)&pevData, 0); int iEdge = 0; for(int u=0; uGetNumFaces(); u++) { for(int t=0; t<3; t++) { if(pAdj[u * 3 + t] >= pMesh->GetNumFaces()) { unsigned short edge0 = indexData[u * 3 + t]; unsigned short edge1 = indexData[u * 3 + (t+1)%3]; unsigned short inner = indexData[u * 3 + (t+2)%3]; //push vertex edge0, edge1 pevData[iEdge * 2] = vertexData[edge0]; pevData[iEdge * 2 + 1] = vertexData[edge1]; D3DXVECTOR2 ediff = vertexData[edge1].tex0 - vertexData[edge0].tex0; if(fabsf(ediff.x) > fabsf(ediff.y)) { if(vertexData[inner].tex0.y <= vertexData[edge0].tex0.y + (vertexData[inner].tex0.x - vertexData[edge0].tex0.x) * (vertexData[edge1].tex0.y - vertexData[edge0].tex0.y) / (vertexData[edge1].tex0.x - vertexData[edge0].tex0.x)) { pevData[iEdge * 2].tex0.y += 1.0/DBLATLASSIZE; pevData[iEdge * 2 + 1].tex0.y += 1.0/DBLATLASSIZE; } else { pevData[iEdge * 2].tex0.y -= 1.0/DBLATLASSIZE; pevData[iEdge * 2 + 1].tex0.y -= 1.0/DBLATLASSIZE; } D3DXVECTOR2 edgeDirUnitExt(1.0f, (vertexData[edge1].tex0.y - vertexData[edge0].tex0.y) / (vertexData[edge1].tex0.x - vertexData[edge0].tex0.x)); edgeDirUnitExt *= 1.0/ATLASSIZE; if(vertexData[edge1].tex0.x > vertexData[edge0].tex0.x) { pevData[iEdge * 2].tex0 -= edgeDirUnitExt; pevData[iEdge * 2 + 1].tex0 += edgeDirUnitExt; } else { pevData[iEdge * 2].tex0 += edgeDirUnitExt; pevData[iEdge * 2 + 1].tex0 -= edgeDirUnitExt; } } else { if(vertexData[inner].tex0.x <= vertexData[edge0].tex0.x + (vertexData[inner].tex0.y - vertexData[edge0].tex0.y) * (vertexData[edge1].tex0.x - vertexData[edge0].tex0.x) / (vertexData[edge1].tex0.y - vertexData[edge0].tex0.y)) { pevData[iEdge * 2].tex0.x += 1.0/DBLATLASSIZE; pevData[iEdge * 2 + 1].tex0.x += 1.0/DBLATLASSIZE; } else { pevData[iEdge * 2].tex0.x -= 1.0/DBLATLASSIZE; pevData[iEdge * 2 + 1].tex0.x -= 1.0/DBLATLASSIZE; } D3DXVECTOR2 edgeDirUnitExt((vertexData[edge1].tex0.x - vertexData[edge0].tex0.x) / (vertexData[edge1].tex0.y - vertexData[edge0].tex0.y), 1.0f); edgeDirUnitExt *= 1.0/ATLASSIZE; if(vertexData[edge1].tex0.y > vertexData[edge0].tex0.y) { pevData[iEdge * 2].tex0 -= edgeDirUnitExt; pevData[iEdge * 2 + 1].tex0 += edgeDirUnitExt; } else { pevData[iEdge * 2].tex0 += edgeDirUnitExt; pevData[iEdge * 2 + 1].tex0 -= edgeDirUnitExt; } } iEdge++; } } } nEdges = iEdge; edgeVertexBuffer->Unlock(); vertexBuffer->Unlock(); indexBuffer->Unlock(); SAFE_RELEASE(vertexBuffer); SAFE_RELEASE(indexBuffer); delete pAdj; } void PathMapEffect::uploadRadions() { int nRadions = bushStarters.size(); struct TMR{ float pos[4]; float dir[4]; // float pow[4]; }; TMR* tm = new TMR[nRadions]; for(int i=0; iindex = index; this->dist2 = dist2;} bool operator<(const ClusterDist2& o) const {return dist2 > o.dist2;} bool operator>(const ClusterDist2& o) const {return dist2 < o.dist2;} bool operator<=(const ClusterDist2& o) const {return dist2 >= o.dist2;} bool operator>=(const ClusterDist2& o) const {return dist2 <= o.dist2;} }; void PathMapEffect::Entity::findNearClusters(const std::vector& starters, unsigned int nClusters) { D3DXVECTOR3 cc = (D3DXVECTOR3&)rayTraceEntity->bbox.getCentre(); std::priority_queue nearestClusterDists; for(unsigned int iCluster = 0; iCluster < NCLUSTERS; iCluster++) { unsigned int iRadion = 0; unsigned int nRadionsPerCluster = owner->clusterLenghts[iCluster]; double aClusterDist2 = 0.0; for(unsigned int iric=0; iric < nRadionsPerCluster; iric++, iRadion++) { aClusterDist2 += (starters[iRadion++].position - cc).norm2(); } nearestClusterDists.push( ClusterDist2(iCluster, aClusterDist2) ); } for(unsigned int i=0; i<32; i++) { nearClusterIndices[i] = 31 - i;// nearestClusterDists.top().index; nearestClusterDists.pop(); } } void PathMapEffect::savePathMaps() { std::fstream entryPointFile("prm\\prmEntryPoints.dat", std::ios::out | std::ios::binary); for(unsigned int u=0; u < NRADIONS; u++) { entryPointFile << bushStarters.at(u); } for(unsigned int c=0; c < NCLUSTERS; c++) { entryPointFile.write((char*)&clusterLenghts[c], sizeof(unsigned int)); } entryPointFile.flush(); entryPointFile.close(); unsigned int iEntity = 0; std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { wchar_t prmFileName[256]; // wsprintf(prmFileName, L"prm\\prm_%08d.hdr", iEntity); MultiByteToWideChar(CP_ACP, 0, entityIterator->prmfilename, -1, prmFileName, 255); D3DXSaveSurfaceToFile(prmFileName, D3DXIFF_HDR, entityIterator->prmSurface, NULL, NULL); entityIterator++; iEntity++; } } void PathMapEffect::loadPathMaps() { std::fstream entryPointFile("prm\\prmEntryPoints.dat", std::ios::in | std::ios::binary); bushStarters.clear(); for(unsigned int u=0; u < NRADIONS; u++) { Radion ri; entryPointFile >> ri; bushStarters.push_back(ri); } for(unsigned int c=0; c < NCLUSTERS; c++) { entryPointFile.read((char*)&clusterLenghts[c], sizeof(unsigned int)); } entryPointFile.close(); unsigned int iEntity = 0; std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { entityIterator->findNearClusters(bushStarters, NCLUSTERS); wchar_t prmFileName[256]; // wsprintf(prmFileName, L"prm\\prm_%08d.hdr", iEntity); MultiByteToWideChar(CP_ACP, 0, entityIterator->prmfilename, -1, prmFileName, 255); D3DXLoadSurfaceFromFile(entityIterator->prmSurface, NULL, NULL, prmFileName, NULL, D3DX_DEFAULT, 0, NULL); entityIterator++; iEntity++; } } void PathMapEffect::exportEntityData() { std::fstream entryPointFile("media\\entityPathMapData.txt", std::ios::out); unsigned int iEntity = 0; std::vector::iterator entityIterator = entities.begin(); while(entityIterator != entities.end()) { entryPointFile << "entity " << entityIterator->name << '\n'; entryPointFile << "{" << '\n'; entryPointFile << " pathmapfile " << entityIterator->prmfilename << '\n'; entryPointFile << " clusters "; for(int i=0; inearClusterIndices[i] << " "; entryPointFile << '\n'; entryPointFile << "}" << '\n'; entryPointFile << '\n'; // for(int i=0; i<16; i++) // entryPointFile << entityIterator->modelWorldTransform.m[i%4][i/4] << " "; entryPointFile << '\n'; entityIterator++; iEntity++; } entryPointFile.flush(); entryPointFile.close(); } void PathMapEffect::loadScene(const char* sceneFileName) { std::fstream sceneFile(sceneFileName, std::ios::in); char keyword[256]; while(!sceneFile.eof()) { sceneFile >> keyword; if(strcmp(keyword, "mesh") == 0) { char meshname[256]; sceneFile >> meshname; if(strcmp(meshname, "{") == 0) strcpy(meshname, "mesh"); while(strcmp(keyword, "}") != 0 && !sceneFile.eof()) { sceneFile >> keyword; if(strcmp(keyword, "xfile") == 0) { sceneFile >> keyword; wchar_t* wide = NULL; if(keyword) { wide = new wchar_t[MultiByteToWideChar(CP_ACP, 0, keyword, -1, NULL, 0)]; MultiByteToWideChar(CP_ACP, 0, keyword, -1, wide, 511); } loadMesh(wide); strcpy(renderMeshes[renderMeshes.size()-1]->name, meshname); delete wide; } } } if(strcmp(keyword, "entity") == 0) { Entity e; e.owner = this; char entityname[256]; sceneFile >> entityname; if(strcmp(entityname, "{") == 0) strcpy(entityname, "noname"); strcpy(e.name, entityname); while(strcmp(keyword, "}") != 0 && !sceneFile.eof()) { sceneFile >> keyword; if(strcmp(keyword, "pathmapfile") == 0) { sceneFile >> keyword; strcpy(e.prmfilename, keyword); } if(strcmp(keyword, "mesh") == 0) { sceneFile >> keyword; std::vector::iterator i = renderMeshes.begin(); while(i != renderMeshes.end()) { if(strcmp((*i)->name, keyword) == 0) { e.renderMesh = *i; break; } i++; } } if(strcmp(keyword, "transformation") == 0) { for(int i=0; i<16; i++) sceneFile >> e.modelWorldTransform.m[i%4][i/4]; D3DXMatrixInverse(&e.inverseTransposedModelWorldTransform, NULL, &e.modelWorldTransform); } } e.createRayTraceEntity(); entities.push_back(e); } } sceneFile.close(); }