• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

PolyVoxCore/include/PolyVoxCore/AmbientOcclusionCalculator.inl

Go to the documentation of this file.
00001 /*******************************************************************************
00002 Copyright (c) 2005-2009 David Williams
00003 
00004 This software is provided 'as-is', without any express or implied
00005 warranty. In no event will the authors be held liable for any damages
00006 arising from the use of this software.
00007 
00008 Permission is granted to anyone to use this software for any purpose,
00009 including commercial applications, and to alter it and redistribute it
00010 freely, subject to the following restrictions:
00011 
00012     1. The origin of this software must not be misrepresented; you must not
00013     claim that you wrote the original software. If you use this software
00014     in a product, an acknowledgment in the product documentation would be
00015     appreciated but is not required.
00016 
00017     2. Altered source versions must be plainly marked as such, and must not be
00018     misrepresented as being the original software.
00019 
00020     3. This notice may not be removed or altered from any source
00021     distribution.   
00022 *******************************************************************************/
00023 
00024 namespace PolyVox
00025 {
00026     template< template<typename> class VolumeType, typename VoxelType>
00027     AmbientOcclusionCalculator<VolumeType, VoxelType>::AmbientOcclusionCalculator(VolumeType<VoxelType>* volInput, Array<3, uint8_t>* arrayResult, Region region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement)
00028         :m_region(region)
00029         ,m_sampVolume(volInput)
00030         ,m_volInput(volInput)
00031         ,m_arrayResult(arrayResult)
00032         ,m_fRayLength(fRayLength)
00033         ,m_uNoOfSamplesPerOutputElement(uNoOfSamplesPerOutputElement)
00034         ,mRandomUnitVectorIndex(0) //Although these could be uninitialised, we 
00035         ,mRandomVectorIndex(0) //initialise for consistant results in the tests.
00036     {
00037         //Make sure that the size of the volume is an exact multiple of the size of the array.
00038         assert(m_volInput->getWidth() % arrayResult->getDimension(0) == 0);
00039         assert(m_volInput->getHeight() % arrayResult->getDimension(1) == 0);
00040         assert(m_volInput->getDepth() % arrayResult->getDimension(2) == 0);
00041 
00042         //Our initial indices. It doesn't matter exactly what we set here, but the code below makes 
00043         //sure they are different for different regions which helps reduce tiling patterns in the results.
00044         mRandomUnitVectorIndex += m_region.getLowerCorner().getX() + m_region.getLowerCorner().getY() + m_region.getLowerCorner().getZ();
00045         mRandomVectorIndex += m_region.getLowerCorner().getX() + m_region.getLowerCorner().getY() + m_region.getLowerCorner().getZ();
00046 
00047         //This value helps us jump around in the array a bit more, so the
00048         //nth 'random' value isn't always followed by the n+1th 'random' value.
00049         mIndexIncreament = 1;
00050     }
00051 
00052     template< template<typename> class VolumeType, typename VoxelType>
00053     AmbientOcclusionCalculator<VolumeType, VoxelType>::~AmbientOcclusionCalculator()
00054     {
00055     }
00056 
00057     template< template<typename> class VolumeType, typename VoxelType>
00058     void AmbientOcclusionCalculator<VolumeType, VoxelType>::execute(void)
00059     {
00060         const int iRatioX = m_volInput->getWidth()  / m_arrayResult->getDimension(0);
00061         const int iRatioY = m_volInput->getHeight() / m_arrayResult->getDimension(1);
00062         const int iRatioZ = m_volInput->getDepth()  / m_arrayResult->getDimension(2);
00063 
00064         const float fRatioX = iRatioX;
00065         const float fRatioY = iRatioY;
00066         const float fRatioZ = iRatioZ;
00067         const Vector3DFloat v3dRatio(fRatioX, fRatioY, fRatioZ);
00068 
00069         const float fHalfRatioX = fRatioX * 0.5f;
00070         const float fHalfRatioY = fRatioY * 0.5f;
00071         const float fHalfRatioZ = fRatioZ * 0.5f;
00072         const Vector3DFloat v3dHalfRatio(fHalfRatioX, fHalfRatioY, fHalfRatioZ);
00073 
00074         const Vector3DFloat v3dOffset(0.5f,0.5f,0.5f);
00075 
00076         RaycastResult raycastResult;
00077         Raycast<VolumeType, VoxelType> raycast(m_volInput, Vector3DFloat(0.0f,0.0f,0.0f), Vector3DFloat(1.0f,1.0f,1.0f), raycastResult);
00078 
00079         //This loop iterates over the bottom-lower-left voxel in each of the cells in the output array
00080         for(uint16_t z = m_region.getLowerCorner().getZ(); z <= m_region.getUpperCorner().getZ(); z += iRatioZ)
00081         {
00082             for(uint16_t y = m_region.getLowerCorner().getY(); y <= m_region.getUpperCorner().getY(); y += iRatioY)
00083             {
00084                 for(uint16_t x = m_region.getLowerCorner().getX(); x <= m_region.getUpperCorner().getX(); x += iRatioX)
00085                 {
00086                     //Compute a start position corresponding to 
00087                     //the centre of the cell in the output array.
00088                     Vector3DFloat v3dStart(x, y, z);
00089                     v3dStart -= v3dOffset;
00090                     v3dStart += v3dHalfRatio;
00091 
00092                     //Keep track of how many rays did not hit anything
00093                     uint8_t uVisibleDirections = 0;
00094 
00095                     for(int ct = 0; ct < m_uNoOfSamplesPerOutputElement; ct++)
00096                     {                       
00097                         //We take a random vector with components going from -1 to 1 and scale it to go from -halfRatio to +halfRatio.
00098                         //This jitter value moves our sample point from the center of the array cell to somewhere else in the array cell
00099                         Vector3DFloat v3dJitter = randomVectors[(mRandomVectorIndex += (++mIndexIncreament)) % 1019]; //Prime number helps avoid repetition on sucessive loops.
00100                         v3dJitter *= v3dHalfRatio;
00101                         const Vector3DFloat v3dRayStart = v3dStart + v3dJitter;
00102 
00103                         Vector3DFloat v3dRayDirection = randomUnitVectors[(mRandomUnitVectorIndex += (++mIndexIncreament)) % 1021]; //Differenct prime number.
00104                         v3dRayDirection *= m_fRayLength;
00105                         
00106                         raycast.setStart(v3dRayStart);
00107                         raycast.setDirection(v3dRayDirection);
00108                         raycast.execute();
00109 
00110                         if(raycastResult.foundIntersection == false)
00111                         {
00112                             ++uVisibleDirections;
00113                         }
00114                     }
00115 
00116                     float fVisibility;
00117                     if(m_uNoOfSamplesPerOutputElement == 0)
00118                     {
00119                         //The user might request zero samples (I've done this in the past while debugging - I don't want to
00120                         //wait for ambient occlusion but I do want as valid result for rendering). Avoid the divide by zero.
00121                         fVisibility = 1.0f;
00122                     }
00123                     else
00124                     {
00125                         fVisibility = static_cast<float>(uVisibleDirections) / static_cast<float>(m_uNoOfSamplesPerOutputElement);
00126                         assert((fVisibility >= 0.0f) && (fVisibility <= 1.0f));
00127                     }
00128 
00129                     (*m_arrayResult)[z / iRatioZ][y / iRatioY][x / iRatioX] = static_cast<uint8_t>(255.0f * fVisibility);
00130                 }
00131             }
00132         }
00133     }
00134 }

Generated on Sat Nov 19 2011 00:27:30 for PolyVox by  doxygen 1.7.1