769 lines
26 KiB
C++
769 lines
26 KiB
C++
///////////////////////////////////////////////////////////////////////
|
|
// 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<SBlade> 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<SBlade> 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<SBlade>& 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<SBlade>::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<SBlade>::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
|