Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/particle_distribute.c')
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c43
1 files changed, 26 insertions, 17 deletions
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index f6bddfa6f99..c814713f3f4 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -392,22 +392,25 @@ static int distribute_binary_search(float *sum, int n, float value)
{
int mid, low = 0, high = n - 1;
+ if (high == low)
+ return low;
+
if (sum[low] >= value)
return low;
- if (sum[high] < value)
+ if (sum[high - 1] < value)
return high;
while (low < high) {
mid = (low + high) / 2;
- if ((sum[mid] < value) && (sum[mid + 1] >= value))
+ if ((sum[mid] >= value) && (sum[mid - 1] < value))
return mid;
- if (sum[mid] >= value) {
+ if (sum[mid] > value) {
high = mid - 1;
}
- else if (sum[mid] < value) {
+ else {
low = mid + 1;
}
}
@@ -1004,56 +1007,62 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
MEM_freeN(vweight);
}
+#define MIN_WEIGHT 1e-7f /* Weights too small cause issues e.g. with binary search... */
+
/* Calculate total weight of all elements */
int totmapped = 0;
totweight = 0.0f;
for (i = 0; i < totelem; i++) {
- if (element_weight[i] != 0.0f) {
+ if (element_weight[i] > MIN_WEIGHT) {
totmapped++;
+ totweight += element_weight[i];
}
- totweight += element_weight[i];
}
- if (totweight == 0.0f) {
+ if (totmapped == 0) {
/* We are not allowed to distribute particles anywhere... */
return 0;
}
- inv_totweight = (totweight > 0.f ? 1.f/totweight : 0.f);
+ inv_totweight = 1.0f / totweight;
/* Calculate cumulative weights.
* We remove all null-weighted elements from element_sum, and create a new mapping
* 'activ'_elem_index -> orig_elem_index.
- * This simplifies greatly the filtering of zero-weighted items - and can be much mor efficient
+ * This simplifies greatly the filtering of zero-weighted items - and can be much more efficient
* especially in random case (reducing a lot the size of binary-searched array)...
*/
float *element_sum = MEM_mallocN(sizeof(*element_sum) * totmapped, __func__);
int *element_map = MEM_mallocN(sizeof(*element_map) * totmapped, __func__);
int i_mapped = 0;
- for (i = 0; i < totelem && element_weight[i] == 0.0f; i++);
+ for (i = 0; i < totelem && element_weight[i] <= MIN_WEIGHT; i++);
element_sum[i_mapped] = element_weight[i] * inv_totweight;
element_map[i_mapped] = i;
i_mapped++;
for (i++; i < totelem; i++) {
- if (element_weight[i] != 0.0f) {
+ if (element_weight[i] > MIN_WEIGHT) {
element_sum[i_mapped] = element_sum[i_mapped - 1] + element_weight[i] * inv_totweight;
+ BLI_assert(element_sum[i_mapped] > element_sum[i_mapped - 1]);
element_map[i_mapped] = i;
i_mapped++;
}
}
BLI_assert(i_mapped == totmapped);
-
+
+#undef MIN_WEIGHT
+
/* Finally assign elements to particles */
if ((part->flag & PART_TRAND) || (part->simplify_flag & PART_SIMPLIFY_ENABLE)) {
- float pos;
-
for (p = 0; p < totpart; p++) {
- /* In theory element_sum[totelem - 1] should be 1.0,
+ /* In theory element_sum[totmapped - 1] should be 1.0,
* but due to float errors this is not necessarily always true, so scale pos accordingly. */
- pos = BLI_frand() * element_sum[totmapped - 1];
- particle_element[p] = element_map[distribute_binary_search(element_sum, totmapped, pos)];
+ const float pos = BLI_frand() * element_sum[totmapped - 1];
+ const int eidx = distribute_binary_search(element_sum, totmapped, pos);
+ particle_element[p] = element_map[eidx];
+ BLI_assert(pos <= element_sum[eidx]);
+ BLI_assert(eidx ? (pos > element_sum[eidx - 1]) : (pos >= 0.0f));
jitter_offset[particle_element[p]] = pos;
}
}