1) added iterator based traversal to 3D-DDR

2) modified balloon to use iterators
3) added "support" weight interpolator
This commit is contained in:
Paolo Cignoni cignoni 2010-09-14 17:04:29 +00:00
parent 6ace2ea140
commit 2556d779ab
5 changed files with 184 additions and 20 deletions

View File

@ -53,21 +53,34 @@ void Balloon::init( int gridsize, int gridpad ){
vol.band.reserve(5*surf.fn);
vol.updateSurfaceCorrespondence( surf, gridAccell, 2*vol.getDelta() );
}
bool Balloon::initializeField(){
//--- Setup the interpolation system
// if we fail, signal the failure to the caller
// Lower levels of omega might cause overshoothing problems
// float OMEGA = 1e3; // 1e8
float OMEGA = 1e8; // 1e8
LAPLACIAN type = COTANGENT; // COMBINATORIAL
bool op_succeed = finterp.Init( &surf, 1, type );
bool op_succeed = finterp.Init( &surf, 1, type );
if( !op_succeed ){
finterp.ColorizeIllConditioned( type );
return false;
}
float OMEGA_VERTEX = 1e-1;
float OMEGA_DATA = 1e-1;
winterp.Init( &surf, 1, type );
if( !op_succeed ){
winterp.ColorizeIllConditioned( type );
return false;
}
// Shared data
enum INITMODE {BIFACEINTERSECTIONS, FACEINTERSECTIONS, BOXINTERSECTIONS} mode;
// mode = BIFACEINTERSECTIONS;
mode = BIFACEINTERSECTIONS;
const float ONETHIRD = 1.0f/3.0f;
float t,u,v; // Ray-Triangle intersection parameters
@ -87,7 +100,9 @@ bool Balloon::initializeField(){
f.C() = ( rays.size()>0 ) ? Color4b(255,0,0,255) : Color4b(255,255,255,255);
}
qDebug() << "WARNING: test-mode only, per vertex field not updated!!";
}
}
// Each intersecting ray gives a contribution on the face to each of the
// face vertices according to the barycentric weights
else if( mode == FACEINTERSECTIONS ){
this->rm ^= SURF_VCOLOR;
this->rm |= SURF_FCOLOR;
@ -102,12 +117,13 @@ bool Balloon::initializeField(){
f.Q() = 0; // initialize
Point3f fcenter = f.P(0) + f.P(1) + f.P(2);
fcenter = myscale( fcenter, ONETHIRD );
gridAccell.pos2off( fcenter, off );
PointerVector& prays = gridAccell.Val(off[0], off[1], off[2]);
// Each intersecting ray gives a contribution on the face to each of the
// face vertices according to the barycentric weights
for(unsigned int i=0; i<prays.size(); i++)
if( vcg::IntersectionRayTriangle<float>(prays[i]->ray, f.P(0), f.P(1), f.P(2), t, u, v) ){
// NEW/OLD ITERATOR
// gridAccell.pos2off( fcenter, off );
// PointerVector& prays = gridAccell.Val(off[0], off[1], off[2]);
// for(unsigned int i=0; i<prays.size(); i++){ Ray3f& ray = prays[i]->ray;
for(gridAccell.iter.first(fcenter); !gridAccell.iter.isDone(); gridAccell.iter.next()){
Ray3f& ray = gridAccell.iter.currentItem().ray;
if( vcg::IntersectionRayTriangle<float>(ray, f.P(0), f.P(1), f.P(2), t, u, v) ){
// Color the faces, if more than one, take average
tot_w[ tri::Index(surf,f) ]++;
f.Q() += t; // normalize with tot_w after
@ -117,6 +133,7 @@ bool Balloon::initializeField(){
finterp.AddConstraint( tri::Index(surf,f.V(1)), OMEGA*(u), t );
finterp.AddConstraint( tri::Index(surf,f.V(2)), OMEGA*(v), t );
}
}
}
//--- Normalize in case there is more than 1 ray per-face
@ -162,8 +179,13 @@ bool Balloon::initializeField(){
// We check each of the possibly intersecting rays and we associate this face
// with him if and only if this face is the closest to it. Note that we study
// the values of t,u,v directly as a t<0 is accepted as intersecting.
for(unsigned int i=0; i<prays.size(); i++){
Line3<float> line(prays[i]->ray.Origin(), prays[i]->ray.Direction());
for(gridAccell.iter.first(f); !gridAccell.iter.isDone(); gridAccell.iter.next()){
// for(gridAccell.iter.first(fcenter); !gridAccell.iter.isDone(); gridAccell.iter.next()){
PokingRay& pray = gridAccell.iter.currentItem();
Line3<float> line(pray.ray.Origin(), pray.ray.Direction());
// for(unsigned int i=0; i<prays.size(); i++){
// Line3<float> line(prays[i]->ray.Origin(), prays[i]->ray.Direction());
// If the ray falls within the domain of the face
if( IntersectionLineTriangle(line, f.P(0), f.P(1), f.P(2), t, u, v) ){
@ -179,14 +201,18 @@ bool Balloon::initializeField(){
// If no face was associated with this ray or this face is closer
// than the one that I stored previously
if( prays[i]->f==NULL || fabs(t)<fabs(prays[i]->t) ){
prays[i]->f=&f;
prays[i]->t=t;
if( pray.f==NULL || fabs(t)<fabs(pray.t) ){
pray.f=&f;
pray.t=t;
}
}
}
}
//--- Add constraints on vertexes of balloon
for(CMeshO::VertexIterator vi=surf.vert.begin();vi!=surf.vert.end();vi++)
winterp.AddConstraint( tri::Index(surf,*vi), OMEGA_VERTEX, 0 );
// Now we scan through the rays, we visit the "best" corresponding face and we
// set a constraint on this face. Also we modify the color of the face so that
// an approximation can be visualized
@ -217,6 +243,12 @@ bool Balloon::initializeField(){
finterp.AddConstraint( tri::Index(surf,f.V(0)), OMEGA*(1-u-v), t );
finterp.AddConstraint( tri::Index(surf,f.V(1)), OMEGA*(u), t );
finterp.AddConstraint( tri::Index(surf,f.V(2)), OMEGA*(v), t );
//--- And for the second interpolator
winterp.AddConstraint( tri::Index(surf,f.V(0)), OMEGA_DATA*(1-u-v), 1 );
winterp.AddConstraint( tri::Index(surf,f.V(1)), OMEGA_DATA*(u), 1 );
winterp.AddConstraint( tri::Index(surf,f.V(2)), OMEGA_DATA*(v), 1 );
assert( u>=0 && u<=1 && v>=0 && v<=1 );
}
@ -236,11 +268,14 @@ void Balloon::interpolateField(){
surf.vert.QualityEnabled = true;
//--- Interpolate the field
finterp.SolveInQuality();
// finterp.SolveInQuality();
//--- Interpolate the field
winterp.SolveInQuality();
//--- Transfer vertex quality to surface
rm &= ~SURF_FCOLOR; // disable face colors
rm |= SURF_VCOLOR; // enable vertex colors
rm |= SURF_VCOLOR; // enable vertex colors
Histogram<float> H;
tri::Stat<CMeshO>::ComputePerVertexQualityHistogram(surf,H);
tri::UpdateColor<CMeshO>::VertexQualityRamp(surf,H.Percentile(0.0f),H.Percentile(1.0f));

View File

@ -38,6 +38,8 @@ public:
GridAccell gridAccell;
/// Scalar field interpolator (one constraint per poking ray)
FieldInterpolator finterp;
/// How close am I to the data? (1: close 0: far)
FieldInterpolator winterp;
/// Smoothing interpolator (one constraint per vertex)
FieldInterpolator sinterp;
@ -49,7 +51,6 @@ public:
/// Constructor: set default render mode
Balloon( CMeshO& _cloud ) : cloud( _cloud ){}
//--- Logic (if failed, return != 0)
void init(int gridsize, int gridpad);
bool initializeField();

View File

@ -193,7 +193,7 @@ void FieldInterpolator::ColorizeIllConditioned(LAPLACIAN laptype){
if( alpha==0 ){
fi->V(icurr)->Q() = 1;
float ratio = (f.P(iprev)-f.P(inext)).Norm() / va.Norm();
qDebug("ratio between edges: %.4f", ratio);
// qDebug("ratio between edges: %.4f", ratio);
}
// if( alpha==0 ) fi->V(iprev)->Q() = 1;

View File

@ -26,6 +26,8 @@ void GridAccell::init( MyVolume& vol, CMeshO& pcloud ){
// if( i!=12 ) continue;
trace_ray( rays[i] );
}
// Initializes the iterator
iter.init(this);
}
void GridAccell::trace_ray(PokingRay& pray, float off){
// We want to go behind the pixel, you better give me a default of 0,
@ -119,3 +121,81 @@ void GridAccell::clearCorrespondences(){
rays[i].t = +FLT_MAX;
}
}
//-------------------------------------------------------------------------------------------//
//
// ITERATOR / QUERY
//
//-------------------------------------------------------------------------------------------//
void GridAccellIterator::init(GridAccell* parent){
this->parent = parent;
this->v = &( parent->Val(0,0,0) );
}
void GridAccellIterator::first(Point3f& p){
//--- Convert the bounding box in grid space
parent->pos2off( p, box.max );
box.min = box.max;
//--- Initialize starting point
curr = box.min;
v = &( parent->Val(curr) );
offset = 0;
}
void GridAccellIterator::first(CFaceO& f){
//--- Compute bbox of face
Box3f f_bbox;
f_bbox.Add(f.P(0));
f_bbox.Add(f.P(1));
f_bbox.Add(f.P(2));
//--- Convert the bounding box in grid space
parent->pos2off( f_bbox.max, box.max );
parent->pos2off( f_bbox.min, box.min );
//--- Initialize starting point
curr = box.min;
v = &( parent->Val(curr) );
offset = -1;
#ifdef DEBUG_GRIDACCELL_ITERATOR
qDebug() << "new query initiated on " << toString(box.min);
#endif
//--- Visit first valid
this->next();
}
void GridAccellIterator::next(){
#ifdef DEBUG_GRIDACCELL_ITERATOR
qDebug() << "next element required";
#endif
// Until I find a non-empty list continue explore
for(; curr.X() <= box.max.X(); curr.X()++ ){
for(; curr.Y() <= box.max.Y(); curr.Y()++ ){
for(; curr.Z() <= box.max.Z(); curr.Z()++ ){
v = &( parent->Val(curr) );
if( v->size() != 0 && ++offset < v->size() ){
#ifdef DEBUG_GRIDACCELL_ITERATOR
qDebug() << "Accepted next [curr: " << toString(curr) << " offset: " << offset << "]";
#endif
return;
}
}
}
}
#ifdef DEBUG_GRIDACCELL_ITERATOR
qDebug() << "nothing has been found";
#endif
}
bool GridAccellIterator::isDone(){
bool condition = curr.X() >= box.max.X() && curr.Y() >= box.max.Y() && curr.Z() >= box.max.Z() && offset >= v->size();
#ifdef DEBUG_GRIDACCELL_ITERATOR
qDebug("isDone: (%s) (%d/%d %d/%d %d/%d => %d/%d)", condition?"y":"n", curr.X(),box.max.X(), curr.Y(),box.max.Y(), curr.Z(),box.max.Z(), offset+1, v->size() );
#endif
return condition;
}
PokingRay& GridAccellIterator::currentItem(){
#ifdef DEBUG_GRIDACCELL_ITERATOR
qDebug("extracted element");
#endif
return *( (*v)[offset] );
}

View File

@ -7,8 +7,10 @@
namespace vcg{
// Forward declaration
// Forward declarations
class MyVolume;
class GridAccellIterator;
class GridAccell;
/**
* Each ray is a triple of elements, the startpoint/direction
@ -36,6 +38,35 @@ public:
typedef PokingRay* PTRTYPE;
typedef std::vector< PTRTYPE > PointerVector;
/// Iterator class that queries the rays crossing a certain region
class GridAccellIterator{
private:
// Reference to class over which we are iterating
GridAccell* parent;
// the bounds of space we are currently checking
Box3i box;
// the index of the element we are currently visiting
Point3i curr;
// the content of the element we are currently visiting
PointerVector* v;
// the current internal position (grid offset)
int offset;
public:
GridAccellIterator(){
parent = NULL;
v = NULL;
offset = 0;
}
void init(GridAccell* parent);
/// Iterates over rays which intersects the box which contains the sample
void first(Point3f& p);
/// Iterates over rays which intersects the boxes which englobe the bounding box of the face
void first(CFaceO& f);
void next();
bool isDone();
PokingRay& currentItem();
};
/**
* Each volume cell contains a *set* of pointers which
* might intersect the geometry defined within the same cell
@ -57,6 +88,9 @@ private:
float delta;
public:
// Data access (to be initialized)
GridAccellIterator iter;
// Coordinate change
/// Converts a general position to a voxel index
void pos2off( const Point3f& pos, Point3i& off ){
@ -64,6 +98,7 @@ public:
off[1] = pos2off( pos[1], 1 );
off[2] = pos2off( pos[2], 2 );
}
/// Converts a general position to a voxel index
int pos2off( float p, int dim ){
int v = round( (p-bbox.min[dim])/delta + padsize-.5 );
@ -71,39 +106,53 @@ public:
assert(v>=0 && v<size(dim));
return v;
}
/// Converts a volumetric offset in a 3D space coordinate
void off2pos( int i, int j, int k, Point3f& pos ){
pos[0] = off2pos( i, 0 );
pos[1] = off2pos( j, 1 );
pos[2] = off2pos( k, 2 );
}
/// Converts a volumetric offset in a 3D space coordinate
void off2pos( Point3i off, Point3f& pos ){
pos[0] = off2pos( off[0], 0 );
pos[1] = off2pos( off[1], 1 );
pos[2] = off2pos( off[2], 2 );
}
/// Converts an offset on grid in object space coordinate
float off2pos( int i, int dim ){
assert(i>=0 && i<size(dim));
return (i-padsize+.5)*delta + bbox.min[dim];
}
/// Does not allocate memory, refer to Init
GridAccell(){ sz=Point3i(0,0,0); }
/// Allocates memory for a grid of the given size
void init( MyVolume& v, CMeshO& pcloud );
/// Accessor for memory grid representation
inline PointerVector& Val( Point3i p ){
return Val(p.X(), p.Y(), p.Z());
}
/// Accessor for memory grid representation
inline PointerVector& Val( const int x, const int y, const int z ){
return Vol[x+y*sz[0]+z*sz[0]*sz[1]];
}
/// Has this volume been initialized?
inline bool isInit(){
return sz[0]>0 && sz[1]>0 && sz[2]>0;
}
/// Size of the volume in specific dimension (padding included)
inline const int size(int dim){ return sz[dim]; }
/// Renders the intersections
void render();
/// Trace a ray in the current volume updating PointerVectors in the traversed cells
/// Before starting the marching we pull the ray back of the quantity "off", so that
/// we are able to test for intersections with triangles which are slightly behind
@ -113,7 +162,6 @@ public:
/// This function scans through the PokingRay array and reset the correspondence information
/// and the distance information (used to compute a new correspondence)
void clearCorrespondences();
};
} // Namespace VCG