|
|
@@ -10,6 +10,7 @@
|
|
|
#include "ViewerData.h"
|
|
|
#include "gl.h"
|
|
|
#include "../quat_to_mat.h"
|
|
|
+#include "../null.h"
|
|
|
#include "../snap_to_fixed_up.h"
|
|
|
#include "../look_at.h"
|
|
|
#include "../frustum.h"
|
|
|
@@ -17,6 +18,8 @@
|
|
|
#include "../massmatrix.h"
|
|
|
#include "../barycenter.h"
|
|
|
#include "../PI.h"
|
|
|
+#include "report_gl_error.h"
|
|
|
+#include "read_pixels.h"
|
|
|
#include <Eigen/Geometry>
|
|
|
#include <iostream>
|
|
|
|
|
|
@@ -175,11 +178,33 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
|
|
|
GLint matcap_factori = glGetUniformLocation(data.meshgl.shader_mesh,"matcap_factor");
|
|
|
GLint double_sidedi = glGetUniformLocation(data.meshgl.shader_mesh,"double_sided");
|
|
|
|
|
|
+ const bool eff_is_directional_light = is_directional_light || is_shadow_mapping;
|
|
|
glUniform1f(specular_exponenti, data.shininess);
|
|
|
- glUniform3fv(light_position_eyei, 1, light_position.data());
|
|
|
+ if(eff_is_directional_light)
|
|
|
+ {
|
|
|
+ Eigen::Vector3f light_direction = light_position.normalized();
|
|
|
+ glUniform3fv(light_position_eyei, 1, light_direction.data());
|
|
|
+ }else
|
|
|
+ {
|
|
|
+ glUniform3fv(light_position_eyei, 1, light_position.data());
|
|
|
+ }
|
|
|
+ if(is_shadow_mapping)
|
|
|
+ {
|
|
|
+ glUniformMatrix4fv(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_view"), 1, GL_FALSE, shadow_view.data());
|
|
|
+ glUniformMatrix4fv(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_proj"), 1, GL_FALSE, shadow_proj.data());
|
|
|
+ glActiveTexture(GL_TEXTURE0+1);
|
|
|
+ glBindTexture(GL_TEXTURE_2D, shadow_depth_tex);
|
|
|
+ {
|
|
|
+ glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_tex"), 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
glUniform1f(lighting_factori, lighting_factor); // enables lighting
|
|
|
glUniform4f(fixed_colori, 0.0, 0.0, 0.0, 0.0);
|
|
|
|
|
|
+ glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"is_directional_light"),eff_is_directional_light);
|
|
|
+ glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"is_shadow_mapping"),is_shadow_mapping);
|
|
|
+ glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_pass"),false);
|
|
|
+
|
|
|
if (data.V.rows()>0)
|
|
|
{
|
|
|
// Render fill
|
|
|
@@ -252,6 +277,74 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
|
|
|
draw_labels(data, data.meshgl.custom_labels);
|
|
|
}
|
|
|
|
|
|
+IGL_INLINE void igl::opengl::ViewerCore::initialize_shadow_pass()
|
|
|
+{
|
|
|
+ // attach buffers
|
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, shadow_depth_fbo);
|
|
|
+ glBindRenderbuffer(GL_RENDERBUFFER, shadow_color_rbo);
|
|
|
+ // clear buffer
|
|
|
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
+ // In the libigl viewer setup, each mesh has its own shader program. This is
|
|
|
+ // kind of funny because they should all be the same, just different uniform
|
|
|
+ // values.
|
|
|
+ glViewport(0,0,shadow_width,shadow_height);
|
|
|
+ // Assumes light is directional
|
|
|
+ assert(is_directional_light);
|
|
|
+ Eigen::Vector3f camera_eye = light_position.normalized()*5;
|
|
|
+ Eigen::Vector3f camera_up = [&camera_eye]()
|
|
|
+ {
|
|
|
+ Eigen::Matrix<float,3,2> T;
|
|
|
+ igl::null(camera_eye.transpose().eval(),T);
|
|
|
+ return T.col(0);
|
|
|
+ }();
|
|
|
+ Eigen::Vector3f camera_center = this->camera_center;
|
|
|
+ // Same camera parameters except 2× field of view and reduced far plane
|
|
|
+ float camera_view_angle = 2*this->camera_view_angle;
|
|
|
+ float camera_dnear = this->camera_dnear;
|
|
|
+ float camera_dfar = this->camera_dfar;
|
|
|
+ Eigen::Quaternionf trackball_angle = this->trackball_angle;
|
|
|
+ float camera_zoom = 1;//this->camera_zoom;
|
|
|
+ float camera_base_zoom = this->camera_base_zoom;
|
|
|
+ Eigen::Vector3f camera_translation = this->camera_translation;
|
|
|
+ Eigen::Vector3f camera_base_translation = this->camera_base_translation;
|
|
|
+ camera_dfar = exp2( 0.5 * ( log2(camera_dnear) + log2(camera_dfar)));
|
|
|
+ igl::look_at( camera_eye, camera_center, camera_up, shadow_view);
|
|
|
+ shadow_view = shadow_view
|
|
|
+ * (trackball_angle * Eigen::Scaling(camera_zoom * camera_base_zoom)
|
|
|
+ * Eigen::Translation3f(camera_translation + camera_base_translation)).matrix();
|
|
|
+
|
|
|
+ float length = (camera_eye - camera_center).norm();
|
|
|
+ float h = tan(camera_view_angle/360.0 * igl::PI) * (length);
|
|
|
+ igl::ortho(-h*shadow_width/shadow_height, h*shadow_width/shadow_height, -h, h, camera_dnear, camera_dfar,shadow_proj);
|
|
|
+}
|
|
|
+
|
|
|
+IGL_INLINE void igl::opengl::ViewerCore::deinitialize_shadow_pass()
|
|
|
+{
|
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
|
+}
|
|
|
+
|
|
|
+IGL_INLINE void igl::opengl::ViewerCore::draw_shadow_pass(
|
|
|
+ ViewerData& data,
|
|
|
+ bool update_matrices)
|
|
|
+{
|
|
|
+ if (data.dirty)
|
|
|
+ {
|
|
|
+ data.updateGL(data, data.invert_normals, data.meshgl);
|
|
|
+ data.dirty = igl::opengl::MeshGL::DIRTY_NONE;
|
|
|
+ }
|
|
|
+ data.meshgl.bind_mesh();
|
|
|
+ // Send transformations to the GPU as if rendering from shadow point of view
|
|
|
+ GLint viewi = glGetUniformLocation(data.meshgl.shader_mesh,"view");
|
|
|
+ GLint proji = glGetUniformLocation(data.meshgl.shader_mesh,"proj");
|
|
|
+ glUniformMatrix4fv(viewi, 1, GL_FALSE, shadow_view.data());
|
|
|
+ glUniformMatrix4fv(proji, 1, GL_FALSE, shadow_proj.data());
|
|
|
+ glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_pass"),true);
|
|
|
+ data.meshgl.draw_mesh(true);
|
|
|
+ glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_pass"),false);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
IGL_INLINE void igl::opengl::ViewerCore::draw_buffer(
|
|
|
ViewerData& data,
|
|
|
bool update_matrices,
|
|
|
@@ -442,6 +535,11 @@ IGL_INLINE igl::opengl::ViewerCore::ViewerCore()
|
|
|
|
|
|
// Default lights settings
|
|
|
light_position << 0.0f, 0.3f, 0.0f;
|
|
|
+ is_directional_light = false;
|
|
|
+ is_shadow_mapping = false;
|
|
|
+ shadow_width = 2056;
|
|
|
+ shadow_height = 2056;
|
|
|
+
|
|
|
lighting_factor = 1.0f; //on
|
|
|
|
|
|
// Default trackball
|
|
|
@@ -472,8 +570,71 @@ IGL_INLINE igl::opengl::ViewerCore::ViewerCore()
|
|
|
|
|
|
IGL_INLINE void igl::opengl::ViewerCore::init()
|
|
|
{
|
|
|
+ delete_shadow_buffers();
|
|
|
+ generate_shadow_buffers();
|
|
|
}
|
|
|
|
|
|
IGL_INLINE void igl::opengl::ViewerCore::shut()
|
|
|
{
|
|
|
+ delete_shadow_buffers();
|
|
|
+}
|
|
|
+
|
|
|
+IGL_INLINE void igl::opengl::ViewerCore::delete_shadow_buffers()
|
|
|
+{
|
|
|
+ glDeleteTextures(1,&shadow_depth_tex);
|
|
|
+ glDeleteFramebuffers(1,&shadow_depth_fbo);
|
|
|
+ glDeleteRenderbuffers(1,&shadow_color_rbo);
|
|
|
}
|
|
|
+
|
|
|
+IGL_INLINE void igl::opengl::ViewerCore::generate_shadow_buffers()
|
|
|
+{
|
|
|
+ // Create a texture for writing the shadow map depth values into
|
|
|
+ {
|
|
|
+ glDeleteTextures(1,&shadow_depth_tex);
|
|
|
+ glGenTextures(1, &shadow_depth_tex);
|
|
|
+ glBindTexture(GL_TEXTURE_2D, shadow_depth_tex);
|
|
|
+ // Should this be using double/float precision?
|
|
|
+ glTexImage2D(
|
|
|
+ GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
|
|
|
+ shadow_width,
|
|
|
+ shadow_height,
|
|
|
+ 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
|
|
|
+ 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_BORDER);
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
|
|
+ glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, Eigen::Vector4f(1,1,1,1).data() );
|
|
|
+ glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
+ }
|
|
|
+ // Generate a framebuffer with depth attached to this texture and color
|
|
|
+ // attached to a render buffer object
|
|
|
+ glGenFramebuffers(1, &shadow_depth_fbo);
|
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, shadow_depth_fbo);
|
|
|
+ // Attach depth texture
|
|
|
+ glFramebufferTexture2D(
|
|
|
+ GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
|
|
|
+ shadow_depth_tex,0);
|
|
|
+ // Generate a render buffer to write colors into. Low precision we don't
|
|
|
+ // care about them. Is there a way to not write/compute them at? Probably
|
|
|
+ // just need to change fragment shader.
|
|
|
+ glGenRenderbuffers(1,&shadow_color_rbo);
|
|
|
+ glBindRenderbuffer(GL_RENDERBUFFER,shadow_color_rbo);
|
|
|
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, shadow_width, shadow_height);
|
|
|
+ // Attach color buffer
|
|
|
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
|
|
+ GL_RENDERBUFFER, shadow_color_rbo);
|
|
|
+ //Does the GPU support current FBO configuration?
|
|
|
+ GLenum status;
|
|
|
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
|
+ switch(status)
|
|
|
+ {
|
|
|
+ case GL_FRAMEBUFFER_COMPLETE:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ printf("[ViewerCore] Error: We failed to set up a good FBO: %d\n",status);
|
|
|
+ assert(false);
|
|
|
+ }
|
|
|
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
+}
|
|
|
+
|