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:
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
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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 <->def[BKE_lattice_index_from_uvw(lt, u, v, w)];
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -92,8 +92,6 @@ typedef struct MetaBall {
|
|||
/* used in editmode */
|
||||
// ListBase edit_elems;
|
||||
MetaElem *lastelem;
|
||||
|
||||
void *batch_cache;
|
||||
} MetaBall;
|
||||
|
||||
/* **************** METABALL ********************* */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue