Metaball: Evaluate metaball objects as mesh components

With the ultimate goal of simplifying drawing and evaluation,
this patch makes the following changes and removes code:
- Use `Mesh` instead of `DispList` for evaluated basis metaballs.
- Remove all `DispList` drawing code, which is now unused.
- Simplify code that converts evaluated metaballs to meshes.
- Store the evaluated mesh in the evaluated geometry set.

This has the following indirect benefits:
- Evaluated meshes from metaball objects can be used in geometry nodes.
- Renderers can ignore evaluated metaball objects completely
- Cycles rendering no longer has to convert to mesh from `DispList`.
- We get closer to removing `DispList` completely.
- Optimizations to mesh rendering will also apply to metaball objects.

The vertex normals on the evaluated mesh are technically invalid;
the regular calculation wouldn't reproduce them. Metaball objects
don't support modifiers though, so it shouldn't be a problem.
Eventually we can support per-vertex custom normals (T93551).

Differential Revision: https://developer.blender.org/D14593
This commit is contained in:
Hans Goudey 2022-08-17 10:20:25 -04:00
parent 71f091a631
commit eaa87101cd
Notes: blender-bot 2023-03-15 17:14:57 +01:00
Referenced by issue #103021, Regression: Metaballs have jagged normals in 3.4
Referenced by issue #100639, Metaball particles are handled inconsistently in Geometry Nodes
Referenced by issue #105593, Metaballs render mistake in 3.4.1
Referenced by pull request #105799, Fix #103021: Metaballs have jagged normals
Referenced by commit c6878d5e82, Fix #103021: Metaballs have jagged normals
35 changed files with 210 additions and 1193 deletions

View File

@ -66,12 +66,6 @@ bool BlenderSync::object_is_geometry(BObjectInfo &b_ob_info)
return true;
}
/* Other object types that are not meshes but evaluate to meshes are presented to render engines
* as separate instance objects. Metaballs have not been affected by that change yet. */
if (type == BL::Object::type_META) {
return true;
}
return b_ob_data.is_a(&RNA_Mesh);
}

View File

@ -24,8 +24,6 @@ enum {
DL_SURF = 2,
/** Triangles. */
DL_INDEX3 = 4,
/** Quads, with support for triangles (when values of the 3rd and 4th indices match). */
DL_INDEX4 = 5,
// DL_VERTCOL = 6, /* UNUSED */
/** Isolated points. */
DL_VERTS = 7,
@ -62,15 +60,12 @@ typedef struct DispList {
} DispList;
DispList *BKE_displist_find(struct ListBase *lb, int type);
void BKE_displist_normals_add(struct ListBase *lb);
void BKE_displist_count(const struct ListBase *lb, int *totvert, int *totface, int *tottri);
void BKE_displist_free(struct ListBase *lb);
void BKE_displist_make_curveTypes(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *ob,
bool for_render);
void BKE_displist_make_mball(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph,
const struct Scene *scene,

View File

@ -27,7 +27,6 @@ void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *
struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name);
void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du);
bool object_deform_mball(struct Object *ob, struct ListBase *dispbase);
void outside_lattice(struct Lattice *lt);
float (*BKE_lattice_vert_coords_alloc(const struct Lattice *lt, int *r_vert_len))[3];

View File

@ -54,14 +54,6 @@ bool BKE_mball_is_basis(const struct Object *ob);
*/
struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob);
/**
* Compute bounding box of all meta-elements / meta-ball.
*
* Bounding box is computed from polygonized surface. \a ob is
* basic meta-balls (with name `Meta` for example). All other meta-ball objects
* (with names `Meta.001`, `Meta.002`, etc) are included in this bounding-box.
*/
void BKE_mball_texspace_calc(struct Object *ob);
/**
* Return or compute bounding-box for given meta-ball object.
*/
@ -110,18 +102,7 @@ bool BKE_mball_select_swap_multi_ex(struct Base **bases, int bases_len);
/* **** Depsgraph evaluation **** */
struct Depsgraph;
/* Draw Cache */
enum {
BKE_MBALL_BATCH_DIRTY_ALL = 0,
};
void BKE_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode);
void BKE_mball_batch_cache_free(struct MetaBall *mb);
extern void (*BKE_mball_batch_cache_dirty_tag_cb)(struct MetaBall *mb, int mode);
extern void (*BKE_mball_batch_cache_free_cb)(struct MetaBall *mb);
void BKE_mball_data_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
#ifdef __cplusplus
}

View File

@ -12,11 +12,11 @@ extern "C" {
struct Depsgraph;
struct Object;
struct Scene;
struct Mesh;
void BKE_mball_polygonize(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct ListBase *dispbase);
struct Mesh *BKE_mball_polygonize(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
void BKE_mball_cubeTable_free(void);

View File

@ -193,7 +193,6 @@ void BKE_mesh_orco_ensure(struct Object *ob, struct Mesh *mesh);
struct Mesh *BKE_mesh_from_object(struct Object *ob);
void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me);
void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me);
void BKE_mesh_to_curve_nurblist(const struct Mesh *me,
struct ListBase *nurblist,
int edge_users_test);

View File

