Водная поверхность земли. Бывает ли горизонтальной поверхность воды

Очень часто в трехмерных приложениях, точнее в играх, встречаются водные пространства. Если некогда можно было обойтись синим прямоугольником, обозначающим жидкость, то сейчас такое изображение воды кажется смехотворным и никак не удовлетворяет негласным требованиям к реалистичности графики. Перед разработчиками встает вопрос: как же изобразить водную поверхность?

Что же она в себя включает? Давайте разберемся.
1. Отражение – отображение на поверхности воды пространства, находящегося над ней. Этот пункт является, пожалуй, самым главным при изображении более-менее реалистичной воды.
2. Преломление – отображение пространства, находящегося под водной поверхностью.
3. Туманность/плотность воды – изменение цвета преломления в зависимости от глубины (чем глубже по отношению к поверхности воды расположено пространство, тем темнее/мутнее оно выглядит).
4. Освещение.
5. Волны – тоже немаловажный пункт для реализации реалистичной водной поверхности.

Теперь давайте разберемся, что и как реализовывается с точки зрения приложения.

1. Для начала определимся что из себя представляет вода. Есть несколько случаев:
- квад
- малополигональная модель
- многополигональная модель.

В зависимости от поставленной задачи выбирается один из способов реализации. Самый простой - водная поверхность представляет из себя квадрат (два полигона). Физическое движение отсутствует. Эффект волновой поверхности достигается лишь с помощью специальных карт смещений.
Малополигональная модель – ничем не отличается от предыдущей, за исключением того, что поверхность состоит из нескольких полигонов, совершающих колебания по определенному закону (в простейшем случае по синусоиду). Таким образом, создается видимость «более динамичного» движения волн.
Многополигональная модель – совершенно другой способ. Волны представляют собой массивы динамически изменяющихся примитивов. Самое честное изображение волн, но и самый ресурсоемкий вариант. Стоит использовать только тогда, когда необходим наивысший уровень качества.
Чаще всего используется первый или второй вариант.

2. Отражение. Отражение на поверхности воды есть ничто иное, как текстура. Сложность заключается лишь в том, что она постоянно меняется и одной постоянной текстурой не обойтись (за исключением фейкового отражения – текстура неба; метод нереалистичный и следует его использовать только для ускорения отрисовки, если оное требуется). Давайте разберемся, откуда это изображение брать. Отражение на поверхности воды представляет собой изображение пространства, находящегося над водой, но отраженное по горизонтали.

Чтобы его получить нужно всего лишь "отразить" камеру относительно поверхности воды.

3. Преломление. Все аналогично, за исключением того, что изображение преломления – есть изображение точно такое, какое видит камера, не учитывая самой воды.

4. Освещение. Ничего необычного, простое освещение, такое же, как и у остальных объектов (чтобы вода не была однотонного цвета).

5. Волны. Как мы уже говорили – волны можно изобразить двумя способами (фейковые волны с помощью текстур и корректные волны с помощью геометрии) .
Если с геометрией все понятно (позиция каждой вершины меняется в зависимости от физического закона или карты шумов), то фейк делается чуть запутанней, но, при этом, проще.
Фейковые волны можно отобразить с помощью двух вещей: свет и искажение отражения/ преломления. Наиболее качественные результаты достигаются с помощью совместного использования этих двух способов.


С помощью карт нормалей мы освещаем воду так, будто на ней
действительно есть рельефны волн.


С помощью искажения мы "размазываем" отражение/преломление по структуре волн.

Как уже упоминалось, освещать по структуре волн мы будем с помощью карт нормалей.


Карта нормалей

Карта нормалей представляет собой графический файл, в r/g/b каналы которого записаны координаты вектора нормали, а не цвета. Как правило, она выглядит так (карта в которой не трудно разглядеть структуру объекта, освещенную сине-фиолетовым цветом) .

Искажать изображение на поверхности воды (будь то преломление или отражение, или их комбинация) мы будем с помощью карты смещений текстурных координат.


Карта смещений текстурных координат (du/dv карта)

Карта смещений текстурных координат (или du/dv карта) также представляет собой карту со структурой объекта, но цвета у нее могут быть очень различны (от серо-коричневых, до желто-красных). Такие карты в каналах цвета хранят расстояния, на которые изменяются текстурные координаты. Исходя из этого, они могут быть различного формата, как одноканальные (карты с черно-белым градиентом), так и много-канальные (например, двух канальные, для хранения смещения по оси x и по оси y отдельно) .

Итак, давайте из полученных знаний составим небольшой план по рисованию воды в нашем приложении. Нам нужно:
1. квад;
2. две вспомогательные текстуры (normal map и du/dv map);
3. несколько методов для нормального рендеринга отражения;
4. шейдер, который все это дело отрисует.

Ну что же, переходим к реализации.

2. Реализация

#define FVF_XYZ_TEX1 (D3DFVF_XYZ|D3DFVF_TEX1) struct VERTEX_XYZ_TEX1 { VERTEX_XYZ_TEX1() { }; VERTEX_XYZ_TEX1(D3DXVECTOR3 _pos, D3DXVECTOR2 _tex) { pos = _pos; tex = _tex; }; D3DXVECTOR3 pos; D3DXVECTOR2 tex; };

Создаем структуру и определение для формата вершин. Хранить будем только координаты вершины и текстурные координаты, остальное нам ни к чему.

