1 #ifndef CRATERS_UTILS_H 2 #define CRATERS_UTILS_H 3 4 #include <vcg/space/index/grid_static_ptr.h> 5 #include "fractal_utils.h" 6 7 /* some utilities needed by the crater generation filter */ 8 template<class MeshType> 9 class CratersUtils 10 { 11 public: 12 typedef typename MeshType::FacePointer FacePointer; 13 typedef typename MeshType::FaceIterator FaceIterator; 14 typedef typename MeshType::FaceType FaceType; 15 typedef typename MeshType::VertexPointer VertexPointer; 16 typedef typename MeshType::VertexIterator VertexIterator; 17 typedef std::pair<VertexPointer, FacePointer> SampleFace; 18 typedef std::vector<SampleFace> SampleFaceVector; 19 typedef typename MeshType::ScalarType ScalarType; 20 typedef GridStaticPtr<FaceType, ScalarType> MetroMeshGrid; 21 typedef tri::FaceTmark<MeshType> MarkerFace; 22 typedef typename MeshType::template PerVertexAttributeHandle<ScalarType> PertHandle; 23 24 /* wrapper for FP_CRATERS filter arguments */ 25 class CratersArgs 26 { 27 public: 28 RadialFunctor<ScalarType>* radialFunctor; // The radial functor that is defined according to 29 // the chosen radial algorithm. 30 RadialFunctor<ScalarType>* blendingFunctor; // Blending functor defined accordingly to 31 // the chosen blending algorithm. 32 NoiseFunctor<ScalarType>* noiseFunctor; // Noise functor needed for postprocessing 33 // noise application. 34 CraterFunctor<ScalarType>* craterFunctor; // Functor constructed from the combination 35 // of the above three functors. 36 MeshModel* target_model; 37 MeshModel* samples_model; 38 MeshType* target_mesh; 39 MeshType* samples_mesh; 40 int smoothingSteps; // number of vertex normal smoothing steps (pre-processing) 41 ScalarType max_radius, max_depth, min_radius, min_depth, radius_range, depth_range; 42 bool save_as_quality, postprocessing_noise, successiveImpacts; 43 CratersArgs(MeshModel * target,MeshModel * samples,int radial_alg,int seed,ScalarType min_r,ScalarType max_r,ScalarType min_d,ScalarType max_d,int smoothingSteps,bool save_as_quality,bool invert,bool ppNoise,bool successiveImpacts,ScalarType elevation,int blending_alg,ScalarType blendingThreshold)44 CratersArgs(MeshModel* target, MeshModel* samples, int radial_alg, int seed, 45 ScalarType min_r, ScalarType max_r, ScalarType min_d, ScalarType max_d, 46 int smoothingSteps, bool save_as_quality, bool invert, bool ppNoise, bool successiveImpacts, 47 ScalarType elevation, int blending_alg, ScalarType blendingThreshold) 48 { 49 // Builds the random number generator used to generate radiuses and depths 50 // for craters. 51 generator = new vcg::math::SubtractiveRingRNG(seed); 52 53 // builds the radial functor 54 switch(radial_alg) 55 { 56 case 0: 57 radialFunctor = new GaussianBlending<ScalarType>(); 58 break; 59 case 1: 60 radialFunctor = new MultiquadricBlending<ScalarType>(); 61 break; 62 case 2: 63 radialFunctor = new F3Blending<ScalarType>(); 64 break; 65 } 66 67 // builds the blending functor 68 switch(blending_alg) 69 { 70 case 0: 71 blendingFunctor = new ExponentialBlending<ScalarType>(); 72 break; 73 case 1: 74 blendingFunctor = new LinearBlending<ScalarType>(); 75 break; 76 case 2: 77 blendingFunctor = new GaussianBlending<ScalarType>(); 78 break; 79 case 3: 80 blendingFunctor = new F3Blending<ScalarType>(); 81 break; 82 } 83 84 // if necessary, builds the noise functor 85 postprocessing_noise = ppNoise; 86 if (ppNoise) 87 { 88 noiseFunctor = new FBMNoiseFunctor<ScalarType>(8, 0.7, 2); 89 } 90 craterFunctor = new CraterFunctor<ScalarType>(radialFunctor, blendingFunctor, 91 noiseFunctor, blendingThreshold, elevation, ppNoise, invert); 92 93 // fields assignments 94 target_model = target; 95 samples_model = samples; 96 target_mesh = &(target->cm); 97 samples_mesh = &(samples->cm); 98 this->save_as_quality = save_as_quality; 99 this->successiveImpacts = successiveImpacts; 100 this->smoothingSteps = smoothingSteps; 101 float target_bb_diag = target_mesh->bbox.Diag(); 102 max_radius = target_bb_diag * 0.25 * max_r; // calculates the maximum crater radius 103 min_radius = target_bb_diag * 0.25 * min_r; // calculates the minimum crater radius 104 radius_range = max_radius - min_radius; // calculates the radius range 105 max_depth = target_bb_diag * 0.25 * max_d; // calculates the maximum crater depth 106 min_depth = target_bb_diag * 0.25 * min_d; // calculates the minimum crater depth 107 depth_range = max_depth - min_depth; // calculates the depth range 108 109 // some cleanup operations on target mesh 110 vcg::tri::Clean<MeshType>::RemoveUnreferencedVertex(*target_mesh); 111 vcg::tri::Allocator<MeshType>::CompactVertexVector(*target_mesh); 112 vcg::tri::Allocator<MeshType>::CompactFaceVector(*target_mesh); 113 } 114 115 // destructor ~CratersArgs()116 ~CratersArgs(){ 117 delete radialFunctor; 118 delete blendingFunctor; 119 if(postprocessing_noise) 120 delete noiseFunctor; 121 122 delete craterFunctor; 123 delete generator; 124 } 125 126 /* generates a crater radius within the specified range */ generateRadius()127 ScalarType generateRadius() 128 { 129 ScalarType rnd = generator->generate01closed(); 130 return min_radius + radius_range * rnd; 131 } 132 133 /* generates a crater depth within the specified range */ generateDepth()134 ScalarType generateDepth() 135 { 136 ScalarType rnd = generator->generate01closed(); 137 return min_depth + depth_range * rnd; 138 } 139 140 private: 141 vcg::math::RandomGenerator* generator; // private random number generator 142 }; 143 144 145 /* Finds the nearest faces of samples and stores the pairs (sample, nearest_face) 146 in the "sfv" vector (third parameter). */ FindSamplesFaces(MeshType * target,MeshType * samples,SampleFaceVector & sfv)147 static void FindSamplesFaces(MeshType *target, MeshType *samples, SampleFaceVector &sfv) 148 { 149 tri::UpdateNormal<MeshType>::PerFaceNormalized(*target); 150 // tri::UpdateFlags<MeshType>::FaceProjection(*target); 151 152 MetroMeshGrid mmg; 153 mmg.Set(target->face.begin(), target->face.end()); 154 MarkerFace markerFunctor; 155 markerFunctor.SetMesh(target); 156 vcg::face::PointDistanceBaseFunctor<ScalarType> PDistFunct; 157 FacePointer nearestFace; 158 ScalarType dist_upper_bound = target->bbox.Diag()/10, dist; 159 Point3<ScalarType> closest; 160 sfv.clear(); 161 SampleFace* tmpPair; 162 int i=0; 163 164 for(VertexIterator vi=samples->vert.begin(); vi!=samples->vert.end(); ++vi, ++i) 165 { 166 nearestFace = mmg.GetClosest(PDistFunct, markerFunctor, (*vi).P(), dist_upper_bound, dist, closest); 167 tmpPair = new SampleFace(&(*vi), nearestFace); 168 sfv.push_back(*tmpPair); 169 } 170 } 171 172 /* Detectes the faces of a crater starting from a given face, using FF adjacency. */ GetCraterFaces(MeshType * m,FacePointer startingFace,VertexPointer centre,ScalarType radius,std::vector<FacePointer> & toFill)173 static void GetCraterFaces(MeshType *m, // target mesh 174 FacePointer startingFace, // face under the crater centre 175 VertexPointer centre, // crater centre 176 ScalarType radius, // crater radius 177 std::vector<FacePointer> &toFill) // the vector that has to be 178 // filled with crater faces 179 { 180 assert(vcg::tri::HasFFAdjacency(*m)); 181 vcg::tri::UpdateFlags<MeshType>::FaceClearV(*m); 182 vcg::tri::UpdateFlags<MeshType>::VertexClearV(*m); 183 184 vcg::Sphere3<ScalarType> craterSphere(centre->P(), radius); // crater sphere 185 std::vector<FacePointer> fl; 186 fl.push_back(startingFace); 187 188 toFill.clear(); 189 FacePointer f; 190 Point3<ScalarType> dummyPoint; 191 std::pair<ScalarType, ScalarType> dummyPair; 192 193 while(!fl.empty()) 194 { 195 f = fl.back(); 196 fl.pop_back(); 197 198 if((f != NULL) && (!f->IsV())) 199 { 200 f->SetV(); 201 if(vcg::IntersectionSphereTriangle<ScalarType, FaceType> 202 (craterSphere, *f, dummyPoint, &dummyPair)) 203 { // intersection test succedeed 204 toFill.push_back(f); 205 for(int i=0; i<3; i++) 206 { 207 if(!f->FFp(i)->IsV()) 208 { 209 fl.push_back(f->FFp(i)); 210 } 211 } 212 } 213 } 214 } 215 } 216 217 /* Computes the radial perturbation given: 218 - args: a CratersArgs object that stores the needed perturbation parameters; 219 - centre: a pointer to the centre of the to-be-generated crater; 220 - craterFaces: a vector that contains the faces contained in the crater radius; 221 - radius: the radius of the to-be-generated crater; 222 - depth: the depth of the to-be-generated crater; 223 - pertHandle: an handle to a user-defined vertex attribute of type MeshType::ScalarType 224 (i.e. s floating point value). This attribute is filled with the computed perturbation. 225 */ ComputeRadialPerturbation(CratersArgs & args,VertexPointer centre,std::vector<FacePointer> & craterFaces,ScalarType radius,ScalarType depth,PertHandle & pertHandle)226 static void ComputeRadialPerturbation 227 (CratersArgs &args, VertexPointer centre, 228 std::vector<FacePointer> &craterFaces, ScalarType radius, 229 ScalarType depth, PertHandle& pertHandle) 230 { 231 vcg::tri::UpdateFlags<MeshType>::VertexClearV(*(args.target_mesh)); 232 233 typename std::vector<FacePointer>::iterator fi; 234 VertexPointer vp; 235 ScalarType perturbation = .0; 236 Point3<ScalarType> p; 237 238 /* for each crater vertex, calculates the associated perturbation 239 and then stores it in the passed per-vertex-attribute handle */ 240 for(fi = craterFaces.begin(); fi!=craterFaces.end(); ++fi) 241 { 242 for(int i=0; i<3; i++) 243 { 244 vp = (*fi)->V(i); 245 if(!vp->IsV()) 246 { 247 vp->SetV(); 248 p = (vp->P() - centre->P())/radius; 249 perturbation = (*(args.craterFunctor))(p) * depth; 250 251 // stores the perturbation in the passed handle, according to 252 // the successiveImpacts flag 253 if(args.successiveImpacts) 254 { 255 if(perturbation < 0) // we are in the crater "depression" 256 { 257 pertHandle[vp] = std::min(perturbation, pertHandle[vp]); 258 } else // crater "elevation" and/or blending portion 259 { 260 if(pertHandle[vp] == .0) 261 { 262 pertHandle[vp] += perturbation; 263 } 264 } 265 } else { 266 // by adding the perturbation to the one that is already present 267 // we obtain a "crater intersection", so we cannot recognize 268 // which crater is created before each other 269 pertHandle[vp] += perturbation; 270 } 271 } 272 } 273 } 274 } 275 276 /* craters generation algorithm */ GenerateCraters(CratersArgs & args,vcg::CallBackPos * cb)277 static bool GenerateCraters(CratersArgs &args, vcg::CallBackPos *cb) 278 { 279 // enables per-vertex-quality if needed 280 if(args.save_as_quality) 281 args.target_model->updateDataMask(MeshModel::MM_VERTQUALITY); 282 283 // tri::UpdateFlags<MeshType>::FaceProjection(args.target_model->cm); 284 // smoothes vertex normals 285 cb(0, "Smoothing vertex normals.."); 286 tri::Smooth<MeshType>::VertexNormalLaplacian(*(args.target_mesh), args.smoothingSteps, false); 287 288 // finds samples faces 289 args.target_model->updateDataMask(MeshModel::MM_FACEFACETOPO); 290 args.target_model->updateDataMask(MeshModel::MM_FACEMARK); 291 SampleFaceVector sfv; 292 CratersUtils<MeshType>::FindSamplesFaces(args.target_mesh, args.samples_mesh, sfv); 293 294 // detectes crater faces and applies the radial perturbation 295 int cratersNo = int(args.samples_mesh->vert.size()), currentCrater = 0; 296 char buffer[50]; 297 typename SampleFaceVector::iterator sfvi; 298 SampleFace p; 299 ScalarType radius = .0, depth = .0; 300 std::vector<FacePointer> craterFaces; 301 302 // per-vertex float attribute 303 PertHandle h = tri::Allocator<MeshType>::template AddPerVertexAttribute<ScalarType> 304 (*(args.target_mesh), std::string("perturbation")); 305 for(VertexIterator vi=args.target_mesh->vert.begin(); vi!=args.target_mesh->vert.end(); ++vi) 306 { 307 h[vi] = .0; 308 } 309 310 // calculates the perturbation and stores it in the per-vertex-attribute 311 for(sfvi=sfv.begin(); sfvi!=sfv.end(); ++sfvi) 312 { 313 sprintf(buffer, "Generating crater %i...", currentCrater); 314 cb(100*(currentCrater++)/cratersNo, buffer); 315 316 p = (*sfvi); 317 radius = args.generateRadius(); 318 depth = args.generateDepth(); 319 CratersUtils<MeshType>::GetCraterFaces(args.target_mesh, p.second, p.first, radius, craterFaces); 320 CratersUtils<MeshType>::ComputeRadialPerturbation(args, p.first, craterFaces, radius, depth, h); 321 } 322 323 for(VertexIterator vi=args.target_mesh->vert.begin(); vi!=args.target_mesh->vert.end(); ++vi) 324 { 325 if(h[vi] == .0) continue; 326 327 if(args.save_as_quality) 328 { 329 (*vi).Q() = h[vi]; 330 } else 331 { 332 (*vi).P() += ((*vi).N() * h[vi]); 333 } 334 } 335 336 // updates bounding box and normals 337 tri::Allocator<MeshType>::DeletePerVertexAttribute(*(args.target_mesh), std::string("perturbation")); 338 vcg::tri::UpdateBounding<MeshType>::Box(*(args.target_mesh)); 339 vcg::tri::UpdateNormal<MeshType>::PerVertexNormalizedPerFaceNormalized(*(args.target_mesh)); 340 return true; 341 } 342 }; 343 344 #endif // CRATERS_UTILS_H 345