@ -34,10 +34,8 @@
#include "BKE_displist.h"
#include "BKE_geometry_set.hh"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_lib_id.h"
#include "BKE_mball.h"
#include "BKE_mball_tessellate.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@ -86,120 +84,6 @@ DispList *BKE_displist_find(ListBase *lb, int type)
return nullptr;
}
void BKE_displist_normals_add(ListBase *lb)
{
float *vdata, *ndata, nor[3];
float *v1, *v2, *v3, *v4;
float *n1, *n2, *n3, *n4;
int a, b, p1, p2, p3, p4;
LISTBASE_FOREACH (DispList *, dl, lb) {
if (dl->type == DL_INDEX3) {
if (dl->nors == nullptr) {
dl->nors = (float *)MEM_callocN(sizeof(float[3]), __func__);
if (dl->flag & DL_BACK_CURVE) {
dl->nors[2] = -1.0f;
}
else {
dl->nors[2] = 1.0f;
}
}
}
else if (dl->type == DL_SURF) {
if (dl->nors == nullptr) {
dl->nors = (float *)MEM_callocN(sizeof(float[3]) * dl->nr * dl->parts, __func__);
vdata = dl->verts;
ndata = dl->nors;
for (a = 0; a < dl->parts; a++) {
if (BKE_displist_surfindex_get(dl, a, &b, &p1, &p2, &p3, &p4) == 0) {
break;
}
v1 = vdata + 3 * p1;
n1 = ndata + 3 * p1;
v2 = vdata + 3 * p2;
n2 = ndata + 3 * p2;
v3 = vdata + 3 * p3;
n3 = ndata + 3 * p3;
v4 = vdata + 3 * p4;
n4 = ndata + 3 * p4;
for (; b < dl->nr; b++) {
normal_quad_v3(nor, v1, v3, v4, v2);
add_v3_v3(n1, nor);
add_v3_v3(n2, nor);
add_v3_v3(n3, nor);
add_v3_v3(n4, nor);
v2 = v1;
v1 += 3;
v4 = v3;
v3 += 3;
n2 = n1;
n1 += 3;
n4 = n3;
n3 += 3;
}
}
a = dl->parts * dl->nr;
v1 = ndata;
while (a--) {
normalize_v3(v1);
v1 += 3;
}
}
}
}
}
void BKE_displist_count(const ListBase *lb, int *totvert, int *totface, int *tottri)
{
LISTBASE_FOREACH (const DispList *, dl, lb) {
int vert_tot = 0;
int face_tot = 0;
int tri_tot = 0;
bool cyclic_u = dl->flag & DL_CYCL_U;
bool cyclic_v = dl->flag & DL_CYCL_V;
switch (dl->type) {
case DL_SURF: {
int segments_u = dl->nr - (cyclic_u == false);
int segments_v = dl->parts - (cyclic_v == false);
vert_tot = dl->nr * dl->parts;
face_tot = segments_u * segments_v;
tri_tot = face_tot * 2;
break;
}
case DL_INDEX3: {
vert_tot = dl->nr;
face_tot = dl->parts;
tri_tot = face_tot;
break;
}
case DL_INDEX4: {
vert_tot = dl->nr;
face_tot = dl->parts;
tri_tot = face_tot * 2;
break;
}
case DL_POLY:
case DL_SEGM: {
vert_tot = dl->nr * dl->parts;
break;
}
}
*totvert += vert_tot;
*totface += face_tot;
*tottri += tri_tot;
}
}
bool BKE_displist_surfindex_get(
const DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4)
{
@ -625,27 +509,6 @@ float BKE_displist_calc_taper(
return displist_calc_taper(depsgraph, scene, taperobj, fac);
}
void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
if (!ob || ob->type != OB_MBALL) {
return;
}
if (ob == BKE_mball_basis_find(scene, ob)) {
if (ob->runtime.curve_cache) {
BKE_displist_free(&(ob->runtime.curve_cache->disp));
}
else {
ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__);
}
BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp);
BKE_mball_texspace_calc(ob);
object_deform_mball(ob, &ob->runtime.curve_cache->disp);
}
}
static ModifierData *curve_get_tessellate_point(const Scene *scene,
const Object *ob,
const bool for_render,
@ -1504,7 +1367,7 @@ void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
bool doit = false;
LISTBASE_FOREACH (const DispList *, dl, dispbase) {
const int tot = (ELEM(dl->type, DL_INDEX3, DL_INDEX4)) ? dl->nr : dl->nr * dl->parts;
const int tot = dl->type == DL_INDEX3 ? dl->nr : dl->nr * dl->parts;
for (const int i : IndexRange(tot)) {
minmax_v3v3_v3(min, max, &dl->verts[i * 3]);
}

View File

@ -398,21 +398,6 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name)
return lt;
}
bool object_deform_mball(Object *ob, ListBase *dispbase)
{
if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) {
DispList *dl;
for (dl = dispbase->first; dl; dl = dl->next) {
BKE_lattice_deform_coords(ob->parent, ob, (float(*)[3])dl->verts, dl->nr, 0, NULL, 1.0f);
}
return true;
}
return false;
}
static BPoint *latt_bp(Lattice *lt, int u, int v, int w)
{
return &lt->def[BKE_lattice_index_from_uvw(lt, u, v, w)];

View File

@ -25,6 +25,7 @@
#include "DNA_defaults.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@ -41,11 +42,15 @@
#include "BKE_anim_data.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_geometry_set.hh"
#include "BKE_idtype.h"
#include "BKE_lattice.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_mball_tessellate.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@ -76,15 +81,12 @@ static void metaball_copy_data(Main *UNUSED(bmain),
metaball_dst->editelems = nullptr;
metaball_dst->lastelem = nullptr;
metaball_dst->batch_cache = nullptr;
}
static void metaball_free_data(ID *id)
{
MetaBall *metaball = (MetaBall *)id;
BKE_mball_batch_cache_free(metaball);
MEM_SAFE_FREE(metaball->mat);
BLI_freelistN(&metaball->elems);
@ -111,7 +113,6 @@ static void metaball_blend_write(BlendWriter *writer, ID *id, const void *id_add
/* Must always be cleared (meta's don't have their own edit-data). */
mb->needs_flush_to_id = 0;
mb->lastelem = nullptr;
mb->batch_cache = nullptr;
/* write LibData */
BLO_write_id_struct(writer, MetaBall, id_address, &mb->id);
@ -144,7 +145,6 @@ static void metaball_blend_read_data(BlendDataReader *reader, ID *id)
mb->needs_flush_to_id = 0;
// mb->edit_elems.first = mb->edit_elems.last = nullptr;
mb->lastelem = nullptr;
mb->batch_cache = nullptr;
}
static void metaball_blend_read_lib(BlendLibReader *reader, ID *id)
@ -249,63 +249,36 @@ MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
return ml;
}
void BKE_mball_texspace_calc(Object *ob)
{
DispList *dl;
BoundBox *bb;
float *data, min[3], max[3] /*, loc[3], size[3] */;
int tot;
bool do_it = false;
if (ob->runtime.bb == nullptr) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
bb = ob->runtime.bb;
/* Weird one, this. */
// INIT_MINMAX(min, max);
(min)[0] = (min)[1] = (min)[2] = 1.0e30f;
(max)[0] = (max)[1] = (max)[2] = -1.0e30f;
dl = static_cast<DispList *>(ob->runtime.curve_cache->disp.first);
while (dl) {
tot = dl->nr;
if (tot) {
do_it = true;
}
data = dl->verts;
while (tot--) {
/* Also weird... but longer. From utildefines. */
minmax_v3v3_v3(min, max, data);
data += 3;
}
dl = dl->next;
}
if (!do_it) {
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
BKE_boundbox_init_from_minmax(bb, min, max);
bb->flag &= ~BOUNDBOX_DIRTY;
}
BoundBox *BKE_mball_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_MBALL);
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
if (ob->runtime.bb != NULL && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
return ob->runtime.bb;
}
/* This should always only be called with evaluated objects,
* but currently RNA is a problem here... */
if (ob->runtime.curve_cache != nullptr) {
BKE_mball_texspace_calc(ob);
if (ob->runtime.bb == NULL) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
/* Expect that this function is only called for evaluated objects. */
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
float min[3];
float max[3];
if (mesh_eval) {
INIT_MINMAX(min, max);
if (!BKE_mesh_minmax(mesh_eval, min, max)) {
copy_v3_fl(min, -1.0f);
copy_v3_fl(max, 1.0f);
}
}
else {
copy_v3_fl(min, 0.0f);
copy_v3_fl(max, 0.0f);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
return ob->runtime.bb;
}
@ -735,20 +708,44 @@ bool BKE_mball_select_swap_multi_ex(Base **bases, int bases_len)
/* **** Depsgraph evaluation **** */
/* Draw Engine */
void (*BKE_mball_batch_cache_dirty_tag_cb)(MetaBall *mb, int mode) = nullptr;
void (*BKE_mball_batch_cache_free_cb)(MetaBall *mb) = nullptr;
void BKE_mball_batch_cache_dirty_tag(MetaBall *mb, int mode)
void BKE_mball_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
if (mb->batch_cache) {
BKE_mball_batch_cache_dirty_tag_cb(mb, mode);
BLI_assert(ob->type == OB_MBALL);
BKE_object_free_derived_caches(ob);
const Object *basis_object = BKE_mball_basis_find(scene, ob);
if (ob != basis_object) {
return;
}
}
void BKE_mball_batch_cache_free(MetaBall *mb)
{
if (mb->batch_cache) {
BKE_mball_batch_cache_free_cb(mb);
Mesh *mesh = BKE_mball_polygonize(depsgraph, scene, ob);
if (mesh == NULL) {
return;
}
}
const MetaBall *mball = static_cast<MetaBall *>(ob->data);
mesh->mat = static_cast<Material **>(MEM_dupallocN(mball->mat));
mesh->totcol = mball->totcol;
if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) {
int verts_num;
float(*positions)[3] = BKE_mesh_vert_coords_alloc(mesh, &verts_num);
BKE_lattice_deform_coords(ob->parent, ob, positions, verts_num, 0, NULL, 1.0f);
BKE_mesh_vert_coords_apply(mesh, positions);
MEM_freeN(positions);
}
ob->runtime.geometry_set_eval = new GeometrySet(GeometrySet::create_with_mesh(mesh));
if (ob->runtime.bb == NULL) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
blender::float3 min(std::numeric_limits<float>::max());
blender::float3 max(-std::numeric_limits<float>::max());
if (!ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max)) {
min = blender::float3(0);
max = blender::float3(0);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
};

View File

@ -14,6 +14,8 @@
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@ -24,10 +26,11 @@
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_mball_tessellate.h" /* own include */
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@ -1371,7 +1374,7 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
}
}
void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
PROCESS process = {0};
const bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
@ -1394,10 +1397,10 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa
}
if (!is_render && (mb->flag == MB_UPDATE_NEVER)) {
return;
return NULL;
}
if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) {
return;
return NULL;
}
if (is_render) {
@ -1418,7 +1421,7 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa
init_meta(depsgraph, &process, scene, ob);
if (process.totelem == 0) {
freepolygonize(&process);
return;
return NULL;
}
build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb);
@ -1430,40 +1433,63 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa
ob->scale[1] < 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) ||
ob->scale[2] < 0.00001f * (process.allbb.max[2] - process.allbb.min[2])) {
freepolygonize(&process);
return;
return NULL;
}
polygonize(&process);
if (process.curindex == 0) {
freepolygonize(&process);
return;
return NULL;
}
/* add resulting surface to displist */
/* Avoid over-allocation since this is stored in the displist. */
if (process.curindex != process.totindex) {
process.indices = MEM_reallocN(process.indices, sizeof(int[4]) * process.curindex);
}
if (process.curvertex != process.totvertex) {
process.co = MEM_reallocN(process.co, process.curvertex * sizeof(float[3]));
process.no = MEM_reallocN(process.no, process.curvertex * sizeof(float[3]));
}
DispList *dl = MEM_callocN(sizeof(DispList), "mballdisp");
BLI_addtail(dispbase, dl);
dl->type = DL_INDEX4;
dl->nr = (int)process.curvertex;
dl->parts = (int)process.curindex;
dl->index = (int *)process.indices;
for (uint a = 0; a < process.curvertex; a++) {
normalize_v3(process.no[a]);
}
dl->verts = (float *)process.co;
dl->nors = (float *)process.no;
freepolygonize(&process);
Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name + 2);
mesh->totvert = (int)process.curvertex;
MVert *mvert = CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_DEFAULT, NULL, mesh->totvert);
for (int i = 0; i < mesh->totvert; i++) {
copy_v3_v3(mvert[i].co, process.co[i]);
mvert->bweight = 0;
mvert->flag = 0;
}
MEM_freeN(process.co);
mesh->totpoly = (int)process.curindex;
MPoly *mpoly = CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_DEFAULT, NULL, mesh->totpoly);
MLoop *mloop = CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_DEFAULT, NULL, mesh->totpoly * 4);
int loop_offset = 0;
for (int i = 0; i < mesh->totpoly; i++) {
const int *indices = process.indices[i];
const int count = indices[2] != indices[3] ? 4 : 3;
mpoly[i].loopstart = loop_offset;
mpoly[i].totloop = count;
mpoly[i].flag = ME_SMOOTH;
mloop[loop_offset].v = (uint32_t)indices[0];
mloop[loop_offset + 1].v = (uint32_t)indices[1];
mloop[loop_offset + 2].v = (uint32_t)indices[2];
if (count == 4) {
mloop[loop_offset + 3].v = (uint32_t)indices[3];
}
loop_offset += count;
}
MEM_freeN(process.indices);
for (int i = 0; i < mesh->totvert; i++) {
normalize_v3(process.no[i]);
}
mesh->runtime.vert_normals = process.no;
BKE_mesh_vertex_normals_clear_dirty(mesh);
mesh->totloop = loop_offset;
BKE_mesh_update_customdata_pointers(mesh, false);
BKE_mesh_calc_edges(mesh, false, false);
return mesh;
}

View File

