/////////////////////////////////////////////////////////////////////// // CSpeedGrassRT Class // // (c) 2003 IDV, Inc. // // *** INTERACTIVE DATA VISUALIZATION (IDV) PROPRIETARY INFORMATION *** // // This software is supplied under the terms of a license agreement or // nondisclosure agreement with Interactive Data Visualization and may // not be copied or disclosed except in accordance with the terms of // that agreement. // // Copyright (c) 2001-2003 IDV, Inc. // All Rights Reserved. // // IDV, Inc. // 1233 Washington St. Suite 610 // Columbia, SC 29201 // Voice: (803) 799-1699 // Fax: (803) 931-0320 // Web: http://www.idvinc.com #include "StdAfx.h" #include "BoundaryShapeManager.h" #ifdef USE_SPEEDGRASS inline float VecInterpolate(float fStart, float fEnd, float fPercent) { return fStart + (fEnd - fStart) * fPercent; } #define VectorSinD(x) sinf((x) / 57.29578f) #define VectorCosD(x) cosf((x) / 57.29578f) using namespace std; // macros #ifndef max #define max(a, b) (((a) > (b)) ? (a) : (b)) #endif #ifndef min #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif // static variables float CSpeedGrassRT::m_fLodFarDistance = 100.0f; float CSpeedGrassRT::m_fLodTransitionLength = 37.5f; float CSpeedGrassRT::m_afUnitBillboard[12] = { 0.0f }; float CSpeedGrassRT::m_afWindDir[4] = { 1.0f, 0.3f, 0.0f, 0.0f }; // camera float CSpeedGrassRT::m_afCameraOut[3] = { 0.0f, 1.0f, 0.0f }; float CSpeedGrassRT::m_afCameraUp[3] = { 0.0f, 0.0f, 1.0f }; float CSpeedGrassRT::m_afCameraRight[3] = { 1.0f, 0.0f, 0.0f }; float CSpeedGrassRT::m_afCameraPos[3] = { 0.0f, 0.0f, 0.0f }; float CSpeedGrassRT::m_fFieldOfView = D3DXToRadian(40.0f); float CSpeedGrassRT::m_fAspectRatio = 4.0f / 3.0f; // culling float CSpeedGrassRT::m_afFrustumBox[6] = { 0.0f }; float CSpeedGrassRT::m_afFrustumMin[2] = { FLT_MAX, FLT_MAX }; float CSpeedGrassRT::m_afFrustumMax[2] = { -FLT_MAX, -FLT_MAX }; float CSpeedGrassRT::m_afFrustumPlanes[5][4] = { 0.0f }; /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::SBlade::SBlade CSpeedGrassRT::SBlade::SBlade( ) : m_fSize(1.0f), m_fNoise(0.0f), m_fThrow(0.0f), m_ucWhichTexture(0) { m_afBottomColor[0] = m_afBottomColor[1] = m_afBottomColor[2] = 1.0f; m_afTopColor[0] = m_afTopColor[1] = m_afTopColor[2] = 1.0f; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::SRegion::SRegion CSpeedGrassRT::SRegion::SRegion( ) : m_bCulled(false), m_fCullingRadius(1.0f) { m_afCenter[0] = m_afCenter[1] = m_afCenter[2] = 0.5f; m_afMin[0] = m_afMin[1] = m_afMin[2] = 0.0f; m_afMax[0] = m_afMax[1] = m_afMax[2] = 1.0f; m_VertexBuffer.Destroy(); } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::CSpeedGrassRT CSpeedGrassRT::CSpeedGrassRT( ) : m_nNumRegions(0), m_nNumRegionCols(0), m_nNumRegionRows(0), m_pRegions(NULL), m_bAllRegionsCulled(false) { m_afBoundingBox[0] = m_afBoundingBox[1] = m_afBoundingBox[2] = 0.0f; m_afBoundingBox[3] = m_afBoundingBox[4] = m_afBoundingBox[5] = 1.0f; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::~CSpeedGrassRT CSpeedGrassRT::~CSpeedGrassRT( ) { } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::DeleteRegions void CSpeedGrassRT::DeleteRegions(void) { delete[] m_pRegions; m_pRegions = NULL; m_nNumRegions = 0; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::GetRegions const CSpeedGrassRT::SRegion* CSpeedGrassRT::GetRegions(unsigned int& uiNumRegions) { uiNumRegions = m_nNumRegions; return m_pRegions; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::ParseBsfFile bool CSpeedGrassRT::ParseBsfFile(const char* pFilename, unsigned int nNumBlades, unsigned int uiRows, unsigned int uiCols, float fCollisionDistance) { bool bSuccess = false; // copy region settings m_nNumRegionCols = int(uiCols); m_nNumRegionRows = int(uiRows); // initialize bounding box m_afBoundingBox[0] = m_afBoundingBox[1] = m_afBoundingBox[2] = FLT_MAX; m_afBoundingBox[3] = m_afBoundingBox[4] = m_afBoundingBox[5] = -FLT_MAX; CBoundaryShapeManager cManager; vector vSceneBlades; if (cManager.LoadBsfFile(pFilename)) { for (unsigned int i = 0; i < nNumBlades; ++i) { SBlade sBlade; // try to place a blade if (cManager.RandomPoint(sBlade.m_afPos[0], sBlade.m_afPos[1])) { sBlade.m_afPos[2] = Height(sBlade.m_afPos[0], sBlade.m_afPos[1], sBlade.m_afNormal); // CVec3 cNormal(sBlade.m_afNormal[0], sBlade.m_afNormal[1], sBlade.m_afNormal[2]); // cNormal.Normalize( ); // cNormal[2] = -cNormal[2]; // memcpy(sBlade.m_afNormal, cNormal, 3 * sizeof(float)); D3DXVECTOR3 v3Normal(sBlade.m_afNormal[0], sBlade.m_afNormal[1], sBlade.m_afNormal[2]); D3DXVec3Normalize(&v3Normal, &v3Normal); v3Normal.z = -v3Normal.z; sBlade.m_afNormal[0] = v3Normal.x; sBlade.m_afNormal[1] = v3Normal.y; sBlade.m_afNormal[2] = v3Normal.z; // check against overall scene bounding box for (int nAxis = 0; nAxis < 3; ++nAxis) { m_afBoundingBox[nAxis] = min(m_afBoundingBox[nAxis], sBlade.m_afPos[nAxis]); m_afBoundingBox[nAxis + 3] = max(m_afBoundingBox[nAxis + 3], sBlade.m_afPos[nAxis]); } // set bottom and top color float fHeightPercent = Color(sBlade.m_afPos[0], sBlade.m_afPos[1], sBlade.m_afNormal, sBlade.m_afTopColor, sBlade.m_afBottomColor); sBlade.m_fSize = VecInterpolate(c_fMinBladeSize, c_fMaxBladeSize, fHeightPercent); // assign which blade texture map sBlade.m_ucWhichTexture = GetRandom(0, c_nNumBladeMaps - 1); // compute wind effects sBlade.m_fNoise = GetRandom(c_fMinBladeNoise, c_fMaxBladeNoise); sBlade.m_fThrow = GetRandom(c_fMinBladeThrow, c_fMaxBladeThrow); // store all blades together vSceneBlades.push_back(sBlade); } } bSuccess = true; } else fprintf(stderr, "%s\n", cManager.GetCurrentError( ).c_str( )); if (bSuccess) CreateRegions(vSceneBlades, fCollisionDistance); return bSuccess; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::CustomPlacement // // Use this function to perform custom grass blade placement. Feel free // to add parameters as necessary but be sure to call CreateRegions( ) // at the end of the function to set up the SpeedGrass region system. bool CSpeedGrassRT::CustomPlacement(unsigned int uiRows, unsigned int uiCols) { // copy region settings (do not remove) m_nNumRegionCols = int(uiCols); m_nNumRegionRows = int(uiRows); // initialize bounding box (do not remove) m_afBoundingBox[0] = m_afBoundingBox[1] = m_afBoundingBox[2] = FLT_MAX; m_afBoundingBox[3] = m_afBoundingBox[4] = m_afBoundingBox[5] = -FLT_MAX; // place one blade as an example vector vSceneBlades; SBlade sBlade; sBlade.m_afPos[0] = 0.0f; sBlade.m_afPos[1] = 0.0f; sBlade.m_afPos[2] = 0.0f; sBlade.m_afNormal[0] = 0.0f; sBlade.m_afNormal[1] = 0.0f; sBlade.m_afNormal[2] = 1.0f; // check against overall scene bounding box (always do this) for (int nAxis = 0; nAxis < 3; ++nAxis) { m_afBoundingBox[nAxis] = min(m_afBoundingBox[nAxis], sBlade.m_afPos[nAxis]); m_afBoundingBox[nAxis + 3] = max(m_afBoundingBox[nAxis + 3], sBlade.m_afPos[nAxis]); } // set bottom and top color memcpy(sBlade.m_afBottomColor, sBlade.m_afNormal, 12); memcpy(sBlade.m_afTopColor, sBlade.m_afNormal, 12); // assign which blade texture map sBlade.m_ucWhichTexture = GetRandom(0, c_nNumBladeMaps - 1); // compute wind effects sBlade.m_fNoise = GetRandom(c_fMinBladeNoise, c_fMaxBladeNoise); sBlade.m_fThrow = GetRandom(c_fMinBladeThrow, c_fMaxBladeThrow); // compute dimensions sBlade.m_fSize = GetRandom(c_fMinBladeSize, c_fMaxBladeSize); // store all blades together vSceneBlades.push_back(sBlade); // create regions based on blades (do not remove) CreateRegions(vSceneBlades); // true = success, false = error return true; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::GetLodParams void CSpeedGrassRT::GetLodParams(float& fFarDistance, float& fTransitionLength) { fFarDistance = m_fLodFarDistance; fTransitionLength = m_fLodTransitionLength; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::SetLodParams void CSpeedGrassRT::SetLodParams(float fFarDistance, float fTransitionLength) { m_fLodFarDistance = fFarDistance; m_fLodTransitionLength = fTransitionLength; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::Cull // // Using a two-dimensional projection, determine which regions // intersect with the view frustum (+Z is assumed to be up) void CSpeedGrassRT::Cull(void) { // convert raw frustum min and max values into min and max region cell indices int anFrustumCellsMin[2], anFrustumCellsMax[2]; ConvertCoordsToCell(m_afFrustumMin, anFrustumCellsMin); ConvertCoordsToCell(m_afFrustumMax, anFrustumCellsMax); // set all regions to culled, modify later for (int i = 0; i < m_nNumRegions; ++i) m_pRegions[i].m_bCulled = true; int nRegionsDrawn = 0; // is the entire set of regions culled? if ((anFrustumCellsMin[0] < 0 && anFrustumCellsMax[0] < 0) || (anFrustumCellsMin[0] >= m_nNumRegionCols && anFrustumCellsMax[0] >= m_nNumRegionCols) || (anFrustumCellsMin[1] < 0 && anFrustumCellsMax[1] < 0) || (anFrustumCellsMin[1] >= m_nNumRegionRows && anFrustumCellsMax[1] >= m_nNumRegionRows)) m_bAllRegionsCulled = true; else { // clip cell values anFrustumCellsMin[0] = max(anFrustumCellsMin[0], 0); anFrustumCellsMin[1] = max(anFrustumCellsMin[1], 0); anFrustumCellsMax[0] = min(anFrustumCellsMax[0], m_nNumRegionCols - 1); anFrustumCellsMax[1] = min(anFrustumCellsMax[1], m_nNumRegionRows - 1); for (i = anFrustumCellsMin[0]; i <= anFrustumCellsMax[0]; ++i) for (int j = anFrustumCellsMin[1]; j <= anFrustumCellsMax[1]; ++j) { SRegion* pRegion = m_pRegions + GetRegionIndex(j, i); pRegion->m_bCulled = OutsideFrustum(pRegion); } m_bAllRegionsCulled = false; } } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::SetWindDirection void CSpeedGrassRT::SetWindDirection(const float* pWindDir) { memcpy(m_afWindDir, pWindDir, 3 * sizeof(float)); m_afWindDir[3] = 0.0f; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::GetWindDirection const float* CSpeedGrassRT::GetWindDirection(void) { return m_afWindDir; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::GetCameraPos const float* CSpeedGrassRT::GetCameraPos(void) { return m_afCameraPos; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::SetCamera void CSpeedGrassRT::SetCamera(const float* pPosition, const double* pModelviewMatrix) { memcpy(m_afCameraPos, pPosition, 3 * sizeof(float)); // "right" vector m_afCameraRight[0] = pModelviewMatrix[0]; m_afCameraRight[1] = pModelviewMatrix[4]; m_afCameraRight[2] = pModelviewMatrix[8]; // "up" vector m_afCameraUp[0] = pModelviewMatrix[1]; m_afCameraUp[1] = pModelviewMatrix[5]; m_afCameraUp[2] = pModelviewMatrix[9]; // "out of screen" vector m_afCameraOut[0] = pModelviewMatrix[2]; m_afCameraOut[1] = pModelviewMatrix[6]; m_afCameraOut[2] = pModelviewMatrix[10]; // with direction changed, billboard turns ComputeUnitBillboard( ); // compute new frustum box ComputeFrustum( ); } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::SetPerspective void CSpeedGrassRT::SetPerspective(float fAspectRatio, float fFieldOfView) { m_fAspectRatio = fAspectRatio; m_fFieldOfView = D3DXToRadian(fAspectRatio * fFieldOfView); } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::CreateRegions void CSpeedGrassRT::CreateRegions(const vector& vSceneBlades, float fCollisionDistance) { // create regions based on overall extents DeleteRegions( ); m_nNumRegions = int(m_nNumRegionRows * m_nNumRegionCols); m_pRegions = new SRegion[m_nNumRegions]; // run through all regions, computing extents for each float fCellWidth = (m_afBoundingBox[3] - m_afBoundingBox[0]) / m_nNumRegionCols; float fCellHeight = (m_afBoundingBox[4] - m_afBoundingBox[1]) / m_nNumRegionRows; float fY = m_afBoundingBox[1]; for (int nRow = 0; nRow < m_nNumRegionRows; ++nRow) { float fX = m_afBoundingBox[0]; for (int nCol = 0; nCol < m_nNumRegionCols; ++nCol) { SRegion* pRegion = m_pRegions + GetRegionIndex(nRow, nCol); // compute extents pRegion->m_afMin[0] = fX; pRegion->m_afMax[0] = fX + fCellWidth; pRegion->m_afMin[1] = fY; pRegion->m_afMax[1] = fY + fCellHeight; // compute center pRegion->m_afCenter[0] = 0.5f * (pRegion->m_afMin[0] + pRegion->m_afMax[0]); pRegion->m_afCenter[1] = 0.5f * (pRegion->m_afMin[1] + pRegion->m_afMax[1]); // compute culling radius pRegion->m_fCullingRadius = 1.1f * sqrt( ((pRegion->m_afMax[0] - pRegion->m_afCenter[0]) * (pRegion->m_afMax[0] - pRegion->m_afCenter[0])) + ((pRegion->m_afMax[1] - pRegion->m_afCenter[1]) * (pRegion->m_afMax[1] - pRegion->m_afCenter[1])) ); fX += fCellWidth; } fY += fCellHeight; } // assign each blade of grass to its particular region for (vector::const_iterator iBlade = vSceneBlades.begin( ); iBlade != vSceneBlades.end( ); ++iBlade) { // convert position to row/col index float fPercentAlongX = (iBlade->m_afPos[0] - m_afBoundingBox[0]) / (m_afBoundingBox[3] - m_afBoundingBox[0]); float fPercentAlongY = (iBlade->m_afPos[1] - m_afBoundingBox[1]) / (m_afBoundingBox[4] - m_afBoundingBox[1]); // clip values unsigned int uiCol = min(fPercentAlongX * m_nNumRegionCols, m_nNumRegionCols - 1); unsigned int uiRow = min(fPercentAlongY * m_nNumRegionRows, m_nNumRegionRows - 1); m_pRegions[GetRegionIndex(uiRow, uiCol)].m_vBlades.push_back(*iBlade); } // compute z extents (now that the blades are in) for (int i = 0; i < m_nNumRegions; ++i) { SRegion* pRegion = m_pRegions + i; pRegion->m_afMin[2] = FLT_MAX; pRegion->m_afMax[2] = -FLT_MAX; for (vector::iterator iBlade = pRegion->m_vBlades.begin( ); iBlade != pRegion->m_vBlades.end( ); ++iBlade) { pRegion->m_afMin[2] = min(pRegion->m_afMin[2], iBlade->m_afPos[2]); pRegion->m_afMax[2] = max(pRegion->m_afMax[2], iBlade->m_afPos[2] + iBlade->m_fSize); } pRegion->m_afCenter[0] = 0.5f * (pRegion->m_afMin[0] + pRegion->m_afMax[0]); pRegion->m_afCenter[1] = 0.5f * (pRegion->m_afMin[1] + pRegion->m_afMax[1]); pRegion->m_afCenter[2] = 0.5f * (pRegion->m_afMin[2] + pRegion->m_afMax[2]); // compute culling radius pRegion->m_fCullingRadius = 1.1f * sqrt( ((pRegion->m_afMax[0] - pRegion->m_afCenter[0]) * (pRegion->m_afMax[0] - pRegion->m_afCenter[0])) + ((pRegion->m_afMax[1] - pRegion->m_afCenter[1]) * (pRegion->m_afMax[1] - pRegion->m_afCenter[1])) + ((pRegion->m_afMax[2] - pRegion->m_afCenter[2]) * (pRegion->m_afMax[2] - pRegion->m_afCenter[2])) ); } // collision detection if (fCollisionDistance > 0.0f) { fCollisionDistance *= fCollisionDistance; for (int nRow = 0; nRow < m_nNumRegionRows; ++nRow) { float fX = m_afBoundingBox[0]; for (int nCol = 0; nCol < m_nNumRegionCols; ++nCol) { SRegion* pRegion = m_pRegions + GetRegionIndex(nRow, nCol); // check each blade against all other blades in the region for (DWORD i = 0; i < pRegion->m_vBlades.size( ); ++i) { float fX = pRegion->m_vBlades[i].m_afPos[0]; float fY = pRegion->m_vBlades[i].m_afPos[1]; bool bCollision = false; for (DWORD j = 0; j < pRegion->m_vBlades.size( ) && !bCollision; ++j) { if (i != j) { float fDistance = (fX - pRegion->m_vBlades[j].m_afPos[0]) * (fX - pRegion->m_vBlades[j].m_afPos[0]) + (fY - pRegion->m_vBlades[j].m_afPos[1]) * (fY - pRegion->m_vBlades[j].m_afPos[1]); if (fDistance < fCollisionDistance) bCollision = true; } } // delete the blade if necessary and adjust the main loop counter to compensate if (bCollision) pRegion->m_vBlades.erase(pRegion->m_vBlades.begin( ) + i--); } } } } } ////////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::RotateAxisFromIdentity __forceinline void CSpeedGrassRT::RotateAxisFromIdentity(D3DXMATRIX * pMat, const float & c_fAngle, const D3DXVECTOR3 & c_rv3Axis) { float s = VectorSinD(c_fAngle); float c = VectorCosD(c_fAngle); float t = 1.0 - c; float x = c_rv3Axis.x; float y = c_rv3Axis.y; float z = c_rv3Axis.z; pMat->_11 = t * x * x + c; pMat->_12 = t * x * y + s * z; pMat->_13 = t * x * z - s * y; pMat->_21 = t * x * y - s * z; pMat->_22 = t * y * y + c; pMat->_23 = t * y * z + s * x; pMat->_31 = t * x * z + s * y; pMat->_32 = t * y * z - s * x; pMat->_33 = t * z * z + c; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::ComputeFrustum void CSpeedGrassRT::ComputeFrustum(void) { // setup useful vectors // CVec3 cCameraIn(-m_afCameraOut[0], -m_afCameraOut[1], -m_afCameraOut[2]); // CVec3 cCameraUp(m_afCameraUp[0], m_afCameraUp[1], m_afCameraUp[2]); // CVec3 cCameraRight(m_afCameraRight[0], m_afCameraRight[1], m_afCameraRight[2]); // CVec3 cCameraPos(m_afCameraPos[0], m_afCameraPos[1], m_afCameraPos[2]); // CVec3 cFarPoint = cCameraPos + cCameraIn * (m_fLodFarDistance + m_fLodTransitionLength); D3DXVECTOR3 cCameraIn(-m_afCameraOut[0], -m_afCameraOut[1], -m_afCameraOut[2]); D3DXVECTOR3 cCameraUp(m_afCameraUp[0], m_afCameraUp[1], m_afCameraUp[2]); D3DXVECTOR3 cCameraRight(m_afCameraRight[0], m_afCameraRight[1], m_afCameraRight[2]); D3DXVECTOR3 cCameraPos(m_afCameraPos[0], m_afCameraPos[1], m_afCameraPos[2]); D3DXVECTOR3 cFarPoint = cCameraPos + cCameraIn * (m_fLodFarDistance + m_fLodTransitionLength); // far plane // memcpy(m_afFrustumPlanes[0], cCameraIn, 3 * sizeof(float)); // m_afFrustumPlanes[0][3] = -(cCameraIn ^ cFarPoint); // operator^ is dot product m_afFrustumPlanes[0][0] = cCameraIn.x; m_afFrustumPlanes[0][1] = cCameraIn.y; m_afFrustumPlanes[0][2] = cCameraIn.z; m_afFrustumPlanes[0][3] = -D3DXVec3Dot(&cCameraIn, &cFarPoint); // operator^ is dot product // CRotTransform cRotate(true); D3DXMATRIX cRotate; D3DXMatrixIdentity(&cRotate); D3DXVECTOR3 cNormal; // upper plane // cRotate.RotateAxisFromIdentity(VecRad2Deg(0.5f * m_fFieldOfView * m_fAspectRatio + c_fHalfPi) , cCameraRight); // CVec3 cNormal = cCameraIn * cRotate; // cNormal.Normalize( ); // memcpy(m_afFrustumPlanes[1], cNormal, 3 * sizeof(float)); // m_afFrustumPlanes[1][3] = -(cNormal ^ cCameraPos); // left plane // cRotate.RotateAxisFromIdentity(VecRad2Deg(0.5f * m_fFieldOfView + c_fHalfPi) , cCameraUp); // cNormal = cCameraIn * cRotate; // cNormal.Normalize( ); // memcpy(m_afFrustumPlanes[2], cNormal, 3 * sizeof(float)); // m_afFrustumPlanes[2][3] = -(cNormal ^ cCameraPos); // lower plane // cRotate.RotateAxisFromIdentity(-VecRad2Deg(0.5f * m_fFieldOfView * m_fAspectRatio + c_fHalfPi) , cCameraRight); // cNormal = cCameraIn * cRotate; // cNormal.Normalize( ); // memcpy(m_afFrustumPlanes[3], cNormal, 3 * sizeof(float)); // m_afFrustumPlanes[3][3] = -(cNormal ^ cCameraPos); // right plane // cRotate.RotateAxisFromIdentity(-VecRad2Deg(0.5f * m_fFieldOfView + c_fHalfPi) , cCameraUp); // cNormal = cCameraIn * cRotate; // cNormal.Normalize( ); // memcpy(m_afFrustumPlanes[4], cNormal, 3 * sizeof(float)); // m_afFrustumPlanes[4][3] = -(cNormal ^ cCameraPos); RotateAxisFromIdentity(&cRotate, D3DXToDegree(0.5f * m_fFieldOfView * m_fAspectRatio + c_fHalfPi), cCameraRight); D3DXVec3TransformCoord(&cNormal, &cCameraIn, &cRotate); D3DXVec3Normalize(&cNormal, &cNormal); m_afFrustumPlanes[1][0] = cNormal.x; m_afFrustumPlanes[1][1] = cNormal.y; m_afFrustumPlanes[1][2] = cNormal.z; m_afFrustumPlanes[1][3] = -D3DXVec3Dot(&cNormal, &cCameraPos); // operator^ is dot product RotateAxisFromIdentity(&cRotate, D3DXToDegree(0.5f * m_fFieldOfView + c_fHalfPi), cCameraUp); D3DXVec3TransformCoord(&cNormal, &cCameraIn, &cRotate); D3DXVec3Normalize(&cNormal, &cNormal); m_afFrustumPlanes[2][0] = cNormal.x; m_afFrustumPlanes[2][1] = cNormal.y; m_afFrustumPlanes[2][2] = cNormal.z; m_afFrustumPlanes[2][3] = -D3DXVec3Dot(&cNormal, &cCameraPos); // operator^ is dot product RotateAxisFromIdentity(&cRotate, -D3DXToDegree(0.5f * m_fFieldOfView * m_fAspectRatio + c_fHalfPi), cCameraRight); D3DXVec3TransformCoord(&cNormal, &cCameraIn, &cRotate); D3DXVec3Normalize(&cNormal, &cNormal); m_afFrustumPlanes[3][0] = cNormal.x; m_afFrustumPlanes[3][1] = cNormal.y; m_afFrustumPlanes[3][2] = cNormal.z; m_afFrustumPlanes[3][3] = -D3DXVec3Dot(&cNormal, &cCameraPos); // operator^ is dot product RotateAxisFromIdentity(&cRotate, -D3DXToDegree(0.5f * m_fFieldOfView + c_fHalfPi), cCameraUp); D3DXVec3TransformCoord(&cNormal, &cCameraIn, &cRotate); D3DXVec3Normalize(&cNormal, &cNormal); m_afFrustumPlanes[4][0] = cNormal.x; m_afFrustumPlanes[4][1] = cNormal.y; m_afFrustumPlanes[4][2] = cNormal.z; m_afFrustumPlanes[4][3] = -D3DXVec3Dot(&cNormal, &cCameraPos); // operator^ is dot product // frustum points float fFrustumHeight = (m_fLodFarDistance + m_fLodTransitionLength) * tanf(0.5f * m_fFieldOfView); float fFrustumWidth = (m_fLodFarDistance + m_fLodTransitionLength) * tanf(0.5f * m_fFieldOfView * m_fAspectRatio); // CVec3 acFrustum[5]; D3DXVECTOR3 acFrustum[5]; acFrustum[0] = cCameraPos; acFrustum[1] = cFarPoint + cCameraRight * fFrustumWidth + cCameraUp * fFrustumHeight; acFrustum[2] = cFarPoint - cCameraRight * fFrustumWidth + cCameraUp * fFrustumHeight; acFrustum[3] = cFarPoint - cCameraRight * fFrustumWidth - cCameraUp * fFrustumHeight; acFrustum[4] = cFarPoint + cCameraRight * fFrustumWidth - cCameraUp * fFrustumHeight; // find min/max (x,y) coordinates m_afFrustumMin[0] = m_afFrustumMin[1] = FLT_MAX; m_afFrustumMax[0] = m_afFrustumMax[1] = -FLT_MAX; for (int i = 0; i < 5; ++i) { m_afFrustumMin[0] = min(m_afFrustumMin[0], acFrustum[i][0]); m_afFrustumMax[0] = max(m_afFrustumMax[0], acFrustum[i][0]); m_afFrustumMin[1] = min(m_afFrustumMin[1], acFrustum[i][1]); m_afFrustumMax[1] = max(m_afFrustumMax[1], acFrustum[i][1]); } } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::ComputeUnitBillboard void CSpeedGrassRT::ComputeUnitBillboard(void) { // float fAzimuth = D3DXToDegree(atan2(-m_afCameraOut[1], -m_afCameraOut[0])); float fAzimuth = atan2(-m_afCameraOut[1], -m_afCameraOut[0]); // CRotTransform cTrans; // cTrans.RotateZ(fAzimuth); // // static CVec3 afCorner1(0.0f, 0.5f, 1.0f); // static CVec3 afCorner2(0.0f, -0.5f, 1.0f); // static CVec3 afCorner3(0.0f, -0.5f, 0.0f); // static CVec3 afCorner4(0.0f, 0.5f, 0.0f); // // CVec3 afNewCorner1 = afCorner1 * cTrans; // CVec3 afNewCorner2 = afCorner2 * cTrans; // CVec3 afNewCorner3 = afCorner3 * cTrans; // CVec3 afNewCorner4 = afCorner4 * cTrans; // // memcpy(m_afUnitBillboard + 0, afNewCorner1.m_afData, 3 * sizeof(float)); // memcpy(m_afUnitBillboard + 3, afNewCorner2.m_afData, 3 * sizeof(float)); // memcpy(m_afUnitBillboard + 6, afNewCorner3.m_afData, 3 * sizeof(float)); // memcpy(m_afUnitBillboard + 9, afNewCorner4.m_afData, 3 * sizeof(float)); D3DXMATRIX cTrans; D3DXMatrixRotationZ(&cTrans, fAzimuth); static D3DXVECTOR3 afCorner1(0.0f, 0.5f, 1.0f); static D3DXVECTOR3 afCorner2(0.0f, -0.5f, 1.0f); static D3DXVECTOR3 afCorner3(0.0f, -0.5f, 0.0f); static D3DXVECTOR3 afCorner4(0.0f, 0.5f, 0.0f); D3DXVECTOR3 afNewCorner1; D3DXVECTOR3 afNewCorner2; D3DXVECTOR3 afNewCorner3; D3DXVECTOR3 afNewCorner4; D3DXVec3TransformCoord(&afNewCorner1, &afCorner1, &cTrans); D3DXVec3TransformCoord(&afNewCorner2, &afCorner2, &cTrans); D3DXVec3TransformCoord(&afNewCorner3, &afCorner3, &cTrans); D3DXVec3TransformCoord(&afNewCorner4, &afCorner4, &cTrans); m_afUnitBillboard[0] = afNewCorner1.x; m_afUnitBillboard[1] = afNewCorner1.y; m_afUnitBillboard[2] = afNewCorner1.z; m_afUnitBillboard[3] = afNewCorner2.x; m_afUnitBillboard[4] = afNewCorner2.y; m_afUnitBillboard[5] = afNewCorner2.z; m_afUnitBillboard[6] = afNewCorner3.x; m_afUnitBillboard[7] = afNewCorner3.y; m_afUnitBillboard[8] = afNewCorner3.z; m_afUnitBillboard[9] = afNewCorner4.x; m_afUnitBillboard[10] = afNewCorner4.y; m_afUnitBillboard[11] = afNewCorner4.z; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::ConvertCoordsToCell void CSpeedGrassRT::ConvertCoordsToCell(const float* pCoords, int* pGridCoords) const { float fPercentAlongX = (pCoords[0] - m_afBoundingBox[0]) / (m_afBoundingBox[3] - m_afBoundingBox[0]); float fPercentAlongY = (pCoords[1] - m_afBoundingBox[1]) / (m_afBoundingBox[4] - m_afBoundingBox[1]); if (fPercentAlongX < 0.0f) pGridCoords[0] = -1; else if (fPercentAlongX > 1.0f) pGridCoords[0] = m_nNumRegionCols; else pGridCoords[0] = fPercentAlongX * m_nNumRegionCols; if (fPercentAlongY < 0.0f) pGridCoords[1] = -1; else if (fPercentAlongY > 1.0f) pGridCoords[1] = m_nNumRegionRows; else pGridCoords[1] = fPercentAlongY * m_nNumRegionRows; } /////////////////////////////////////////////////////////////////////// // CSpeedGrassRT::OutsideFrustum __forceinline bool CSpeedGrassRT::OutsideFrustum(CSpeedGrassRT::SRegion* pRegion) { bool bOutside = false; for (int i = 0; i < 5 && !bOutside; ++i) if (m_afFrustumPlanes[i][0] * pRegion->m_afCenter[0] + m_afFrustumPlanes[i][1] * pRegion->m_afCenter[1] + m_afFrustumPlanes[i][2] * pRegion->m_afCenter[2] + m_afFrustumPlanes[i][3] > pRegion->m_fCullingRadius) bOutside = true; return bOutside; } #endif // USE_SPEEDGRASS