⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hemicube.cpp

📁 The goal of this project is to explore the idea of point-based radiosity, which is a shooting radio
💻 CPP
📖 第 1 页 / 共 3 页
字号:
  to figure out which scene elements are visible from each 
  face of the hemicube. Each color in the item buffer is
  treated as an identifier instead of a color.

*/
void HemiCube::debug_draw_item_buffer (void)
{
    glDrawPixels(m_center_pixel_width, 
		 m_center_pixel_height, 
		 GL_RGB, GL_UNSIGNED_BYTE,
		 m_center_item_buffer);
}


/*+-------------------------------------------------------------------
  HemiCube::render_buffers

  Set the camera to be at center of the hemicube.  

  Render the scene into 5 item buffers, once corresponding 
  to each side of the hemicube.
  
  Next, render the scene into 5 RC (rendering x cosine)
  buffers, one corresponding to each side of the hemicube.
  
  
*/
void HemiCube::render_buffers (const Scene& scene, 
			       const Point& camera_point,
			       const Vector& normal,
			       const Color& light_color
			       )
{
    Vector top_normal;
    Vector bottom_normal;

    // Take the normal of the top face to be the 
    // perpendicular to the normal, as calculated by
    // Vector::get_perpendicular_vector.
    normal.get_perpendicular_vector(top_normal);
    
    // The bottom normal is the negative of the top normal.
    bottom_normal.set(-top_normal.x(), 
		      -top_normal.y(),
		      -top_normal.z());

    // Compute the left normal by takig the cross product
    // of the normal with the top normal.
    Vector left_normal = normal * top_normal;

    // The right normal is the negation of left normal.
    Vector right_normal;
    right_normal.set(-left_normal.x(),
                     -left_normal.y(),
                     -left_normal.z());
    
    for (int side_index = 0; side_index < 5; side_index++)
    {
	HemiCubeSide which_side = (HemiCubeSide)side_index;

	const Vector* which_normal = NULL;
	const Vector* which_up = NULL;
	
	float frustum_bottom = 0.0f;
	float frustum_top = 1.0f;

	unsigned char* which_item_rgb_buffer = NULL;
	float* which_rc_buffer = NULL;
	float* which_item_depth_buffer = NULL;
	GLdouble* which_modelview_array = NULL;
	GLdouble* which_projection_array = NULL;
        int pixel_width = m_side_pixel_width;
        int pixel_height = m_side_pixel_height;

	switch(which_side)
	{
	case Center:
	    which_normal = &normal;
	    which_up = &top_normal;
	    frustum_bottom = -1.0f;
	    which_item_rgb_buffer = m_center_item_buffer;
	    which_item_depth_buffer = m_center_depth_buffer;
	    which_rc_buffer = m_center_rc_buffer;
	    which_modelview_array = m_center_modelview;
	    which_projection_array = m_center_projection;
	    pixel_width = m_center_pixel_width;
	    pixel_height = m_center_pixel_height;
	    break;

	case Left:
	    which_normal = &left_normal;
	    which_up = &normal;
	    which_item_rgb_buffer = m_left_item_buffer;
	    which_item_depth_buffer = m_left_depth_buffer;
	    which_rc_buffer = m_left_rc_buffer;
	    which_modelview_array = m_left_modelview;
	    which_projection_array = m_left_projection;
	    break;

	case Bottom:
	    which_normal = &bottom_normal;
	    which_up = &normal;
	    which_item_rgb_buffer = m_bottom_item_buffer;
	    which_item_depth_buffer = m_bottom_depth_buffer;
	    which_rc_buffer = m_bottom_rc_buffer;
	    which_modelview_array = m_bottom_modelview;
	    which_projection_array = m_bottom_projection;
	    break;

	case Right:
	    which_normal = &right_normal;
	    which_up = &normal;
	    which_item_rgb_buffer = m_right_item_buffer;
	    which_item_depth_buffer = m_right_depth_buffer;
	    which_rc_buffer = m_right_rc_buffer;
	    which_modelview_array = m_right_modelview;
	    which_projection_array = m_right_projection;
	    break;

	case Top:
	    which_normal = &top_normal;
	    which_up = &normal;
	    which_item_rgb_buffer = m_top_item_buffer;
	    which_item_depth_buffer = m_top_depth_buffer;
	    which_rc_buffer = m_top_rc_buffer;
	    which_modelview_array = m_top_modelview;
	    which_projection_array = m_top_projection;
	    break;
	}
	
	assert(which_normal != NULL);
	assert(which_up != NULL);
        assert(which_item_rgb_buffer != NULL);
        assert(which_item_depth_buffer != NULL);
	assert(which_rc_buffer != NULL);
	assert(which_modelview_array != NULL);
	assert(which_projection_array != NULL);
	assert(which_projection_array != which_modelview_array);

	// Restrict drawing to the desired buffer size
	glViewport(0, 0, pixel_width, pixel_height);
	this->render_one_item_buffer(scene, 
				     camera_point, 
				     *which_normal,
				     *which_up, 
				     frustum_bottom,
				     frustum_top);

	// Now get the depth and color buffers
	glReadPixels(0, 0, 
		     pixel_width,
		     pixel_height,
		     GL_RGB, 
		     GL_UNSIGNED_BYTE, 
		     which_item_rgb_buffer);

	// Restrict drawing to the desired buffer size
	glViewport(0, 0, pixel_width, pixel_height);
	this->render_one_lighted_scene_buffer(scene,
					      camera_point,
					      *which_normal,
					      *which_up,
                                              light_color,
					      frustum_bottom,
					      frustum_top, 
					      which_modelview_array,
					      which_projection_array);

	// Now get the color and depth buffers
	glReadPixels(0, 0, 
		     pixel_width,
		     pixel_height,
		     GL_RGB, 
		     GL_FLOAT,
		     which_rc_buffer);

	glReadPixels(0, 0, 
                     pixel_width,
                     pixel_height,
                     GL_DEPTH_COMPONENT, 
		     GL_FLOAT, 
		     which_item_depth_buffer);
        
        
        // Multiply the contents of which_rc_buffer
	// by the appropriate cosine map.
        GrayscaleTexture* which_texture = NULL;
	if (which_side == Center)
	{
            which_texture = m_center_cosine_texture;
        }
	else
	{
            which_texture = m_bottom_cosine_texture;
        }

        assert(pixel_width != -1);
        assert(pixel_height != -1);
        assert(which_rc_buffer != NULL);
        assert(which_texture != NULL);
	
        this->multiply_rc_buffer_by_cosine_texture(which_rc_buffer,
						   pixel_width, 
						   pixel_height,
						   which_texture);
	
    }
    
    // Hang on to the maximum splat value in all of the five
    // renderings.  This is done because some scaling might be
    // necessary during the reconstruction phase.
    float max_splat_value = this->find_max_rc_value();

    Splat::max_splat_value = 
	(max_splat_value > 0.0f ? 1.0f / max_splat_value : 0.0f);
}


/*+-------------------------------------------------------------------
  HemiCube::multiply_rc_buffer_by_cosine_texture
  
  This multiplies a single rc buffer by the specified map.  
  This function will be unnecssary once I figure out how to 
  get projective texture mapping to work.
  
*/
void HemiCube::multiply_rc_buffer_by_cosine_texture (float* which_rc_buffer, 
						     int pixel_width,
						     int pixel_height,
                                                     GrayscaleTexture* gs_tex
                                                     )
{
    assert(gs_tex != NULL);
    assert(which_rc_buffer != NULL);

    int pixel_x, pixel_y;
    int counter = 0;
    int cos_map_x = 0;
    int cos_map_y = 0;       
    
    // Get the mipmap that corresponds to pixel_width, pixel_height
    int mipmap_level = gs_tex->mipmap_level(pixel_width, pixel_height);

    float* cosine_texels = NULL;

    if (mipmap_level == -1)
    {
	throw HemiCubeException();
    }
    else
    {
	cosine_texels = new float[pixel_width * pixel_height];
	gs_tex->mipmap_texels(mipmap_level, cosine_texels);
    }        
    
    assert(cosine_texels != NULL);

    // The following block of code depends on the 
    // RC buffer being stored in row-major format.
    for (pixel_y = 0; pixel_y < pixel_height; pixel_y++)
    {
	for (pixel_x = 0; pixel_x < pixel_width; pixel_x++)
	{
	    unsigned int mipmap_offset = pixel_y * pixel_width + pixel_x;

	    float gray_val = cosine_texels[mipmap_offset];
	    
	    float r = which_rc_buffer[counter];
	    float g = which_rc_buffer[counter + 1];
	    float b = which_rc_buffer[counter + 2];
	    
	    which_rc_buffer[counter] = r * gray_val;
	    which_rc_buffer[counter + 1] = g * gray_val;
	    which_rc_buffer[counter + 2] = b * gray_val;
	    
  	    counter += m_components_per_pixel;
	}
    }
    
    if (cosine_texels)
    {
        delete [] cosine_texels;
        cosine_texels = NULL;
    }
}


