Slight clean up of the water code. Uses vertex data instead of a texture for foam. Should be faster to generate and render. Still no Atlas support.
This was SVN commit r13374.
This commit is contained in:
parent
092108b304
commit
4233acfa36
@ -22,6 +22,7 @@ uniform float time;
|
||||
|
||||
varying vec3 worldPos;
|
||||
varying float waterDepth;
|
||||
varying vec4 waterInfo;
|
||||
|
||||
uniform sampler2D normalMap;
|
||||
uniform sampler2D normalMap2;
|
||||
@ -36,8 +37,6 @@ uniform sampler2D normalMap2;
|
||||
uniform sampler2D depthTex;
|
||||
#endif
|
||||
#if USE_FOAM || USE_WAVES
|
||||
uniform sampler2D heightmap;
|
||||
uniform sampler2D infoTex;
|
||||
uniform sampler2D Foam;
|
||||
uniform sampler2D waveTex;
|
||||
#endif
|
||||
@ -97,9 +96,9 @@ vec3 get_fog(vec3 color)
|
||||
void main()
|
||||
{
|
||||
#if USE_FOAM || USE_WAVES
|
||||
vec4 heightmapval = texture2D(heightmap, gl_TexCoord[3].zw);
|
||||
vec2 beachOrientation = heightmapval.rb - vec2(0.5,0.5);
|
||||
float distToShore = heightmapval.a;
|
||||
vec4 heightmapval = waterInfo;
|
||||
vec2 beachOrientation = heightmapval.rg;
|
||||
float distToShore = heightmapval.b;
|
||||
#endif
|
||||
|
||||
vec3 n, l, h, v; // Normal, light vector, half-vector and view vector (vector to eye)
|
||||
@ -182,11 +181,11 @@ void main()
|
||||
// texture is not rotated, moves twice faster in the opposite direction, translated.
|
||||
vec2 foam2RC = gl_TexCoord[0].st*1.8 + vec2(time*-0.019,time*-0.012) - 0.012*n.xz + vec2(0.4,0.2);
|
||||
|
||||
vec2 WaveRocking = cos(time*1.2566) * beachOrientation * clamp(1.0 - distToShore*2.0,0.1,1.0)/3.0;
|
||||
vec2 WaveRocking = cos(time*1.2566) * beachOrientation * clamp(1.0 - distToShore,0.1,1.0)/6.0;
|
||||
vec4 foam1 = texture2D(Foam, foam1RC + vec2(-WaveRocking.t,WaveRocking.s));
|
||||
vec4 foam2 = foam1.r*texture2D(Foam, foam2RC + WaveRocking);
|
||||
|
||||
vec3 finalFoam = min((foam2).rrr * texture2D(infoTex,gl_TexCoord[3].zw).g,1.0);
|
||||
vec3 finalFoam = min((foam2).rrr * waterInfo.a,1.0);
|
||||
|
||||
if ((1.0 - finalFoam.r) >= wavyFactor)
|
||||
finalFoam = vec3(0.0);
|
||||
|
@ -17,15 +17,17 @@ uniform float mapSize;
|
||||
|
||||
varying vec3 worldPos;
|
||||
varying float waterDepth;
|
||||
varying vec4 waterInfo;
|
||||
#if USE_SHADOW && USE_SHADOWS
|
||||
varying vec4 v_shadow;
|
||||
#endif
|
||||
attribute vec3 a_vertex;
|
||||
attribute vec4 a_encodedDepth;
|
||||
|
||||
attribute vec4 a_waterInfo;
|
||||
void main()
|
||||
{
|
||||
worldPos = a_vertex;
|
||||
waterInfo = a_waterInfo;
|
||||
waterDepth = dot(a_encodedDepth.xyz, vec3(255.0, -255.0, 1.0));
|
||||
|
||||
gl_TexCoord[0] = vec4(a_vertex.xz*repeatScale,translation);
|
||||
|
@ -6,6 +6,7 @@
|
||||
<stream name="color"/>
|
||||
<attrib name="a_vertex" semantics="gl_Vertex"/>
|
||||
<attrib name="a_encodedDepth" semantics="gl_Color"/>
|
||||
<attrib name="a_waterInfo" semantics="gl_MultiTexCoord0"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="glsl/water_high.fs"/>
|
||||
|
@ -45,6 +45,10 @@
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/components/ICmpWaterManager.h"
|
||||
|
||||
#include "tools/atlas/GameInterface/GameLoop.h"
|
||||
|
||||
extern GameLoopState* g_AtlasGameLoop;
|
||||
|
||||
const ssize_t BlendOffsets[9][2] = {
|
||||
{ 0, -1 },
|
||||
{ -1, -1 },
|
||||
@ -1297,7 +1301,7 @@ void CPatchRData::BuildWater()
|
||||
CmpPtr<ICmpWaterManager> cmpWaterManager(*m_Simulation, SYSTEM_ENTITY);
|
||||
if (!cmpWaterManager)
|
||||
return;
|
||||
|
||||
|
||||
// Build data for water
|
||||
std::vector<SWaterVertex> water_vertex_data;
|
||||
std::vector<GLushort> water_indices;
|
||||
@ -1307,9 +1311,16 @@ void CPatchRData::BuildWater()
|
||||
// TODO: This is not (yet) exported via the ICmp interface so... we stick to these values which can be compiled in defaults
|
||||
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
|
||||
|
||||
if (WaterMgr->m_NeedsFullReloading && !g_AtlasGameLoop->running)
|
||||
{
|
||||
WaterMgr->m_NeedsFullReloading = false;
|
||||
WaterMgr->CreateSuperfancyInfo(m_Simulation);
|
||||
}
|
||||
CPatch* patch = m_Patch;
|
||||
CTerrain* terrain = patch->m_Parent;
|
||||
|
||||
ssize_t mapSize = (size_t)terrain->GetVerticesPerSide();
|
||||
|
||||
ssize_t x1 = m_Patch->m_X*PATCH_SIZE;
|
||||
ssize_t z1 = m_Patch->m_Z*PATCH_SIZE;
|
||||
|
||||
@ -1374,6 +1385,21 @@ void CPatchRData::BuildWater()
|
||||
u8(clamp(depthFrac*255.0f, 0.0f, 255.0f)),
|
||||
u8(clamp(alpha*255.0f, 0.0f, 255.0f)));
|
||||
|
||||
int tx = x+x1;
|
||||
int ty = z+z1 + j*water_cell_size;
|
||||
|
||||
if (g_AtlasGameLoop->running)
|
||||
{
|
||||
// currently no foam is used so push whatever
|
||||
vertex.m_WaterData = CVector4D(0.0f,0.0f,0.0f,0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
vertex.m_WaterData = CVector4D(WaterMgr->m_WaveX[tx + ty*mapSize],
|
||||
WaterMgr->m_WaveZ[tx + ty*mapSize],
|
||||
WaterMgr->m_DistanceToShore[tx + ty*mapSize],
|
||||
WaterMgr->m_FoamFactor[tx + ty*mapSize]);
|
||||
}
|
||||
water_index_map[z+j*water_cell_size][x] = water_vertex_data.size();
|
||||
water_vertex_data.push_back(vertex);
|
||||
}
|
||||
@ -1418,6 +1444,7 @@ void CPatchRData::RenderWater(CShaderProgramPtr& shader)
|
||||
GLsizei stride = sizeof(SWaterVertex);
|
||||
shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &base[m_VBWater->m_Index].m_DepthData);
|
||||
shader->VertexPointer(3, GL_FLOAT, stride, &base[m_VBWater->m_Index].m_Position);
|
||||
shader->TexCoordPointer(GL_TEXTURE0, 4, GL_FLOAT, stride, &base[m_VBWater->m_Index].m_WaterData);
|
||||
|
||||
shader->AssertPointersBound();
|
||||
|
||||
|
@ -109,8 +109,9 @@ private:
|
||||
// p*255 + q*-255 + r = depth of water
|
||||
// a = depth-dependent alpha
|
||||
SColor4ub m_DepthData;
|
||||
CVector4D m_WaterData;
|
||||
};
|
||||
cassert(sizeof(SWaterVertex) == 16);
|
||||
cassert(sizeof(SWaterVertex) == 32);
|
||||
|
||||
// build this renderdata object
|
||||
void Build();
|
||||
|
@ -692,15 +692,10 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap*
|
||||
// we need to actually recompute the whole map settings.
|
||||
if (WaterMgr->m_NeedsFullReloading)
|
||||
{
|
||||
delete[] WaterMgr->m_Heightmap;
|
||||
WaterMgr->m_Heightmap = NULL;
|
||||
glDeleteTextures(1, &WaterMgr->m_HeightmapTexture);
|
||||
WaterMgr->m_NeedsReloading = false;
|
||||
WaterMgr->m_NeedsFullReloading = false;
|
||||
|
||||
WaterMgr->m_waveTT = 0;
|
||||
WaterMgr->m_depthTT = 0;
|
||||
}
|
||||
WaterMgr->m_NeedsReloading = false;
|
||||
}
|
||||
|
||||
if (g_AtlasGameLoop->running)
|
||||
@ -732,9 +727,12 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap*
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
// Calculating the advanced informations about Foam and all if the quality calls for it.
|
||||
if (WaterMgr->m_Heightmap == NULL && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves))
|
||||
/*if (WaterMgr->m_NeedsFullReloading && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves))
|
||||
{
|
||||
WaterMgr->m_NeedsFullReloading = false;
|
||||
WaterMgr->CreateSuperfancyInfo();
|
||||
|
||||
}*/
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
@ -783,7 +781,6 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap*
|
||||
// rendering
|
||||
m->wavesShader->Bind();
|
||||
m->wavesShader->BindTexture("waveTex", WaterMgr->m_Wave);
|
||||
m->wavesShader->BindTexture("infoTex", WaterMgr->m_OtherInfoTex);
|
||||
m->wavesShader->Uniform("time", (float)time);
|
||||
m->wavesShader->Uniform("waviness", WaterMgr->m_Waviness);
|
||||
m->wavesShader->Uniform("mapSize", (float)(WaterMgr->m_TexSize));
|
||||
@ -823,8 +820,6 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap*
|
||||
if (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves)
|
||||
{
|
||||
m->fancyWaterShader->BindTexture("Foam", WaterMgr->m_Foam);
|
||||
m->fancyWaterShader->BindTexture("heightmap", WaterMgr->m_HeightmapTexture);
|
||||
m->fancyWaterShader->BindTexture("infoTex", WaterMgr->m_OtherInfoTex);
|
||||
m->fancyWaterShader->Uniform("mapSize", (float)(WaterMgr->m_TexSize));
|
||||
}
|
||||
if (WaterMgr->m_WaterRealDepth)
|
||||
@ -840,7 +835,6 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap*
|
||||
|
||||
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
|
||||
|
||||
|
||||
// TODO: only bind what's really needed for that.
|
||||
m->fancyWaterShader->Uniform("sunDir", lightEnv.GetSunDir());
|
||||
m->fancyWaterShader->Uniform("sunColor", lightEnv.m_SunColor.X);
|
||||
|
@ -38,6 +38,10 @@
|
||||
#include "renderer/WaterManager.h"
|
||||
#include "renderer/Renderer.h"
|
||||
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/components/ICmpWaterManager.h"
|
||||
#include "simulation2/components/ICmpRangeManager.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WaterManager implementation
|
||||
@ -74,9 +78,10 @@ WaterManager::WaterManager()
|
||||
m_WaterTint = CColor(0.28f, 0.3f, 0.59f, 1.0f);
|
||||
m_Murkiness = 0.45f;
|
||||
m_RepeatPeriod = 16.0f;
|
||||
m_Heightmap = NULL;
|
||||
m_HeightmapTexture = 0;
|
||||
m_OtherInfoTex = 0;
|
||||
m_WaveX = NULL;
|
||||
m_WaveZ = NULL;
|
||||
m_DistanceToShore = NULL;
|
||||
m_FoamFactor = NULL;
|
||||
|
||||
m_WaterNormal = false;
|
||||
m_WaterRealDepth = false;
|
||||
@ -87,12 +92,11 @@ WaterManager::WaterManager()
|
||||
m_WaterShadows = false;
|
||||
|
||||
m_NeedsReloading = false;
|
||||
m_NeedsFullReloading = false;
|
||||
m_NeedsFullReloading = true;
|
||||
m_TerrainChangeThisTurn = false;
|
||||
|
||||
m_VBWaves = NULL;
|
||||
m_VBWavesIndices = NULL;
|
||||
m_TexSize = -1;
|
||||
|
||||
m_depthTT = 0;
|
||||
m_waveTT = 0;
|
||||
@ -103,9 +107,11 @@ WaterManager::~WaterManager()
|
||||
{
|
||||
// Cleanup if the caller messed up
|
||||
UnloadWaterTextures();
|
||||
delete[] m_Heightmap;
|
||||
glDeleteTextures(1, &m_HeightmapTexture);
|
||||
glDeleteTextures(1, &m_OtherInfoTex);
|
||||
delete[] m_WaveX;
|
||||
delete[] m_WaveZ;
|
||||
delete[] m_DistanceToShore;
|
||||
delete[] m_FoamFactor;
|
||||
|
||||
glDeleteTextures(1, &m_depthTT);
|
||||
glDeleteTextures(1, &m_waveTT);
|
||||
|
||||
@ -225,30 +231,55 @@ void WaterManager::UnloadWaterTextures()
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Create information about the terrain and wave vertices.
|
||||
void WaterManager::CreateSuperfancyInfo()
|
||||
void WaterManager::CreateSuperfancyInfo(CSimulation2* simulation)
|
||||
{
|
||||
ssize_t mapSize = g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide();
|
||||
ssize_t texSize = (GLsizei)round_up_to_pow2((size_t)mapSize);
|
||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
||||
ssize_t mapSize = terrain->GetVerticesPerSide();
|
||||
|
||||
u32* newHeightmap = NULL;
|
||||
newHeightmap = new u32[texSize*texSize];
|
||||
CmpPtr<ICmpWaterManager> cmpWaterManager(*simulation, SYSTEM_ENTITY);
|
||||
if (!cmpWaterManager)
|
||||
return; // REALLY shouldn't happen and will most likely crash.
|
||||
|
||||
// Using this to get some more optimization on circular maps
|
||||
CmpPtr<ICmpRangeManager> cmpRangeManager(*simulation, SYSTEM_ENTITY);
|
||||
if (!cmpRangeManager)
|
||||
return;
|
||||
bool circular = cmpRangeManager->GetLosCircular();
|
||||
float mSize = mapSize*mapSize;
|
||||
float halfSize = (mapSize/2.0);
|
||||
|
||||
// Warning: this won't work with multiple water planes
|
||||
m_WaterHeight = cmpWaterManager->GetExactWaterLevel(0,0);
|
||||
|
||||
u32* otherInfo = NULL;
|
||||
otherInfo = new u32[texSize*texSize];
|
||||
// TODO: change this whenever we incrementally update because it's def. not too efficient
|
||||
delete[] m_WaveX;
|
||||
delete[] m_WaveZ;
|
||||
delete[] m_DistanceToShore;
|
||||
delete[] m_FoamFactor;
|
||||
|
||||
m_WaveX = new float[mapSize*mapSize];
|
||||
m_WaveZ = new float[mapSize*mapSize];
|
||||
m_DistanceToShore = new float[mapSize*mapSize];
|
||||
m_FoamFactor = new float[mapSize*mapSize];
|
||||
|
||||
u16* heightmap = terrain->GetHeightMap();
|
||||
|
||||
// Recovering wave intensity
|
||||
u8* waveForceHQ = new u8[(mapSize+1)*(mapSize+1)]; // high qual map.
|
||||
u16 waterHeightInu16 = this->m_WaterHeight/HEIGHT_SCALE;
|
||||
// some temporary stuff for wave intensity
|
||||
// not really used too much right now.
|
||||
u8* waveForceHQ = new u8[mapSize*mapSize];
|
||||
u16 waterHeightInu16 = m_WaterHeight/HEIGHT_SCALE;
|
||||
|
||||
for (ssize_t i = 0; i < mapSize; ++i)
|
||||
{
|
||||
for (ssize_t j = 0; j < mapSize; ++j)
|
||||
{
|
||||
if (circular && (i-halfSize)*(i-halfSize)+(j-halfSize)*(j-halfSize) > mSize)
|
||||
{
|
||||
waveForceHQ[j*mapSize + i] = 255;
|
||||
continue;
|
||||
}
|
||||
u8 color = 0;
|
||||
for (int v = 0; v < 20; v++){
|
||||
for (int v = 0; v <= 18; v += 3){
|
||||
if (j-v >= 0 && i-v >= 0 && heightmap[(j-v)*mapSize + i-v] > waterHeightInu16)
|
||||
{
|
||||
if (color == 0)
|
||||
@ -257,21 +288,28 @@ void WaterManager::CreateSuperfancyInfo()
|
||||
color++;
|
||||
}
|
||||
}
|
||||
waveForceHQ[j*mapSize + i] = 255 - color * 7;
|
||||
waveForceHQ[j*mapSize + i] = 255 - color * 40;
|
||||
}
|
||||
}
|
||||
// this creates information for waves and stores it in a texture.
|
||||
// texture "newHeightmap" is [x vector of wave direction, coefficient of "water raise", y vector of waves, distance to shore.]
|
||||
// texture "OtherInfo" stores the intensity of actual waves and of foam.
|
||||
// this creates information for waves and stores it in float arrays. PatchRData then puts it in the vertex info for speed.
|
||||
for (ssize_t i = 0; i < mapSize; ++i)
|
||||
{
|
||||
for (ssize_t j = 0; j < mapSize; ++j)
|
||||
{
|
||||
|
||||
float depth = this->m_WaterHeight - heightmap[j*mapSize + i]*HEIGHT_SCALE;
|
||||
if (circular && (i-halfSize)*(i-halfSize)+(j-halfSize)*(j-halfSize) > mSize)
|
||||
{
|
||||
m_WaveX[j*mapSize + i] = 0.0f;
|
||||
m_WaveZ[j*mapSize + i] = 0.0f;
|
||||
m_DistanceToShore[j*mapSize + i] = 100;
|
||||
m_FoamFactor[j*mapSize + i] = 0.0f;
|
||||
continue;
|
||||
}
|
||||
float depth = m_WaterHeight - heightmap[j*mapSize + i]*HEIGHT_SCALE;
|
||||
int distanceToShore = 10000;
|
||||
|
||||
// calculation of the distance to the shore.
|
||||
// this is pretty exact.
|
||||
// TODO: this is fairly dumb, though it returns a good result
|
||||
// Could be sped up a fair bit.
|
||||
if (depth >= 0)
|
||||
{
|
||||
// check in the square around.
|
||||
@ -282,246 +320,231 @@ void WaterManager::CreateSuperfancyInfo()
|
||||
if (i+xx >= 0 && i + xx < mapSize)
|
||||
if (j + yy >= 0 && j + yy < mapSize)
|
||||
{
|
||||
float hereDepth = this->m_WaterHeight - heightmap[(j+yy)*mapSize + (i+xx)]*HEIGHT_SCALE;
|
||||
float hereDepth = m_WaterHeight - heightmap[(j+yy)*mapSize + (i+xx)]*HEIGHT_SCALE;
|
||||
if (hereDepth < 0 && xx*xx + yy*yy < distanceToShore)
|
||||
distanceToShore = xx*xx + yy*yy;
|
||||
}
|
||||
}
|
||||
}
|
||||
// finer check
|
||||
for (float xx = -2.5f; xx <= 2.5f; ++xx)
|
||||
// refine the calculation if we're close enough
|
||||
if (distanceToShore < 9)
|
||||
{
|
||||
for (float yy = -2.5f; yy <= 2.5f; ++yy)
|
||||
for (float xx = -2.5f; xx <= 2.5f; ++xx)
|
||||
{
|
||||
float hereDepth = this->m_WaterHeight - terrain->GetExactGroundLevel( (i+xx)*4, (j+yy)*4 );
|
||||
if (hereDepth < 0 && xx*xx + yy*yy < distanceToShore)
|
||||
distanceToShore = xx*xx + yy*yy;
|
||||
for (float yy = -2.5f; yy <= 2.5f; ++yy)
|
||||
{
|
||||
float hereDepth = m_WaterHeight - terrain->GetExactGroundLevel( (i+xx)*4, (j+yy)*4 );
|
||||
if (hereDepth < 0 && xx*xx + yy*yy < distanceToShore)
|
||||
distanceToShore = xx*xx + yy*yy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (float xx = -2.0f; xx <= 2.0f; xx+=0.5f)
|
||||
for (int xx = -2; xx <= 2; ++xx)
|
||||
{
|
||||
for (float yy = -2.0f; yy <= 2.0f; yy+=0.5f)
|
||||
for (int yy = -2; yy <= 2; ++yy)
|
||||
{
|
||||
float hereDepth = this->m_WaterHeight - terrain->GetExactGroundLevel( (i+xx)*4, (j+yy)*4 );
|
||||
float hereDepth = m_WaterHeight - terrain->GetVertexGroundLevel(i+xx, j+yy);
|
||||
if (hereDepth > 0)
|
||||
distanceToShore = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
distanceToShore = (int)sqrt((float)distanceToShore);
|
||||
// Compute the normals
|
||||
// Also create the waves quad.
|
||||
CVector3D normal;
|
||||
|
||||
int waterRaise = 0;
|
||||
for (int xx = -4; xx <= 4; ++xx)
|
||||
// speedup with default values for land squares
|
||||
if (distanceToShore == 10000)
|
||||
{
|
||||
for (int yy = -4; yy <= 4; ++yy)
|
||||
m_WaveX[j*mapSize + i] = 0.0f;
|
||||
m_WaveZ[j*mapSize + i] = 0.0f;
|
||||
m_DistanceToShore[j*mapSize + i] = 100;
|
||||
m_FoamFactor[j*mapSize + i] = 0.0f;
|
||||
continue;
|
||||
}
|
||||
// We'll compute the normals and the "water raise", to know about foam
|
||||
// Normals are a pretty good calculation but it's slow since we normalize so much.
|
||||
CVector3D normal;
|
||||
int waterRaise = 0;
|
||||
for (int xx = -4; xx <= 4; xx += 2) // every 2 tile is good enough.
|
||||
{
|
||||
for (int yy = -4; yy <= 4; yy += 2)
|
||||
{
|
||||
normal += terrain->CalcExactNormal(((float)i+xx)*4.0f,((float)j+yy)*4.0f);
|
||||
if (terrain->GetVertexGroundLevel(i+xx,j+yy) < heightmap[j*mapSize + i]*HEIGHT_SCALE)
|
||||
waterRaise += heightmap[j*mapSize + i]*HEIGHT_SCALE - terrain->GetVertexGroundLevel(i+xx,j+yy);
|
||||
}
|
||||
}
|
||||
waterRaise = waterRaise > 255 ? 255 : waterRaise; // gives a very good result, actually.
|
||||
normal *= 1.0f/81.0f;
|
||||
normal[1] = 0.1f; // acts as an anti distorter
|
||||
// normalizes the terrain info to avoid foam moving at too different speeds.
|
||||
normal *= 0.012345679f;
|
||||
normal[1] = 0.1;
|
||||
normal = normal.Normalized();
|
||||
|
||||
u8 r = static_cast<u8>(normal[0]*128 + 127);
|
||||
u8 b = static_cast<u8>(normal[2]*128 + 127);
|
||||
distanceToShore = distanceToShore > 10 ? 10 : distanceToShore;
|
||||
newHeightmap[j*texSize + i] = (r << 24) + (waterRaise << 16) + (b << 8) + (distanceToShore*25 << 0);
|
||||
|
||||
depth = clamp(depth,0.0f,10.0f);
|
||||
|
||||
float wvness = this->m_Waviness;
|
||||
|
||||
|
||||
m_WaveX[j*mapSize + i] = normal[0];
|
||||
m_WaveZ[j*mapSize + i] = normal[2];
|
||||
// distance is /5.0 to be a [0,1] value.
|
||||
|
||||
m_DistanceToShore[j*mapSize + i] = sqrt(distanceToShore)/5.0; // TODO: this can probably be cached as I'm integer here.
|
||||
|
||||
// computing the amount of foam I want
|
||||
float foamAmount = (waterRaise/255.0f) * (1.0f - depth/10.0f) * (waveForceHQ[j*mapSize+i]/255.0f) * (wvness/8.0f);
|
||||
foamAmount += clamp(wvness/2.0f - distanceToShore,0.0f,wvness/2.0f)/(wvness/2.0f) * clamp(wvness/9.0f,0.3f,1.0f);
|
||||
|
||||
|
||||
depth = clamp(depth,0.0f,10.0f);
|
||||
float foamAmount = (waterRaise/255.0f) * (1.0f - depth/10.0f) * (waveForceHQ[j*mapSize+i]/255.0f) * (m_Waviness/8.0f);
|
||||
foamAmount += clamp(m_Waviness/2.0f - distanceToShore,0.0f,m_Waviness/2.0f)/(m_Waviness/2.0f) * clamp(m_Waviness/9.0f,0.3f,1.0f);
|
||||
foamAmount = foamAmount > 1.0f ? 1.0f: foamAmount;
|
||||
|
||||
otherInfo[j*texSize + i] = (waveForceHQ[j*mapSize+i] << 24) + ((u8)(foamAmount*255) << 16) + (0x00 << 8) + (0x00 << 0);
|
||||
m_FoamFactor[j*mapSize + i] = foamAmount;
|
||||
}
|
||||
}
|
||||
this->m_TexSize = texSize*4;
|
||||
this->m_Heightmap = newHeightmap;
|
||||
delete[] waveForceHQ;
|
||||
|
||||
GLuint heightName;
|
||||
glGenTextures(1, &heightName);
|
||||
glBindTexture(GL_TEXTURE_2D, heightName);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSize,texSize, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,newHeightmap);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
this->m_HeightmapTexture = heightName;
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
// TODO: The rest should be cleaned up
|
||||
|
||||
GLuint otherInfoId;
|
||||
glGenTextures(1, &otherInfoId);
|
||||
glBindTexture(GL_TEXTURE_2D, otherInfoId);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSize,texSize, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,otherInfo);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
this->m_OtherInfoTex = otherInfoId;
|
||||
// okay let's create the waves squares. i'll divide the map in arbitrary squares
|
||||
// For each of these squares, check if waves are needed.
|
||||
// If yes, look for the best positionning (in order to have a nice blending with the shore)
|
||||
// Then clean-up: remove squares that are too close to each other
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
std::vector<CVector2D> waveSquares;
|
||||
|
||||
if (this->m_WaterCoastalWaves)
|
||||
int size = 8; // I think this is the size of the squares.
|
||||
for (int i = 0; i < mapSize/size; ++i)
|
||||
{
|
||||
// okay let's create the waves squares. i'll divide the map in arbitrary squares
|
||||
// For each of these squares, check if waves are needed.
|
||||
// If yes, look for the best positionning (in order to have a nice blending with the shore)
|
||||
// Then clean-up: remove squares that are too close to each other
|
||||
|
||||
std::vector<CVector2D> waveSquares;
|
||||
|
||||
int size = 8; // I think this is the size of the squares.
|
||||
for (int i = 0; i < mapSize/size; ++i)
|
||||
for (int j = 0; j < mapSize/size; ++j)
|
||||
{
|
||||
for (int j = 0; j < mapSize/size; ++j)
|
||||
|
||||
int landTexel = 0;
|
||||
int waterTexel = 0;
|
||||
CVector3D avnormal (0.0f,0.0f,0.0f);
|
||||
CVector2D landPosition(0.0f,0.0f);
|
||||
CVector2D waterPosition(0.0f,0.0f);
|
||||
for (int xx = 0; xx < size; ++xx)
|
||||
{
|
||||
|
||||
int landTexel = 0;
|
||||
int waterTexel = 0;
|
||||
CVector3D avnormal (0.0f,0.0f,0.0f);
|
||||
CVector2D landPosition(0.0f,0.0f);
|
||||
CVector2D waterPosition(0.0f,0.0f);
|
||||
for (int xx = 0; xx < size; ++xx)
|
||||
for (int yy = 0; yy < size; ++yy)
|
||||
{
|
||||
for (int yy = 0; yy < size; ++yy)
|
||||
if (terrain->GetVertexGroundLevel(i*size+xx,j*size+yy) > m_WaterHeight)
|
||||
{
|
||||
if (terrain->GetVertexGroundLevel(i*size+xx,j*size+yy) > this->m_WaterHeight)
|
||||
{
|
||||
landTexel++;
|
||||
landPosition += CVector2D(i*size+xx,j*size+yy);
|
||||
}
|
||||
else
|
||||
{
|
||||
waterPosition += CVector2D(i*size+xx,j*size+yy);
|
||||
waterTexel++;
|
||||
}
|
||||
avnormal += terrain->CalcExactNormal( (i*size+xx)*4.0f,(j*size+yy)*4.0f);
|
||||
landTexel++;
|
||||
landPosition += CVector2D(i*size+xx,j*size+yy);
|
||||
}
|
||||
}
|
||||
landPosition /= landTexel;
|
||||
waterPosition /= waterTexel;
|
||||
|
||||
avnormal[1] = 1.0f;
|
||||
avnormal.Normalize();
|
||||
avnormal[1] = 0.0f;
|
||||
|
||||
if (landTexel < size/2)
|
||||
continue;
|
||||
// this should help ensure that the shore is pretty flat.
|
||||
if (avnormal.Length() <= 0.2f)
|
||||
continue;
|
||||
|
||||
// To get the best position for squares, I start at the mean "ocean" position
|
||||
// And step by step go to the mean "land" position. I keep the position where I change from water to land.
|
||||
// If this never happens, the square is scrapped.
|
||||
if (terrain->GetExactGroundLevel(waterPosition.X*4.0f,waterPosition.Y*4.0f) > this->m_WaterHeight)
|
||||
continue;
|
||||
|
||||
CVector2D squarePos(-1,-1);
|
||||
for (u8 i = 0; i < 40; i++)
|
||||
{
|
||||
squarePos = landPosition * (i/40.0f) + waterPosition * (1.0f-(i/40.0f));
|
||||
if (terrain->GetExactGroundLevel(squarePos.X*4.0f,squarePos.Y*4.0f) > this->m_WaterHeight)
|
||||
break;
|
||||
}
|
||||
if (squarePos.X == -1)
|
||||
continue;
|
||||
|
||||
u8 enter = 1;
|
||||
// okaaaaaay. Got a square. Check for proximity.
|
||||
for (unsigned long i = 0; i < waveSquares.size(); i++)
|
||||
{
|
||||
if ( CVector2D(waveSquares[i]-squarePos).LengthSquared() < 80) {
|
||||
enter = 0;
|
||||
break;
|
||||
else
|
||||
{
|
||||
waterPosition += CVector2D(i*size+xx,j*size+yy);
|
||||
waterTexel++;
|
||||
}
|
||||
avnormal += terrain->CalcExactNormal( (i*size+xx)*4.0f,(j*size+yy)*4.0f);
|
||||
}
|
||||
if (enter == 1)
|
||||
waveSquares.push_back(squarePos);
|
||||
}
|
||||
}
|
||||
|
||||
// Actually create the waves' meshes.
|
||||
std::vector<SWavesVertex> waves_vertex_data;
|
||||
std::vector<GLushort> waves_indices;
|
||||
|
||||
// loop through each square point. Look in the square around it, calculate the normal
|
||||
// create the square.
|
||||
for (unsigned long i = 0; i < waveSquares.size(); i++)
|
||||
{
|
||||
CVector2D pos(waveSquares[i]);
|
||||
landPosition /= landTexel;
|
||||
waterPosition /= waterTexel;
|
||||
|
||||
CVector3D avgnorm(0.0f,0.0f,0.0f);
|
||||
for (int xx = -size/2; xx < size/2; ++xx)
|
||||
avnormal[1] = 1.0f;
|
||||
avnormal.Normalize();
|
||||
avnormal[1] = 0.0f;
|
||||
|
||||
if (landTexel < size/2)
|
||||
continue;
|
||||
// this should help ensure that the shore is pretty flat.
|
||||
if (avnormal.Length() <= 0.2f)
|
||||
continue;
|
||||
|
||||
// To get the best position for squares, I start at the mean "ocean" position
|
||||
// And step by step go to the mean "land" position. I keep the position where I change from water to land.
|
||||
// If this never happens, the square is scrapped.
|
||||
if (terrain->GetExactGroundLevel(waterPosition.X*4.0f,waterPosition.Y*4.0f) > m_WaterHeight)
|
||||
continue;
|
||||
|
||||
CVector2D squarePos(-1,-1);
|
||||
for (u8 i = 0; i < 40; i++)
|
||||
{
|
||||
for (int yy = -size/2; yy < size/2; ++yy)
|
||||
{
|
||||
avgnorm += terrain->CalcExactNormal((pos.X+xx)*4.0f,(pos.Y+yy)*4.0f);
|
||||
squarePos = landPosition * (i/40.0f) + waterPosition * (1.0f-(i/40.0f));
|
||||
if (terrain->GetExactGroundLevel(squarePos.X*4.0f,squarePos.Y*4.0f) > m_WaterHeight)
|
||||
break;
|
||||
}
|
||||
if (squarePos.X == -1)
|
||||
continue;
|
||||
|
||||
u8 enter = 1;
|
||||
// okaaaaaay. Got a square. Check for proximity.
|
||||
for (unsigned long i = 0; i < waveSquares.size(); i++)
|
||||
{
|
||||
if ( CVector2D(waveSquares[i]-squarePos).LengthSquared() < 80) {
|
||||
enter = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
avgnorm[1] = 0.1f;
|
||||
// okay crank out a square.
|
||||
// we have the direction of the square. We'll get the perpendicular vector too
|
||||
CVector2D perp(-avgnorm[2],avgnorm[0]);
|
||||
perp = perp.Normalized();
|
||||
avgnorm = avgnorm.Normalized();
|
||||
|
||||
SWavesVertex vertex[4];
|
||||
vertex[0].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y + perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
|
||||
vertex[0].m_Position *= 4.0f;
|
||||
vertex[0].m_Position.Y = this->m_WaterHeight + 1.0f;
|
||||
vertex[0].m_UV[1] = 1;
|
||||
vertex[0].m_UV[0] = 0;
|
||||
|
||||
vertex[1].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y - perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
|
||||
vertex[1].m_Position *= 4.0f;
|
||||
vertex[1].m_Position.Y = this->m_WaterHeight + 1.0f;
|
||||
vertex[1].m_UV[1] = 1;
|
||||
vertex[1].m_UV[0] = 1;
|
||||
|
||||
vertex[3].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y + perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
|
||||
vertex[3].m_Position *= 4.0f;
|
||||
vertex[3].m_Position.Y = this->m_WaterHeight + 1.0f;
|
||||
vertex[3].m_UV[1] = 0;
|
||||
vertex[3].m_UV[0] = 0;
|
||||
|
||||
vertex[2].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y - perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
|
||||
vertex[2].m_Position *= 4.0f;
|
||||
vertex[2].m_Position.Y = this->m_WaterHeight + 1.0f;
|
||||
vertex[2].m_UV[1] = 0;
|
||||
vertex[2].m_UV[0] = 1;
|
||||
|
||||
waves_indices.push_back(waves_vertex_data.size());
|
||||
waves_vertex_data.push_back(vertex[0]);
|
||||
waves_indices.push_back(waves_vertex_data.size());
|
||||
waves_vertex_data.push_back(vertex[1]);
|
||||
waves_indices.push_back(waves_vertex_data.size());
|
||||
waves_vertex_data.push_back(vertex[2]);
|
||||
waves_indices.push_back(waves_vertex_data.size());
|
||||
waves_vertex_data.push_back(vertex[3]);
|
||||
if (enter == 1)
|
||||
waveSquares.push_back(squarePos);
|
||||
}
|
||||
|
||||
// waves
|
||||
// allocate vertex buffer
|
||||
this->m_VBWaves = g_VBMan.Allocate(sizeof(SWavesVertex), waves_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
|
||||
this->m_VBWaves->m_Owner->UpdateChunkVertices(this->m_VBWaves, &waves_vertex_data[0]);
|
||||
|
||||
// Construct indices buffer
|
||||
this->m_VBWavesIndices = g_VBMan.Allocate(sizeof(GLushort), waves_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
|
||||
this->m_VBWavesIndices->m_Owner->UpdateChunkVertices(this->m_VBWavesIndices, &waves_indices[0]);
|
||||
}
|
||||
|
||||
// Actually create the waves' meshes.
|
||||
std::vector<SWavesVertex> waves_vertex_data;
|
||||
std::vector<GLushort> waves_indices;
|
||||
|
||||
// loop through each square point. Look in the square around it, calculate the normal
|
||||
// create the square.
|
||||
for (unsigned long i = 0; i < waveSquares.size(); i++)
|
||||
{
|
||||
CVector2D pos(waveSquares[i]);
|
||||
|
||||
CVector3D avgnorm(0.0f,0.0f,0.0f);
|
||||
for (int xx = -size/2; xx < size/2; ++xx)
|
||||
{
|
||||
for (int yy = -size/2; yy < size/2; ++yy)
|
||||
{
|
||||
avgnorm += terrain->CalcExactNormal((pos.X+xx)*4.0f,(pos.Y+yy)*4.0f);
|
||||
}
|
||||
}
|
||||
avgnorm[1] = 0.1f;
|
||||
// okay crank out a square.
|
||||
// we have the direction of the square. We'll get the perpendicular vector too
|
||||
CVector2D perp(-avgnorm[2],avgnorm[0]);
|
||||
perp = perp.Normalized();
|
||||
avgnorm = avgnorm.Normalized();
|
||||
|
||||
SWavesVertex vertex[4];
|
||||
vertex[0].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y + perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
|
||||
vertex[0].m_Position *= 4.0f;
|
||||
vertex[0].m_Position.Y = m_WaterHeight + 1.0f;
|
||||
vertex[0].m_UV[1] = 1;
|
||||
vertex[0].m_UV[0] = 0;
|
||||
|
||||
vertex[1].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y - perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
|
||||
vertex[1].m_Position *= 4.0f;
|
||||
vertex[1].m_Position.Y = m_WaterHeight + 1.0f;
|
||||
vertex[1].m_UV[1] = 1;
|
||||
vertex[1].m_UV[0] = 1;
|
||||
|
||||
vertex[3].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y + perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
|
||||
vertex[3].m_Position *= 4.0f;
|
||||
vertex[3].m_Position.Y = m_WaterHeight + 1.0f;
|
||||
vertex[3].m_UV[1] = 0;
|
||||
vertex[3].m_UV[0] = 0;
|
||||
|
||||
vertex[2].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y - perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
|
||||
vertex[2].m_Position *= 4.0f;
|
||||
vertex[2].m_Position.Y = m_WaterHeight + 1.0f;
|
||||
vertex[2].m_UV[1] = 0;
|
||||
vertex[2].m_UV[0] = 1;
|
||||
|
||||
waves_indices.push_back(waves_vertex_data.size());
|
||||
waves_vertex_data.push_back(vertex[0]);
|
||||
waves_indices.push_back(waves_vertex_data.size());
|
||||
waves_vertex_data.push_back(vertex[1]);
|
||||
waves_indices.push_back(waves_vertex_data.size());
|
||||
waves_vertex_data.push_back(vertex[2]);
|
||||
waves_indices.push_back(waves_vertex_data.size());
|
||||
waves_vertex_data.push_back(vertex[3]);
|
||||
}
|
||||
|
||||
// waves
|
||||
// allocate vertex buffer
|
||||
m_VBWaves = g_VBMan.Allocate(sizeof(SWavesVertex), waves_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
|
||||
m_VBWaves->m_Owner->UpdateChunkVertices(m_VBWaves, &waves_vertex_data[0]);
|
||||
|
||||
// Construct indices buffer
|
||||
m_VBWavesIndices = g_VBMan.Allocate(sizeof(GLushort), waves_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
|
||||
m_VBWavesIndices->m_Owner->UpdateChunkVertices(m_VBWavesIndices, &waves_indices[0]);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "ps/Overlay.h"
|
||||
#include "renderer/VertexBufferManager.h"
|
||||
|
||||
class CSimulation2;
|
||||
|
||||
struct SWavesVertex {
|
||||
// vertex position
|
||||
@ -52,10 +53,11 @@ public:
|
||||
CTexturePtr m_NormalMap[60];
|
||||
CTexturePtr m_Foam;
|
||||
CTexturePtr m_Wave;
|
||||
u32* m_Heightmap;
|
||||
float* m_WaveX;
|
||||
float* m_WaveZ;
|
||||
float* m_DistanceToShore;
|
||||
float* m_FoamFactor;
|
||||
|
||||
GLuint m_HeightmapTexture;
|
||||
GLuint m_OtherInfoTex;
|
||||
ssize_t m_TexSize;
|
||||
|
||||
GLuint m_depthTT;
|
||||
@ -143,7 +145,7 @@ public:
|
||||
/**
|
||||
* CreateSuperfancyInfo: creates textures and wave vertices for superfancy water
|
||||
*/
|
||||
void CreateSuperfancyInfo();
|
||||
void CreateSuperfancyInfo(CSimulation2* simulation);
|
||||
|
||||
/**
|
||||
* Updates the settings to the one from the renderer, and sets m_NeedsReloading.
|
||||
|
@ -32,7 +32,6 @@ public:
|
||||
static void ClassInit(CComponentManager& componentManager)
|
||||
{
|
||||
componentManager.SubscribeToMessageType(MT_Interpolate);
|
||||
componentManager.SubscribeToMessageType(MT_RenderSubmit);
|
||||
componentManager.SubscribeToMessageType(MT_TerrainChanged);
|
||||
}
|
||||
|
||||
@ -72,20 +71,13 @@ public:
|
||||
{
|
||||
switch (msg.GetType())
|
||||
{
|
||||
case MT_Interpolate:
|
||||
{
|
||||
const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg);
|
||||
if (CRenderer::IsInitialised())
|
||||
g_Renderer.GetWaterManager()->m_WaterTexTimer += msgData.deltaSimTime;
|
||||
break;
|
||||
}
|
||||
case MT_RenderSubmit:
|
||||
{
|
||||
// Don't actually do rendering here, but tell the renderer how to draw water
|
||||
if (CRenderer::IsInitialised())
|
||||
g_Renderer.GetWaterManager()->m_WaterHeight = m_WaterHeight.ToFloat();
|
||||
break;
|
||||
}
|
||||
case MT_Interpolate:
|
||||
{
|
||||
const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg);
|
||||
if (CRenderer::IsInitialised())
|
||||
g_Renderer.GetWaterManager()->m_WaterTexTimer += msgData.deltaSimTime;
|
||||
break;
|
||||
}
|
||||
case MT_TerrainChanged:
|
||||
{
|
||||
// Tell the renderer to redraw the map.
|
||||
|
Loading…
Reference in New Issue
Block a user