📄 hemicube.cpp
字号:
properties for the scene to be rendered.
Parameters:
scene - The Scene object to be rendered.
camera_point - The position of the camera. This is the center
of the HemiCube.
normal - The normal vector, which is perpendicular to the
center face of the hemicube. This is the same as the normal
vector to the SceneTriangle where the HemiCube is currently
situated.
up - The vector "up" vector for orienting the camera.
light_color - The RGB color of the light to be placed
at the center of the HemiCube.
frustum_bottom - A floating point value describing the
frustum bottom to be passed to glFrustum. This is -1.0
for the center face of the hemicube and 0.0 for the
side faces, although we shouldn't depend on this.
frustum_top - A floating point value that specifies the
top of the frustum to be passed to glFrustum. This
is currently always 1.0, but we shouldn't depend on
this either.
Note: The left side of the frustum is always at -1.0f
and the right side of the frustum is always at 1.0f;
modelview_matrix - Pointer to an array of 16 doubles. This is used
to store the current modelview matrix (current when the scene is
rendered). We need to get the modelview matrix because it
is used later in the reconstruction phase as a parameter to
gluUnProject.
projection_matrix - Same as the modelview matrix parameter except
that this is for the projection matrix. Likewise, this is used
later during reconstruction as a parameter for gluUnProject.
*/
void HemiCube::render_one_lighted_scene_buffer (const Scene& scene,
const Point& camera_point,
const Vector& normal,
const Vector& up,
const Color& light_color,
float frustum_bottom,
float frustum_top,
GLdouble* modelview_matrix,
GLdouble* projection_matrix)
{
assert(modelview_matrix != NULL);
assert(projection_matrix != NULL);
// This is a positional light, so the w component must
// be 1.0f.
GLfloat light_origin[] = { 0.0f, 0.0f, 0.0f, 1.0f };
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// We need diffuse lighting, so enable lighting
// and light 0.
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glShadeModel(GL_SMOOTH);
glDisable(GL_TEXTURE_2D);
// Set the camera to be a the camera_point
Point look_at = camera_point + normal;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Set the light position to be the origin, so that it
// is at the lens of the camera.
glLightfv(GL_LIGHT0, GL_POSITION, light_origin);
gluLookAt(camera_point.x(), camera_point.y(), camera_point.z(),
look_at.x(), look_at.y(), look_at.z(),
up.x(), up.y(), up.z());
// Set the lighting parameters
GLfloat light_color_vec[4];
light_color.to_float_array(light_color_vec, 4);
GLfloat no_light_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color_vec);
glLightfv(GL_LIGHT0, GL_AMBIENT, no_light_color);
glLightfv(GL_LIGHT0, GL_SPECULAR, no_light_color);
// Do I need to adjust constant attenuation?
// 3.14159f
// The quadratic attenuation is supposed to be pi,
// but this value is too large, so nothing gets drawn.
// Maybe I have to
// take the size of the scene into account to properly
// set this. For now, just use pi/10 as the quadratic
// attenuation coefficient.
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.3f);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0f);
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0f);
GLenum err = glGetError();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0f, frustum_bottom, frustum_top, 1.0f, 100.0f);
glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix);
glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix);
scene.draw_diffuse_shaded();
// Put the quadratic attenuation of light 0 back to zero,
// which is the default state. I'm sure that if i don't
// do this here, then I'll forget and it will look weird
// later.
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0f);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0f);
}
/*+-------------------------------------------------------------------
HemiCube::clear_item_buffers
Set all of the item buffers, both for RGB data and for
depth, to zero.
*/
void HemiCube::clear_item_buffers (void)
{
memset(m_center_depth_buffer, 0,
m_center_pixel_width * m_center_pixel_width * sizeof(float));
size_t side_depth_buffer_size =
m_side_pixel_width * m_side_pixel_height * sizeof(float);
memset(m_left_depth_buffer, 0, side_depth_buffer_size);
memset(m_bottom_depth_buffer, 0, side_depth_buffer_size);
memset(m_right_depth_buffer, 0, side_depth_buffer_size);
memset(m_top_depth_buffer, 0, side_depth_buffer_size);
size_t center_rgb_buffer_size =
m_components_per_pixel * m_center_pixel_width * m_center_pixel_height;
memset(m_center_item_buffer, 0, center_rgb_buffer_size);
size_t side_rgb_buffer_size =
m_components_per_pixel * m_side_pixel_width * m_side_pixel_height;
memset(m_left_item_buffer, 0, side_rgb_buffer_size);
memset(m_bottom_item_buffer, 0, side_rgb_buffer_size);
memset(m_right_item_buffer, 0, side_rgb_buffer_size);
memset(m_top_item_buffer, 0, side_rgb_buffer_size);
}
/*+-------------------------------------------------------------------
HemiCube::clear_rc_buffers
Set the contents of the RC buffers to zero.
*/
void HemiCube::clear_rc_buffers (void)
{
size_t center_rgb_buffer_size =
m_components_per_pixel * m_center_pixel_width * m_center_pixel_height * sizeof(float);
size_t side_rgb_buffer_size =
m_components_per_pixel * m_side_pixel_width * m_side_pixel_height * sizeof(float);
memset(m_center_rc_buffer, 0, center_rgb_buffer_size);
memset(m_left_rc_buffer, 0, side_rgb_buffer_size);
memset(m_bottom_rc_buffer, 0, side_rgb_buffer_size);
memset(m_right_rc_buffer, 0, side_rgb_buffer_size);
memset(m_top_rc_buffer, 0, side_rgb_buffer_size);
}
/*+-------------------------------------------------------------------
HemiCube::reconstruct
This method takes the item buffer, the depth buffer, and the
RC buffer, and computes points in 3D from them using gluUnProject.
These points and their corresponding colors are then stored
with the triangle that they correspond to.
These splats are later rendered onto the scenes textures
in software or using glBegin(GL_POINTS), etc.
*/
void HemiCube::reconstruct (Scene& scene)
{
for (int side_index = 0; side_index < 5; side_index++)
{
HemiCubeSide which_side = (HemiCubeSide)side_index;
float* which_depth_buffer = NULL;
float* which_rc_buffer = NULL;
unsigned char* which_item_buffer = NULL;
GLdouble* which_projection_matrix = NULL;
GLdouble* which_modelview_matrix = NULL;
int pixel_width = -1;
int pixel_height = -1;
float area = 2.0f;
// Set various parameters to reconstruct
// each side. The code to do each side
// is very very similar, so it makes sense to
// set up the parameters for the rendering
// in the following switch statement, and
// then invoke the reconstruction method
// on one side.
switch(which_side)
{
case Center:
which_depth_buffer = m_center_depth_buffer;
which_rc_buffer = m_center_rc_buffer;
which_item_buffer = m_center_item_buffer;
which_projection_matrix = m_center_projection;
which_modelview_matrix = m_center_modelview;
pixel_width = m_center_pixel_width;
pixel_height = m_center_pixel_height;
area = 4.0f;
break;
case Left:
which_depth_buffer = m_left_depth_buffer;
which_rc_buffer = m_left_rc_buffer;
which_item_buffer = m_left_item_buffer;
which_projection_matrix = m_left_projection;
which_modelview_matrix = m_left_modelview;
pixel_width = m_side_pixel_width;
pixel_height = m_side_pixel_height;
break;
case Bottom:
which_depth_buffer = m_bottom_depth_buffer;
which_rc_buffer = m_bottom_rc_buffer;
which_item_buffer = m_bottom_item_buffer;
which_projection_matrix = m_bottom_projection;
which_modelview_matrix = m_bottom_modelview;
pixel_width = m_side_pixel_width;
pixel_height = m_side_pixel_height;
break;
case Right:
which_depth_buffer = m_right_depth_buffer;
which_rc_buffer = m_right_rc_buffer;
which_item_buffer = m_right_item_buffer;
which_projection_matrix = m_right_projection;
which_modelview_matrix = m_right_modelview;
pixel_width = m_side_pixel_width;
pixel_height = m_side_pixel_height;
break;
case Top:
which_depth_buffer = m_top_depth_buffer;
which_rc_buffer = m_top_rc_buffer;
which_item_buffer = m_top_item_buffer;
which_projection_matrix = m_top_projection;
which_modelview_matrix = m_top_modelview;
pixel_width = m_side_pixel_width;
pixel_height = m_side_pixel_height;
break;
}
// Assert that the needed paramters to
// reconstruct one side have all been set.
// This isn't completely sufficient to
// ensure that everything has been set up
// properly, but it's better than nothing.
assert(which_depth_buffer != NULL);
assert(which_rc_buffer != NULL);
assert(which_item_buffer != NULL);
assert(which_projection_matrix != NULL);
assert(which_modelview_matrix != NULL);
assert(pixel_width != -1);
assert(pixel_height != -1);
this->reconstruct_one_side(scene,
which_rc_buffer,
which_depth_buffer,
which_item_buffer,
pixel_width,
pixel_height,
area,
which_modelview_matrix,
which_projection_matrix);
}
}
/*+-------------------------------------------------------------------
HemiCube::reconstruct_one_side
For one side of the HemiCube go through the item buffer,
the depth buffer, and the RC buffer (RC = diffuse rendering * cosine)
and figure out which reprojected points belong to which scene
elements.
*/
void HemiCube::reconstruct_one_side (Scene& scene,
float* rc_buffer,
float* depth_buffer,
unsigned char* item_buffer,
int pixel_width,
int pixel_height,
float area,
GLdouble* modelview_matrix,
GLdouble* projection_matrix)
{
SceneTriangle* tri = NULL;
GLint viewport[] = { 0, 0, pixel_width, pixel_height};
// Go through the center item buffer
for (int pixel_y = 0; pixel_y < pixel_height; pixel_y++)
{
for (int pixel_x = 0; pixel_x < pixel_width; pixel_x++)
{
// Get the element from the item buffer and
// get an id for it.
// Use (r, g, b) to get a SceneTriangle out.
unsigned int depth_offset =
(pixel_y * pixel_width + pixel_x);
unsigned int item_offset = 3 * depth_offset;
unsigned char item_r = item_buffer[item_offset];
unsigned char item_g = item_buffer[item_offset + 1];
unsigned char item_b = item_buffer[item_offset + 2];
float depth = depth_buffer[depth_offset];
unsigned int rc_offset = item_offset;
float rc_red = rc_buffer[rc_offset];
float rc_green = rc_buffer[rc_offset + 1];
float rc_blue = rc_buffer[rc_offset + 2];
GLdouble objx, objy, objz;
unsigned int tri_id =
SceneTriangle::item_rgb_to_id(item_r, item_g, item_b);
if ((tri == NULL) ||
(tri->id() != tri_id))
{
tri = scene.item_rgb_to_triangle(item_r, item_g, item_b);
}
if (item_r != 0 && item_g != 0 && item_b != 0)
{
assert(tri != NULL);
}
if (tri && (depth < 1.0f) && (depth > 0.0f))
{
gluUnProject(pixel_x + 0.5, pixel_y + 0.5,
depth,
modelview_matrix,
projection_matrix,
viewport,
&objx, &objy, &objz);
// At this point we have a point and a SceneTriangle
// onto which this should be drawn. Next comes
// reconstruction. We can take advantage of coherence
// since adjacent pixels are likely to map to the same
// SceneTriangle.
Splat splat;
// Multiplying by 1 / (res)^2 is the correct thing
// to do.
float res_factor = area / float(pixel_width * pixel_height);
float factor = 100.0f * res_factor;
splat.color = Color(factor * rc_red,
factor * rc_green,
factor * rc_blue);
splat.point = Point((float)objx, (float)objy,(float)objz);
tri->add_splat(splat);
}
}
}
// For this side of the hemicube, all of the splats have
// been accumulated into the scene. Maybe now is the
// time to do the reconstruction.
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -