Optional clumping noise feature for simulating twisted hair strands.
This adds another level of clumping on child hairs. When enabled, child hairs chose a secondary clumping target using a Voronoi pattern. This adds visual detail on a smaller scale, which is useful particularly when the number of parents is relatively small. Natural fibres behave in a similar way when they become sticky and intertwined. Hairs close to each other form a first twisted strand, then combine into larger strands. Similar features can be found in ropes: http://en.wikipedia.org/wiki/Hair_twists http://en.wikipedia.org/wiki/Rope Conflicts: source/blender/blenloader/intern/versioning_270.c
This commit is contained in:
parent
7f219137cf
commit
c2306919b7
@ -1173,6 +1173,11 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
|
||||
else:
|
||||
sub.prop(part, "clump_factor", slider=True)
|
||||
sub.prop(part, "clump_shape", slider=True)
|
||||
sub = col.column(align=True)
|
||||
sub.prop(part, "use_clump_noise")
|
||||
subsub = sub.column()
|
||||
subsub.enabled = part.use_clump_noise
|
||||
subsub.prop(part, "clump_noise_size")
|
||||
|
||||
sub = col.column(align=True)
|
||||
sub.prop(part, "child_length", slider=True)
|
||||
|
@ -343,7 +343,7 @@ void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part);
|
||||
void BKE_particlesettings_rough_curve_init(struct ParticleSettings *part);
|
||||
void psys_apply_child_modifiers(struct ParticleThreadContext *ctx, struct ListBase *modifiers,
|
||||
struct ChildParticle *cpa, struct ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
|
||||
struct ParticleCacheKey *keys, struct ParticleCacheKey *parent_keys);
|
||||
struct ParticleCacheKey *keys, struct ParticleCacheKey *parent_keys, const float parent_orco[3]);
|
||||
|
||||
void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata);
|
||||
void psys_sph_finalise(struct SPHData *sphdata);
|
||||
|
@ -104,8 +104,8 @@ void psys_init_rng(void)
|
||||
static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx,
|
||||
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
|
||||
extern void do_child_modifiers(ParticleSimulationData *sim,
|
||||
ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa,
|
||||
const float orco[3], float mat[4][4], ParticleKey *state, float t);
|
||||
ParticleTexture *ptex, ParticleKey *par, float *par_rot, const float par_orco[3],
|
||||
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
|
||||
|
||||
/* few helpers for countall etc. */
|
||||
int count_particles(ParticleSystem *psys)
|
||||
@ -1672,7 +1672,8 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
|
||||
|
||||
extern void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat,
|
||||
short type, short axis, float obmat[4][4], int smooth_start);
|
||||
extern float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve);
|
||||
extern float do_clump(ParticleKey *state, ParticleKey *par, float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
|
||||
bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve);
|
||||
|
||||
void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
|
||||
{
|
||||
@ -1720,7 +1721,6 @@ int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, i
|
||||
EffectorCache *eff;
|
||||
PartDeflect *pd;
|
||||
Curve *cu;
|
||||
ParticleKey key, par;
|
||||
GuideEffectorData *data;
|
||||
|
||||
float effect[3] = {0.0f, 0.0f, 0.0f}, veffect[3] = {0.0f, 0.0f, 0.0f};
|
||||
@ -1790,11 +1790,17 @@ int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, i
|
||||
if (part->roughcurve)
|
||||
curvemapping_changed_all(part->roughcurve);
|
||||
|
||||
par.co[0] = par.co[1] = par.co[2] = 0.0f;
|
||||
copy_v3_v3(key.co, vec_to_point);
|
||||
do_kink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, 0.f, pd->kink, pd->kink_axis, 0, 0);
|
||||
do_clump(&key, &par, guidetime, pd->clump_fac, pd->clump_pow, 1.0f, part->clumpcurve);
|
||||
copy_v3_v3(vec_to_point, key.co);
|
||||
{
|
||||
ParticleKey key, par;
|
||||
float orco_offset[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
par.co[0] = par.co[1] = par.co[2] = 0.0f;
|
||||
copy_v3_v3(key.co, vec_to_point);
|
||||
do_kink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, 0.f, pd->kink, pd->kink_axis, 0, 0);
|
||||
do_clump(&key, &par, guidetime, orco_offset, pd->clump_fac, pd->clump_pow, 1.0f,
|
||||
part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, part->clumpcurve);
|
||||
copy_v3_v3(vec_to_point, key.co);
|
||||
}
|
||||
|
||||
add_v3_v3(vec_to_point, guidevec);
|
||||
|
||||
@ -2018,7 +2024,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
|
||||
ParticleSettings *part = psys->part;
|
||||
ParticleCacheKey **cache = psys->childcache;
|
||||
ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.scene, psys) && psys->edit ? psys->edit->pathcache : psys->pathcache;
|
||||
ParticleCacheKey *child, *par = NULL, *key[4];
|
||||
ParticleCacheKey *child, *key[4];
|
||||
ParticleTexture ptex;
|
||||
float *cpa_fuv = 0, *par_rot = 0, rot[4];
|
||||
float orco[3], ornor[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3];
|
||||
@ -2219,16 +2225,35 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->totparent)
|
||||
/* this is now threadsafe, virtual parents are calculated before rest of children */
|
||||
par = (i >= ctx->totparent) ? cache[cpa->parent] : NULL;
|
||||
else if (cpa->parent >= 0)
|
||||
par = pcache[cpa->parent];
|
||||
|
||||
{
|
||||
ListBase modifiers;
|
||||
BLI_listbase_clear(&modifiers);
|
||||
psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, ornor, hairmat, child_keys, par);
|
||||
ParticleData *pa = NULL;
|
||||
ParticleCacheKey *par = NULL;
|
||||
float par_co[3];
|
||||
float par_orco[3];
|
||||
|
||||
if (ctx->totparent) {
|
||||
if (i >= ctx->totparent) {
|
||||
pa = &psys->particles[cpa->parent];
|
||||
/* this is now threadsafe, virtual parents are calculated before rest of children */
|
||||
par = cache[cpa->parent];
|
||||
}
|
||||
}
|
||||
else if (cpa->parent >= 0) {
|
||||
pa = &psys->particles[cpa->parent];
|
||||
par = pcache[cpa->parent];
|
||||
}
|
||||
|
||||
if (pa)
|
||||
psys_particle_on_emitter(ctx->sim.psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset,
|
||||
par_co, NULL, NULL, NULL, par_orco, NULL);
|
||||
else
|
||||
zero_v3(par_orco);
|
||||
|
||||
{
|
||||
ListBase modifiers;
|
||||
BLI_listbase_clear(&modifiers);
|
||||
psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, ornor, hairmat, child_keys, par, par_orco);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
for (k = 0, child = child_keys; k <= ctx->steps; k++, child++) {
|
||||
@ -3093,6 +3118,7 @@ static void default_particle_settings(ParticleSettings *part)
|
||||
part->adapt_pix = 3;
|
||||
part->kink_axis = 2;
|
||||
part->kink_amp_clump = 1.f;
|
||||
part->clump_noise_size = 1.0f;
|
||||
part->reactevent = PART_EVENT_DEATH;
|
||||
part->disp = 100;
|
||||
part->from = PART_FROM_FACE;
|
||||
@ -3674,6 +3700,8 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
|
||||
copy_qt_qt(state->rot, result.rot);
|
||||
}
|
||||
else {
|
||||
float par_co[3], par_orco[3];
|
||||
|
||||
cpa = psys->child + p - totpart;
|
||||
|
||||
if (state->time < 0.0f)
|
||||
@ -3710,6 +3738,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
|
||||
|
||||
pa = psys->particles + cpa->parent;
|
||||
|
||||
psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
|
||||
if (part->type == PART_HAIR)
|
||||
psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
|
||||
else
|
||||
@ -3729,8 +3758,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
|
||||
cpa_num = pa->num;
|
||||
cpa_fuv = pa->fuv;
|
||||
|
||||
|
||||
|
||||
psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
|
||||
if (part->type == PART_HAIR) {
|
||||
psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco, 0);
|
||||
psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
|
||||
@ -3788,7 +3816,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
|
||||
copy_particle_key(&tstate, state, 1);
|
||||
|
||||
/* apply different deformations to the child path */
|
||||
do_child_modifiers(sim, &ptex, par, par->rot, cpa, orco, hairmat, state, t);
|
||||
do_child_modifiers(sim, &ptex, par, par->rot, par_orco, cpa, orco, hairmat, state, t);
|
||||
|
||||
/* try to estimate correct velocity */
|
||||
if (vel) {
|
||||
@ -3883,6 +3911,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
|
||||
float mat[4][4];
|
||||
ParticleKey *key1;
|
||||
float t = (cfra - pa->time) / pa->lifetime;
|
||||
float par_orco[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
key1 = &pa->state;
|
||||
offset_child(cpa, key1, key1->rot, state, part->childflat, part->childrad);
|
||||
@ -3890,7 +3919,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
|
||||
CLAMP(t, 0.0f, 1.0f);
|
||||
|
||||
unit_m4(mat);
|
||||
do_child_modifiers(sim, NULL, key1, key1->rot, cpa, cpa->fuv, mat, state, t);
|
||||
do_child_modifiers(sim, NULL, key1, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t);
|
||||
|
||||
if (psys->lattice_deform_data)
|
||||
calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f);
|
||||
|
@ -41,10 +41,11 @@ struct Material;
|
||||
|
||||
void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat,
|
||||
short type, short axis, float obmat[4][4], int smooth_start);
|
||||
float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve);
|
||||
float do_clump(ParticleKey *state, ParticleKey *par, float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
|
||||
bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve);
|
||||
void do_child_modifiers(ParticleSimulationData *sim,
|
||||
ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa,
|
||||
const float orco[3], float mat[4][4], ParticleKey *state, float t);
|
||||
ParticleTexture *ptex, ParticleKey *par, float *par_rot, const float par_orco[3],
|
||||
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
|
||||
|
||||
static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3])
|
||||
{
|
||||
@ -89,7 +90,8 @@ typedef struct ParticlePathIterator {
|
||||
float parent_rotation[4];
|
||||
} ParticlePathIterator;
|
||||
|
||||
static void psys_path_iter_get(ParticlePathIterator *iter, ParticleCacheKey *keys, int totkeys, ParticleCacheKey *parent, int index)
|
||||
static void psys_path_iter_get(ParticlePathIterator *iter, ParticleCacheKey *keys, int totkeys,
|
||||
ParticleCacheKey *parent, int index)
|
||||
{
|
||||
BLI_assert(index >= 0 && index < totkeys);
|
||||
|
||||
@ -136,7 +138,7 @@ static bool check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *k
|
||||
|
||||
void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *modifiers,
|
||||
ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
|
||||
ParticleCacheKey *keys, ParticleCacheKey *parent_keys)
|
||||
ParticleCacheKey *keys, ParticleCacheKey *parent_keys, const float parent_orco[3])
|
||||
{
|
||||
struct ParticleSettings *part = ctx->sim.psys->part;
|
||||
struct Material *ma = ctx->ma;
|
||||
@ -165,7 +167,7 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
|
||||
psys_path_iter_get(&iter, keys, totkeys, parent_keys, k);
|
||||
|
||||
/* apply different deformations to the child path */
|
||||
do_child_modifiers(&ctx->sim, ptex, (ParticleKey *)iter.parent_key, iter.parent_rotation, cpa, orco, hairmat, (ParticleKey *)key, iter.time);
|
||||
do_child_modifiers(&ctx->sim, ptex, (ParticleKey *)iter.parent_key, iter.parent_rotation, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, iter.time);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -360,17 +362,15 @@ void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, f
|
||||
copy_v3_v3(state->co, result);
|
||||
}
|
||||
|
||||
float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve)
|
||||
static float do_clump_level(float result[3], const float co[3], const float par_co[3], float time,
|
||||
float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve)
|
||||
{
|
||||
float clump = 0.f;
|
||||
|
||||
if (!par)
|
||||
return 0.0f;
|
||||
float clump = 0.0f;
|
||||
|
||||
if (clumpcurve) {
|
||||
clump = pa_clump * (1.0f - CLAMPIS(curvemapping_evaluateF(clumpcurve, 0, time), 0.0f, 1.0f));
|
||||
|
||||
interp_v3_v3v3(state->co, state->co, par->co, clump);
|
||||
interp_v3_v3v3(result, co, par_co, clump);
|
||||
}
|
||||
else if (clumpfac != 0.0f) {
|
||||
float cpow;
|
||||
@ -385,9 +385,34 @@ float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac,
|
||||
else
|
||||
clump = clumpfac * pa_clump * (float)pow((double)time, (double)cpow);
|
||||
|
||||
interp_v3_v3v3(state->co, state->co, par->co, clump);
|
||||
interp_v3_v3v3(result, co, par_co, clump);
|
||||
}
|
||||
|
||||
return clump;
|
||||
}
|
||||
|
||||
float do_clump(ParticleKey *state, ParticleKey *par, float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
|
||||
bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve)
|
||||
{
|
||||
float clump;
|
||||
|
||||
if (!par)
|
||||
return 0.0f;
|
||||
|
||||
if (use_clump_noise && clump_noise_size != 0.0f) {
|
||||
float center[3], noisevec[3];
|
||||
float da[4], pa[12];
|
||||
|
||||
mul_v3_v3fl(noisevec, orco_offset, 1.0f / clump_noise_size);
|
||||
voronoi(noisevec[0], noisevec[1], noisevec[2], da, pa, 1.0f, 0);
|
||||
mul_v3_fl(&pa[0], clump_noise_size);
|
||||
add_v3_v3v3(center, par->co, &pa[0]);
|
||||
|
||||
do_clump_level(state->co, state->co, center, time, clumpfac, clumppow, pa_clump, clumpcurve);
|
||||
}
|
||||
|
||||
clump = do_clump_level(state->co, state->co, par->co, time, clumpfac, clumppow, pa_clump, clumpcurve);
|
||||
|
||||
return clump;
|
||||
}
|
||||
|
||||
@ -449,7 +474,8 @@ static void do_rough_curve(const float loc[3], float mat[4][4], float time, floa
|
||||
madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
|
||||
}
|
||||
|
||||
void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t)
|
||||
void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, ParticleKey *par, float *par_rot, const float par_orco[3],
|
||||
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t)
|
||||
{
|
||||
ParticleSettings *part = sim->psys->part;
|
||||
int i = cpa - sim->psys->child;
|
||||
@ -472,7 +498,12 @@ void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, Part
|
||||
guided = do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
|
||||
|
||||
if (guided == 0) {
|
||||
float clump = do_clump(state, par, t, part->clumpfac, part->clumppow, ptex ? ptex->clump : 1.f, part->clumpcurve);
|
||||
float orco_offset[3];
|
||||
float clump;
|
||||
|
||||
sub_v3_v3v3(orco_offset, orco, par_orco);
|
||||
clump = do_clump(state, par, t, orco_offset, part->clumpfac, part->clumppow, ptex ? ptex->clump : 1.f,
|
||||
part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, part->clumpcurve);
|
||||
|
||||
if (kink_freq != 0.f) {
|
||||
float kink_amp = part->kink_amp * (1.f - part->kink_amp_clump * clump);
|
||||
|
@ -491,4 +491,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "ParticleSettings", "float", "clumpnoisesize")) {
|
||||
ParticleSettings *part;
|
||||
for (part = main->particle.first; part; part = part->id.next) {
|
||||
part->clump_noise_size = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -208,6 +208,8 @@ typedef struct ParticleSettings {
|
||||
/* length */
|
||||
float randlength;
|
||||
/* children */
|
||||
int child_flag;
|
||||
int pad3;
|
||||
int child_nbr, ren_child_nbr;
|
||||
float parents, childsize, childrandsize;
|
||||
float childrad, childflat;
|
||||
@ -235,10 +237,10 @@ typedef struct ParticleSettings {
|
||||
int keyed_loops;
|
||||
struct CurveMapping *clumpcurve;
|
||||
struct CurveMapping *roughcurve;
|
||||
float clump_noise_size;
|
||||
|
||||
/* hair dynamics */
|
||||
float bending_random;
|
||||
int pad3;
|
||||
|
||||
struct MTex *mtex[18]; /* MAX_MTEX */
|
||||
|
||||
@ -421,6 +423,11 @@ typedef enum eParticleDrawFlag {
|
||||
#define PART_KINK_WAVE 3
|
||||
#define PART_KINK_BRAID 4
|
||||
|
||||
/* part->kink_flag */
|
||||
typedef enum eParticleChildFlag {
|
||||
PART_CHILD_USE_CLUMP_NOISE = 1,
|
||||
} eParticleChildFlag;
|
||||
|
||||
/* part->draw_col */
|
||||
#define PART_DRAW_COL_NONE 0
|
||||
#define PART_DRAW_COL_MAT 1
|
||||
|
@ -2856,6 +2856,18 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Clump Curve", "Curve defining clump tapering");
|
||||
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
|
||||
|
||||
prop = RNA_def_property(srna, "use_clump_noise", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "child_flag", PART_CHILD_USE_CLUMP_NOISE);
|
||||
RNA_def_property_ui_text(prop, "Use Clump Noise", "Create random clumps around the parent");
|
||||
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
|
||||
|
||||
prop = RNA_def_property(srna, "clump_noise_size", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "clump_noise_size");
|
||||
RNA_def_property_range(prop, 0.00001f, 100000.0f);
|
||||
RNA_def_property_ui_range(prop, 0.01f, 10.0f, 0.1f, 3);
|
||||
RNA_def_property_ui_text(prop, "Clump Noise Size", "Size of clump noise");
|
||||
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
|
||||
|
||||
/* kink */
|
||||
prop = RNA_def_property(srna, "kink_amplitude", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "kink_amp");
|
||||
|
Loading…
Reference in New Issue
Block a user