Multi-thread displace modifier

The title says it all actually. Use BLI task to loop over vertices
and distort their locations. Gives 2x FPS increase in a file with
just time-dependent displace modifier on my desktop.
This commit is contained in:
2017-02-06 14:21:29 +01:00
parent 89f3837d68
commit d0015cba02

View File

@@ -38,6 +38,7 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_task.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
@@ -201,23 +202,131 @@ static void updateDepsgraph(ModifierData *md,
}
}
typedef struct DisplaceUserdata {
/*const*/ DisplaceModifierData *dmd;
struct ImagePool *pool;
MDeformVert *dvert;
float weight;
int defgrp_index;
int direction;
bool use_global_direction;
float (*tex_co)[3];
float (*vertexCos)[3];
float local_mat[4][4];
MVert *mvert;
float (*vert_clnors)[3];
} DisplaceUserdata;
static void displaceModifier_do_task(void *userdata, const int iter)
{
DisplaceUserdata *data = (DisplaceUserdata *)userdata;
DisplaceModifierData *dmd = data->dmd;
MDeformVert *dvert = data->dvert;
float weight = data->weight;
int defgrp_index = data->defgrp_index;
int direction = data->direction;
bool use_global_direction = data->use_global_direction;
float (*tex_co)[3] = data->tex_co;
float (*vertexCos)[3] = data->vertexCos;
MVert *mvert = data->mvert;
float (*vert_clnors)[3] = data->vert_clnors;
const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */
TexResult texres;
float strength = dmd->strength;
float delta;
float local_vec[3];
if (dvert) {
weight = defvert_find_weight(dvert + iter, defgrp_index);
if (weight == 0.0f) {
return;
}
}
if (dmd->texture) {
texres.nor = NULL;
BKE_texture_get_value_ex(dmd->modifier.scene, dmd->texture, tex_co[iter], &texres, data->pool, false);
delta = texres.tin - dmd->midlevel;
}
else {
delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */
}
if (dvert) {
strength *= weight;
}
delta *= strength;
CLAMP(delta, -10000, 10000);
switch (direction) {
case MOD_DISP_DIR_X:
if (use_global_direction) {
vertexCos[iter][0] += delta * data->local_mat[0][0];
vertexCos[iter][1] += delta * data->local_mat[1][0];
vertexCos[iter][2] += delta * data->local_mat[2][0];
}
else {
vertexCos[iter][0] += delta;
}
break;
case MOD_DISP_DIR_Y:
if (use_global_direction) {
vertexCos[iter][0] += delta * data->local_mat[0][1];
vertexCos[iter][1] += delta * data->local_mat[1][1];
vertexCos[iter][2] += delta * data->local_mat[2][1];
}
else {
vertexCos[iter][1] += delta;
}
break;
case MOD_DISP_DIR_Z:
if (use_global_direction) {
vertexCos[iter][0] += delta * data->local_mat[0][2];
vertexCos[iter][1] += delta * data->local_mat[1][2];
vertexCos[iter][2] += delta * data->local_mat[2][2];
}
else {
vertexCos[iter][2] += delta;
}
break;
case MOD_DISP_DIR_RGB_XYZ:
local_vec[0] = texres.tr - dmd->midlevel;
local_vec[1] = texres.tg - dmd->midlevel;
local_vec[2] = texres.tb - dmd->midlevel;
if (use_global_direction) {
mul_transposed_mat3_m4_v3(data->local_mat, local_vec);
}
mul_v3_fl(local_vec, strength);
add_v3_v3(vertexCos[iter], local_vec);
break;
case MOD_DISP_DIR_NOR:
vertexCos[iter][0] += delta * (mvert[iter].no[0] / 32767.0f);
vertexCos[iter][1] += delta * (mvert[iter].no[1] / 32767.0f);
vertexCos[iter][2] += delta * (mvert[iter].no[2] / 32767.0f);
break;
case MOD_DISP_DIR_CLNOR:
madd_v3_v3fl(vertexCos[iter], vert_clnors[iter], delta);
break;
}
}
/* dm must be a CDDerivedMesh */
static void displaceModifier_do(
DisplaceModifierData *dmd, Object *ob,
DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
int i;
MVert *mvert;
MDeformVert *dvert;
int direction = dmd->direction;
int defgrp_index;
float (*tex_co)[3];
float weight = 1.0f; /* init value unused but some compilers may complain */
const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */
float (*vert_clnors)[3] = NULL;
float local_mat[4][4];
float local_mat[4][4] = {0};
const bool use_global_direction = dmd->space == MOD_DISP_SPACE_GLOBAL;
struct ImagePool *pool = NULL;
if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return;
if (dmd->strength == 0.0f) return;
@@ -261,89 +370,25 @@ static void displaceModifier_do(
copy_m4_m4(local_mat, ob->obmat);
}
DisplaceUserdata data = {NULL};
data.dmd = dmd;
data.dvert = dvert;
data.weight = weight;
data.defgrp_index = defgrp_index;
data.direction = direction;
data.use_global_direction = use_global_direction;
data.tex_co = tex_co;
data.vertexCos = vertexCos;
copy_m4_m4(data.local_mat, local_mat);
data.mvert = mvert;
data.vert_clnors = vert_clnors;
if (dmd->texture != NULL) {
pool = BKE_image_pool_new();
data.pool = BKE_image_pool_new();
}
BLI_task_parallel_range(0, numVerts, &data, displaceModifier_do_task, numVerts > 512);
for (i = 0; i < numVerts; i++) {
TexResult texres;
float strength = dmd->strength;
float delta;
float local_vec[3];
if (dvert) {
weight = defvert_find_weight(dvert + i, defgrp_index);
if (weight == 0.0f) continue;
}
if (dmd->texture) {
texres.nor = NULL;
BKE_texture_get_value_ex(dmd->modifier.scene, dmd->texture, tex_co[i], &texres, pool, false);
delta = texres.tin - dmd->midlevel;
}
else {
delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */
}
if (dvert) strength *= weight;
delta *= strength;
CLAMP(delta, -10000, 10000);
switch (direction) {
case MOD_DISP_DIR_X:
if (use_global_direction) {
vertexCos[i][0] += delta * local_mat[0][0];
vertexCos[i][1] += delta * local_mat[1][0];
vertexCos[i][2] += delta * local_mat[2][0];
}
else {
vertexCos[i][0] += delta;
}
break;
case MOD_DISP_DIR_Y:
if (use_global_direction) {
vertexCos[i][0] += delta * local_mat[0][1];
vertexCos[i][1] += delta * local_mat[1][1];
vertexCos[i][2] += delta * local_mat[2][1];
}
else {
vertexCos[i][1] += delta;
}
break;
case MOD_DISP_DIR_Z:
if (use_global_direction) {
vertexCos[i][0] += delta * local_mat[0][2];
vertexCos[i][1] += delta * local_mat[1][2];
vertexCos[i][2] += delta * local_mat[2][2];
}
else {
vertexCos[i][2] += delta;
}
break;
case MOD_DISP_DIR_RGB_XYZ:
local_vec[0] = texres.tr - dmd->midlevel;
local_vec[1] = texres.tg - dmd->midlevel;
local_vec[2] = texres.tb - dmd->midlevel;
if (use_global_direction) {
mul_transposed_mat3_m4_v3(local_mat, local_vec);
}
mul_v3_fl(local_vec, strength);
add_v3_v3(vertexCos[i], local_vec);
break;
case MOD_DISP_DIR_NOR:
vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f);
vertexCos[i][1] += delta * (mvert[i].no[1] / 32767.0f);
vertexCos[i][2] += delta * (mvert[i].no[2] / 32767.0f);
break;
case MOD_DISP_DIR_CLNOR:
madd_v3_v3fl(vertexCos[i], vert_clnors[i], delta);
break;
}
}
if (pool != NULL) {
BKE_image_pool_free(pool);
if (data.pool != NULL) {
BKE_image_pool_free(data.pool);
}
if (tex_co) {