Blender V2.61 - r43446
|
00001 00015 #include "MEM_guardedalloc.h" 00016 00017 #include <math.h> 00018 #include <stdio.h> 00019 00020 #include "BLI_blenlib.h" 00021 #include "BLI_math.h" 00022 #include "BLI_kdtree.h" 00023 #include "BLI_threads.h" 00024 #include "BLI_utildefines.h" 00025 00026 #include "DNA_anim_types.h" 00027 #include "DNA_constraint_types.h" 00028 #include "DNA_dynamicpaint_types.h" 00029 #include "DNA_group_types.h" /*GroupObject*/ 00030 #include "DNA_material_types.h" 00031 #include "DNA_mesh_types.h" 00032 #include "DNA_meshdata_types.h" 00033 #include "DNA_modifier_types.h" 00034 #include "DNA_object_types.h" 00035 #include "DNA_scene_types.h" 00036 #include "DNA_space_types.h" 00037 #include "DNA_texture_types.h" 00038 00039 #include "BKE_animsys.h" 00040 #include "BKE_bvhutils.h" /* bvh tree */ 00041 #include "BKE_blender.h" 00042 #include "BKE_cdderivedmesh.h" 00043 #include "BKE_constraint.h" 00044 #include "BKE_context.h" 00045 #include "BKE_customdata.h" 00046 #include "BKE_colortools.h" 00047 #include "BKE_deform.h" 00048 #include "BKE_depsgraph.h" 00049 #include "BKE_DerivedMesh.h" 00050 #include "BKE_dynamicpaint.h" 00051 #include "BKE_effect.h" 00052 #include "BKE_global.h" 00053 #include "BKE_image.h" 00054 #include "BKE_main.h" 00055 #include "BKE_material.h" 00056 #include "BKE_modifier.h" 00057 #include "BKE_object.h" 00058 #include "BKE_particle.h" 00059 #include "BKE_pointcache.h" 00060 #include "BKE_scene.h" 00061 #include "BKE_texture.h" 00062 00063 #include "RNA_access.h" 00064 #include "RNA_define.h" 00065 #include "RNA_enum_types.h" 00066 00067 /* for image output */ 00068 #include "IMB_imbuf_types.h" 00069 #include "IMB_imbuf.h" 00070 00071 /* to read material/texture color */ 00072 #include "RE_render_ext.h" 00073 #include "RE_shader_ext.h" 00074 00075 #ifdef _OPENMP 00076 #include <omp.h> 00077 #endif 00078 00079 /* precalculated gaussian factors for 5x super sampling */ 00080 static float gaussianFactors[5] = { 0.996849f, 00081 0.596145f, 00082 0.596145f, 00083 0.596145f, 00084 0.524141f}; 00085 static float gaussianTotal = 3.309425f; 00086 00087 /* UV Image neighbouring pixel table x and y list */ 00088 static int neighX[8] = {1,1,0,-1,-1,-1, 0, 1}; 00089 static int neighY[8] = {0,1,1, 1, 0,-1,-1,-1}; 00090 00091 /* subframe_updateObject() flags */ 00092 #define UPDATE_PARENTS (1<<0) 00093 #define UPDATE_MESH (1<<1) 00094 #define UPDATE_EVERYTHING (UPDATE_PARENTS|UPDATE_MESH) 00095 /* surface_getBrushFlags() return vals */ 00096 #define BRUSH_USES_VELOCITY (1<<0) 00097 /* brush mesh raycast status */ 00098 #define HIT_VOLUME 1 00099 #define HIT_PROXIMITY 2 00100 /* paint effect default movement per frame in global units */ 00101 #define EFF_MOVEMENT_PER_FRAME 0.05f 00102 /* initial wave time factor */ 00103 #define WAVE_TIME_FAC (1.0f/24.f) 00104 #define CANVAS_REL_SIZE 5.0f 00105 /* drying limits */ 00106 #define MIN_WETNESS 0.001f 00107 #define MAX_WETNESS 5.0f 00108 /* dissolve macro */ 00109 #define VALUE_DISSOLVE(VALUE, TIME, SCALE, LOG) (VALUE) = (LOG) ? (VALUE) * (pow(MIN_WETNESS,1.0f/(1.2f*((float)(TIME))/(SCALE)))) : (VALUE) - 1.0f/(TIME)*(SCALE) 00110 00111 /***************************** Internal Structs ***************************/ 00112 00113 typedef struct Bounds2D { 00114 float min[2], max[2]; 00115 } Bounds2D; 00116 00117 typedef struct Bounds3D { 00118 int valid; 00119 float min[3], max[3]; 00120 } Bounds3D; 00121 00122 typedef struct VolumeGrid { 00123 int dim[3]; 00124 Bounds3D grid_bounds; /* whole grid bounds */ 00125 00126 Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */ 00127 int *s_pos; /* (x*y*z) t_index begin id */ 00128 int *s_num; /* (x*y*z) number of t_index points */ 00129 int *t_index; /* actual surface point index, 00130 access: (s_pos+s_num) */ 00131 } VolumeGrid; 00132 00133 typedef struct Vec3f { 00134 float v[3]; 00135 } Vec3f; 00136 00137 typedef struct BakeNeighPoint { 00138 float dir[3]; /* vector pointing towards this neighbour */ 00139 float dist; /* distance to */ 00140 } BakeNeighPoint; 00141 00142 /* Surface data used while processing a frame */ 00143 typedef struct PaintBakeNormal { 00144 float invNorm[3]; /* current pixel world-space inverted normal */ 00145 float normal_scale; /* normal directional scale for displace mapping */ 00146 } PaintBakeNormal; 00147 00148 /* Temp surface data used to process a frame */ 00149 typedef struct PaintBakeData { 00150 /* point space data */ 00151 PaintBakeNormal *bNormal; 00152 int *s_pos; /* index to start reading point sample realCoord */ 00153 int *s_num; /* num of realCoord samples */ 00154 Vec3f *realCoord; /* current pixel center world-space coordinates for each sample 00155 * ordered as (s_pos+s_num)*/ 00156 Bounds3D mesh_bounds; 00157 00158 /* adjacency info */ 00159 BakeNeighPoint *bNeighs; /* current global neighbour distances and directions, if required */ 00160 double average_dist; 00161 /* space partitioning */ 00162 VolumeGrid *grid; /* space partitioning grid to optimize brush checks */ 00163 00164 /* velocity and movement */ 00165 Vec3f *velocity; /* speed vector in global space movement per frame, if required */ 00166 Vec3f *prev_velocity; 00167 float *brush_velocity; /* special temp data for post-p velocity based brushes like smudge 00168 * 3 float dir vec + 1 float str */ 00169 MVert *prev_verts; /* copy of previous frame vertices. used to observe surface movement */ 00170 float prev_obmat[4][4]; /* previous frame object matrix */ 00171 int clear; /* flag to check if surface was cleared/reset -> have to redo velocity etc. */ 00172 00173 } PaintBakeData; 00174 00175 /* UV Image sequence format point */ 00176 typedef struct PaintUVPoint { 00177 /* Pixel / mesh data */ 00178 unsigned int face_index, pixel_index; /* face index on domain derived mesh */ 00179 unsigned int v1, v2, v3; /* vertex indexes */ 00180 00181 unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face, 00182 but it's neighbouring pixel is */ 00183 short quad; 00184 } PaintUVPoint; 00185 00186 typedef struct ImgSeqFormatData { 00187 PaintUVPoint *uv_p; 00188 Vec3f *barycentricWeights; /* b-weights for all pixel samples */ 00189 } ImgSeqFormatData; 00190 00191 typedef struct EffVelPoint { 00192 float previous_pos[3]; 00193 float previous_vel[3]; 00194 } EffVelPoint; 00195 00196 00197 /* adjacency data flags */ 00198 #define ADJ_ON_MESH_EDGE (1<<0) 00199 00200 typedef struct PaintAdjData { 00201 int *n_target; /* array of neighbouring point indexes, 00202 for single sample use (n_index+neigh_num) */ 00203 int *n_index; /* index to start reading n_target for each point */ 00204 int *n_num; /* num of neighs for each point */ 00205 int *flags; /* vertex adjacency flags */ 00206 int total_targets; /* size of n_target */ 00207 } PaintAdjData; 00208 00209 /***************************** General Utils ******************************/ 00210 00211 /* Set canvas error string to display at the bake report */ 00212 static int setError(DynamicPaintCanvasSettings *canvas, const char *string) 00213 { 00214 /* Add error to canvas ui info label */ 00215 BLI_strncpy(canvas->error, string, sizeof(canvas->error)); 00216 return 0; 00217 } 00218 00219 /* Get number of surface points for cached types */ 00220 static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface) 00221 { 00222 if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) { 00223 return 0; /* not supported atm */ 00224 } 00225 else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { 00226 if (!surface->canvas->dm) return 0; /* invalid derived mesh */ 00227 return surface->canvas->dm->getNumVerts(surface->canvas->dm); 00228 } 00229 else 00230 return 0; 00231 } 00232 00233 /* checks whether surface's format/type has realtime preview */ 00234 int dynamicPaint_surfaceHasColorPreview(DynamicPaintSurface *surface) 00235 { 00236 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return 0; 00237 else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { 00238 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || 00239 surface->type == MOD_DPAINT_SURFACE_T_WAVE) return 0; 00240 else return 1; 00241 } 00242 else return 1; 00243 } 00244 00245 /* get currently active surface (in user interface) */ 00246 struct DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas) 00247 { 00248 DynamicPaintSurface *surface = canvas->surfaces.first; 00249 int i; 00250 00251 for(i=0; surface; surface=surface->next) { 00252 if(i == canvas->active_sur) 00253 return surface; 00254 i++; 00255 } 00256 return NULL; 00257 } 00258 00259 /* set preview to first previewable surface */ 00260 void dynamicPaint_resetPreview(DynamicPaintCanvasSettings *canvas) 00261 { 00262 DynamicPaintSurface *surface = canvas->surfaces.first; 00263 int done=0; 00264 00265 for(; surface; surface=surface->next) { 00266 if (!done && dynamicPaint_surfaceHasColorPreview(surface)) { 00267 surface->flags |= MOD_DPAINT_PREVIEW; 00268 done=1; 00269 } 00270 else 00271 surface->flags &= ~MOD_DPAINT_PREVIEW; 00272 } 00273 } 00274 00275 /* set preview to defined surface */ 00276 static void dynamicPaint_setPreview(DynamicPaintSurface *t_surface) 00277 { 00278 DynamicPaintSurface *surface = t_surface->canvas->surfaces.first; 00279 for(; surface; surface=surface->next) { 00280 if (surface == t_surface) 00281 surface->flags |= MOD_DPAINT_PREVIEW; 00282 else 00283 surface->flags &= ~MOD_DPAINT_PREVIEW; 00284 } 00285 } 00286 00287 int dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object *ob, int output) 00288 { 00289 char *name; 00290 00291 if (output == 0) 00292 name = surface->output_name; 00293 else if (output == 1) 00294 name = surface->output_name2; 00295 else 00296 return 0; 00297 00298 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { 00299 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { 00300 Mesh *me = ob->data; 00301 return (CustomData_get_named_layer_index(&me->fdata, CD_MCOL, name) != -1); 00302 } 00303 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) 00304 return (defgroup_name_index(ob, surface->output_name) != -1); 00305 } 00306 00307 return 0; 00308 } 00309 00310 static int surface_duplicateOutputExists(void *arg, const char *name) 00311 { 00312 DynamicPaintSurface *t_surface = (DynamicPaintSurface*)arg; 00313 DynamicPaintSurface *surface = t_surface->canvas->surfaces.first; 00314 00315 for(; surface; surface=surface->next) { 00316 if (surface!=t_surface && surface->type==t_surface->type && 00317 surface->format==t_surface->format) { 00318 if (surface->output_name[0]!='\0' && !strcmp(name, surface->output_name)) return 1; 00319 if (surface->output_name2[0]!='\0' && !strcmp(name, surface->output_name2)) return 1; 00320 } 00321 } 00322 return 0; 00323 } 00324 00325 static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *basename, int output) 00326 { 00327 char name[64]; 00328 BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */ 00329 if (!output) 00330 BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.', surface->output_name, sizeof(surface->output_name)); 00331 if (output) 00332 BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.', surface->output_name2, sizeof(surface->output_name2)); 00333 } 00334 00335 00336 static int surface_duplicateNameExists(void *arg, const char *name) 00337 { 00338 DynamicPaintSurface *t_surface = (DynamicPaintSurface*)arg; 00339 DynamicPaintSurface *surface = t_surface->canvas->surfaces.first; 00340 00341 for(; surface; surface=surface->next) { 00342 if (surface!=t_surface && !strcmp(name, surface->name)) return 1; 00343 } 00344 return 0; 00345 } 00346 00347 void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char *basename) 00348 { 00349 char name[64]; 00350 BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */ 00351 BLI_uniquename_cb(surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name)); 00352 } 00353 00354 00355 /* change surface data to defaults on new type */ 00356 void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface) 00357 { 00358 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) { 00359 surface->output_name[0]='\0'; 00360 surface->output_name2[0]='\0'; 00361 surface->flags |= MOD_DPAINT_ANTIALIAS; 00362 surface->depth_clamp = 1.0f; 00363 } 00364 else { 00365 strcpy(surface->output_name, "dp_"); 00366 strcpy(surface->output_name2, surface->output_name); 00367 surface->flags &= ~MOD_DPAINT_ANTIALIAS; 00368 surface->depth_clamp = 0.0f; 00369 } 00370 00371 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { 00372 strcat(surface->output_name,"paintmap"); 00373 strcat(surface->output_name2,"wetmap"); 00374 surface_setUniqueOutputName(surface, surface->output_name2, 1); 00375 } 00376 else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) { 00377 strcat(surface->output_name,"displace"); 00378 } 00379 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) { 00380 strcat(surface->output_name,"weight"); 00381 } 00382 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) { 00383 strcat(surface->output_name,"wave"); 00384 } 00385 00386 surface_setUniqueOutputName(surface, surface->output_name, 0); 00387 00388 /* update preview */ 00389 if (dynamicPaint_surfaceHasColorPreview(surface)) 00390 dynamicPaint_setPreview(surface); 00391 else 00392 dynamicPaint_resetPreview(surface->canvas); 00393 } 00394 00395 static int surface_totalSamples(DynamicPaintSurface *surface) 00396 { 00397 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ && 00398 surface->flags & MOD_DPAINT_ANTIALIAS) 00399 return (surface->data->total_points*5); 00400 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && 00401 surface->flags & MOD_DPAINT_ANTIALIAS && surface->data->adj_data) 00402 return (surface->data->total_points+surface->data->adj_data->total_targets); 00403 00404 return surface->data->total_points; 00405 } 00406 00407 static void blendColors(float t_color[3], float t_alpha, float s_color[3], float s_alpha, float result[4]) 00408 { 00409 int i; 00410 float i_alpha = 1.0f - s_alpha; 00411 float f_alpha = t_alpha*i_alpha + s_alpha; 00412 00413 /* blend colors */ 00414 if (f_alpha) { 00415 for (i=0; i<3; i++) { 00416 result[i] = (t_color[i]*t_alpha*i_alpha + s_color[i]*s_alpha)/f_alpha; 00417 } 00418 } 00419 else { 00420 copy_v3_v3(result, t_color); 00421 } 00422 /* return final alpha */ 00423 result[3] = f_alpha; 00424 } 00425 00426 /* Mix two alpha weighed colors by a defined ratio. output is saved at a_color */ 00427 static float mixColors(float a_color[3], float a_weight, float b_color[3], float b_weight, float ratio) 00428 { 00429 float weight_ratio, factor; 00430 if (b_weight) { 00431 /* if first value has no weight just use b_color */ 00432 if (!a_weight) { 00433 copy_v3_v3(a_color, b_color); 00434 return b_weight*ratio; 00435 } 00436 weight_ratio = b_weight/(a_weight+b_weight); 00437 } 00438 else return a_weight*(1.0f-ratio); 00439 00440 /* calculate final interpolation factor */ 00441 if (ratio<=0.5f) { 00442 factor = weight_ratio*(ratio*2.0f); 00443 } 00444 else { 00445 ratio = (ratio*2.0f - 1.0f); 00446 factor = weight_ratio*(1.0f-ratio) + ratio; 00447 } 00448 /* mix final color */ 00449 interp_v3_v3v3(a_color, a_color, b_color, factor); 00450 return (1.0f-factor)*a_weight + factor*b_weight; 00451 } 00452 00453 /* set "ignore cache" flag for all caches on this object */ 00454 static void object_cacheIgnoreClear(Object *ob, int state) 00455 { 00456 ListBase pidlist; 00457 PTCacheID *pid; 00458 BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0); 00459 00460 for(pid=pidlist.first; pid; pid=pid->next) { 00461 if(pid->cache) { 00462 if (state) 00463 pid->cache->flag |= PTCACHE_IGNORE_CLEAR; 00464 else 00465 pid->cache->flag &= ~PTCACHE_IGNORE_CLEAR; 00466 } 00467 } 00468 00469 BLI_freelistN(&pidlist); 00470 } 00471 00472 static void subframe_updateObject(Scene *scene, Object *ob, int flags, float frame) 00473 { 00474 DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint); 00475 bConstraint *con; 00476 00477 /* if other is dynamic paint canvas, dont update */ 00478 if (pmd && pmd->canvas) 00479 return; 00480 00481 /* if object has parents, update them too */ 00482 if (flags & UPDATE_PARENTS) { 00483 if (ob->parent) subframe_updateObject(scene, ob->parent, 0, frame); 00484 if (ob->track) subframe_updateObject(scene, ob->track, 0, frame); 00485 00486 /* also update constraint targets */ 00487 for (con = ob->constraints.first; con; con=con->next) { 00488 bConstraintTypeInfo *cti= constraint_get_typeinfo(con); 00489 ListBase targets = {NULL, NULL}; 00490 00491 if (cti && cti->get_constraint_targets) { 00492 bConstraintTarget *ct; 00493 cti->get_constraint_targets(con, &targets); 00494 for (ct= targets.first; ct; ct= ct->next) { 00495 if (ct->tar) 00496 subframe_updateObject(scene, ct->tar, 0, frame); 00497 } 00498 /* free temp targets */ 00499 if (cti->flush_constraint_targets) 00500 cti->flush_constraint_targets(con, &targets, 0); 00501 } 00502 } 00503 } 00504 /* for curve following objects, parented curve has to be updated too */ 00505 if(ob->type==OB_CURVE) { 00506 Curve *cu= ob->data; 00507 BKE_animsys_evaluate_animdata(scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM); 00508 } 00509 00510 ob->recalc |= OB_RECALC_ALL; 00511 BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM); 00512 if (flags & UPDATE_MESH) { 00513 /* ignore cache clear during subframe updates 00514 * to not mess up cache validity */ 00515 object_cacheIgnoreClear(ob, 1); 00516 object_handle_update(scene, ob); 00517 object_cacheIgnoreClear(ob, 0); 00518 } 00519 else 00520 where_is_object_time(scene, ob, frame); 00521 } 00522 00523 static void scene_setSubframe(Scene *scene, float subframe) 00524 { 00525 /* dynamic paint subframes must be done on previous frame */ 00526 scene->r.cfra -= 1; 00527 scene->r.subframe = subframe; 00528 } 00529 00530 static int surface_getBrushFlags(DynamicPaintSurface *surface, Scene *scene) 00531 { 00532 Base *base = NULL; 00533 GroupObject *go = NULL; 00534 Object *brushObj = NULL; 00535 ModifierData *md = NULL; 00536 00537 int flags = 0; 00538 00539 if(surface->brush_group) 00540 go = surface->brush_group->gobject.first; 00541 else 00542 base = scene->base.first; 00543 00544 while (base || go) 00545 { 00546 brushObj = NULL; 00547 00548 /* select object */ 00549 if(surface->brush_group) { 00550 if(go->ob) brushObj = go->ob; 00551 } 00552 else 00553 brushObj = base->object; 00554 00555 if(!brushObj) 00556 { 00557 if(surface->brush_group) go = go->next; 00558 else base= base->next; 00559 continue; 00560 } 00561 00562 if(surface->brush_group) 00563 go = go->next; 00564 else 00565 base= base->next; 00566 00567 md = modifiers_findByType(brushObj, eModifierType_DynamicPaint); 00568 if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) 00569 { 00570 DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md; 00571 00572 if (pmd2->brush) 00573 { 00574 DynamicPaintBrushSettings *brush = pmd2->brush; 00575 00576 if (brush->flags & MOD_DPAINT_USES_VELOCITY) 00577 flags |= BRUSH_USES_VELOCITY; 00578 } 00579 } 00580 } 00581 00582 return flags; 00583 } 00584 00585 static int brush_usesMaterial(DynamicPaintBrushSettings *brush, Scene *scene) 00586 { 00587 return ((brush->flags & MOD_DPAINT_USE_MATERIAL) && (!strcmp(scene->r.engine, "BLENDER_RENDER"))); 00588 } 00589 00590 /* check whether two bounds intersect */ 00591 static int boundsIntersect(Bounds3D *b1, Bounds3D *b2) 00592 { 00593 int i=2; 00594 if (!b1->valid || !b2->valid) return 0; 00595 for (; i>=0; i-=1) 00596 if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i])) return 0; 00597 return 1; 00598 } 00599 00600 /* check whether two bounds intersect inside defined proximity */ 00601 static int boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, float dist) 00602 { 00603 int i=2; 00604 if (!b1->valid || !b2->valid) return 0; 00605 for (; i>=0; i-=1) 00606 if (!(b1->min[i] <= (b2->max[i]+dist) && b1->max[i] >= (b2->min[i]-dist))) return 0; 00607 return 1; 00608 } 00609 00610 /* check whether bounds intersects a point with given radius */ 00611 static int boundIntersectPoint(Bounds3D *b, float point[3], float radius) 00612 { 00613 int i=2; 00614 if (!b->valid) return 0; 00615 for (; i>=0; i-=1) 00616 if (!(b->min[i] <= (point[i]+radius) && b->max[i] >= (point[i]-radius))) return 0; 00617 return 1; 00618 } 00619 00620 /* expand bounds by a new point */ 00621 static void boundInsert(Bounds3D *b, float point[3]) 00622 { 00623 int i=2; 00624 if (!b->valid) { 00625 copy_v3_v3(b->min, point); 00626 copy_v3_v3(b->max, point); 00627 b->valid = 1; 00628 } 00629 else { 00630 for (; i>=0; i-=1) { 00631 if (point[i] < b->min[i]) b->min[i]=point[i]; 00632 if (point[i] > b->max[i]) b->max[i]=point[i]; 00633 } 00634 } 00635 } 00636 00637 float getSurfaceDimension(PaintSurfaceData *sData) 00638 { 00639 Bounds3D *mb = &sData->bData->mesh_bounds; 00640 return MAX3((mb->max[0]-mb->min[0]), (mb->max[1]-mb->min[1]), (mb->max[2]-mb->min[2])); 00641 } 00642 00643 static void freeGrid(PaintSurfaceData *data) 00644 { 00645 PaintBakeData *bData = data->bData; 00646 VolumeGrid *grid = bData->grid; 00647 00648 if (grid->bounds) MEM_freeN(grid->bounds); 00649 if (grid->s_pos) MEM_freeN(grid->s_pos); 00650 if (grid->s_num) MEM_freeN(grid->s_num); 00651 if (grid->t_index) MEM_freeN(grid->t_index); 00652 00653 MEM_freeN(bData->grid); 00654 bData->grid = NULL; 00655 } 00656 00657 static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) 00658 { 00659 PaintSurfaceData *sData = surface->data; 00660 PaintBakeData *bData = sData->bData; 00661 Bounds3D *grid_bounds; 00662 VolumeGrid *grid; 00663 int grid_cells, axis = 3; 00664 int *temp_t_index = NULL; 00665 int *temp_s_num = NULL; 00666 00667 #ifdef _OPENMP 00668 int num_of_threads = omp_get_max_threads(); 00669 #else 00670 int num_of_threads = 1; 00671 #endif 00672 00673 if (bData->grid) 00674 freeGrid(sData); 00675 00676 /* allocate separate bounds for each thread */ 00677 grid_bounds = MEM_callocN(sizeof(Bounds3D)*num_of_threads, "Grid Bounds"); 00678 bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid"); 00679 grid = bData->grid; 00680 00681 if (grid && grid_bounds) { 00682 int i, error = 0; 00683 float dim_factor, volume, dim[3]; 00684 float td[3]; 00685 float min_dim; 00686 00687 /* calculate canvas dimensions */ 00688 #pragma omp parallel for schedule(static) 00689 for (i=0; i<sData->total_points; i++) { 00690 #ifdef _OPENMP 00691 int id = omp_get_thread_num(); 00692 boundInsert(&grid_bounds[id], (bData->realCoord[bData->s_pos[i]].v)); 00693 #else 00694 boundInsert(&grid_bounds[0], (bData->realCoord[bData->s_pos[i]].v)); 00695 #endif 00696 } 00697 00698 /* get final dimensions */ 00699 for (i=0; i<num_of_threads; i++) { 00700 boundInsert(&grid->grid_bounds, grid_bounds[i].min); 00701 boundInsert(&grid->grid_bounds, grid_bounds[i].max); 00702 } 00703 00704 /* get dimensions */ 00705 sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min); 00706 copy_v3_v3(td, dim); 00707 min_dim = MAX3(td[0],td[1],td[2]) / 1000.f; 00708 00709 /* deactivate zero axises */ 00710 for (i=0; i<3; i++) { 00711 if (td[i]<min_dim) {td[i]=1.0f; axis-=1;} 00712 } 00713 00714 if (axis == 0 || MAX3(td[0],td[1],td[2]) < 0.0001f) { 00715 MEM_freeN(grid_bounds); 00716 MEM_freeN(bData->grid); 00717 bData->grid = NULL; 00718 return; 00719 } 00720 00721 /* now calculate grid volume/area/width depending on num of active axis */ 00722 volume = td[0]*td[1]*td[2]; 00723 00724 /* determine final grid size by trying to fit average 10.000 points per grid cell */ 00725 dim_factor = (float)pow(volume / ((double)sData->total_points / 10000.0), 1.0/(double)axis); 00726 00727 /* define final grid size using dim_factor, use min 3 for active axises */ 00728 for (i=0; i<3; i++) { 00729 grid->dim[i] = (int)floor(td[i] / dim_factor); 00730 CLAMP(grid->dim[i], (dim[i]>=min_dim) ? 3 : 1, 100); 00731 } 00732 grid_cells = grid->dim[0]*grid->dim[1]*grid->dim[2]; 00733 00734 /* allocate memory for grids */ 00735 grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds"); 00736 grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position"); 00737 grid->s_num = MEM_callocN(sizeof(int) * grid_cells*num_of_threads, "Surface Grid Points"); 00738 temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points"); 00739 grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids"); 00740 temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids"); 00741 00742 /* in case of an allocation failture abort here */ 00743 if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num || !temp_t_index) 00744 error = 1; 00745 00746 if (!error) { 00747 /* calculate number of points withing each cell */ 00748 #pragma omp parallel for schedule(static) 00749 for (i=0; i<sData->total_points; i++) { 00750 int co[3], j; 00751 for (j=0; j<3; j++) { 00752 co[j] = (int)floor((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j])/dim[j]*grid->dim[j]); 00753 CLAMP(co[j], 0, grid->dim[j]-1); 00754 } 00755 00756 temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0]*grid->dim[1]; 00757 #ifdef _OPENMP 00758 grid->s_num[temp_t_index[i]+omp_get_thread_num()*grid_cells]++; 00759 #else 00760 grid->s_num[temp_t_index[i]]++; 00761 #endif 00762 } 00763 00764 /* for first cell only calc s_num */ 00765 for (i=1; i<num_of_threads; i++) { 00766 grid->s_num[0] += grid->s_num[i*grid_cells]; 00767 } 00768 00769 /* calculate grid indexes */ 00770 for (i=1; i<grid_cells; i++) { 00771 int id; 00772 for (id=1; id<num_of_threads; id++) { 00773 grid->s_num[i] += grid->s_num[i+id*grid_cells]; 00774 } 00775 grid->s_pos[i] = grid->s_pos[i-1] + grid->s_num[i-1]; 00776 } 00777 00778 /* save point indexes to final array */ 00779 for (i=0; i<sData->total_points; i++) { 00780 int pos = grid->s_pos[temp_t_index[i]] + temp_s_num[temp_t_index[i]]; 00781 grid->t_index[pos] = i; 00782 00783 temp_s_num[temp_t_index[i]]++; 00784 } 00785 00786 /* calculate cell bounds */ 00787 { 00788 int x; 00789 #pragma omp parallel for schedule(static) 00790 for (x=0; x<grid->dim[0]; x++) { 00791 int y; 00792 for (y=0; y<grid->dim[1]; y++) { 00793 int z; 00794 for (z=0; z<grid->dim[2]; z++) { 00795 int j, b_index = x + y * grid->dim[0] + z * grid->dim[0]*grid->dim[1]; 00796 /* set bounds */ 00797 for (j=0; j<3; j++) { 00798 int s = (j==0) ? x : ((j==1) ? y : z); 00799 grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j]/grid->dim[j]*s; 00800 grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j]/grid->dim[j]*(s+1); 00801 } 00802 grid->bounds[b_index].valid = 1; 00803 } 00804 } 00805 } 00806 } 00807 } 00808 00809 if (temp_s_num) MEM_freeN(temp_s_num); 00810 if (temp_t_index) MEM_freeN(temp_t_index); 00811 00812 /* free per thread s_num values */ 00813 grid->s_num = MEM_reallocN(grid->s_num, sizeof(int) * grid_cells); 00814 00815 if (error || !grid->s_num) { 00816 setError(surface->canvas, "Not enough free memory."); 00817 freeGrid(sData); 00818 } 00819 } 00820 00821 if (grid_bounds) MEM_freeN(grid_bounds); 00822 } 00823 00824 /***************************** Freeing data ******************************/ 00825 00826 /* Free brush data */ 00827 void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd) 00828 { 00829 if(pmd->brush) { 00830 if(pmd->brush->dm) 00831 pmd->brush->dm->release(pmd->brush->dm); 00832 pmd->brush->dm = NULL; 00833 00834 if(pmd->brush->paint_ramp) 00835 MEM_freeN(pmd->brush->paint_ramp); 00836 pmd->brush->paint_ramp = NULL; 00837 if(pmd->brush->vel_ramp) 00838 MEM_freeN(pmd->brush->vel_ramp); 00839 pmd->brush->vel_ramp = NULL; 00840 00841 MEM_freeN(pmd->brush); 00842 pmd->brush = NULL; 00843 } 00844 } 00845 00846 static void dynamicPaint_freeAdjData(PaintSurfaceData *data) 00847 { 00848 if (data->adj_data) { 00849 if (data->adj_data->n_index) MEM_freeN(data->adj_data->n_index); 00850 if (data->adj_data->n_num) MEM_freeN(data->adj_data->n_num); 00851 if (data->adj_data->n_target) MEM_freeN(data->adj_data->n_target); 00852 if (data->adj_data->flags) MEM_freeN(data->adj_data->flags); 00853 MEM_freeN(data->adj_data); 00854 data->adj_data = NULL; 00855 } 00856 } 00857 00858 static void free_bakeData(PaintSurfaceData *data) 00859 { 00860 PaintBakeData *bData = data->bData; 00861 if (bData) { 00862 if (bData->bNormal) MEM_freeN(bData->bNormal); 00863 if (bData->s_pos) MEM_freeN(bData->s_pos); 00864 if (bData->s_num) MEM_freeN(bData->s_num); 00865 if (bData->realCoord) MEM_freeN(bData->realCoord); 00866 if (bData->bNeighs) MEM_freeN(bData->bNeighs); 00867 if (bData->grid) freeGrid(data); 00868 if (bData->prev_verts) MEM_freeN(bData->prev_verts); 00869 if (bData->velocity) MEM_freeN(bData->velocity); 00870 if (bData->prev_velocity) MEM_freeN(bData->prev_velocity); 00871 00872 MEM_freeN(data->bData); 00873 data->bData = NULL; 00874 } 00875 } 00876 00877 /* free surface data if it's not used anymore */ 00878 void surface_freeUnusedData(DynamicPaintSurface *surface) 00879 { 00880 if (!surface->data) return; 00881 00882 /* free bakedata if not active or surface is baked */ 00883 if (!(surface->flags & MOD_DPAINT_ACTIVE) || 00884 (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED)) 00885 free_bakeData(surface->data); 00886 } 00887 00888 void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface) 00889 { 00890 PaintSurfaceData *data = surface->data; 00891 if (!data) return; 00892 if (data->format_data) { 00893 /* format specific free */ 00894 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) { 00895 ImgSeqFormatData *format_data = (ImgSeqFormatData*)data->format_data; 00896 if (format_data->uv_p) 00897 MEM_freeN(format_data->uv_p); 00898 if (format_data->barycentricWeights) 00899 MEM_freeN(format_data->barycentricWeights); 00900 } 00901 MEM_freeN(data->format_data); 00902 } 00903 /* type data */ 00904 if (data->type_data) MEM_freeN(data->type_data); 00905 dynamicPaint_freeAdjData(data); 00906 /* bake data */ 00907 free_bakeData(data); 00908 00909 MEM_freeN(surface->data); 00910 surface->data = NULL; 00911 } 00912 00913 void dynamicPaint_freeSurface(DynamicPaintSurface *surface) 00914 { 00915 /* point cache */ 00916 BKE_ptcache_free_list(&(surface->ptcaches)); 00917 surface->pointcache = NULL; 00918 00919 if(surface->effector_weights) 00920 MEM_freeN(surface->effector_weights); 00921 surface->effector_weights = NULL; 00922 00923 BLI_remlink(&(surface->canvas->surfaces), surface); 00924 dynamicPaint_freeSurfaceData(surface); 00925 MEM_freeN(surface); 00926 } 00927 00928 /* Free canvas data */ 00929 void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd) 00930 { 00931 if(pmd->canvas) { 00932 /* Free surface data */ 00933 DynamicPaintSurface *surface = pmd->canvas->surfaces.first; 00934 DynamicPaintSurface *next_surface = NULL; 00935 00936 while (surface) { 00937 next_surface = surface->next; 00938 dynamicPaint_freeSurface(surface); 00939 surface = next_surface; 00940 } 00941 00942 /* free dm copy */ 00943 if (pmd->canvas->dm) 00944 pmd->canvas->dm->release(pmd->canvas->dm); 00945 pmd->canvas->dm = NULL; 00946 00947 MEM_freeN(pmd->canvas); 00948 pmd->canvas = NULL; 00949 } 00950 } 00951 00952 /* Free whole dp modifier */ 00953 void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd) 00954 { 00955 if(pmd) { 00956 dynamicPaint_freeCanvas(pmd); 00957 dynamicPaint_freeBrush(pmd); 00958 } 00959 } 00960 00961 00962 /***************************** Initialize and reset ******************************/ 00963 00964 /* 00965 * Creates a new surface and adds it to the list 00966 * If scene is null, frame range of 1-250 is used 00967 * A pointer to this surface is returned 00968 */ 00969 struct DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas, Scene *scene) 00970 { 00971 DynamicPaintSurface *surface= MEM_callocN(sizeof(DynamicPaintSurface), "DynamicPaintSurface"); 00972 if (!surface) return NULL; 00973 00974 surface->canvas = canvas; 00975 surface->format = MOD_DPAINT_SURFACE_F_VERTEX; 00976 surface->type = MOD_DPAINT_SURFACE_T_PAINT; 00977 00978 /* cache */ 00979 surface->pointcache = BKE_ptcache_add(&(surface->ptcaches)); 00980 surface->pointcache->flag |= PTCACHE_DISK_CACHE; 00981 surface->pointcache->step = 1; 00982 00983 /* Set initial values */ 00984 surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG | MOD_DPAINT_DISSOLVE_LOG | 00985 MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW | MOD_DPAINT_OUT1 | MOD_DPAINT_USE_DRYING; 00986 surface->effect = 0; 00987 surface->effect_ui = 1; 00988 00989 surface->diss_speed = 250; 00990 surface->dry_speed = 500; 00991 surface->color_dry_threshold = 1.0f; 00992 surface->depth_clamp = 0.0f; 00993 surface->disp_factor = 1.0f; 00994 surface->disp_type = MOD_DPAINT_DISP_DISPLACE; 00995 surface->image_fileformat = MOD_DPAINT_IMGFORMAT_PNG; 00996 00997 surface->influence_scale = 1.0f; 00998 surface->radius_scale = 1.0f; 00999 01000 surface->init_color[0] = 1.0f; 01001 surface->init_color[1] = 1.0f; 01002 surface->init_color[2] = 1.0f; 01003 surface->init_color[3] = 1.0f; 01004 01005 surface->image_resolution = 256; 01006 surface->substeps = 0; 01007 01008 if (scene) { 01009 surface->start_frame = scene->r.sfra; 01010 surface->end_frame = scene->r.efra; 01011 } 01012 else { 01013 surface->start_frame = 1; 01014 surface->end_frame = 250; 01015 } 01016 01017 surface->spread_speed = 1.0f; 01018 surface->color_spread_speed = 1.0f; 01019 surface->shrink_speed = 1.0f; 01020 01021 surface->wave_damping = 0.04f; 01022 surface->wave_speed = 1.0f; 01023 surface->wave_timescale = 1.0f; 01024 surface->wave_spring = 0.20f; 01025 01026 modifier_path_init(surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint"); 01027 01028 dynamicPaintSurface_setUniqueName(surface, "Surface"); 01029 01030 surface->effector_weights = BKE_add_effector_weights(NULL); 01031 01032 dynamicPaintSurface_updateType(surface); 01033 01034 BLI_addtail(&canvas->surfaces, surface); 01035 01036 return surface; 01037 } 01038 01039 /* 01040 * Initialize modifier data 01041 */ 01042 int dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene) 01043 { 01044 if(pmd) { 01045 if(type == MOD_DYNAMICPAINT_TYPE_CANVAS) { 01046 DynamicPaintCanvasSettings *canvas; 01047 if(pmd->canvas) 01048 dynamicPaint_freeCanvas(pmd); 01049 01050 canvas = pmd->canvas = MEM_callocN(sizeof(DynamicPaintCanvasSettings), "DynamicPaint Canvas"); 01051 if (!canvas) 01052 return 0; 01053 canvas->pmd = pmd; 01054 canvas->dm = NULL; 01055 01056 /* Create one surface */ 01057 if (!dynamicPaint_createNewSurface(canvas, scene)) 01058 return 0; 01059 01060 } 01061 else if(type == MOD_DYNAMICPAINT_TYPE_BRUSH) { 01062 DynamicPaintBrushSettings *brush; 01063 if(pmd->brush) 01064 dynamicPaint_freeBrush(pmd); 01065 01066 brush = pmd->brush = MEM_callocN(sizeof(DynamicPaintBrushSettings), "DynamicPaint Paint"); 01067 if (!brush) 01068 return 0; 01069 brush->pmd = pmd; 01070 01071 brush->psys = NULL; 01072 01073 brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA; 01074 brush->collision = MOD_DPAINT_COL_VOLUME; 01075 01076 brush->mat = NULL; 01077 brush->r = 0.15f; 01078 brush->g = 0.4f; 01079 brush->b = 0.8f; 01080 brush->alpha = 1.0f; 01081 brush->wetness = 1.0f; 01082 01083 brush->paint_distance = 1.0f; 01084 brush->proximity_falloff = MOD_DPAINT_PRFALL_SMOOTH; 01085 01086 brush->particle_radius = 0.2f; 01087 brush->particle_smooth = 0.05f; 01088 01089 brush->wave_type = MOD_DPAINT_WAVEB_CHANGE; 01090 brush->wave_factor = 1.0f; 01091 brush->wave_clamp = 0.0f; 01092 brush->smudge_strength = 0.3f; 01093 brush->max_velocity = 1.0f; 01094 01095 brush->dm = NULL; 01096 01097 /* Paint proximity falloff colorramp. */ 01098 { 01099 CBData *ramp; 01100 01101 brush->paint_ramp = add_colorband(0); 01102 if (!brush->paint_ramp) 01103 return 0; 01104 ramp = brush->paint_ramp->data; 01105 /* Add default smooth-falloff ramp. */ 01106 ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f; 01107 ramp[0].pos = 0.0f; 01108 ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].pos = 1.0f; 01109 ramp[1].a = 0.0f; 01110 pmd->brush->paint_ramp->tot = 2; 01111 } 01112 01113 /* Brush velocity ramp. */ 01114 { 01115 CBData *ramp; 01116 01117 brush->vel_ramp = add_colorband(0); 01118 if (!brush->vel_ramp) 01119 return 0; 01120 ramp = brush->vel_ramp->data; 01121 ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = ramp[0].pos = 0.0f; 01122 ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].a = ramp[1].pos = 1.0f; 01123 brush->paint_ramp->tot = 2; 01124 } 01125 } 01126 } 01127 else 01128 return 0; 01129 01130 return 1; 01131 } 01132 01133 void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tpmd) 01134 { 01135 /* Init modifier */ 01136 tpmd->type = pmd->type; 01137 if (pmd->canvas) 01138 dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_CANVAS, NULL); 01139 if (pmd->brush) 01140 dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_BRUSH, NULL); 01141 01142 /* Copy data */ 01143 if (tpmd->canvas) { 01144 tpmd->canvas->pmd = tpmd; 01145 01146 } else if (tpmd->brush) { 01147 DynamicPaintBrushSettings *brush = pmd->brush, *t_brush = tpmd->brush; 01148 t_brush->pmd = tpmd; 01149 01150 t_brush->flags = brush->flags; 01151 t_brush->collision = brush->collision; 01152 01153 t_brush->mat = brush->mat; 01154 t_brush->r = brush->r; 01155 t_brush->g = brush->g; 01156 t_brush->b = brush->b; 01157 t_brush->alpha = brush->alpha; 01158 t_brush->wetness = brush->wetness; 01159 01160 t_brush->particle_radius = brush->particle_radius; 01161 t_brush->particle_smooth = brush->particle_smooth; 01162 t_brush->paint_distance = brush->paint_distance; 01163 t_brush->psys = brush->psys; 01164 01165 if (brush->paint_ramp) 01166 memcpy(t_brush->paint_ramp, brush->paint_ramp, sizeof(ColorBand)); 01167 if (brush->vel_ramp) 01168 memcpy(t_brush->vel_ramp, brush->vel_ramp, sizeof(ColorBand)); 01169 01170 t_brush->proximity_falloff = brush->proximity_falloff; 01171 t_brush->wave_type = brush->wave_type; 01172 t_brush->ray_dir = brush->ray_dir; 01173 01174 t_brush->wave_factor = brush->wave_factor; 01175 t_brush->wave_clamp = brush->wave_clamp; 01176 t_brush->max_velocity = brush->max_velocity; 01177 t_brush->smudge_strength = brush->smudge_strength; 01178 } 01179 } 01180 01181 /* allocates surface data depending on surface type */ 01182 static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface) 01183 { 01184 PaintSurfaceData *sData = surface->data; 01185 01186 switch (surface->type) { 01187 case MOD_DPAINT_SURFACE_T_PAINT: 01188 sData->type_data = MEM_callocN(sizeof(PaintPoint)*sData->total_points, "DynamicPaintSurface Data"); 01189 break; 01190 case MOD_DPAINT_SURFACE_T_DISPLACE: 01191 sData->type_data = MEM_callocN(sizeof(float)*sData->total_points, "DynamicPaintSurface DepthData"); 01192 break; 01193 case MOD_DPAINT_SURFACE_T_WEIGHT: 01194 sData->type_data = MEM_callocN(sizeof(float)*sData->total_points, "DynamicPaintSurface WeightData"); 01195 break; 01196 case MOD_DPAINT_SURFACE_T_WAVE: 01197 sData->type_data = MEM_callocN(sizeof(PaintWavePoint)*sData->total_points, "DynamicPaintSurface WaveData"); 01198 break; 01199 } 01200 01201 if (sData->type_data == NULL) setError(surface->canvas, "Not enough free memory!"); 01202 } 01203 01204 static int surface_usesAdjDistance(DynamicPaintSurface *surface) 01205 { 01206 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) return 1; 01207 if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) return 1; 01208 return 0; 01209 } 01210 01211 static int surface_usesAdjData(DynamicPaintSurface *surface) 01212 { 01213 if (surface_usesAdjDistance(surface)) return 1; 01214 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && 01215 surface->flags & MOD_DPAINT_ANTIALIAS) return 1; 01216 01217 return 0; 01218 } 01219 01220 /* initialize surface adjacency data */ 01221 static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int force_init) 01222 { 01223 PaintSurfaceData *sData = surface->data; 01224 PaintAdjData *ed; 01225 int *temp_data; 01226 int neigh_points = 0; 01227 01228 if (!surface_usesAdjData(surface) && !force_init) return; 01229 01230 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { 01231 /* For vertex format, neighbours are connected by edges */ 01232 neigh_points = 2*surface->canvas->dm->getNumEdges(surface->canvas->dm); 01233 } 01234 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) 01235 neigh_points = sData->total_points*8; 01236 01237 if (!neigh_points) return; 01238 01239 /* allocate memory */ 01240 ed = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data"); 01241 if (!ed) return; 01242 ed->n_index = MEM_callocN(sizeof(int)*sData->total_points, "Surface Adj Index"); 01243 ed->n_num = MEM_callocN(sizeof(int)*sData->total_points, "Surface Adj Counts"); 01244 temp_data = MEM_callocN(sizeof(int)*sData->total_points, "Temp Adj Data"); 01245 ed->n_target = MEM_callocN(sizeof(int)*neigh_points, "Surface Adj Targets"); 01246 ed->flags = MEM_callocN(sizeof(int)*sData->total_points, "Surface Adj Flags"); 01247 ed->total_targets = neigh_points; 01248 01249 /* in case of allocation error, free memory */ 01250 if (!ed->n_index || !ed->n_num || !ed->n_target || !temp_data) { 01251 dynamicPaint_freeAdjData(sData); 01252 if (temp_data) MEM_freeN(temp_data); 01253 setError(surface->canvas, "Not enough free memory."); 01254 return; 01255 } 01256 01257 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { 01258 int i; 01259 int n_pos; 01260 01261 /* For vertex format, count every vertex that is connected by an edge */ 01262 int numOfEdges = surface->canvas->dm->getNumEdges(surface->canvas->dm); 01263 int numOfFaces = surface->canvas->dm->getNumFaces(surface->canvas->dm); 01264 struct MEdge *edge = surface->canvas->dm->getEdgeArray(surface->canvas->dm); 01265 struct MFace *face = surface->canvas->dm->getFaceArray(surface->canvas->dm); 01266 01267 /* count number of edges per vertex */ 01268 for (i=0; i<numOfEdges; i++) { 01269 ed->n_num[edge[i].v1]++; 01270 ed->n_num[edge[i].v2]++; 01271 01272 temp_data[edge[i].v1]++; 01273 temp_data[edge[i].v2]++; 01274 } 01275 01276 /* to locate points on "mesh edge" */ 01277 for (i=0; i<numOfFaces; i++) { 01278 temp_data[face[i].v1]++; 01279 temp_data[face[i].v2]++; 01280 temp_data[face[i].v3]++; 01281 if (face[i].v4) 01282 temp_data[face[i].v4]++; 01283 } 01284 01285 /* now check if total number of edges+faces for 01286 * each vertex is even, if not -> vertex is on mesh edge */ 01287 for (i=0; i<sData->total_points; i++) { 01288 if ((temp_data[i]%2) || 01289 temp_data[i] < 4) 01290 ed->flags[i] |= ADJ_ON_MESH_EDGE; 01291 01292 /* reset temp data */ 01293 temp_data[i] = 0; 01294 } 01295 01296 /* order n_index array */ 01297 n_pos = 0; 01298 for (i=0; i<sData->total_points; i++) { 01299 ed->n_index[i] = n_pos; 01300 n_pos += ed->n_num[i]; 01301 } 01302 01303 /* and now add neighbour data using that info */ 01304 for (i=0; i<numOfEdges; i++) { 01305 /* first vertex */ 01306 int index = edge[i].v1; 01307 n_pos = ed->n_index[index]+temp_data[index]; 01308 ed->n_target[n_pos] = edge[i].v2; 01309 temp_data[index]++; 01310 01311 /* second vertex */ 01312 index = edge[i].v2; 01313 n_pos = ed->n_index[index]+temp_data[index]; 01314 ed->n_target[n_pos] = edge[i].v1; 01315 temp_data[index]++; 01316 } 01317 } 01318 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) { 01319 /* for image sequences, only allocate memory. 01320 * bake initialization takes care of rest */ 01321 } 01322 01323 MEM_freeN(temp_data); 01324 } 01325 01326 void dynamicPaint_setInitialColor(DynamicPaintSurface *surface) 01327 { 01328 PaintSurfaceData *sData = surface->data; 01329 PaintPoint* pPoint = (PaintPoint*)sData->type_data; 01330 DerivedMesh *dm = surface->canvas->dm; 01331 int i; 01332 01333 if (surface->type != MOD_DPAINT_SURFACE_T_PAINT) 01334 return; 01335 01336 if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE) 01337 return; 01338 /* Single color */ 01339 else if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) { 01340 /* apply color to every surface point */ 01341 #pragma omp parallel for schedule(static) 01342 for (i=0; i<sData->total_points; i++) { 01343 copy_v3_v3(pPoint[i].color, surface->init_color); 01344 pPoint[i].alpha = surface->init_color[3]; 01345 } 01346 } 01347 /* UV mapped texture */ 01348 else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) { 01349 Tex *tex = surface->init_texture; 01350 MTFace *tface; 01351 MFace *mface = dm->getFaceArray(dm); 01352 int numOfFaces = dm->getNumFaces(dm); 01353 char uvname[MAX_CUSTOMDATA_LAYER_NAME]; 01354 01355 if (!tex) return; 01356 01357 /* get uv map */ 01358 CustomData_validate_layer_name(&dm->faceData, CD_MTFACE, surface->init_layername, uvname); 01359 tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname); 01360 if (!tface) return; 01361 01362 /* for vertex surface loop through tfaces and find uv color 01363 * that provides highest alpha */ 01364 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { 01365 #pragma omp parallel for schedule(static) 01366 for (i=0; i<numOfFaces; i++) { 01367 int numOfVert = (mface[i].v4) ? 4 : 3; 01368 float uv[3] = {0.0f}; 01369 int j; 01370 for (j=0; j<numOfVert; j++) { 01371 TexResult texres = {0}; 01372 unsigned int *vert = (&mface[i].v1)+j; 01373 01374 /* remap to -1.0 to 1.0 */ 01375 uv[0] = tface[i].uv[j][0]*2.0f - 1.0f; 01376 uv[1] = tface[i].uv[j][1]*2.0f - 1.0f; 01377 01378 multitex_ext_safe(tex, uv, &texres); 01379 01380 if (texres.tin > pPoint[*vert].alpha) { 01381 copy_v3_v3(pPoint[*vert].color, &texres.tr); 01382 pPoint[*vert].alpha = texres.tin; 01383 } 01384 } 01385 } 01386 } 01387 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) { 01388 ImgSeqFormatData *f_data = (ImgSeqFormatData*)sData->format_data; 01389 int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1; 01390 01391 #pragma omp parallel for schedule(static) 01392 for (i=0; i<sData->total_points; i++) { 01393 float uv[9] = {0.0f}; 01394 float uv_final[3] = {0.0f}; 01395 int j; 01396 TexResult texres = {0}; 01397 01398 /* collect all uvs */ 01399 for (j=0; j<3; j++) { 01400 int v=(f_data->uv_p[i].quad && j>0) ? j+1 : j; 01401 copy_v2_v2(&uv[j*3], tface[f_data->uv_p[i].face_index].uv[v]); 01402 } 01403 01404 /* interpolate final uv pos */ 01405 interp_v3_v3v3v3( uv_final, &uv[0], &uv[3], &uv[6], 01406 f_data->barycentricWeights[i*samples].v); 01407 /* remap to -1.0 to 1.0 */ 01408 uv_final[0] = uv_final[0]*2.0f - 1.0f; 01409 uv_final[1] = uv_final[1]*2.0f - 1.0f; 01410 01411 multitex_ext_safe(tex, uv_final, &texres); 01412 01413 /* apply color */ 01414 copy_v3_v3(pPoint[i].color, &texres.tr); 01415 pPoint[i].alpha = texres.tin; 01416 } 01417 } 01418 } 01419 /* vertex color layer */ 01420 else if (surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) { 01421 MCol *col = CustomData_get_layer_named(&dm->faceData, CD_MCOL, surface->init_layername); 01422 if (!col) return; 01423 01424 /* for vertex surface, just copy colors from mcol */ 01425 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { 01426 MFace *mface = dm->getFaceArray(dm); 01427 int numOfFaces = dm->getNumFaces(dm); 01428 01429 #pragma omp parallel for schedule(static) 01430 for (i=0; i<numOfFaces; i++) { 01431 int numOfVert = (mface[i].v4) ? 4 : 3; 01432 int j; 01433 for (j=0; j<numOfVert; j++) { 01434 unsigned int *vert = ((&mface[i].v1)+j); 01435 01436 pPoint[*vert].color[0] = 1.0f/255.f*(float)col[i*4+j].b; 01437 pPoint[*vert].color[1] = 1.0f/255.f*(float)col[i*4+j].g; 01438 pPoint[*vert].color[2] = 1.0f/255.f*(float)col[i*4+j].r; 01439 pPoint[*vert].alpha = 1.0f/255.f*(float)col[i*4+j].a; 01440 } 01441 } 01442 } 01443 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) { 01444 ImgSeqFormatData *f_data = (ImgSeqFormatData*)sData->format_data; 01445 int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1; 01446 01447 #pragma omp parallel for schedule(static) 01448 for (i=0; i<sData->total_points; i++) { 01449 int face_ind = f_data->uv_p[i].face_index; 01450 float colors[3][4] = {{0.0f,0.0f,0.0f,0.0f}}; 01451 float final_color[4]; 01452 int j; 01453 /* collect color values */ 01454 for (j=0; j<3; j++) { 01455 int v=(f_data->uv_p[i].quad && j>0) ? j+1 : j; 01456 colors[j][0] = 1.0f/255.f*(float)col[face_ind*4+v].b; 01457 colors[j][1] = 1.0f/255.f*(float)col[face_ind*4+v].g; 01458 colors[j][2] = 1.0f/255.f*(float)col[face_ind*4+v].r; 01459 colors[j][3] = 1.0f/255.f*(float)col[face_ind*4+v].a; 01460 } 01461 01462 /* interpolate final color */ 01463 interp_v4_v4v4v4( final_color, colors[0], colors[1], colors[2], 01464 f_data->barycentricWeights[i*samples].v); 01465 01466 copy_v3_v3(pPoint[i].color, final_color); 01467 pPoint[i].alpha = final_color[3]; 01468 } 01469 } 01470 } 01471 } 01472 01473 /* clears surface data back to zero */ 01474 void dynamicPaint_clearSurface(DynamicPaintSurface *surface) 01475 { 01476 PaintSurfaceData *sData = surface->data; 01477 if (sData && sData->type_data) { 01478 unsigned int data_size; 01479 01480 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) 01481 data_size = sizeof(PaintPoint); 01482 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) 01483 data_size = sizeof(PaintWavePoint); 01484 else 01485 data_size = sizeof(float); 01486 01487 memset(sData->type_data, 0, data_size * sData->total_points); 01488 01489 /* set initial color */ 01490 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) 01491 dynamicPaint_setInitialColor(surface); 01492 01493 if (sData->bData) 01494 sData->bData->clear = 1; 01495 } 01496 } 01497 01498 /* completely (re)initializes surface (only for point cache types)*/ 01499 int dynamicPaint_resetSurface(DynamicPaintSurface *surface) 01500 { 01501 int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface); 01502 /* dont touch image sequence types. they get handled only on bake */ 01503 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return 1; 01504 01505 if (surface->data) dynamicPaint_freeSurfaceData(surface); 01506 if (numOfPoints < 1) return 0; 01507 01508 /* allocate memory */ 01509 surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData"); 01510 if (!surface->data) return 0; 01511 01512 /* allocate data depending on surface type and format */ 01513 surface->data->total_points = numOfPoints; 01514 dynamicPaint_allocateSurfaceType(surface); 01515 dynamicPaint_initAdjacencyData(surface, 0); 01516 01517 /* set initial color */ 01518 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) 01519 dynamicPaint_setInitialColor(surface); 01520 01521 return 1; 01522 } 01523 01524 /* make sure allocated surface size matches current requirements */ 01525 static int dynamicPaint_checkSurfaceData(DynamicPaintSurface *surface) 01526 { 01527 if (!surface->data || ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) { 01528 return dynamicPaint_resetSurface(surface); 01529 } 01530 return 1; 01531 } 01532 01533 01534 /***************************** Modifier processing ******************************/ 01535 01536 01537 /* apply displacing vertex surface to the derived mesh */ 01538 static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result) 01539 { 01540 PaintSurfaceData *sData = surface->data; 01541 01542 if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX) return; 01543 01544 /* displace paint */ 01545 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) { 01546 MVert *mvert = result->getVertArray(result); 01547 int i; 01548 float* value = (float*)sData->type_data; 01549 01550 #pragma omp parallel for schedule(static) 01551 for (i=0; i<sData->total_points; i++) { 01552 float normal[3], val=value[i]*surface->disp_factor; 01553 normal_short_to_float_v3(normal, mvert[i].no); 01554 normalize_v3(normal); 01555 01556 mvert[i].co[0] -= normal[0]*val; 01557 mvert[i].co[1] -= normal[1]*val; 01558 mvert[i].co[2] -= normal[2]*val; 01559 } 01560 } 01561 } 01562 01563 /* 01564 * Apply canvas data to the object derived mesh 01565 */ 01566 static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, 01567 Object *ob, 01568 DerivedMesh *dm) 01569 { 01570 DerivedMesh *result = CDDM_copy(dm); 01571 01572 if(pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) { 01573 01574 DynamicPaintSurface *surface = pmd->canvas->surfaces.first; 01575 int update_normals = 0; 01576 pmd->canvas->flags &= ~MOD_DPAINT_PREVIEW_READY; 01577 01578 /* loop through surfaces */ 01579 for (; surface; surface=surface->next) { 01580 PaintSurfaceData *sData = surface->data; 01581 01582 if (surface && surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) { 01583 if (!(surface->flags & (MOD_DPAINT_ACTIVE))) continue; 01584 01585 /* process vertex surface previews */ 01586 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { 01587 01588 /* vertex color paint */ 01589 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { 01590 01591 MFace *mface = result->getFaceArray(result); 01592 int numOfFaces = result->getNumFaces(result); 01593 int i; 01594 PaintPoint* pPoint = (PaintPoint*)sData->type_data; 01595 MCol *col; 01596 01597 /* paint is stored on dry and wet layers, so mix final color first */ 01598 float *fcolor = MEM_callocN(sizeof(float)*sData->total_points*4, "Temp paint color"); 01599 01600 #pragma omp parallel for schedule(static) 01601 for (i=0; i<sData->total_points; i++) { 01602 /* blend dry and wet layer */ 01603 blendColors(pPoint[i].color, pPoint[i].alpha, pPoint[i].e_color, pPoint[i].e_alpha, &fcolor[i*4]); 01604 } 01605 01606 /* viewport preview */ 01607 if (surface->flags & MOD_DPAINT_PREVIEW) { 01608 /* Save preview results to weight layer, to be 01609 * able to share same drawing methods */ 01610 col = result->getFaceDataArray(result, CD_WEIGHT_MCOL); 01611 if (!col) col = CustomData_add_layer(&result->faceData, CD_WEIGHT_MCOL, CD_CALLOC, NULL, numOfFaces); 01612 01613 if (col) { 01614 #pragma omp parallel for schedule(static) 01615 for (i=0; i<numOfFaces; i++) { 01616 int j=0; 01617 Material *material = give_current_material(ob, mface[i].mat_nr+1); 01618 01619 for (; j<((mface[i].v4)?4:3); j++) { 01620 int index = (j==0)?mface[i].v1: (j==1)?mface[i].v2: (j==2)?mface[i].v3: mface[i].v4; 01621 01622 if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) { 01623 float c[3]; 01624 index *= 4; 01625 01626 /* Apply material color as base vertex color for preview */ 01627 col[i*4+j].a = 255; 01628 if (material) { 01629 c[0] = material->r; 01630 c[1] = material->g; 01631 c[2] = material->b; 01632 } 01633 else { /* default grey */ 01634 c[0] = 0.65f; 01635 c[1] = 0.65f; 01636 c[2] = 0.65f; 01637 } 01638 /* mix surface color */ 01639 interp_v3_v3v3(c, c, &fcolor[index], fcolor[index+3]); 01640 01641 col[i*4+j].r = FTOCHAR(c[2]); 01642 col[i*4+j].g = FTOCHAR(c[1]); 01643 col[i*4+j].b = FTOCHAR(c[0]); 01644 } 01645 else { 01646 col[i*4+j].a = 255; 01647 col[i*4+j].r = 01648 col[i*4+j].g = 01649 col[i*4+j].b = FTOCHAR(pPoint[index].wetness); 01650 } 01651 } 01652 } 01653 pmd->canvas->flags |= MOD_DPAINT_PREVIEW_READY; 01654 } 01655 } 01656 01657 01658 /* save layer data to output layer */ 01659 01660 /* paint layer */ 01661 col = CustomData_get_layer_named(&result->faceData, CD_MCOL, surface->output_name); 01662 /* if output layer is lost from a constructive modifier, re-add it */ 01663 if (!col && dynamicPaint_outputLayerExists(surface, ob, 0)) 01664 col = CustomData_add_layer_named(&result->faceData, CD_MCOL, CD_CALLOC, NULL, numOfFaces, surface->output_name); 01665 /* apply color */ 01666 if (col) { 01667 #pragma omp parallel for schedule(static) 01668 for (i=0; i<numOfFaces; i++) { 01669 int j=0; 01670 for (; j<((mface[i].v4)?4:3); j++) { 01671 int index = (j==0)?mface[i].v1: (j==1)?mface[i].v2: (j==2)?mface[i].v3: mface[i].v4; 01672 index *= 4; 01673 01674 col[i*4+j].a = FTOCHAR(fcolor[index+3]); 01675 col[i*4+j].r = FTOCHAR(fcolor[index+2]); 01676 col[i*4+j].g = FTOCHAR(fcolor[index+1]); 01677 col[i*4+j].b = FTOCHAR(fcolor[index]); 01678 } 01679 } 01680 } 01681 01682 MEM_freeN(fcolor); 01683 01684 /* wet layer */ 01685 col = CustomData_get_layer_named(&result->faceData, CD_MCOL, surface->output_name2); 01686 /* if output layer is lost from a constructive modifier, re-add it */ 01687 if (!col && dynamicPaint_outputLayerExists(surface, ob, 1)) 01688 col = CustomData_add_layer_named(&result->faceData, CD_MCOL, CD_CALLOC, NULL, numOfFaces, surface->output_name2); 01689 /* apply color */ 01690 if (col) { 01691 #pragma omp parallel for schedule(static) 01692 for (i=0; i<numOfFaces; i++) { 01693 int j=0; 01694 01695 for (; j<((mface[i].v4)?4:3); j++) { 01696 int index = (j==0)?mface[i].v1: (j==1)?mface[i].v2: (j==2)?mface[i].v3: mface[i].v4; 01697 col[i*4+j].a = 255; 01698 col[i*4+j].r = 01699 col[i*4+j].g = 01700 col[i*4+j].b = FTOCHAR(pPoint[index].wetness); 01701 } 01702 } 01703 } 01704 } 01705 /* vertex group paint */ 01706 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) { 01707 int defgrp_index = defgroup_name_index(ob, surface->output_name); 01708 MDeformVert *dvert = result->getVertDataArray(result, CD_MDEFORMVERT); 01709 float *weight = (float*)sData->type_data; 01710 /* viewport preview */ 01711 if (surface->flags & MOD_DPAINT_PREVIEW) { 01712 /* Save preview results to weight layer, to be 01713 * able to share same drawing methods */ 01714 MFace *mface = result->getFaceArray(result); 01715 int numOfFaces = result->getNumFaces(result); 01716 int i; 01717 MCol *col = result->getFaceDataArray(result, CD_WEIGHT_MCOL); 01718 if (!col) col = CustomData_add_layer(&result->faceData, CD_WEIGHT_MCOL, CD_CALLOC, NULL, numOfFaces); 01719 01720 if (col) { 01721 #pragma omp parallel for schedule(static) 01722 for (i=0; i<numOfFaces; i++) { 01723 float temp_color[3]; 01724 int j=0; 01725 for (; j<((mface[i].v4)?4:3); j++) { 01726 int index = (j==0)?mface[i].v1: (j==1)?mface[i].v2: (j==2)?mface[i].v3: mface[i].v4; 01727 01728 weight_to_rgb(temp_color, weight[index]); 01729 col[i*4+j].r = FTOCHAR(temp_color[2]); 01730 col[i*4+j].g = FTOCHAR(temp_color[1]); 01731 col[i*4+j].b = FTOCHAR(temp_color[0]); 01732 col[i*4+j].a = 255; 01733 } 01734 } 01735 pmd->canvas->flags |= MOD_DPAINT_PREVIEW_READY; 01736 } 01737 } 01738 01739 /* apply weights into a vertex group, if doesnt exists add a new layer */ 01740 if (defgrp_index >= 0 && !dvert && (surface->output_name[0] != '\0')) 01741 dvert = CustomData_add_layer_named(&result->vertData, CD_MDEFORMVERT, CD_CALLOC, 01742 NULL, sData->total_points, surface->output_name); 01743 if (defgrp_index >= 0 && dvert) { 01744 int i; 01745 for(i=0; i<sData->total_points; i++) { 01746 MDeformVert *dv= &dvert[i]; 01747 MDeformWeight *def_weight = defvert_find_index(dv, defgrp_index); 01748 01749 /* skip if weight value is 0 and no existing weight is found */ 01750 if ((def_weight != NULL) || (weight[i] != 0.0f)) { 01751 01752 /* if not found, add a weight for it */ 01753 if (def_weight == NULL) { 01754 def_weight= defvert_verify_index(dv, defgrp_index); 01755 } 01756 01757 /* set weight value */ 01758 def_weight->weight = weight[i]; 01759 } 01760 } 01761 } 01762 } 01763 /* wave simulation */ 01764 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) { 01765 MVert *mvert = result->getVertArray(result); 01766 int i; 01767 PaintWavePoint* wPoint = (PaintWavePoint*)sData->type_data; 01768 01769 #pragma omp parallel for schedule(static) 01770 for (i=0; i<sData->total_points; i++) { 01771 float normal[3]; 01772 normal_short_to_float_v3(normal, mvert[i].no); 01773 madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height); 01774 } 01775 update_normals = 1; 01776 } 01777 01778 /* displace */ 01779 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) { 01780 dynamicPaint_applySurfaceDisplace(surface, result); 01781 update_normals = 1; 01782 } 01783 } 01784 } 01785 } 01786 01787 if (update_normals) 01788 CDDM_calc_normals(result); 01789 } 01790 /* make a copy of dm to use as brush data */ 01791 if (pmd->brush) { 01792 if (pmd->brush->dm) pmd->brush->dm->release(pmd->brush->dm); 01793 pmd->brush->dm = CDDM_copy(result); 01794 } 01795 01796 return result; 01797 } 01798 01799 /* update cache frame range */ 01800 void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface) 01801 { 01802 if (surface->pointcache) { 01803 surface->pointcache->startframe = surface->start_frame; 01804 surface->pointcache->endframe = surface->end_frame; 01805 } 01806 } 01807 01808 void canvas_copyDerivedMesh(DynamicPaintCanvasSettings *canvas, DerivedMesh *dm) 01809 { 01810 if (canvas->dm) canvas->dm->release(canvas->dm); 01811 canvas->dm = CDDM_copy(dm); 01812 } 01813 01814 /* 01815 * Updates derived mesh copy and processes dynamic paint step / caches. 01816 */ 01817 static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm) 01818 { 01819 if(pmd->canvas) { 01820 DynamicPaintCanvasSettings *canvas = pmd->canvas; 01821 DynamicPaintSurface *surface = canvas->surfaces.first; 01822 01823 /* update derived mesh copy */ 01824 canvas_copyDerivedMesh(canvas, dm); 01825 01826 /* in case image sequence baking, stop here */ 01827 if (canvas->flags & MOD_DPAINT_BAKING) return; 01828 01829 /* loop through surfaces */ 01830 for (; surface; surface=surface->next) { 01831 int current_frame = (int)scene->r.cfra; 01832 01833 /* free bake data if not required anymore */ 01834 surface_freeUnusedData(surface); 01835 01836 /* image sequences are handled by bake operator */ 01837 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) continue; 01838 if (!(surface->flags & MOD_DPAINT_ACTIVE)) continue; 01839 01840 /* make sure surface is valid */ 01841 if (!dynamicPaint_checkSurfaceData(surface)) continue; 01842 01843 /* limit frame range */ 01844 CLAMP(current_frame, surface->start_frame, surface->end_frame); 01845 01846 if (current_frame != surface->current_frame || (int)scene->r.cfra == surface->start_frame) { 01847 PointCache *cache = surface->pointcache; 01848 PTCacheID pid; 01849 surface->current_frame = current_frame; 01850 01851 /* read point cache */ 01852 BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface); 01853 pid.cache->startframe = surface->start_frame; 01854 pid.cache->endframe = surface->end_frame; 01855 BKE_ptcache_id_time(&pid, scene, (float)scene->r.cfra, NULL, NULL, NULL); 01856 01857 /* reset non-baked cache at first frame */ 01858 if((int)scene->r.cfra == surface->start_frame && !(cache->flag & PTCACHE_BAKED)) 01859 { 01860 cache->flag |= PTCACHE_REDO_NEEDED; 01861 BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); 01862 cache->flag &= ~PTCACHE_REDO_NEEDED; 01863 } 01864 01865 /* try to read from cache */ 01866 if(BKE_ptcache_read(&pid, (float)scene->r.cfra)) { 01867 BKE_ptcache_validate(cache, (int)scene->r.cfra); 01868 } 01869 /* if read failed and we're on surface range do recalculate */ 01870 else if ((int)scene->r.cfra == current_frame 01871 && !(cache->flag & PTCACHE_BAKED)) { 01872 /* calculate surface frame */ 01873 canvas->flags |= MOD_DPAINT_BAKING; 01874 dynamicPaint_calculateFrame(surface, scene, ob, current_frame); 01875 canvas->flags &= ~MOD_DPAINT_BAKING; 01876 01877 /* restore canvas derivedmesh if required */ 01878 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE && 01879 surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next) 01880 canvas_copyDerivedMesh(canvas, dm); 01881 01882 BKE_ptcache_validate(cache, surface->current_frame); 01883 BKE_ptcache_write(&pid, surface->current_frame); 01884 } 01885 } 01886 } 01887 } 01888 } 01889 01890 /* Modifier call. Processes dynamic paint modifier step. */ 01891 struct DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm) 01892 { 01893 /* Update canvas data for a new frame */ 01894 dynamicPaint_frameUpdate(pmd, scene, ob, dm); 01895 01896 /* Return output mesh */ 01897 return dynamicPaint_Modifier_apply(pmd, ob, dm); 01898 } 01899 01900 01901 /***************************** Image Sequence / UV Image Surface Calls ******************************/ 01902 01903 /* 01904 * Tries to find the neighbouring pixel in given (uv space) direction. 01905 * Result is used by effect system to move paint on the surface. 01906 * 01907 * px,py : origin pixel x and y 01908 * n_index : lookup direction index (use neighX,neighY to get final index) 01909 */ 01910 static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh *dm, 01911 const char *uvname, int w, int h, int px, int py, int n_index) 01912 { 01913 /* Note: Current method only uses polygon edges to detect neighbouring pixels. 01914 * -> It doesn't always lead to the optimum pixel but is accurate enough 01915 * and faster/simplier than including possible face tip point links) 01916 */ 01917 01918 int x,y; 01919 PaintUVPoint *tPoint = NULL; 01920 PaintUVPoint *cPoint = NULL; 01921 01922 /* shift position by given n_index */ 01923 x = px + neighX[n_index]; 01924 y = py + neighY[n_index]; 01925 01926 if (x<0 || x>=w) return -1; 01927 if (y<0 || y>=h) return -1; 01928 01929 tPoint = &tempPoints[x+w*y]; /* UV neighbour */ 01930 cPoint = &tempPoints[px+w*py]; /* Origin point */ 01931 01932 /* 01933 * Check if shifted point is on same face -> it's a correct neighbour 01934 * (and if it isn't marked as an "edge pixel") 01935 */ 01936 if ((tPoint->face_index == cPoint->face_index) && (tPoint->neighbour_pixel == -1)) 01937 return (x+w*y); 01938 01939 /* 01940 * Even if shifted point is on another face 01941 * -> use this point. 01942 * 01943 * !! Replace with "is uv faces linked" check !! 01944 * This should work fine as long as uv island 01945 * margin is > 1 pixel. 01946 */ 01947 if ((tPoint->face_index != -1) && (tPoint->neighbour_pixel == -1)) { 01948 return (x+w*y); 01949 } 01950 01951 /* 01952 * If we get here, the actual neighbouring pixel 01953 * is located on a non-linked uv face, and we have to find 01954 * it's "real" position. 01955 * 01956 * Simple neighbouring face finding algorithm: 01957 * - find closest uv edge to shifted pixel and get 01958 * the another face that shares that edge 01959 * - find corresponding position of that new face edge 01960 * in uv space 01961 * 01962 * TODO: Implement something more accurate / optimized? 01963 */ 01964 { 01965 int numOfFaces = dm->getNumFaces(dm); 01966 MFace *mface = dm->getFaceArray(dm); 01967 MTFace *tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname); 01968 01969 /* Get closest edge to that subpixel on UV map */ 01970 { 01971 float pixel[2], dist, t_dist; 01972 int i, uindex[3], edge1_index, edge2_index, 01973 e1_index, e2_index, target_face; 01974 float closest_point[2], lambda, dir_vec[2]; 01975 int target_uv1, target_uv2, final_pixel[2], final_index; 01976 01977 float *s_uv1, *s_uv2, *t_uv1, *t_uv2; 01978 01979 pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w; 01980 pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h; 01981 01982 /* Get uv indexes for current face part */ 01983 if (cPoint->quad) { 01984 uindex[0] = 0; uindex[1] = 2; uindex[2] = 3; 01985 } 01986 else { 01987 uindex[0] = 0; uindex[1] = 1; uindex[2] = 2; 01988 } 01989 01990 /* 01991 * Find closest edge to that pixel 01992 */ 01993 /* Dist to first edge */ 01994 e1_index = cPoint->v1; e2_index = cPoint->v2; edge1_index = uindex[0]; edge2_index = uindex[1]; 01995 dist = dist_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[edge1_index], tface[cPoint->face_index].uv[edge2_index]); 01996 01997 /* Dist to second edge */ 01998 t_dist = dist_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[uindex[1]], tface[cPoint->face_index].uv[uindex[2]]); 01999 if (t_dist < dist) {e1_index = cPoint->v2; e2_index = cPoint->v3; edge1_index = uindex[1]; edge2_index = uindex[2]; dist = t_dist;} 02000 02001 /* Dist to third edge */ 02002 t_dist = dist_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[uindex[2]], tface[cPoint->face_index].uv[uindex[0]]); 02003 if (t_dist < dist) {e1_index = cPoint->v3; e2_index = cPoint->v1; edge1_index = uindex[2]; edge2_index = uindex[0]; dist = t_dist;} 02004 02005 02006 /* 02007 * Now find another face that is linked to that edge 02008 */ 02009 target_face = -1; 02010 02011 for (i=0; i<numOfFaces; i++) { 02012 /* 02013 * Check if both edge vertices share this face 02014 */ 02015 int v4 = (mface[i].v4) ? mface[i].v4 : -1; 02016 02017 if ((e1_index == mface[i].v1 || e1_index == mface[i].v2 || e1_index == mface[i].v3 || e1_index == v4) && 02018 (e2_index == mface[i].v1 || e2_index == mface[i].v2 || e2_index == mface[i].v3 || e2_index == v4)) { 02019 if (i == cPoint->face_index) continue; 02020 02021 target_face = i; 02022 02023 /* 02024 * Get edge UV index 02025 */ 02026 if (e1_index == mface[i].v1) target_uv1 = 0; 02027 else if (e1_index == mface[i].v2) target_uv1 = 1; 02028 else if (e1_index == mface[i].v3) target_uv1 = 2; 02029 else target_uv1 = 3; 02030 02031 if (e2_index == mface[i].v1) target_uv2 = 0; 02032 else if (e2_index == mface[i].v2) target_uv2 = 1; 02033 else if (e2_index == mface[i].v3) target_uv2 = 2; 02034 else target_uv2 = 3; 02035 02036 break; 02037 } 02038 } 02039 02040 /* If none found return -1 */ 02041 if (target_face == -1) return -1; 02042 02043 /* 02044 * If target face is connected in UV space as well, just use original index 02045 */ 02046 s_uv1 = (float *)tface[cPoint->face_index].uv[edge1_index]; 02047 s_uv2 = (float *)tface[cPoint->face_index].uv[edge2_index]; 02048 t_uv1 = (float *)tface[target_face].uv[target_uv1]; 02049 t_uv2 = (float *)tface[target_face].uv[target_uv2]; 02050 02051 //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]); 02052 02053 if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) && 02054 (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1]) ) || 02055 ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) && 02056 (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]) )) return ((px+neighX[n_index]) + w*(py+neighY[n_index])); 02057 02058 /* 02059 * Find a point that is relatively at same edge position 02060 * on this other face UV 02061 */ 02062 lambda = closest_to_line_v2(closest_point, pixel, tface[cPoint->face_index].uv[edge1_index], tface[cPoint->face_index].uv[edge2_index]); 02063 if (lambda < 0.0f) lambda = 0.0f; 02064 if (lambda > 1.0f) lambda = 1.0f; 02065 02066 sub_v2_v2v2(dir_vec, tface[target_face].uv[target_uv2], tface[target_face].uv[target_uv1]); 02067 02068 mul_v2_fl(dir_vec, lambda); 02069 02070 copy_v2_v2(pixel, tface[target_face].uv[target_uv1]); 02071 add_v2_v2(pixel, dir_vec); 02072 pixel[0] = (pixel[0] * (float)w) - 0.5f; 02073 pixel[1] = (pixel[1] * (float)h) - 0.5f; 02074 02075 final_pixel[0] = (int)floor(pixel[0]); 02076 final_pixel[1] = (int)floor(pixel[1]); 02077 02078 /* If current pixel uv is outside of texture */ 02079 if (final_pixel[0] < 0 || final_pixel[0] >= w) return -1; 02080 if (final_pixel[1] < 0 || final_pixel[1] >= h) return -1; 02081 02082 final_index = final_pixel[0] + w * final_pixel[1]; 02083 02084 /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */ 02085 if (final_index == (px+w*py)) return -1; 02086 /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */ 02087 if (tempPoints[final_index].face_index != target_face) return -1; 02088 02089 /* 02090 * If final point is an "edge pixel", use it's "real" neighbour instead 02091 */ 02092 if (tempPoints[final_index].neighbour_pixel != -1) final_index = cPoint->neighbour_pixel; 02093 02094 return final_index; 02095 } 02096 } 02097 } 02098 02099 /* 02100 * Create a surface for uv image sequence format 02101 */ 02102 int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) 02103 { 02104 /* Antialias jitter point relative coords */ 02105 float jitter5sample[10] = {0.0f, 0.0f, 02106 -0.2f, -0.4f, 02107 0.2f, 0.4f, 02108 0.4f, -0.2f, 02109 -0.4f, 0.3f}; 02110 int ty; 02111 int w,h; 02112 int numOfFaces; 02113 char uvname[MAX_CUSTOMDATA_LAYER_NAME]; 02114 int active_points = 0; 02115 int error = 0; 02116 02117 PaintSurfaceData *sData; 02118 DynamicPaintCanvasSettings *canvas = surface->canvas; 02119 DerivedMesh *dm = canvas->dm; 02120 02121 PaintUVPoint *tempPoints = NULL; 02122 Vec3f *tempWeights = NULL; 02123 MFace *mface = NULL; 02124 MTFace *tface = NULL; 02125 Bounds2D *faceBB = NULL; 02126 int *final_index; 02127 int aa_samples; 02128 02129 if (!dm) return setError(canvas, "Canvas mesh not updated."); 02130 if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ) return setError(canvas, "Can't bake non-\"image sequence\" formats."); 02131 02132 numOfFaces = dm->getNumFaces(dm); 02133 mface = dm->getFaceArray(dm); 02134 02135 /* get uv map */ 02136 CustomData_validate_layer_name(&dm->faceData, CD_MTFACE, surface->uvlayer_name, uvname); 02137 tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname); 02138 02139 /* Check for validity */ 02140 if (!tface) return setError(canvas, "No UV data on canvas."); 02141 if (surface->image_resolution < 16 || surface->image_resolution > 8192) return setError(canvas, "Invalid resolution."); 02142 02143 w = h = surface->image_resolution; 02144 02145 /* 02146 * Start generating the surface 02147 */ 02148 printf("DynamicPaint: Preparing UV surface of %ix%i pixels and %i faces.\n", w, h, numOfFaces); 02149 02150 /* Init data struct */ 02151 if (surface->data) dynamicPaint_freeSurfaceData(surface); 02152 sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData"); 02153 if (!surface->data) return setError(canvas, "Not enough free memory."); 02154 02155 aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1; 02156 tempPoints = (struct PaintUVPoint *) MEM_callocN(w*h*sizeof(struct PaintUVPoint), "Temp PaintUVPoint"); 02157 if (!tempPoints) error=1; 02158 02159 final_index = (int *) MEM_callocN(w*h*sizeof(int), "Temp UV Final Indexes"); 02160 if (!final_index) error=1; 02161 02162 tempWeights = (struct Vec3f *) MEM_mallocN(w*h*aa_samples*sizeof(struct Vec3f), "Temp bWeights"); 02163 if (!tempWeights) error=1; 02164 02165 /* 02166 * Generate a temporary bounding box array for UV faces to optimize 02167 * the pixel-inside-a-face search. 02168 */ 02169 if (!error) { 02170 faceBB = (struct Bounds2D *) MEM_mallocN(numOfFaces*sizeof(struct Bounds2D), "MPCanvasFaceBB"); 02171 if (!faceBB) error=1; 02172 } 02173 02174 if (!error) 02175 for (ty=0; ty<numOfFaces; ty++) { 02176 int numOfVert = (mface[ty].v4) ? 4 : 3; 02177 int i; 02178 02179 copy_v2_v2(faceBB[ty].min, tface[ty].uv[0]); 02180 copy_v2_v2(faceBB[ty].max, tface[ty].uv[0]); 02181 02182 for (i = 1; i<numOfVert; i++) { 02183 if (tface[ty].uv[i][0] < faceBB[ty].min[0]) faceBB[ty].min[0] = tface[ty].uv[i][0]; 02184 if (tface[ty].uv[i][1] < faceBB[ty].min[1]) faceBB[ty].min[1] = tface[ty].uv[i][1]; 02185 if (tface[ty].uv[i][0] > faceBB[ty].max[0]) faceBB[ty].max[0] = tface[ty].uv[i][0]; 02186 if (tface[ty].uv[i][1] > faceBB[ty].max[1]) faceBB[ty].max[1] = tface[ty].uv[i][1]; 02187 02188 } 02189 } 02190 02191 /* 02192 * Loop through every pixel and check 02193 * if pixel is uv-mapped on a canvas face. 02194 */ 02195 if (!error) { 02196 #pragma omp parallel for schedule(static) 02197 for (ty = 0; ty < h; ty++) 02198 { 02199 int tx; 02200 for (tx = 0; tx < w; tx++) 02201 { 02202 int i, sample; 02203 int index = tx+w*ty; 02204 PaintUVPoint *tPoint = (&tempPoints[index]); 02205 02206 short isInside = 0; /* if point is inside a uv face */ 02207 02208 float d1[2], d2[2], d3[2], point[5][2]; 02209 float dot00,dot01,dot02,dot11,dot12, invDenom, u,v; 02210 02211 /* Init per pixel settings */ 02212 tPoint->face_index = -1; 02213 tPoint->neighbour_pixel = -1; 02214 tPoint->pixel_index = index; 02215 02216 /* Actual pixel center, used when collision is found */ 02217 point[0][0] = ((float)tx + 0.5f) / w; 02218 point[0][1] = ((float)ty + 0.5f) / h; 02219 02220 /* 02221 * A pixel middle sample isn't enough to find very narrow polygons 02222 * So using 4 samples of each corner too 02223 */ 02224 point[1][0] = ((float)tx) / w; 02225 point[1][1] = ((float)ty) / h; 02226 02227 point[2][0] = ((float)tx+1) / w; 02228 point[2][1] = ((float)ty) / h; 02229 02230 point[3][0] = ((float)tx) / w; 02231 point[3][1] = ((float)ty+1) / h; 02232 02233 point[4][0] = ((float)tx+1) / w; 02234 point[4][1] = ((float)ty+1) / h; 02235 02236 02237 /* Loop through samples, starting from middle point */ 02238 for (sample=0; sample<5; sample++) { 02239 02240 /* Loop through every face in the mesh */ 02241 for (i=0; i<numOfFaces; i++) { 02242 02243 /* Check uv bb */ 02244 if (faceBB[i].min[0] > (point[sample][0])) continue; 02245 if (faceBB[i].min[1] > (point[sample][1])) continue; 02246 if (faceBB[i].max[0] < (point[sample][0])) continue; 02247 if (faceBB[i].max[1] < (point[sample][1])) continue; 02248 02249 /* Calculate point inside a triangle check 02250 * for uv0,1,2 */ 02251 sub_v2_v2v2(d1, tface[i].uv[2], tface[i].uv[0]); // uv2 - uv0 02252 sub_v2_v2v2(d2, tface[i].uv[1], tface[i].uv[0]); // uv1 - uv0 02253 sub_v2_v2v2(d3, point[sample], tface[i].uv[0]); // point - uv0 02254 02255 dot00 = d1[0]*d1[0] + d1[1]*d1[1]; 02256 dot01 = d1[0]*d2[0] + d1[1]*d2[1]; 02257 dot02 = d1[0]*d3[0] + d1[1]*d3[1]; 02258 dot11 = d2[0]*d2[0] + d2[1]*d2[1]; 02259 dot12 = d2[0]*d3[0] + d2[1]*d3[1]; 02260 02261 invDenom = 1 / (dot00 * dot11 - dot01 * dot01); 02262 u = (dot11 * dot02 - dot01 * dot12) * invDenom; 02263 v = (dot00 * dot12 - dot01 * dot02) * invDenom; 02264 02265 if ((u > 0) && (v > 0) && (u + v < 1)) {isInside=1;} /* is inside a triangle */ 02266 02267 /* If collision wasn't found but the face is a quad 02268 * do another check for the second half */ 02269 if ((!isInside) && mface[i].v4) 02270 { 02271 02272 /* change d2 to test the other half */ 02273 sub_v2_v2v2(d2, tface[i].uv[3], tface[i].uv[0]); // uv3 - uv0 02274 02275 /* test again */ 02276 dot00 = d1[0]*d1[0] + d1[1]*d1[1]; 02277 dot01 = d1[0]*d2[0] + d1[1]*d2[1]; 02278 dot02 = d1[0]*d3[0] + d1[1]*d3[1]; 02279 dot11 = d2[0]*d2[0] + d2[1]*d2[1]; 02280 dot12 = d2[0]*d3[0] + d2[1]*d3[1]; 02281 02282 invDenom = 1 / (dot00 * dot11 - dot01 * dot01); 02283 u = (dot11 * dot02 - dot01 * dot12) * invDenom; 02284 v = (dot00 * dot12 - dot01 * dot02) * invDenom; 02285 02286 if ((u > 0) && (v > 0) && (u + v < 1)) {isInside=2;} /* is inside the second half of the quad */ 02287 02288 } 02289 02290 /* 02291 * If point was inside the face 02292 */ 02293 if (isInside != 0) { 02294 02295 float uv1co[2], uv2co[2], uv3co[2], uv[2]; 02296 int j; 02297 02298 /* Get triagnle uvs */ 02299 if (isInside==1) { 02300 copy_v2_v2(uv1co, tface[i].uv[0]); 02301 copy_v2_v2(uv2co, tface[i].uv[1]); 02302 copy_v2_v2(uv3co, tface[i].uv[2]); 02303 } 02304 else { 02305 copy_v2_v2(uv1co, tface[i].uv[0]); 02306 copy_v2_v2(uv2co, tface[i].uv[2]); 02307 copy_v2_v2(uv3co, tface[i].uv[3]); 02308 } 02309 02310 /* Add b-weights per anti-aliasing sample */ 02311 for (j=0; j<aa_samples; j++) { 02312 uv[0] = point[0][0] + jitter5sample[j*2] / w; 02313 uv[1] = point[0][1] + jitter5sample[j*2+1] / h; 02314 02315 barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index*aa_samples+j].v); 02316 } 02317 02318 /* Set surface point face values */ 02319 tPoint->face_index = i; /* face index */ 02320 tPoint->quad = (isInside == 2) ? 1 : 0; /* quad or tri part*/ 02321 02322 /* save vertex indexes */ 02323 tPoint->v1 = mface[i].v1; 02324 tPoint->v2 = (isInside == 2) ? mface[i].v3 : mface[i].v2; 02325 tPoint->v3 = (isInside == 2) ? mface[i].v4 : mface[i].v3; 02326 02327 sample = 5; /* make sure we exit sample loop as well */ 02328 break; 02329 } 02330 } 02331 } /* sample loop */ 02332 } 02333 } 02334 02335 /* 02336 * Now loop through every pixel that was left without index 02337 * and find if they have neighbouring pixels that have an index. 02338 * If so use that polygon as pixel surface. 02339 * (To avoid seams on uv island edges) 02340 */ 02341 #pragma omp parallel for schedule(static) 02342 for (ty = 0; ty < h; ty++) 02343 { 02344 int tx; 02345 for (tx = 0; tx < w; tx++) 02346 { 02347 int index = tx+w*ty; 02348 PaintUVPoint *tPoint = (&tempPoints[index]); 02349 02350 /* If point isnt't on canvas mesh */ 02351 if (tPoint->face_index == -1) { 02352 int u_min, u_max, v_min, v_max; 02353 int u,v, ind; 02354 float point[2]; 02355 02356 /* get loop area */ 02357 u_min = (tx > 0) ? -1 : 0; 02358 u_max = (tx < (w-1)) ? 1 : 0; 02359 v_min = (ty > 0) ? -1 : 0; 02360 v_max = (ty < (h-1)) ? 1 : 0; 02361 02362 point[0] = ((float)tx + 0.5f) / w; 02363 point[1] = ((float)ty + 0.5f) / h; 02364 02365 /* search through defined area for neighbour */ 02366 for (u=u_min; u<=u_max; u++) 02367 for (v=v_min; v<=v_max; v++) { 02368 /* if not this pixel itself */ 02369 if (u!=0 || v!=0) { 02370 ind = (tx+u)+w*(ty+v); 02371 02372 /* if neighbour has index */ 02373 if (tempPoints[ind].face_index != -1) { 02374 02375 float uv1co[2], uv2co[2], uv3co[2], uv[2]; 02376 int i = tempPoints[ind].face_index, j; 02377 02378 /* Now calculate pixel data for this pixel as it was on polygon surface */ 02379 if (!tempPoints[ind].quad) { 02380 copy_v2_v2(uv1co, tface[i].uv[0]); 02381 copy_v2_v2(uv2co, tface[i].uv[1]); 02382 copy_v2_v2(uv3co, tface[i].uv[2]); 02383 } 02384 else { 02385 copy_v2_v2(uv1co, tface[i].uv[0]); 02386 copy_v2_v2(uv2co, tface[i].uv[2]); 02387 copy_v2_v2(uv3co, tface[i].uv[3]); 02388 } 02389 02390 /* Add b-weights per anti-aliasing sample */ 02391 for (j=0; j<aa_samples; j++) { 02392 02393 uv[0] = point[0] + jitter5sample[j*2] / w; 02394 uv[1] = point[1] + jitter5sample[j*2+1] / h; 02395 barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index*aa_samples+j].v); 02396 } 02397 02398 /* Set values */ 02399 tPoint->neighbour_pixel = ind; // face index 02400 tPoint->quad = tempPoints[ind].quad; // quad or tri 02401 02402 /* save vertex indexes */ 02403 tPoint->v1 = mface[i].v1; 02404 tPoint->v2 = (tPoint->quad) ? mface[i].v3 : mface[i].v2; 02405 tPoint->v3 = (tPoint->quad) ? mface[i].v4 : mface[i].v3; 02406 02407 u = u_max + 1; /* make sure we exit outer loop as well */ 02408 break; 02409 } 02410 } 02411 } 02412 } 02413 } 02414 } 02415 02416 /* 02417 * When base loop is over convert found neighbour indexes to real ones 02418 * Also count the final number of active surface points 02419 */ 02420 for (ty = 0; ty < h; ty++) 02421 { 02422 int tx; 02423 for (tx = 0; tx < w; tx++) 02424 { 02425 int index = tx+w*ty; 02426 PaintUVPoint *tPoint = (&tempPoints[index]); 02427 02428 if (tPoint->face_index == -1 && tPoint->neighbour_pixel != -1) tPoint->face_index = tempPoints[tPoint->neighbour_pixel].face_index; 02429 if (tPoint->face_index != -1) active_points++; 02430 } 02431 } 02432 02433 /* Generate surface adjacency data. */ 02434 { 02435 int i, cursor=0; 02436 02437 /* Create a temporary array of final indexes (before unassigned 02438 * pixels have been dropped) */ 02439 for (i=0; i<w*h; i++) { 02440 if (tempPoints[i].face_index != -1) { 02441 final_index[i] = cursor; 02442 cursor++; 02443 } 02444 } 02445 /* allocate memory */ 02446 sData->total_points = w*h; 02447 dynamicPaint_initAdjacencyData(surface, 1); 02448 02449 if (sData->adj_data) { 02450 PaintAdjData *ed = sData->adj_data; 02451 unsigned int n_pos = 0; 02452 for (ty = 0; ty < h; ty++) 02453 { 02454 int tx; 02455 for (tx = 0; tx < w; tx++) 02456 { 02457 int i, index = tx+w*ty; 02458 02459 if (tempPoints[index].face_index != -1) { 02460 ed->n_index[final_index[index]] = n_pos; 02461 ed->n_num[final_index[index]] = 0; 02462 02463 for (i=0; i<8; i++) { 02464 02465 /* Try to find a neighbouring pixel in defined direction 02466 * If not found, -1 is returned */ 02467 int n_target = dynamicPaint_findNeighbourPixel(tempPoints, dm, uvname, w, h, tx, ty, i); 02468 02469 if (n_target != -1) { 02470 ed->n_target[n_pos] = final_index[n_target]; 02471 ed->n_num[final_index[index]]++; 02472 n_pos++; 02473 } 02474 } 02475 } 02476 } 02477 } 02478 } 02479 } 02480 02481 /* Create final surface data without inactive points */ 02482 { 02483 ImgSeqFormatData *f_data = MEM_callocN(sizeof(struct ImgSeqFormatData), "ImgSeqFormatData"); 02484 if (f_data) { 02485 f_data->uv_p = MEM_callocN(active_points*sizeof(struct PaintUVPoint), "PaintUVPoint"); 02486 f_data->barycentricWeights = MEM_callocN(active_points*aa_samples*sizeof(struct Vec3f), "PaintUVPoint"); 02487 02488 if (!f_data->uv_p || !f_data->barycentricWeights) error=1; 02489 } 02490 else error=1; 02491 02492 sData->total_points = active_points; 02493 02494 /* in case of allocation error, free everything */ 02495 if (error) { 02496 if (f_data) { 02497 if (f_data->uv_p) MEM_freeN(f_data->uv_p); 02498 if (f_data->barycentricWeights) MEM_freeN(f_data->barycentricWeights); 02499 MEM_freeN(f_data); 02500 } 02501 } 02502 else { 02503 int index, cursor = 0; 02504 sData->total_points = active_points; 02505 sData->format_data = f_data; 02506 02507 for(index = 0; index < (w*h); index++) { 02508 if (tempPoints[index].face_index != -1) { 02509 memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint)); 02510 memcpy(&f_data->barycentricWeights[cursor*aa_samples], &tempWeights[index*aa_samples], sizeof(Vec3f)*aa_samples); 02511 cursor++; 02512 } 02513 } 02514 } 02515 } 02516 } 02517 if (error==1) setError(canvas, "Not enough free memory."); 02518 02519 if (faceBB) MEM_freeN(faceBB); 02520 if (tempPoints) MEM_freeN(tempPoints); 02521 if (tempWeights) MEM_freeN(tempWeights); 02522 if (final_index) MEM_freeN(final_index); 02523 02524 /* Init surface type data */ 02525 if (!error) { 02526 dynamicPaint_allocateSurfaceType(surface); 02527 02528 #if 0 02529 /* ----------------------------------------------------------------- 02530 * For debug, output pixel statuses to the color map 02531 * -----------------------------------------------------------------*/ 02532 #pragma omp parallel for schedule(static) 02533 for (index = 0; index < sData->total_points; index++) 02534 { 02535 ImgSeqFormatData *f_data = (ImgSeqFormatData*)sData->format_data; 02536 PaintUVPoint *uvPoint = &((PaintUVPoint*)f_data->uv_p)[index]; 02537 PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index]; 02538 pPoint->alpha=1.0f; 02539 02540 /* Every pixel that is assigned as "edge pixel" gets blue color */ 02541 if (uvPoint->neighbour_pixel != -1) pPoint->color[2] = 1.0f; 02542 /* and every pixel that finally got an polygon gets red color */ 02543 if (uvPoint->face_index != -1) pPoint->color[0] = 1.0f; 02544 /* green color shows pixel face index hash */ 02545 if (uvPoint->face_index != -1) pPoint->color[1] = (float)(uvPoint->face_index % 255)/256.0f; 02546 } 02547 02548 #endif 02549 dynamicPaint_setInitialColor(surface); 02550 } 02551 02552 return (error == 0); 02553 } 02554 02555 /* 02556 * Outputs an image file from uv surface data. 02557 */ 02558 void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char* filename, short output_layer) 02559 { 02560 int index; 02561 ImBuf* ibuf = NULL; 02562 PaintSurfaceData *sData = surface->data; 02563 ImgSeqFormatData *f_data = (ImgSeqFormatData*)sData->format_data; 02564 /* OpenEXR or PNG */ 02565 int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR : R_IMF_IMTYPE_PNG; 02566 char output_file[FILE_MAX]; 02567 02568 if (!sData || !sData->type_data) {setError(surface->canvas, "Image save failed: Invalid surface.");return;} 02569 /* if selected format is openexr, but current build doesnt support one */ 02570 #ifndef WITH_OPENEXR 02571 if (format == R_IMF_IMTYPE_OPENEXR) format = R_IMF_IMTYPE_PNG; 02572 #endif 02573 BLI_strncpy(output_file, filename, sizeof(output_file)); 02574 BKE_add_image_extension(output_file, format); 02575 02576 /* Validate output file path */ 02577 BLI_path_abs(output_file, G.main->name); 02578 BLI_make_existing_file(output_file); 02579 02580 /* Init image buffer */ 02581 ibuf = IMB_allocImBuf(surface->image_resolution, surface->image_resolution, 32, IB_rectfloat); 02582 if (ibuf == NULL) {setError(surface->canvas, "Image save failed: Not enough free memory.");return;} 02583 02584 #pragma omp parallel for schedule(static) 02585 for (index = 0; index < sData->total_points; index++) 02586 { 02587 int pos=f_data->uv_p[index].pixel_index*4; /* image buffer position */ 02588 02589 /* Set values of preferred type */ 02590 if (output_layer == 1) { 02591 /* wetmap */ 02592 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { 02593 PaintPoint *point = &((PaintPoint*)sData->type_data)[index]; 02594 float value = (point->wetness > 1.0f) ? 1.0f : point->wetness; 02595 02596 ibuf->rect_float[pos]=value; 02597 ibuf->rect_float[pos+1]=value; 02598 ibuf->rect_float[pos+2]=value; 02599 ibuf->rect_float[pos+3]=1.0f; 02600 } 02601 } 02602 else if (output_layer == 0) { 02603 /* Paintmap */ 02604 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { 02605 PaintPoint *point = &((PaintPoint*)sData->type_data)[index]; 02606 02607 /* blend wet and dry layers */ 02608 blendColors(point->color, point->alpha, point->e_color, point->e_alpha, &ibuf->rect_float[pos]); 02609 02610 /* Multiply color by alpha if enabled */ 02611 if (surface->flags & MOD_DPAINT_MULALPHA) { 02612 ibuf->rect_float[pos] *= ibuf->rect_float[pos+3]; 02613 ibuf->rect_float[pos+1] *= ibuf->rect_float[pos+3]; 02614 ibuf->rect_float[pos+2] *= ibuf->rect_float[pos+3]; 02615 } 02616 } 02617 /* displace */ 02618 else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) { 02619 float depth = ((float*)sData->type_data)[index]; 02620 if (surface->depth_clamp) 02621 depth /= surface->depth_clamp; 02622 02623 if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) { 02624 depth = (0.5f - depth/2.0f); 02625 } 02626 02627 CLAMP(depth, 0.0f, 1.0f); 02628 02629 ibuf->rect_float[pos]=depth; 02630 ibuf->rect_float[pos+1]=depth; 02631 ibuf->rect_float[pos+2]=depth; 02632 ibuf->rect_float[pos+3]=1.0f; 02633 } 02634 /* waves */ 02635 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) { 02636 PaintWavePoint *wPoint = &((PaintWavePoint*)sData->type_data)[index]; 02637 float depth = wPoint->height; 02638 if (surface->depth_clamp) 02639 depth /= surface->depth_clamp; 02640 depth = (0.5f + depth/2.0f); 02641 CLAMP(depth, 0.0f, 1.0f); 02642 02643 ibuf->rect_float[pos]=depth; 02644 ibuf->rect_float[pos+1]=depth; 02645 ibuf->rect_float[pos+2]=depth; 02646 ibuf->rect_float[pos+3]=1.0f; 02647 } 02648 } 02649 } 02650 02651 /* Set output format, png in case exr isnt supported */ 02652 ibuf->ftype= PNG|95; 02653 #ifdef WITH_OPENEXR 02654 if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */ 02655 ibuf->ftype = OPENEXR | OPENEXR_COMPRESS; 02656 } 02657 #endif 02658 02659 /* Save image */ 02660 IMB_saveiff(ibuf, output_file, IB_rectfloat); 02661 IMB_freeImBuf(ibuf); 02662 } 02663 02664 02665 /***************************** Material / Texture Sampling ******************************/ 02666 02667 /* stores a copy of required materials to allow doing adjustments 02668 * without interfering the render/preview */ 02669 typedef struct BrushMaterials { 02670 Material *mat; 02671 Material **ob_mats; 02672 int tot; 02673 } BrushMaterials; 02674 02675 /* Initialize materials for brush object: 02676 * Calculates inverse matrices for linked objects, updates 02677 * volume caches etc. */ 02678 static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat, Scene *scene, BrushMaterials *bMats) 02679 { 02680 /* Calculate inverse transformation matrix 02681 * for this object */ 02682 invert_m4_m4(brushOb->imat, brushOb->obmat); 02683 copy_m4_m4(brushOb->imat_ren, brushOb->imat); 02684 02685 /* Now process every material linked to this brush object */ 02686 if ((ui_mat == NULL) && brushOb->mat && brushOb->totcol) { 02687 int i, tot=(*give_totcolp(brushOb)); 02688 02689 /* allocate material pointer array */ 02690 if (tot) { 02691 bMats->ob_mats = MEM_callocN(sizeof(Material*)*(tot), "BrushMaterials"); 02692 for (i=0; i<tot; i++) { 02693 bMats->ob_mats[i] = RE_init_sample_material(give_current_material(brushOb,(i+1)), scene); 02694 } 02695 } 02696 bMats->tot = tot; 02697 } 02698 else { 02699 bMats->mat = RE_init_sample_material(ui_mat, scene); 02700 } 02701 } 02702 02703 /* free all data allocated by dynamicPaint_updateBrushMaterials() */ 02704 static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats) 02705 { 02706 /* Now process every material linked to this brush object */ 02707 if (bMats->ob_mats) { 02708 int i; 02709 for (i=0; i<bMats->tot; i++) { 02710 RE_free_sample_material(bMats->ob_mats[i]); 02711 } 02712 MEM_freeN(bMats->ob_mats); 02713 } 02714 else if (bMats->mat) { 02715 RE_free_sample_material(bMats->mat); 02716 } 02717 } 02718 02719 /* 02720 * Get material diffuse color and alpha (including linked textures) in given coordinates 02721 */ 02722 void dynamicPaint_doMaterialTex(BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb, const float volume_co[3], const float surface_co[3], int faceIndex, short isQuad, DerivedMesh *orcoDm) 02723 { 02724 Material *mat = bMats->mat; 02725 MFace *mface = orcoDm->getFaceArray(orcoDm); 02726 02727 /* If no material defined, use the one assigned to the mesh face */ 02728 if (mat == NULL) { 02729 if (bMats->ob_mats) { 02730 int mat_nr = mface[faceIndex].mat_nr; 02731 if (mat_nr >= (*give_totcolp(brushOb))) return; 02732 mat = bMats->ob_mats[mat_nr]; 02733 if (mat == NULL) return; /* No material assigned */ 02734 } 02735 else return; 02736 } 02737 02738 RE_sample_material_color(mat, color, alpha, volume_co, surface_co, faceIndex, isQuad, orcoDm, brushOb); 02739 } 02740 02741 02742 /***************************** Ray / Nearest Point Utils ******************************/ 02743 02744 02745 /* A modified callback to bvh tree raycast. The tree must bust have been built using bvhtree_from_mesh_faces. 02746 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. 02747 * 02748 * To optimize brush detection speed this doesn't calculate hit coordinates or normal. 02749 * If ray hit the second half of a quad, no[0] is set to 1.0f. 02750 */ 02751 static void mesh_faces_spherecast_dp(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) 02752 { 02753 const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata; 02754 MVert *vert = data->vert; 02755 MFace *face = data->face + index; 02756 short quad = 0; 02757 02758 float *t0, *t1, *t2, *t3; 02759 t0 = vert[ face->v1 ].co; 02760 t1 = vert[ face->v2 ].co; 02761 t2 = vert[ face->v3 ].co; 02762 t3 = face->v4 ? vert[ face->v4].co : NULL; 02763 02764 do 02765 { 02766 float dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2); 02767 02768 if(dist >= 0 && dist < hit->dist) 02769 { 02770 hit->index = index; 02771 hit->dist = dist; 02772 hit->no[0] = (quad) ? 1.0f : 0.0f; 02773 } 02774 02775 t1 = t2; 02776 t2 = t3; 02777 t3 = NULL; 02778 quad = 1; 02779 02780 } while(t2); 02781 } 02782 02783 /* A modified callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_faces. 02784 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. 02785 * 02786 * To optimize brush detection speed this doesn't calculate hit normal. 02787 * If ray hit the second half of a quad, no[0] is set to 1.0f, else 0.0f 02788 */ 02789 static void mesh_faces_nearest_point_dp(void *userdata, int index, const float *co, BVHTreeNearest *nearest) 02790 { 02791 const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata; 02792 MVert *vert = data->vert; 02793 MFace *face = data->face + index; 02794 short quad = 0; 02795 02796 float *t0, *t1, *t2, *t3; 02797 t0 = vert[ face->v1 ].co; 02798 t1 = vert[ face->v2 ].co; 02799 t2 = vert[ face->v3 ].co; 02800 t3 = face->v4 ? vert[ face->v4].co : NULL; 02801 02802 do 02803 { 02804 float nearest_tmp[3], dist; 02805 int vertex, edge; 02806 02807 dist = nearest_point_in_tri_surface(t0, t1, t2, co, &vertex, &edge, nearest_tmp); 02808 if(dist < nearest->dist) 02809 { 02810 nearest->index = index; 02811 nearest->dist = dist; 02812 copy_v3_v3(nearest->co, nearest_tmp); 02813 nearest->no[0] = (quad) ? 1.0f : 0.0f; 02814 } 02815 02816 t1 = t2; 02817 t2 = t3; 02818 t3 = NULL; 02819 quad = 1; 02820 02821 } while(t2); 02822 } 02823 02824 02825 /***************************** Brush Painting Calls ******************************/ 02826 02827 /* 02828 * Mix color values to canvas point. 02829 * 02830 * surface : canvas surface 02831 * index : surface point index 02832 * paintFlags : paint object flags 02833 * paintColor,Alpha,Wetness : to be mixed paint values 02834 * timescale : value used to adjust time dependand 02835 * operations when using substeps 02836 */ 02837 static void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int paintFlags, float *paintColor, float *paintAlpha, float *paintWetness, float *timescale) 02838 { 02839 PaintPoint *pPoint = &((PaintPoint*)surface->data->type_data)[index]; 02840 02841 /* Add paint */ 02842 if (!(paintFlags & MOD_DPAINT_ERASE)) { 02843 float mix[4]; 02844 float temp_alpha = (*paintAlpha) * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : (*timescale)); 02845 02846 /* mix brush color with wet layer color */ 02847 blendColors(pPoint->e_color, pPoint->e_alpha, paintColor, temp_alpha, mix); 02848 copy_v3_v3(pPoint->e_color, mix); 02849 02850 /* mix wetness and alpha depending on selected alpha mode */ 02851 if (paintFlags & MOD_DPAINT_ABS_ALPHA) { 02852 /* update values to the brush level unless theyre higher already */ 02853 if (pPoint->e_alpha < (*paintAlpha)) pPoint->e_alpha = (*paintAlpha); 02854 if (pPoint->wetness < (*paintWetness)) pPoint->wetness = (*paintWetness); 02855 } 02856 else { 02857 float wetness = (*paintWetness); 02858 CLAMP(wetness, 0.0f, 1.0f); 02859 pPoint->e_alpha = mix[3]; 02860 pPoint->wetness = pPoint->wetness*(1.0f-wetness) + wetness; 02861 } 02862 02863 if (pPoint->wetness<MIN_WETNESS) pPoint->wetness = MIN_WETNESS; 02864 02865 pPoint->state = DPAINT_PAINT_NEW; 02866 } 02867 /* Erase paint */ 02868 else { 02869 float a_ratio, a_highest; 02870 float wetness; 02871 float invFact = 1.0f - (*paintAlpha); 02872 02873 /* 02874 * Make highest alpha to match erased value 02875 * but maintain alpha ratio 02876 */ 02877 if (paintFlags & MOD_DPAINT_ABS_ALPHA) { 02878 a_highest = (pPoint->e_alpha > pPoint->alpha) ? pPoint->e_alpha : pPoint->alpha; 02879 if (a_highest > invFact) { 02880 a_ratio = invFact / a_highest; 02881 02882 pPoint->e_alpha *= a_ratio; 02883 pPoint->alpha *= a_ratio; 02884 } 02885 } 02886 else { 02887 pPoint->e_alpha -= (*paintAlpha) * (*timescale); 02888 if (pPoint->e_alpha < 0.0f) pPoint->e_alpha = 0.0f; 02889 pPoint->alpha -= (*paintAlpha) * (*timescale); 02890 if (pPoint->alpha < 0.0f) pPoint->alpha = 0.0f; 02891 } 02892 02893 wetness = (1.0f - (*paintWetness)) * pPoint->e_alpha; 02894 if (pPoint->wetness > wetness) pPoint->wetness = wetness; 02895 } 02896 } 02897 02898 /* applies given brush intersection value for wave surface */ 02899 static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrushSettings *brush, float isect_height) 02900 { 02901 float isect_change = isect_height - wPoint->brush_isect; 02902 int hit = 0; 02903 /* intersection marked regardless of brush type or hit */ 02904 wPoint->brush_isect = isect_height; 02905 wPoint->state = DPAINT_WAVE_ISECT_CHANGED; 02906 02907 isect_height *= brush->wave_factor; 02908 02909 /* determine hit depending on wave_factor */ 02910 if (brush->wave_factor > 0.0f && wPoint->height > isect_height) 02911 hit = 1; 02912 else if (brush->wave_factor < 0.0f && wPoint->height < isect_height) 02913 hit = 1; 02914 02915 if (hit) { 02916 if (brush->wave_type == MOD_DPAINT_WAVEB_DEPTH) { 02917 wPoint->height = isect_height; 02918 wPoint->state = DPAINT_WAVE_OBSTACLE; 02919 wPoint->velocity = 0.0f; 02920 } 02921 else if (brush->wave_type == MOD_DPAINT_WAVEB_FORCE) 02922 wPoint->velocity = isect_height; 02923 else if (brush->wave_type == MOD_DPAINT_WAVEB_REFLECT) 02924 wPoint->state = DPAINT_WAVE_REFLECT_ONLY; 02925 else if (brush->wave_type == MOD_DPAINT_WAVEB_CHANGE) { 02926 if (isect_change < 0.0f) 02927 wPoint->height += isect_change*brush->wave_factor; 02928 } 02929 } 02930 } 02931 02932 /* 02933 * add brush results to the surface data depending on surface type 02934 */ 02935 static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned int index, DynamicPaintBrushSettings *brush, 02936 float paint[3], float influence, float depth, float vel_factor, float timescale) 02937 { 02938 PaintSurfaceData *sData = surface->data; 02939 float strength; 02940 02941 /* apply influence scale */ 02942 influence *= surface->influence_scale; 02943 depth *= surface->influence_scale; 02944 02945 strength = influence * brush->alpha; 02946 CLAMP(strength, 0.0f, 1.0f); 02947 02948 /* Sample velocity colorband if required */ 02949 if (brush->flags & (MOD_DPAINT_VELOCITY_ALPHA|MOD_DPAINT_VELOCITY_COLOR|MOD_DPAINT_VELOCITY_DEPTH)) { 02950 float coba_res[4]; 02951 vel_factor /= brush->max_velocity; 02952 CLAMP(vel_factor, 0.0f, 1.0f); 02953 02954 if (do_colorband(brush->vel_ramp, vel_factor, coba_res)) { 02955 if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) { 02956 paint[0] = coba_res[0]; 02957 paint[1] = coba_res[1]; 02958 paint[2] = coba_res[2]; 02959 } 02960 if (brush->flags & MOD_DPAINT_VELOCITY_ALPHA) 02961 strength *= coba_res[3]; 02962 if (brush->flags & MOD_DPAINT_VELOCITY_DEPTH) 02963 depth *= coba_res[3]; 02964 } 02965 } 02966 02967 /* mix paint surface */ 02968 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { 02969 02970 float paintWetness = brush->wetness * strength; 02971 float paintAlpha = strength; 02972 02973 dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, &paintAlpha, &paintWetness, ×cale); 02974 02975 } 02976 /* displace surface */ 02977 else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) { 02978 float *value = (float*)sData->type_data; 02979 02980 if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) 02981 depth = value[index] + depth; 02982 02983 if (surface->depth_clamp) { 02984 CLAMP(depth, 0.0f-surface->depth_clamp, surface->depth_clamp); 02985 } 02986 02987 if (brush->flags & MOD_DPAINT_ERASE) { 02988 value[index] *= (1.0f - strength); 02989 if (value[index] < 0.0f) value[index] = 0.0f; 02990 } 02991 else { 02992 if (value[index] < depth) value[index] = depth; 02993 } 02994 } 02995 /* vertex weight group surface */ 02996 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) { 02997 float *value = (float*)sData->type_data; 02998 02999 if (brush->flags & MOD_DPAINT_ERASE) { 03000 value[index] *= (1.0f - strength); 03001 if (value[index] < 0.0f) value[index] = 0.0f; 03002 } 03003 else { 03004 if (value[index] < strength) value[index] = strength; 03005 } 03006 } 03007 /* wave surface */ 03008 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) { 03009 if (brush->wave_clamp) { 03010 CLAMP(depth, 0.0f-brush->wave_clamp, brush->wave_clamp); 03011 } 03012 03013 dynamicPaint_mixWaveHeight(&((PaintWavePoint*)sData->type_data)[index], 03014 brush, 0.0f-depth); 03015 } 03016 03017 /* doing velocity based painting */ 03018 if (sData->bData->brush_velocity) { 03019 sData->bData->brush_velocity[index*4+3] *= influence; 03020 } 03021 } 03022 03023 /* checks whether surface and brush bounds intersect depending on brush type */ 03024 static int meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius) 03025 { 03026 if (brush->collision == MOD_DPAINT_COL_VOLUME) 03027 return boundsIntersect(b1, b2); 03028 else if (brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST) 03029 return boundsIntersectDist(b1, b2, brush_radius); 03030 else return 1; 03031 } 03032 03033 /* calculate velocity for mesh vertices */ 03034 static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale) 03035 { 03036 int i; 03037 float prev_obmat[4][4]; 03038 DerivedMesh *dm_p, *dm_c; 03039 MVert *mvert_p, *mvert_c; 03040 int numOfVerts_p, numOfVerts_c; 03041 03042 float cur_sfra = scene->r.subframe; 03043 int cur_fra = scene->r.cfra; 03044 float prev_sfra = cur_sfra - timescale; 03045 int prev_fra = cur_fra; 03046 03047 if (prev_sfra < 0.0f) { 03048 prev_sfra += 1.0f; 03049 prev_fra = cur_fra - 1; 03050 } 03051 03052 /* previous frame dm */ 03053 scene->r.cfra = prev_fra; 03054 scene->r.subframe = prev_sfra; 03055 03056 subframe_updateObject(scene, ob, UPDATE_EVERYTHING, BKE_curframe(scene)); 03057 dm_p = CDDM_copy(brush->dm); 03058 numOfVerts_p = dm_p->getNumVerts(dm_p); 03059 mvert_p = dm_p->getVertArray(dm_p); 03060 copy_m4_m4(prev_obmat, ob->obmat); 03061 03062 /* current frame dm */ 03063 scene->r.cfra = cur_fra; 03064 scene->r.subframe = cur_sfra; 03065 03066 subframe_updateObject(scene, ob, UPDATE_EVERYTHING, BKE_curframe(scene)); 03067 dm_c = brush->dm; 03068 numOfVerts_c = dm_c->getNumVerts(dm_c); 03069 mvert_c = dm_p->getVertArray(dm_c); 03070 03071 (*brushVel) = (struct Vec3f *) MEM_mallocN(numOfVerts_c*sizeof(Vec3f), "Dynamic Paint brush velocity"); 03072 if (!(*brushVel)) return; 03073 03074 /* if mesh is constructive -> num of verts has changed, 03075 * only use current frame derived mesh */ 03076 if (numOfVerts_p != numOfVerts_c) 03077 mvert_p = mvert_c; 03078 03079 /* calculate speed */ 03080 #pragma omp parallel for schedule(static) 03081 for (i=0; i<numOfVerts_c; i++) { 03082 float p1[3], p2[3]; 03083 03084 copy_v3_v3(p1, mvert_p[i].co); 03085 mul_m4_v3(prev_obmat, p1); 03086 03087 copy_v3_v3(p2, mvert_c[i].co); 03088 mul_m4_v3(ob->obmat, p2); 03089 03090 sub_v3_v3v3((*brushVel)[i].v, p2, p1); 03091 mul_v3_fl((*brushVel)[i].v, 1.0f/timescale); 03092 } 03093 03094 dm_p->release(dm_p); 03095 } 03096 03097 /* calculate velocity for object center point */ 03098 static void dynamicPaint_brushObjectCalculateVelocity(Scene *scene, Object *ob, Vec3f *brushVel, float timescale) 03099 { 03100 float prev_obmat[4][4]; 03101 float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f}; 03102 03103 float cur_sfra = scene->r.subframe; 03104 int cur_fra = scene->r.cfra; 03105 float prev_sfra = cur_sfra - timescale; 03106 int prev_fra = cur_fra; 03107 03108 if (prev_sfra < 0.0f) { 03109 prev_sfra += 1.0f; 03110 prev_fra = cur_fra - 1; 03111 } 03112 03113 /* previous frame dm */ 03114 scene->r.cfra = prev_fra; 03115 scene->r.subframe = prev_sfra; 03116 subframe_updateObject(scene, ob, UPDATE_PARENTS, BKE_curframe(scene)); 03117 copy_m4_m4(prev_obmat, ob->obmat); 03118 03119 /* current frame dm */ 03120 scene->r.cfra = cur_fra; 03121 scene->r.subframe = cur_sfra; 03122 subframe_updateObject(scene, ob, UPDATE_PARENTS, BKE_curframe(scene)); 03123 03124 /* calculate speed */ 03125 mul_m4_v3(prev_obmat, prev_loc); 03126 mul_m4_v3(ob->obmat, cur_loc); 03127 03128 sub_v3_v3v3(brushVel->v, cur_loc, prev_loc); 03129 mul_v3_fl(brushVel->v, 1.0f/timescale); 03130 } 03131 03132 /* 03133 * Paint a brush object mesh to the surface 03134 */ 03135 static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, 03136 DynamicPaintBrushSettings *brush, 03137 Object *brushOb, 03138 BrushMaterials *bMats, 03139 Scene *scene, 03140 float timescale) 03141 { 03142 PaintSurfaceData *sData = surface->data; 03143 PaintBakeData *bData = sData->bData; 03144 DerivedMesh *dm = NULL; 03145 Vec3f *brushVelocity = NULL; 03146 MVert *mvert = NULL; 03147 MFace *mface = NULL; 03148 03149 if (brush->flags & MOD_DPAINT_USES_VELOCITY) 03150 dynamicPaint_brushMeshCalculateVelocity(scene, brushOb, brush, &brushVelocity, timescale); 03151 03152 if (!brush->dm) return 0; 03153 { 03154 BVHTreeFromMesh treeData = {0}; 03155 float avg_brushNor[3] = {0.0f}; 03156 float brush_radius = brush->paint_distance * surface->radius_scale; 03157 int numOfVerts; 03158 int ii; 03159 Bounds3D mesh_bb = {0}; 03160 VolumeGrid *grid = bData->grid; 03161 03162 dm = CDDM_copy(brush->dm); 03163 mvert = dm->getVertArray(dm); 03164 mface = dm->getFaceArray(dm); 03165 numOfVerts = dm->getNumVerts(dm); 03166 03167 /* Transform collider vertices to global space 03168 * (Faster than transforming per surface point 03169 * coordinates and normals to object space) */ 03170 for (ii=0; ii<numOfVerts; ii++) { 03171 mul_m4_v3(brushOb->obmat, mvert[ii].co); 03172 boundInsert(&mesh_bb, mvert[ii].co); 03173 03174 /* for project brush calculate average normal */ 03175 if (brush->collision & MOD_DPAINT_COL_DIST && brush->flags & MOD_DPAINT_PROX_PROJECT) { 03176 float nor[3]; 03177 normal_short_to_float_v3(nor, mvert[ii].no); 03178 mul_mat3_m4_v3(brushOb->obmat, nor); 03179 normalize_v3(nor); 03180 03181 add_v3_v3(avg_brushNor, nor); 03182 } 03183 } 03184 03185 if (brush->collision & MOD_DPAINT_COL_DIST && brush->flags & MOD_DPAINT_PROX_PROJECT) { 03186 mul_v3_fl(avg_brushNor, 1.0f/(float)numOfVerts); 03187 /* instead of null vector use positive z */ 03188 if (!(MIN3(avg_brushNor[0],avg_brushNor[1],avg_brushNor[2]))) 03189 avg_brushNor[2] = 1.0f; 03190 else 03191 normalize_v3(avg_brushNor); 03192 } 03193 03194 /* check bounding box collision */ 03195 if(grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) 03196 /* Build a bvh tree from transformed vertices */ 03197 if (bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 8)) 03198 { 03199 int c_index; 03200 int total_cells = grid->dim[0]*grid->dim[1]*grid->dim[2]; 03201 03202 /* loop through space partitioning grid */ 03203 for (c_index=0; c_index<total_cells; c_index++) { 03204 int id; 03205 03206 /* check grid cell bounding box */ 03207 if (!grid->s_num[c_index] || !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius)) 03208 continue; 03209 03210 /* loop through cell points and process brush */ 03211 #pragma omp parallel for schedule(static) 03212 for (id = 0; id < grid->s_num[c_index]; id++) 03213 { 03214 int index = grid->t_index[grid->s_pos[c_index] + id]; 03215 int ss, samples = bData->s_num[index]; 03216 float total_sample = (float)samples; 03217 float brushStrength = 0.0f; /* brush influence factor */ 03218 float depth = 0.0f; /* brush intersection depth */ 03219 float velocity_val = 0.0f; 03220 03221 float paintColor[3] = {0.0f}; 03222 int numOfHits = 0; 03223 03224 /* for image sequence anti-aliasing, use gaussian factors */ 03225 if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) 03226 total_sample = gaussianTotal; 03227 03228 /* Supersampling */ 03229 for (ss=0; ss<samples; ss++) 03230 { 03231 03232 float ray_start[3], ray_dir[3]; 03233 float sample_factor = 0.0f; 03234 float sampleStrength = 0.0f; 03235 BVHTreeRayHit hit; 03236 BVHTreeNearest nearest; 03237 short hit_found = 0; 03238 03239 /* volume sample */ 03240 float volume_factor = 0.0f; 03241 /* proximity sample */ 03242 float proximity_factor = 0.0f; 03243 float prox_colorband[4] = {0.0f}; 03244 int inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX && 03245 brush->collision == MOD_DPAINT_COL_VOLDIST); 03246 03247 /* hit data */ 03248 float hitCoord[3]; 03249 int hitFace = -1; 03250 short hitQuad = 0; 03251 03252 /* Supersampling factor */ 03253 if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) 03254 sample_factor = gaussianFactors[ss]; 03255 else 03256 sample_factor = 1.0f; 03257 03258 /* Get current sample position in world coordinates */ 03259 copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index]+ss].v); 03260 copy_v3_v3(ray_dir, bData->bNormal[index].invNorm); 03261 03262 /* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */ 03263 add_v3_fl(ray_start, 0.001f); 03264 03265 hit.index = -1; 03266 hit.dist = 9999; 03267 nearest.index = -1; 03268 nearest.dist = brush_radius * brush_radius; /* find_nearest uses squared distance */ 03269 03270 /* Check volume collision */ 03271 if (brush->collision == MOD_DPAINT_COL_VOLUME || brush->collision == MOD_DPAINT_COL_VOLDIST) 03272 if(BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData) != -1) 03273 { 03274 /* We hit a triangle, now check if collision point normal is facing the point */ 03275 03276 /* For optimization sake, hit point normal isn't calculated in ray cast loop */ 03277 int v1=mface[hit.index].v1, v2=mface[hit.index].v2, v3=mface[hit.index].v3, quad=(hit.no[0] == 1.0f); 03278 float dot; 03279 03280 if (quad) {v2=mface[hit.index].v3; v3=mface[hit.index].v4;} 03281 normal_tri_v3( hit.no, mvert[v1].co, mvert[v2].co, mvert[v3].co); 03282 dot = ray_dir[0]*hit.no[0] + ray_dir[1]*hit.no[1] + ray_dir[2]*hit.no[2]; 03283 03284 /* If ray and hit face normal are facing same direction 03285 * hit point is inside a closed mesh. */ 03286 if (dot>=0) 03287 { 03288 float dist = hit.dist; 03289 int f_index = hit.index; 03290 03291 /* Also cast a ray in opposite direction to make sure 03292 * point is at least surrounded by two brush faces */ 03293 negate_v3(ray_dir); 03294 hit.index = -1; 03295 hit.dist = 9999; 03296 03297 BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData); 03298 03299 if(hit.index != -1) { 03300 /* Add factor on supersample filter */ 03301 volume_factor = 1.0f; 03302 hit_found = HIT_VOLUME; 03303 03304 /* Mark hit info */ 03305 madd_v3_v3v3fl(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */ 03306 depth += dist*sample_factor; 03307 hitFace = f_index; 03308 hitQuad = quad; 03309 } 03310 } 03311 } 03312 03313 /* Check proximity collision */ 03314 if ((brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST) && 03315 (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX))) 03316 { 03317 float proxDist = -1.0f; 03318 float hitCo[3]; 03319 short hQuad; 03320 int face; 03321 03322 /* if inverse prox and no hit found, skip this sample */ 03323 if (inner_proximity && !hit_found) continue; 03324 03325 /* If pure distance proximity, find the nearest point on the mesh */ 03326 if (brush->collision != MOD_DPAINT_COL_DIST || !(brush->flags & MOD_DPAINT_PROX_PROJECT)) { 03327 if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, mesh_faces_nearest_point_dp, &treeData) != -1) { 03328 proxDist = sqrtf(nearest.dist); 03329 copy_v3_v3(hitCo, nearest.co); 03330 hQuad = (nearest.no[0] == 1.0f); 03331 face = nearest.index; 03332 } 03333 } 03334 else { /* else cast a ray in defined projection direction */ 03335 float proj_ray[3] = {0.0f}; 03336 03337 if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) { 03338 copy_v3_v3(proj_ray, bData->bNormal[index].invNorm); 03339 negate_v3(proj_ray); 03340 } 03341 else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) { 03342 copy_v3_v3(proj_ray, avg_brushNor); 03343 } 03344 else { /* MOD_DPAINT_RAY_ZPLUS */ 03345 proj_ray[2] = 1.0f; 03346 } 03347 hit.index = -1; 03348 hit.dist = brush_radius; 03349 03350 /* Do a face normal directional raycast, and use that distance */ 03351 if(BLI_bvhtree_ray_cast(treeData.tree, ray_start, proj_ray, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData) != -1) 03352 { 03353 proxDist = hit.dist; 03354 madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */ 03355 hQuad = (hit.no[0] == 1.0f); 03356 face = hit.index; 03357 } 03358 } 03359 03360 /* If a hit was found, calculate required values */ 03361 if (proxDist >= 0.0f && proxDist <= brush_radius) { 03362 proximity_factor = proxDist / brush_radius; 03363 CLAMP(proximity_factor, 0.0f, 1.0f); 03364 if (!inner_proximity) 03365 proximity_factor = 1.0f - proximity_factor; 03366 03367 hit_found = HIT_PROXIMITY; 03368 03369 /* if no volume hit, use prox point face info */ 03370 if (hitFace == -1) { 03371 copy_v3_v3(hitCoord, hitCo); 03372 hitQuad = hQuad; 03373 hitFace = face; 03374 } 03375 } 03376 } 03377 03378 /* mix final sample strength depending on brush settings */ 03379 if (hit_found) { 03380 /* if "negate volume" enabled, negate all factors within volume*/ 03381 if (brush->collision == MOD_DPAINT_COL_VOLDIST && brush->flags & MOD_DPAINT_NEGATE_VOLUME) { 03382 volume_factor = 1.0f - volume_factor; 03383 if (inner_proximity) 03384 proximity_factor = 1.0f - proximity_factor; 03385 } 03386 03387 /* apply final sample depending on final hit type */ 03388 if (hit_found == HIT_VOLUME) { 03389 sampleStrength = volume_factor; 03390 } 03391 else if (hit_found == HIT_PROXIMITY) { 03392 /* apply falloff curve to the proximity_factor */ 03393 if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, (1.0f-proximity_factor), prox_colorband)) 03394 proximity_factor = prox_colorband[3]; 03395 else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT) 03396 proximity_factor = (!inner_proximity || brush->flags & MOD_DPAINT_NEGATE_VOLUME) ? 1.0f : 0.0f; 03397 /* apply sample */ 03398 sampleStrength = proximity_factor; 03399 } 03400 03401 sampleStrength *= sample_factor; 03402 } 03403 else continue; 03404 03405 /* velocity brush, only do on main sample */ 03406 if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss==0 && brushVelocity) { 03407 int v1,v2,v3; 03408 float weights[4]; 03409 float brushPointVelocity[3]; 03410 float velocity[3]; 03411 03412 if (!hitQuad) { 03413 v1 = mface[hitFace].v1; 03414 v2 = mface[hitFace].v2; 03415 v3 = mface[hitFace].v3; 03416 } 03417 else { 03418 v1 = mface[hitFace].v2; 03419 v2 = mface[hitFace].v3; 03420 v3 = mface[hitFace].v4; 03421 } 03422 /* calculate barycentric weights for hit point */ 03423 interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord); 03424 03425 /* simple check based on brush surface velocity, 03426 * todo: perhaps implement something that handles volume movement as well */ 03427 03428 /* interpolate vertex speed vectors to get hit point velocity */ 03429 interp_v3_v3v3v3( brushPointVelocity, 03430 brushVelocity[v1].v, 03431 brushVelocity[v2].v, 03432 brushVelocity[v3].v, weights); 03433 03434 /* substract canvas point velocity */ 03435 if (bData->velocity) { 03436 sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v); 03437 } 03438 else { 03439 copy_v3_v3(velocity, brushPointVelocity); 03440 } 03441 velocity_val = len_v3(velocity); 03442 03443 /* if brush has smudge enabled store brush velocity */ 03444 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && 03445 brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity) { 03446 copy_v3_v3(&bData->brush_velocity[index*4], velocity); 03447 mul_v3_fl(&bData->brush_velocity[index*4], 1.0f/velocity_val); 03448 bData->brush_velocity[index*4+3] = velocity_val; 03449 } 03450 } 03451 03452 /* 03453 * Process hit color and alpha 03454 */ 03455 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) 03456 { 03457 float sampleColor[3]; 03458 float alpha_factor = 1.0f; 03459 03460 sampleColor[0] = brush->r; 03461 sampleColor[1] = brush->g; 03462 sampleColor[2] = brush->b; 03463 03464 /* Get material+textures color on hit point if required */ 03465 if (brush_usesMaterial(brush, scene)) 03466 dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb, bData->realCoord[bData->s_pos[index]+ss].v, hitCoord, hitFace, hitQuad, brush->dm); 03467 03468 /* Sample proximity colorband if required */ 03469 if ((hit_found == HIT_PROXIMITY) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)) { 03470 if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) { 03471 sampleColor[0] = prox_colorband[0]; 03472 sampleColor[1] = prox_colorband[1]; 03473 sampleColor[2] = prox_colorband[2]; 03474 } 03475 } 03476 03477 /* Add AA sample */ 03478 paintColor[0] += sampleColor[0]; 03479 paintColor[1] += sampleColor[1]; 03480 paintColor[2] += sampleColor[2]; 03481 sampleStrength *= alpha_factor; 03482 numOfHits++; 03483 } 03484 03485 /* apply sample strength */ 03486 brushStrength += sampleStrength; 03487 } // end supersampling 03488 03489 03490 /* if any sample was inside paint range */ 03491 if (brushStrength > 0.0f || depth > 0.0f) { 03492 03493 /* apply supersampling results */ 03494 if (samples > 1) { 03495 brushStrength /= total_sample; 03496 } 03497 CLAMP(brushStrength, 0.0f, 1.0f); 03498 03499 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { 03500 /* Get final pixel color and alpha */ 03501 paintColor[0] /= numOfHits; 03502 paintColor[1] /= numOfHits; 03503 paintColor[2] /= numOfHits; 03504 } 03505 /* get final object space depth */ 03506 else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || 03507 surface->type == MOD_DPAINT_SURFACE_T_WAVE) { 03508 depth /= bData->bNormal[index].normal_scale * total_sample; 03509 } 03510 03511 dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale); 03512 } 03513 } 03514 } 03515 } 03516 /* free bvh tree */ 03517 free_bvhtree_from_mesh(&treeData); 03518 dm->release(dm); 03519 03520 } 03521 03522 /* free brush velocity data */ 03523 if (brushVelocity) 03524 MEM_freeN(brushVelocity); 03525 03526 return 1; 03527 } 03528 03529 /* 03530 * Paint a particle system to the surface 03531 */ 03532 static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, 03533 ParticleSystem *psys, 03534 DynamicPaintBrushSettings *brush, 03535 float timescale) 03536 { 03537 ParticleSettings *part=psys->part; 03538 ParticleData *pa = NULL; 03539 PaintSurfaceData *sData = surface->data; 03540 PaintBakeData *bData = sData->bData; 03541 VolumeGrid *grid = bData->grid; 03542 03543 KDTree *tree; 03544 int particlesAdded = 0; 03545 int invalidParticles = 0; 03546 int p = 0; 03547 03548 float solidradius = surface->radius_scale*((brush->flags & MOD_DPAINT_PART_RAD) ? psys->part->size : brush->particle_radius); 03549 float smooth = brush->particle_smooth*surface->radius_scale; 03550 03551 float range = solidradius + smooth; 03552 float particle_timestep = 0.04f * part->timetweak; 03553 03554 Bounds3D part_bb = {0}; 03555 03556 if (psys->totpart < 1) return 1; 03557 03558 /* 03559 * Build a kd-tree to optimize distance search 03560 */ 03561 tree= BLI_kdtree_new(psys->totpart); 03562 03563 /* loop through particles and insert valid ones to the tree */ 03564 for(p=0, pa=psys->particles; p<psys->totpart; p++, pa++) { 03565 03566 /* Proceed only if particle is active */ 03567 if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue; 03568 else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0) continue; 03569 else if(pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) continue; 03570 03571 /* for debug purposes check if any NAN particle proceeds 03572 * For some reason they get past activity check, this should rule most of them out */ 03573 if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {invalidParticles++;continue;} 03574 03575 /* make sure particle is close enough to canvas */ 03576 if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range)) continue; 03577 03578 BLI_kdtree_insert(tree, p, pa->state.co, NULL); 03579 03580 /* calc particle system bounds */ 03581 boundInsert(&part_bb, pa->state.co); 03582 03583 particlesAdded++; 03584 } 03585 if (invalidParticles) 03586 printf("Warning: Invalid particle(s) found!\n"); 03587 03588 /* If no suitable particles were found, exit */ 03589 if (particlesAdded < 1) { 03590 BLI_kdtree_free(tree); 03591 return 1; 03592 } 03593 03594 /* begin thread safe malloc */ 03595 BLI_begin_threaded_malloc(); 03596 03597 /* only continue if particle bb is close enough to canvas bb */ 03598 if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) 03599 { 03600 int c_index; 03601 int total_cells = grid->dim[0]*grid->dim[1]*grid->dim[2]; 03602 03603 /* balance tree */ 03604 BLI_kdtree_balance(tree); 03605 03606 /* loop through space partitioning grid */ 03607 for (c_index=0; c_index<total_cells; c_index++) { 03608 int id; 03609 03610 /* check cell bounding box */ 03611 if (!grid->s_num[c_index] || 03612 !boundsIntersectDist(&grid->bounds[c_index], &part_bb, range)) 03613 continue; 03614 03615 /* loop through cell points */ 03616 #pragma omp parallel for schedule(static) 03617 for (id = 0; id < grid->s_num[c_index]; id++) 03618 { 03619 int index = grid->t_index[grid->s_pos[c_index] + id]; 03620 float disp_intersect = 0.0f; 03621 float radius = 0.0f; 03622 float strength = 0.0f; 03623 float velocity_val = 0.0f; 03624 int part_index= -1; 03625 03626 /* 03627 * With predefined radius, there is no variation between particles. 03628 * It's enough to just find the nearest one. 03629 */ 03630 { 03631 KDTreeNearest nearest; 03632 float smooth_range, part_solidradius; 03633 03634 /* Find nearest particle and get distance to it */ 03635 BLI_kdtree_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, NULL, &nearest); 03636 /* if outside maximum range, no other particle can influence either */ 03637 if (nearest.dist > range) continue; 03638 03639 if (brush->flags & MOD_DPAINT_PART_RAD) { 03640 /* use particles individual size */ 03641 ParticleData *pa = psys->particles + nearest.index; 03642 part_solidradius = pa->size; 03643 } 03644 else { 03645 part_solidradius = solidradius; 03646 } 03647 radius = part_solidradius + smooth; 03648 if (nearest.dist < radius) { 03649 /* distances inside solid radius has maximum influence -> dist = 0 */ 03650 smooth_range = (nearest.dist - part_solidradius); 03651 if (smooth_range<0.0f) smooth_range=0.0f; 03652 /* do smoothness if enabled */ 03653 if (smooth) smooth_range/=smooth; 03654 03655 strength = 1.0f - smooth_range; 03656 disp_intersect = radius - nearest.dist; 03657 part_index = nearest.index; 03658 } 03659 } 03660 /* If using random per particle radius and closest particle didn't give max influence */ 03661 if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) { 03662 /* 03663 * If we use per particle radius, we have to sample all particles 03664 * within max radius range 03665 */ 03666 KDTreeNearest *nearest; 03667 03668 int n, particles = 0; 03669 float smooth_range = smooth * (1.0f-strength), dist; 03670 /* calculate max range that can have particles with higher influence than the nearest one */ 03671 float max_range = smooth - strength*smooth + solidradius; 03672 03673 particles = BLI_kdtree_range_search(tree, max_range, bData->realCoord[bData->s_pos[index]].v, NULL, &nearest); 03674 03675 /* Find particle that produces highest influence */ 03676 for(n=0; n<particles; n++) { 03677 ParticleData *pa = psys->particles + nearest[n].index; 03678 float s_range; 03679 03680 /* skip if out of range */ 03681 if (nearest[n].dist > (pa->size + smooth)) 03682 continue; 03683 03684 /* update hit data */ 03685 s_range = nearest[n].dist - pa->size; 03686 /* skip if higher influence is already found */ 03687 if (smooth_range < s_range) 03688 continue; 03689 03690 /* update hit data */ 03691 smooth_range = s_range; 03692 dist = nearest[n].dist; 03693 part_index = nearest[n].index; 03694 03695 /* If inside solid range and no disp depth required, no need to seek further */ 03696 if ( (s_range < 0.0f) && 03697 (surface->type != MOD_DPAINT_SURFACE_T_DISPLACE) && 03698 (surface->type != MOD_DPAINT_SURFACE_T_WAVE)) 03699 { 03700 break; 03701 } 03702 } 03703 03704 if (nearest) MEM_freeN(nearest); 03705 03706 /* now calculate influence for this particle */ 03707 { 03708 float rad = radius + smooth, str; 03709 if ((rad-dist) > disp_intersect) { 03710 disp_intersect = radius - dist; 03711 radius = rad; 03712 } 03713 03714 /* do smoothness if enabled */ 03715 if (smooth_range<0.0f) smooth_range=0.0f; 03716 if (smooth) smooth_range/=smooth; 03717 str = 1.0f - smooth_range; 03718 /* if influence is greater, use this one */ 03719 if (str > strength) strength = str; 03720 } 03721 } 03722 03723 if (strength > 0.001f) 03724 { 03725 float paintColor[4] = {0.0f}; 03726 float depth = 0.0f; 03727 03728 /* apply velocity */ 03729 if ((brush->flags & MOD_DPAINT_USES_VELOCITY) && (part_index != -1)) { 03730 float velocity[3]; 03731 ParticleData *pa = psys->particles + part_index; 03732 mul_v3_v3fl(velocity, pa->state.vel, particle_timestep); 03733 03734 /* substract canvas point velocity */ 03735 if (bData->velocity) { 03736 sub_v3_v3(velocity, bData->velocity[index].v); 03737 } 03738 velocity_val = len_v3(velocity); 03739 03740 /* store brush velocity for smudge */ 03741 if ( (surface->type == MOD_DPAINT_SURFACE_T_PAINT) && 03742 (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)) 03743 { 03744 copy_v3_v3(&bData->brush_velocity[index*4], velocity); 03745 mul_v3_fl(&bData->brush_velocity[index*4], 1.0f/velocity_val); 03746 bData->brush_velocity[index*4+3] = velocity_val; 03747 } 03748 } 03749 03750 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { 03751 copy_v3_v3(paintColor, &brush->r); 03752 } 03753 else if ( (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) || 03754 (surface->type == MOD_DPAINT_SURFACE_T_WAVE)) 03755 { 03756 /* get displace depth */ 03757 disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius; 03758 depth = (radius - disp_intersect) / bData->bNormal[index].normal_scale; 03759 if (depth<0.0f) depth = 0.0f; 03760 } 03761 03762 dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale); 03763 } 03764 } 03765 } 03766 } 03767 BLI_end_threaded_malloc(); 03768 BLI_kdtree_free(tree); 03769 03770 return 1; 03771 } 03772 03773 /* paint a single point of defined proximity radius to the surface */ 03774 static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush, 03775 Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale) 03776 { 03777 int index; 03778 float brush_radius = brush->paint_distance * surface->radius_scale; 03779 PaintSurfaceData *sData = surface->data; 03780 PaintBakeData *bData = sData->bData; 03781 Vec3f brushVel; 03782 03783 if (brush->flags & MOD_DPAINT_USES_VELOCITY) 03784 dynamicPaint_brushObjectCalculateVelocity(scene, brushOb, &brushVel, timescale); 03785 03786 /* 03787 * Loop through every surface point 03788 */ 03789 #pragma omp parallel for schedule(static) 03790 for (index = 0; index < sData->total_points; index++) 03791 { 03792 float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v); 03793 float colorband[4] = {0.0f}; 03794 float strength; 03795 03796 if (distance > brush_radius) continue; 03797 03798 /* Smooth range or color ramp */ 03799 if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH || 03800 brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP) { 03801 03802 strength = 1.0f - distance / brush_radius; 03803 CLAMP(strength, 0.0f, 1.0f); 03804 } 03805 else strength = 1.0f; 03806 03807 if (strength >= 0.001f) { 03808 float paintColor[3] = {0.0f}; 03809 float depth = 0.0f; 03810 float velocity_val = 0.0f; 03811 03812 /* material */ 03813 if (brush_usesMaterial(brush, scene)) { 03814 float alpha_factor = 1.0f; 03815 float hit_coord[3]; 03816 MVert *mvert = brush->dm->getVertArray(brush->dm); 03817 /* use dummy coord of first vertex */ 03818 copy_v3_v3(hit_coord, mvert[0].co); 03819 mul_m4_v3(brushOb->obmat, hit_coord); 03820 03821 dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb, bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, 0, brush->dm); 03822 } 03823 03824 /* color ramp */ 03825 if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, (1.0f-strength), colorband)) 03826 strength = colorband[3]; 03827 03828 if (brush->flags & MOD_DPAINT_USES_VELOCITY) { 03829 float velocity[3]; 03830 03831 /* substract canvas point velocity */ 03832 if (bData->velocity) { 03833 sub_v3_v3v3(velocity, brushVel.v, bData->velocity[index].v); 03834 } 03835 else { 03836 copy_v3_v3(velocity, brushVel.v); 03837 } 03838 velocity_val = len_v3(velocity); 03839 03840 /* store brush velocity for smudge */ 03841 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && 03842 brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity) { 03843 copy_v3_v3(&bData->brush_velocity[index*4], velocity); 03844 mul_v3_fl(&bData->brush_velocity[index*4], 1.0f/velocity_val); 03845 bData->brush_velocity[index*4+3] = velocity_val; 03846 } 03847 } 03848 03849 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { 03850 if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && 03851 !(brush->flags & MOD_DPAINT_RAMP_ALPHA)) { 03852 paintColor[0] = colorband[0]; 03853 paintColor[1] = colorband[1]; 03854 paintColor[2] = colorband[2]; 03855 } 03856 else { 03857 if (!brush_usesMaterial(brush, scene)) { 03858 paintColor[0] = brush->r; 03859 paintColor[1] = brush->g; 03860 paintColor[2] = brush->b; 03861 } 03862 } 03863 } 03864 else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || 03865 surface->type == MOD_DPAINT_SURFACE_T_WAVE) { 03866 /* get displace depth */ 03867 float disp_intersect = (1.0f - sqrtf((brush_radius-distance) / brush_radius)) * brush_radius; 03868 depth = (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale; 03869 if (depth<0.0f) depth = 0.0f; 03870 } 03871 dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale); 03872 } 03873 } 03874 03875 return 1; 03876 } 03877 03878 03879 /***************************** Dynamic Paint Step / Baking ******************************/ 03880 03881 /* 03882 * Calculate current frame neighbouring point distances 03883 * and direction vectors 03884 */ 03885 static void dynamicPaint_prepareNeighbourData(DynamicPaintSurface *surface, int force_init) 03886 { 03887 PaintSurfaceData *sData = surface->data; 03888 PaintBakeData *bData = sData->bData; 03889 BakeNeighPoint *bNeighs; 03890 PaintAdjData *adj_data = sData->adj_data; 03891 Vec3f *realCoord = bData->realCoord; 03892 int index; 03893 03894 if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data) return; 03895 03896 if (bData->bNeighs) MEM_freeN(bData->bNeighs); 03897 bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets*sizeof(struct BakeNeighPoint),"PaintEffectBake"); 03898 if (!bNeighs) return; 03899 03900 #pragma omp parallel for schedule(static) 03901 for (index = 0; index < sData->total_points; index++) 03902 { 03903 int i; 03904 int numOfNeighs = adj_data->n_num[index]; 03905 03906 for (i=0; i<numOfNeighs; i++) { 03907 int n_index = adj_data->n_index[index]+i; 03908 int t_index = adj_data->n_target[n_index]; 03909 03910 /* dir vec */ 03911 sub_v3_v3v3(bNeighs[n_index].dir, realCoord[bData->s_pos[t_index]].v, realCoord[bData->s_pos[index]].v); 03912 /* dist */ 03913 bNeighs[n_index].dist = len_v3(bNeighs[n_index].dir); 03914 /* normalize dir */ 03915 if (bNeighs[n_index].dist) mul_v3_fl(bNeighs[n_index].dir, 1.0f/bNeighs[n_index].dist); 03916 } 03917 } 03918 03919 /* calculate average values (single thread) */ 03920 bData->average_dist = 0.0f; 03921 for (index = 0; index < sData->total_points; index++) 03922 { 03923 int i; 03924 int numOfNeighs = adj_data->n_num[index]; 03925 03926 for (i=0; i<numOfNeighs; i++) { 03927 bData->average_dist += (double)bNeighs[adj_data->n_index[index]+i].dist; 03928 } 03929 } 03930 bData->average_dist /= adj_data->total_targets; 03931 } 03932 03933 /* find two adjacency points (closest_id) and influence (closest_d) to move paint towards when affected by a force */ 03934 void surface_determineForceTargetPoints(PaintSurfaceData *sData, int index, float force[3], float closest_d[2], int closest_id[2]) 03935 { 03936 BakeNeighPoint *bNeighs = sData->bData->bNeighs; 03937 int numOfNeighs = sData->adj_data->n_num[index]; 03938 int i; 03939 03940 closest_id[0]=closest_id[1]= -1; 03941 closest_d[0]=closest_d[1]= -1.0f; 03942 03943 /* find closest neigh */ 03944 for (i=0; i<numOfNeighs; i++) { 03945 int n_index = sData->adj_data->n_index[index]+i; 03946 float dir_dot = dot_v3v3(bNeighs[n_index].dir, force); 03947 03948 if (dir_dot>closest_d[0] && dir_dot>0.0f) {closest_d[0]=dir_dot; closest_id[0]=n_index;} 03949 } 03950 03951 if (closest_d[0] < 0.0f) return; 03952 03953 /* find second closest neigh */ 03954 for (i=0; i<numOfNeighs; i++) { 03955 int n_index = sData->adj_data->n_index[index]+i; 03956 float dir_dot = dot_v3v3(bNeighs[n_index].dir, force); 03957 float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir); 03958 03959 if (n_index == closest_id[0]) continue; 03960 03961 /* only accept neighbour at "other side" of the first one in relation to force dir 03962 * so make sure angle between this and closest neigh is greater than first angle */ 03963 if (dir_dot>closest_d[1] && closest_dot<closest_d[0] && dir_dot>0.0f) {closest_d[1]=dir_dot; closest_id[1]=n_index;} 03964 } 03965 03966 /* if two valid neighs found, calculate how force effect is divided 03967 * evenly between them (so that d[0]+d[1] = 1.0)*/ 03968 if (closest_id[1] != -1) { 03969 float force_proj[3]; 03970 float tangent[3]; 03971 float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir)); 03972 float force_intersect; 03973 float temp; 03974 03975 /* project force vector on the plane determined by these two neightbour points 03976 * and calculate relative force angle from it*/ 03977 cross_v3_v3v3(tangent, bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir); 03978 normalize_v3(tangent); 03979 force_intersect = dot_v3v3(force, tangent); 03980 madd_v3_v3v3fl(force_proj, force, tangent, (-1.0f)*force_intersect); 03981 normalize_v3(force_proj); 03982 03983 /* get drip factor based on force dir in relation to angle between those neighbours */ 03984 temp = dot_v3v3(bNeighs[closest_id[0]].dir, force_proj); 03985 CLAMP(temp, -1.0f, 1.0f); /* float precision might cause values > 1.0f that return infinite */ 03986 closest_d[1] = acosf(temp)/neigh_diff; 03987 closest_d[0] = 1.0f - closest_d[1]; 03988 03989 /* and multiply depending on how deeply force intersects surface */ 03990 temp = fabs(force_intersect); 03991 CLAMP(temp, 0.0f, 1.0f); 03992 closest_d[0] *= acosf(temp)/1.57079633f; 03993 closest_d[1] *= acosf(temp)/1.57079633f; 03994 } 03995 else { 03996 /* if only single neighbour, still linearize force intersection effect */ 03997 closest_d[0] = 1.0f - acosf(closest_d[0])/1.57079633f; 03998 } 03999 } 04000 04001 static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrushSettings *brush, float timescale) 04002 { 04003 PaintSurfaceData *sData = surface->data; 04004 PaintBakeData *bData = sData->bData; 04005 BakeNeighPoint *bNeighs = sData->bData->bNeighs; 04006 int index, steps, step; 04007 float eff_scale, max_velocity = 0.0f; 04008 04009 if (!sData->adj_data) return; 04010 04011 /* find max velocity */ 04012 for (index = 0; index < sData->total_points; index++) { 04013 float vel = bData->brush_velocity[index*4+3]; 04014 if (vel > max_velocity) max_velocity = vel; 04015 } 04016 04017 steps = (int)ceil(max_velocity / bData->average_dist * timescale); 04018 CLAMP(steps, 0, 12); 04019 eff_scale = brush->smudge_strength/(float)steps*timescale; 04020 04021 for (step=0; step<steps; step++) { 04022 04023 for (index = 0; index < sData->total_points; index++) { 04024 int i; 04025 PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index]; 04026 float smudge_str = bData->brush_velocity[index*4+3]; 04027 04028 /* force targets */ 04029 int closest_id[2]; 04030 float closest_d[2]; 04031 04032 if (!smudge_str) continue; 04033 04034 /* get force affect points */ 04035 surface_determineForceTargetPoints(sData, index, &bData->brush_velocity[index*4], closest_d, closest_id); 04036 04037 /* Apply movement towards those two points */ 04038 for (i=0; i<2; i++) { 04039 int n_index = closest_id[i]; 04040 if (n_index != -1 && closest_d[i]>0.0f) { 04041 float dir_dot = closest_d[i], dir_factor; 04042 float speed_scale = eff_scale*smudge_str/bNeighs[n_index].dist; 04043 PaintPoint *ePoint = &((PaintPoint*)sData->type_data)[sData->adj_data->n_target[n_index]]; 04044 04045 /* just skip if angle is too extreme */ 04046 if (dir_dot <= 0.0f) continue; 04047 04048 dir_factor = dir_dot * speed_scale; 04049 if (dir_factor > brush->smudge_strength) dir_factor = brush->smudge_strength; 04050 04051 /* mix new color and alpha */ 04052 mixColors(ePoint->color, ePoint->alpha, pPoint->color, pPoint->alpha, dir_factor); 04053 ePoint->alpha = ePoint->alpha*(1.0f-dir_factor) + pPoint->alpha*dir_factor; 04054 04055 /* smudge "wet layer" */ 04056 mixColors(ePoint->e_color, ePoint->e_alpha, pPoint->e_color, pPoint->e_alpha, dir_factor); 04057 ePoint->e_alpha = ePoint->e_alpha*(1.0f-dir_factor) + pPoint->e_alpha*dir_factor; 04058 pPoint->wetness *= (1.0f-dir_factor); 04059 } 04060 } 04061 } 04062 } 04063 } 04064 04065 /* 04066 * Prepare data required by effects for current frame. 04067 * Returns number of steps required 04068 */ 04069 static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale) 04070 { 04071 double average_force = 0.0f; 04072 float shrink_speed=0.0f, spread_speed=0.0f; 04073 float fastest_effect, avg_dist; 04074 int steps; 04075 PaintSurfaceData *sData = surface->data; 04076 PaintBakeData *bData = sData->bData; 04077 Vec3f *realCoord = bData->realCoord; 04078 int index; 04079 04080 /* Init force data if required */ 04081 if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) { 04082 float vel[3] = {0}; 04083 ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights); 04084 04085 /* allocate memory for force data (dir vector + strength) */ 04086 *force = MEM_mallocN(sData->total_points*4*sizeof(float), "PaintEffectForces"); 04087 04088 if (*force) { 04089 #pragma omp parallel for schedule(static) 04090 for (index = 0; index < sData->total_points; index++) 04091 { 04092 float forc[3] = {0}; 04093 04094 /* apply force fields */ 04095 if (effectors) { 04096 EffectedPoint epoint; 04097 pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint); 04098 epoint.vel_to_sec = 1.0f; 04099 pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL); 04100 } 04101 04102 /* if global gravity is enabled, add it too */ 04103 if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) 04104 /* also divide by 10 to about match default grav 04105 * with default force strength (1.0) */ 04106 madd_v3_v3fl(forc, scene->physics_settings.gravity, 04107 surface->effector_weights->global_gravity*surface->effector_weights->weight[0] / 10.f); 04108 04109 /* add surface point velocity and acceleration if enabled */ 04110 if (bData->velocity) { 04111 if (surface->drip_vel) 04112 madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel*(-1.0f)); 04113 04114 /* acceleration */ 04115 if (bData->prev_velocity && surface->drip_acc) { 04116 float acc[3]; 04117 copy_v3_v3(acc, bData->velocity[index].v); 04118 sub_v3_v3(acc, bData->prev_velocity[index].v); 04119 madd_v3_v3fl(forc, acc, surface->drip_acc*(-1.0f)); 04120 } 04121 } 04122 04123 /* force strength */ 04124 (*force)[index*4+3] = len_v3(forc); 04125 /* normalize and copy */ 04126 if ((*force)[index*4+3]) mul_v3_fl(forc, 1.0f/(*force)[index*4+3]); 04127 copy_v3_v3(&((*force)[index*4]), forc); 04128 } 04129 04130 /* calculate average values (single thread) */ 04131 for (index = 0; index < sData->total_points; index++) 04132 { 04133 average_force += (*force)[index*4+3]; 04134 } 04135 average_force /= sData->total_points; 04136 } 04137 pdEndEffectors(&effectors); 04138 } 04139 04140 /* Get number of required steps using averate point distance 04141 * so that just a few ultra close pixels wont up substeps to max */ 04142 04143 /* adjust number of required substep by fastest active effect */ 04144 if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) 04145 spread_speed = surface->spread_speed; 04146 if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) 04147 shrink_speed = surface->shrink_speed; 04148 04149 fastest_effect = MAX3(spread_speed, shrink_speed, average_force); 04150 avg_dist = bData->average_dist*CANVAS_REL_SIZE/getSurfaceDimension(sData); 04151 04152 steps = (int)ceil(1.5f*EFF_MOVEMENT_PER_FRAME*fastest_effect/avg_dist*timescale); 04153 CLAMP(steps, 1, 20); 04154 04155 return steps; 04156 } 04157 04158 /* 04159 * Processes active effect step. 04160 */ 04161 static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps) 04162 { 04163 PaintSurfaceData *sData = surface->data; 04164 BakeNeighPoint *bNeighs = sData->bData->bNeighs; 04165 float distance_scale = getSurfaceDimension(sData)/CANVAS_REL_SIZE; 04166 int index; 04167 timescale /= steps; 04168 04169 if (!sData->adj_data) return; 04170 04171 /* 04172 * Spread Effect 04173 */ 04174 if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) { 04175 float eff_scale = distance_scale*EFF_MOVEMENT_PER_FRAME*surface->spread_speed*timescale; 04176 04177 /* Copy current surface to the previous points array to read unmodified values */ 04178 memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(struct PaintPoint)); 04179 04180 #pragma omp parallel for schedule(static) 04181 for (index = 0; index < sData->total_points; index++) 04182 { 04183 int i; 04184 int numOfNeighs = sData->adj_data->n_num[index]; 04185 PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index]; 04186 04187 /* Only reads values from the surface copy (prevPoint[]), 04188 * so this one is thread safe */ 04189 04190 /* Loop through neighbouring points */ 04191 for (i=0; i<numOfNeighs; i++) { 04192 int n_index = sData->adj_data->n_index[index]+i; 04193 float w_factor /* , p_alpha = pPoint->e_alpha */ /* UNUSED */; 04194 PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]]; 04195 float speed_scale = (bNeighs[n_index].dist<eff_scale) ? 1.0f : eff_scale/bNeighs[n_index].dist; 04196 float color_mix = (MIN3(ePoint->wetness, pPoint->wetness, 1.0f))*0.25f*surface->color_spread_speed; 04197 04198 /* do color mixing */ 04199 if (color_mix) mixColors(pPoint->e_color, pPoint->e_alpha, ePoint->e_color, ePoint->e_alpha, color_mix); 04200 04201 /* Only continue if surrounding point has higher wetness */ 04202 if (ePoint->wetness<pPoint->wetness || ePoint->wetness<MIN_WETNESS) continue; 04203 04204 w_factor = 1.0f/numOfNeighs * MIN2(ePoint->wetness, 1.0f) * speed_scale; 04205 CLAMP(w_factor, 0.0f, 1.0f); 04206 04207 /* mix new wetness and color */ 04208 pPoint->wetness = (1.0f-w_factor)*pPoint->wetness + w_factor*ePoint->wetness; 04209 pPoint->e_alpha = mixColors(pPoint->e_color, pPoint->e_alpha, ePoint->e_color, ePoint->e_alpha, w_factor); 04210 } 04211 } 04212 } 04213 04214 /* 04215 * Shrink Effect 04216 */ 04217 if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) { 04218 float eff_scale = distance_scale*EFF_MOVEMENT_PER_FRAME*surface->shrink_speed*timescale; 04219 04220 /* Copy current surface to the previous points array to read unmodified values */ 04221 memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(struct PaintPoint)); 04222 04223 #pragma omp parallel for schedule(static) 04224 for (index = 0; index < sData->total_points; index++) 04225 { 04226 int i; 04227 int numOfNeighs = sData->adj_data->n_num[index]; 04228 float totalAlpha = 0.0f; 04229 PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index]; 04230 04231 for (i=0; i<numOfNeighs; i++) { 04232 int n_index = sData->adj_data->n_index[index]+i; 04233 float speed_scale = (bNeighs[n_index].dist<eff_scale) ? 1.0f : eff_scale/bNeighs[n_index].dist; 04234 PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]]; 04235 float a_factor, ea_factor, w_factor; 04236 04237 totalAlpha += ePoint->e_alpha; 04238 04239 /* Check if neighbouring point has lower alpha, 04240 * if so, decrease this point's alpha as well*/ 04241 if (pPoint->alpha <= 0.0f && pPoint->e_alpha <= 0.0f && pPoint->wetness <= 0.0f) continue; 04242 04243 /* decrease factor for dry paint alpha */ 04244 a_factor = (1.0f - ePoint->alpha)/numOfNeighs * (pPoint->alpha - ePoint->alpha) * speed_scale; 04245 if (a_factor < 0.0f) a_factor = 0.0f; 04246 /* decrease factor for wet paint alpha */ 04247 ea_factor = (1.0f - ePoint->e_alpha)/8 * (pPoint->e_alpha - ePoint->e_alpha) * speed_scale; 04248 if (ea_factor < 0.0f) ea_factor = 0.0f; 04249 /* decrease factor for paint wetness */ 04250 w_factor = (1.0f - ePoint->wetness)/8 * (pPoint->wetness - ePoint->wetness) * speed_scale; 04251 if (w_factor < 0.0f) w_factor = 0.0f; 04252 04253 pPoint->alpha -= a_factor; 04254 if (pPoint->alpha < 0.0f) pPoint->alpha = 0.0f; 04255 pPoint->e_alpha -= ea_factor; 04256 if (pPoint->e_alpha < 0.0f) pPoint->e_alpha = 0.0f; 04257 pPoint->wetness -= w_factor; 04258 if (pPoint->wetness < 0.0f) pPoint->wetness = 0.0f; 04259 } 04260 } 04261 } 04262 04263 /* 04264 * Drip Effect 04265 */ 04266 if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) 04267 { 04268 float eff_scale = distance_scale*EFF_MOVEMENT_PER_FRAME*timescale/2.0f; 04269 /* Copy current surface to the previous points array to read unmodified values */ 04270 memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(struct PaintPoint)); 04271 04272 for (index = 0; index < sData->total_points; index++) { 04273 int i; 04274 PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index]; 04275 PaintPoint *pPoint_prev = &prevPoint[index]; 04276 04277 int closest_id[2]; 04278 float closest_d[2]; 04279 04280 /* adjust drip speed depending on wetness */ 04281 float w_factor = pPoint_prev->wetness - 0.025f; 04282 if (w_factor <= 0) continue; 04283 CLAMP(w_factor, 0.0f, 1.0f); 04284 04285 /* get force affect points */ 04286 surface_determineForceTargetPoints(sData, index, &force[index*4], closest_d, closest_id); 04287 04288 /* Apply movement towards those two points */ 04289 for (i=0; i<2; i++) { 04290 int n_index = closest_id[i]; 04291 if (n_index != -1 && closest_d[i]>0.0f) { 04292 float dir_dot = closest_d[i], dir_factor, a_factor; 04293 float speed_scale = eff_scale*force[index*4+3]/bNeighs[n_index].dist; 04294 PaintPoint *ePoint = &((PaintPoint*)sData->type_data)[sData->adj_data->n_target[n_index]]; 04295 float e_wet = ePoint->wetness; 04296 04297 /* just skip if angle is too extreme */ 04298 if (dir_dot <= 0.0f) continue; 04299 04300 dir_factor = dir_dot * MIN2(speed_scale, 1.0f) * w_factor; 04301 if (dir_factor > 0.5f) dir_factor = 0.5f; 04302 04303 /* mix new wetness*/ 04304 ePoint->wetness += dir_factor; 04305 CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS); 04306 04307 /* mix new color */ 04308 a_factor = dir_factor / pPoint_prev->wetness; 04309 CLAMP(a_factor, 0.0f, 1.0f); 04310 mixColors(ePoint->e_color, ePoint->e_alpha, pPoint_prev->e_color, pPoint_prev->e_alpha, a_factor); 04311 /* dripping is supposed to preserve alpha level */ 04312 if (pPoint_prev->e_alpha > ePoint->e_alpha) { 04313 ePoint->e_alpha += a_factor * pPoint_prev->e_alpha; 04314 if (ePoint->e_alpha > pPoint_prev->e_alpha) 04315 ePoint->e_alpha = pPoint_prev->e_alpha; 04316 } 04317 04318 /* decrease paint wetness on current point */ 04319 pPoint->wetness -= (ePoint->wetness - e_wet); 04320 CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS); 04321 } 04322 } 04323 } 04324 } 04325 } 04326 04327 void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescale) 04328 { 04329 PaintSurfaceData *sData = surface->data; 04330 BakeNeighPoint *bNeighs = sData->bData->bNeighs; 04331 int index; 04332 int steps, ss; 04333 float dt, min_dist, damp_factor; 04334 float wave_speed = surface->wave_speed; 04335 double average_dist = 0.0f; 04336 Bounds3D *mb = &sData->bData->mesh_bounds; 04337 float canvas_size = MAX3((mb->max[0]-mb->min[0]), (mb->max[1]-mb->min[1]), (mb->max[2]-mb->min[2])); 04338 float wave_scale = CANVAS_REL_SIZE/canvas_size; 04339 04340 /* allocate memory */ 04341 PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points*sizeof(PaintWavePoint), "Temp previous points for wave simulation"); 04342 if (!prevPoint) return; 04343 04344 /* calculate average neigh distance (single thread) */ 04345 for (index = 0; index < sData->total_points; index++) 04346 { 04347 int i; 04348 int numOfNeighs = sData->adj_data->n_num[index]; 04349 04350 for (i=0; i<numOfNeighs; i++) { 04351 average_dist += bNeighs[sData->adj_data->n_index[index]+i].dist; 04352 } 04353 } 04354 average_dist *= wave_scale/sData->adj_data->total_targets; 04355 04356 /* determine number of required steps */ 04357 steps = (int)ceil((WAVE_TIME_FAC*timescale*surface->wave_timescale) / (average_dist/wave_speed/3)); 04358 CLAMP(steps, 1, 20); 04359 timescale /= steps; 04360 04361 /* apply simulation values for final timescale */ 04362 dt = WAVE_TIME_FAC*timescale*surface->wave_timescale; 04363 min_dist = wave_speed*dt*1.5f; 04364 damp_factor = pow((1.0f-surface->wave_damping), timescale*surface->wave_timescale); 04365 04366 for (ss=0; ss<steps; ss++) { 04367 04368 /* copy previous frame data */ 04369 memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(PaintWavePoint)); 04370 04371 #pragma omp parallel for schedule(static) 04372 for (index = 0; index < sData->total_points; index++) { 04373 PaintWavePoint *wPoint = &((PaintWavePoint*)sData->type_data)[index]; 04374 int numOfNeighs = sData->adj_data->n_num[index]; 04375 float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f; 04376 int numOfN = 0, numOfRN = 0; 04377 int i; 04378 04379 if (wPoint->state > 0) continue; 04380 04381 /* calculate force from surrounding points */ 04382 for (i=0; i<numOfNeighs; i++) { 04383 int n_index = sData->adj_data->n_index[index]+i; 04384 float dist = bNeighs[n_index].dist*wave_scale; 04385 PaintWavePoint *tPoint = &prevPoint[sData->adj_data->n_target[n_index]]; 04386 04387 if (!dist || tPoint->state>0) continue; 04388 if (dist<min_dist) dist=min_dist; 04389 avg_dist += dist; 04390 numOfN++; 04391 04392 /* count average height for edge points for open borders */ 04393 if (!(sData->adj_data->flags[sData->adj_data->n_target[n_index]] & ADJ_ON_MESH_EDGE)) { 04394 avg_height += tPoint->height; 04395 numOfRN++; 04396 } 04397 04398 force += (tPoint->height - wPoint->height) / (dist*dist); 04399 } 04400 avg_dist = (numOfN) ? avg_dist/numOfN : 0.0f; 04401 04402 if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS && 04403 sData->adj_data->flags[index] & ADJ_ON_MESH_EDGE) { 04404 /* if open borders, apply a fake height to keep waves going on */ 04405 avg_height = (numOfRN) ? avg_height/numOfRN : 0.0f; 04406 wPoint->height = (dt*wave_speed*avg_height + wPoint->height*avg_dist) / (avg_dist + dt*wave_speed); 04407 } 04408 /* else do wave eq */ 04409 else { 04410 /* add force towards zero height based on average dist */ 04411 if (avg_dist) 04412 force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist*avg_dist) / 2.0f; 04413 04414 /* change point velocity */ 04415 wPoint->velocity += force*dt * wave_speed*wave_speed; 04416 /* damping */ 04417 wPoint->velocity *= damp_factor; 04418 /* and new height */ 04419 wPoint->height += wPoint->velocity*dt; 04420 } 04421 } 04422 } 04423 04424 /* reset state */ 04425 #pragma omp parallel for schedule(static) 04426 for (index = 0; index < sData->total_points; index++) { 04427 PaintWavePoint *wPoint = &((PaintWavePoint*)sData->type_data)[index]; 04428 /* if there wasnt any brush intersection, clear isect height */ 04429 if (wPoint->state == DPAINT_WAVE_NONE) { 04430 wPoint->brush_isect = 0.0f; 04431 } 04432 wPoint->state = DPAINT_WAVE_NONE; 04433 } 04434 04435 MEM_freeN(prevPoint); 04436 } 04437 04438 /* Do dissolve and fading effects */ 04439 static void dynamicPaint_surfacePreStep(DynamicPaintSurface *surface, float timescale) 04440 { 04441 PaintSurfaceData *sData = surface->data; 04442 int index; 04443 04444 #pragma omp parallel for schedule(static) 04445 for (index=0; index<sData->total_points; index++) 04446 { 04447 /* Do drying dissolve effects */ 04448 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { 04449 PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index]; 04450 /* drying */ 04451 if (surface->flags & MOD_DPAINT_USE_DRYING) { 04452 if (pPoint->wetness >= MIN_WETNESS) { 04453 int i; 04454 float dry_ratio, f_color[4]; 04455 float p_wetness = pPoint->wetness; 04456 VALUE_DISSOLVE(pPoint->wetness, surface->dry_speed, timescale, (surface->flags & MOD_DPAINT_DRY_LOG)); 04457 if (pPoint->wetness<0.0f) pPoint->wetness=0.0f; 04458 04459 if (pPoint->wetness < surface->color_dry_threshold) { 04460 dry_ratio = pPoint->wetness/p_wetness; 04461 04462 /* 04463 * Slowly "shift" paint from wet layer to dry layer as it drys: 04464 */ 04465 /* make sure alpha values are within proper range */ 04466 CLAMP(pPoint->alpha, 0.0f, 1.0f); 04467 CLAMP(pPoint->e_alpha, 0.0f, 1.0f); 04468 04469 /* get current final blended color of these layers */ 04470 blendColors(pPoint->color, pPoint->alpha, pPoint->e_color, pPoint->e_alpha, f_color); 04471 /* reduce wet layer alpha by dry factor */ 04472 pPoint->e_alpha *= dry_ratio; 04473 04474 /* now calculate new alpha for dry layer that keeps final blended color unchanged */ 04475 pPoint->alpha = (f_color[3] - pPoint->e_alpha)/(1.0f-pPoint->e_alpha); 04476 /* for each rgb component, calculate a new dry layer color that keeps the final blend color 04477 * with these new alpha values. (wet layer color doesnt change)*/ 04478 if (pPoint->alpha) { 04479 for (i=0; i<3; i++) { 04480 pPoint->color[i] = (f_color[i]*f_color[3] - pPoint->e_color[i]*pPoint->e_alpha)/(pPoint->alpha*(1.0f-pPoint->e_alpha)); 04481 } 04482 } 04483 } 04484 04485 pPoint->state = DPAINT_PAINT_WET; 04486 } 04487 /* in case of just dryed paint, just mix it to the dry layer and mark it empty */ 04488 else if (pPoint->state > 0) { 04489 float f_color[4]; 04490 blendColors(pPoint->color, pPoint->alpha, pPoint->e_color, pPoint->e_alpha, f_color); 04491 copy_v3_v3(pPoint->color, f_color); 04492 pPoint->alpha = f_color[3]; 04493 /* clear wet layer */ 04494 pPoint->wetness = 0.0f; 04495 pPoint->e_alpha = 0.0f; 04496 pPoint->state = DPAINT_PAINT_DRY; 04497 } 04498 } 04499 04500 if (surface->flags & MOD_DPAINT_DISSOLVE) { 04501 VALUE_DISSOLVE(pPoint->alpha, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG)); 04502 if (pPoint->alpha < 0.0f) pPoint->alpha = 0.0f; 04503 04504 VALUE_DISSOLVE(pPoint->e_alpha, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG)); 04505 if (pPoint->e_alpha < 0.0f) pPoint->e_alpha = 0.0f; 04506 } 04507 } 04508 /* dissolve for float types */ 04509 else if (surface->flags & MOD_DPAINT_DISSOLVE && 04510 (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || 04511 surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)) { 04512 04513 float *point = &((float*)sData->type_data)[index]; 04514 /* log or linear */ 04515 VALUE_DISSOLVE(*point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG)); 04516 if (*point < 0.0f) *point = 0.0f; 04517 } 04518 } 04519 } 04520 04521 static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob) 04522 { 04523 PaintSurfaceData *sData = surface->data; 04524 PaintBakeData *bData = sData->bData; 04525 DerivedMesh *dm = surface->canvas->dm; 04526 MVert *mvert = dm->getVertArray(dm); 04527 04528 int numOfVerts = dm->getNumVerts(dm); 04529 int i; 04530 int ret = 0; 04531 04532 if (!bData->prev_verts) return 1; 04533 04534 /* matrix comparison */ 04535 for (i=0; i<4; i++) { 04536 int j; 04537 for (j=0; j<4; j++) 04538 if (bData->prev_obmat[i][j] != ob->obmat[i][j]) return 1; 04539 } 04540 04541 /* vertices */ 04542 #pragma omp parallel for schedule(static) 04543 for (i=0; i<numOfVerts; i++) { 04544 int j; 04545 for (j=0; j<3; j++) 04546 if (bData->prev_verts[i].co[j] != mvert[i].co[j]) { 04547 ret = 1; 04548 break; 04549 } 04550 } 04551 04552 return ret; 04553 } 04554 04555 static int surface_needsVelocityData(DynamicPaintSurface *surface, Scene *scene) 04556 { 04557 if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) 04558 return 1; 04559 04560 if (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY) 04561 return 1; 04562 04563 return 0; 04564 } 04565 04566 static int surface_needsAccelerationData(DynamicPaintSurface *surface) 04567 { 04568 if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) 04569 return 1; 04570 04571 return 0; 04572 } 04573 04574 /* Prepare for surface step by creating PaintBakeNormal data */ 04575 static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Scene *scene, Object *ob) 04576 { 04577 PaintSurfaceData *sData = surface->data; 04578 PaintAdjData *adj_data = sData->adj_data; 04579 PaintBakeData *bData = sData->bData; 04580 DerivedMesh *dm = surface->canvas->dm; 04581 int index, new_bdata = 0; 04582 int do_velocity_data = surface_needsVelocityData(surface, scene); 04583 int do_accel_data = surface_needsAccelerationData(surface); 04584 04585 int canvasNumOfVerts = dm->getNumVerts(dm); 04586 MVert *mvert = dm->getVertArray(dm); 04587 Vec3f *canvas_verts; 04588 04589 if (bData) { 04590 int surface_moved = dynamicPaint_surfaceHasMoved(surface, ob); 04591 04592 /* get previous speed for accelertaion */ 04593 if (do_accel_data && bData->prev_velocity && bData->velocity) 04594 memcpy(bData->prev_velocity, bData->velocity, sData->total_points*sizeof(Vec3f)); 04595 04596 /* reset speed vectors */ 04597 if (do_velocity_data && bData->velocity && (bData->clear || !surface_moved)) 04598 memset(bData->velocity, 0, sData->total_points*sizeof(Vec3f)); 04599 04600 /* if previous data exists and mesh hasn't moved, no need to recalc */ 04601 if (!surface_moved) 04602 return 1; 04603 } 04604 04605 canvas_verts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts*sizeof(struct Vec3f), "Dynamic Paint transformed canvas verts"); 04606 if (!canvas_verts) return 0; 04607 04608 /* allocate memory if required */ 04609 if (!bData) { 04610 sData->bData = bData = (struct PaintBakeData *) MEM_callocN(sizeof(struct PaintBakeData), "Dynamic Paint bake data"); 04611 if (!bData) { 04612 if (canvas_verts) MEM_freeN(canvas_verts); 04613 return 0; 04614 } 04615 04616 /* Init bdata */ 04617 bData->bNormal = (struct PaintBakeNormal *) MEM_mallocN(sData->total_points*sizeof(struct PaintBakeNormal), "Dynamic Paint step data"); 04618 bData->s_pos = MEM_mallocN(sData->total_points*sizeof(unsigned int), "Dynamic Paint bData s_pos"); 04619 bData->s_num = MEM_mallocN(sData->total_points*sizeof(unsigned int), "Dynamic Paint bData s_num"); 04620 bData->realCoord = (struct Vec3f *) MEM_mallocN(surface_totalSamples(surface)*sizeof(Vec3f), "Dynamic Paint point coords"); 04621 bData->prev_verts = MEM_mallocN(canvasNumOfVerts*sizeof(MVert), "Dynamic Paint bData prev_verts"); 04622 04623 /* if any allocation failed, free everything */ 04624 if (!bData->bNormal || !bData->s_pos || !bData->s_num || !bData->realCoord || !canvas_verts) { 04625 if (bData->bNormal) MEM_freeN(bData->bNormal); 04626 if (bData->s_pos) MEM_freeN(bData->s_pos); 04627 if (bData->s_num) MEM_freeN(bData->s_num); 04628 if (bData->realCoord) MEM_freeN(bData->realCoord); 04629 if (canvas_verts) MEM_freeN(canvas_verts); 04630 04631 return setError(surface->canvas, "Not enough free memory."); 04632 } 04633 04634 new_bdata = 1; 04635 } 04636 04637 if (do_velocity_data && !bData->velocity) { 04638 bData->velocity = (struct Vec3f *) MEM_callocN(sData->total_points*sizeof(Vec3f), "Dynamic Paint velocity"); 04639 } 04640 if (do_accel_data && !bData->prev_velocity) { 04641 bData->prev_velocity = (struct Vec3f *) MEM_mallocN(sData->total_points*sizeof(Vec3f), "Dynamic Paint prev velocity"); 04642 /* copy previous vel */ 04643 if (bData->prev_velocity && bData->velocity) 04644 memcpy(bData->prev_velocity, bData->velocity, sData->total_points*sizeof(Vec3f)); 04645 } 04646 04647 /* 04648 * Make a transformed copy of canvas derived mesh vertices to avoid recalculation. 04649 */ 04650 bData->mesh_bounds.valid = 0; 04651 for (index=0; index<canvasNumOfVerts; index++) { 04652 copy_v3_v3(canvas_verts[index].v, mvert[index].co); 04653 mul_m4_v3(ob->obmat, canvas_verts[index].v); 04654 boundInsert(&bData->mesh_bounds, canvas_verts[index].v); 04655 } 04656 04657 /* 04658 * Prepare each surface point for a new step 04659 */ 04660 #pragma omp parallel for schedule(static) 04661 for (index=0; index<sData->total_points; index++) 04662 { 04663 float prev_point[3] = {0.0f, 0.0f, 0.0f}; 04664 if (do_velocity_data && !new_bdata) { 04665 copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v); 04666 } 04667 /* 04668 * Calculate current 3D-position and normal of each surface point 04669 */ 04670 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) { 04671 float n1[3], n2[3], n3[3]; 04672 ImgSeqFormatData *f_data = (ImgSeqFormatData*)sData->format_data; 04673 PaintUVPoint *tPoint = &((PaintUVPoint*)f_data->uv_p)[index]; 04674 int ss; 04675 04676 bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1; 04677 bData->s_pos[index] = index * bData->s_num[index]; 04678 04679 /* per sample coordinates */ 04680 for (ss=0; ss<bData->s_num[index]; ss++) { 04681 interp_v3_v3v3v3( bData->realCoord[bData->s_pos[index]+ss].v, 04682 canvas_verts[tPoint->v1].v, 04683 canvas_verts[tPoint->v2].v, 04684 canvas_verts[tPoint->v3].v, f_data->barycentricWeights[index*bData->s_num[index]+ss].v); 04685 } 04686 04687 /* Calculate current pixel surface normal */ 04688 normal_short_to_float_v3(n1, mvert[tPoint->v1].no); 04689 normal_short_to_float_v3(n2, mvert[tPoint->v2].no); 04690 normal_short_to_float_v3(n3, mvert[tPoint->v3].no); 04691 04692 interp_v3_v3v3v3( bData->bNormal[index].invNorm, 04693 n1, n2, n3, f_data->barycentricWeights[index*bData->s_num[index]].v); 04694 mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm); 04695 normalize_v3(bData->bNormal[index].invNorm); 04696 negate_v3(bData->bNormal[index].invNorm); 04697 } 04698 else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { 04699 int ss; 04700 if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) { 04701 bData->s_num[index] = adj_data->n_num[index]+1; 04702 bData->s_pos[index] = adj_data->n_index[index]+index; 04703 } 04704 else { 04705 bData->s_num[index] = 1; 04706 bData->s_pos[index] = index; 04707 } 04708 04709 /* calculate position for each sample */ 04710 for (ss=0; ss<bData->s_num[index]; ss++) { 04711 /* first sample is always point center */ 04712 copy_v3_v3(bData->realCoord[bData->s_pos[index]+ss].v, canvas_verts[index].v); 04713 if (ss > 0) { 04714 int t_index = adj_data->n_index[index]+(ss-1); 04715 /* get vertex position at 1/3 of each neigh edge */ 04716 mul_v3_fl(bData->realCoord[bData->s_pos[index]+ss].v, 2.0f/3.0f); 04717 madd_v3_v3fl(bData->realCoord[bData->s_pos[index]+ss].v, canvas_verts[adj_data->n_target[t_index]].v, 1.0f/3.0f); 04718 } 04719 } 04720 04721 /* normal */ 04722 normal_short_to_float_v3(bData->bNormal[index].invNorm, mvert[index].no); 04723 mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm); 04724 normalize_v3(bData->bNormal[index].invNorm); 04725 negate_v3(bData->bNormal[index].invNorm); 04726 } 04727 04728 /* Prepare surface normal directional scale to easily convert 04729 * brush intersection amount between global and local space */ 04730 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || 04731 surface->type == MOD_DPAINT_SURFACE_T_WAVE) { 04732 float temp_nor[3]; 04733 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { 04734 normal_short_to_float_v3(temp_nor, mvert[index].no); 04735 normalize_v3(temp_nor); 04736 } 04737 else { 04738 float n1[3], n2[3], n3[3]; 04739 ImgSeqFormatData *f_data = (ImgSeqFormatData*)sData->format_data; 04740 PaintUVPoint *tPoint = &((PaintUVPoint*)f_data->uv_p)[index]; 04741 04742 normal_short_to_float_v3(n1, mvert[tPoint->v1].no); 04743 normal_short_to_float_v3(n2, mvert[tPoint->v2].no); 04744 normal_short_to_float_v3(n3, mvert[tPoint->v3].no); 04745 interp_v3_v3v3v3(temp_nor, 04746 n1, n2, n3, f_data->barycentricWeights[index*bData->s_num[index]].v); 04747 } 04748 04749 mul_v3_v3(temp_nor, ob->size); 04750 bData->bNormal[index].normal_scale = len_v3(temp_nor); 04751 } 04752 04753 /* calculate speed vector */ 04754 if (do_velocity_data && !new_bdata && !bData->clear) { 04755 sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point); 04756 } 04757 } 04758 04759 MEM_freeN(canvas_verts); 04760 04761 /* generate surface space partitioning grid */ 04762 surfaceGenerateGrid(surface); 04763 /* calculate current frame neighbouring point distances and global dirs */ 04764 dynamicPaint_prepareNeighbourData(surface, 0); 04765 04766 /* Copy current frame vertices to check against in next frame */ 04767 copy_m4_m4(bData->prev_obmat, ob->obmat); 04768 memcpy(bData->prev_verts, mvert, canvasNumOfVerts*sizeof(MVert)); 04769 04770 bData->clear = 0; 04771 04772 return 1; 04773 } 04774 04775 /* 04776 * Do Dynamic Paint step. Paints scene brush objects of current state/frame to the surface. 04777 */ 04778 static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *surface, float timescale, float subframe) 04779 { 04780 PaintSurfaceData *sData = surface->data; 04781 PaintBakeData *bData = sData->bData; 04782 DynamicPaintCanvasSettings *canvas = surface->canvas; 04783 int ret = 1; 04784 if (!sData || sData->total_points < 1) return 0; 04785 04786 dynamicPaint_surfacePreStep(surface, timescale); 04787 /* 04788 * Loop through surface's target paint objects and do painting 04789 */ 04790 { 04791 Base *base = NULL; 04792 GroupObject *go = NULL; 04793 Object *brushObj = NULL; 04794 ModifierData *md = NULL; 04795 04796 /* backup current scene frame */ 04797 int scene_frame = scene->r.cfra; 04798 float scene_subframe = scene->r.subframe; 04799 04800 /* either from group or from all objects */ 04801 if(surface->brush_group) 04802 go = surface->brush_group->gobject.first; 04803 else 04804 base = scene->base.first; 04805 04806 while (base || go) 04807 { 04808 brushObj = NULL; 04809 /* select object */ 04810 if(surface->brush_group) { 04811 if(go->ob) brushObj = go->ob; 04812 } 04813 else 04814 brushObj = base->object; 04815 04816 if(!brushObj) { 04817 /* skip item */ 04818 if(surface->brush_group) go = go->next; 04819 else base= base->next; 04820 continue; 04821 } 04822 04823 /* next item */ 04824 if(surface->brush_group) 04825 go = go->next; 04826 else 04827 base= base->next; 04828 04829 /* check if target has an active dp modifier */ 04830 md = modifiers_findByType(brushObj, eModifierType_DynamicPaint); 04831 if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) 04832 { 04833 DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md; 04834 /* make sure we're dealing with a brush */ 04835 if (pmd2->brush) 04836 { 04837 DynamicPaintBrushSettings *brush = pmd2->brush; 04838 BrushMaterials bMats = {0}; 04839 04840 /* calculate brush speed vectors if required */ 04841 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) { 04842 bData->brush_velocity = MEM_callocN(sData->total_points*sizeof(float)*4, "Dynamic Paint brush velocity"); 04843 /* init adjacency data if not already */ 04844 if (!sData->adj_data) 04845 dynamicPaint_initAdjacencyData(surface, 1); 04846 if (!bData->bNeighs) 04847 dynamicPaint_prepareNeighbourData(surface, 1); 04848 } 04849 04850 /* update object data on this subframe */ 04851 if (subframe) { 04852 scene_setSubframe(scene, subframe); 04853 subframe_updateObject(scene, brushObj, UPDATE_EVERYTHING, BKE_curframe(scene)); 04854 } 04855 /* Prepare materials if required */ 04856 if (brush_usesMaterial(brush, scene)) 04857 dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats); 04858 04859 /* Apply brush on the surface depending on it's collision type */ 04860 /* Particle brush: */ 04861 if (brush->collision == MOD_DPAINT_COL_PSYS) { 04862 if (brush && brush->psys && brush->psys->part && brush->psys->part->type==PART_EMITTER && 04863 psys_check_enabled(brushObj, brush->psys)) { 04864 04865 /* Paint a particle system */ 04866 BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt, BKE_curframe(scene), ADT_RECALC_ANIM); 04867 dynamicPaint_paintParticles(surface, brush->psys, brush, timescale); 04868 } 04869 } 04870 /* Object center distance: */ 04871 else if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) { 04872 dynamicPaint_paintSinglePoint(surface, brushObj->loc, brush, brushObj, &bMats, scene, timescale); 04873 } 04874 /* Mesh volume/proximity: */ 04875 else if (brushObj != ob) { 04876 dynamicPaint_paintMesh(surface, brush, brushObj, &bMats, scene, timescale); 04877 } 04878 04879 /* free temp material data */ 04880 if (brush_usesMaterial(brush, scene)) 04881 dynamicPaint_freeBrushMaterials(&bMats); 04882 /* reset object to it's original state */ 04883 if (subframe) { 04884 scene->r.cfra = scene_frame; 04885 scene->r.subframe = scene_subframe; 04886 subframe_updateObject(scene, brushObj, UPDATE_EVERYTHING, BKE_curframe(scene)); 04887 } 04888 04889 /* process special brush effects, like smudge */ 04890 if (bData->brush_velocity) { 04891 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) 04892 dynamicPaint_doSmudge(surface, brush, timescale); 04893 MEM_freeN(bData->brush_velocity); 04894 bData->brush_velocity = NULL; 04895 } 04896 } 04897 } 04898 } 04899 } 04900 04901 /* surfaces operations that use adjacency data */ 04902 if (sData->adj_data && bData->bNeighs) 04903 { 04904 /* wave type surface simulation step */ 04905 if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) { 04906 dynamicPaint_doWaveStep(surface, timescale); 04907 } 04908 04909 /* paint surface effects */ 04910 if (surface->effect && surface->type == MOD_DPAINT_SURFACE_T_PAINT) 04911 { 04912 int steps = 1, s; 04913 PaintPoint *prevPoint; 04914 float *force = NULL; 04915 04916 /* Allocate memory for surface previous points to read unchanged values from */ 04917 prevPoint = MEM_mallocN(sData->total_points*sizeof(struct PaintPoint), "PaintSurfaceDataCopy"); 04918 if (!prevPoint) 04919 return setError(canvas, "Not enough free memory."); 04920 04921 /* Prepare effects and get number of required steps */ 04922 steps = dynamicPaint_prepareEffectStep(surface, scene, ob, &force, timescale); 04923 for (s = 0; s < steps; s++) { 04924 dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, (float)steps); 04925 } 04926 04927 /* Free temporary effect data */ 04928 if (prevPoint) MEM_freeN(prevPoint); 04929 if (force) MEM_freeN(force); 04930 } 04931 } 04932 04933 return ret; 04934 } 04935 04936 /* 04937 * Calculate a single frame and included subframes for surface 04938 */ 04939 int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Object *cObject, int frame) 04940 { 04941 float timescale = 1.0f; 04942 04943 /* apply previous displace on derivedmesh if incremental surface */ 04944 if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) 04945 dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm); 04946 04947 /* update bake data */ 04948 dynamicPaint_generateBakeData(surface, scene, cObject); 04949 04950 /* dont do substeps for first frame */ 04951 if (surface->substeps && (frame != surface->start_frame)) { 04952 int st; 04953 timescale = 1.0f / (surface->substeps+1); 04954 04955 for (st = 1; st <= surface->substeps; st++) { 04956 float subframe = ((float) st) / (surface->substeps+1); 04957 if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe)) return 0; 04958 } 04959 } 04960 04961 return dynamicPaint_doStep(scene, cObject, surface, timescale, 0.0f); 04962 }