class CWATER { private : LPDIRECT3DSURFACE9 psBackBuffer; LPDIRECT3DSURFACE9 psTextureReflect; D3DXMATRIX oldMatView; LPDIRECT3DVERTEXBUFFER9 vb_Water; LPDIRECT3DSURFACE9 pSurfaceZBuffer; LPDIRECT3DSURFACE9 pLastSurfaceZBuffer; // Разрешение текстуры отражения и дополнительного буфера глубина int iTextureResolution; float fWidthWater; float fDepthWater; // Длина и ширина водной поверхности public : LPDIRECT3DTEXTURE9 tex_Reflect; // Текстура отражения D3DXVECTOR3 ObjPos; // Левая ближняя вершина воды void PreRenderForReflection(Camera *Cam); void PostRenderForReflection(Camera *Cam); CWATER(); ~CWATER(); void Init(float _fWidthWater, float _fDepthWater, float fTexScale); // Инициализация void Draw(); };

Вот основной класс для воды. Здесь мы видим несколько переменных, о которых не было и намека ранее. Давайте разберемся, зачем они?

Рисовать отражение (при желании и преломление) мы будем в текстуру. А значит, нам сначала нужно создать поверхность для этой текстуры. Хранить ее будем в psTextureReflect. Перед рисованием пространства в нее, нужно указать устройству, что рендеринг делается в текстуру, а не в задний буфер. Но для того, чтобы потом корректно рисовать в задний буфер нужно его запомнить, а потом вернуть. Запоминать его будем в psBackBuffer.

Так мы меняем активный Render Target, но для того, чтобы не было проблем при рисовании в текстуру (рисуется как будто буфер глубины отключен или неправильно выставлено отсечение) нужно сделать еще кое что. Дело в том, что размер заднего буфера равен определенному значению (как правило, 1024x768), а когда рисуем в текстуру, то, скорее всего, она имеет другое разрешение, а значит, данный буфер глубины для нее не подходит. Можно использовать его, только если размер буфера больше или равен размеру текстуры, в которую рисуем.

Получается, что нам придется создать еще две поверхности (для запоминания прошлого и хранения текущего буфера). Это pSurfaceZBuffer и pLastSurfaceZBuffer.
iTextureResolution – разрешение текстуры для отражения (чем больше, тем более качественное отражение, но и более ресурсоемкий метод).

CWATER::CWATER() { ObjPos = D3DXVECTOR3(0.0f,5.0f,0.0f); vb_Water = NULL; tex_Reflect = NULL; iTextureResolution=1024; fWidthWater=10.0f; fDepthWater=10.0f; }

В конструкторе мы устанавливаем значения по умолчанию и обнуляем указатели на поверхностей.

CWATER::~CWATER() { CLEAR(vb_Water); CLEAR(psTextureReflect); CLEAR(psBackBuffer); CLEAR(pLastSurfaceZBuffer); CLEAR(pSurfaceZBuffer); }

В деструкторе мы очищаем занятую вершинным буфером и поверхностями память.

void CWATER::Init(float _fWidthWater=10.0f, float _fDepthWater=10.0f, float fTexScale=1.0f) { fWidthWater=_fWidthWater; fDepthWater=_fDepthWater; D3DXCreateTexture(D3DDevice, iTextureResolution, iTextureResolution, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tex_Reflect); D3DDevice->CreateVertexBuffer(6*sizeof(VERTEX_XYZ_TEX1), D3DUSAGE_WRITEONLY, FVF_XYZ_TEX1, D3DPOOL_MANAGED, &vb_Water, NULL); VERTEX_XYZ_TEX1 p; int k = 0; p[k].pos = D3DXVECTOR3(fWidthWater, 0, fDepthWater); p[k].tex = D3DXVECTOR2(fTexScale,fTexScale); ++k; p[k].pos = D3DXVECTOR3(fWidthWater, 0, 0.0f); p[k].tex = D3DXVECTOR2(fTexScale,0.0f); ++k; p[k].pos = D3DXVECTOR3(0.0f, 0.0f, 0.0f); p[k].tex = D3DXVECTOR2(0.0f,0.0f); ++k; p[k].pos = D3DXVECTOR3(0.0f, 0, 0.0f); p[k].tex = D3DXVECTOR2(0.0f,0.0f); ++k; p[k].pos = D3DXVECTOR3(0.0f, 0, fDepthWater); p[k].tex = D3DXVECTOR2(0.0f,fTexScale); ++k; p[k].pos = D3DXVECTOR3(fWidthWater, 0, fDepthWater); p[k].tex = D3DXVECTOR2(fTexScale,fTexScale); ++k; void * pBuf; vb_Water->Lock(0, 6 * sizeof(VERTEX_XYZ_TEX1), &pBuf, 0); memcpy(pBuf, p, 6 * sizeof(VERTEX_XYZ_TEX1)); vb_Water->Unlock(); D3DDevice->CreateDepthStencilSurface(iTextureResolution, iTextureResolution, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, TRUE, &pSurfaceZBuffer, NULL); }

В функции инициализации мы создаем вершинный буфер для шести вершин (два треугольника), создаем текстуру, в которой будем хранить отражение и создаем дополнительную поверхность заднего буфера.

void CWATER::Draw() { D3DDevice -> SetFVF(FVF_XYZ_TEX1); D3DDevice -> SetStreamSource(0, vb_Water, 0, sizeof(VERTEX_XYZ_TEX1)); D3DDevice -> DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); }

В методе рисования нет ничего необычного – выставление формата вершин, вершинного буфера и вызов функции рендеринга (обратите внимание, рисоваться вода будет через шейдер, то есть данный метод вызывается после старта шейдера; см. пример использования) .

void CWATER::PreRenderForReflection(Camera *Cam) { D3DXVECTOR3 CamPos = Cam->GetCamPos(); D3DXVECTOR3 ViewPos = Cam->GetViewPos(); Cam->GetViewMat(&oldMatView); D3DXVECTOR3 h = CamPos; float tmp = CamPos.y-ObjPos.y; h.y = CamPos.y - 2*tmp; D3DXVECTOR3 hv = ViewPos; float tmpv = ViewPos.y-ObjPos.y; hv.y = ViewPos.y - 2*tmpv; D3DXMATRIX MatrixView; D3DXMatrixLookAtLH(&MatrixView,&h,&hv,&D3DXVECTOR3(0.0f, 1.0f, 0.0f)); D3DDevice -> SetTransform(D3DTS_VIEW, &MatrixView); D3DDevice->GetRenderTarget(0, &psBackBuffer); tex_Reflect->GetSurfaceLevel(0, &psTextureReflect); D3DDevice->SetRenderTarget(0, psTextureReflect); D3DDevice->GetDepthStencilSurface(&pLastSurfaceZBuffer); D3DDevice->SetDepthStencilSurface(pSurfaceZBuffer); D3DDevice->Clear(0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0,180,180,245), 1.0f, 0L); }

А вот эта функция делает около половины всей работы по рендеру отражению. Здесь мы берем позицию камеры и позицию, на которую она смотрит (позицию взгляда, не направление), запоминаем текущую матрицу вида. Далее небольшие махинации по перемещению камеры в нужное место (чтобы отражение было правильным, мы переносим камеру относительно поверхности воды, делать это можно и другим способом, например через функции reflect’а от плоскости воды (из библиотеки D3DX) и пр., но смысл остается один). Формируем и ставим новую матрицу вида. Далее сохраняем и выставляем новые значения рендеринга для устройства (поверхности). И, конечно, очищаем текстуру.

void CWATER::PostRenderForReflection(Camera *Cam) { Cam->SetViewMat(&oldMatView); D3DDevice->SetRenderTarget(0, psBackBuffer); D3DDevice->SetDepthStencilSurface(pLastSurfaceZBuffer); }

После того, как отражение отрисовано в текстуру надо все вернуть на место, так как было до трансформации камеры.

А теперь рассмотрим вторую половину всего рендеринга водной поверхности – шейдер рисования.

static float4x4 Mr= { 0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0.5, 0, 0.5, 0.5, 0.5, 1 };

Это то, благодаря чему мы в состоянии корректно отрисовать именно отражение – "матрица отражения". Она такая, какая она есть и нечего здесь менять не нужно. Постоянная величина, так сказать.

float f_height_wave; //высота волны float4x4 WVP; //world * view * projection matrix uniform float time; //delta time - время прошедшее за кадр texture tex_tex; //текстура отражения texture tex_bumpMap; //текстура с бампом texture tex_bumpdudv1; //текстура с коэффициентами смещения координат float3 vec_light_dir; //вектор направления света float4 EyePosition; //позиция камеры float4 LightColor; //цвет света float4 MatColor; //цвет воды float4x4 World; //матрица мира float Ambient; //свет "фона"

Тут и так все понятно, кроме f_height_wave. Это коэффициент смещения текстурных координат.


"Высота" волны = 12


"Высота" волны = 2

