📄 scene.cpp
字号:
*/
void SceneTriangle::add_splat (Splat& splat)
{
m_splats.append(splat);
}
/*+-------------------------------------------------------------------
SceneTriangle::accumulate_splats_by_hand
Each SceneTriangle has a set of splats that have to be accumulated
into the accumulation texture and the emission texture.
This can be done using gluProject and doing the add into the
textures by hand. It can also be done by OpenGL using
GL_POINTS. See SceneTriangle::accumulate_splats_by_gl_points
for an example of this.
*/
void SceneTriangle::accumulate_splats_by_hand (void)
{
// We have to have a valid OpenGL context
// for this to work. This isn't a logical
// necessity, it is an artifact of the implementation.
// Use an OffscreenDrawable object for this.
unsigned int num_splats = m_splats.num_elements();
if (num_splats == 0)
return;
int vp_width = m_accumulation_texture->width();
int vp_height = m_accumulation_texture->height();
Map_of<float> temp_red_accumulator(vp_width, vp_height);
Map_of<float> temp_green_accumulator(vp_width, vp_height);
Map_of<float> temp_blue_accumulator(vp_width, vp_height);
temp_red_accumulator.clear(0.0f);
temp_green_accumulator.clear(0.0f);
temp_blue_accumulator.clear(0.0f);
glPushMatrix();
// Set the viewport to be the same
// as the texture bounds.
// This will be used later with
// gluProject.
glViewport(0, 0, vp_width, vp_height);
unsigned int i = 0;
float emissive_sum = this->m_emissive_texture->get_texel_sum();
float accumulation_sum = this->m_accumulation_texture->get_texel_sum();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Situate the view point so that it is looking
Point camera_point = m_bbox_center + m_normal;
gluLookAt(camera_point.x(), camera_point.y(), camera_point.z(),
m_bbox_center.x(), m_bbox_center.y(), m_bbox_center.z(),
m_up.x(), m_up.y(), m_up.z());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// This isn't going to work for drawing the accumulation
// texture.
// gluOrtho2D(0, m_ortho_width, 0, m_ortho_height);
float half_width = m_ortho_width / 2.0f;
float half_height = m_ortho_height / 2.0f;
glOrtho(-half_width, half_width, -half_height, half_height, 0.0f, 20.0f);
GLdouble modelview[16];
GLdouble projection[16];
GLint viewport[4];
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);
GLdouble winx, winy, winz;
winx = winy = winz = 0.0;
for (i = 0; i < num_splats; i++)
{
const Splat& splat = m_splats.get(i);
// Use gluProject to figure out where the splat
// should go in the in the texture.
gluProject(splat.point.x(), splat.point.y(), splat.point.z(),
modelview, projection, viewport,
&winx, &winy, &winz);
int tex_x, tex_y;
tex_x = (int)winx;
tex_y = (int)winy;
float red_texel = temp_red_accumulator.get(tex_x, tex_y);
float green_texel = temp_green_accumulator.get(tex_x, tex_y);
float blue_texel = temp_blue_accumulator.get(tex_x, tex_y);
red_texel += splat.color.red();
green_texel += splat.color.green();
blue_texel += splat.color.blue();
temp_red_accumulator.set(red_texel, tex_x, tex_y);
temp_green_accumulator.set(green_texel, tex_x, tex_y);
temp_blue_accumulator.set(blue_texel, tex_x, tex_y);
}
// Now set these pixels in the accumulation and emission textures.
unsigned int u, v;
unsigned int tex_width = m_emissive_texture->width();
unsigned int tex_height = m_emissive_texture->height();
assert(tex_width == temp_red_accumulator.width());
assert(tex_width == temp_green_accumulator.width());
assert(tex_width == temp_blue_accumulator.width());
assert(tex_height == temp_red_accumulator.height());
assert(tex_height == temp_green_accumulator.height());
assert(tex_height == temp_blue_accumulator.height());
Color texel_color;
for (u = 0; u < tex_width; u++)
{
for (v = 0; v < tex_height; v++)
{
float red_texel = temp_red_accumulator.get(u, v);
float green_texel = temp_green_accumulator.get(u, v);
float blue_texel = temp_blue_accumulator.get(u, v);
// Clamp at one
// red_texel = (red_texel > 1.0f ? 1.0f : red_texel);
// green_texel = (green_texel > 1.0f ? 1.0f : green_texel);
// blue_texel = (blue_texel > 1.0f ? 1.0f : blue_texel);
assert(red_texel >= 0.0f);
assert(green_texel >= 0.0f);
assert(blue_texel >= 0.0f);
texel_color.set(red_texel, green_texel, blue_texel);
m_emissive_texture->add(texel_color, u, v, false);
// Don't reset OpenGL's idea of this texture until later
m_accumulation_texture->add(texel_color, u, v, false);
}
}
accumulation_sum = m_accumulation_texture->get_texel_sum();
emissive_sum = m_emissive_texture->get_texel_sum();
m_accumulation_texture->tell_opengl();
m_emissive_texture->tell_opengl();
glPopMatrix();
}
/*+-------------------------------------------------------------------
SceneTriangle::accumulate_splats_by_gl_points
Use GL_POINTS to render into the scene and then read back the frame
buffer and set the textures based on this. There are currently some
fundamental problems with this, such as what to do if there
are many points to be drawn, but each one (or most) are less than
the color channel resolution (e.g. < 1/256). This leads
to not as much energy being accumulated as one would expect.
*/
void SceneTriangle::accumulate_splats_by_gl_points (void)
{
GLenum err = GL_NO_ERROR;
GLubyte* error_string = NULL;
int vp_width = m_accumulation_texture->width();
int vp_height = m_accumulation_texture->height();
glViewport(0, 0, vp_width, vp_height);
unsigned int num_splats = m_splats.num_elements();
unsigned int i = 0;
// Do we need an offscreen drawable for this?
// Maybe one that is the same resolution as the
// accumulation texture ?
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // | GL_ACCUM_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
// Blending is needed to get the accumulation texture.
glEnable(GL_BLEND);
// Use 1,1 as the blend func
glBlendFunc(GL_ONE, GL_ONE);
// Depth testing has to be disabled so that the splats
// add instead of replace each other.
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
// Render the triangle with its accumulation
// texture.
// Find the bounding box for this triangle
// render into it with an orthographic projection
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Situate the view point so that it is looking
Point camera_point = m_bbox_center + m_normal;
gluLookAt(camera_point.x(), camera_point.y(), camera_point.z(),
m_bbox_center.x(), m_bbox_center.y(), m_bbox_center.z(),
m_up.x(), m_up.y(), m_up.z());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// This isn't going to work for drawing the accumulation
// texture.
// gluOrtho2D(0, m_ortho_width, 0, m_ortho_height);
float half_width = m_ortho_width / 2.0f;
float half_height = m_ortho_height / 2.0f;
glOrtho(-half_width, half_width, -half_height, half_height, 0.0f, 20.0f);
float msv = Splat::max_splat_value;
// Now divide by max_splat_value using the accumulation buffer
if (msv > 0.0f)
{
glBegin(GL_POINTS);
for (i = 0; i < num_splats; i++)
{
const Splat& splat = m_splats.get(i);
float r = msv * splat.color.r();
float g = msv * splat.color.g();
float b = msv * splat.color.b();
float a = msv * splat.color.a();
glColor4f(r, g, b, a);
glVertex3f(splat.point.x(), splat.point.y(), splat.point.z());
}
glEnd();
glFinish();
float debug_factor = 1.0f / msv;
// glAccum(GL_LOAD, 1.0f);
// glAccum(GL_RETURN, 1.0f / msv);
}
// Now draw with the accumulation texture
this->draw_with_accumulation_texture();
// Now read back the frame buffer, and set the SceneTexture to
// be this.
float* frame_buffer_pixels = new float [4 * vp_width * vp_height];
assert(frame_buffer_pixels != NULL);
glReadPixels(0, 0, vp_width, vp_height, GL_RGBA, GL_FLOAT,
frame_buffer_pixels);
for (i = 0; i < (unsigned int)vp_width; i++)
{
for (int j = 0; j < vp_height; j++)
{
unsigned int offset = 4 * (j * vp_width + i) + 3;
frame_buffer_pixels[offset] = 1.0f;
}
}
err = glGetError();
const GLubyte* str = gluErrorString(err);
assert(err == 0);
// Now set these pixels in the accumulation and emission textures.
this->m_emissive_texture->set_texels(frame_buffer_pixels, 4 * vp_width * vp_height);
this->m_accumulation_texture->set_texels(frame_buffer_pixels, 4 * vp_width * vp_height);
delete [] frame_buffer_pixels;
frame_buffer_pixels = NULL;
// Set the blend functions back to one and zero.
glBlendFunc(GL_ONE, GL_ZERO);
}
/*+-------------------------------------------------------------------
SceneTriangle::accumulate_splats (public method)
Go through the set of splats and render them into the
accumulation texture and emission texture.
This method decides whether to accumulate by hand
(i.e. in software) or by using GL points.
*/
void SceneTriangle::accumulate_splats (bool use_gl_points)
{
if (use_gl_points)
this->accumulate_splats_by_gl_points();
else
this->accumulate_splats_by_hand();
}
/*+-------------------------------------------------------------------
SceneTriangle::subtract_emissive_texel
Subtract a texel from the emissive texture associated with this
SceneTriangle object. This is used to subtract the texel that was
just used as an emitter in the radiosity step.
*/
void SceneTriangle::subtract_emissive_texel (const Color& light_color,
int u, int v)
{
assert(m_emissive_texture != NULL);
m_emissive_texture->subtract(light_color, u, v);
}
/*+-------------------------------------------------------------------
SceneTriangle::item_rgb_to_id (static method)
Given an RGB value from the item buffer, compute the
id for that SceneTriangle. This is used to reconstruct
the image given the item buffer.
*/
unsigned int SceneTriangle::item_rgb_to_id (GLubyte r, GLubyte g, GLubyte b)
{
int index = 0;
index = r;
index |= (g << 8);
index |= (b << 16);
return index;
}
/*+-------------------------------------------------------------------
SceneTriangle::debug_draw_splats
Debugging method to draw the splats (reprojected points)
associated with this SceneTriangle object. This is useful
to see how the position of the hemicube is affects where
the reprojected points land.
*/
void SceneTriangle::debug_draw_splats (void) const
{
unsigned int num_splats = m_splats.num_elements();
glBegin(GL_POINTS);
glColor3f(1.0f, 0.0f, 0.0f);
for (unsigned int i = 0; i < num_splats; i++)
{
const Splat& splat = m_splats.get(i);
glVertex3f(splat.point.x(), splat.point.y(), splat.point.z());
}
glEnd();
glFinish();
}
/*+-------------------------------------------------------------------
Scene::Scene
Scene default constructor. This doesn't do anything because
the scene is actually initialized in Scene::load_simple_scene.
*/
Scene::Scene (void)
{
}
/*+-------------------------------------------------------------------
Scene::~Scene
Scene destructor. Go through and delete all of the SceneTriangle
objects that are aggregated
*/
Scene::~Scene (void)
{
unsigned int num_elements = this->m_scene_triangles.num_elements();
for (unsigned int i = 0; i < num_elements; i++)
{
SceneTriangle* element = this->m_scene_triangles.get(i);
delete element;
element = NULL;
}
}
/*+-------------------------------------------------------------------
Scene::draw
This is used for debugging.
*/
void Scene::draw (void) const
{
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glDisable(GL_LIGHTING);
unsigned int num_scene_triangles = m_scene_triangles.num_elements();
for (unsigned int i = 0; i < num_scene_triangles; i++)
{
SceneTriangle* element = m_scene_triangles.get(i);
element->draw();
}
}
/*+-------------------------------------------------------------------
Scene::draw_flat
This is used to create the item buffer. It renders the scene
with flat shading and no lighting.
*/
void Scene::draw_flat (void) const
{
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
// Now render the whole scene
unsigned int num_scene_triangles = m_scene_triangles.num_elements();
for (unsigned int index = 0; index < num_scene_triangles; index++)
{
GLbyte r, g, b;
SceneTriangle* element = m_scene_triangles.get(index);
index_to_color(element->m_element_index, r, g, b);
glColor3b(r, g, b);
element->draw_flat();
}
}
/*+-------------------------------------------------------------------
Scene::draw_diffuse_shaded
This method is used to create the rc buffers for each
side of the hemicube.
*/
void Scene::draw_diffuse_shaded (void) const
{
// Now render the whole scene
unsigned int num_scene_triangles = m_scene_triangles.num_elements();
for (unsigned int index = 0; index < num_scene_triangles; index++)
{
SceneTriangle* element = m_scene_triangles.get(index);
element->draw_diffuse_shaded();
}
}
/*+-------------------------------------------------------------------
Scene::draw_with_accumulation_textures
This is used to display the results of reconstructing the
accumulation textures.
*/
void Scene::draw_with_accumulation_textures (void)
{
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
unsigned int num_triangles = m_scene_triangles.num_elements();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -