Skip to content

Instantly share code, notes, and snippets.

@roxlu
Created July 16, 2012 19:04
Show Gist options
  • Save roxlu/3124394 to your computer and use it in GitHub Desktop.
Save roxlu/3124394 to your computer and use it in GitHub Desktop.
Light Rays
#include "LightRays.h"
#include <roxlu/opengl/Error.h>
LightRays::LightRays()
:w(0)
,h(0)
,tex(0)
,fbo(0)
,depth_buffer(0)
,frag_shader(0)
,vert_shader(0)
,prog(0)
,vbo(0)
,vao(0)
,exposure(0.0034f)
,decay(0.9999f)
,density(0.84f)
,weight(5.56f)
,light_x(0.0)
,light_y(0.0)
{
}
void LightRays::createTexture(int texW, int texH, GLuint& texID) {
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexImage2D(
GL_TEXTURE_2D
,0
,GL_RGBA
,texW
,texH
,0
,GL_RGBA
,GL_UNSIGNED_BYTE
,NULL
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
void LightRays::setup(int w, int h) {
this->w = w;
this->h = h;
this->dw = w;
this->dh = h;
// Create our fbo.
// ++++++++++++++++++++++++++++++++++++
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// render to this texture.
createTexture(w,h,tex);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
// apply fx into this texture.
createTexture(w,h,fx_tex);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, fx_tex, 0);
// create depth buffer.
glGenRenderbuffers(1, &depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// Create shader
// ++++++++++++++++++++++++++++++++++++
const char* vsp = LR_VS.c_str();
const char* fsp = LR_FS.c_str();
frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
vert_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vert_shader, 1, &(vsp), NULL);
glShaderSource(frag_shader, 1, &(fsp), NULL);
glCompileShader(vert_shader);
glCompileShader(frag_shader);
GLint result;
glGetShaderiv(vert_shader, GL_COMPILE_STATUS, &result);
if(!result) {
printf("Cannot compile vertex shader.\n");
}
glGetShaderiv(frag_shader, GL_COMPILE_STATUS, &result);
if(!result) {
printf("Cannot compile fragment shader.\n");
}
prog = glCreateProgram();
glAttachShader(prog, vert_shader);
glAttachShader(prog, frag_shader);
glBindAttribLocation(prog, 0, "a_pos");
glBindAttribLocation(prog, 1, "a_tex");
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &result);
if(!result) {
printf("Cannot link shaders.\n");
}
// Create VAO + VBO for full screen quad
// ++++++++++++++++++++++++++++++++++++++
LightRayVertex verts[4];
float s = 1.0f;
verts[0].set(-s, s, 0, 0, 1);
verts[1].set( s, s, 0, 1, 1);
verts[2].set( s,-s, 0, 1, 0);
verts[3].set(-s,-s, 0, 0, 0);
#ifdef _WIN32
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);
#elif defined(__APPLE__)
glGenVertexArraysAPPLE(1,&vao);
glBindVertexArrayAPPLE(vao);
#else
#error I need to figure out, how to create a vertex array on your system?
#endif
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(LightRayVertex) * 4, verts[0].getPtr(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0); // pos
glEnableVertexAttribArray(1); // tex
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(LightRayVertex), (GLvoid*)offsetof(LightRayVertex, pos));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(LightRayVertex), (GLvoid*)offsetof(LightRayVertex, tex));
glBindBuffer(GL_ARRAY_BUFFER, 0);
#ifdef _WIN32
glBindVertexArray(0);
#elif defined(__APPLE__)
glBindVertexArrayAPPLE(0);
#else
#error Cannot compile LightRays on this OS
#endif
}
void LightRays::resize(int w, int h) {
this->w = w;
this->h = h;
printf("New w/h: %d, %d\n", w,h);
}
void LightRays::bind() {
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
// GLenum bfs[] = {GL_COLOR_ATTACHMENT0};
//glDrawBuffers(1, bfs);
glViewport(0,0,this->dw,this->dh);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void LightRays::unbind() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0,0,this->w,this->h);
}
void LightRays::draw() {
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// int bfs = {GL_COLOR_ATTACHMENT1};
glDrawBuffer(GL_COLOR_ATTACHMENT1);
// GLenum bfs[] = {GL_COLOR_ATTACHMENT1};
// glDrawBuffers(1, bfs);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0,0,this->dw,this->dh);
// bind
#ifdef _WIN32
glBindVertexArray(vao);
#elif defined(__APPLE__)
glBindVertexArrayAPPLE(vao);
#else
#error Don't now how to draw on your machine (1)
#endif
//glDisable(GL_DEPTH_TEST);
//glDisable(GL_CULL_FACE);
// set shader vars.
glUseProgram(prog);
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(glGetUniformLocation(prog, "u_texture"), 1);
glUniform1f(glGetUniformLocation(prog, "u_exposure"), exposure);
glUniform1f(glGetUniformLocation(prog, "u_decay"), decay);
glUniform1f(glGetUniformLocation(prog, "u_density"), density);
glUniform1f(glGetUniformLocation(prog, "u_weight"), weight);
glUniform1f(glGetUniformLocation(prog, "u_light_x"), light_x);
glUniform1f(glGetUniformLocation(prog, "u_light_y"), light_y);
// apply effect
glUniform1i(glGetUniformLocation(prog, "u_mode"), 0);
glDrawArrays(GL_QUADS, 0, 4);
// draw full screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, fx_tex);
//glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDepthMask(GL_FALSE);
glViewport(0,0,this->w,this->h);
glUniform1i(glGetUniformLocation(prog, "u_mode"), 1);
glDrawArrays(GL_QUADS, 0, 4);
glDepthMask(GL_TRUE);
// unbind
#ifdef _WIN32
glBindVertexArray(0);
#elif defined(__APPLE__)
glBindVertexArrayAPPLE(0);
#else
#error Don't now how to draw on your machine (2)
#endif
glUseProgram(0);
// just make sure 0 and 1 unit are unbound.
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
//glDisable(GL_DEPTH_TEST);
//glDisable(GL_CULL_FACE);
}
#ifndef ROXLU_LIGHTRAYSH
#define ROXLU_LIGHTRAYSH
/**
Drop in light rays
------------------
Basic usage:
- create a member "LightRays lr", then
// setup()
lr.setup(width, height);
// call every draw()
lr.bind();
// draw your scene with 'white' lights and black occulding objects
lr.unbind()
lr.draw()
// resize
lr.resize(w, h);
*/
#include <roxlu/opengl/OpenGL.h>
#include <string>
const std::string LR_VS = " \
attribute vec4 a_pos; \
attribute vec2 a_tex; \
varying vec2 v_tex; \
\
void main() { \
mat4 ident = mat4(1.0); \
v_tex = a_tex; \
gl_Position = ident * a_pos; \
}\
";
const std::string LR_FS = " \
uniform int u_mode;\n \
uniform sampler2D u_texture;\n \
uniform float u_exposure;\n \
uniform float u_decay;\n \
uniform float u_density;\n \
uniform float u_weight;\n \
uniform float u_light_x;\n \
uniform float u_light_y;\n \
const int NUM_SAMPLES = 50;\n \
varying vec2 v_tex;\n \
void main() {\n \
if (u_mode == 0) {\n \
gl_FragColor.rgb = vec3(0.0, 0.0, 0.0); \
vec2 pos_on_screen = vec2(u_light_x, u_light_y);\n \
vec2 delta_texc = vec2(v_tex.st - pos_on_screen.xy);\n \
vec2 texc = v_tex; \n\
delta_texc *= 1.0 / float(NUM_SAMPLES) * u_density;\n \
float illum_decay = 1.0;\n \
for(int i = 0; i < NUM_SAMPLES; i++) {\n \
texc -= delta_texc; \n\
vec4 sample = texture2D(u_texture, texc);\n \
sample *= illum_decay * u_weight; \n\
gl_FragColor += sample; \n\
illum_decay *= u_decay; \n\
}\n \
gl_FragColor *= u_exposure; \n \
} \n\
else if(u_mode == 1) { \n\
gl_FragColor = texture2D(u_texture, v_tex);\n \
gl_FragColor.a = 1.0;\n \
} \n\
\n\
}\n ";
struct LightRayVertex {
float pos[3];
float tex[2];
LightRayVertex(){
pos[0] = pos[1] = pos[2] = 0.0f;
tex[0] = tex[1] = 0.0f;
}
LightRayVertex(const float x, const float y, const float z, const float s, const float t) {
pos[0] = x;
pos[1] = y;
pos[2] = z;
tex[0] = s;
tex[1] = t;
}
void set(const float x, const float y, const float z, const float s, const float t) {
pos[0] = x;
pos[1] = y;
pos[2] = z;
tex[0] = s;
tex[1] = t;
}
const float* getPtr() {
return &pos[0];
}
};
class LightRays {
public:
LightRays();
void setup(int w, int h);
void resize(int w, int h);
void bind();
void unbind();
void draw();
void createTexture(int texW, int texH, GLuint& texID);
float exposure;
float decay;
float density;
float weight;
float light_x;
float light_y;
int w;
int h;
int dw;
int dh;
GLuint fbo;
GLuint tex;
GLuint fx_tex;
GLuint depth_buffer;
GLuint vbo;
GLuint vao;
GLuint prog;
GLuint frag_shader;
GLuint vert_shader;
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment