OGLplus (0.52.0) a C++ wrapper for OpenGL

oglplus/022_volumetric_light.cpp

Shows how to render a volumetric light

022_volumetric_light.png

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 <oglplus/gl.hpp>
#include <oglplus/all.hpp>
#include "example.hpp"
namespace oglplus {
class VolLightExample : public Example
{
private:
// wrapper around the current OpenGL context
Context gl;
// Vertex shaders
Shader volume_vs, plane_vs;
// Gemoetry shader
Shader volume_gs;
// Fragment shaders
Shader volume_fs, plane_fs;
Program volume_prog, plane_prog;
VertexArray volume, plane;
Buffer volume_pos, plane_pos;
const GLuint samples;
Texture light_tex;
public:
VolLightExample(void)
: volume_vs(ShaderType::Vertex, ObjectDesc("Volume vertex"))
, plane_vs(ShaderType::Vertex, ObjectDesc("Plane vertex"))
, volume_gs(ShaderType::Geometry, ObjectDesc("Volume geometry"))
, volume_fs(ShaderType::Fragment, ObjectDesc("Volume fragment"))
, plane_fs(ShaderType::Fragment, ObjectDesc("Plane fragment"))
, volume_prog(ObjectDesc("Volume"))
, plane_prog(ObjectDesc("Plane"))
, samples(150)
{
volume_vs.Source(
"#version 330\n"
"in vec4 Position;"
"out float vertZOffs;"
"uniform int SampleCount;"
"uniform mat4 CameraMatrix;"
"uniform vec3 ViewZ;"
"uniform float Size;"
"void main(void)"
"{"
" float hp = (SampleCount-1) * 0.5;"
" vertZOffs = (gl_InstanceID - hp)/hp;"
" gl_Position = vec4("
" Position.xyz +"
" ViewZ*vertZOffs*Size*0.5,"
" 1.0"
" );"
"}"
);
volume_vs.Compile();
volume_gs.Source(
"#version 330\n"
"layout(points) in;"
"layout(triangle_strip, max_vertices = 4) out;"
"uniform mat4 CameraMatrix, ProjectionMatrix;"
"uniform mat4 TexProjectionMatrix;"
"uniform vec3 ViewX, ViewY;"
"uniform float Size;"
"in float vertZOffs[];"
"out vec4 geomTexCoord;"
"void main(void)"
"{"
" float zo = vertZOffs[0];"
" float yo[2] = float[2](-1.0, 1.0);"
" float xo[2] = float[2](-1.0, 1.0);"
" for(int j=0;j!=2;++j)"
" for(int i=0;i!=2;++i)"
" {"
" vec4 v = vec4("
" gl_in[0].gl_Position.xyz+"
" ViewX * xo[i] * Size+"
" ViewY * yo[j] * Size,"
" 1.0"
" );"
" geomTexCoord = "
" TexProjectionMatrix *"
" v;"
" gl_Position = "
" ProjectionMatrix *"
" CameraMatrix * v;"
" EmitVertex();"
" }"
" EndPrimitive();"
"}"
);
volume_gs.Compile();
volume_fs.Source(
"#version 330\n"
"uniform sampler2D LightTex;"
"uniform int SampleCount;"
"in vec4 geomTexCoord;"
"out vec4 fragColor;"
"void main(void)"
"{"
" vec2 coord = geomTexCoord.st/geomTexCoord.q;"
" float depth = geomTexCoord.z;"
" if(depth < 0.0) discard;"
" vec4 t = texture(LightTex, coord*0.5 + 0.5);"
" if(t.a == 0.0) discard;"
" float alpha = 10.0*(1.0-t.a)/SampleCount;"
" alpha *= (t.r+t.g+t.b)*0.3333;"
" alpha /= sqrt(depth);"
" fragColor = vec4(t.rgb, alpha);"
"}"
);
volume_fs.Compile();
volume_prog.AttachShader(volume_vs);
volume_prog.AttachShader(volume_gs);
volume_prog.AttachShader(volume_fs);
volume_prog.Link();
volume_prog.Use();
// bind the VAO for the volumes
volume.Bind();
// bind the VBO for the volume positions
volume_pos.Bind(Buffer::Target::Array);
{
GLfloat position[3] = {0.0, 0.0, 0.0};
Buffer::Data(Buffer::Target::Array, 3, position);
VertexArrayAttrib attr(volume_prog, "Position");
attr.Setup<Vec3f>();
attr.Enable();
}
Vec3f lightPos(2.0f, 4.0f, -3.0f);
auto texProjMat =
CamMatrixf::PerspectiveX(Degrees(30), 1.0, 0.3, 20.0) *
CamMatrixf::LookingAt(lightPos, Vec3f(0, 0, 0));
Uniform<GLint>(volume_prog, "SampleCount").Set(samples);
Uniform<GLfloat>(volume_prog, "Size").Set(Length(lightPos));
Uniform<Mat4f>(volume_prog, "TexProjectionMatrix").Set(texProjMat);
plane_vs.Source(
"#version 330\n"
"in vec4 Position;"
"uniform mat4 CameraMatrix, ProjectionMatrix;"
"uniform mat4 TexProjectionMatrix;"
"out vec2 vertChecker;"
"out vec4 vertTexCoord;"
"void main(void)"
"{"
" gl_Position = "
" ProjectionMatrix *"
" CameraMatrix *"
" Position;"
" vertTexCoord = "
" TexProjectionMatrix *"
" Position;"
" vertChecker = Position.xz;"
"}"
);
plane_vs.Compile();
plane_fs.Source(
"#version 330\n"
"uniform sampler2D LightTex;"
"in vec4 vertTexCoord;"
"in vec2 vertChecker;"
"out vec4 fragColor;"
"void main(void)"
"{"
" vec2 coord = vertTexCoord.st/vertTexCoord.q;"
" vec4 t = texture(LightTex, coord*0.5 + 0.5);"
" float i = ("
" 1 +"
" int(vertChecker.x+10) % 2+"
" int(vertChecker.y+10) % 2"
" ) % 2;"
" vec3 color = vec3(0.1, 0.1, 0.1);"
" color += t.rgb * (1.0 - t.a);"
" color *= mix("
" vec3(0.9, 0.9, 1.0), "
" vec3(0.4, 0.4, 0.9), "
" i"
" );"
" fragColor = vec4(color, 1.0);"
"}"
);
plane_fs.Compile();
plane_prog.AttachShader(plane_vs);
plane_prog.AttachShader(plane_fs);
plane_prog.Link();
plane_prog.Use();
Uniform<Mat4f>(plane_prog, "TexProjectionMatrix").Set(texProjMat);
plane.Bind();
// bind the VBO for the plane vertices
plane_pos.Bind(Buffer::Target::Array);
{
GLfloat data[4*3] = {
-9.0f, -4.0f, 9.0f,
-9.0f, -4.0f, -9.0f,
9.0f, -4.0f, 9.0f,
9.0f, -4.0f, -9.0f
};
Buffer::Data(Buffer::Target::Array, 4*3, data);
plane_prog.Use();
VertexArrayAttrib attr(plane_prog, "Position");
attr.Setup<Vec3f>();
attr.Enable();
}
Texture::Active(0);
ProgramUniformSampler(volume_prog, "LightTex").Set(0);
light_tex
<< Texture::Target::_2D
<< Vec4f(0.0f, 0.0f, 0.0f, 0.0f)
<< images::LoadTexture("flower_glass")
<< TextureMipmap();
gl.ClearColor(0.0f, 0.05f, 0.1f, 0.0f);
gl.ClearDepth(1.0f);
}
void Reshape(GLuint width, GLuint height)
{
gl.Viewport(width, height);
auto perspective = CamMatrixf::PerspectiveX(
Degrees(60),
double(width)/height,
1, 40
);
ProgramUniform<Mat4f>(
plane_prog,
"ProjectionMatrix"
).Set(perspective);
ProgramUniform<Mat4f>(
volume_prog,
"ProjectionMatrix"
).Set(perspective);
}
void Render(double time)
{
gl.Clear().ColorBuffer().DepthBuffer();
auto cameraMatrix = CamMatrixf::Orbiting(
Vec3f(0.0f, 3.0f, 0.0f),
8.0f,
FullCircles(time / 12.0),
Degrees(SineWave(time / 20.0) * 80)
);
plane.Bind();
plane_prog.Use();
Uniform<Mat4f>(plane_prog, "CameraMatrix").Set(cameraMatrix);
gl.DrawArrays(PrimitiveType::TriangleStrip, 0, 4);
gl.Enable(Capability::Blend);
volume.Bind();
volume_prog.Use();
Uniform<Mat4f>(volume_prog, "CameraMatrix").Set(cameraMatrix);
Uniform<Vec3f>(volume_prog, "ViewX").Set(
cameraMatrix.Row(0).xyz()
);
Uniform<Vec3f>(volume_prog, "ViewY").Set(
cameraMatrix.Row(1).xyz()
);
Uniform<Vec3f>(volume_prog, "ViewZ").Set(
cameraMatrix.Row(2).xyz()
);
gl.DrawArraysInstanced(
0, 1,
samples
);
gl.Disable(Capability::Blend);
}
bool Continue(double time)
{
return time < 60.0;
}
};
void setupExample(ExampleParams& /*params*/){ }
std::unique_ptr<ExampleThread> makeExampleThread(
Example& /*example*/,
unsigned /*thread_id*/,
const ExampleParams& /*params*/
){ return std::unique_ptr<ExampleThread>(); }
std::unique_ptr<Example> makeExample(const ExampleParams& /*params*/)
{
return std::unique_ptr<Example>(new VolLightExample);
}
} // namespace oglplus

Copyright © 2010-2014 Matúš Chochlík, University of Žilina, Žilina, Slovakia.
<matus.chochlik -at- fri.uniza.sk>
<chochlik -at -gmail.com>
Documentation generated on Mon Sep 22 2014 by Doxygen (version 1.8.6).