mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-18 10:34:41 +00:00
593 lines
25 KiB
C++
593 lines
25 KiB
C++
#include "balloon.h"
|
|
#include "float.h"
|
|
#include "math.h"
|
|
#include "vcg/complex/trimesh/update/curvature.h"
|
|
#include "vcg/complex/trimesh/update/curvature_fitting.h"
|
|
|
|
using namespace vcg;
|
|
|
|
//---------------------------------------------------------------------------------------//
|
|
//
|
|
// LOGIC
|
|
//
|
|
//---------------------------------------------------------------------------------------//
|
|
void Balloon::init( int gridsize, int gridpad ){
|
|
//--- Reset the iteration counter
|
|
numiterscompleted = 0;
|
|
|
|
//--- Instantiate a properly sized wrapping volume
|
|
vol.init( gridsize, gridpad, cloud.bbox );
|
|
qDebug() << "Created a volume of sizes: " << vol.size(0) << " " << vol.size(1) << " " << vol.size(2);
|
|
|
|
//--- Compute hashing of ray intersections (using similar space structure of volume)
|
|
gridAccell.init( vol, cloud );
|
|
qDebug() << "Finished hashing rays into the volume";
|
|
|
|
//--- Construct EDF of initial wrapping volume (BBOX)
|
|
// Instead of constructing isosurface exactly on the bounding box, stay a bit large,
|
|
// so that ray-isosurface intersections will not fail for that region.
|
|
// Remember that rays will take a step JUST in their direction, so if they lie exactly
|
|
// on the bbox, they would go outside. The code below corrects this from happening.
|
|
Box3f enlargedbb = cloud.bbox;
|
|
// float del = .99*vol.getDelta(); // almost +1 voxel in each direction
|
|
float del = 1.99*vol.getDelta(); // USED FOR DEBUG
|
|
|
|
// float del = .50*vol.getDelta(); // ADEBUG: almost to debug correspondences
|
|
Point3f offset( del,del,del );
|
|
enlargedbb.Offset( offset );
|
|
vol.initField( enlargedbb ); // init volumetric field with the bounding box
|
|
|
|
//--- Extract initial zero level set surface
|
|
vol.isosurface( surf, 0 ); // qDebug() << "Extracted balloon isosurface (" << surf.vn << " " << surf.fn << ")";
|
|
//--- Clear band for next isosurface, clearing the corresponding computation field
|
|
for(unsigned int i=0; i<vol.band.size(); i++){
|
|
Point3i& voxi = vol.band[i];
|
|
MyVoxel& v = vol.Voxel(voxi);
|
|
v.status = 0;
|
|
v.face = 0;
|
|
v.index = 0;
|
|
v.field = NAN;
|
|
}
|
|
vol.band.clear();
|
|
//--- Update correspondences & band
|
|
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
|
|
float OMEGA = 1e3; // 1e8
|
|
LAPLACIAN type = COTANGENT; // COMBINATORIAL
|
|
bool op_succeed = finterp.Init( &surf, 1, type );
|
|
if( !op_succeed ){
|
|
finterp.ColorizeIllConditioned( type );
|
|
return false;
|
|
}
|
|
|
|
// Shared data
|
|
enum INITMODE {BIFACEINTERSECTIONS, FACEINTERSECTIONS, BOXINTERSECTIONS} mode;
|
|
mode = BIFACEINTERSECTIONS;
|
|
const float ONETHIRD = 1.0f/3.0f;
|
|
float t,u,v; // Ray-Triangle intersection parameters
|
|
Point3f fcenter;
|
|
Point3i off;
|
|
|
|
// Uses the face centroid as a hash key in the accellGrid to determine which
|
|
// rays might intersect the current face.
|
|
if( mode == BOXINTERSECTIONS ){
|
|
for(CMeshO::FaceIterator fi=surf.face.begin();fi!=surf.face.end();fi++){
|
|
CFaceO& f = *(fi);
|
|
fcenter = f.P(0) + f.P(1) + f.P(2);
|
|
fcenter = myscale( fcenter, ONETHIRD );
|
|
gridAccell.pos2off( fcenter, off );
|
|
//--- examine intersections and determine real ones...
|
|
PointerVector& rays = gridAccell.Val(off[0], off[1], off[2]);
|
|
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!!";
|
|
}
|
|
else if( mode == FACEINTERSECTIONS ){
|
|
this->rm ^= SURF_VCOLOR;
|
|
this->rm |= SURF_FCOLOR;
|
|
surf.face.EnableColor();
|
|
surf.face.EnableQuality();
|
|
tri::UpdateQuality<CMeshO>::FaceConstant(surf, 0);
|
|
std::vector<float> tot_w( surf.fn, 0 );
|
|
for(CMeshO::FaceIterator fi=surf.face.begin();fi!=surf.face.end();fi++){
|
|
CFaceO& f = *(fi);
|
|
f.ClearS();
|
|
f.C() = Color4b(255,255,255, 255);
|
|
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) ){
|
|
// Color the faces, if more than one, take average
|
|
tot_w[ tri::Index(surf,f) ]++;
|
|
f.Q() += t; // normalize with tot_w after
|
|
f.SetS();
|
|
//--- Add the constraints to the field
|
|
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 );
|
|
}
|
|
}
|
|
|
|
//--- Normalize in case there is more than 1 ray per-face
|
|
for(CMeshO::FaceIterator fi=surf.face.begin();fi!=surf.face.end();fi++){
|
|
if( tot_w[ tri::Index(surf,*fi) ] > 0 )
|
|
fi->Q() /= tot_w[ tri::Index(surf,*fi) ];
|
|
}
|
|
//--- Transfer the average distance stored in face quality to a color
|
|
// and do it only for the selection (true)
|
|
tri::UpdateColor<CMeshO>::FaceQualityRamp(surf, true);
|
|
}
|
|
// This is the variation that adds to add constraints on both sides of the isosurface
|
|
// to cope with noise but especially to guarantee convergence of the surface. If we go
|
|
// through a sample, a negative force field will be generated that will push the
|
|
// isosurface back close to the sample.
|
|
else if( mode == BIFACEINTERSECTIONS ){
|
|
this->rm ^= SURF_VCOLOR;
|
|
this->rm |= SURF_FCOLOR;
|
|
surf.face.EnableColor();
|
|
surf.face.EnableQuality();
|
|
tri::UpdateQuality<CMeshO>::FaceConstant(surf, 0);
|
|
std::vector<float> tot_w( surf.fn, 0 );
|
|
|
|
// We clear the pokingRay-triangle correspondence information + distance information
|
|
// to get ready for the next step
|
|
gridAccell.clearCorrespondences();
|
|
|
|
// In this first phase, we scan through faces and we update the information
|
|
// contained in the rays. We try to have a many-1 correspondence in between
|
|
// rays and faces: each face can have more than one ray, but one ray can only
|
|
// have one face associated with it. This face can either be behind or in
|
|
// front of the ray startpoint.
|
|
for(CMeshO::FaceIterator fi=surf.face.begin();fi!=surf.face.end();fi++){
|
|
CFaceO& f = *(fi);
|
|
f.ClearS();
|
|
f.C() = Color4b(255,255,255, 255);
|
|
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]);
|
|
|
|
// 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());
|
|
|
|
// 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) ){
|
|
|
|
// DEBUG
|
|
// f.C() = t>0 ? Color4b(0,0,255,255) : f.C() = Color4b(255,0,0,255);
|
|
|
|
// DEBUG
|
|
// if( prays[i]->f!=NULL && fabs(t)<fabs(prays[i]->t) ){
|
|
// prays[i]->f->C() = Color4b(255,0,0,255);
|
|
// qDebug() << "replaced: " << tri::Index(surf,prays[i]->f) << " from t: " << prays[i]->t << " to " << tri::Index(surf,f) << t;
|
|
// }
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
for(unsigned int i=0; i<gridAccell.rays.size(); i++){
|
|
// Retrieve the corresponding face and signed distance
|
|
Ray3f& ray = gridAccell.rays[i].ray;
|
|
// The use of vcg::Simplify to remove degenerate triangles could cause a ray to fail the intersection test!!
|
|
if( gridAccell.rays[i].f == NULL){
|
|
qDebug() << "warning: ray #" << i << "has provided NULL intersection"; // << toString(ray.Origin()) << " " << toString(ray.Direction());
|
|
continue;
|
|
}
|
|
CFaceO& f = *(gridAccell.rays[i].f);
|
|
float t = gridAccell.rays[i].t;
|
|
assert( !math::IsNAN(t) );
|
|
|
|
// Color the faces, if more than one, take average
|
|
tot_w[ tri::Index(surf,f) ]++;
|
|
f.Q() += t; // normalize with tot_w after
|
|
f.SetS(); // enable the face for coloring
|
|
|
|
// DEBUG
|
|
// f.C() = Color4b(0,255,0,255);
|
|
|
|
// I was lazy and didn't store the u,v... we need to recompute them
|
|
vcg::IntersectionRayTriangle<float>(ray, f.P(0), f.P(1), f.P(2), t, u, v);
|
|
|
|
//--- Add the barycenter-weighted constraints to the vertices of the face
|
|
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 );
|
|
assert( u>=0 && u<=1 && v>=0 && v<=1 );
|
|
}
|
|
|
|
//--- Normalize in case there is more than 1 ray per-face
|
|
for(CMeshO::FaceIterator fi=surf.face.begin();fi!=surf.face.end();fi++){
|
|
if( tot_w[ tri::Index(surf,*fi) ] > 0 )
|
|
fi->Q() /= tot_w[ tri::Index(surf,*fi) ];
|
|
}
|
|
//--- Transfer the average distance stored in face quality to a color and do it only for the selection (true)
|
|
tri::UpdateColor<CMeshO>::FaceQualityRamp(surf, true);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
void Balloon::interpolateField(){
|
|
//--- Mark property active
|
|
surf.vert.QualityEnabled = true;
|
|
|
|
//--- Interpolate the field
|
|
finterp.SolveInQuality();
|
|
|
|
//--- Transfer vertex quality to surface
|
|
rm &= ~SURF_FCOLOR; // disable face 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));
|
|
}
|
|
void Balloon::computeCurvature(){
|
|
#if FALSE
|
|
float OMEGA = 1; // interpolation coefficient
|
|
sinterp.Init( &surf, 3, COMBINATORIAL );
|
|
for( CMeshO::VertexIterator vi=surf.vert.begin();vi!=surf.vert.end();vi++ )
|
|
sinterp.AddConstraint3( tri::Index(surf,*vi), OMEGA, (*vi).P()[0], (*vi).P()[1], (*vi).P()[2] );
|
|
FieldInterpolator::XBType* coords[3];
|
|
sinterp.Solve(coords);
|
|
for( CMeshO::VertexIterator vi=surf.vert.begin();vi!=surf.vert.end();vi++ ){
|
|
int vIdx = tri::Index(surf,*vi);
|
|
(*vi).P()[0] = (*coords[0])(vIdx);
|
|
(*vi).P()[1] = (*coords[1])(vIdx);
|
|
(*vi).P()[2] = (*coords[2])(vIdx);
|
|
}
|
|
#endif
|
|
|
|
#if TRUE
|
|
surf.vert.EnableCurvature();
|
|
surf.vert.EnableCurvatureDir();
|
|
tri::UpdateCurvatureFitting<CMeshO>::computeCurvature( surf );
|
|
for(CMeshO::VertexIterator vi = surf.vert.begin(); vi != surf.vert.end(); ++vi){
|
|
(*vi).Kh() = ( (*vi).K1() + (*vi).K2() ) / 2;
|
|
}
|
|
#endif
|
|
|
|
#if FALSE
|
|
// Enable curvature supports, How do I avoid a
|
|
// double computation of topology here?
|
|
surf.vert.EnableCurvature();
|
|
surf.vert.EnableVFAdjacency();
|
|
surf.face.EnableVFAdjacency();
|
|
surf.face.EnableFFAdjacency();
|
|
vcg::tri::UpdateTopology<CMeshO>::VertexFace( surf );
|
|
vcg::tri::UpdateTopology<CMeshO>::FaceFace( surf );
|
|
|
|
//--- Compute curvature and its bounds
|
|
tri::UpdateCurvature<CMeshO>::MeanAndGaussian( surf );
|
|
#endif
|
|
|
|
if( surf.vert.CurvatureEnabled ){
|
|
//--- Enable color coding
|
|
rm &= ~SURF_FCOLOR;
|
|
rm |= SURF_VCOLOR;
|
|
|
|
//--- DEBUG compute curvature bounds
|
|
float absmax = -FLT_MAX;
|
|
for(CMeshO::VertexIterator vi = surf.vert.begin(); vi != surf.vert.end(); ++vi){
|
|
float cabs = fabs((*vi).Kh());
|
|
absmax = (cabs>absmax) ? cabs : absmax;
|
|
}
|
|
|
|
//--- Map curvature to two color ranges:
|
|
// Blue => Yellow: negative values
|
|
// Yellow => Red: positive values
|
|
typedef unsigned char CT;
|
|
for(CMeshO::VertexIterator vi = surf.vert.begin(); vi != surf.vert.end(); ++vi){
|
|
if( (*vi).Kh() < 0 )
|
|
(*vi).C().lerp(Color4<CT>::Yellow, Color4<CT>::Blue, fabs((*vi).Kh())/absmax );
|
|
else
|
|
(*vi).C().lerp(Color4<CT>::Yellow, Color4<CT>::Red, (*vi).Kh()/absmax);
|
|
}
|
|
}
|
|
}
|
|
|
|
// HP: a correspondence has already been executed once!
|
|
void Balloon::evolve(){
|
|
// Update iteration counter
|
|
numiterscompleted++;
|
|
|
|
//--- THIS IS A DEBUG TEST, ATTEMPTS TO DEBUG
|
|
if( false ){
|
|
//--- Test uniform band update
|
|
for(unsigned int i=0; i<vol.band.size(); i++){
|
|
Point3i& voxi = vol.band[i];
|
|
MyVoxel& v = vol.Voxel(voxi);
|
|
v.sfield += .05;
|
|
}
|
|
//--- Estrai isosurface
|
|
vol.isosurface( surf, 0 );
|
|
//--- Clear band for next isosurface, clearing the corresponding computation field
|
|
for(unsigned int i=0; i<vol.band.size(); i++){
|
|
Point3i& voxi = vol.band[i];
|
|
MyVoxel& v = vol.Voxel(voxi);
|
|
v.status = 0;
|
|
v.face = 0;
|
|
v.index = 0;
|
|
v.field = NAN;
|
|
}
|
|
vol.band.clear();
|
|
//--- Update correspondences & band
|
|
vol.band.reserve(5*surf.fn);
|
|
vol.updateSurfaceCorrespondence( surf, gridAccell, 2*vol.getDelta() );
|
|
return;
|
|
}
|
|
|
|
//--- Compute updates from amount stored in vertex quality
|
|
Point3f c; // barycentric coefficients
|
|
Point3f voxp;
|
|
std::vector<float> updates_view(vol.band.size(),0);
|
|
std::vector<float> updates_curv(vol.band.size(),0);
|
|
float view_max_absdst = -FLT_MAX;
|
|
float view_max_dst = -FLT_MAX, view_min_dst = +FLT_MAX;
|
|
float curv_maxval = -FLT_MAX;
|
|
for(unsigned int i=0; i<vol.band.size(); i++){
|
|
Point3i& voxi = vol.band[i];
|
|
MyVoxel& v = vol.Voxel(voxi);
|
|
CFaceO& f = *v.face;
|
|
// extract projected points on surface and obtain barycentric coordinates
|
|
// TODO: double work, it was already computed during correspodence, write a new function?
|
|
Point3f proj;
|
|
vol.off2pos(voxi, voxp);
|
|
vcg::SignedFacePointDistance(f, voxp, proj);
|
|
Triangle3<float> triFace( f.P(0), f.P(1), f.P(2) );
|
|
|
|
// Paolo, is this really necessary?
|
|
int axis;
|
|
if (f.Flags() & CFaceO::NORMX ) axis = 0;
|
|
else if(f.Flags() & CFaceO::NORMY ) axis = 1;
|
|
else axis = 2;
|
|
vcg::InterpolationParameters(triFace, axis, proj, c);
|
|
|
|
// Interpolate update amounts & keep track of the range
|
|
if( surf.vert.QualityEnabled ){
|
|
updates_view[i] = c[0]*f.V(0)->Q() + c[1]*f.V(1)->Q() + c[2]*f.V(2)->Q();
|
|
view_max_absdst = (fabs(updates_view[i])>view_max_absdst) ? fabs(updates_view[i]) : view_max_absdst;
|
|
view_max_dst = updates_view[i]>view_max_dst ? updates_view[i] : view_max_dst;
|
|
view_min_dst = updates_view[i]<view_min_dst ? updates_view[i] : view_min_dst;
|
|
}
|
|
// Interpolate curvature amount & keep track of the range
|
|
if( surf.vert.CurvatureEnabled ){
|
|
updates_curv[i] = c[0]*f.V(0)->Kh() + c[1]*f.V(1)->Kh() + c[2]*f.V(2)->Kh();
|
|
curv_maxval = (fabs(updates_curv[i])>curv_maxval) ? fabs(updates_curv[i]) : curv_maxval;
|
|
}
|
|
}
|
|
// Only meaningful if it has been computed..
|
|
qDebug("Delta: %f", vol.getDelta());
|
|
|
|
if( surf.vert.QualityEnabled )
|
|
qDebug("view distance: min %.3f max %.3f", view_min_dst, view_max_dst);
|
|
if( surf.vert.CurvatureEnabled )
|
|
qDebug("max curvature: %f", curv_maxval);
|
|
|
|
//--- Apply exponential functions to modulate and regularize the updates
|
|
float sigma2 = vol.getDelta()*vol.getDelta();
|
|
float k1, k3;
|
|
|
|
//--- Maximum speed: avoid over-shoothing by limiting update speed
|
|
// E_view + alpha*E_smooth
|
|
float balance_coeff = .5;
|
|
|
|
// Slowdown weight, smaller if worst case scenario is very converging
|
|
float k2 = 1 - exp( -powf(view_max_absdst,2) / sigma2 );
|
|
|
|
for(unsigned int i=0; i<vol.band.size(); i++){
|
|
Point3i& voxi = vol.band[i];
|
|
MyVoxel& v = vol.Voxel(voxi);
|
|
|
|
//--- Avoids over-shooting, as maximum speed is bound to dist from surface
|
|
float max_speed = std::min( vol.getDelta()/2, std::abs(updates_view[i]) );
|
|
|
|
//--- Distance weights
|
|
if( surf.vert.QualityEnabled ){
|
|
// Faster if I am located further
|
|
k1 = exp( -powf(fabs(updates_view[i])-view_max_absdst,2) / sigma2 );
|
|
}
|
|
//--- Curvature weight (faster if spiky)
|
|
if( surf.vert.CurvatureEnabled )
|
|
// k3 = updates_curv[i] / curv_maxval;
|
|
k3 = sign(1.0f,updates_curv[i])*exp(-powf(fabs(updates_curv[i])-curv_maxval,2)/curv_maxval);
|
|
|
|
//--- Apply the update on the implicit field
|
|
if( surf.vert.QualityEnabled ){
|
|
float prev = v.sfield;
|
|
v.sfield += vcg::sign( k1*k2*max_speed, updates_view[i] );
|
|
if( v.sfield < 0 && prev > 0){
|
|
qDebug("Update from f=%.3f to %.3f", prev, v.sfield);
|
|
qDebug("k1: %.2f", k1);
|
|
qDebug("k3: %.2f", k3);
|
|
qDebug("max_speed: %.2f", max_speed);
|
|
}
|
|
|
|
// v.sfield += vcg::sign( .15f*k1*k2*vol.getDelta(), updates_view[i]);
|
|
// v.sfield += .25f * k1 * vol.getDelta();
|
|
}
|
|
// if we don't have computed the distance field, we don't really know how to
|
|
// modulate the laplacian accordingly...
|
|
// #if TRUE // ENABLE_CURVATURE_IN_EVOLUTION
|
|
// if( surf.vert.CurvatureEnabled && surf.vert.QualityEnabled ){
|
|
// v.sfield += .1*k3*k2;
|
|
// }
|
|
|
|
if( surf.vert.CurvatureEnabled ){
|
|
v.sfield += k3*balance_coeff*max_speed; // prev .1
|
|
}
|
|
// #endif
|
|
}
|
|
|
|
//--- DEBUG LINES: what's being updated (cannot put above cause it's in a loop)
|
|
if( surf.vert.QualityEnabled )
|
|
qDebug() << "updating implicit function using distance field";
|
|
if( surf.vert.CurvatureEnabled && surf.vert.QualityEnabled )
|
|
qDebug() << "updating implicit function using (modulated) curvature";
|
|
else if( surf.vert.CurvatureEnabled )
|
|
qDebug() << "updating implicit function using (unmodulated) curvature";
|
|
|
|
//--- Estrai isosurface
|
|
vol.isosurface( surf, 0 );
|
|
|
|
//--- Clear band for next isosurface, clearing the corresponding computation field
|
|
for(unsigned int i=0; i<vol.band.size(); i++){
|
|
Point3i& voxi = vol.band[i];
|
|
MyVoxel& v = vol.Voxel(voxi);
|
|
v.status = 0;
|
|
v.face = 0;
|
|
v.index = 0;
|
|
v.field = NAN;
|
|
}
|
|
vol.band.clear();
|
|
//--- Update correspondences & band
|
|
vol.band.reserve(5*surf.fn);
|
|
vol.updateSurfaceCorrespondence( surf, gridAccell, 2*vol.getDelta() );
|
|
//--- Disable curvature and quality
|
|
surf.vert.CurvatureEnabled = false;
|
|
surf.vert.QualityEnabled = false;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------//
|
|
//
|
|
// RENDERING
|
|
//
|
|
//---------------------------------------------------------------------------------------//
|
|
void Balloon::render_cloud(){
|
|
// Draw the ray/rays from their origin up to some distance away
|
|
glDisable(GL_LIGHTING);
|
|
glColor3f(.5, .5, .5);
|
|
for(CMeshO::VertexIterator vi=cloud.vert.begin(); vi!=cloud.vert.end(); ++vi){
|
|
Point3f p1 = (*vi).P();
|
|
Point3f n = (*vi).N();
|
|
// n[0] *= .1; n[1] *= .1; n[2] *= .1; // Scale the viewdir
|
|
Point3f p2 = (*vi).P() + n;
|
|
glBegin(GL_LINES);
|
|
glVertex3f(p1[0],p1[1],p1[2]);
|
|
glVertex3f(p2[0],p2[1],p2[2]);
|
|
glEnd();
|
|
}
|
|
glEnable(GL_LIGHTING);
|
|
}
|
|
void Balloon::render_isosurface(GLArea* gla){
|
|
GLW::DrawMode dm = GLW::DMFlatWire;
|
|
GLW::ColorMode cm = GLW::CMPerVert;
|
|
GLW::TextureMode tm = GLW::TMNone;
|
|
|
|
// By default vertColor is defined, so let's check if we need/want to
|
|
// draw the face colors first.
|
|
if( (rm & SURF_FCOLOR) && tri::HasPerFaceColor(surf) ){
|
|
gla->rm.colorMode = vcg::GLW::CMPerFace; // Corrects MESHLAB BUG
|
|
cm = GLW::CMPerFace;
|
|
}
|
|
else if( (rm & SURF_VCOLOR) && tri::HasPerVertexColor(surf) ){
|
|
gla->rm.colorMode = vcg::GLW::CMPerVert; // Corrects MESHLAB BUG
|
|
cm = GLW::CMPerVert;
|
|
}
|
|
GlTrimesh<CMeshO> surf_renderer;
|
|
surf_renderer.m = &surf;
|
|
surf_renderer.Draw(dm, cm, tm);
|
|
}
|
|
void Balloon::render_surf_to_acc(){
|
|
gridAccell.render();
|
|
|
|
#if 0
|
|
glDisable( GL_LIGHTING );
|
|
const float ONETHIRD = 1.0f/3.0f;
|
|
Point3f fcenter;
|
|
Point3i off, o;
|
|
glColor3f(1.0, 0.0, 0.0);
|
|
for(unsigned int fi =0; fi<surf.face.size(); fi++){
|
|
if( fi!= 5 )
|
|
continue;
|
|
CFaceO& f = surf.face[fi];
|
|
fcenter = f.P(0) + f.P(1) + f.P(2);
|
|
fcenter = myscale( fcenter, ONETHIRD );
|
|
gridAccell.pos2off( fcenter, off );
|
|
vol.pos2off( fcenter, o );
|
|
gridAccell.off2pos( off, fcenter );
|
|
vcg::drawBox( fcenter, vol.getDelta()*.95, true );
|
|
|
|
|
|
// SHO BLOCK
|
|
qDebug() << "full volume: " << endl << vol.toString(2, o[2]);
|
|
// DEBUG: examine field values around current coordinate
|
|
QString q;
|
|
qDebug();
|
|
q.sprintf("%2.2f %2.2f %2.2f \n%2.2f %2.2f %2.2f \n%2.2f %2.2f %2.2f",
|
|
vol.Val(o[0]-1,o[1]+1,o[2]), vol.Val(o[0],o[1]+1,o[2]), vol.Val(o[0]+1,o[1]+1,o[2]),
|
|
vol.Val(o[0]-1,o[1],o[2]), vol.Val(o[0],o[1],o[2]), vol.Val(o[0]+1,o[1]+0,o[2]),
|
|
vol.Val(o[0]-1,o[1]-1,o[2]), vol.Val(o[0],o[1]-1,o[2]), vol.Val(o[0]+1,o[1]-1,o[2]) );
|
|
qDebug() << q;
|
|
qDebug();
|
|
o = off; // use the gridaccell data
|
|
q.sprintf("%2.2f %2.2f %2.2f \n%2.2f %2.2f %2.2f \n%2.2f %2.2f %2.2f",
|
|
vol.Val(o[0]-1,o[1]+1,o[2]), vol.Val(o[0],o[1]+1,o[2]), vol.Val(o[0]+1,o[1]+1,o[2]),
|
|
vol.Val(o[0]-1,o[1],o[2]), vol.Val(o[0],o[1],o[2]), vol.Val(o[0]+1,o[1]+0,o[2]),
|
|
vol.Val(o[0]-1,o[1]-1,o[2]), vol.Val(o[0],o[1]-1,o[2]), vol.Val(o[0]+1,o[1]-1,o[2]) );
|
|
qDebug() << q;
|
|
}
|
|
#endif
|
|
|
|
glEnable( GL_LIGHTING );
|
|
}
|
|
void Balloon::render_surf_to_vol(){
|
|
if( !vol.isInit() ) return;
|
|
Point3f p, proj;
|
|
glDisable(GL_LIGHTING);
|
|
for(int i=0;i<vol.size(0);i++)
|
|
for(int j=0;j<vol.size(1);j++)
|
|
for(int k=0;k<vol.size(2);k++){
|
|
// if( i!=3 || j!=6 || k!=5 ) continue;
|
|
|
|
MyVoxel& v = vol.Voxel(i,j,k);
|
|
vol.off2pos(i,j,k,p);
|
|
// Only ones belonging to active band
|
|
if( v.status == 2 ){ // && ( tri::Index(surf, v.face)==35||tri::Index(surf, v.face)==34) ){
|
|
assert( v.face != 0 );
|
|
vcg::drawBox(p, .05*vol.getDelta());
|
|
Point3f proj;
|
|
// float dist = vcg::SignedFacePointDistance(*v.face, p, proj);
|
|
vcg::SignedFacePointDistance(*v.face, p, proj);
|
|
//proj = vcg::Barycenter(*v.face);
|
|
vcg::drawSegment( p, proj );
|
|
}
|
|
}
|
|
glEnable(GL_LIGHTING);
|
|
}
|
|
void Balloon::render(GLArea* gla){
|
|
if( rm & SHOW_CLOUD )
|
|
render_cloud();
|
|
if( rm & SHOW_VOLUME )
|
|
vol.render();
|
|
if( rm & SHOW_SURF )
|
|
render_isosurface(gla);
|
|
//if( rm & SHOW_ACCEL )
|
|
// gridAccell.render();
|
|
if( rm & SHOW_3DDDR )
|
|
render_surf_to_acc();
|
|
if( rm & SHOW_SURF_TO_VOL )
|
|
render_surf_to_vol();
|
|
}
|