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/lattice_deform.c
Sergey Sharybin f17fbf8065 Refactor: Rename Object->obmat to Object->object_to_world
Motivation is to disambiguate on the naming level what the matrix
actually means. It is very easy to understand the meaning backwards,
especially since in Python the name goes the opposite way (it is
called `world_matrix` in the Python API).

It is important to disambiguate the naming without making developers
to look into the comment in the header file (which is also not super
clear either). Additionally, more clear naming facilitates the unit
verification (or, in this case, space validation) when reading an
expression.

This patch calls the matrix `object_to_world` which makes it clear
from the local code what is it exactly going on. This is only done
on DNA level, and a lot of local variables still follow the old
naming.

A DNA rename is setup in a way that there is no change on the file
level, so there should be no regressions at all.

The possibility is to add `_matrix` or `_mat` suffix to the name
to make it explicit that it is a matrix. Although, not sure if it
really helps the readability, or is it something redundant.

Differential Revision: https://developer.blender.org/D16328
2022-11-01 10:48:18 +01:00

465 lines
15 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
/** \file
* \ingroup bke
*
* Deform coordinates by a lattice object (used by modifier).
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_simd.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "DNA_curve_types.h"
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_deform.h"
/* -------------------------------------------------------------------- */
/** \name Lattice Deform API
* \{ */
typedef struct LatticeDeformData {
/* Convert from object space to deform space */
float latmat[4][4];
/* Cached reference to the lattice to use for evaluation. When in edit mode this attribute
* is set to the edit mode lattice. */
const Lattice *lt;
/* Preprocessed lattice points (converted to deform space). */
float *latticedata;
/* Prefetched DeformWeights of the lattice. */
float *lattice_weights;
} LatticeDeformData;
LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Object *ob)
{
/* we make an array with all differences */
Lattice *lt = BKE_object_get_lattice(oblatt);
BPoint *bp;
DispList *dl = oblatt->runtime.curve_cache ?
BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) :
NULL;
const float *co = dl ? dl->verts : NULL;
float *fp, imat[4][4];
float fu, fv, fw;
int u, v, w;
float *latticedata;
float *lattice_weights = NULL;
float latmat[4][4];
LatticeDeformData *lattice_deform_data;
bp = lt->def;
const int32_t num_points = lt->pntsu * lt->pntsv * lt->pntsw;
/* We allocate one additional float for SSE2 optimizations. Without this
* the SSE2 instructions for the last item would read in unallocated memory. */
fp = latticedata = MEM_mallocN(sizeof(float[3]) * num_points + sizeof(float), "latticedata");
/* for example with a particle system: (ob == NULL) */
if (ob == NULL) {
/* In deform-space, calc matrix. */
invert_m4_m4(latmat, oblatt->object_to_world);
/* back: put in deform array */
invert_m4_m4(imat, latmat);
}
else {
/* In deform-space, calc matrix. */
invert_m4_m4(imat, oblatt->object_to_world);
mul_m4_m4m4(latmat, imat, ob->object_to_world);
/* back: put in deform array. */
invert_m4_m4(imat, latmat);
}
/* Prefetch lattice deform group weights. */
int defgrp_index = -1;
const MDeformVert *dvert = BKE_lattice_deform_verts_get(oblatt);
if (lt->vgroup[0] && dvert) {
defgrp_index = BKE_id_defgroup_name_index(&lt->id, lt->vgroup);
if (defgrp_index != -1) {
lattice_weights = MEM_malloc_arrayN(num_points, sizeof(float), "lattice_weights");
for (int index = 0; index < num_points; index++) {
lattice_weights[index] = BKE_defvert_find_weight(dvert + index, defgrp_index);
}
}
}
for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) {
for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) {
for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) {
if (dl) {
fp[0] = co[0] - fu;
fp[1] = co[1] - fv;
fp[2] = co[2] - fw;
}
else {
fp[0] = bp->vec[0] - fu;
fp[1] = bp->vec[1] - fv;
fp[2] = bp->vec[2] - fw;
}
mul_mat3_m4_v3(imat, fp);
}
}
}
lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data");
lattice_deform_data->latticedata = latticedata;
lattice_deform_data->lattice_weights = lattice_weights;
lattice_deform_data->lt = lt;
copy_m4_m4(lattice_deform_data->latmat, latmat);
return lattice_deform_data;
}
void BKE_lattice_deform_data_eval_co(LatticeDeformData *lattice_deform_data,
float co[3],
float weight)
{
float *latticedata = lattice_deform_data->latticedata;
float *lattice_weights = lattice_deform_data->lattice_weights;
BLI_assert(latticedata);
const Lattice *lt = lattice_deform_data->lt;
float u, v, w, tu[4], tv[4], tw[4];
float vec[3];
int idx_w, idx_v, idx_u;
int ui, vi, wi, uu, vv, ww;
/* vgroup influence */
float co_prev[4] = {0}, weight_blend = 0.0f;
copy_v3_v3(co_prev, co);
#ifdef BLI_HAVE_SSE2
__m128 co_vec = _mm_loadu_ps(co_prev);
#endif
/* co is in local coords, treat with latmat */
mul_v3_m4v3(vec, lattice_deform_data->latmat, co);
/* u v w coords */
if (lt->pntsu > 1) {
u = (vec[0] - lt->fu) / lt->du;
ui = (int)floor(u);
u -= ui;
key_curve_position_weights(u, tu, lt->typeu);
}
else {
tu[0] = tu[2] = tu[3] = 0.0;
tu[1] = 1.0;
ui = 0;
}
if (lt->pntsv > 1) {
v = (vec[1] - lt->fv) / lt->dv;
vi = (int)floor(v);
v -= vi;
key_curve_position_weights(v, tv, lt->typev);
}
else {
tv[0] = tv[2] = tv[3] = 0.0;
tv[1] = 1.0;
vi = 0;
}
if (lt->pntsw > 1) {
w = (vec[2] - lt->fw) / lt->dw;
wi = (int)floor(w);
w -= wi;
key_curve_position_weights(w, tw, lt->typew);
}
else {
tw[0] = tw[2] = tw[3] = 0.0;
tw[1] = 1.0;
wi = 0;
}
const int w_stride = lt->pntsu * lt->pntsv;
const int idx_w_max = (lt->pntsw - 1) * lt->pntsu * lt->pntsv;
const int v_stride = lt->pntsu;
const int idx_v_max = (lt->pntsv - 1) * lt->pntsu;
const int idx_u_max = (lt->pntsu - 1);
for (ww = wi - 1; ww <= wi + 2; ww++) {
w = weight * tw[ww - wi + 1];
idx_w = CLAMPIS(ww * w_stride, 0, idx_w_max);
for (vv = vi - 1; vv <= vi + 2; vv++) {
v = w * tv[vv - vi + 1];
idx_v = CLAMPIS(vv * v_stride, 0, idx_v_max);
for (uu = ui - 1; uu <= ui + 2; uu++) {
u = v * tu[uu - ui + 1];
idx_u = CLAMPIS(uu, 0, idx_u_max);
const int idx = idx_w + idx_v + idx_u;
#ifdef BLI_HAVE_SSE2
{
__m128 weight_vec = _mm_set1_ps(u);
/* We need to address special case for last item to avoid accessing invalid memory. */
__m128 lattice_vec;
if (idx * 3 == idx_w_max) {
copy_v3_v3((float *)&lattice_vec, &latticedata[idx * 3]);
}
else {
/* When not on last item, we can safely access one extra float, it will be ignored
* anyway. */
lattice_vec = _mm_loadu_ps(&latticedata[idx * 3]);
}
co_vec = _mm_add_ps(co_vec, _mm_mul_ps(lattice_vec, weight_vec));
}
#else
madd_v3_v3fl(co, &latticedata[idx * 3], u);
#endif
if (lattice_weights) {
weight_blend += (u * lattice_weights[idx]);
}
}
}
}
#ifdef BLI_HAVE_SSE2
{
copy_v3_v3(co, (float *)&co_vec);
}
#endif
if (lattice_weights) {
interp_v3_v3v3(co, co_prev, co, weight_blend);
}
}
void BKE_lattice_deform_data_destroy(LatticeDeformData *lattice_deform_data)
{
if (lattice_deform_data->latticedata) {
MEM_freeN(lattice_deform_data->latticedata);
}
MEM_freeN(lattice_deform_data);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Lattice Deform #BKE_lattice_deform_coords API
*
* #BKE_lattice_deform_coords and related functions.
* \{ */
typedef struct LatticeDeformUserdata {
LatticeDeformData *lattice_deform_data;
float (*vert_coords)[3];
const MDeformVert *dvert;
int defgrp_index;
float fac;
bool invert_vgroup;
/** Specific data types. */
struct {
int cd_dvert_offset;
} bmesh;
} LatticeDeformUserdata;
static void lattice_deform_vert_with_dvert(const LatticeDeformUserdata *data,
const int index,
const MDeformVert *dvert)
{
if (dvert != NULL) {
const float weight = data->invert_vgroup ?
1.0f - BKE_defvert_find_weight(dvert, data->defgrp_index) :
BKE_defvert_find_weight(dvert, data->defgrp_index);
if (weight > 0.0f) {
BKE_lattice_deform_data_eval_co(
data->lattice_deform_data, data->vert_coords[index], weight * data->fac);
}
}
else {
BKE_lattice_deform_data_eval_co(
data->lattice_deform_data, data->vert_coords[index], data->fac);
}
}
static void lattice_deform_vert_task(void *__restrict userdata,
const int index,
const TaskParallelTLS *__restrict UNUSED(tls))
{
const LatticeDeformUserdata *data = userdata;
lattice_deform_vert_with_dvert(data, index, data->dvert ? &data->dvert[index] : NULL);
}
static void lattice_vert_task_editmesh(void *__restrict userdata,
MempoolIterData *iter,
const TaskParallelTLS *__restrict UNUSED(tls))
{
const LatticeDeformUserdata *data = userdata;
BMVert *v = (BMVert *)iter;
MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(v, data->bmesh.cd_dvert_offset);
lattice_deform_vert_with_dvert(data, BM_elem_index_get(v), dvert);
}
static void lattice_vert_task_editmesh_no_dvert(void *__restrict userdata,
MempoolIterData *iter,
const TaskParallelTLS *__restrict UNUSED(tls))
{
const LatticeDeformUserdata *data = userdata;
BMVert *v = (BMVert *)iter;
lattice_deform_vert_with_dvert(data, BM_elem_index_get(v), NULL);
}
static void lattice_deform_coords_impl(const Object *ob_lattice,
const Object *ob_target,
float (*vert_coords)[3],
const int vert_coords_len,
const short flag,
const char *defgrp_name,
const float fac,
const Mesh *me_target,
BMEditMesh *em_target)
{
LatticeDeformData *lattice_deform_data;
const MDeformVert *dvert = NULL;
int defgrp_index = -1;
int cd_dvert_offset = -1;
if (ob_lattice->type != OB_LATTICE) {
return;
}
lattice_deform_data = BKE_lattice_deform_data_create(ob_lattice, ob_target);
/* Check whether to use vertex groups (only possible if ob_target is a Mesh or Lattice).
* We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
*/
if (defgrp_name && defgrp_name[0] && ob_target && ELEM(ob_target->type, OB_MESH, OB_LATTICE)) {
defgrp_index = BKE_id_defgroup_name_index(me_target ? &me_target->id : (ID *)ob_target->data,
defgrp_name);
if (defgrp_index != -1) {
/* if there's derived data without deformverts, don't use vgroups */
if (em_target) {
cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT);
}
else if (me_target) {
dvert = CustomData_get_layer(&me_target->vdata, CD_MDEFORMVERT);
}
else if (ob_target->type == OB_LATTICE) {
dvert = ((Lattice *)ob_target->data)->dvert;
}
else {
dvert = BKE_mesh_deform_verts((Mesh *)ob_target->data);
}
}
}
LatticeDeformUserdata data = {
.lattice_deform_data = lattice_deform_data,
.vert_coords = vert_coords,
.dvert = dvert,
.defgrp_index = defgrp_index,
.fac = fac,
.invert_vgroup = (flag & MOD_LATTICE_INVERT_VGROUP) != 0,
.bmesh =
{
.cd_dvert_offset = cd_dvert_offset,
},
};
if (em_target != NULL) {
/* While this could cause an extra loop over mesh data, in most cases this will
* have already been properly set. */
BM_mesh_elem_index_ensure(em_target->bm, BM_VERT);
TaskParallelSettings settings;
BLI_parallel_mempool_settings_defaults(&settings);
if (cd_dvert_offset != -1) {
BLI_task_parallel_mempool(
em_target->bm->vpool, &data, lattice_vert_task_editmesh, &settings);
}
else {
BLI_task_parallel_mempool(
em_target->bm->vpool, &data, lattice_vert_task_editmesh_no_dvert, &settings);
}
}
else {
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.min_iter_per_thread = 32;
BLI_task_parallel_range(0, vert_coords_len, &data, lattice_deform_vert_task, &settings);
}
BKE_lattice_deform_data_destroy(lattice_deform_data);
}
void BKE_lattice_deform_coords(const Object *ob_lattice,
const Object *ob_target,
float (*vert_coords)[3],
const int vert_coords_len,
const short flag,
const char *defgrp_name,
float fac)
{
lattice_deform_coords_impl(
ob_lattice, ob_target, vert_coords, vert_coords_len, flag, defgrp_name, fac, NULL, NULL);
}
void BKE_lattice_deform_coords_with_mesh(const Object *ob_lattice,
const Object *ob_target,
float (*vert_coords)[3],
const int vert_coords_len,
const short flag,
const char *defgrp_name,
const float fac,
const Mesh *me_target)
{
lattice_deform_coords_impl(ob_lattice,
ob_target,
vert_coords,
vert_coords_len,
flag,
defgrp_name,
fac,
me_target,
NULL);
}
void BKE_lattice_deform_coords_with_editmesh(const struct Object *ob_lattice,
const struct Object *ob_target,
float (*vert_coords)[3],
const int vert_coords_len,
const short flag,
const char *defgrp_name,
const float fac,
struct BMEditMesh *em_target)
{
lattice_deform_coords_impl(ob_lattice,
ob_target,
vert_coords,
vert_coords_len,
flag,
defgrp_name,
fac,
NULL,
em_target);
}
/** \} */