diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py index 3797d7f363c..bf8d7d8552f 100644 --- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py +++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py @@ -137,11 +137,14 @@ class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel): # dissolve if surface_type == 'PAINT': split = layout.split(percentage=0.35) - split.label(text="Wetmap drying:") + split.prop(surface, "use_drying", text="Dry:") col = split.column() + col.active = surface.use_drying split = col.split(percentage=0.7) - split.prop(surface, "dry_speed", text="Time") + col = split.column(align=True) + col.prop(surface, "dry_speed", text="Time") + col.prop(surface, "color_dry_threshold") split.prop(surface, "use_dry_log", text="Slow") if surface_type != 'WAVE': @@ -179,7 +182,10 @@ class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel): col.prop(surface, "wave_spring") layout.separator() - layout.prop(surface, "brush_group", text="Brush Group") + layout.prop(surface, "brush_group") + row = layout.row() + row.prop(surface, "brush_influence_scale") + row.prop(surface, "brush_radius_scale") class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel): diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 3632eb33717..f24687e0fc9 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -42,7 +42,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 261 -#define BLENDER_SUBVERSION 2 +#define BLENDER_SUBVERSION 3 #define BLENDER_MINVERSION 250 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index f93aee80ab8..a9e612b08e0 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -101,9 +101,10 @@ static int neighY[8] = {0,1,1, 1, 0,-1,-1,-1}; #define EFF_MOVEMENT_PER_FRAME 0.05f /* initial wave time factor */ #define WAVE_TIME_FAC (1.0f/24.f) -#define WAVE_INIT_SIZE 5.0f +#define CANVAS_REL_SIZE 5.0f /* drying limits */ #define MIN_WETNESS 0.001f +#define MAX_WETNESS 5.0f /* dissolve macro */ #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) @@ -422,15 +423,31 @@ static void blendColors(float t_color[3], float t_alpha, float s_color[3], float result[3] = f_alpha; } -/* assumes source alpha > 0.0f or results NaN colors */ -static void mixColors(float *t_color, float t_alpha, float *s_color, float s_alpha) +/* Mix two alpha weighed colors by a defined ratio. output is saved at a_color */ +static float mixColors(float a_color[3], float a_weight, float b_color[3], float b_weight, float ratio) { - float factor = (s_alphabData->mesh_bounds; + return MAX3((mb->max[0]-mb->min[0]), (mb->max[1]-mb->min[1]), (mb->max[2]-mb->min[2])); +} + static void freeGrid(PaintSurfaceData *data) { PaintBakeData *bData = data->bData; @@ -959,17 +982,21 @@ struct DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSett /* Set initial values */ surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG | MOD_DPAINT_DISSOLVE_LOG | - MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW | MOD_DPAINT_OUT1; + MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW | MOD_DPAINT_OUT1 | MOD_DPAINT_USE_DRYING; surface->effect = 0; surface->effect_ui = 1; surface->diss_speed = 250; surface->dry_speed = 500; + surface->color_dry_threshold = 1.0f; surface->depth_clamp = 0.0f; surface->disp_factor = 1.0f; surface->disp_type = MOD_DPAINT_DISP_DISPLACE; surface->image_fileformat = MOD_DPAINT_IMGFORMAT_PNG; + surface->influence_scale = 1.0f; + surface->radius_scale = 1.0f; + surface->init_color[0] = 1.0f; surface->init_color[1] = 1.0f; surface->init_color[2] = 1.0f; @@ -1508,7 +1535,7 @@ static int dynamicPaint_checkSurfaceData(DynamicPaintSurface *surface) /* apply displacing vertex surface to the derived mesh */ -static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result, int update_normals) +static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result) { PaintSurfaceData *sData = surface->data; @@ -1531,10 +1558,6 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Deri mvert[i].co[2] -= normal[2]*val; } } - else return; - - if (update_normals) - CDDM_calc_normals(result); } /* @@ -1549,6 +1572,7 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData if(pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) { DynamicPaintSurface *surface = pmd->canvas->surfaces.first; + int update_normals = 0; pmd->canvas->flags &= ~MOD_DPAINT_PREVIEW_READY; /* loop through surfaces */ @@ -1748,14 +1772,20 @@ static struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData normal_short_to_float_v3(normal, mvert[i].no); madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height); } - CDDM_calc_normals(result); + update_normals = 1; } /* displace */ - dynamicPaint_applySurfaceDisplace(surface, result, 1); + if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) { + dynamicPaint_applySurfaceDisplace(surface, result); + update_normals = 1; + } } } } + + if (update_normals) + CDDM_calc_normals(result); } /* make a copy of dm to use as brush data */ if (pmd->brush) { @@ -2574,14 +2604,8 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char* filenam if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { PaintPoint *point = &((PaintPoint*)sData->type_data)[index]; - ibuf->rect_float[pos] = point->color[0]; - ibuf->rect_float[pos+1] = point->color[1]; - ibuf->rect_float[pos+2] = point->color[2]; - /* mix wet layer */ - if (point->e_alpha) mixColors(&ibuf->rect_float[pos], point->alpha, point->e_color, point->e_alpha); - - /* use highest alpha */ - ibuf->rect_float[pos+3] = (point->e_alpha > point->alpha) ? point->e_alpha : point->alpha; + /* blend wet and dry layers */ + blendColors(point->color, point->alpha, point->e_color, point->e_alpha, &ibuf->rect_float[pos]); /* Multiply color by alpha if enabled */ if (surface->flags & MOD_DPAINT_MULALPHA) { @@ -2912,7 +2936,13 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned float paint[3], float influence, float depth, float vel_factor, float timescale) { PaintSurfaceData *sData = surface->data; - float strength = influence * brush->alpha; + float strength; + + /* apply influence scale */ + influence *= surface->influence_scale; + depth *= surface->influence_scale; + + strength = influence * brush->alpha; CLAMP(strength, 0.0f, 1.0f); /* Sample velocity colorband if required */ @@ -2991,12 +3021,12 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned } /* checks whether surface and brush bounds intersect depending on brush type */ -static int meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush) +static int meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius) { if (brush->collision == MOD_DPAINT_COL_VOLUME) return boundsIntersect(b1, b2); else if (brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST) - return boundsIntersectDist(b1, b2, brush->paint_distance); + return boundsIntersectDist(b1, b2, brush_radius); else return 1; } @@ -3123,6 +3153,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, { BVHTreeFromMesh treeData = {0}; float avg_brushNor[3] = {0.0f}; + float brush_radius = brush->paint_distance * surface->radius_scale; int numOfVerts; int ii; Bounds3D mesh_bb = {0}; @@ -3161,7 +3192,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, } /* check bounding box collision */ - if(grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush)) + if(grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) /* Build a bvh tree from transformed vertices */ if (bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 8)) { @@ -3173,7 +3204,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, int id; /* check grid cell bounding box */ - if (!grid->s_num[c_index] || !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush)) + if (!grid->s_num[c_index] || !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius)) continue; /* loop through cell points and process brush */ @@ -3234,7 +3265,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, hit.index = -1; hit.dist = 9999; nearest.index = -1; - nearest.dist = brush->paint_distance * brush->paint_distance; /* find_nearest uses squared distance */ + nearest.dist = brush_radius * brush_radius; /* find_nearest uses squared distance */ /* Check volume collision */ if (brush->collision == MOD_DPAINT_COL_VOLUME || brush->collision == MOD_DPAINT_COL_VOLDIST) @@ -3294,7 +3325,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, /* If pure distance proximity, find the nearest point on the mesh */ if (brush->collision != MOD_DPAINT_COL_DIST || !(brush->flags & MOD_DPAINT_PROX_PROJECT)) { if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, mesh_faces_nearest_point_dp, &treeData) != -1) { - proxDist = sqrt(nearest.dist); + proxDist = sqrtf(nearest.dist); copy_v3_v3(hitCo, nearest.co); hQuad = (nearest.no[0] == 1.0f); face = nearest.index; @@ -3314,7 +3345,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, proj_ray[2] = 1.0f; } hit.index = -1; - hit.dist = brush->paint_distance; + hit.dist = brush_radius; /* Do a face normal directional raycast, and use that distance */ if(BLI_bvhtree_ray_cast(treeData.tree, ray_start, proj_ray, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData) != -1) @@ -3327,8 +3358,8 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, } /* If a hit was found, calculate required values */ - if (proxDist >= 0.0f && proxDist <= brush->paint_distance) { - proximity_factor = proxDist / brush->paint_distance; + if (proxDist >= 0.0f && proxDist <= brush_radius) { + proximity_factor = proxDist / brush_radius; CLAMP(proximity_factor, 0.0f, 1.0f); if (!inner_proximity) proximity_factor = 1.0f - proximity_factor; @@ -3514,8 +3545,8 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, int invalidParticles = 0; int p = 0; - float solidradius = (brush->flags & MOD_DPAINT_PART_RAD) ? psys->part->size : brush->particle_radius; - float smooth = brush->particle_smooth; + float solidradius = surface->radius_scale*((brush->flags & MOD_DPAINT_PART_RAD) ? psys->part->size : brush->particle_radius); + float smooth = brush->particle_smooth*surface->radius_scale; float range = solidradius + smooth; float particle_timestep = 0.04f * part->timetweak; @@ -3744,6 +3775,7 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *po Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale) { int index; + float brush_radius = brush->paint_distance * surface->radius_scale; PaintSurfaceData *sData = surface->data; PaintBakeData *bData = sData->bData; Vec3f brushVel; @@ -3761,13 +3793,13 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *po float colorband[4] = {0.0f}; float strength; - if (distance>brush->paint_distance) continue; + if (distance > brush_radius) continue; /* Smooth range or color ramp */ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH || brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP) { - strength = 1.0f - distance / brush->paint_distance; + strength = 1.0f - distance / brush_radius; CLAMP(strength, 0.0f, 1.0f); } else strength = 1.0f; @@ -3832,8 +3864,8 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *po else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WAVE) { /* get displace depth */ - float disp_intersect = (1.0f - sqrtf((brush->paint_distance-distance) / brush->paint_distance)) * brush->paint_distance; - depth = (brush->paint_distance - disp_intersect) / bData->bNormal[index].normal_scale; + float disp_intersect = (1.0f - sqrtf((brush_radius-distance) / brush_radius)) * brush_radius; + depth = (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale; if (depth<0.0f) depth = 0.0f; } dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale); @@ -3936,7 +3968,7 @@ void surface_determineForceTargetPoints(PaintSurfaceData *sData, int index, floa if (closest_id[1] != -1) { float force_proj[3]; float tangent[3]; - float neigh_diff = acos(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir)); + float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir)); float force_intersect; float temp; @@ -4008,7 +4040,6 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus if (n_index != -1 && closest_d[i]>0.0f) { float dir_dot = closest_d[i], dir_factor; float speed_scale = eff_scale*smudge_str/bNeighs[n_index].dist; - float mix; PaintPoint *ePoint = &((PaintPoint*)sData->type_data)[sData->adj_data->n_target[n_index]]; /* just skip if angle is too extreme */ @@ -4018,13 +4049,11 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus if (dir_factor > brush->smudge_strength) dir_factor = brush->smudge_strength; /* mix new color and alpha */ - mix = dir_factor*pPoint->alpha; - if (mix) mixColors(ePoint->color, ePoint->alpha, pPoint->color, mix); + mixColors(ePoint->color, ePoint->alpha, pPoint->color, pPoint->alpha, dir_factor); ePoint->alpha = ePoint->alpha*(1.0f-dir_factor) + pPoint->alpha*dir_factor; /* smudge "wet layer" */ - mix = dir_factor*pPoint->e_alpha; - if (mix) mixColors(ePoint->e_color, ePoint->e_alpha, pPoint->e_color, mix); + mixColors(ePoint->e_color, ePoint->e_alpha, pPoint->e_color, pPoint->e_alpha, dir_factor); ePoint->e_alpha = ePoint->e_alpha*(1.0f-dir_factor) + pPoint->e_alpha*dir_factor; pPoint->wetness *= (1.0f-dir_factor); } @@ -4041,7 +4070,7 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s { double average_force = 0.0f; float shrink_speed=0.0f, spread_speed=0.0f; - float fastest_effect; + float fastest_effect, avg_dist; int steps; PaintSurfaceData *sData = surface->data; PaintBakeData *bData = sData->bData; @@ -4118,9 +4147,10 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s shrink_speed = surface->shrink_speed; fastest_effect = MAX3(spread_speed, shrink_speed, average_force); + avg_dist = bData->average_dist*CANVAS_REL_SIZE/getSurfaceDimension(sData); - steps = (int)ceil(1.5f*EFF_MOVEMENT_PER_FRAME*fastest_effect/bData->average_dist*timescale); - CLAMP(steps, 1, 14); + steps = (int)ceil(1.5f*EFF_MOVEMENT_PER_FRAME*fastest_effect/avg_dist*timescale); + CLAMP(steps, 1, 20); return steps; } @@ -4132,6 +4162,7 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force { PaintSurfaceData *sData = surface->data; BakeNeighPoint *bNeighs = sData->bData->bNeighs; + float distance_scale = getSurfaceDimension(sData)/CANVAS_REL_SIZE; int index; timescale /= steps; @@ -4141,7 +4172,7 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force * Spread Effect */ if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) { - float eff_scale = EFF_MOVEMENT_PER_FRAME*surface->spread_speed*timescale; + float eff_scale = distance_scale*EFF_MOVEMENT_PER_FRAME*surface->spread_speed*timescale; /* Copy current surface to the previous points array to read unmodified values */ memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(struct PaintPoint)); @@ -4151,7 +4182,6 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force { int i; int numOfNeighs = sData->adj_data->n_num[index]; - float totalAlpha = 0.0f; PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index]; /* Only reads values from the surface copy (prevPoint[]), @@ -4160,39 +4190,23 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force /* Loop through neighbouring points */ for (i=0; iadj_data->n_index[index]+i; - float w_factor, alphaAdd = 0.0f; + float w_factor, p_alpha = pPoint->e_alpha; PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]]; float speed_scale = (bNeighs[n_index].distwetness, pPoint->wetness))*0.25f*surface->color_spread_speed; - - totalAlpha += ePoint->e_alpha; + float color_mix = (MIN3(ePoint->wetness, pPoint->wetness, 1.0f))*0.25f*surface->color_spread_speed; /* do color mixing */ - if (color_mix > MIN_WETNESS) mixColors(pPoint->e_color, pPoint->e_alpha, ePoint->e_color, color_mix); + if (color_mix) mixColors(pPoint->e_color, pPoint->e_alpha, ePoint->e_color, ePoint->e_alpha, color_mix); - /* Check if neighbouring point has higher wetness, - * if so, add it's wetness to this point as well*/ - if (ePoint->wetness <= pPoint->wetness) continue; - w_factor = ePoint->wetness/numOfNeighs * (ePoint->wetness - pPoint->wetness) * speed_scale; - if (w_factor <= MIN_WETNESS) continue; + /* Only continue if surrounding point has higher wetness */ + if (ePoint->wetnesswetness || ePoint->wetnesse_alpha > pPoint->e_alpha) { - alphaAdd = ePoint->e_alpha/numOfNeighs * (ePoint->wetness*ePoint->e_alpha - pPoint->wetness*pPoint->e_alpha) * speed_scale; - } + w_factor = 1.0f/numOfNeighs * MIN2(ePoint->wetness, 1.0f) * speed_scale; + CLAMP(w_factor, 0.0f, 1.0f); - /* mix new color */ - mixColors(pPoint->e_color, pPoint->e_alpha, ePoint->e_color, w_factor); - - pPoint->e_alpha += alphaAdd; - pPoint->wetness += w_factor; - - if (pPoint->e_alpha > 1.0f) pPoint->e_alpha = 1.0f; - } - - /* For antialiasing sake, don't let alpha go much higher than average alpha of neighbours */ - if (pPoint->e_alpha > (totalAlpha/numOfNeighs+0.25f)) { - pPoint->e_alpha = (totalAlpha/numOfNeighs+0.25f); - if (pPoint->e_alpha>1.0f) pPoint->e_alpha = 1.0f; + /* mix new wetness and color */ + pPoint->wetness = (1.0f-w_factor)*pPoint->wetness + w_factor*ePoint->wetness; + pPoint->e_alpha = mixColors(pPoint->e_color, pPoint->e_alpha, ePoint->e_color, ePoint->e_alpha, w_factor); } } } @@ -4201,7 +4215,7 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force * Shrink Effect */ if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) { - float eff_scale = EFF_MOVEMENT_PER_FRAME*surface->shrink_speed*timescale; + float eff_scale = distance_scale*EFF_MOVEMENT_PER_FRAME*surface->shrink_speed*timescale; /* Copy current surface to the previous points array to read unmodified values */ memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(struct PaintPoint)); @@ -4251,7 +4265,7 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force */ if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) { - float eff_scale = EFF_MOVEMENT_PER_FRAME*timescale/2.0f; + float eff_scale = distance_scale*EFF_MOVEMENT_PER_FRAME*timescale/2.0f; /* Copy current surface to the previous points array to read unmodified values */ memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(struct PaintPoint)); @@ -4264,8 +4278,9 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force float closest_d[2]; /* adjust drip speed depending on wetness */ - float w_factor = pPoint_prev->wetness*0.5f - 0.025f; + float w_factor = pPoint_prev->wetness - 0.025f; if (w_factor <= 0) continue; + CLAMP(w_factor, 0.0f, 1.0f); /* get force affect points */ surface_determineForceTargetPoints(sData, index, &force[index*4], closest_d, closest_id); @@ -4274,41 +4289,38 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force for (i=0; i<2; i++) { int n_index = closest_id[i]; if (n_index != -1 && closest_d[i]>0.0f) { - float dir_dot = closest_d[i], dir_factor; + float dir_dot = closest_d[i], dir_factor, a_factor; float speed_scale = eff_scale*force[index*4+3]/bNeighs[n_index].dist; PaintPoint *ePoint = &((PaintPoint*)sData->type_data)[sData->adj_data->n_target[n_index]]; + float e_wet = ePoint->wetness; /* just skip if angle is too extreme */ if (dir_dot <= 0.0f) continue; - dir_factor = dir_dot * speed_scale * w_factor; - if (dir_factor > (0.5f/steps)) dir_factor = (0.5f/steps); + dir_factor = dir_dot * MIN2(speed_scale, 1.0f) * w_factor; + if (dir_factor > 0.5f) dir_factor = 0.5f; + + /* mix new wetness*/ + ePoint->wetness += dir_factor; + CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS); /* mix new color */ - if (dir_factor) mixColors(ePoint->e_color, ePoint->e_alpha, pPoint->e_color, dir_factor); + a_factor = dir_factor / pPoint_prev->wetness; + CLAMP(a_factor, 0.0f, 1.0f); + mixColors(ePoint->e_color, ePoint->e_alpha, pPoint_prev->e_color, pPoint_prev->e_alpha, a_factor); + /* dripping is supposed to preserve alpha level */ + if (pPoint_prev->e_alpha > ePoint->e_alpha) { + ePoint->e_alpha += a_factor * pPoint_prev->e_alpha; + if (ePoint->e_alpha > pPoint_prev->e_alpha) + ePoint->e_alpha = pPoint_prev->e_alpha; + } - ePoint->e_alpha += dir_factor; - ePoint->wetness += dir_factor; - if (ePoint->e_alpha > 1.0f) ePoint->e_alpha = 1.0f; - - /* and decrease paint wetness on current point */ - pPoint->wetness -= dir_factor; + /* decrease paint wetness on current point */ + pPoint->wetness -= (ePoint->wetness - e_wet); + CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS); } } } - - /* Keep values within acceptable range */ - #pragma omp parallel for schedule(static) - for (index = 0; index < sData->total_points; index++) - { - PaintPoint *cPoint = &((PaintPoint*)sData->type_data)[index]; - - if (cPoint->e_alpha > 1.0f) cPoint->e_alpha=1.0f; - if (cPoint->wetness > 2.0f) cPoint->wetness=2.0f; - - if (cPoint->e_alpha < 0.0f) cPoint->e_alpha=0.0f; - if (cPoint->wetness < 0.0f) cPoint->wetness=0.0f; - } } } @@ -4323,7 +4335,7 @@ void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescale) double average_dist = 0.0f; Bounds3D *mb = &sData->bData->mesh_bounds; float canvas_size = MAX3((mb->max[0]-mb->min[0]), (mb->max[1]-mb->min[1]), (mb->max[2]-mb->min[2])); - float wave_scale = WAVE_INIT_SIZE/canvas_size; + float wave_scale = CANVAS_REL_SIZE/canvas_size; /* allocate memory */ PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points*sizeof(PaintWavePoint), "Temp previous points for wave simulation"); @@ -4436,48 +4448,53 @@ static void dynamicPaint_surfacePreStep(DynamicPaintSurface *surface, float time if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index]; /* drying */ - if (pPoint->wetness >= MIN_WETNESS) { - int i; - float dry_ratio, f_color[4]; - float p_wetness = pPoint->wetness; - VALUE_DISSOLVE(pPoint->wetness, surface->dry_speed, timescale, (surface->flags & MOD_DPAINT_DRY_LOG)); - if (pPoint->wetness<0.0f) pPoint->wetness=0.0f; - dry_ratio = pPoint->wetness/p_wetness; + if (surface->flags & MOD_DPAINT_USE_DRYING) { + if (pPoint->wetness >= MIN_WETNESS) { + int i; + float dry_ratio, f_color[4]; + float p_wetness = pPoint->wetness; + VALUE_DISSOLVE(pPoint->wetness, surface->dry_speed, timescale, (surface->flags & MOD_DPAINT_DRY_LOG)); + if (pPoint->wetness<0.0f) pPoint->wetness=0.0f; - /* - * Slowly "shift" paint from wet layer to dry layer as it drys: - */ - /* make sure alpha values are within proper range */ - CLAMP(pPoint->alpha, 0.0f, 1.0f); - CLAMP(pPoint->e_alpha, 0.0f, 1.0f); + if (pPoint->wetness < surface->color_dry_threshold) { + dry_ratio = pPoint->wetness/p_wetness; - /* get current final blended color of these layers */ - blendColors(pPoint->color, pPoint->alpha, pPoint->e_color, pPoint->e_alpha, f_color); - /* reduce wet layer alpha by dry factor */ - pPoint->e_alpha *= dry_ratio; + /* + * Slowly "shift" paint from wet layer to dry layer as it drys: + */ + /* make sure alpha values are within proper range */ + CLAMP(pPoint->alpha, 0.0f, 1.0f); + CLAMP(pPoint->e_alpha, 0.0f, 1.0f); - /* now calculate new alpha for dry layer that keeps final blended color unchanged */ - pPoint->alpha = (f_color[3] - pPoint->e_alpha)/(1.0f-pPoint->e_alpha); - /* for each rgb component, calculate a new dry layer color that keeps the final blend color - * with these new alpha values. (wet layer color doesnt change)*/ - if (pPoint->alpha) { - for (i=0; i<3; i++) { - pPoint->color[i] = (f_color[i]*f_color[3] - pPoint->e_color[i]*pPoint->e_alpha)/(pPoint->alpha*(1.0f-pPoint->e_alpha)); + /* get current final blended color of these layers */ + blendColors(pPoint->color, pPoint->alpha, pPoint->e_color, pPoint->e_alpha, f_color); + /* reduce wet layer alpha by dry factor */ + pPoint->e_alpha *= dry_ratio; + + /* now calculate new alpha for dry layer that keeps final blended color unchanged */ + pPoint->alpha = (f_color[3] - pPoint->e_alpha)/(1.0f-pPoint->e_alpha); + /* for each rgb component, calculate a new dry layer color that keeps the final blend color + * with these new alpha values. (wet layer color doesnt change)*/ + if (pPoint->alpha) { + for (i=0; i<3; i++) { + pPoint->color[i] = (f_color[i]*f_color[3] - pPoint->e_color[i]*pPoint->e_alpha)/(pPoint->alpha*(1.0f-pPoint->e_alpha)); + } + } } - } - pPoint->state = DPAINT_PAINT_WET; - } - /* in case of just dryed paint, just mix it to the dry layer and mark it empty */ - else if (pPoint->state > 0) { - float f_color[4]; - blendColors(pPoint->color, pPoint->alpha, pPoint->e_color, pPoint->e_alpha, f_color); - copy_v3_v3(pPoint->color, f_color); - pPoint->alpha = f_color[3]; - /* clear wet layer */ - pPoint->wetness = 0.0f; - pPoint->e_alpha = 0.0f; - pPoint->state = DPAINT_PAINT_DRY; + pPoint->state = DPAINT_PAINT_WET; + } + /* in case of just dryed paint, just mix it to the dry layer and mark it empty */ + else if (pPoint->state > 0) { + float f_color[4]; + blendColors(pPoint->color, pPoint->alpha, pPoint->e_color, pPoint->e_alpha, f_color); + copy_v3_v3(pPoint->color, f_color); + pPoint->alpha = f_color[3]; + /* clear wet layer */ + pPoint->wetness = 0.0f; + pPoint->e_alpha = 0.0f; + pPoint->state = DPAINT_PAINT_DRY; + } } if (surface->flags & MOD_DPAINT_DISSOLVE) { @@ -4925,7 +4942,7 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje /* apply previous displace on derivedmesh if incremental surface */ if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) - dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm, 0); + dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm); /* update bake data */ dynamicPaint_generateBakeData(surface, scene, cObject); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1aa71732697..6855ece8cd7 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -12974,8 +12974,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } } - - /* put compatibility code here until next subversion bump */ + + if (main->versionfile < 261 || (main->versionfile == 261 && main->subversionfile < 3)) { { /* convert extended ascii to utf-8 for text editor */ @@ -12994,6 +12994,32 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } } + { + /* set new dynamic paint values */ + Object *ob; + for(ob = main->object.first; ob; ob = ob->id.next) { + ModifierData *md; + for(md= ob->modifiers.first; md; md= md->next) { + if (md->type == eModifierType_DynamicPaint) { + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; + if(pmd->canvas) + { + DynamicPaintSurface *surface = pmd->canvas->surfaces.first; + for (; surface; surface=surface->next) { + surface->color_dry_threshold = 1.0f; + surface->influence_scale = 1.0f; + surface->radius_scale = 1.0f; + surface->flags |= MOD_DPAINT_USE_DRYING; + } + } + } + } + } + } + } + + /* put compatibility code here until next subversion bump */ + { } /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ diff --git a/source/blender/makesdna/DNA_dynamicpaint_types.h b/source/blender/makesdna/DNA_dynamicpaint_types.h index 0bf4ffb76ee..6dab70c6dee 100644 --- a/source/blender/makesdna/DNA_dynamicpaint_types.h +++ b/source/blender/makesdna/DNA_dynamicpaint_types.h @@ -55,6 +55,7 @@ struct PaintSurfaceData; #define MOD_DPAINT_WAVE_OPEN_BORDERS (1<<7) /* passes waves through mesh edges */ #define MOD_DPAINT_DISP_INCREMENTAL (1<<8) /* builds displace on top of earlier values */ +#define MOD_DPAINT_USE_DRYING (1<<9) /* use drying */ #define MOD_DPAINT_OUT1 (1<<10) /* output primary surface */ #define MOD_DPAINT_OUT2 (1<<11) /* output secondary surface */ @@ -69,8 +70,8 @@ struct PaintSurfaceData; /* effect */ #define MOD_DPAINT_EFFECT_DO_SPREAD (1<<0) /* do spread effect */ -#define MOD_DPAINT_EFFECT_DO_DRIP (1<<1) /* do spread effect */ -#define MOD_DPAINT_EFFECT_DO_SHRINK (1<<2) /* do spread effect */ +#define MOD_DPAINT_EFFECT_DO_DRIP (1<<1) /* do drip effect */ +#define MOD_DPAINT_EFFECT_DO_SHRINK (1<<2) /* do shrink effect */ /* preview_id */ #define MOD_DPAINT_SURFACE_PREV_PAINT 0 @@ -114,16 +115,18 @@ typedef struct DynamicPaintSurface { char init_layername[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ int dry_speed, diss_speed; + float color_dry_threshold; float depth_clamp, disp_factor; float spread_speed, color_spread_speed, shrink_speed; float drip_vel, drip_acc; + /* per surface brush settings */ + float influence_scale, radius_scale; + /* wave settings */ float wave_damping, wave_speed, wave_timescale, wave_spring; - int pad_; - char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ char image_output_path[240]; /* 240 = FILE_MAX */ char output_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c index 4886a4f30b1..95770685077 100644 --- a/source/blender/makesrna/intern/rna_dynamicpaint.c +++ b/source/blender/makesrna/intern/rna_dynamicpaint.c @@ -395,6 +395,10 @@ static void rna_def_canvas_surface(BlenderRNA *brna) RNA_def_property_range(prop, 1.0, 10000.0); RNA_def_property_ui_range(prop, 1.0, 10000.0, 5, 0); RNA_def_property_ui_text(prop, "Dissolve Speed", "Approximately in how many frames should dissolve happen"); + + prop= RNA_def_property(srna, "use_drying", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_USE_DRYING); + RNA_def_property_ui_text(prop, "Dry", "Enable to make surface wetness dry over time"); prop= RNA_def_property(srna, "dry_speed", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 1.0, 10000.0); @@ -443,6 +447,20 @@ static void rna_def_canvas_surface(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Anti-aliasing", "Use 5x multisampling to smoothen paint edges"); RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_DynamicPaintSurface_reset"); + prop= RNA_def_property(srna, "brush_influence_scale", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "influence_scale"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 2); + RNA_def_property_ui_text(prop, "Influence Scale", "Adjust influence brush objects have on this surface"); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_DynamicPaint_redoModifier"); + + prop= RNA_def_property(srna, "brush_radius_scale", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "radius_scale"); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 2); + RNA_def_property_ui_text(prop, "Radius Scale", "Adjust radius of proximity brushes or particles for this surface"); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_DynamicPaint_redoModifier"); + /* * Initial Color */ @@ -454,6 +472,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna) RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING_DRAW|ND_MODIFIER, "rna_DynamicPaintSurface_initialcolortype"); prop= RNA_def_property(srna, "init_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Color", "Initial color of the surface"); RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING_DRAW|ND_MODIFIER, "rna_DynamicPaintSurface_reset"); @@ -495,6 +514,12 @@ static void rna_def_canvas_surface(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0.01, 5.0, 1, 2); RNA_def_property_ui_text(prop, "Spread Speed", "How fast spread effect moves on the canvas surface"); + prop= RNA_def_property(srna, "color_dry_threshold", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "color_dry_threshold"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 2); + RNA_def_property_ui_text(prop, "Color Dry", "The wetness level when colors start to shift to the background"); + prop= RNA_def_property(srna, "color_spread_speed", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "color_spread_speed"); RNA_def_property_range(prop, 0.0, 2.0);