SceneRefract: Updates to compute refraction vectors through the front and back
of the object. This required adding a color target for the first pass so that
we can store the surface normals from the back side of the object. Still need
to determine whether or not to factor in the distance from the front to the
back of the object (else the distance map may not be needed and we may not need
the depth target in the first pass).
diff --git a/data/shaders/light-refract.frag b/data/shaders/light-refract.frag
index f7ae395..cc04071 100644
--- a/data/shaders/light-refract.frag
+++ b/data/shaders/light-refract.frag
@@ -1,24 +1,35 @@
uniform sampler2D DistanceMap;
+uniform sampler2D NormalMap;
+uniform sampler2D ImageMap;
varying vec3 vertex_normal;
varying vec4 vertex_position;
+varying vec4 MapCoord;
void main()
{
- const vec4 lightAmbient = vec4(0.1, 0.1, 0.1, 1.0);
const vec4 lightSpecular = vec4(0.8, 0.8, 0.8, 1.0);
- const vec4 matAmbient = vec4(0.2, 0.2, 0.2, 1.0);
const vec4 matSpecular = vec4(1.0, 1.0, 1.0, 1.0);
const float matShininess = 100.0;
- vec3 eye_direction = normalize(-vertex_position.xyz);
- vec3 light_direction = normalize(LightSourcePosition.xyz/LightSourcePosition.w -
- vertex_position.xyz/vertex_position.w);
+ const vec2 point_five = vec2(0.5);
+ // Need the normalized light direction and surface normal vectors to
+ // compute the refraction vector through the "front" surface of the object.
+ vec3 light_direction = normalize(vertex_position.xyz/vertex_position.w -
+ LightSourcePosition.xyz/LightSourcePosition.w);
vec3 normalized_normal = normalize(vertex_normal);
- vec3 reflection = reflect(-light_direction, normalized_normal);
+ vec3 front_refraction = refract(light_direction, normalized_normal, 1.5);
+ // Offset the base map coordinate by the refaction vector, and re-normalize
+ // to texture coordinate space [0, 1].
+ vec2 normcoord = (MapCoord.st + front_refraction.st + point_five) * point_five;
+ vec4 back_normal = texture2D(NormalMap, normcoord);
+ // Now refract again, using the minus normal from the lookup.
+ vec3 back_refraction = refract(front_refraction, -back_normal.xyz, 1.5);
+ vec2 imagecoord = (normcoord + back_refraction.st + point_five) * point_five;
+ vec4 texel = texture2D(ImageMap, imagecoord);
+ // Add in a specular component
+ vec3 reflection = reflect(light_direction, normalized_normal);
+ vec3 eye_direction = normalize(-vertex_position.xyz);
float specularTerm = pow(max(0.0, dot(reflection, eye_direction)), matShininess);
- float diffuseTerm = max(0.0, dot(normalized_normal, light_direction));
vec4 specular = (lightSpecular * matSpecular);
- vec4 ambient = (lightAmbient * matAmbient);
- vec4 diffuse = (LightColor * MaterialDiffuse);
- gl_FragColor = (specular * specularTerm) + ambient + (diffuse * diffuseTerm);
+ gl_FragColor = (specular * specularTerm) + texel;
}
diff --git a/data/shaders/light-refract.vert b/data/shaders/light-refract.vert
index 8a95ca7..9beeb9c 100644
--- a/data/shaders/light-refract.vert
+++ b/data/shaders/light-refract.vert
@@ -4,9 +4,11 @@
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 NormalMatrix;
uniform mat4 ModelViewMatrix;
+uniform mat4 LightMatrix;
varying vec3 vertex_normal;
varying vec4 vertex_position;
+varying vec4 MapCoord;
void main(void)
{
@@ -18,6 +20,9 @@
// Transform the current position to eye coordinates
vertex_position = ModelViewMatrix * current_position;
+ // Transform the current position for use as texture coordinates
+ MapCoord = LightMatrix * current_position;
+
// Transform the current position to clip coordinates
gl_Position = ModelViewProjectionMatrix * current_position;
}
diff --git a/src/scene-refract.cpp b/src/scene-refract.cpp
index b1d8dcc..aca59a8 100644
--- a/src/scene-refract.cpp
+++ b/src/scene-refract.cpp
@@ -33,7 +33,7 @@
using LibMatrix::vec4;
using LibMatrix::vec3;
-static const vec4 lightPosition(0.0f, 3.0f, 2.0f, 1.0f);
+static const vec4 lightPosition(1.0f, 1.0f, 2.0f, 1.0f);
//
// Public interfaces
@@ -193,20 +193,29 @@
return false;
}
- glGenTextures(1, &tex_);
- glBindTexture(GL_TEXTURE_2D, tex_);
+ glGenTextures(2, &tex_[0]);
+ glBindTexture(GL_TEXTURE_2D, tex_[DEPTH]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width_, height_, 0,
GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0);
+ glBindTexture(GL_TEXTURE_2D, tex_[COLOR]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &fbo_);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
- tex_, 0);
+ tex_[DEPTH], 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ tex_[COLOR], 0);
unsigned int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
Log::error("DepthRenderState::setup: glCheckFramebufferStatus failed (0x%x)\n", status);
@@ -223,8 +232,8 @@
program_.stop();
program_.release();
if (tex_) {
- glDeleteTextures(1, &tex_);
- tex_ = 0;
+ glDeleteTextures(2, &tex_[0]);
+ tex_[DEPTH] = tex_[COLOR] = 0;
}
if (fbo_) {
glDeleteFramebuffers(1, &fbo_);
@@ -239,17 +248,17 @@
program_["ModelViewProjectionMatrix"] = mvp;
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
- tex_, 0);
+ tex_[DEPTH], 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ tex_[COLOR], 0);
glViewport(0, 0, width_, height_);
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- glClear(GL_DEPTH_BUFFER_BIT);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
}
void DistanceRenderTarget::disable()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, canvas_width_, canvas_height_);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
bool
@@ -258,8 +267,8 @@
// Program object setup
static const string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/light-refract.vert");
static const string frg_shader_filename(GLMARK_DATA_PATH"/shaders/light-refract.frag");
- static const vec4 materialDiffuse(0.0f, 0.0f, 0.0f, 0.0f);
- static const vec4 lightColor(1.0, 1.0, 1.0, 1.0);
+ static const vec4 materialDiffuse(1.0f, 1.0f, 1.0f, 0.0f);
+ static const vec4 lightColor(0.4, 0.4, 0.4, 1.0);
ShaderSource vtx_source(vtx_shader_filename);
ShaderSource frg_source(frg_shader_filename);
@@ -344,7 +353,17 @@
fovy /= M_PI;
fovy *= 180.0;
float aspect(static_cast<float>(canvas_.width())/static_cast<float>(canvas_.height()));
- projection_.perspective(fovy, aspect, 2.0, 50.0);
+ projection_.perspective(fovy, aspect, 2.0, 2.0 + diameter);
+
+ // Set up the light matrix with a bias that will convert values
+ // in the range of [-1, 1] to [0, 1)], then add in the projection
+ // and the "look at" matrix from the light position.
+ light_ *= LibMatrix::Mat4::translate(0.5, 0.5, 0.5);
+ light_ *= LibMatrix::Mat4::scale(0.5, 0.5, 0.5);
+ light_ *= projection_.getCurrent();
+ light_ *= LibMatrix::Mat4::lookAt(lightPosition.x(), lightPosition.y(), lightPosition.z(),
+ 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0);
if (!depthTarget_.setup(canvas_.width(), canvas_.height())) {
Log::error("Failed to set up the render target for the depth pass\n");
@@ -385,6 +404,7 @@
modelview_.pop();
// Enable the depth render target with our transformation and render.
+ glCullFace(GL_FRONT);
depthTarget_.enable(mvp);
vector<GLint> attrib_locations;
attrib_locations.push_back(depthTarget_.program()["position"].location());
@@ -397,6 +417,7 @@
mesh_.render_array();
}
depthTarget_.disable();
+ glCullFace(GL_BACK);
// Ground rendering using the above generated texture...
//ground_.draw();
@@ -410,15 +431,23 @@
program_.start();
glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, texture_);
+ glBindTexture(GL_TEXTURE_2D, depthTarget_.depthTexture());
program_["DistanceMap"] = 0;
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, depthTarget_.colorTexture());
+ program_["NormalMap"] = 1;
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, texture_);
+ program_["ImageMap"] = 2;
+ // Load both the modelview*projection as well as the modelview matrix itself
program_["ModelViewProjectionMatrix"] = mvp;
-
+ program_["ModelViewMatrix"] = modelview_.getCurrent();
// Load the NormalMatrix uniform in the shader. The NormalMatrix is the
// inverse transpose of the model view matrix.
mat4 normal_matrix(modelview_.getCurrent());
normal_matrix.inverse().transpose();
program_["NormalMatrix"] = normal_matrix;
+ program_["LightMatrix"] = light_;
attrib_locations.clear();
attrib_locations.push_back(program_["position"].location());
attrib_locations.push_back(program_["normal"].location());
diff --git a/src/scene-refract.h b/src/scene-refract.h
index 2d61ab3..660678b 100644
--- a/src/scene-refract.h
+++ b/src/scene-refract.h
@@ -34,12 +34,17 @@
//
class DistanceRenderTarget
{
+ enum
+ {
+ DEPTH = 0,
+ COLOR
+ };
Program program_;
unsigned int canvas_width_;
unsigned int canvas_height_;
unsigned int width_;
unsigned int height_;
- unsigned int tex_;
+ unsigned int tex_[2];
unsigned int fbo_;
public:
DistanceRenderTarget() :
@@ -47,14 +52,17 @@
canvas_height_(0),
width_(0),
height_(0),
- tex_(0),
- fbo_(0) {}
+ fbo_(0)
+ {
+ tex_[DEPTH] = tex_[COLOR] = 0;
+ }
~DistanceRenderTarget() {}
bool setup(unsigned int width, unsigned int height);
void teardown();
void enable(const LibMatrix::mat4& mvp);
void disable();
- unsigned int texture() { return tex_; }
+ unsigned int depthTexture() { return tex_[DEPTH]; }
+ unsigned int colorTexture() { return tex_[COLOR]; }
Program& program() { return program_; }
};
@@ -65,6 +73,7 @@
Program program_;
LibMatrix::Stack4 modelview_;
LibMatrix::Stack4 projection_;
+ LibMatrix::mat4 light_;
Mesh mesh_;
LibMatrix::vec3 centerVec_;
bool orientModel_;