Copyright 2008-2014 Matus Chochlik. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <cmath>
namespace oglplus {
class WavesExample : public Example
{
private:
shapes::Plane make_plane;
shapes::DrawingInstructions plane_instr;
Context gl;
Lazy<Uniform<Mat4f>> camera_matrix;
Lazy<Uniform<Vec3f>> camera_position;
Lazy<Uniform<GLfloat>> anim_time;
int prev_period;
public:
WavesExample(void)
: make_plane(
Vec3f( 0.0f, 0.0f, 0.0f),
Vec3f(100.0f, 0.0f, 0.0f),
Vec3f( 0.0f, 0.0f,-100.0f),
50, 50
), plane_instr(make_plane.Instructions(shapes::DrawMode::Patches()))
, plane_indices(make_plane.Indices(shapes::DrawMode::Patches()))
, camera_matrix(prog, "CameraMatrix")
, camera_position(prog, "CameraPosition")
, anim_time(prog, "Time")
, prev_period(-1)
{
vs.Source(
"#version 330\n"
"uniform vec3 CameraPosition;"
"in vec3 Position;"
"out vec3 vertPosition;"
"out float vertDistance;"
"void main(void)"
"{"
" vertPosition = Position;"
" vertDistance = distance(CameraPosition, Position);"
"}"
);
prog.AttachShader(vs);
cs.Source(
"#version 330\n"
"#extension ARB_tessellation_shader : enable\n"
"layout(vertices = 3) out;"
"in vec3 vertPosition[];"
"in float vertDistance[];"
"out vec3 tecoPosition[];"
"int tessLevel(float dist)"
"{"
" return clamp(int(150.0 / (dist+0.1)), 1, 10);"
"}"
"void main(void)"
"{"
" tecoPosition[gl_InvocationID] ="
" vertPosition[gl_InvocationID];"
" if(gl_InvocationID == 0)"
" {"
" gl_TessLevelInner[0] = tessLevel(("
" vertDistance[0]+"
" vertDistance[1]+"
" vertDistance[2] "
" )*0.333);"
" gl_TessLevelOuter[0] = tessLevel(("
" vertDistance[1]+"
" vertDistance[2] "
" )*0.5);"
" gl_TessLevelOuter[1] = tessLevel(("
" vertDistance[2]+"
" vertDistance[0] "
" )*0.5);"
" gl_TessLevelOuter[2] = tessLevel(("
" vertDistance[0]+"
" vertDistance[1] "
" )*0.5);"
" }"
"}"
);
prog.AttachShader(cs);
es.Source(
"#version 330\n"
"#extension ARB_tessellation_shader : enable\n"
"#define MaxWaves 5\n"
"layout(triangles, equal_spacing, ccw) in;"
"uniform mat4 ProjectionMatrix, CameraMatrix;"
"uniform vec3 LightPosition;"
"uniform vec3 CameraPosition;"
"uniform float Time;"
"uniform int WaveCount;"
"uniform vec3 WaveDirections[MaxWaves];"
"uniform vec3 WaveDimensions[MaxWaves];"
"in vec3 tecoPosition[];"
"out vec3 teevNormal;"
"out vec3 teevLightDir;"
"out vec3 teevViewDir;"
"out float teevDistance;"
"void main(void)"
"{"
" const vec3 Up = vec3(0.0, 1.0, 0.0);"
" vec3 Position ="
" gl_TessCoord.x * tecoPosition[0]+"
" gl_TessCoord.y * tecoPosition[1]+"
" gl_TessCoord.z * tecoPosition[2];"
" vec3 Pos = Position;"
" vec3 Nml = Up;"
" for(int wave=0; wave!=WaveCount; ++wave)"
" {"
" vec3 Dir = WaveDirections[wave];"
" vec3 Dim = WaveDimensions[wave];"
" float Dist = dot(Position, Dir);"
" float u = Dim.y*sin(Dist/Dim.x + Time*Dim.z);"
" Pos += Up * u;"
" float w = (Dim.y/Dim.x)*cos(Dist/Dim.x + Time*Dim.z);"
" Nml -= Dir * w;"
" float d = -0.125*Dim.x*sin(2.0*Dist/Dim.x + Time*Dim.z);"
" Pos += Dir * d;"
" }"
" gl_Position = "
" ProjectionMatrix *"
" CameraMatrix *"
" vec4(Pos, 1.0);"
" teevNormal = normalize(Nml);"
" teevLightDir = normalize(LightPosition - Pos);"
" teevViewDir = normalize(CameraPosition - Pos);"
" teevDistance = distance(CameraPosition, Pos);"
"}"
);
prog.AttachShader(es);
fs.Source(
"#version 330\n"
"uniform samplerCube EnvMap;"
"in vec3 teevNormal;"
"in vec3 teevLightDir;"
"in vec3 teevViewDir;"
"in float teevDistance;"
"out vec3 fragColor;"
"void main(void)"
"{"
" float Dim = clamp(30.0/teevDistance, 0.0, 1.0);"
" float LightRefl = dot(reflect(-teevLightDir, teevNormal), teevViewDir);"
" float LightHit = dot(teevNormal, teevLightDir);"
" float Diffuse = clamp(LightHit+0.1, 0.0, 1.0);"
" float Specular = pow(clamp(LightRefl, 0.0, 0.91), 32);"
" vec3 Environ=texture(EnvMap,reflect(-teevViewDir, teevNormal)).rgb;"
" vec3 WaterColor = vec3(0.4, 0.5, 0.5);"
" vec3 LightColor = vec3(1.0, 1.0, 1.0);"
" vec3 FogColor = vec3(0.9, 0.9, 0.9);"
" vec3 WaveColor ="
" LightColor*Specular+"
" WaterColor*Diffuse+"
" Environ*0.02;"
" fragColor = mix(WaveColor, FogColor, 1.0-Dim);"
"}"
);
prog.AttachShader(fs);
prog.Build();
gl.Use(prog);
gl.Bind(plane);
gl.Bind(Buffer::Target::Array, verts);
{
std::vector<GLfloat> data;
GLuint n_per_vertex = make_plane.Positions(data);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib attr(prog, "Position");
attr.Setup<GLfloat>(n_per_vertex);
attr.Enable();
}
Uniform<Vec3f>(prog,
"LightPosition").
Set(-100.0, 100.0, 20.0);
Uniform<Vec3f> wave_directions(prog, "WaveDirections");
Uniform<Vec3f> wave_dimensions(prog, "WaveDimensions");
Uniform<GLint>(prog,
"WaveCount").
Set(5);
wave_directions[0] = Normalized(
Vec3f(1.0f, 0.0f, 1.0f));
wave_dimensions[0] =
Vec3f(5.0f, 1.5f, 1.2f);
wave_directions[1] = Normalized(
Vec3f(1.0f, 0.0f, 0.5f));
wave_dimensions[1] =
Vec3f(4.0f, 0.8f, 1.2f);
wave_directions[2] = Normalized(
Vec3f(1.0f, 0.0f, 0.1f));
wave_dimensions[2] =
Vec3f(2.0f, 0.5f, 2.4f);
wave_directions[3] = Normalized(
Vec3f(1.0f, 0.0f,-0.1f));
wave_dimensions[3] =
Vec3f(1.5f, 0.2f, 3.7f);
wave_directions[4] = Normalized(
Vec3f(1.0f, 0.0f, 0.4f));
wave_dimensions[4] =
Vec3f(1.1f, 0.2f, 4.7f);
Texture::Active(0);
{
auto image = images::Squares(512, 512, 0.9f, 16, 16);
gl.Bind(Texture::Target::CubeMap, env_map);
for(int i=0; i!=6; ++i)
gl.Current(Texture::Target::CubeMap)
.GenerateMipmap();
}
UniformSampler(prog, "EnvMap").Set(0);
gl.ClearColor(0.9f, 0.9f, 0.9f, 0.0f);
gl.ClearDepth(1.0f);
}
void Reshape(GLuint width, GLuint height)
{
gl.Viewport(width, height);
prog.Use();
Uniform<Mat4f>(prog,
"ProjectionMatrix").
Set(
Degrees(75),
double(width)/height,
1, 150
)
);
}
{
gl.Clear().ColorBuffer().DepthBuffer();
int period = int(time * 0.125);
if(prev_period < period)
{
if(period % 2)
prev_period = period;
}
Degrees(45 -
SineWave(time / 29.0f) * 35)
);
camera_matrix.Set(camera);
camera_position.Set(camera.Position());
anim_time.Set(time);
plane_instr.Draw(plane_indices);
}
{
return time < 90.0;
}
};
void setupExample(ExampleParams& ){ }
std::unique_ptr<ExampleThread> makeExampleThread(
Example& ,
unsigned ,
const ExampleParams&
){ return std::unique_ptr<ExampleThread>(); }
std::unique_ptr<Example> makeExample(const ExampleParams& )
{
return std::unique_ptr<Example>(new WavesExample);
}
}