contrib/brl/bbas/imesh/algo/imesh_render.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/imesh/algo/imesh_render.cxx
00002 #include "imesh_render.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_limits.h>
00007 #include <vcl_cassert.h>
00008 #include <imesh/algo/imesh_project.h>
00009 #include <imesh/imesh_operations.h>
00010 #include <vil/vil_bilin_interp.h>
00011 
00012 //: Render a textured triangle defined by its vertices
00013 // \p v1,v2,v3 are coordinates in the projected image (plus depth)
00014 // \p t1,t2,t3 are corresponding texture coordinates (in the unit square)
00015 void imesh_render_triangle_texture(const vgl_point_3d<double>& v1,
00016                                    const vgl_point_3d<double>& v2,
00017                                    const vgl_point_3d<double>& v3,
00018                                    const vgl_point_2d<double>& t1,
00019                                    const vgl_point_2d<double>& t2,
00020                                    const vgl_point_2d<double>& t3,
00021                                    const vil_image_view<vxl_byte>& texture,
00022                                    vil_image_view<vxl_byte>& image,
00023                                    vil_image_view<double>& depth_img)
00024 {
00025   assert(depth_img.ni() == image.ni());
00026   assert(depth_img.nj() == image.nj());
00027 
00028   unsigned tw = texture.ni();
00029   unsigned th = texture.nj();
00030   vnl_matrix_fixed<double,3,3> texmap =
00031       imesh_affine_map(vgl_point_2d<double>(v1.x(),v1.y()),
00032                        vgl_point_2d<double>(v2.x(),v2.y()),
00033                        vgl_point_2d<double>(v3.x(),v3.y()),
00034                        vgl_point_2d<double>(t1.x()*tw,(1-t1.y())*th),
00035                        vgl_point_2d<double>(t2.x()*tw,(1-t2.y())*th),
00036                        vgl_point_2d<double>(t3.x()*tw,(1-t3.y())*th));
00037 
00038   vgl_triangle_scan_iterator<double> tsi;
00039   tsi.a.x = v1.x();  tsi.a.y = v1.y();
00040   tsi.b.x = v2.x();  tsi.b.y = v2.y();
00041   tsi.c.x = v3.x();  tsi.c.y = v3.y();
00042   vgl_vector_3d<double> b1(v2.x()-v1.x(), v2.y()-v1.y(), v2.z()-v1.z());
00043   vgl_vector_3d<double> b2(v3.x()-v1.x(), v3.y()-v1.y(), v3.z()-v1.z());
00044   vgl_vector_3d<double> n = cross_product(b1,b2);
00045   double A = -n.x()/n.z();
00046   double B = -n.y()/n.z();
00047   double C = (v1.x()*n.x() + v1.y()*n.y() + v1.z()*n.z())/n.z();
00048   for (tsi.reset(); tsi.next(); ) {
00049     int y = tsi.scany();
00050     if (y<0 || y>=int(image.nj())) continue;
00051     int min_x = tsi.startx();
00052     int max_x = tsi.endx();
00053     if (min_x >= (int)image.ni() || max_x < 0)
00054       continue;
00055     if (min_x < 0) min_x = 0;
00056     if (max_x >= (int)image.ni()) max_x = image.ni()-1;
00057     double new_i = B*y+C;
00058     for (int x = min_x; x <= max_x; ++x) {
00059       double depth = new_i + A*x;
00060       if (depth < depth_img(x,y)) {
00061         depth_img(x,y) = depth;
00062         double tx = texmap[0][0]*x + texmap[0][1]*y + texmap[0][2];
00063         double ty = texmap[1][0]*x + texmap[1][1]*y + texmap[1][2];
00064         for (unsigned p=0; p<texture.nplanes(); ++p) {
00065           image(x,y,p) = (vxl_byte)vil_bilin_interp_safe(texture,tx,ty,p);
00066         }
00067       }
00068     }
00069   }
00070 }
00071 
00072 
00073 //: Render the mesh using the camera and a texture image
00074 //  A depth map is also computed and used for occlusion.
00075 //  Texture mapping uses interpolates from the texture image with no
00076 //  additional lighting calculations.
00077 void imesh_render_textured(const imesh_mesh& mesh,
00078                            const vpgl_proj_camera<double>& camera,
00079                            const vil_image_view<vxl_byte>& texture,
00080                            vil_image_view<vxl_byte>& image,
00081                            vil_image_view<double>& depth_img)
00082 {
00083   assert(mesh.vertices().dim() == 3);
00084   assert(mesh.has_tex_coords() == imesh_mesh::TEX_COORD_ON_VERT);
00085   const vcl_vector<vgl_point_2d<double> >& tex_coords = mesh.tex_coords();
00086 
00087   vcl_vector<vgl_point_2d<double> > verts2d;
00088   vcl_vector<double> depths;
00089   depth_img.fill(vcl_numeric_limits<double>::infinity());
00090   imesh_project_verts(mesh.vertices<3>(), camera, verts2d, depths);
00091   assert(tex_coords.size() == verts2d.size());
00092 
00093   const imesh_face_array_base& faces = mesh.faces();
00094   vcl_auto_ptr<imesh_regular_face_array<3> > tri_data;
00095   const imesh_regular_face_array<3>* tris;
00096   if (faces.regularity() != 3) {
00097     tri_data = imesh_triangulate(faces);
00098     tris = tri_data.get();
00099   }
00100   else {
00101     tris = static_cast<const imesh_regular_face_array<3>*>(&faces);
00102   }
00103 
00104   for (unsigned i=0; i<tris->size(); ++i) {
00105     const imesh_regular_face<3>& tri = (*tris)[i];
00106     const vgl_point_2d<double>& v1 = verts2d[tri[0]];
00107     const vgl_point_2d<double>& v2 = verts2d[tri[1]];
00108     const vgl_point_2d<double>& v3 = verts2d[tri[2]];
00109     const vgl_point_2d<double>& t1 = tex_coords[tri[0]];
00110     const vgl_point_2d<double>& t2 = tex_coords[tri[1]];
00111     const vgl_point_2d<double>& t3 = tex_coords[tri[2]];
00112 
00113     vgl_point_3d<double> p1(v1.x(),v1.y(),depths[tri[0]]);
00114     vgl_point_3d<double> p2(v2.x(),v2.y(),depths[tri[1]]);
00115     vgl_point_3d<double> p3(v3.x(),v3.y(),depths[tri[2]]);
00116     imesh_render_triangle_texture(p1,p2,p3,t1,t2,t3,texture,image,depth_img);
00117   }
00118 }