This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/blenkernel/intern/particle_child.c
Campbell Barton 525364be31 Cleanup: reduce indirect DNA header inclusion
Remove DNA headers, using forward declarations where possible.

Also removed duplicate header, header including it's self
and unnecessary inclusion of libc system headers from BKE header.
2020-12-15 12:34:14 +11:00

925 lines
27 KiB
C

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) Blender Foundation
* All rights reserved.
*/
/** \file
* \ingroup bke
*/
#include "BLI_math.h"
#include "BLI_noise.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "BKE_colortools.h"
#include "BKE_particle.h"
#include "particle_private.h"
/* ------------------------------------------------------------------------- */
typedef struct ParticlePathIterator {
ParticleCacheKey *key;
int index;
float time;
ParticleCacheKey *parent_key;
float parent_rotation[4];
} ParticlePathIterator;
static void psys_path_iter_get(ParticlePathIterator *iter,
ParticleCacheKey *keys,
int totkeys,
ParticleCacheKey *parent,
int index)
{
BLI_assert(index >= 0 && index < totkeys);
iter->key = keys + index;
iter->index = index;
iter->time = (float)index / (float)(totkeys - 1);
if (parent) {
iter->parent_key = parent + index;
if (index > 0) {
mul_qt_qtqt(iter->parent_rotation, iter->parent_key->rot, parent->rot);
}
else {
copy_qt_qt(iter->parent_rotation, parent->rot);
}
}
else {
iter->parent_key = NULL;
unit_qt(iter->parent_rotation);
}
}
typedef struct ParticlePathModifier {
struct ParticlePathModifier *next, *prev;
void (*apply)(ParticleCacheKey *keys, int totkeys, ParticleCacheKey *parent_keys);
} ParticlePathModifier;
/* ------------------------------------------------------------------------- */
static void do_kink_spiral_deform(ParticleKey *state,
const float dir[3],
const float kink[3],
float time,
float freq,
float shape,
float amplitude,
const float spiral_start[3])
{
float result[3];
CLAMP(time, 0.0f, 1.0f);
copy_v3_v3(result, state->co);
{
/* Creates a logarithmic spiral:
* r(theta) = a * exp(b * theta)
*
* The "density" parameter b is defined by the shape parameter
* and goes up to the Golden Spiral for 1.0
* https://en.wikipedia.org/wiki/Golden_spiral
*/
const float b = shape * (1.0f + sqrtf(5.0f)) / (float)M_PI * 0.25f;
/* angle of the spiral against the curve (rotated opposite to make a smooth transition) */
const float start_angle = ((b != 0.0f) ? atanf(1.0f / b) : (float)-M_PI_2) +
(b > 0.0f ? -(float)M_PI_2 : (float)M_PI_2);
float spiral_axis[3], rot[3][3];
float vec[3];
float theta = freq * time * 2.0f * (float)M_PI;
float radius = amplitude * expf(b * theta);
/* a bit more intuitive than using negative frequency for this */
if (amplitude < 0.0f) {
theta = -theta;
}
cross_v3_v3v3(spiral_axis, dir, kink);
normalize_v3(spiral_axis);
mul_v3_v3fl(vec, kink, -radius);
axis_angle_normalized_to_mat3(rot, spiral_axis, theta);
mul_m3_v3(rot, vec);
madd_v3_v3fl(vec, kink, amplitude);
axis_angle_normalized_to_mat3(rot, spiral_axis, -start_angle);
mul_m3_v3(rot, vec);
add_v3_v3v3(result, spiral_start, vec);
}
copy_v3_v3(state->co, result);
}
static void do_kink_spiral(ParticleThreadContext *ctx,
ParticleTexture *ptex,
const float parent_orco[3],
ChildParticle *cpa,
const float orco[3],
float hairmat[4][4],
ParticleCacheKey *keys,
ParticleCacheKey *parent_keys,
int *r_totkeys,
float *r_max_length)
{
struct ParticleSettings *part = ctx->sim.psys->part;
const int seed = ctx->sim.psys->child_seed + (int)(cpa - ctx->sim.psys->child);
const int totkeys = ctx->segments + 1;
const int extrakeys = ctx->extra_segments;
float kink_amp_random = part->kink_amp_random;
float kink_amp = part->kink_amp *
(1.0f - kink_amp_random * psys_frand(ctx->sim.psys, 93541 + seed));
float kink_freq = part->kink_freq;
float kink_shape = part->kink_shape;
float kink_axis_random = part->kink_axis_random;
float rough1 = part->rough1;
float rough2 = part->rough2;
float rough_end = part->rough_end;
ParticlePathIterator iter;
ParticleCacheKey *key;
int k;
float dir[3];
float spiral_start[3] = {0.0f, 0.0f, 0.0f};
float spiral_start_time = 0.0f;
float spiral_par_co[3] = {0.0f, 0.0f, 0.0f};
float spiral_par_vel[3] = {0.0f, 0.0f, 0.0f};
float spiral_par_rot[4] = {1.0f, 0.0f, 0.0f, 0.0f};
float totlen;
float cut_time;
int start_index = 0, end_index = 0;
float kink_base[3];
if (ptex) {
kink_amp *= ptex->kink_amp;
kink_freq *= ptex->kink_freq;
rough1 *= ptex->rough1;
rough2 *= ptex->rough2;
rough_end *= ptex->roughe;
}
cut_time = (totkeys - 1) * ptex->length;
zero_v3(spiral_start);
for (k = 0, key = keys; k < totkeys - 1; k++, key++) {
if ((float)(k + 1) >= cut_time) {
float fac = cut_time - (float)k;
ParticleCacheKey *par = parent_keys + k;
start_index = k + 1;
end_index = start_index + extrakeys;
spiral_start_time = ((float)k + fac) / (float)(totkeys - 1);
interp_v3_v3v3(spiral_start, key->co, (key + 1)->co, fac);
interp_v3_v3v3(spiral_par_co, par->co, (par + 1)->co, fac);
interp_v3_v3v3(spiral_par_vel, par->vel, (par + 1)->vel, fac);
interp_qt_qtqt(spiral_par_rot, par->rot, (par + 1)->rot, fac);
break;
}
}
zero_v3(dir);
zero_v3(kink_base);
kink_base[part->kink_axis] = 1.0f;
mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base);
/* Fill in invariant part of modifier context. */
ParticleChildModifierContext modifier_ctx = {NULL};
modifier_ctx.thread_ctx = ctx;
modifier_ctx.sim = &ctx->sim;
modifier_ctx.ptex = ptex;
modifier_ctx.cpa = cpa;
modifier_ctx.orco = orco;
modifier_ctx.parent_keys = parent_keys;
for (k = 0, key = keys; k < end_index; k++, key++) {
float par_time;
float *par_co, *par_vel, *par_rot;
psys_path_iter_get(&iter, keys, end_index, NULL, k);
if (k < start_index) {
sub_v3_v3v3(dir, (key + 1)->co, key->co);
normalize_v3(dir);
par_time = (float)k / (float)(totkeys - 1);
par_co = parent_keys[k].co;
par_vel = parent_keys[k].vel;
par_rot = parent_keys[k].rot;
}
else {
float spiral_time = (float)(k - start_index) / (float)(extrakeys - 1);
float kink[3], tmp[3];
/* use same time value for every point on the spiral */
par_time = spiral_start_time;
par_co = spiral_par_co;
par_vel = spiral_par_vel;
par_rot = spiral_par_rot;
project_v3_v3v3(tmp, kink_base, dir);
sub_v3_v3v3(kink, kink_base, tmp);
normalize_v3(kink);
if (kink_axis_random > 0.0f) {
float a = kink_axis_random * (psys_frand(ctx->sim.psys, 7112 + seed) * 2.0f - 1.0f) *
(float)M_PI;
float rot[3][3];
axis_angle_normalized_to_mat3(rot, dir, a);
mul_m3_v3(rot, kink);
}
do_kink_spiral_deform((ParticleKey *)key,
dir,
kink,
spiral_time,
kink_freq,
kink_shape,
kink_amp,
spiral_start);
}
/* Fill in variant part of modifier context. */
modifier_ctx.par_co = par_co;
modifier_ctx.par_vel = par_vel;
modifier_ctx.par_rot = par_rot;
modifier_ctx.par_orco = parent_orco;
/* Apply different deformations to the child path/ */
do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, par_time);
}
totlen = 0.0f;
for (k = 0, key = keys; k < end_index - 1; k++, key++) {
totlen += len_v3v3((key + 1)->co, key->co);
}
*r_totkeys = end_index;
*r_max_length = totlen;
}
/* ------------------------------------------------------------------------- */
static bool check_path_length(int k,
ParticleCacheKey *keys,
ParticleCacheKey *key,
float max_length,
float step_length,
float *cur_length,
float dvec[3])
{
if (*cur_length + step_length > max_length) {
sub_v3_v3v3(dvec, key->co, (key - 1)->co);
mul_v3_fl(dvec, (max_length - *cur_length) / step_length);
add_v3_v3v3(key->co, (key - 1)->co, dvec);
keys->segments = k;
/* something over the maximum step value */
return false;
}
*cur_length += step_length;
return true;
}
void psys_apply_child_modifiers(ParticleThreadContext *ctx,
struct ListBase *modifiers,
ChildParticle *cpa,
ParticleTexture *ptex,
const float orco[3],
float hairmat[4][4],
ParticleCacheKey *keys,
ParticleCacheKey *parent_keys,
const float parent_orco[3])
{
struct ParticleSettings *part = ctx->sim.psys->part;
struct Material *ma = ctx->ma;
const bool draw_col_ma = (part->draw_col == PART_DRAW_COL_MAT);
const bool use_length_check = !ELEM(part->kink, PART_KINK_SPIRAL);
ParticlePathModifier *mod;
ParticleCacheKey *key;
int totkeys, k;
float max_length;
/* TODO for the future: use true particle modifiers that work on the whole curve */
(void)modifiers;
(void)mod;
if (part->kink == PART_KINK_SPIRAL) {
do_kink_spiral(
ctx, ptex, parent_orco, cpa, orco, hairmat, keys, parent_keys, &totkeys, &max_length);
keys->segments = totkeys - 1;
}
else {
/* Fill in invariant part of modifier context. */
ParticleChildModifierContext modifier_ctx = {NULL};
modifier_ctx.thread_ctx = ctx;
modifier_ctx.sim = &ctx->sim;
modifier_ctx.ptex = ptex;
modifier_ctx.cpa = cpa;
modifier_ctx.orco = orco;
modifier_ctx.parent_keys = parent_keys;
totkeys = ctx->segments + 1;
max_length = ptex->length;
for (k = 0, key = keys; k < totkeys; k++, key++) {
ParticlePathIterator iter;
psys_path_iter_get(&iter, keys, totkeys, parent_keys, k);
ParticleKey *par = (ParticleKey *)iter.parent_key;
/* Fill in variant part of modifier context. */
modifier_ctx.par_co = par->co;
modifier_ctx.par_vel = par->vel;
modifier_ctx.par_rot = iter.parent_rotation;
modifier_ctx.par_orco = parent_orco;
/* Apply different deformations to the child path. */
do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, iter.time);
}
}
{
const float step_length = 1.0f / (float)(totkeys - 1);
float cur_length = 0.0f;
if (max_length <= 0.0f) {
keys->segments = -1;
totkeys = 0;
}
/* we have to correct velocity because of kink & clump */
for (k = 0, key = keys; k < totkeys; k++, key++) {
if (k >= 2) {
sub_v3_v3v3((key - 1)->vel, key->co, (key - 2)->co);
mul_v3_fl((key - 1)->vel, 0.5);
}
if (use_length_check && k > 0) {
float dvec[3];
/* check if path needs to be cut before actual end of data points */
if (!check_path_length(k, keys, key, max_length, step_length, &cur_length, dvec)) {
/* last key */
sub_v3_v3v3(key->vel, key->co, (key - 1)->co);
if (ma && draw_col_ma) {
copy_v3_v3(key->col, &ma->r);
}
break;
}
}
if (k == totkeys - 1) {
/* last key */
sub_v3_v3v3(key->vel, key->co, (key - 1)->co);
}
if (ma && draw_col_ma) {
copy_v3_v3(key->col, &ma->r);
}
}
}
}
/* ------------------------------------------------------------------------- */
void do_kink(ParticleKey *state,
const float par_co[3],
const float par_vel[3],
const float par_rot[4],
float time,
float freq,
float shape,
float amplitude,
float flat,
short type,
short axis,
float obmat[4][4],
int smooth_start)
{
float kink[3] = {1.0f, 0.0f, 0.0f}, par_vec[3], q1[4] = {1.0f, 0.0f, 0.0f, 0.0f};
float t, dt = 1.0f, result[3];
if (ELEM(type, PART_KINK_NO, PART_KINK_SPIRAL)) {
return;
}
CLAMP(time, 0.0f, 1.0f);
if (shape != 0.0f && !ELEM(type, PART_KINK_BRAID)) {
if (shape < 0.0f) {
time = (float)pow(time, 1.0f + shape);
}
else {
time = (float)pow(time, 1.0f / (1.0f - shape));
}
}
t = time * freq * (float)M_PI;
if (smooth_start) {
dt = fabsf(t);
/* smooth the beginning of kink */
CLAMP(dt, 0.0f, (float)M_PI);
dt = sinf(dt / 2.0f);
}
if (!ELEM(type, PART_KINK_RADIAL)) {
float temp[3];
kink[axis] = 1.0f;
if (obmat) {
mul_mat3_m4_v3(obmat, kink);
}
mul_qt_v3(par_rot, kink);
/* make sure kink is normal to strand */
project_v3_v3v3(temp, kink, par_vel);
sub_v3_v3(kink, temp);
normalize_v3(kink);
}
copy_v3_v3(result, state->co);
sub_v3_v3v3(par_vec, par_co, state->co);
switch (type) {
case PART_KINK_CURL: {
float curl_offset[3];
/* rotate kink vector around strand tangent */
mul_v3_v3fl(curl_offset, kink, amplitude);
axis_angle_to_quat(q1, par_vel, t);
mul_qt_v3(q1, curl_offset);
interp_v3_v3v3(par_vec, state->co, par_co, flat);
add_v3_v3v3(result, par_vec, curl_offset);
break;
}
case PART_KINK_RADIAL: {
if (flat > 0.0f) {
float proj[3];
/* flatten along strand */
project_v3_v3v3(proj, par_vec, par_vel);
madd_v3_v3fl(result, proj, flat);
}
madd_v3_v3fl(result, par_vec, -amplitude * sinf(t));
break;
}
case PART_KINK_WAVE: {
madd_v3_v3fl(result, kink, amplitude * sinf(t));
if (flat > 0.0f) {
float proj[3];
/* flatten along wave */
project_v3_v3v3(proj, par_vec, kink);
madd_v3_v3fl(result, proj, flat);
/* flatten along strand */
project_v3_v3v3(proj, par_vec, par_vel);
madd_v3_v3fl(result, proj, flat);
}
break;
}
case PART_KINK_BRAID: {
float y_vec[3] = {0.0f, 1.0f, 0.0f};
float z_vec[3] = {0.0f, 0.0f, 1.0f};
float vec_one[3], state_co[3];
float inp_y, inp_z, length;
if (par_rot) {
mul_qt_v3(par_rot, y_vec);
mul_qt_v3(par_rot, z_vec);
}
negate_v3(par_vec);
normalize_v3_v3(vec_one, par_vec);
inp_y = dot_v3v3(y_vec, vec_one);
inp_z = dot_v3v3(z_vec, vec_one);
if (inp_y > 0.5f) {
copy_v3_v3(state_co, y_vec);
mul_v3_fl(y_vec, amplitude * cosf(t));
mul_v3_fl(z_vec, amplitude / 2.0f * sinf(2.0f * t));
}
else if (inp_z > 0.0f) {
mul_v3_v3fl(state_co, z_vec, sinf((float)M_PI / 3.0f));
madd_v3_v3fl(state_co, y_vec, -0.5f);
mul_v3_fl(y_vec, -amplitude * cosf(t + (float)M_PI / 3.0f));
mul_v3_fl(z_vec, amplitude / 2.0f * cosf(2.0f * t + (float)M_PI / 6.0f));
}
else {
mul_v3_v3fl(state_co, z_vec, -sinf((float)M_PI / 3.0f));
madd_v3_v3fl(state_co, y_vec, -0.5f);
mul_v3_fl(y_vec, amplitude * -sinf(t + (float)M_PI / 6.0f));
mul_v3_fl(z_vec, amplitude / 2.0f * -sinf(2.0f * t + (float)M_PI / 3.0f));
}
mul_v3_fl(state_co, amplitude);
add_v3_v3(state_co, par_co);
sub_v3_v3v3(par_vec, state->co, state_co);
length = normalize_v3(par_vec);
mul_v3_fl(par_vec, MIN2(length, amplitude / 2.0f));
add_v3_v3v3(state_co, par_co, y_vec);
add_v3_v3(state_co, z_vec);
add_v3_v3(state_co, par_vec);
shape = 2.0f * (float)M_PI * (1.0f + shape);
if (t < shape) {
shape = t / shape;
shape = (float)sqrt((double)shape);
interp_v3_v3v3(result, result, state_co, shape);
}
else {
copy_v3_v3(result, state_co);
}
break;
}
}
/* blend the start of the kink */
if (dt < 1.0f) {
interp_v3_v3v3(state->co, state->co, result, dt);
}
else {
copy_v3_v3(state->co, result);
}
}
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.0f;
if (clumpcurve) {
clump = pa_clump *
(1.0f - clamp_f(BKE_curvemapping_evaluateF(clumpcurve, 0, time), 0.0f, 1.0f));
interp_v3_v3v3(result, co, par_co, clump);
}
else if (clumpfac != 0.0f) {
float cpow;
if (clumppow < 0.0f) {
cpow = 1.0f + clumppow;
}
else {
cpow = 1.0f + 9.0f * clumppow;
}
if (clumpfac < 0.0f) { /* clump roots instead of tips */
clump = -clumpfac * pa_clump * (float)pow(1.0 - (double)time, (double)cpow);
}
else {
clump = clumpfac * pa_clump * (float)pow((double)time, (double)cpow);
}
interp_v3_v3v3(result, co, par_co, clump);
}
return clump;
}
float do_clump(ParticleKey *state,
const float par_co[3],
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 (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);
BLI_noise_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;
}
static void do_rough(const float loc[3],
const float mat[4][4],
float t,
float fac,
float size,
float thres,
ParticleKey *state)
{
float rough[3];
float rco[3];
if (thres != 0.0f) {
if (fabsf((float)(-1.5f + loc[0] + loc[1] + loc[2])) < 1.5f * thres) {
return;
}
}
copy_v3_v3(rco, loc);
mul_v3_fl(rco, t);
rough[0] = -1.0f + 2.0f * BLI_noise_generic_turbulence(size, rco[0], rco[1], rco[2], 2, 0, 2);
rough[1] = -1.0f + 2.0f * BLI_noise_generic_turbulence(size, rco[1], rco[2], rco[0], 2, 0, 2);
rough[2] = -1.0f + 2.0f * BLI_noise_generic_turbulence(size, rco[2], rco[0], rco[1], 2, 0, 2);
madd_v3_v3fl(state->co, mat[0], fac * rough[0]);
madd_v3_v3fl(state->co, mat[1], fac * rough[1]);
madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
}
static void do_rough_end(
const float loc[3], const float mat[4][4], float t, float fac, float shape, ParticleKey *state)
{
float rough[2];
float roughfac;
roughfac = fac * (float)pow((double)t, shape);
copy_v2_v2(rough, loc);
rough[0] = -1.0f + 2.0f * rough[0];
rough[1] = -1.0f + 2.0f * rough[1];
mul_v2_fl(rough, roughfac);
madd_v3_v3fl(state->co, mat[0], rough[0]);
madd_v3_v3fl(state->co, mat[1], rough[1]);
}
static void do_rough_curve(const float loc[3],
const float mat[4][4],
float time,
float fac,
float size,
CurveMapping *roughcurve,
ParticleKey *state)
{
float rough[3];
float rco[3];
if (!roughcurve) {
return;
}
fac *= clamp_f(BKE_curvemapping_evaluateF(roughcurve, 0, time), 0.0f, 1.0f);
copy_v3_v3(rco, loc);
mul_v3_fl(rco, time);
rough[0] = -1.0f + 2.0f * BLI_noise_generic_turbulence(size, rco[0], rco[1], rco[2], 2, 0, 2);
rough[1] = -1.0f + 2.0f * BLI_noise_generic_turbulence(size, rco[1], rco[2], rco[0], 2, 0, 2);
rough[2] = -1.0f + 2.0f * BLI_noise_generic_turbulence(size, rco[2], rco[0], rco[1], 2, 0, 2);
madd_v3_v3fl(state->co, mat[0], fac * rough[0]);
madd_v3_v3fl(state->co, mat[1], fac * rough[1]);
madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
}
static int twist_num_segments(const ParticleChildModifierContext *modifier_ctx)
{
ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx;
return (thread_ctx != NULL) ? thread_ctx->segments : modifier_ctx->sim->psys->part->draw_step;
}
static void twist_get_axis(const ParticleChildModifierContext *modifier_ctx,
const float time,
float r_axis[3])
{
const int num_segments = twist_num_segments(modifier_ctx);
const int index = clamp_i(time * num_segments, 0, num_segments);
if (index > 0) {
sub_v3_v3v3(
r_axis, modifier_ctx->parent_keys[index].co, modifier_ctx->parent_keys[index - 1].co);
}
else {
sub_v3_v3v3(
r_axis, modifier_ctx->parent_keys[index + 1].co, modifier_ctx->parent_keys[index].co);
}
}
static float BKE_curvemapping_integrate_clamped(CurveMapping *curve,
float start,
float end,
float step)
{
float integral = 0.0f;
float x = start;
while (x < end) {
float y = BKE_curvemapping_evaluateF(curve, 0, x);
y = clamp_f(y, 0.0f, 1.0f);
/* TODO(sergey): Clamp last step to end. */
integral += y * step;
x += step;
}
return integral;
}
static void do_twist(const ParticleChildModifierContext *modifier_ctx,
ParticleKey *state,
const float time)
{
ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx;
ParticleSimulationData *sim = modifier_ctx->sim;
ParticleTexture *ptex = modifier_ctx->ptex;
ParticleSettings *part = sim->psys->part;
/* Early output checks. */
if (modifier_ctx->parent_keys == NULL) {
/* Cannot get axis of rotation... */
return;
}
if (part->childtype != PART_CHILD_PARTICLES) {
/* Interpolated children behave weird with twist. */
return;
}
if (part->twist == 0.0f) {
/* No twist along the strand. */
return;
}
/* Dependent on whether it's threaded update or not, curve comes
* from different places.
*/
CurveMapping *twist_curve = NULL;
if (part->child_flag & PART_CHILD_USE_TWIST_CURVE) {
twist_curve = (thread_ctx != NULL) ? thread_ctx->twistcurve : part->twistcurve;
}
/* Axis of rotation. */
float axis[3];
twist_get_axis(modifier_ctx, time, axis);
/* Angle of rotation. */
float angle = part->twist;
if (ptex != NULL) {
angle *= (ptex->twist - 0.5f) * 2.0f;
}
if (twist_curve != NULL) {
const int num_segments = twist_num_segments(modifier_ctx);
angle *= BKE_curvemapping_integrate_clamped(twist_curve, 0.0f, time, 1.0f / num_segments);
}
else {
angle *= time;
}
/* Perform rotation around parent curve. */
float vec[3];
sub_v3_v3v3(vec, state->co, modifier_ctx->par_co);
rotate_v3_v3v3fl(state->co, vec, axis, angle * 2.0f * M_PI);
add_v3_v3(state->co, modifier_ctx->par_co);
}
void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx,
float mat[4][4],
ParticleKey *state,
float t)
{
ParticleThreadContext *ctx = modifier_ctx->thread_ctx;
ParticleSimulationData *sim = modifier_ctx->sim;
ParticleTexture *ptex = modifier_ctx->ptex;
ChildParticle *cpa = modifier_ctx->cpa;
ParticleSettings *part = sim->psys->part;
CurveMapping *clumpcurve = NULL, *roughcurve = NULL;
int i = cpa - sim->psys->child;
int guided = 0;
if (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) {
clumpcurve = (ctx != NULL) ? ctx->clumpcurve : part->clumpcurve;
}
if (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) {
roughcurve = (ctx != NULL) ? ctx->roughcurve : part->roughcurve;
}
float kink_amp = part->kink_amp;
float kink_amp_clump = part->kink_amp_clump;
float kink_freq = part->kink_freq;
float rough1 = part->rough1;
float rough2 = part->rough2;
float rough_end = part->rough_end;
const bool smooth_start = (sim->psys->part->childtype == PART_CHILD_FACES);
if (ptex) {
kink_amp *= ptex->kink_amp;
kink_freq *= ptex->kink_freq;
rough1 *= ptex->rough1;
rough2 *= ptex->rough2;
rough_end *= ptex->roughe;
}
do_twist(modifier_ctx, state, t);
if (part->flag & PART_CHILD_EFFECT) {
/* state is safe to cast, since only co and vel are used */
guided = do_guides(sim->depsgraph,
sim->psys->part,
sim->psys->effectors,
(ParticleKey *)state,
cpa->parent,
t);
}
if (guided == 0) {
float orco_offset[3];
float clump;
sub_v3_v3v3(orco_offset, modifier_ctx->orco, modifier_ctx->par_orco);
clump = do_clump(state,
modifier_ctx->par_co,
t,
orco_offset,
part->clumpfac,
part->clumppow,
ptex ? ptex->clump : 1.0f,
part->child_flag & PART_CHILD_USE_CLUMP_NOISE,
part->clump_noise_size,
clumpcurve);
if (kink_freq != 0.0f) {
kink_amp *= (1.0f - kink_amp_clump * clump);
do_kink(state,
modifier_ctx->par_co,
modifier_ctx->par_vel,
modifier_ctx->par_rot,
t,
kink_freq,
part->kink_shape,
kink_amp,
part->kink_flat,
part->kink,
part->kink_axis,
sim->ob->obmat,
smooth_start);
}
}
if (roughcurve) {
do_rough_curve(modifier_ctx->orco, mat, t, rough1, part->rough1_size, roughcurve, state);
}
else {
if (rough1 > 0.0f) {
do_rough(modifier_ctx->orco, mat, t, rough1, part->rough1_size, 0.0, state);
}
if (rough2 > 0.0f) {
float vec[3];
psys_frand_vec(sim->psys, i + 27, vec);
do_rough(vec, mat, t, rough2, part->rough2_size, part->rough2_thres, state);
}
if (rough_end > 0.0f) {
float vec[3];
psys_frand_vec(sim->psys, i + 27, vec);
do_rough_end(vec, mat, t, rough_end, part->rough_end_shape, state);
}
}
}