@ -72,61 +72,6 @@ using blender::Span;
static CLG_LogRef LOG = {"bke.mesh_convert"};
void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
{
DispList *dl;
MVert *mvert;
MLoop *mloop, *allloop;
MPoly *mpoly;
int a, *index;
dl = (DispList *)lb->first;
if (dl == nullptr) {
return;
}
if (dl->type == DL_INDEX4) {
mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, dl->nr);
allloop = mloop = (MLoop *)CustomData_add_layer(
&me->ldata, CD_MLOOP, CD_CALLOC, nullptr, dl->parts * 4);
mpoly = (MPoly *)CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, nullptr, dl->parts);
me->mvert = mvert;
me->mloop = mloop;
me->mpoly = mpoly;
me->totvert = dl->nr;
me->totpoly = dl->parts;
for (const int i : IndexRange(dl->nr)) {
copy_v3_v3(me->mvert[i].co, &dl->verts[3 * i]);
}
a = dl->parts;
index = dl->index;
while (a--) {
int count = index[2] != index[3] ? 4 : 3;
mloop[0].v = index[0];
mloop[1].v = index[1];
mloop[2].v = index[2];
if (count == 4) {
mloop[3].v = index[3];
}
mpoly->totloop = count;
mpoly->loopstart = (int)(mloop - allloop);
mpoly->flag = ME_SMOOTH;
mpoly++;
mloop += count;
me->totloop += count;
index += 4;
}
BKE_mesh_update_customdata_pointers(me, true);
BKE_mesh_calc_edges(me, true, false);
}
}
/**
* Specialized function to use when we _know_ existing edges don't overlap with poly edges.
*/
@ -929,32 +874,21 @@ static Mesh *mesh_new_from_curve_type_object(const Object *object)
static Mesh *mesh_new_from_mball_object(Object *object)
{
MetaBall *mball = (MetaBall *)object->data;
/* NOTE: We can only create mesh for a polygonized meta ball. This figures out all original meta
* balls and all evaluated child meta balls (since polygonization is only stored in the mother
* ball).
*
* Create empty mesh so script-authors don't run into None objects. */
if (!DEG_is_evaluated_object(object) || object->runtime.curve_cache == nullptr ||
BLI_listbase_is_empty(&object->runtime.curve_cache->disp)) {
if (!DEG_is_evaluated_object(object)) {
return (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
}
Mesh *mesh_result = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result);
BKE_mesh_texspace_copy_from_object(mesh_result, object);
/* Copy materials. */
mesh_result->totcol = mball->totcol;
mesh_result->mat = (Material **)MEM_dupallocN(mball->mat);
if (mball->mat != nullptr) {
for (int i = mball->totcol; i-- > 0;) {
mesh_result->mat[i] = BKE_object_material_get(object, i + 1);
}
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object);
if (mesh_eval == nullptr) {
return (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
}
return mesh_result;
return BKE_mesh_copy_for_eval(mesh_eval, false);
}
static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh)

View File

@ -201,7 +201,7 @@ static DupliObject *make_dupli(
/* Meta-balls never draw in duplis, they are instead merged into one by the basis
* meta-ball outside of the group. this does mean that if that meta-ball is not in the
* scene, they will not show up at all, limitation that should be solved once. */
if (ob->type == OB_MBALL) {
if (object_data && GS(object_data->name) == ID_MB) {
dob->no_draw = true;
}
@ -1563,6 +1563,13 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
return nullptr;
}
/* Metaball objects can't create instances, but the dupli system is used to "instance" their
* evaluated mesh to render engines. We need to exit early to avoid recursively instancing the
* evaluated metaball mesh on metaball instances that already contribute to the basis. */
if (ctx->object->type == OB_MBALL && ctx->level > 0) {
return nullptr;
}
/* Should the dupli's be generated for this object? - Respect restrict flags. */
if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (visibility_flag & OB_HIDE_RENDER) :
(visibility_flag & OB_HIDE_VIEWPORT)) {

View File

@ -168,7 +168,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
break;
case OB_MBALL:
BKE_displist_make_mball(depsgraph, scene, ob);
BKE_mball_data_update(depsgraph, scene, ob);
break;
case OB_CURVES_LEGACY:
@ -292,9 +292,15 @@ void BKE_object_batch_cache_dirty_tag(Object *ob)
case OB_CURVES_LEGACY:
BKE_curve_batch_cache_dirty_tag((struct Curve *)ob->data, BKE_CURVE_BATCH_DIRTY_ALL);
break;
case OB_MBALL:
BKE_mball_batch_cache_dirty_tag((struct MetaBall *)ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
case OB_MBALL: {
/* This function is currently called on original objects, so to properly
* clear the actual displayed geometry, we have to tag the evaluated mesh. */
Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh) {
BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
}
break;
}
case OB_GPENCIL:
BKE_gpencil_batch_cache_dirty_tag((struct bGPdata *)ob->data);
break;

View File

@ -153,10 +153,10 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data)
if (dob->no_draw) {
continue;
}
if (obd->type == OB_MBALL) {
if (dob->ob_data && GS(dob->ob_data->name) == ID_MB) {
continue;
}
if (deg_object_hide_original(data->eval_mode, dob->ob, dob)) {
if (obd->type != OB_MBALL && deg_object_hide_original(data->eval_mode, dob->ob, dob)) {
continue;
}

View File

@ -71,11 +71,9 @@ set(SRC
intern/draw_attributes.cc
intern/draw_cache_impl_curve.cc
intern/draw_cache_impl_curves.cc
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_gpencil.c
intern/draw_cache_impl_lattice.c
intern/draw_cache_impl_mesh.cc
intern/draw_cache_impl_metaball.c
intern/draw_cache_impl_particles.c
intern/draw_cache_impl_pointcloud.cc
intern/draw_cache_impl_subdivision.cc

View File

@ -109,7 +109,7 @@ void EEVEE_cache_populate(void *vedata, Object *ob)
}
if (DRW_object_is_renderable(ob) && (ob_visibility & OB_VISIBLE_SELF)) {
if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL)) {
if (ELEM(ob->type, OB_MESH, OB_SURF)) {
EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow);
}
else if (ob->type == OB_CURVES) {

View File

@ -806,7 +806,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
!DRW_state_is_image_render();
/* First get materials for this mesh. */
if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL)) {
if (ELEM(ob->type, OB_MESH, OB_SURF)) {
const int materials_len = DRW_cache_object_material_count_get(ob);
EeveeMaterialCache *matcache = BLI_array_alloca(matcache, materials_len);

View File

@ -224,7 +224,7 @@ void EEVEE_render_cache(void *vedata,
}
if (ob_visibility & OB_VISIBLE_SELF) {
if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL)) {
if (ELEM(ob->type, OB_MESH, OB_SURF)) {
EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow);
if (do_cryptomatte) {
EEVEE_cryptomatte_cache_populate(data, sldata, ob);

View File

@ -144,8 +144,7 @@ void Instance::object_sync(Object *ob)
case OB_MESH:
case OB_CURVES_LEGACY:
case OB_SURF:
case OB_FONT:
case OB_MBALL: {
case OB_FONT: {
sync.sync_mesh(ob, ob_handle);
break;
}

View File

@ -320,7 +320,6 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
OB_MESH,
OB_CURVES_LEGACY,
OB_SURF,
OB_MBALL,
OB_FONT,
OB_GPENCIL,
OB_CURVES,

View File

@ -409,7 +409,7 @@ void workbench_cache_populate(void *ved, Object *ob)
return;
}
if (ELEM(ob->type, OB_MESH, OB_SURF, OB_MBALL, OB_POINTCLOUD)) {
if (ELEM(ob->type, OB_MESH, OB_SURF, OB_POINTCLOUD)) {
bool use_sculpt_pbvh, use_texpaint_mode, draw_shadow, has_transp_mat = false;
eV3DShadingColorType color_type = workbench_color_type_get(
wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, &draw_shadow);

View File

@ -780,6 +780,39 @@ GPUBatch *DRW_cache_normal_arrow_get(void)
return SHC.drw_normal_arrow;
}
void DRW_vertbuf_create_wiredata(GPUVertBuf *vbo, const int vert_len)
{
static GPUVertFormat format = {0};
static struct {
uint wd;
} attr_id;
if (format.attr_len == 0) {
/* initialize vertex format */
if (!GPU_crappy_amd_driver()) {
/* Some AMD drivers strangely crash with a vbo with this format. */
attr_id.wd = GPU_vertformat_attr_add(
&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
else {
attr_id.wd = GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
}
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, vert_len);
if (GPU_vertbuf_get_format(vbo)->stride == 1) {
memset(GPU_vertbuf_get_data(vbo), 0xFF, (size_t)vert_len);
}
else {
GPUVertBufRaw wd_step;
GPU_vertbuf_attr_get_raw_data(vbo, attr_id.wd, &wd_step);
for (int i = 0; i < vert_len; i++) {
*((float *)GPU_vertbuf_raw_step(&wd_step)) = 1.0f;
}
}
}
/** \} */
/* -------------------------------------------------------------------- */
@ -836,8 +869,6 @@ GPUBatch *DRW_cache_object_edge_detection_get(Object *ob, bool *r_is_manifold)
return NULL;
case OB_FONT:
return NULL;
case OB_MBALL:
return DRW_cache_mball_edge_detection_get(ob, r_is_manifold);
case OB_CURVES:
return NULL;
case OB_POINTCLOUD:
@ -860,8 +891,6 @@ GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob)
return NULL;
case OB_FONT:
return NULL;
case OB_MBALL:
return DRW_cache_mball_face_wireframe_get(ob);
case OB_CURVES:
return NULL;
case OB_POINTCLOUD:
@ -887,8 +916,6 @@ GPUBatch *DRW_cache_object_loose_edges_get(struct Object *ob)
return NULL;
case OB_FONT:
return NULL;
case OB_MBALL:
return NULL;
case OB_CURVES:
return NULL;
case OB_POINTCLOUD:
@ -911,8 +938,6 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob)
return NULL;
case OB_FONT:
return NULL;
case OB_MBALL:
return DRW_cache_mball_surface_get(ob);
case OB_CURVES:
return NULL;
case OB_POINTCLOUD:
@ -936,8 +961,6 @@ GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob)
case OB_SURF:
case OB_FONT:
return NULL;
case OB_MBALL:
return DRW_mball_batch_cache_pos_vertbuf_get(ob);
case OB_CURVES:
return NULL;
case OB_POINTCLOUD:
@ -968,8 +991,6 @@ int DRW_cache_object_material_count_get(struct Object *ob)
case OB_SURF:
case OB_FONT:
return DRW_curve_material_count_get(ob->data);
case OB_MBALL:
return DRW_metaball_material_count_get(ob->data);
case OB_CURVES:
return DRW_curves_material_count_get(ob->data);
case OB_POINTCLOUD:
@ -997,8 +1018,6 @@ GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
return NULL;
case OB_FONT:
return NULL;
case OB_MBALL:
return DRW_cache_mball_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
case OB_CURVES:
return NULL;
case OB_POINTCLOUD:
@ -2971,39 +2990,6 @@ GPUBatch *DRW_cache_curve_vert_overlay_get(Object *ob)
/** \} */
/* -------------------------------------------------------------------- */
/** \name MetaBall
* \{ */
GPUBatch *DRW_cache_mball_surface_get(Object *ob)
{
BLI_assert(ob->type == OB_MBALL);
return DRW_metaball_batch_cache_get_triangles_with_normals(ob);
}
GPUBatch *DRW_cache_mball_edge_detection_get(Object *ob, bool *r_is_manifold)
{
BLI_assert(ob->type == OB_MBALL);
return DRW_metaball_batch_cache_get_edge_detection(ob, r_is_manifold);
}
GPUBatch *DRW_cache_mball_face_wireframe_get(Object *ob)
{
BLI_assert(ob->type == OB_MBALL);
return DRW_metaball_batch_cache_get_wireframes_face(ob);
}
GPUBatch **DRW_cache_mball_surface_shaded_get(Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len)
{
BLI_assert(ob->type == OB_MBALL);
MetaBall *mb = ob->data;
return DRW_metaball_batch_cache_get_surface_shaded(ob, mb, gpumat_array, gpumat_array_len);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Font
* \{ */
@ -3322,9 +3308,6 @@ void drw_batch_cache_validate(Object *ob)
case OB_SURF:
DRW_curve_batch_cache_validate((Curve *)ob->data);
break;
case OB_MBALL:
DRW_mball_batch_cache_validate((MetaBall *)ob->data);
break;
case OB_LATTICE:
DRW_lattice_batch_cache_validate((Lattice *)ob->data);
break;

View File

@ -213,15 +213,6 @@ struct GPUBatch *DRW_cache_particles_get_edit_tip_points(struct Object *object,
struct PTCacheEdit *edit);
struct GPUBatch *DRW_cache_particles_get_prim(int type);
/* Metaball */
struct GPUBatch *DRW_cache_mball_surface_get(struct Object *ob);
struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
struct GPUBatch *DRW_cache_mball_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_mball_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* Curves */
struct GPUBatch *DRW_cache_curves_surface_get(struct Object *ob);

View File

@ -36,10 +36,6 @@ extern "C" {
/** \name Expose via BKE callbacks
* \{ */
void DRW_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode);
void DRW_mball_batch_cache_validate(struct MetaBall *mb);
void DRW_mball_batch_cache_free(struct MetaBall *mb);
void DRW_curve_batch_cache_dirty_tag(struct Curve *cu, int mode);
void DRW_curve_batch_cache_validate(struct Curve *cu);
void DRW_curve_batch_cache_free(struct Curve *cu);
@ -110,39 +106,6 @@ struct GPUBatch *DRW_curve_batch_cache_get_edit_verts(struct Curve *cu);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Metaball
* \{ */
int DRW_metaball_material_count_get(struct MetaBall *mb);
struct GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(struct Object *ob);
struct GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(struct Object *ob,
struct MetaBall *mb,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
struct GPUBatch *DRW_metaball_batch_cache_get_wireframes_face(struct Object *ob);
struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob,
bool *r_is_manifold);
/** \} */
/* -------------------------------------------------------------------- */
/** \name DispList
* \{ */
void DRW_displist_vertbuf_create_pos_and_nor(struct ListBase *lb,
struct GPUVertBuf *vbo,
const struct Scene *scene);
void DRW_displist_vertbuf_create_wiredata(struct ListBase *lb, struct GPUVertBuf *vbo);
void DRW_displist_indexbuf_create_lines_in_order(struct ListBase *lb, struct GPUIndexBuf *ibo);
void DRW_displist_indexbuf_create_triangles_in_order(struct ListBase *lb, struct GPUIndexBuf *ibo);
void DRW_displist_indexbuf_create_edges_adjacency_lines(struct ListBase *lb,
struct GPUIndexBuf *ibo,
bool *r_is_manifold);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Lattice
* \{ */
@ -309,7 +272,6 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(struct Mesh *me);
* \{ */
struct GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(struct Mesh *me);
struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(struct Object *ob);
int DRW_mesh_material_count_get(const struct Object *object, const struct Mesh *me);

View File

@ -1,354 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2017 Blender Foundation. All rights reserved. */
/** \file
* \ingroup draw
*
* \brief DispList API for render engines
*
* \note DispList may be removed soon! This is a utility for object types that use render.
*/
#include "BLI_edgehash.h"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_curve_types.h"
#include "DNA_scene_types.h"
#include "BKE_displist.h"
#include "GPU_batch.h"
#include "GPU_capabilities.h"
#include "draw_cache_inline.h"
#include "draw_cache_impl.h" /* own include */
static int dl_vert_len(const DispList *dl)
{
switch (dl->type) {
case DL_INDEX3:
case DL_INDEX4:
return dl->nr;
case DL_SURF:
return dl->parts * dl->nr;
}
return 0;
}
static int dl_tri_len(const DispList *dl)
{
switch (dl->type) {
case DL_INDEX3:
return dl->parts;
case DL_INDEX4:
return dl->parts * 2;
case DL_SURF:
return dl->totindex * 2;
}
return 0;
}
/* see: displist_vert_coords_alloc */
static int curve_render_surface_vert_len_get(const ListBase *lb)
{
int vert_len = 0;
LISTBASE_FOREACH (const DispList *, dl, lb) {
vert_len += dl_vert_len(dl);
}
return vert_len;
}
static int curve_render_surface_tri_len_get(const ListBase *lb)
{
int tri_len = 0;
LISTBASE_FOREACH (const DispList *, dl, lb) {
tri_len += dl_tri_len(dl);
}
return tri_len;
}
typedef void(SetTriIndicesFn)(void *thunk, uint v1, uint v2, uint v3);
static void displist_indexbufbuilder_set(
SetTriIndicesFn *set_tri_indices,
SetTriIndicesFn *set_quad_tri_indices, /* meh, find a better solution. */
void *thunk,
const DispList *dl,
const int ofs)
{
if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
const int *idx = dl->index;
if (dl->type == DL_INDEX3) {
const int i_end = dl->parts;
for (int i = 0; i < i_end; i++, idx += 3) {
set_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
}
}
else if (dl->type == DL_SURF) {
const int i_end = dl->totindex;
for (int i = 0; i < i_end; i++, idx += 4) {
set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[3] + ofs);
}
}
else {
BLI_assert(dl->type == DL_INDEX4);
const int i_end = dl->parts;
for (int i = 0; i < i_end; i++, idx += 4) {
if (idx[2] != idx[3]) {
set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs);
set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs);
}
else {
set_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs);
}
}
}
}
}
void DRW_displist_vertbuf_create_pos_and_nor(ListBase *lb, GPUVertBuf *vbo, const Scene *scene)
{
const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
GPU_use_hq_normals_workaround();
static GPUVertFormat format = {0};
static GPUVertFormat format_hq = {0};
static struct {
uint pos, nor;
uint pos_hq, nor_hq;
} attr_id;
if (format.attr_len == 0) {
/* initialize vertex format */
attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
attr_id.nor = GPU_vertformat_attr_add(
&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
/* initialize vertex format */
attr_id.pos_hq = GPU_vertformat_attr_add(&format_hq, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
attr_id.nor_hq = GPU_vertformat_attr_add(
&format_hq, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
uint pos_id = do_hq_normals ? attr_id.pos_hq : attr_id.pos;
uint nor_id = do_hq_normals ? attr_id.nor_hq : attr_id.nor;
GPU_vertbuf_init_with_format(vbo, do_hq_normals ? &format_hq : &format);
GPU_vertbuf_data_alloc(vbo, curve_render_surface_vert_len_get(lb));
BKE_displist_normals_add(lb);
int vbo_len_used = 0;
LISTBASE_FOREACH (const DispList *, dl, lb) {
const bool ndata_is_single = dl->type == DL_INDEX3;
if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
const float *fp_co = dl->verts;
const float *fp_no = dl->nors;
const int vbo_end = vbo_len_used + dl_vert_len(dl);
while (vbo_len_used < vbo_end) {
GPU_vertbuf_attr_set(vbo, pos_id, vbo_len_used, fp_co);
if (fp_no) {
GPUNormal vnor_pack;
GPU_normal_convert_v3(&vnor_pack, fp_no, do_hq_normals);
GPU_vertbuf_attr_set(vbo, nor_id, vbo_len_used, &vnor_pack);
if (ndata_is_single == false) {
fp_no += 3;
}
}
fp_co += 3;
vbo_len_used += 1;
}
}
}
}
void DRW_vertbuf_create_wiredata(GPUVertBuf *vbo, const int vert_len)
{
static GPUVertFormat format = {0};
static struct {
uint wd;
} attr_id;
if (format.attr_len == 0) {
/* initialize vertex format */
if (!GPU_crappy_amd_driver()) {
/* Some AMD drivers strangely crash with a vbo with this format. */
attr_id.wd = GPU_vertformat_attr_add(
&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
else {
attr_id.wd = GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
}
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, vert_len);
if (GPU_vertbuf_get_format(vbo)->stride == 1) {
memset(GPU_vertbuf_get_data(vbo), 0xFF, (size_t)vert_len);
}
else {
GPUVertBufRaw wd_step;
GPU_vertbuf_attr_get_raw_data(vbo, attr_id.wd, &wd_step);
for (int i = 0; i < vert_len; i++) {
*((float *)GPU_vertbuf_raw_step(&wd_step)) = 1.0f;
}
}
}
void DRW_displist_vertbuf_create_wiredata(ListBase *lb, GPUVertBuf *vbo)
{
const int vert_len = curve_render_surface_vert_len_get(lb);
DRW_vertbuf_create_wiredata(vbo, vert_len);
}
void DRW_displist_indexbuf_create_triangles_in_order(ListBase *lb, GPUIndexBuf *ibo)
{
const int tri_len = curve_render_surface_tri_len_get(lb);
const int vert_len = curve_render_surface_vert_len_get(lb);
GPUIndexBufBuilder elb;
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len);
int ofs = 0;
LISTBASE_FOREACH (const DispList *, dl, lb) {
displist_indexbufbuilder_set((SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
(SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
&elb,
dl,
ofs);
ofs += dl_vert_len(dl);
}
GPU_indexbuf_build_in_place(&elb, ibo);
}
static void set_overlay_wires_tri_indices(void *thunk, uint v1, uint v2, uint v3)
{
GPUIndexBufBuilder *eld = (GPUIndexBufBuilder *)thunk;
GPU_indexbuf_add_line_verts(eld, v1, v2);
GPU_indexbuf_add_line_verts(eld, v2, v3);
GPU_indexbuf_add_line_verts(eld, v3, v1);
}
static void set_overlay_wires_quad_tri_indices(void *thunk, uint v1, uint v2, uint v3)
{
GPUIndexBufBuilder *eld = (GPUIndexBufBuilder *)thunk;
GPU_indexbuf_add_line_verts(eld, v1, v3);
GPU_indexbuf_add_line_verts(eld, v3, v2);
}
void DRW_displist_indexbuf_create_lines_in_order(ListBase *lb, GPUIndexBuf *ibo)
{
const int tri_len = curve_render_surface_tri_len_get(lb);
const int vert_len = curve_render_surface_vert_len_get(lb);
GPUIndexBufBuilder elb;
GPU_indexbuf_init(&elb, GPU_PRIM_LINES, tri_len * 3, vert_len);
int ofs = 0;
LISTBASE_FOREACH (const DispList *, dl, lb) {
displist_indexbufbuilder_set(
set_overlay_wires_tri_indices, set_overlay_wires_quad_tri_indices, &elb, dl, ofs);
ofs += dl_vert_len(dl);
}
GPU_indexbuf_build_in_place(&elb, ibo);
}
/* Edge detection/adjacency. */
#define NO_EDGE INT_MAX
static void set_edge_adjacency_lines_indices(
EdgeHash *eh, GPUIndexBufBuilder *elb, bool *r_is_manifold, uint v1, uint v2, uint v3)
{
bool inv_indices = (v2 > v3);
void **pval;
bool value_is_init = BLI_edgehash_ensure_p(eh, v2, v3, &pval);
int v_data = POINTER_AS_INT(*pval);
if (!value_is_init || v_data == NO_EDGE) {
/* Save the winding order inside the sign bit. Because the
* edgehash sort the keys and we need to compare winding later. */
int value = (int)v1 + 1; /* Int 0 bm_looptricannot be signed */
*pval = POINTER_FROM_INT((inv_indices) ? -value : value);
}
else {
/* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
*pval = POINTER_FROM_INT(NO_EDGE);
bool inv_opposite = (v_data < 0);
uint v_opposite = (uint)abs(v_data) - 1;
if (inv_opposite == inv_indices) {
/* Don't share edge if triangles have non matching winding. */
GPU_indexbuf_add_line_adj_verts(elb, v1, v2, v3, v1);
GPU_indexbuf_add_line_adj_verts(elb, v_opposite, v2, v3, v_opposite);
*r_is_manifold = false;
}
else {
GPU_indexbuf_add_line_adj_verts(elb, v1, v2, v3, v_opposite);
}
}
}
static void set_edges_adjacency_lines_indices(void *thunk, uint v1, uint v2, uint v3)
{
void **packed = (void **)thunk;
GPUIndexBufBuilder *elb = (GPUIndexBufBuilder *)packed[0];
EdgeHash *eh = (EdgeHash *)packed[1];
bool *r_is_manifold = (bool *)packed[2];
set_edge_adjacency_lines_indices(eh, elb, r_is_manifold, v1, v2, v3);
set_edge_adjacency_lines_indices(eh, elb, r_is_manifold, v2, v3, v1);
set_edge_adjacency_lines_indices(eh, elb, r_is_manifold, v3, v1, v2);
}
void DRW_displist_indexbuf_create_edges_adjacency_lines(struct ListBase *lb,
struct GPUIndexBuf *ibo,
bool *r_is_manifold)
{
const int tri_len = curve_render_surface_tri_len_get(lb);
const int vert_len = curve_render_surface_vert_len_get(lb);
*r_is_manifold = true;
/* Allocate max but only used indices are sent to GPU. */
GPUIndexBufBuilder elb;
GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, tri_len * 3, vert_len);
EdgeHash *eh = BLI_edgehash_new_ex(__func__, tri_len * 3);
/* pack values to pass to `set_edges_adjacency_lines_indices` function. */
void *thunk[3] = {&elb, eh, r_is_manifold};
int v_idx = 0;
LISTBASE_FOREACH (const DispList *, dl, lb) {
displist_indexbufbuilder_set((SetTriIndicesFn *)set_edges_adjacency_lines_indices,
(SetTriIndicesFn *)set_edges_adjacency_lines_indices,
thunk,
dl,
v_idx);
v_idx += dl_vert_len(dl);
}
/* Create edges for remaining non manifold edges. */
EdgeHashIterator *ehi;
for (ehi = BLI_edgehashIterator_new(eh); BLI_edgehashIterator_isDone(ehi) == false;
BLI_edgehashIterator_step(ehi)) {
uint v1, v2;
int v_data = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
if (v_data == NO_EDGE) {
continue;
}
BLI_edgehashIterator_getKey(ehi, &v1, &v2);
uint v0 = (uint)abs(v_data) - 1;
if (v_data < 0) { /* inv_opposite */
SWAP(uint, v1, v2);
}
GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v0);
*r_is_manifold = false;
}
BLI_edgehashIterator_free(ehi);
BLI_edgehash_free(eh, NULL);
GPU_indexbuf_build_in_place(&elb, ibo);
}
#undef NO_EDGE

View File

@ -1,294 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2017 Blender Foundation. All rights reserved. */
/** \file
* \ingroup draw
*
* \brief MetaBall API for render engines
*/
#include "MEM_guardedalloc.h"
#include "BLI_math_base.h"
#include "BLI_utildefines.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "BKE_curve.h"
#include "BKE_mball.h"
#include "GPU_batch.h"
#include "DRW_render.h"
#include "draw_cache_impl.h" /* own include */
static void metaball_batch_cache_clear(MetaBall *mb);
/* -------------------------------------------------------------------- */
/** \name MetaBall GPUBatch Cache
* \{ */
typedef struct MetaBallBatchCache {
GPUBatch *batch;
GPUBatch **shaded_triangles;
int mat_len;
/* Shared */
GPUVertBuf *pos_nor_in_order;
/* Wireframe */
struct {
GPUBatch *batch;
} face_wire;
/* Edge detection */
GPUBatch *edge_detection;
GPUIndexBuf *edges_adj_lines;
/* settings to determine if cache is invalid */
bool is_dirty;
/* Valid only if edge_detection is up to date. */
bool is_manifold;
} MetaBallBatchCache;
/* GPUBatch cache management. */
static bool metaball_batch_cache_valid(MetaBall *mb)
{
MetaBallBatchCache *cache = mb->batch_cache;
if (cache == NULL) {
return false;
}
return cache->is_dirty == false;
}
static void metaball_batch_cache_init(MetaBall *mb)
{
MetaBallBatchCache *cache = mb->batch_cache;
if (!cache) {
cache = mb->batch_cache = MEM_mallocN(sizeof(*cache), __func__);
}
cache->batch = NULL;
cache->mat_len = 0;
cache->shaded_triangles = NULL;
cache->is_dirty = false;
cache->pos_nor_in_order = NULL;
cache->face_wire.batch = NULL;
cache->edge_detection = NULL;
cache->edges_adj_lines = NULL;
cache->is_manifold = false;
}
void DRW_mball_batch_cache_validate(MetaBall *mb)
{
if (!metaball_batch_cache_valid(mb)) {
metaball_batch_cache_clear(mb);
metaball_batch_cache_init(mb);
}
}
static MetaBallBatchCache *metaball_batch_cache_get(MetaBall *mb)
{
return mb->batch_cache;
}
void DRW_mball_batch_cache_dirty_tag(MetaBall *mb, int mode)
{
MetaBallBatchCache *cache = mb->batch_cache;
if (cache == NULL) {
return;
}
switch (mode) {
case BKE_MBALL_BATCH_DIRTY_ALL:
cache->is_dirty = true;
break;
default:
BLI_assert(0);
}
}
static void metaball_batch_cache_clear(MetaBall *mb)
{
MetaBallBatchCache *cache = mb->batch_cache;
if (!cache) {
return;
}
GPU_BATCH_DISCARD_SAFE(cache->face_wire.batch);
GPU_BATCH_DISCARD_SAFE(cache->batch);
GPU_BATCH_DISCARD_SAFE(cache->edge_detection);
GPU_VERTBUF_DISCARD_SAFE(cache->pos_nor_in_order);
GPU_INDEXBUF_DISCARD_SAFE(cache->edges_adj_lines);
/* NOTE: shaded_triangles[0] is already freed by `cache->batch`. */
MEM_SAFE_FREE(cache->shaded_triangles);
cache->mat_len = 0;
cache->is_manifold = false;
}
void DRW_mball_batch_cache_free(MetaBall *mb)
{
metaball_batch_cache_clear(mb);
MEM_SAFE_FREE(mb->batch_cache);
}
static GPUVertBuf *mball_batch_cache_get_pos_and_normals(Object *ob,
MetaBallBatchCache *cache,
const struct Scene *scene)
{
if (cache->pos_nor_in_order == NULL) {
ListBase *lb = &ob->runtime.curve_cache->disp;
cache->pos_nor_in_order = GPU_vertbuf_calloc();
DRW_displist_vertbuf_create_pos_and_nor(lb, cache->pos_nor_in_order, scene);
}
return cache->pos_nor_in_order;
}
static GPUIndexBuf *mball_batch_cache_get_edges_adj_lines(Object *ob, MetaBallBatchCache *cache)
{
if (cache->edges_adj_lines == NULL) {
ListBase *lb = &ob->runtime.curve_cache->disp;
cache->edges_adj_lines = GPU_indexbuf_calloc();
DRW_displist_indexbuf_create_edges_adjacency_lines(
lb, cache->edges_adj_lines, &cache->is_manifold);
}
return cache->edges_adj_lines;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Public Object/MetaBall API
* \{ */
GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob)
{
if (!BKE_mball_is_basis(ob)) {
return NULL;
}
MetaBall *mb = ob->data;
MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
const DRWContextState *draw_ctx = DRW_context_state_get();
const struct Scene *scene = draw_ctx->scene;
if (cache->batch == NULL) {
ListBase *lb = &ob->runtime.curve_cache->disp;
GPUIndexBuf *ibo = GPU_indexbuf_calloc();
DRW_displist_indexbuf_create_triangles_in_order(lb, ibo);
cache->batch = GPU_batch_create_ex(GPU_PRIM_TRIS,
mball_batch_cache_get_pos_and_normals(ob, cache, scene),
ibo,
GPU_BATCH_OWNS_INDEX);
}
return cache->batch;
}
GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(Object *ob,
MetaBall *mb,
struct GPUMaterial **UNUSED(gpumat_array),
uint gpumat_array_len)
{
if (!BKE_mball_is_basis(ob)) {
return NULL;
}
BLI_assert(gpumat_array_len == DRW_metaball_material_count_get(mb));
MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
if (cache->shaded_triangles == NULL) {
cache->mat_len = gpumat_array_len;
cache->shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * cache->mat_len,
__func__);
cache->shaded_triangles[0] = DRW_metaball_batch_cache_get_triangles_with_normals(ob);
for (int i = 1; i < cache->mat_len; i++) {
cache->shaded_triangles[i] = NULL;
}
}
return cache->shaded_triangles;
}
GPUBatch *DRW_metaball_batch_cache_get_wireframes_face(Object *ob)
{
if (!BKE_mball_is_basis(ob)) {
return NULL;
}
MetaBall *mb = ob->data;
MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
const DRWContextState *draw_ctx = DRW_context_state_get();
const struct Scene *scene = draw_ctx->scene;
if (cache->face_wire.batch == NULL) {
ListBase *lb = &ob->runtime.curve_cache->disp;
GPUVertBuf *vbo_wiredata = GPU_vertbuf_calloc();
DRW_displist_vertbuf_create_wiredata(lb, vbo_wiredata);
GPUIndexBuf *ibo = GPU_indexbuf_calloc();
DRW_displist_indexbuf_create_lines_in_order(lb, ibo);
cache->face_wire.batch = GPU_batch_create_ex(
GPU_PRIM_LINES,
mball_batch_cache_get_pos_and_normals(ob, cache, scene),
ibo,
GPU_BATCH_OWNS_INDEX);
GPU_batch_vertbuf_add_ex(cache->face_wire.batch, vbo_wiredata, true);
}
return cache->face_wire.batch;
}
struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob,
bool *r_is_manifold)
{
if (!BKE_mball_is_basis(ob)) {
return NULL;
}
MetaBall *mb = ob->data;
MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
const DRWContextState *draw_ctx = DRW_context_state_get();
const struct Scene *scene = draw_ctx->scene;
if (cache->edge_detection == NULL) {
cache->edge_detection = GPU_batch_create(
GPU_PRIM_LINES_ADJ,
mball_batch_cache_get_pos_and_normals(ob, cache, scene),
mball_batch_cache_get_edges_adj_lines(ob, cache));
}
if (r_is_manifold) {
*r_is_manifold = cache->is_manifold;
}
return cache->edge_detection;
}
struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(Object *ob)
{
if (!BKE_mball_is_basis(ob)) {
return NULL;
}
MetaBall *mb = ob->data;
MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
const DRWContextState *draw_ctx = DRW_context_state_get();
const struct Scene *scene = draw_ctx->scene;
return mball_batch_cache_get_pos_and_normals(ob, cache, scene);
}
int DRW_metaball_material_count_get(MetaBall *mb)
{
return max_ii(1, mb->totcol);
}
/** \} */

View File

@ -417,7 +417,6 @@ bool DRW_object_is_flat(Object *ob, int *r_axis)
OB_CURVES_LEGACY,
OB_SURF,
OB_FONT,
OB_MBALL,
OB_CURVES,
OB_POINTCLOUD,
OB_VOLUME)) {

View File

@ -2989,9 +2989,6 @@ void DRW_engines_register(void)
/* setup callbacks */
{
BKE_mball_batch_cache_dirty_tag_cb = DRW_mball_batch_cache_dirty_tag;
BKE_mball_batch_cache_free_cb = DRW_mball_batch_cache_free;
BKE_curve_batch_cache_dirty_tag_cb = DRW_curve_batch_cache_dirty_tag;
BKE_curve_batch_cache_free_cb = DRW_curve_batch_cache_free;

View File

@ -2771,25 +2771,6 @@ static const EnumPropertyItem convert_target_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
static void object_data_convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
if (ob->runtime.curve_cache == nullptr) {
/* Force creation. This is normally not needed but on operator
* redo we might end up with an object which isn't evaluated yet.
* Also happens in case we are working on a copy of the object
* (all its caches have been nuked then).
*/
if (ELEM(ob->type, OB_SURF, OB_CURVES_LEGACY, OB_FONT)) {
/* We need 'for render' ON here, to enable computing bevel #DispList if needed.
* Also makes sense anyway, we would not want e.g. to lose hidden parts etc. */
BKE_displist_make_curveTypes(depsgraph, scene, ob, true);
}
else if (ob->type == OB_MBALL) {
BKE_displist_make_mball(depsgraph, scene, ob);
}
}
}
static void object_data_convert_curve_to_mesh(Main *bmain, Depsgraph *depsgraph, Object *ob)
{
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
@ -2908,7 +2889,7 @@ static int object_convert_exec(bContext *C, wmOperator *op)
const bool use_faces = RNA_boolean_get(op->ptr, "faces");
const float offset = RNA_float_get(op->ptr, "offset");
int a, mballConverted = 0;
int mballConverted = 0;
bool gpencilConverted = false;
bool gpencilCurveConverted = false;
@ -3332,22 +3313,14 @@ static int object_convert_exec(bContext *C, wmOperator *op)
MetaBall *mb = static_cast<MetaBall *>(newob->data);
id_us_min(&mb->id);
newob->data = BKE_mesh_add(bmain, "Mesh");
/* Find the evaluated mesh of the basis metaball object. */
Object *object_eval = DEG_get_evaluated_object(depsgraph, baseob);
Mesh *mesh = BKE_mesh_new_from_object_to_bmain(bmain, depsgraph, object_eval, true);
id_us_plus(&mesh->id);
newob->data = mesh;
newob->type = OB_MESH;
Mesh *me = static_cast<Mesh *>(newob->data);
me->totcol = mb->totcol;
if (newob->totcol) {
me->mat = static_cast<Material **>(MEM_dupallocN(mb->mat));
for (a = 0; a < newob->totcol; a++) {
id_us_plus((ID *)me->mat[a]);
}
}
object_data_convert_ensure_curve_cache(depsgraph, scene, baseob);
BKE_mesh_from_metaball(&baseob->runtime.curve_cache->disp,
static_cast<Mesh *>(newob->data));
if (obact->type == OB_MBALL) {
basact = basen;
}

View File

@ -50,6 +50,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
@ -111,7 +112,7 @@ static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object *
BKE_lattice_modifiers_calc(depsgraph, scene_eval, ob_eval);
}
else if (ob->type == OB_MBALL) {
BKE_displist_make_mball(depsgraph, scene_eval, ob_eval);
BKE_mball_data_update(depsgraph, scene_eval, ob_eval);
}
else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false);

View File

@ -168,33 +168,7 @@ static void stats_object(Object *ob,
if ((me_eval != nullptr) && !BLI_gset_add(objects_gset, (void *)me_eval)) {
break;
}
if (stats_mesheval(me_eval, is_selected, stats)) {
break;
}
ATTR_FALLTHROUGH; /* Fall-through to displist. */
}
case OB_MBALL: {
int totv = 0, totf = 0, tottri = 0;
if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) {
/* NOTE: We only get the same curve_cache for instances of the same curve/font/...
* For simple linked duplicated objects, each has its own dispList. */
if (!BLI_gset_add(objects_gset, ob->runtime.curve_cache)) {
break;
}
BKE_displist_count(&ob->runtime.curve_cache->disp, &totv, &totf, &tottri);
}
stats->totvert += totv;
stats->totface += totf;
stats->tottri += tottri;
if (is_selected) {
stats->totvertsel += totv;
stats->totfacesel += totf;
}
stats_mesheval(me_eval, is_selected, stats);
break;
}
case OB_GPENCIL: {

View File

@ -77,6 +77,11 @@ NodeGroup *BlenderFileLoader::Load()
continue;
}
/* Evaluated metaballs will appear as mesh objects in the iterator. */
if (ob->type == OB_MBALL) {
continue;
}
Mesh *mesh = BKE_object_to_mesh(nullptr, ob, false);
if (mesh) {

View File

@ -60,7 +60,7 @@ TEST_F(obj_exporter_test, filter_objects_curves_as_mesh)
return;
}
auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
EXPECT_EQ(objmeshes.size(), 20);
EXPECT_EQ(objmeshes.size(), 21);
EXPECT_EQ(objcurves.size(), 0);
}

View File

@ -92,8 +92,6 @@ typedef struct MetaBall {
/* used in editmode */
// ListBase edit_elems;
MetaElem *lastelem;
void *batch_cache;
} MetaBall;
/* **************** METABALL ********************* */

View File

@ -28,7 +28,7 @@ static void rna_Meta_transform(struct MetaBall *mb, float mat[16])
static void rna_Mball_update_gpu_tag(MetaBall *mb)
{
BKE_mball_batch_cache_dirty_tag(mb, BKE_MBALL_BATCH_DIRTY_ALL);
DEG_id_tag_update(&mb->id, ID_RECALC_SHADING);
}
#else