www.pudn.com > WaveSimulation.rar > Wave.cpp
// Wave.cpp: implementation of the CWave class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Wave.h" #include "Bezier.h" #include "Terrian.h" #include#include #include ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// #define G 9.8f #define SMALL 0.0001f CWave::CWave() { memset(m_WaveLineArray,0,sizeof(WaveLine) * (WAVE_ARRAY_SIZE + 1)); memset(&m_Segment1,0,sizeof(WaveSegment)); memset(&m_Segment2,0,sizeof(WaveSegment)); m_zParticleIndex = 0; m_WindSpeed = 6.5f; } CWave::~CWave() { } void CWave::Init() { m_rOrbitRadius = ComOrbitRadius(m_WindSpeed); m_wAngleSpeed = ComAngleSpeed(m_WindSpeed); m_TPeriod = 2.0f * PI / m_wAngleSpeed; m_LWaveLength = G * SQR( m_TPeriod ) / (2 * PI); m_kInf = (2 * PI) / m_LWaveLength; m_cSpeed = 2 * PI * m_rOrbitRadius / m_TPeriod; } float CWave::ComOrbitRadius(float windSpeed) { float r = 0.0f; if(windSpeed > SMALL) r = 3.0f * 7.065f * powf(windSpeed,2.5) / 2000.0f ; else r = SMALL; return r; } float CWave::ComAngleSpeed(float windSpeed) { float w; if(windSpeed > SMALL) w = sqrtf(2.0f / 30.0f) * G / windSpeed; else w = SMALL; return w; } inline float CWave::ComWaveNumber(float x0, float z0, float windSpeed, float deep) { float maxk,k; maxk = m_kInf; if( 2.0f * deep > m_LWaveLength ) k = maxk; else { if(deep > SMALL) k = sqrtf(maxk / deep); else k = sqrtf(maxk / SMALL); float s1,s2; s1 = (m_LWaveLength / 2.0f - deep) / (m_LWaveLength / 2.0f) ; s2 = 1.0f - s1; k = s1 * k + s2 * m_kInf; } return k ; } void CWave::ComXY(float x, float z,float h, float *t) { float r,d,phaseangle; r = m_rOrbitRadius; d = ComD(x,z,m_WindSpeed,h); m_aPhaseAngle = d + m_wAngleSpeed * m_tCurrentTime; t[0] = z + r * sinf(m_aPhaseAngle); float lamda = 0.0f,dz = 0.0f,dt = 0.0f; lamda = 2.0f; dz = (z - t[0]) * 2; dt = m_TPeriod / 100.0f ; phaseangle = m_aPhaseAngle + lamda * dz * dt ; int n = phaseangle / (2*PI); phaseangle -= n*2*PI; if(phaseangle < 0) phaseangle += 2*PI; if( phaseangle < PI/2.0f ) phaseangle *= (phaseangle / (PI/2)); t[1] = -r * cosf(phaseangle); //newy t[0] = z + r * sinf(phaseangle); //newz if(2 * r > h) { t[1] = -r * cosf(phaseangle) * h /( 2 * r); //newy } } float CWave::ComD(float x0, float z0, float windSpeed, float h) { return z0 / 3.0f; } void CWave::ComputeWave(float x,float dtimet) { m_tCurrentTime += dtimet; float t[2]; for(int i = 0; i < WAVE_ARRAY_SIZE; i++) { float deep ; if(i <= 100) deep = i / 50.0f; else if(i < 200) deep = i / 10.0f - 8.0f; else deep = 200/ 10.0f - 8.0f; ComXY(x,i / 6.0f, deep,t); m_WaveLineArray[i].x = x; m_WaveLineArray[i].y = t[1]; m_WaveLineArray[i].z = t[0]; } int nperiod = m_tCurrentTime / m_TPeriod; float periodlife = (m_tCurrentTime - nperiod * m_TPeriod) / m_TPeriod ; //0~~1 for(i = WAVE_ARRAY_SIZE; i >= 0; i--) m_WaveLineArray[i].y *= (0.2f + sinf(periodlife * PI) ) / 1.2f; if(m_Segment1.CurrentState == WS_STATE_NORMAL) { SearchStartEnd(m_Segment1.StartIndex,m_Segment1.EndIndex); m_Segment1.RemainTime =m_Segment1.StageTime = m_TPeriod; m_Segment1.CurrentState = WS_STATE_CURVE; } ComputeCurve(m_Segment1,dtimet,x); if(m_Segment2.CurrentState != WS_STATE_NORMAL) ComputeCurve(m_Segment2,dtimet,x); for(i = WAVE_ARRAY_SIZE; i >= 0; i--) { float deep ; deep = -g_cTerrian.GetPositionHeight(x,m_WaveLineArray[i].z); if(deep > m_WaveLineArray[i].y && m_WaveLineArray[i].z <= 5.0f ) m_WaveLineArray[i].y = deep + 0.01f; } MoveParticle(dtimet); } void CWave::SearchStartEnd(int &sI, int &eI) { int changenumber = 0; int presign = m_WaveLineArray[WAVE_ARRAY_SIZE].y > 0 ? 1 : -1;//前一个的符号 for(int i = WAVE_ARRAY_SIZE; i >= 0; i--) { int cursign = m_WaveLineArray[i].y > 0 ? 1 : -1; //当前符号 cursign *= presign; if(cursign < 0) //变号 { if(presign < 0)//由-变为+ 1, { changenumber = 1; sI = i; }//由+变为- -1 if(presign > 0 && changenumber > 0 ) { eI = i; return; } presign = -presign; } } } void CWave::ComputeCurve(WaveSegment &WS,float dtimet,float x) { switch(WS.CurrentState) { case WS_STATE_CURVE: DealWithCurveState(WS,dtimet,x); break; case WS_STATE_SURGE: DealWithSurgeState(WS,dtimet,x); break; case WS_STATE_RETREATE: DealWithRetreateState(WS,dtimet,x); break; default: break; } } //x 用于产生粒子 void CWave::DealWithCurveState(WaveSegment &WS,float dtimet,float x) { if(WS.RemainTime < dtimet) WS.RemainTime = 0; else WS.RemainTime -= dtimet; ///////////modify the offset RepositionStartEnd(WS.StartIndex, WS.EndIndex); float periodlife = ( WS.StageTime - WS.RemainTime) / WS.StageTime; //Init Bezier arg float x1,y1,x2,y2,x3,y3,x4,y4; float slopek1,slopek4; float t = 0.0f ,result[2]; int mI; mI = (WS.StartIndex + WS.EndIndex) / 2; x1 = m_WaveLineArray[WS.StartIndex].z; y1 = m_WaveLineArray[WS.StartIndex].y; slopek1 = ( m_WaveLineArray[WS.StartIndex].y - m_WaveLineArray[WS.StartIndex + 1].y ) / ( m_WaveLineArray[WS.StartIndex + 1].z - m_WaveLineArray[WS.StartIndex].z ); x4 = m_WaveLineArray[mI].z - periodlife * 3.5f * m_rOrbitRadius; y4 = m_WaveLineArray[mI].y + (1.0f + periodlife) * m_rOrbitRadius * sinf( (3.0f / 2.0f) * PI * periodlife); slopek4 = 2 * cosf(PI / 2.0f + periodlife * PI * 6 / 7); x2 = 0.80f * x1 + 0.20f * x4; y2 = y1 + slopek1 * (x1 - x2); x3 = 0.20f * x1 + 0.80f * x4; y3 = y4 + slopek4 * (x4 - x3); CBezier backBezier; backBezier.Init(x1,y1,x2,y2,x3,y3,x4,y4); int indexnum = abs(WS.StartIndex - mI); for(int index = 0; index <= indexnum; index++) { backBezier.ComputeBezier( (float)index / indexnum,result); m_WaveLineArray[WS.StartIndex - index].z = result[0]; m_WaveLineArray[WS.StartIndex - index].y = result[1]; } /////////front side float slopek42 = slopek4 / 3.0f; float x5,y5,x6,y6,x7,y7; x7 = m_WaveLineArray[WS.EndIndex].z; y7 = m_WaveLineArray[WS.EndIndex].y; float slopek7 = ( m_WaveLineArray[WS.EndIndex - 1].y - m_WaveLineArray[WS.EndIndex].y ) / ( m_WaveLineArray[WS.EndIndex - 1].z - m_WaveLineArray[WS.EndIndex].z ); x5 = x4 - cosf(PI / 3 + PI * periodlife) * m_rOrbitRadius * 1.0f; y5 = y4 - slopek42 * (x5 - x4); x6 = x7 + m_rOrbitRadius * (1.2f - periodlife); y6 = y7 - slopek7 * (x7 -x6); CBezier frontBezier; frontBezier.Init(x4,y4,x5,y5,x6,y6,x7,y7); t = 0.0f ; indexnum = abs(WS.EndIndex - mI); for(index = 0; index <= indexnum; index++) { frontBezier.ComputeBezier( (float)index / indexnum,result); m_WaveLineArray[mI - index].z = result[0]; m_WaveLineArray[mI - index].y = result[1]; } //enter to next stage if(WS.RemainTime < 0.00000001 * m_TPeriod) { WS.CurrentState = WS_STATE_SURGE;\ WS.RemainTime = 0.0f; WS.StageTime = 1.0f; } /////////////判断是否需要涌向岸边 int tempIndex = WS.EndIndex - 1; while(tempIndex >= 1 ) { if(m_WaveLineArray[tempIndex].z >= x4 && m_WaveLineArray[tempIndex - 1].z < x4) break; else tempIndex--; } if(m_WaveLineArray[tempIndex].y >= y4 ) { WS.EndIndex = tempIndex; WS.CurrentState = WS_STATE_SURGE; WS.FitLength = WS.StartIndex - WS.EndIndex; WS.ScaleIndex = WS.EndIndex; // ///////////////////////产生粒子 for(int i = 0; i < 80; i++) { CreateParticle(x,y4,x4,true); } } } void CWave::DealWithSurgeState(WaveSegment &WS,float dtimet,float x) { RepositionStartEnd(WS.StartIndex, WS.EndIndex); float x1,y1,x2,y2,x3,y3,x4,y4; float slopek1,slopek4; if(WS.EndIndex > 0) //保持波形不变前进 { float fitlife; //上一段末尾时间的生命期 fitlife = WS.RemainTime / WS.StageTime; x1 = m_WaveLineArray[WS.StartIndex].z; y1 = m_WaveLineArray[WS.StartIndex].y; slopek1 = ( m_WaveLineArray[WS.StartIndex].y - m_WaveLineArray[WS.StartIndex + 1].y ) / ( m_WaveLineArray[WS.StartIndex + 1].z - m_WaveLineArray[WS.StartIndex].z ); x4 = m_WaveLineArray[WS.EndIndex].z; y4 = m_WaveLineArray[WS.EndIndex].y; slopek4 = 2 * cosf(PI / 2.0f + ( (float)WS.EndIndex / WS.ScaleIndex ) * fitlife * PI * 6 / 7); x2 = 0.80f * x1 + 0.20f * x4; y2 = y1 + slopek1 * (x1 - x2); x3 = 0.20f * x1 + 0.80f * x4; y3 = y4 + slopek4 * (x4 - x3); CBezier surgeBezier; surgeBezier.Init(x1,y1,x2,y2,x3,y3,x4,y4); int indexnum = abs(WS.EndIndex - WS.StartIndex); float result[2]; for(int index = 0; index <= indexnum; index++) { surgeBezier.ComputeBezier( (float)index / indexnum,result); m_WaveLineArray[WS.StartIndex - index].z = result[0]; m_WaveLineArray[WS.StartIndex - index].y = result[1]; } } else //到岸边时 { if(WS.StartIndex > 0)//直到sI变为0,波浪一直向前涌 { int i = 0 ; float plife = (float)(WS.FitLength - WS.StartIndex) / WS.FitLength; SearchStartEnd(m_Segment2.StartIndex,m_Segment2.EndIndex); i = (m_Segment2.StartIndex + m_Segment2.EndIndex) / 2; //position :from i to 0; //time: from 0 to 1; x1 = 0.0f; y1 = 0.0f; slopek1 = 0.0f; x4 = 1.0f; y4 = -sinf(plife * PI) * m_rOrbitRadius * 0.5f; slopek4 = plife; x2 = 0.75f * x1 + 0.25f * x4; y2 = 0.0f; x3 = 0.25f * x1 + 0.75f * x4; y3 = y4 - slopek4 * (x3 - x4); CBezier beachBezier; beachBezier.Init(x1,y1,x2,y2,x3,y3,x4,y4); float result[2]; for(int j = i; j >=0 ; j--) { beachBezier.ComputeBezier( (float)(i - j) / i,result); m_WaveLineArray[j].z += result[1]; } } else { WS.CurrentState = WS_STATE_RETREATE; WS.RemainTime = WS.StageTime = m_TPeriod * 0.8f; m_Segment2.CurrentState = WS_STATE_CURVE; m_Segment2.RemainTime = m_Segment2.StageTime = m_TPeriod; } } /////////////////////// for(int i = 0; i < 45 ;i++ ) { float y,z; int zIndex = 0; zIndex = WS.EndIndex; z = m_WaveLineArray[zIndex].z; y = ParticalYFromZ(z); CreateParticle(x,y,z,false); } } void CWave::DealWithRetreateState(WaveSegment &WS,float dtimet,float x) { if(WS.RemainTime < dtimet) WS.RemainTime = 0; else WS.RemainTime -= dtimet; ////////////compute float plife = 1.0f - WS.RemainTime / WS.StageTime; float x1,y1,x2,y2,x3,y3,x4,y4; float slopek1,slopek4; float result[2]; int i = m_Segment2.EndIndex; x1 = 0.0f; y1 = 0.0f; slopek1 = 10.0f; x4 = 1.0f; y4 = sinf(plife * PI) * m_rOrbitRadius * 4.0f; slopek4 = plife; x2 = 0.75f * x1 + 0.25f * x4; y2 = 0.0f; x3 = 0.25f * x1 + 0.75f * x4; y3 = y4 - slopek4 * (x3 - x4); CBezier beachBezier; beachBezier.Init(x1,y1,x2,y2,x3,y3,x4,y4); for(int j = i; j >=0 ; j--) { beachBezier.ComputeBezier( (float)(i - j) / i,result); m_WaveLineArray[j].z += result[1] * ( 1.0f - plife); } if(WS.RemainTime < 0.00000001 * m_TPeriod) { memcpy(&m_Segment1,&m_Segment2,sizeof(WaveSegment)); memset(&m_Segment2,0,sizeof(WaveSegment)); DealWithCurveState(m_Segment1,dtimet,x); } /////////////////////// for(i = 0; i < 25 ;i++ ) { float y,z; int zIndex = 0; int tempindex = m_Segment2.EndIndex / 4; tempindex = tempindex <= 0 ? 1 : tempindex; zIndex = rand() % tempindex; z = m_WaveLineArray[zIndex].z; y = ParticalYFromZ(z); CreateParticle(x,y,z,false); } } void CWave::RepositionStartEnd(int &sI, int &eI) { while(sI > 0 && m_WaveLineArray[sI].y < 0) sI--; while(eI > 0 && m_WaveLineArray[eI].y > 0) eI--; } void CWave::MoveParticle(float timedt) { int endIndex = m_Particle.m_iNextParticle; for(int i = 0; i < endIndex; i++) { FoamPartical *pParticle = &m_Particle.m_ParticalPool[i]; pParticle->z -= timedt * pParticle->hv ; pParticle->y += timedt * pParticle->vv ; //更新速度 pParticle->vv -= timedt * G / 6.0f; if(pParticle->z < m_WaveLineArray[1].z) { pParticle->z = m_WaveLineArray[1].z; pParticle->hv = -pParticle->hv; } float Interploatey = ParticalYFromZ(pParticle->z); if(pParticle->y < Interploatey) pParticle->y = Interploatey + 0.001f; //更新生命值 pParticle->life -= timedt; } m_Particle.Refresh(); } float CWave::ParticalYFromZ(float z) { while(m_zParticleIndex < WAVE_ARRAY_SIZE - 1 && m_WaveLineArray[m_zParticleIndex].z <= z) m_zParticleIndex++; while(m_zParticleIndex >= 0 && m_WaveLineArray[m_zParticleIndex].z > z) m_zParticleIndex--; float distance = m_WaveLineArray[m_zParticleIndex + 1].z - m_WaveLineArray[m_zParticleIndex ].z; float scale = (z - m_WaveLineArray[m_zParticleIndex].z) / distance; float result = 0.0f; float y1 = m_WaveLineArray[m_zParticleIndex].y; float y2 = m_WaveLineArray[m_zParticleIndex + 1].y; result = (1.0f - scale) * y1 + scale * y2; return result; } FoamPartical* CWave::CreateParticle(float x, float y, float z,bool state) { FoamPartical * newparticle = NULL; newparticle = m_Particle.GenerateFoam(); if(newparticle != NULL) { newparticle->x = x + (rand() % 50) / 50.0f - 0.5f; newparticle->y = y; newparticle->z = z + (rand() % 50) / 100.0f - 0.25f; if(state) { newparticle->vv = (rand() % 150) / 100.0f + 1.2f; newparticle->hv = 1.5f * m_cSpeed * ( 1.0f + (rand() % 50) / 100.0f); } else { newparticle->vv = 0.0f; newparticle->hv = m_cSpeed * ( 1.0f + (rand() % 50) / 100.0f); } newparticle->size = rand() % 4; if(newparticle->size == 0) newparticle->size = 1; newparticle->life = (rand() % 250) / 30.0f; } return newparticle; } void CWave::CompTextCor(WaveLine &wl,float &textcorx,float &textcory) { float x = wl.x + 10.0f; float y = wl.z + 10.0f; int nx,ny; nx = int(x / 20); ny = int(y / 20); x = x - nx * 20.0f; y = y - ny * 20.0f; x = x < 0 ? x + 20.0f : x; y = y < 0 ? y + 20.0f : y; textcorx = x / 20.0f; textcory = y / 20.0f; }