sampler tex = sampler_state {Texture = (tex_tex); ADDRESSU=CLAMP; ADDRESSV=CLAMP;}; sampler bumpMap = sampler_state {Texture = (tex_bumpMap);MIPFILTER = LINEAR;MAGFILTER = LINEAR;MINFILTER = LINEAR;}; sampler bumpdudv1 = sampler_state {Texture = (tex_bumpdudv1);MIPFILTER = LINEAR;MAGFILTER = LINEAR;MINFILTER = LINEAR;}; struct VS_INPUT { float4 pos: POSITION; float2 texc:TEXCOORD0; }; struct VS_OUTPUT { float4 pos: POSITION; //позиция float2 tex2:TEXCOORD0; //текстурные координаты для bump карты float2 tex3:TEXCOORD1; //текстурные координаты для du/dv карты float4 pspos:TEXCOORD2; //позиция (для расчета координат отражения) float3 ViewDir:TEXCOORD3; //направление от камера до вершины };

Тут тоже ничего необычного, стандартные процедуры.

VS_OUTPUT vs_main(VS_INPUT IN) { VS_OUTPUT OUT; //вычисляем позицию воды в экранной системе координат OUT.pos = mul(IN.pos,WVP); //направление взгляда OUT.ViewDir = EyePosition - mul(IN.pos,World); OUT.pspos = OUT.pos; //вычисляем новые текстурные координаты OUT.tex2.x = IN.texc.x + sin (time)*0.4; //т.е. смещаем данные текстурные координаты OUT.tex2.y = IN.texc.y - cos (time)*0.3; //для обеих карт по и против OUT.tex3.x = IN.texc.x - sin (time)*0.4; //часовой стрелки по окружности соответственно OUT.tex3.y = IN.texc.y + cos (time)*0.3; return OUT; }

Вот и вершинный шейдер. В OUT.ViewDir сохраняем направление от камеры для каждой вершины квада воды (передаем его во фрагментный шейдер как текстурные координаты, следовательно, значения между вершинами будут интерполироваться) . Далее текстурные координаты. У нас есть две текстуры (одна с картой нормалей, вторая со смещением текстурных координат) . Чтобы вода "никуда не утекала" мы их передвигаем по кругу (sin/cos) в противоположенные стороны. Это один из самых распространенных вариантов скроллинга текстур. Вы можете их передвигать так, как вам вздумается, лишь бы результат устраивал.

float4 ps_main(float2 texCoord2: TEXCOORD0, float2 texCoord3: TEXCOORD1, float4 pspos: TEXCOORD2, float3 ViewDir:TEXCOORD3): COLOR { float4 result; float3 colorOne = 2.0f * tex2D (bumpMap, texCoord2.xy) - 1.0f; float3 colorTwo = 2.0f * tex2D (bumpMap, texCoord3.xy*0.5) - 1.0f; float3 normal = normalize (colorOne+colorTwo + float3 (0.0,0.5,0.0)); float3 WorldNormal = normalize (mul (normal,(float3x3 )World)); float3 texturecoordoffset = 2.0f * tex2D (bumpdudv1,texCoord2.xy) - 1.0f; float3 texturecoordoffset2= 2.0f * tex2D (bumpdudv1,texCoord3.xy*0.5) - 1.0f; float3 normaloffset = normalize (texturecoordoffset+texturecoordoffset2)*f_height_wave; pspos.xyz += normaloffset; float4 inTexProj = mul (pspos,Mr); result = tex2Dproj (tex, inTexProj); float3 LightDir = normalize (vec_light_dir); ViewDir = normalize (ViewDir); float4 I = min (dot (WorldNormal,-LightDir), 1.0f); // float3 Reflect = reflect(-LightDir, WorldNormal); float3 Reflect = reflect (-LightDir, 1.14*I *WorldNormal); float4 Specular = pow (0.5*(1.0+(dot (Reflect, ViewDir))) ,256); result = LightColor * MatColor * result * I + Specular*LightColor; result.a = 1.0; return result; }

Во фрагментном шейдере считаем усредненную нормаль (и это делать вы можете так, как только вздумается, вариантов великое множество) . Перед нормализацией (это все же нормаль) мы корректируем нормаль, чуть склоняя к вектору (0,1,0), водная поверхность ведь горизонтальная. Этого можно и не делать, но так результат выглядит лучше (конечно, можно отредактировать карту нормалей, но данный способ куда проще). Потом мы переводим нашу нормаль в мировые координаты (исключительно для освещения). То же самое что делали для нормали - делаем и для смещения текстурных координат (texturecoordoffset(2)). Далее, домножаем на коэффициент «высота волны». А дальше идет самое интересное: добавляем смещение к позиции водной поверхности в экранных координатах, домножаем все это на матрицу отражения и читаем из текстуры отражения с помощью tex2Dproj. Далее просто идет расчет освещения. Здесь также стоит поэкспериментировать с методами освещения и коэффициентами, вот наиболее интересные варианты:

technique tech0 { pass pass0 { VertexShader = compile vs_2_0 vs_main(); PixelShader = compile ps_2_0 ps_main(); } };

Ну и, конечно, техника, без нее эффект работать не будет (все это можно проделать и на "голых" шейдерах, но я предпочитаю эффекты) .

3. Применение

Теперь рассмотрим применение нашего класса. Добавляем файл с классом воды:

Примечание. К исходному коду добавлен небольшой класс (EffectClass.h) для загрузки эффекта.
Класс не рассмотрен в статье, так как имеет к ней лишь косвенное отношение.

#include "water.h" #include "EffectClass.h" CWATER Water; CEFFECT pActiveEffect; float tt=0.0f; IDirect3DTexture9* tex1; IDirect3DTexture9* tex2;

Создаем воду и две текстуры (карту нормалей и карту смещений текстурных координат).

Функция рисования воды:

void DrawWater() { tt +=DeltaTime*0.3f; D3DXMATRIX world,matView,matProj; D3DXMatrixTranslation (&world, Water.ObjPos.x, Water.ObjPos.y, Water.ObjPos.z); ActiveCamera->GetViewMat(&matView); D3DDevice->GetTransform(D3DTS_PROJECTION,&matProj); pActiveEffect.AddToConstMatWVP("WVP",&world); pActiveEffect.AddToConstTexture("tex_tex",Water.tex_Reflect); pActiveEffect.AddToConstMat("World",&world); pActiveEffect.AddToConstVec3("LightColor",&D3DXVECTOR3(0.7f,0.7f,0.7f)); pActiveEffect.AddToConstVec3("MatColor",&D3DXVECTOR3(0.7f,0.7f,0.7f)); D3DXVECTOR3 dir=D3DXVECTOR3(0.0f,-1.0f,-1.0f); pActiveEffect.AddToConstVec3("vec_light_dir",&dir); pActiveEffect.AddToConstVec3("EyePosition",&ActiveCamera->GetCamPos()); pActiveEffect.AddToConstFloat("time",tt); pActiveEffect.AddToConstFloat("f_height_wave",2.0f); pActiveEffect.AddToConstTexture("tex_bumpMap",tex1); pActiveEffect.AddToConstTexture("tex_bumpdudv1",tex2); pActiveEffect.Begin(); pActiveEffect.Start(0); Water.Draw(); pActiveEffect.Finish(); pActiveEffect.End(); }

tt – глобальная переменная, которая «растет» с каждым кадром. От нее зависит скорость перемещения камеры, скорость движения волн и т.д. (она символизирует время). Все что идет до pActiveEffect.Begin() – это просто заполнение данных для шейдера, так что здесь останавливать незачем.

PActiveEffect.Begin(); pActiveEffect.Start(0); pActiveEffect.Finish(); pActiveEffect.End();

Эта комбинация лишь задает активную технику и проход.
Water.Draw() вызывает отрисовку воды.

В функции инициализации приложения добавляем следующий код:

Water.Init(400.0f, 400.0f, 10.0f); Water.ObjPos = D3DXVECTOR3(-200.0f,-10.0f,-200.0f); pActiveEffect.Init(); D3DXCreateTextureFromFile(D3DDevice, "water_bump.jpg", &tex1); D3DXCreateTextureFromFile(D3DDevice, "dudv.jpg", &tex2);

Здесь мы задаем размеры нашей воды, коэффициент тайлинга, позицию воды в мире, вызываем инициализацию эффекта и загружаем две текстуры.

В функции удаления не забываем очистить ресурсы (текстуры).

Tex1->Release(); tex2->Release();

Ну и в функции рисования:

РИСУЕМ_ВСЕ_ОБЪЕКТЫ_СЦЕНЫ_КРОМЕ_ВОДЫ_ Water.PreRenderForReflection(ActiveCamera); _РИСУЕМ_ВСЕ_ОБЪЕКТЫ_СЦЕНЫ_КРОМЕ_ВОДЫ_ Water.PostRenderForReflection(ActiveCamera); DrawWater();

Далее рисуем все объекты, вызываем подготовку к рисованию отражения, рисуем опять все объекты (если их несколько, то не забывайте менять мировые матрицы), но уже в текстуру, и возвращаем значения, которые были до рисования в текстуру, вызвав PostRenderForReflection . Наконец, рисуем саму воду с отражением на ней (вызываем функцию DrawWater).

Вот и все!

4. Исходный код

Здесь вы можете скачать пример к статье с исходным кодом.
Надеюсь, у вас все получится!

В пределах земной коры роль воды исключительная.

В. И. Вернадский

Замечено также, что Северное полушарие планеты существенно «материковое» (39,4 процента суши), а Южное «океаническое» (19 процентов). Большая часть материковой поверхности видна, если находиться над устьем р. Луары: вокруг «материкового полюса» суша составляет 47 процентов видимой территории. «Океанический полюс» окажется у Новой Зеландии (воды занимают 89 процентов поверхности).

Размах земного рельефа значителен: от 8848 метров - вершина Джомолунгмы до 11020 метров - дно Марианской впадины. Но относительно радиуса геоида это составит незначительную величину: положительные отметки поверхности лишь 11/10 000, а отрицательные 17/10 000. Средняя глубина океана 6/10 000, средняя высота суши около 1/10 000. Следовательно, различия в рельефе Земли на глобусе радиусом 10 метров составят от 1 до 17 миллиметров относительно поверхности океана. Отсюда вывод: на Земле очень мало воды, хотя по разным подсчетам объем поверхностных вод составляет 1380-1450 миллионов кубических километров. Возможно столько же воды в земных недрах. По мнению С. М. Григорьева, поверхностные и подземные воды находятся в динамическом равновесии вплоть до подошвы поверхности Мохоровичича, и вода выступает в роли активного теплоносителя, растворителями транспортирующего агента.

Если мысленно удалить всю воду с поверхности Земли, наша планета предстанет в непривычном виде: над плоскими равнинами океанического дна немного выступают слабо расчлененные массивы материков с узкими цепями горных хребтов. Несколько десятков тысяч лет назад (в плейстоцене) уровень Мирового океана был метров на 100 ниже. И, хотя обширные пространства шельфовых морей были сушей, очертания материков ненамного отличались от теперешних. Контуры материков мало изменились бы даже при понижении уровня Мирового океана на 2-3 тысячи метров. М. В. Муратов (1975 год) считает это особенностью дна океанических впадин - истинной поверхности Земли, не зависящей от количества поверхностной воды. Главное отличие - различное строение материковых и океанических пространств как геологических антиподов, что объясняется планетарными причинами, действующими свыше 4 миллиардов лет.

Океанолог X. Райт в 1961 году писал: «…обширные водные пространства, которые мы видим сегодня, вырастали капля за каплей на протяжении всей жизни нашей планеты за счет воды, просачивающейся из недр Земли». Скорее всего, зарождение внешней водной оболочки от­носится к эпохам, отдаленным от нашего времени на 3 или даже 3,5 миллиарда лет. И, вероятно, очертания материков не так уж изменились за это время. Конечно, глубокие океаны появились сравнительно недавно. И процесс засолонения Мирового океана был мощным геологическим фактором, так как вода интенсивнее растворяла горные породы основного состава. Е. А. Долгинов (1978 год) подметил, что большая часть морских заливов находится в зонах и областях, сложенных чернокитами, гнейсами и изверженными породами основного состава, а мысы и полуострова материков построены из более устойчивых гранитоидов и гранито-гнейсов. Особенно отчетливо это наблюдается в зонах фиордов, образующихся, как правило, на месте даек основного состава.

Кто, волны, вас остановил,

Кто оковал ваш бег могучий,

Кто в пруд безмолвный и дремучий

Поток мятежный обратил?
А. С. Пушкин

Вопрос, вынесенный в заголовок, может вызвать удивление: разве не потому называют поверхность воды уровнем, что ей свойственно занимать строго горизонтальное положение; говоря же об уровне, имеют в виду какую-либо плоскость, а что может быть более плоским, чем водная гладь? Недаром же так говорится!

Не будем оспаривать традиционные представления, только уточним: словосочетание «водная гладь» справедливо в том случае, когда вода неподвижна. Но этого практически не бывает. У воды иной характер...

Обращаясь к естественным водным объ-

ектам, мы редко находим подтверждение

сложившимся представлениям об идеальной

горизонтальности уровня воды, а вот примеры

его негоризонтальности повсеместны — от

капли воды до океана. Негоризонтальность

видна даже на микроуровне. Например,

в мензурке или тонкой трубочке уровень

воды всегда имеет явную вогнутую форму,

соответствующую самому высокому коэф-

фициенту поверхностного натяжения среди

жидкостей (за исключением ртути). По этой

же причине капля воды не распластывается

на вощёной бумаге, а в невесомости вообще

остаётся в форме шара.

Нарушение горизонтальности водной по-

верхности заметно и на макроуровне. Вдали

от океанов и морей поверхность их представ-

ляется нам строго горизонтальной. Но если

морские просторы перед вашими глазами,

пройдитесь взглядом вдоль горизонта — вы

увидите не прямую линию, а дугу... И в плане-

тарных масштабах океанов и морей их водная

поверхность действительно сферична, она

повторяет очертания земного шара, а её кри-

визна определяется законами физики.

Планетарная кривизна — это, конечно, ещё

не водная «гладь» океана, она периодически

нарушается прохождением длинных волн

приливов и отливов, связанных с положением

Луны и Солнца. Во время приливов уклон на-

правлен в сторону суши, во время отливов — в

обратную сторону.

Высота приливной волны различна в разных

местах Земли и зависит от формы берегов.

Высочайшие на Земле приливы (15,6—18 м)

зафиксированы в бухте Фанди (Атлантическое

побережье Канады). На европейском кон-

тиненте самые высокие приливы (до 13,5 м)

наблюдаются на западном берегу Франции, в

Бретани. В России подобные приливы случа-

ются в Пенжинской губе Охотского моря — до

12,9 м. Это место самых высоких приливов на

всём Тихом океане.

Кроме приливно-отливных перекосов уров-

ня океана его горизонтальность постоянно

искажается сгонно-нагонными ветровыми

течениями, штормовыми волнами, а у бере-

гов — всплесками прибоев. Самое мощное на

Земле тёплое течение Гольфстрим выглядит

«выпуклой» рекой, возвышаясь над поверх-

ностью Атлантического океана на 1—2 м.

Так что «гладь океана» — всего лишь роман-

тически-образное выражение, на что обращал

внимание прекрасный знаток географии

океанов писатель Жюль Верн. Его знамени-

тый капитан Немо многократно опровергал

идеализацию «океанской глади»: «Лёгкая

зыбь пробегала по водной глади… Лёгкий

ветерок чуть рябил водную гладь… Ничего

волны, поднятой на водной глади…» А вот и

главный вывод: «Застывшая водная гладь, к

его удивлению, вопреки ожиданиям совсем

не оказалась ровной, словно зеркало».

Так что водная «гладь» — большая редкость.

Пушкину даже «ласковое» Чёрное море увиде-

лось в другом настроении:

Шуми, шуми, послушное ветрило.

Волнуйся подо мной, угрюмый океан.

А какие эмоции одолевают нас при виде

грозной поверхности океана на картинах

И. К. Айвазовского! Океан у нашего великого

мариниста никогда не бывает спокойным.

Но может быть, в поисках «зеркальности»

воды стоит обратиться к меньшим по площади

водоёмам? Не найдём ли там примеры иде-

ально ровной водной плоскости?

Нет, вопреки расхожим представлениям,

уровень воды на поверхности крупных озёр

тоже не бывает строго горизонтальным. Он

имеет «перекосы» в виде длинных, на глаз

малозаметных, волн — так называемых сейш.

Они возникают под воздействием внешних

сил: изменения атмосферного давления,

направления и скорости ветра, сейсмических

толчков, обрушения берегов.

Сейши характеризуются большим перио-

дом (от нескольких минут до десятков часов)

и заметной амплитудой (от миллиметров до

нескольких метров). Так, на Женевском озере

(Швейцария) амплитуда сейш достигает 2 м с

периодом более одного часа. А в достаточно

изолированном и мелководном Азовском

море наблюдались сейши с периодом до 23

часов и амплитудой 10—25 см.

Нечто подобное происходит в Финском

заливе, где глубокий циклон с сильнейши-

ми западными ветрами создаёт «перекос»

уровней и длинная волна, распластываясь,

накатывает в устье Невы, вызывая знаменитые

наводнения в Санкт-Петербурге. Пушкин, не

имея никаких систематических наблюдений,

коротко и точно описал причину обратного

течения Невы, то есть изменения её уклона:

Но силой ветров от залива

Переграждённая Нева

Обратно шла, гневна, бурлива,

И затопляла острова…

Простейшую модель сейши легко про-

наблюдать в тазу с водой. Качнув его один

раз, можно увидеть, как возникшие волны,

многократно отражаясь от бортов, перека-

тываются по поверхности. Они сталкивают-

ся, хаотично накладываются друг на друга,

создавая сложную волновую систему.

Но самые значительные искажения гори-

зонтальности уровня воды происходят на

наиболее подвижных водных объектах — ре-

Очевидно, что любой поток воды не может

быть строго горизонтальным именно потому,

что он течёт, а значит, имеет уклон, ведь, со-

гласитесь, без уклона вода течь не будет. И,

рассматривая продольный профиль реки, мы

всегда видим направленность уклона как дна

реки, так и её поверхности.

Но если русло реки достаточно стабильно,

то уровень воды в нём меняется постоянно.

Неслучайно измерение его на водомерных

постах производится как минимум дважды в

сутки, во время половодья и паводков — каж-

дый час. Именно в эти периоды реки особенно

агрессивны, тем более когда они угрожающе

«прыгают в высоту» (опять-таки лишь образ-

ное выражение, подразумевающее наивыс-

ший подъём уровня и выход речной воды за

пределы собственного русла).

Понятно, что необходимо знать, насколько

высоко река может подняться. Большинство

городов возникло в то время, когда не было

никаких сведений о возможных колебаниях

уровня воды в реках, и теперь многие из них

жестоко страдают от периодически повторяю-

щихся катастрофических наводнений. Обще-

известны наводнения на реках Китая, Индии,

США, некоторых европейских стран. Наводне-

ния происходят в Петербурге, Архангельске,

Красноярске, Благовещенске, Крымске и в

других городах и населённых пунктах России.

Учитывая печальный опыт затопления старых

городов, проектирование и строительство

новых проводится с обязательным учётом

наивысших уровней воды. Но как определить

величину таких подъёмов? Для этого нужно

знать закономерности водного режима рек и

озёр, иметь длительный ряд наблюдений за

ними. По хронологическому графику суточ-

ных изменений уровня воды (он называется

гидрографом) можно судить о характере вод-

ного питания, сроках наступления и величине

экстремальных ситуаций.

Высота подъёма уровня воды на реках во

время половодья или паводков зависит от

многих причин: на одних реках — это величи-

на снегозапасов и интенсивность их таяния,

на других — количество осадков и продол-

жительность ливней, на третьих — условия

замерзания и вскрытия ото льда, дружность

ледохода, на четвёртых — направление вет-

ровых и приливных нагонов воды. Но сильнее

всего влияют размер площади водосбора и

характер русла реки. Очевидно, чем сильнее

стеснено берегами русло, тем больше реке

хочется вырваться за его пределы и тем выше

ей приходится подниматься. И наоборот: в

широких заболоченных поймах, где ничто не

мешает реке разойтись вширь, подъём воды

незначительный. Особенно успокаивающе

действуют на реки… озёра и болота. Чем их

больше в речном бассейне, тем меньше ко-

лебания уровня воды.

Каковы же реальные подъёмы уровня воды

на реках и озёрах? И не являются ли плодом

художественного воображения рассказы о

многометровых скачках уровня реки, о водя-

ных валах, о скрывшихся под водой посёлках,

о затоплении обширных пространств, соизме-

римых с площадью некоторых государств?

Как показывают многолетние гидрологи-

ческие наблюдения, такие события не только

имели и имеют место, но они поддаются оп-

ределённой классификации.

Самые высокие подъёмы уровня воды отме-

чаются на равнинных реках, текущих в чётко

выраженных берегах при отсутствии поймы. В

этих условиях даже на малых реках колебания

уровней достигают 2—4 м, а на средних и круп-

ных — вода способна подниматься до высоты

многоэтажных домов. О «прекрасном голубом

Дунае» слышали все, но не все знают, что за

две тысячи километров от его устья, в Австрии,

амплитуда колебаний уровня дунайской воды

достигает почти 15 м, в Будапеште отмечены

прыжки уровня более 10 м. Однако в Европе

рекорд по «прыжкам в высоту» держит… Ока.

В районе Калуги амплитуда колебаний уровня

воды за более чем 120-летний период наблю-

дений достигла 19 м! На этом фоне подъёмы

воды на Дону покажутся умеренными — «все-

го» 12—14 м, а на верхней Волге (до создания

регулирующих водохранилищ) вода выше 10 м

не поднималась.

Достаточно высокую планку преодолева-

ют наши северные реки. Мощные водные

потоки, ограниченные крутыми и прочными

берегами, способны подниматься на высоту

10—12 м. Особенно велики амплитуды коле-

баний уровней на Печоре. Почти на всём её

протяжении разница между минимальными

и максимальными уровнями достигает 12 м.

Столь же «прыгуч» и приток Печоры — река

Уса. Другой северный гигант — Северная

Двина — почти не уступает своей соседке. В

районе Усть-Пинеги многолетние колебания

уровня превысили 12 м. Достаточно «прыгуча»

и река Сухона, особенно в нижнем течении.

Десятиметровые подъёмы уровня её воды не

раз испытал на себе Великий Устюг.

Однако, несмотря на знаменитые россий-

ские «разливы рек её, подобные морям»,

чемпионов по «прыжкам вверх» следует искать

в Азии. Наибольший подъём уровня воды в на-

шей стране — до 32 м — наблюдался на реке

Тунгуске. К счастью, никаких хозяйственных

объектов в этом створе нет. А среди мировых

рек-гигантов самый высокий «прыжок» совер-

шает река Янцзы в Китае. В теснине у города

Ичан он достигает 50 м. Какой же мощью нуж-

но обладать, чтобы взять такую высоту!

Реки, имеющие поймы, не могут даже при-

близиться к подобным результатам. Обычно

амплитуда колебаний уровней воды в них

не превышает в верхнем течении 1,5—2 м, в

среднем — 15—20 м. По этой причине и Волга

в низовьях, и Урал на всём протяжении не под-

нимаются выше 10 м.

Ещё ниже результаты у рек, протекающих в

пределах равнинных заболоченных террито-

рий — в Западной Сибири, в Полесье. Здесь на

крупных реках — Оби, Припяти — амплитуда

колебаний уровня едва достигает 8—10 м, на

малых реках — 1—1,5 м.

Самые низкие результаты показывают

озёрные и горные реки. Многолетние колеба-

ния уровня воды даже на полноводных реках

не превышают 4—6 м. К их числу относятся

Ангара, Волхов, Нева. Так, за всю историю

наблюдений у Новой Ладоги амплитуда коле-

баний уровня воды в Волхове составила 3,3 м.

Ещё меньше она для Невы, сток которой почти

полностью регулируется Ладогой.

В связи с этим возникает вопрос: способ-

ны ли подниматься озёра? В отличие от рек,

большая ёмкость озёр не позволяет им так

быстро и легко поддаваться капризам пого-

ды — дружному снеготаянию, интенсивному

ливню, нагонным ветрам и т. п. Поэтому ам-

плитуда их уровней гораздо меньше, особенно

у солидных озёр. Уровень Ладожского озера,

например, за период наблюдений более

140 лет колебался в пределах 1,5—2,5 м, на

Байкале вековые колебания уровня не пре-

высили 2,2 м.

На территории России наиболее «подъём-

но» озеро Ильмень, амплитуда его уровней

за весь период наблюдений превышает 7 м.

(Как тут не вспомнить легенду о граде Китеже,

ушедшем под воду?) Это объясняется тем,

что площадь водной поверхности Ильменя

примерно в 90 раз меньше площади питаю-

щего его бассейна. Поэтому озеро так бурно

реагирует на малейшие изменения водности

своей огромной вотчины. Примерно так же

ведёт себя его северный сосед на Вологод-

чине — озеро Кубенское, наивысшие подъёмы

уровня там достигают 5—6 м. Все остальные

озёра севера и северо-запада России под-

нимаются в пределах 2—3 м.

И всё же в мире существует уникальный

пример практически абсолютной горизон-

тальности воды — это бессточное Большое

Солёное озеро на северо-западе США. Вы-

сохший до корки слой соли повторяет уровень

воды и обеспечивает настолько ровную по-

верхность, что на ней проводятся испытания

и гонки сверхскоростных машин.

Но если «перекосы» уровней характерны

даже для озёр, то на реках они ещё более

заметны. Нет сомнений в продольном уклоне

водного потока. Но очевидно ли наличие по-

перечного? Здравый смысл подсказывает:

если бы он был, вода бы двигалась поперёк

реки — между берегами. Такое допущение

может показаться абсурдным — ведь это не

должно происходить!

Тем не менее поперечный уклон воды в

русле существует. В этом легко убедиться, на-

блюдая за жизнью большой равнинной реки.

Обратите внимание на поведение водного

потока в различные сезоны года. Присмо-

тритесь к реке весной, в половодье, во вре-

мя ледохода. Свободно плывущие льдины

приближаются, иногда даже прижимаются

к берегам, а в случае ледяного затора часто

«наползают» на них. Это говорит о том, что

существует уклон, направленный из середины

реки к берегам. Если же проследить за рекой

по окончании половодья, в межень, то нетруд-

но будет заметить, что все свободно плывущие

предметы (брёвна, ветки, различный мусор)

придерживаются середины реки, чётко выяв-

ляя стрежень водного потока. Того самого, на

который «выплывали расписные острогрудые

челны». Следовательно, существует уклон,

направленный от берегов к середине реки.

Опытные водные туристы могут подтвердить

наличие не только продольных, но и попереч-

ных течений в русле реки, особенно там, где

меняется направление стрежня.

Чем же объясняется возникновение раз-

нонаправленных по сезонам поперечных ук-

лонов? Гидрологи полагают, что их причиной

являются существенные изменения расхода

воды в русле. Для большинства рек объём

воды в половодье или в паводок может воз-

растать в десятки раз. Поэтому, когда русло

переполняется водой, наибольшая пропус-

кная способность приходится на срединную

часть реки, где влияние трения о берега и

дно относительно невелико и незначительно

сказывается на скорости потока. В результате

большего напора уровень воды здесь стано-

вится выше, чем у берегов. И тогда говорят:

«река вздулась». Иногда это заметно даже на

глаз; на крупных и полноводных реках превы-

шение срединного уровня над прибрежным

достигает 1 м. В этих случаях при ширине реки

1,5—2 км поперечный уклон превышает 0,001,

что немало даже для продольного уклона ес-

тественных водотоков. Из-за такого перепада

уровней в реке возникает движение воды от

середины русла к берегам, которое и увлекает

за собой льдины.

В конце половодья водность и глубина реки

уменьшаются и возрастает тормозящее вли-

яние дна и берегов. Это приводит к тому, что

уровень воды у берегов оказывается выше,

чем посередине реки, в русле возникает дви-

жение воды в направлении от берегов к центру.

Очевидно, что плывущие по реке предметы

будут стремиться к её середине, так что по их

местонахождению в потоке можно определить

и фазы водного режима — подъём или спад.

Определение, конечно, будет поверхностным,

ведь мы не видим, что происходит в глубине

русла. Река умело прячет «концы в воду»,

и можно только догадываться, что помимо

продольной скорости в реках существуют по-

перечные циркуляционные течения.

Причина данного явления была вскрыта

лишь в середине прошлого века. Эксперимен-

тальными работами М. А. Великанова (1958),

Н. И. Маккавеева и других (1961) установлено,

что поверхность реки может изменять свою

форму, образовывать различные уклоны

под влиянием увеличения или уменьшения

её расхода, наличия центробежной силы на

поворотах, силы вращения Земли, ветра и

Наиболее сложные случаи движения воз-

никают на изгибах русла, где наряду с силой

тяжести на скорость течения влияет центро-

бежная сила, которая «прижимает» поток к во-

гнутому (подмываемому) берегу и несколько

приподнимает уровень воды. В результате

избытка гидростатического давления в при-

донных слоях вода «отжимается» и направля-

ется в сторону выпуклого берега.

Таким образом, возникают два поперечных

течения: одно — «поверхностное», ударяющее

в вогнутый берег, другое — «придонное», на-

правленное в противоположную сторону. В

каждой излучине направление циркуляции

своё. На правых поворотах — струи воды

движутся по часовой стрелке, на левых — в об-

ратном направлении. Так создаётся круговая

циркуляция в потоке.

Смешиваясь с основным продольным

потоком, разно направленные течения на

поверхности и у дна создают спиралевидное

(«винтовое») движение воды. Некоторые реки

так и текут — «по спирали» от излучины до

излучины вниз по течению.

Ещё сложнее движение речного потока в

«критические» сезонные периоды. При ве-

сеннем половодье выпуклая форма водной

поверхности создаёт два расходящихся к

берегам уклона и соответствующие им те-

чения. При этом, достигая дна, они меняют

направление и, сталкиваясь на середине,

устремляются к поверхности. В летнюю ме-

жень движение воды происходит иначе: по-

верхностные потоки направлены к середине

реки, сталкиваются и уходят на глубину, где и

расходятся в сторону берегов. Таким образом,

в эти периоды речной поток состоит из двух

параллельно движущихся, но противоположно

закрученных спиралевидных течений.

Наблюдения показывают, что наиболее

устойчивы уровни в реках и озёрах в летнюю и

зимнюю межень. Это те периоды, когда приток

воды ограничен и может даже прекратиться,

а сами уровни минимальны. Причём часто

поверхность воды теряет естественную откры-

тость, покрываясь летом теплолюбивой вод-

ной растительностью (ряской, водорослями),

а зимой — льдом. И то и другое сдерживает

волновые колебания уровня воды.

Такие водоёмы очень поэтичны и любимы

художниками. Вспомните заросший пруд

на картине В. М. Васнецова «Алёнушка» или

покрытые кувшинками пруды на пейзажах

Клода Моне...

Что касается выравнивающего влияния

ледового покрова, то и тут можно только

восхищаться наблюдательностью Пушкина,

нашедшего точное и изящное сравнение:

Опрятней модного паркета

Блистает речка, льдом одета.

Спору нет, «застывшие» речки и пруды про-

изводят иногда впечатление водного зеркала.

И, действительно, реальная горизонтальность

существует, но лишь на очень немногих вод-

ных объектах, чаще всего небольших, замкну-

тых, изолированных от внешних воздействий,

да и то на короткий период и на определённом

отрезке длины. Таким образом, на вопрос,

поставленный в заголовке, приходится чаще

всего отвечать отрицательно. А если и поло-

жительно, то с большими оговорками…