/*+-------------------------------------------------------------------
  HemiCube::find_max_rc_value 

  Go through the five RC buffers in this hemicube and find the largest
  value.  This method should be invoked only after the diffuse scene
  is rendered to them, and after it is multiplied by the cosine
  texture.

  This method finds the maximum across all channels.  It does not find
  the max red, max green, max_blue, etc.

*/
float HemiCube::find_max_rc_value (void) const
{
    float max_val = 0.0f;

    for (int side_index = 0; side_index < 5; side_index++)
    {
	HemiCubeSide which_side = (HemiCubeSide)side_index;

	int pixel_width = m_side_pixel_width;
	int pixel_height = m_side_pixel_height;
	float* rc_buffer = NULL;
	switch(which_side)
	{
	case Center:
	    pixel_width = m_center_pixel_width;
	    pixel_height = m_center_pixel_height;
	    rc_buffer = m_center_rc_buffer;
	    break;

	case Left:
	    rc_buffer = m_left_rc_buffer;
	    break;

	case Right:
	    rc_buffer = m_right_rc_buffer;
	    break;

	case Bottom:
	    rc_buffer = m_bottom_rc_buffer;
	    break;

	case Top:
	    rc_buffer = m_top_rc_buffer;
	    break;
	}

	assert(rc_buffer != NULL);

	// We're actually comparing all channels, 
	// so adjust pixel_width and pixel_height 
	// so that we hit each element.
	int grid_size = m_components_per_pixel * pixel_width * pixel_height;

	for (int i = 0; i < grid_size; i++)
	{
	    if (rc_buffer[i] > max_val)
		max_val = rc_buffer[i];
	}
    }

    return max_val;
}



/*+-------------------------------------------------------------------
  HemiCube::render_one_item_buffer 

  Render the item buffer for the specified camera position,
  normal and up vector.  The scene is rendered into the 
  specified offscreen drawable. 
  
*/
void HemiCube::render_one_item_buffer (const Scene& scene,
				       const Point& camera_point,
				       const Vector& normal,
				       const Vector& up, 
				       float frustum_bottom,
				       float frustum_top)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Disable lighting and texturing
    glDisable(GL_LIGHTING);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);

    // Flat shading, and use the depth buffer
    glShadeModel(GL_FLAT);
    glEnable(GL_DEPTH_TEST);
    
    // Set the camera to be a the camera_point 
    Point look_at = camera_point + normal;

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    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());
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1.0, 1.0f, frustum_bottom, frustum_top, 1.0f, 100.0f);
    
    scene.draw_flat();
}


/*+-------------------------------------------------------------------
  HemiCube::render_one_lighted_scene_buffer (private method)

  Render the scene when it is diffuse lighted and smooth
  shaded.  The parameters passed to this method describe 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -