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

📄 scene.cpp

📁 The goal of this project is to explore the idea of point-based radiosity, which is a shooting radio
💻 CPP
📖 第 1 页 / 共 3 页
字号:

*/
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 + -