Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/renderer/WaterManager.cpp
Show First 20 Lines • Show All 463 Lines • ▼ Show 20 Lines | |||||
#undef ABOVEWATER | #undef ABOVEWATER | ||||
#undef UPDATELOOKAHEAD | #undef UPDATELOOKAHEAD | ||||
} | } | ||||
/////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////// | ||||
// Calculate our binary heightmap from the terrain heightmap. | // Calculate our binary heightmap from the terrain heightmap. | ||||
void WaterManager::RecomputeDistanceHeightmap() | void WaterManager::RecomputeDistanceHeightmap() | ||||
{ | { | ||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); | const CTerrain& terrain = g_Game->GetWorld()->GetTerrain(); | ||||
if (!terrain || !terrain->GetHeightMap()) | if (!terrain.GetHeightMap()) | ||||
return; | return; | ||||
size_t SideSize = m_MapSize; | size_t SideSize = m_MapSize; | ||||
// we want to look ahead some distance, but not too much (less efficient and not interesting). This is our lookahead. | // we want to look ahead some distance, but not too much (less efficient and not interesting). This is our lookahead. | ||||
const size_t maxLevel = 5; | const size_t maxLevel = 5; | ||||
if (!m_DistanceHeightmap) | if (!m_DistanceHeightmap) | ||||
{ | { | ||||
m_DistanceHeightmap = std::make_unique<float[]>(SideSize * SideSize); | m_DistanceHeightmap = std::make_unique<float[]>(SideSize * SideSize); | ||||
std::fill(m_DistanceHeightmap.get(), m_DistanceHeightmap.get() + SideSize * SideSize, static_cast<float>(maxLevel)); | std::fill(m_DistanceHeightmap.get(), m_DistanceHeightmap.get() + SideSize * SideSize, static_cast<float>(maxLevel)); | ||||
} | } | ||||
// Create a manhattan-distance heightmap. | // Create a manhattan-distance heightmap. | ||||
// This could be refined to only be done near the coast itself, but it's probably not necessary. | // This could be refined to only be done near the coast itself, but it's probably not necessary. | ||||
u16* heightmap = terrain->GetHeightMap(); | const u16* const heightmap = terrain.GetHeightMap(); | ||||
ComputeDirection<false>(m_DistanceHeightmap.get(), heightmap, m_WaterHeight, SideSize, maxLevel); | ComputeDirection<false>(m_DistanceHeightmap.get(), heightmap, m_WaterHeight, SideSize, maxLevel); | ||||
ComputeDirection<true>(m_DistanceHeightmap.get(), heightmap, m_WaterHeight, SideSize, maxLevel); | ComputeDirection<true>(m_DistanceHeightmap.get(), heightmap, m_WaterHeight, SideSize, maxLevel); | ||||
} | } | ||||
// This requires m_DistanceHeightmap to be defined properly. | // This requires m_DistanceHeightmap to be defined properly. | ||||
void WaterManager::CreateWaveMeshes() | void WaterManager::CreateWaveMeshes() | ||||
{ | { | ||||
if (m_MapSize == 0) | if (m_MapSize == 0) | ||||
return; | return; | ||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); | const CTerrain& terrain = g_Game->GetWorld()->GetTerrain(); | ||||
if (!terrain || !terrain->GetHeightMap()) | if (!terrain.GetHeightMap()) | ||||
return; | return; | ||||
m_ShoreWaves.clear(); | m_ShoreWaves.clear(); | ||||
m_ShoreWavesVBIndices.Reset(); | m_ShoreWavesVBIndices.Reset(); | ||||
if (m_Waviness < 5.0f && m_WaterType != L"ocean") | if (m_Waviness < 5.0f && m_WaterType != L"ocean") | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 185 Lines • ▼ Show 20 Lines | for (size_t j = 0; j < CoastalPointsChains[i].size()-waveSizes; ++j) | ||||
firstPerp = perp; | firstPerp = perp; | ||||
if ( a > 1 && perp.Dot(lastPerp) < 0.90f && perp.Dot(firstPerp) < 0.70f) | if ( a > 1 && perp.Dot(lastPerp) < 0.90f && perp.Dot(firstPerp) < 0.70f) | ||||
{ | { | ||||
width = a+1; | width = a+1; | ||||
break; | break; | ||||
} | } | ||||
if (terrain->GetExactGroundLevel(pos.X+perp.X*1.5f, pos.Y+perp.Y*1.5f) > m_WaterHeight) | if (terrain.GetExactGroundLevel(pos.X+perp.X*1.5f, pos.Y+perp.Y*1.5f) | ||||
> m_WaterHeight) | |||||
sign = -1; | sign = -1; | ||||
avgDepth += terrain->GetExactGroundLevel(pos.X+sign*perp.X*20.0f, pos.Y+sign*perp.Y*20.0f) - m_WaterHeight; | avgDepth += terrain.GetExactGroundLevel(pos.X+sign*perp.X*20.0f, | ||||
pos.Y+sign*perp.Y*20.0f) - m_WaterHeight; | |||||
float localOutmost = -2.0f; | float localOutmost = -2.0f; | ||||
while (localOutmost < 0.0f) | while (localOutmost < 0.0f) | ||||
{ | { | ||||
float depth = terrain->GetExactGroundLevel(pos.X+sign*perp.X*localOutmost, pos.Y+sign*perp.Y*localOutmost) - m_WaterHeight; | const float depth = terrain.GetExactGroundLevel( | ||||
pos.X+sign*perp.X*localOutmost, | |||||
pos.Y+sign*perp.Y*localOutmost) - m_WaterHeight; | |||||
if (depth < 0.0f || depth > 0.6f) | if (depth < 0.0f || depth > 0.6f) | ||||
localOutmost += 0.2f; | localOutmost += 0.2f; | ||||
else | else | ||||
break; | break; | ||||
} | } | ||||
outmost += localOutmost; | outmost += localOutmost; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | for (size_t j = 0; j < CoastalPointsChains[i].size()-waveSizes; ++j) | ||||
static const float perpT4[9] = { 2.0f, 2.1f, 1.2f, 1.5f, 1.7f, 1.9f, 2.7f, 3.8f, 9.0f }; | static const float perpT4[9] = { 2.0f, 2.1f, 1.2f, 1.5f, 1.7f, 1.9f, 2.7f, 3.8f, 9.0f }; | ||||
static const float heightT1[9] = { 0.0f, 0.2f, 0.5f, 0.8f, 0.9f, 0.85f, 0.6f, 0.2f, 0.0 }; | static const float heightT1[9] = { 0.0f, 0.2f, 0.5f, 0.8f, 0.9f, 0.85f, 0.6f, 0.2f, 0.0 }; | ||||
static const float heightT2[9] = { -0.8f, -0.4f, 0.0f, 0.1f, 0.1f, 0.03f, 0.0f, 0.0f, 0.0 }; | static const float heightT2[9] = { -0.8f, -0.4f, 0.0f, 0.1f, 0.1f, 0.03f, 0.0f, 0.0f, 0.0 }; | ||||
static const float heightT3[9] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0 }; | static const float heightT3[9] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0 }; | ||||
for (size_t t = 0; t < 9; ++t) | for (size_t t = 0; t < 9; ++t) | ||||
{ | { | ||||
float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT1[t]+outmost), | const float terrHeight = 0.05f + terrain.GetExactGroundLevel( | ||||
pos.X+sign*perp.X*(perpT1[t]+outmost), | |||||
pos.Y+sign*perp.Y*(perpT1[t]+outmost)); | pos.Y+sign*perp.Y*(perpT1[t]+outmost)); | ||||
point[t].m_BasePosition = CVector3D(pos.X+sign*perp.X*(perpT1[t]+outmost), baseHeight + heightT1[t]*sideNess + std::max(m_WaterHeight,terrHeight), | point[t].m_BasePosition = CVector3D(pos.X+sign*perp.X*(perpT1[t]+outmost), baseHeight + heightT1[t]*sideNess + std::max(m_WaterHeight,terrHeight), | ||||
pos.Y+sign*perp.Y*(perpT1[t]+outmost)); | pos.Y+sign*perp.Y*(perpT1[t]+outmost)); | ||||
} | } | ||||
for (size_t t = 0; t < 9; ++t) | for (size_t t = 0; t < 9; ++t) | ||||
{ | { | ||||
float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT2[t]+outmost), | const float terrHeight = 0.05f + terrain.GetExactGroundLevel( | ||||
pos.X+sign*perp.X*(perpT2[t]+outmost), | |||||
pos.Y+sign*perp.Y*(perpT2[t]+outmost)); | pos.Y+sign*perp.Y*(perpT2[t]+outmost)); | ||||
point[t].m_ApexPosition = CVector3D(pos.X+sign*perp.X*(perpT2[t]+outmost), baseHeight + heightT1[t]*sideNess + std::max(m_WaterHeight,terrHeight), | point[t].m_ApexPosition = CVector3D(pos.X+sign*perp.X*(perpT2[t]+outmost), baseHeight + heightT1[t]*sideNess + std::max(m_WaterHeight,terrHeight), | ||||
pos.Y+sign*perp.Y*(perpT2[t]+outmost)); | pos.Y+sign*perp.Y*(perpT2[t]+outmost)); | ||||
} | } | ||||
for (size_t t = 0; t < 9; ++t) | for (size_t t = 0; t < 9; ++t) | ||||
{ | { | ||||
float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT3[t]+outmost*sideNess), | const float terrHeight = 0.05f + terrain.GetExactGroundLevel( | ||||
pos.X+sign*perp.X*(perpT3[t]+outmost*sideNess), | |||||
pos.Y+sign*perp.Y*(perpT3[t]+outmost*sideNess)); | pos.Y+sign*perp.Y*(perpT3[t]+outmost*sideNess)); | ||||
point[t].m_SplashPosition = CVector3D(pos.X+sign*perp.X*(perpT3[t]+outmost*sideNess), baseHeight + heightT2[t]*sideNess + std::max(m_WaterHeight,terrHeight), pos.Y+sign*perp.Y*(perpT3[t]+outmost*sideNess)); | point[t].m_SplashPosition = CVector3D(pos.X+sign*perp.X*(perpT3[t]+outmost*sideNess), baseHeight + heightT2[t]*sideNess + std::max(m_WaterHeight,terrHeight), pos.Y+sign*perp.Y*(perpT3[t]+outmost*sideNess)); | ||||
} | } | ||||
for (size_t t = 0; t < 9; ++t) | for (size_t t = 0; t < 9; ++t) | ||||
{ | { | ||||
float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT4[t]+outmost), | const float terrHeight = 0.05f + terrain.GetExactGroundLevel( | ||||
pos.X+sign*perp.X*(perpT4[t]+outmost), | |||||
pos.Y+sign*perp.Y*(perpT4[t]+outmost)); | pos.Y+sign*perp.Y*(perpT4[t]+outmost)); | ||||
point[t].m_RetreatPosition = CVector3D(pos.X+sign*perp.X*(perpT4[t]+outmost), baseHeight + heightT3[t]*sideNess + std::max(m_WaterHeight,terrHeight), | point[t].m_RetreatPosition = CVector3D(pos.X+sign*perp.X*(perpT4[t]+outmost), baseHeight + heightT3[t]*sideNess + std::max(m_WaterHeight,terrHeight), | ||||
pos.Y+sign*perp.Y*(perpT4[t]+outmost)); | pos.Y+sign*perp.Y*(perpT4[t]+outmost)); | ||||
} | } | ||||
vertices.push_back(point[8]); | vertices.push_back(point[8]); | ||||
vertices.push_back(point[7]); | vertices.push_back(point[7]); | ||||
vertices.push_back(point[6]); | vertices.push_back(point[6]); | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | |||||
void WaterManager::RecomputeWindStrength() | void WaterManager::RecomputeWindStrength() | ||||
{ | { | ||||
if (m_MapSize <= 0) | if (m_MapSize <= 0) | ||||
return; | return; | ||||
if (!m_WindStrength) | if (!m_WindStrength) | ||||
m_WindStrength = std::make_unique<float[]>(m_MapSize * m_MapSize); | m_WindStrength = std::make_unique<float[]>(m_MapSize * m_MapSize); | ||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); | const CTerrain& terrain = g_Game->GetWorld()->GetTerrain(); | ||||
if (!terrain || !terrain->GetHeightMap()) | if (!terrain.GetHeightMap()) | ||||
return; | return; | ||||
CVector2D windDir = CVector2D(cos(m_WindAngle), sin(m_WindAngle)); | CVector2D windDir = CVector2D(cos(m_WindAngle), sin(m_WindAngle)); | ||||
int stepSize = 10; | int stepSize = 10; | ||||
ssize_t windX = -round(stepSize * windDir.X); | ssize_t windX = -round(stepSize * windDir.X); | ||||
ssize_t windY = -round(stepSize * windDir.Y); | ssize_t windY = -round(stepSize * windDir.Y); | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | else | ||||
} | } | ||||
} | } | ||||
// We have all starting points ready, move them all until the map is covered. | // We have all starting points ready, move them all until the map is covered. | ||||
for (SWindPoint& point : startingPoints) | for (SWindPoint& point : startingPoints) | ||||
{ | { | ||||
// Starting velocity is 1.0 unless in shallow water. | // Starting velocity is 1.0 unless in shallow water. | ||||
m_WindStrength[point.Y * m_MapSize + point.X] = 1.f; | m_WindStrength[point.Y * m_MapSize + point.X] = 1.f; | ||||
float depth = m_WaterHeight - terrain->GetVertexGroundLevel(point.X, point.Y); | const float depth = m_WaterHeight - terrain.GetVertexGroundLevel(point.X, point.Y); | ||||
if (depth > 0.f && depth < 2.f) | if (depth > 0.f && depth < 2.f) | ||||
m_WindStrength[point.Y * m_MapSize + point.X] = depth / 2.f; | m_WindStrength[point.Y * m_MapSize + point.X] = depth / 2.f; | ||||
point.windStrength = m_WindStrength[point.Y * m_MapSize + point.X]; | point.windStrength = m_WindStrength[point.Y * m_MapSize + point.X]; | ||||
bool onMap = true; | bool onMap = true; | ||||
while (onMap) | while (onMap) | ||||
for (size_t step = 0; step < movement.size(); ++step) | for (size_t step = 0; step < movement.size(); ++step) | ||||
{ | { | ||||
// Move wind speed towards the mean. | // Move wind speed towards the mean. | ||||
point.windStrength = 0.15f + point.windStrength * 0.85f; | point.windStrength = 0.15f + point.windStrength * 0.85f; | ||||
// Adjust speed based on height difference, a positive height difference slowly increases speed (simulate venturi effect) | // Adjust speed based on height difference, a positive height difference slowly increases speed (simulate venturi effect) | ||||
// and a lower height reduces speed (wind protection from hills/...) | // and a lower height reduces speed (wind protection from hills/...) | ||||
float heightDiff = std::max(m_WaterHeight, terrain->GetVertexGroundLevel(point.X + movement[step].first, point.Y + movement[step].second)) - | const float heightDiff = std::max(m_WaterHeight, terrain.GetVertexGroundLevel( | ||||
std::max(m_WaterHeight, terrain->GetVertexGroundLevel(point.X, point.Y)); | point.X + movement[step].first, point.Y + movement[step].second)) - | ||||
std::max(m_WaterHeight, terrain.GetVertexGroundLevel(point.X, point.Y)); | |||||
if (heightDiff > 0.f) | if (heightDiff > 0.f) | ||||
point.windStrength = std::min(2.f, point.windStrength + std::min(4.f, heightDiff) / 40.f); | point.windStrength = std::min(2.f, point.windStrength + std::min(4.f, heightDiff) / 40.f); | ||||
else | else | ||||
point.windStrength = std::max(0.f, point.windStrength + std::max(-4.f, heightDiff) / 5.f); | point.windStrength = std::max(0.f, point.windStrength + std::max(-4.f, heightDiff) / 5.f); | ||||
point.X += movement[step].first; | point.X += movement[step].first; | ||||
point.Y += movement[step].second; | point.Y += movement[step].second; | ||||
▲ Show 20 Lines • Show All 76 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator