From 0bf8096501a8e7883f4061ba3e425966ba7517cd Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 7 Jul 2018 23:21:20 +0300 Subject: Resolve the opposite vector ambiguity in Damped Track constraint. Damped Track by specification attempts to arrive at the desired direction via the shortest rotation. However with opposite vectors there are infinitely many valid 180 degree rotations. Currently it gives up and does nothing. I think that it would be more reasonable to resolve the ambiguity arbitrarily, so that Damped Track won't have a weird dead zone. To make it more predictable I use a local axis. In addition, the singularity area vicinity has some floating point precision problems that result in significant jitter. This applies workarounds for two causes of instability. Differential Revision: https://developer.blender.org/D3530 --- source/blender/blenkernel/intern/constraint.c | 32 ++++++++++++++++++++-- source/blender/blenlib/BLI_math_vector.h | 1 + source/blender/blenlib/intern/math_vector_inline.c | 10 +++++++ 3 files changed, 41 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 2a5a0cf9ae7..7d861658993 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -3709,7 +3709,7 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t * - the min/max wrappers around (obvec . tarvec) result (stored temporarily in rangle) * are used to ensure that the smallest angle is chosen */ - cross_v3_v3v3(raxis, obvec, tarvec); + cross_v3_v3v3_hi_prec(raxis, obvec, tarvec); rangle = dot_v3v3(obvec, tarvec); rangle = acosf(max_ff(-1.0f, min_ff(1.0f, rangle))); @@ -3717,7 +3717,35 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t /* construct rotation matrix from the axis-angle rotation found above * - this call takes care to make sure that the axis provided is a unit vector first */ - axis_angle_to_mat3(rmat, raxis, rangle); + float norm = normalize_v3(raxis); + + if (norm < FLT_EPSILON) { + /* if dot product is nonzero, while cross is zero, we have two opposite vectors! + * - this is an ambiguity in the math that needs to be resolved arbitrarily, + * or there will be a case where damped track strangely does nothing + * - to do that, rotate around a different local axis + */ + float tmpvec[3]; + + if (fabsf(rangle) < M_PI - 0.01f) { + return; + } + + rangle = M_PI; + copy_v3_v3(tmpvec, track_dir_vecs[(data->trackflag + 1) % 6]); + mul_mat3_m4_v3(cob->matrix, tmpvec); + cross_v3_v3v3(raxis, obvec, tmpvec); + + if (normalize_v3(raxis) == 0.0f) { + return; + } + } + else if (norm < 0.1f) { + /* near 0 and Pi arcsin has way better precision than arccos */ + rangle = (rangle > M_PI_2) ? M_PI - asinf(norm) : asinf(norm); + } + + axis_angle_normalized_to_mat3(rmat, raxis, rangle); /* rotate the owner in the way defined by this rotation matrix, then reapply the location since * we may have destroyed that in the process of multiplying the matrix diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 3f603311530..39625346756 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -169,6 +169,7 @@ MINLINE double dot_v3db_v3fl(const double a[3], const float b[3]) ATTR_WARN_UNUS MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]); +MINLINE void cross_v3_v3v3_hi_prec(float r[3], const float a[3], const float b[3]); MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3]); diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index 08687a1ab47..715e2e65c96 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -753,6 +753,16 @@ MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]) r[2] = a[0] * b[1] - a[1] * b[0]; } +/* cross product suffers from severe precision loss when vectors are + * nearly parallel or opposite; doing the computation in double helps a lot */ +MINLINE void cross_v3_v3v3_hi_prec(float r[3], const float a[3], const float b[3]) +{ + BLI_assert(r != a && r != b); + r[0] = (float)((double)a[1] * (double)b[2] - (double)a[2] * (double)b[1]); + r[1] = (float)((double)a[2] * (double)b[0] - (double)a[0] * (double)b[2]); + r[2] = (float)((double)a[0] * (double)b[1] - (double)a[1] * (double)b[0]); +} + /* Newell's Method */ /* excuse this fairly specific function, * its used for polygon normals all over the place -- cgit v1.2.3 From f48e81e720c1e5fcc93ba6da11f862263da9cadc Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 20 Jul 2018 12:01:38 +0200 Subject: Fix T55414: waveforms are reprocessed when undoing Add new tag to bSound (runtime flags), and make read code to set a 'no reload waveform' new tag, since it uses a mapping to get existing waveform in undo case... --- source/blender/blenkernel/intern/sound.c | 18 +++++++++++------- source/blender/blenloader/intern/readfile.c | 2 ++ source/blender/makesdna/DNA_sound_types.h | 10 +++++++++- 3 files changed, 22 insertions(+), 8 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 6aa44cde0e0..709a0022767 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -757,15 +757,19 @@ int BKE_sound_scene_playing(struct Scene *scene) void BKE_sound_free_waveform(bSound *sound) { - SoundWaveform *waveform = sound->waveform; - if (waveform) { - if (waveform->data) { - MEM_freeN(waveform->data); + if ((sound->tags & SOUND_TAGS_WAVEFORM_NO_RELOAD) == 0) { + SoundWaveform *waveform = sound->waveform; + if (waveform) { + if (waveform->data) { + MEM_freeN(waveform->data); + } + MEM_freeN(waveform); } - MEM_freeN(waveform); - } - sound->waveform = NULL; + sound->waveform = NULL; + } + /* This tag is only valid once. */ + sound->tags &= ~SOUND_TAGS_WAVEFORM_NO_RELOAD; } void BKE_sound_read_waveform(bSound *sound, short *stop) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1def462b1ca..1d772a15efd 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7542,6 +7542,7 @@ static void direct_link_speaker(FileData *fd, Speaker *spk) static void direct_link_sound(FileData *fd, bSound *sound) { + sound->tags = 0; sound->handle = NULL; sound->playback_handle = NULL; @@ -7553,6 +7554,7 @@ static void direct_link_sound(FileData *fd, bSound *sound) if (fd->soundmap) { sound->waveform = newsoundadr(fd, sound->waveform); + sound->tags |= SOUND_TAGS_WAVEFORM_NO_RELOAD; } else { sound->waveform = NULL; diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h index aefe1a7d5a3..7778582b82d 100644 --- a/source/blender/makesdna/DNA_sound_types.h +++ b/source/blender/makesdna/DNA_sound_types.h @@ -65,13 +65,15 @@ typedef struct bSound { */ struct PackedFile *newpackedfile; struct Ipo *ipo; + float volume; float attenuation; float pitch; float min_gain; float max_gain; float distance; - int flags; + short flags; + short tags; /* Runtime only, always reset in readfile. */ int pad; /* unused currently @@ -116,6 +118,7 @@ enum { SND_CFRA_NUM = 2, }; +/* bSound->flags */ enum { #ifdef DNA_DEPRECATED SOUND_FLAGS_3D = (1 << 3), /* deprecated! used for sound actuator loading */ @@ -125,6 +128,11 @@ enum { SOUND_FLAGS_WAVEFORM_LOADING = (1 << 6), }; +/* bSound->tags */ +enum { + SOUND_TAGS_WAVEFORM_NO_RELOAD = 1 << 0, /* Do not free/reset waveform on sound load, only used by undo code. */ +}; + /* to DNA_sound_types.h*/ #endif -- cgit v1.2.3 From 710a05954990c347932b9f540a1b220ea2c5c0da Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 20 Jul 2018 12:11:34 +0200 Subject: Cleanup: Move 'WAVEFORM_LOADING' of sounds from flags to tags. This is purely runtime data, so move it to new tags. ;) --- source/blender/blenkernel/intern/sound.c | 4 ++-- source/blender/blenloader/intern/readfile.c | 2 +- source/blender/editors/space_sequencer/sequencer_draw.c | 4 ++-- source/blender/editors/space_sequencer/sequencer_preview.c | 2 +- source/blender/makesdna/DNA_sound_types.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 709a0022767..d21055ada6a 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -798,7 +798,7 @@ void BKE_sound_read_waveform(bSound *sound, short *stop) } MEM_freeN(waveform); BLI_spin_lock(sound->spinlock); - sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING; + sound->tags &= ~SOUND_TAGS_WAVEFORM_LOADING; BLI_spin_unlock(sound->spinlock); return; } @@ -807,7 +807,7 @@ void BKE_sound_read_waveform(bSound *sound, short *stop) BLI_spin_lock(sound->spinlock); sound->waveform = waveform; - sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING; + sound->tags &= ~SOUND_TAGS_WAVEFORM_LOADING; BLI_spin_unlock(sound->spinlock); } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1d772a15efd..bdfae79a1d0 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7565,7 +7565,7 @@ static void direct_link_sound(FileData *fd, bSound *sound) BLI_spin_init(sound->spinlock); } /* clear waveform loading flag */ - sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING; + sound->tags &= ~SOUND_TAGS_WAVEFORM_LOADING; sound->packedfile = direct_link_packedfile(fd, sound->packedfile); sound->newpackedfile = direct_link_packedfile(fd, sound->newpackedfile); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 97c42cc11e0..915e2466d54 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -220,9 +220,9 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc BLI_spin_lock(sound->spinlock); if (!sound->waveform) { - if (!(sound->flags & SOUND_FLAGS_WAVEFORM_LOADING)) { + if (!(sound->tags & SOUND_TAGS_WAVEFORM_LOADING)) { /* prevent sounds from reloading */ - sound->flags |= SOUND_FLAGS_WAVEFORM_LOADING; + sound->tags |= SOUND_TAGS_WAVEFORM_LOADING; BLI_spin_unlock(sound->spinlock); sequencer_preview_add_sound(C, seq); } diff --git a/source/blender/editors/space_sequencer/sequencer_preview.c b/source/blender/editors/space_sequencer/sequencer_preview.c index c58c05b67c0..ae011e48538 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview.c +++ b/source/blender/editors/space_sequencer/sequencer_preview.c @@ -96,7 +96,7 @@ static void preview_startjob(void *data, short *stop, short *do_update, float *p /* make sure we cleanup the loading flag! */ BLI_spin_lock(sound->spinlock); - sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING; + sound->tags &= ~SOUND_TAGS_WAVEFORM_LOADING; BLI_spin_unlock(sound->spinlock); BLI_mutex_lock(pj->mutex); diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h index 7778582b82d..02d3aa928c7 100644 --- a/source/blender/makesdna/DNA_sound_types.h +++ b/source/blender/makesdna/DNA_sound_types.h @@ -125,12 +125,12 @@ enum { #endif SOUND_FLAGS_CACHING = (1 << 4), SOUND_FLAGS_MONO = (1 << 5), - SOUND_FLAGS_WAVEFORM_LOADING = (1 << 6), }; /* bSound->tags */ enum { SOUND_TAGS_WAVEFORM_NO_RELOAD = 1 << 0, /* Do not free/reset waveform on sound load, only used by undo code. */ + SOUND_TAGS_WAVEFORM_LOADING = (1 << 6), }; /* to DNA_sound_types.h*/ -- cgit v1.2.3