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 ReflectionExample : public Example
{
private:
shapes::Plane make_plane;
shapes::DrawingInstructions plane_instr;
typedef shapes::TwistedTorus Shape;
Shape make_shape;
shapes::DrawingInstructions shape_instr;
Context gl;
ProgramUniform<Mat4f>
plane_projection_matrix, plane_camera_matrix, plane_model_matrix,
shape_projection_matrix, shape_camera_matrix, shape_model_matrix;
Buffer plane_verts, plane_texcoords;
Buffer shape_verts, shape_normals;
GLuint width, height;
const GLuint tex_size_div;
public:
ReflectionExample(void)
: make_plane(
Vec3f(0.0f, 0.0f, -3.0f),
15,
15
), plane_instr(make_plane.Instructions())
, plane_indices(make_plane.Indices())
, make_shape()
, shape_instr(make_shape.Instructions())
, shape_indices(make_shape.Indices())
, plane_vs(ObjectDesc("Plane vertex"))
, shape_vs(ObjectDesc("Shape vertex"))
, plane_fs(ObjectDesc("Plane fragment"))
, shape_fs(ObjectDesc("Shape fragment"))
, plane_projection_matrix(plane_prog)
, plane_camera_matrix(plane_prog)
, plane_model_matrix(plane_prog)
, shape_projection_matrix(shape_prog)
, shape_camera_matrix(shape_prog)
, shape_model_matrix(shape_prog)
, width(800)
, height(600)
, tex_size_div(2)
{
plane_vs.Source(
"#version 330\n"
"uniform vec3 LightPosition;"
"uniform mat4 ProjectionMatrix, CameraMatrix, ModelMatrix;"
"in vec4 Position;"
"out vec3 vertLightDir;"
"out vec4 vertTexCoord;"
"void main(void)"
"{"
" gl_Position = ModelMatrix*Position;"
" vertLightDir = LightPosition - gl_Position.xyz;"
" gl_Position = ProjectionMatrix * CameraMatrix * gl_Position;"
" vertTexCoord = gl_Position;"
"}"
);
plane_vs.Compile();
plane_fs.Source(
"#version 330\n"
"uniform sampler2DRect ReflectTex;"
"uniform vec3 Normal;"
"in vec3 vertLightDir;"
"in vec4 vertTexCoord;"
"out vec3 fragColor;"
"const int n = 5;"
"const int ns = (n*n);"
"const float blur = 0.15/n;"
"void main(void)"
"{"
" float d = dot(Normal, normalize(vertLightDir));"
" float intensity = 0.5 + pow(1.4*d, 2.0);"
" vec3 color = vec3(0.0, 0.0, 0.0);"
" int n = 2;"
" float pct = 0.5/vertTexCoord.w;"
" for(int y=-n; y!=(n+1); ++y)"
" for(int x=-n; x!=(n+1); ++x)"
" {"
" vec2 coord = vertTexCoord.xy;"
" coord += vec2(blur*x, blur*y);"
" coord *= pct;"
" coord += vec2(0.5, 0.5);"
" coord *= textureSize(ReflectTex);"
" color += texture(ReflectTex, coord).rgb/ns;"
" }"
" fragColor = color*intensity;"
"}"
);
plane_fs.Compile();
plane_prog.AttachShader(plane_vs);
plane_prog.AttachShader(plane_fs);
plane_prog.Link();
plane_prog.Use();
plane_projection_matrix.BindTo("ProjectionMatrix");
plane_camera_matrix.BindTo("CameraMatrix");
plane_model_matrix.BindTo("ModelMatrix");
Vec3f lightPos(3.0f, 0.5f, 2.0f);
Uniform<Vec3f>(plane_prog,
"LightPosition").
Set(lightPos);
Uniform<Vec3f>(plane_prog,
"Normal").
Set(make_plane.Normal());
plane.Bind();
plane_verts.Bind(Buffer::Target::Array);
{
std::vector<GLfloat> data;
GLuint n_per_vertex = make_plane.Positions(data);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib attr(plane_prog, "Position");
attr.Setup<GLfloat>(n_per_vertex);
attr.Enable();
}
Texture::Active(1);
gl.Bound(Texture::Target::Rectangle, depth_tex)
Texture::Active(0);
ProgramUniformSampler(plane_prog, "ReflectTex").Set(0);
gl.Bound(Texture::Target::Rectangle, reflect_tex)
gl.Bound(Framebuffer::Target::Draw, fbo)
.AttachTexture(
reflect_tex,
0
).AttachTexture(
depth_tex,
0
);
shape_vs.Source(
"#version 330\n"
"uniform vec3 LightPosition;"
"uniform mat4 ProjectionMatrix, ModelMatrix, CameraMatrix;"
"in vec4 Position;"
"in vec3 Normal;"
"out vec3 vertNormal;"
"out vec3 vertLightDir;"
"out vec3 vertLightRefl;"
"out vec3 vertViewDir;"
"out vec3 vertColor;"
"void main(void)"
"{"
" gl_Position = ModelMatrix * Position;"
" vertLightDir = LightPosition - gl_Position.xyz;"
" vertNormal = mat3(ModelMatrix)*Normal;"
" vertLightRefl = reflect("
" -normalize(vertLightDir),"
" normalize(vertNormal)"
" );"
" vertViewDir = (vec4(0.0, 0.0, 1.0, 1.0)*CameraMatrix).xyz;"
" vertColor = vec3(1, 1, 1) - vertNormal;"
" gl_Position = ProjectionMatrix * CameraMatrix * gl_Position;"
"}"
);
shape_vs.Compile();
shape_fs.Source(
"#version 330\n"
"in vec3 vertNormal;"
"in vec3 vertLightDir;"
"in vec3 vertLightRefl;"
"in vec3 vertViewDir;"
"in vec3 vertColor;"
"out vec3 fragColor;"
"void main(void)"
"{"
" float l = length(vertLightDir);"
" float d = dot("
" normalize(vertNormal), "
" normalize(vertLightDir)"
" ) / l;"
" float s = dot("
" normalize(vertLightRefl),"
" normalize(vertViewDir)"
" );"
" vec3 lt = vec3(1.0, 1.0, 1.0);"
" fragColor = "
" vertColor * 0.4 + "
" (lt + vertColor)*pow(max(2.5*d, 0.0), 3) + "
" lt * pow(max(s, 0.0), 64);"
"}"
);
shape_fs.Compile();
shape_prog.AttachShader(shape_vs);
shape_prog.AttachShader(shape_fs);
shape_prog.Link();
shape_prog.Use();
shape_projection_matrix.BindTo("ProjectionMatrix");
shape_camera_matrix.BindTo("CameraMatrix");
shape_model_matrix.BindTo("ModelMatrix");
Uniform<Vec3f>(shape_prog,
"LightPosition").
Set(lightPos);
shape.Bind();
shape_verts.Bind(Buffer::Target::Array);
{
std::vector<GLfloat> data;
GLuint n_per_vertex = make_shape.Positions(data);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib attr(shape_prog, "Position");
attr.Setup<GLfloat>(n_per_vertex);
attr.Enable();
}
shape_normals.Bind(Buffer::Target::Array);
{
std::vector<GLfloat> data;
GLuint n_per_vertex = make_shape.Normals(data);
Buffer::Data(Buffer::Target::Array, data);
VertexArrayAttrib attr(shape_prog, "Normal");
attr.Setup<GLfloat>(n_per_vertex);
attr.Enable();
}
gl.ClearColor(0.5f, 0.5f, 0.4f, 0.0f);
gl.ClearDepth(1.0f);
}
void Reshape(GLuint vp_width, GLuint vp_height)
{
width = vp_width;
height = vp_height;
float aspect = float(width)/height;
auto projection =
plane_projection_matrix.Set(projection);
shape_projection_matrix.Set(projection);
gl.Bound(Texture::Target::Rectangle, depth_tex).Image2D(
0,
width/tex_size_div, height/tex_size_div,
0,
nullptr
);
gl.Bound(Texture::Target::Rectangle, reflect_tex).Image2D(
0,
width/tex_size_div, height/tex_size_div,
0,
nullptr
);
}
{
4.5,
Degrees(45.0 -
SineWave(time / 7.0)*35.0)
);
shape_prog.Use();
shape.Bind();
gl.FrontFace(make_shape.FaceWinding());
shape_model_matrix =
fbo.Bind(Framebuffer::Target::Draw);
gl.Viewport(width/tex_size_div, height/tex_size_div);
gl.Clear().ColorBuffer().DepthBuffer();
shape_camera_matrix = camera * reflection;
gl.FrontFace(
Inverted(make_shape.FaceWinding()));
shape_instr.Draw(shape_indices);
dfb.Bind(Framebuffer::Target::Draw);
gl.Viewport(width, height);
gl.Clear().ColorBuffer().DepthBuffer();
shape_camera_matrix = camera;
gl.FrontFace(make_shape.FaceWinding());
shape_instr.Draw(shape_indices);
plane_prog.Use();
plane.Bind();
gl.FrontFace(make_plane.FaceWinding());
plane_camera_matrix = camera;
plane_instr.Draw(plane_indices);
}
{
return time < 60.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 ReflectionExample);
}
}