Compare commits
97 Commits
temp-py-gp
...
temp-abc-f
Author | SHA1 | Date | |
---|---|---|---|
c0ef2a5cf5 | |||
5a0efc9c8b | |||
1ca7821b15 | |||
7ce3751757 | |||
70a80c7faa | |||
789d82ffc9 | |||
1ce6836849 | |||
b392982e3c | |||
7d7232c142 | |||
5b64e59b76 | |||
f43ccc010d | |||
21c395fa83 | |||
6143f97531 | |||
491fc93fc6 | |||
711794ffab | |||
e48f74fe4d | |||
749748c140 | |||
bf103be1eb | |||
d05fd030df | |||
ce7abd00ec | |||
b5088f19ff | |||
ed062656fa | |||
04af3002d2 | |||
4617835753 | |||
50a306e799 | |||
3f278af8e7 | |||
c1178d6d6e | |||
08e90abdee | |||
7c1ddc7755 | |||
4a5756bc35 | |||
82610dcb7c | |||
793e0f85c7 | |||
b5d861904a | |||
c54e260c34 | |||
74138fb2d4 | |||
2529300f69 | |||
4a5082317e | |||
f3594f83e1 | |||
90dcbcb236 | |||
26672cb7b5 | |||
899a790bf4 | |||
ade48c51ba | |||
0183d70df2 | |||
0c71d949c0 | |||
945b118a15 | |||
b709e64dbd | |||
d2e6fcfb77 | |||
3c6df4305d | |||
ede08b7b48 | |||
ad698d8001 | |||
872da801a8 | |||
1b2b41110f | |||
d5aea45a86 | |||
1b0b987db2 | |||
487e4b09f6 | |||
5794312f89 | |||
1cee4aa18c | |||
a89d5e9fcc | |||
33e42a1755 | |||
18877cedb2 | |||
a90012ceeb | |||
f62d9b3b8f | |||
a83dfe5c3f | |||
4bea7c806a | |||
d081856bc5 | |||
6e16db01df | |||
baab3e3a4f | |||
0ec0a097bd | |||
9c45860cc4 | |||
f5efb15b30 | |||
290f0d4d89 | |||
a3723635e8 | |||
2fa51473df | |||
5243afbcd8 | |||
9a19253ab2 | |||
16bc4e2607 | |||
a3f7f4bdfe | |||
9369691900 | |||
01b5ff266a | |||
e2a0c5dfbf | |||
3f7a93a4df | |||
3e1a05763b | |||
45c7468e42 | |||
cda3622cb8 | |||
07f1505d6d | |||
e6f1e47a2c | |||
24034bf3d3 | |||
0eb3bf108e | |||
0e54e5181b | |||
d1fa9f1138 | |||
de2242eed7 | |||
bbbbdacf39 | |||
27af10e687 | |||
cb666041ec | |||
e08fe0daa0 | |||
05184e8276 | |||
5cf5e60918 |
@@ -49,6 +49,14 @@ struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
|
||||
int type,
|
||||
AttributeDomain domain);
|
||||
|
||||
/* Return an existing CustomDataLayer, or create a new one if none is found for the given
|
||||
* parameters and return it. */
|
||||
struct CustomDataLayer *BKE_id_attribute_ensure(struct ID *id,
|
||||
const char *name,
|
||||
const int type,
|
||||
const AttributeDomain domain,
|
||||
struct ReportList *reports);
|
||||
|
||||
AttributeDomain BKE_id_attribute_domain(struct ID *id, struct CustomDataLayer *layer);
|
||||
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
|
||||
bool BKE_id_attribute_required(struct ID *id, struct CustomDataLayer *layer);
|
||||
@@ -65,6 +73,13 @@ int *BKE_id_attributes_active_index_p(struct ID *id);
|
||||
|
||||
CustomData *BKE_id_attributes_iterator_next_domain(struct ID *id, struct CustomDataLayer *layers);
|
||||
|
||||
typedef struct DomainInfo {
|
||||
CustomData *customdata;
|
||||
int length;
|
||||
} DomainInfo;
|
||||
|
||||
void BKE_id_attribute_get_domains(const struct ID *id, DomainInfo info[ATTR_DOMAIN_NUM]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -11,6 +11,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct CacheAttributeMapping;
|
||||
struct CacheFile;
|
||||
struct CacheFileLayer;
|
||||
struct CacheReader;
|
||||
@@ -63,6 +64,17 @@ struct CacheFileLayer *BKE_cachefile_get_active_layer(struct CacheFile *cache_fi
|
||||
|
||||
void BKE_cachefile_remove_layer(struct CacheFile *cache_file, struct CacheFileLayer *layer);
|
||||
|
||||
struct CacheAttributeMapping *BKE_cachefile_add_attribute_mapping(struct CacheFile *cache_file,
|
||||
const char *name,
|
||||
int mapping_type,
|
||||
int domain);
|
||||
|
||||
struct CacheAttributeMapping *BKE_cachefile_get_active_attribute_mapping(
|
||||
struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_remove_attribute_mapping(struct CacheFile *cache_file,
|
||||
struct CacheAttributeMapping *mapping);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -601,6 +601,10 @@ void BKE_modifier_blend_read_data(struct BlendDataReader *reader,
|
||||
struct Object *ob);
|
||||
void BKE_modifier_blend_read_lib(struct BlendLibReader *reader, struct Object *ob);
|
||||
|
||||
/* Return whether the modifier can operate directly on a Curve, i.e. without needing a conversion
|
||||
* to a temporary Mesh. */
|
||||
bool BKE_modifier_supports_curve_data(const ModifierData *md);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -25,6 +25,9 @@ extern const char *POINTCLOUD_ATTR_RADIUS;
|
||||
void *BKE_pointcloud_add(struct Main *bmain, const char *name);
|
||||
void *BKE_pointcloud_add_default(struct Main *bmain, const char *name);
|
||||
struct PointCloud *BKE_pointcloud_new_nomain(int totpoint);
|
||||
void BKE_pointcloud_nomain_to_pointcloud(struct PointCloud *pointcloud_src,
|
||||
struct PointCloud *pointcloud_dst,
|
||||
bool take_ownership);
|
||||
|
||||
struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob);
|
||||
bool BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]);
|
||||
|
@@ -29,12 +29,7 @@
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
typedef struct DomainInfo {
|
||||
CustomData *customdata;
|
||||
int length;
|
||||
} DomainInfo;
|
||||
|
||||
static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
|
||||
void BKE_id_attribute_get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
|
||||
{
|
||||
memset(info, 0, sizeof(DomainInfo) * ATTR_DOMAIN_NUM);
|
||||
|
||||
@@ -87,7 +82,7 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
|
||||
static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
BKE_id_attribute_get_domains(id, info);
|
||||
|
||||
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
||||
CustomData *customdata = info[domain].customdata;
|
||||
@@ -102,7 +97,7 @@ static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer)
|
||||
bool BKE_id_attributes_supported(struct ID *id)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
BKE_id_attribute_get_domains(id, info);
|
||||
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
||||
if (info[domain].customdata) {
|
||||
return true;
|
||||
@@ -136,7 +131,7 @@ CustomDataLayer *BKE_id_attribute_new(
|
||||
ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
BKE_id_attribute_get_domains(id, info);
|
||||
|
||||
CustomData *customdata = info[domain].customdata;
|
||||
if (customdata == NULL) {
|
||||
@@ -212,7 +207,7 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
|
||||
const AttributeDomain domain)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
BKE_id_attribute_get_domains(id, info);
|
||||
|
||||
CustomData *customdata = info[domain].customdata;
|
||||
if (customdata == NULL) {
|
||||
@@ -229,10 +224,22 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CustomDataLayer *BKE_id_attribute_ensure(
|
||||
ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
|
||||
{
|
||||
CustomDataLayer *layer = BKE_id_attribute_find(id, name, type, domain);
|
||||
|
||||
if (layer) {
|
||||
return layer;
|
||||
}
|
||||
|
||||
return BKE_id_attribute_new(id, name, type, domain, reports);
|
||||
}
|
||||
|
||||
int BKE_id_attributes_length(ID *id, const CustomDataMask mask)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
BKE_id_attribute_get_domains(id, info);
|
||||
|
||||
int length = 0;
|
||||
|
||||
@@ -249,7 +256,7 @@ int BKE_id_attributes_length(ID *id, const CustomDataMask mask)
|
||||
AttributeDomain BKE_id_attribute_domain(ID *id, CustomDataLayer *layer)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
BKE_id_attribute_get_domains(id, info);
|
||||
|
||||
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
||||
CustomData *customdata = info[domain].customdata;
|
||||
@@ -265,7 +272,7 @@ AttributeDomain BKE_id_attribute_domain(ID *id, CustomDataLayer *layer)
|
||||
int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
BKE_id_attribute_get_domains(id, info);
|
||||
|
||||
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
|
||||
CustomData *customdata = info[domain].customdata;
|
||||
@@ -300,7 +307,7 @@ CustomDataLayer *BKE_id_attributes_active_get(ID *id)
|
||||
}
|
||||
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
BKE_id_attribute_get_domains(id, info);
|
||||
|
||||
int index = 0;
|
||||
|
||||
@@ -325,7 +332,7 @@ CustomDataLayer *BKE_id_attributes_active_get(ID *id)
|
||||
void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
BKE_id_attribute_get_domains(id, info);
|
||||
|
||||
int index = 0;
|
||||
|
||||
@@ -366,7 +373,7 @@ int *BKE_id_attributes_active_index_p(ID *id)
|
||||
CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *layers)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
BKE_id_attribute_get_domains(id, info);
|
||||
|
||||
bool use_next = (layers == NULL);
|
||||
|
||||
|
@@ -73,6 +73,7 @@ static void cache_file_copy_data(Main *UNUSED(bmain),
|
||||
cache_file_dst->handle_readers = NULL;
|
||||
BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_src->object_paths);
|
||||
BLI_duplicatelist(&cache_file_dst->layers, &cache_file_src->layers);
|
||||
BLI_duplicatelist(&cache_file_dst->attribute_mappings, &cache_file_src->attribute_mappings);
|
||||
}
|
||||
|
||||
static void cache_file_free_data(ID *id)
|
||||
@@ -81,6 +82,7 @@ static void cache_file_free_data(ID *id)
|
||||
cachefile_handle_free(cache_file);
|
||||
BLI_freelistN(&cache_file->object_paths);
|
||||
BLI_freelistN(&cache_file->layers);
|
||||
BLI_freelistN(&cache_file->attribute_mappings);
|
||||
}
|
||||
|
||||
static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
|
||||
@@ -110,6 +112,11 @@ static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_a
|
||||
LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) {
|
||||
BLO_write_struct(writer, CacheFileLayer, layer);
|
||||
}
|
||||
|
||||
/* write attribute mappings */
|
||||
LISTBASE_FOREACH (CacheAttributeMapping *, mapping, &cache_file->attribute_mappings) {
|
||||
BLO_write_struct(writer, CacheAttributeMapping, mapping);
|
||||
}
|
||||
}
|
||||
|
||||
static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
|
||||
@@ -126,6 +133,9 @@ static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
|
||||
|
||||
/* relink layers */
|
||||
BLO_read_list(reader, &cache_file->layers);
|
||||
|
||||
/* relink attribute mappings */
|
||||
BLO_read_list(reader, &cache_file->attribute_mappings);
|
||||
}
|
||||
|
||||
IDTypeInfo IDType_ID_CF = {
|
||||
@@ -464,3 +474,38 @@ void BKE_cachefile_remove_layer(CacheFile *cache_file, CacheFileLayer *layer)
|
||||
BLI_remlink(&cache_file->layers, layer);
|
||||
MEM_freeN(layer);
|
||||
}
|
||||
|
||||
CacheAttributeMapping *BKE_cachefile_add_attribute_mapping(CacheFile *cache_file,
|
||||
const char *name,
|
||||
const int mapping_type,
|
||||
const int domain)
|
||||
{
|
||||
const int current_mapping_count = BLI_listbase_count(&cache_file->attribute_mappings);
|
||||
|
||||
CacheAttributeMapping *mapping = MEM_callocN(sizeof(CacheAttributeMapping),
|
||||
"CacheAttributeMapping");
|
||||
|
||||
if (name) {
|
||||
BLI_strncpy(mapping->name, name, sizeof(mapping->name));
|
||||
}
|
||||
mapping->mapping = (char)mapping_type;
|
||||
mapping->domain = (char)domain;
|
||||
|
||||
BLI_addtail(&cache_file->attribute_mappings, mapping);
|
||||
|
||||
cache_file->active_attribute_mapping = current_mapping_count + 1;
|
||||
return mapping;
|
||||
}
|
||||
|
||||
CacheAttributeMapping *BKE_cachefile_get_active_attribute_mapping(CacheFile *cache_file)
|
||||
{
|
||||
/* BLI_findlink handles the out of bounds checks. */
|
||||
return BLI_findlink(&cache_file->attribute_mappings, cache_file->active_attribute_mapping - 1);
|
||||
}
|
||||
|
||||
void BKE_cachefile_remove_attribute_mapping(CacheFile *cache_file, CacheAttributeMapping *mapping)
|
||||
{
|
||||
cache_file->active_attribute_mapping = 0;
|
||||
BLI_remlink(&cache_file->attribute_mappings, mapping);
|
||||
MEM_freeN(mapping);
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "BKE_anim_data.h"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_idtype.h"
|
||||
#include "BKE_lib_id.h"
|
||||
@@ -308,8 +309,15 @@ static Curves *curves_evaluate_modifiers(struct Depsgraph *depsgraph,
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((mti->type == eModifierTypeType_OnlyDeform) &&
|
||||
(mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
|
||||
if (mti->modifyGeometrySet) {
|
||||
GeometrySet geometry_set = GeometrySet::create_with_curves(curves,
|
||||
GeometryOwnershipType::ReadOnly);
|
||||
mti->modifyGeometrySet(md, &mectx, &geometry_set);
|
||||
|
||||
curves = geometry_set.get_component_for_write<CurveComponent>().release();
|
||||
}
|
||||
else if ((mti->type == eModifierTypeType_OnlyDeform) &&
|
||||
(mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
|
||||
/* Ensure we are not modifying the input. */
|
||||
if (curves == curves_input) {
|
||||
curves = BKE_curves_copy_for_eval(curves, true);
|
||||
|
@@ -812,12 +812,12 @@ static bool do_curve_implicit_mesh_conversion(const Curve *curve,
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If a non-geometry-nodes modifier is enabled before a nodes modifier,
|
||||
* force conversion to mesh, since only the nodes modifier supports curve data. */
|
||||
/* If a modifier which does not support curve data is enabled before one that does,
|
||||
* force conversion to mesh. */
|
||||
ModifierData *md = first_modifier;
|
||||
for (; md; md = md->next) {
|
||||
if (BKE_modifier_is_enabled(scene, md, required_mode)) {
|
||||
if (md->type == eModifierType_Nodes) {
|
||||
if (BKE_modifier_supports_curve_data(md)) {
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
@@ -874,7 +874,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (md->type == eModifierType_Nodes) {
|
||||
if (BKE_modifier_supports_curve_data(md)) {
|
||||
mti->modifyGeometrySet(md, &mectx_apply, &geometry_set);
|
||||
continue;
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_cloth_types.h"
|
||||
#include "DNA_dynamicpaint_types.h"
|
||||
#include "DNA_fluid_types.h"
|
||||
@@ -1518,3 +1519,27 @@ void BKE_modifier_blend_read_lib(BlendLibReader *reader, Object *ob)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BKE_modifier_supports_curve_data(const ModifierData *md)
|
||||
{
|
||||
/* Sanity check. */
|
||||
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
|
||||
if (mti->modifyGeometrySet == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (md->type == eModifierType_Nodes) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* For the MeshSequenceCache, only the Alembic backend supports directly reading/modifying
|
||||
* curves.
|
||||
*/
|
||||
if (md->type == eModifierType_MeshSequenceCache) {
|
||||
MeshSeqCacheModifierData *msmd = (MeshSeqCacheModifierData *)md;
|
||||
CacheFile *cache_file = msmd->cache_file;
|
||||
return cache_file && cache_file->type == CACHEFILE_TYPE_ALEMBIC;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -255,6 +255,52 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
|
||||
return pointcloud;
|
||||
}
|
||||
|
||||
void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src,
|
||||
PointCloud *pointcloud_dst,
|
||||
bool take_ownership)
|
||||
{
|
||||
BLI_assert(pointcloud_src->id.tag & LIB_TAG_NO_MAIN);
|
||||
|
||||
/* pointcloud_src might depend on pointcloud_dst, so we need to do everything with a local copy
|
||||
*/
|
||||
PointCloud tmp = *pointcloud_dst;
|
||||
eCDAllocType alloctype = CD_DUPLICATE;
|
||||
|
||||
if (take_ownership) {
|
||||
bool has_any_referenced_layers = CustomData_has_referenced(&pointcloud_src->pdata);
|
||||
|
||||
if (!has_any_referenced_layers) {
|
||||
alloctype = CD_ASSIGN;
|
||||
}
|
||||
}
|
||||
|
||||
CustomData_reset(&tmp.pdata);
|
||||
|
||||
const CustomDataMask pmask = CD_MASK_ALL;
|
||||
|
||||
const int totpoint = tmp.totpoint = pointcloud_src->totpoint;
|
||||
CustomData_copy(&pointcloud_src->pdata, &tmp.pdata, pmask, alloctype, totpoint);
|
||||
|
||||
BKE_pointcloud_update_customdata_pointers(&tmp);
|
||||
|
||||
CustomData_free(&pointcloud_dst->pdata, pointcloud_dst->totpoint);
|
||||
|
||||
/* skip the listbase */
|
||||
MEMCPY_STRUCT_AFTER(pointcloud_dst, &tmp, id.prev);
|
||||
|
||||
if (take_ownership) {
|
||||
if (alloctype == CD_ASSIGN) {
|
||||
CustomData_free_typemask(&pointcloud_src->pdata, pointcloud_src->totpoint, ~pmask);
|
||||
}
|
||||
BKE_id_free(nullptr, pointcloud_src);
|
||||
}
|
||||
}
|
||||
|
||||
struct MinMaxResult {
|
||||
float3 min;
|
||||
float3 max;
|
||||
};
|
||||
|
||||
static std::optional<blender::bounds::MinMaxResult<float3>> point_cloud_bounds(
|
||||
const PointCloud &pointcloud)
|
||||
{
|
||||
|
@@ -2419,6 +2419,13 @@ void uiTemplateCacheFileLayers(uiLayout *layout,
|
||||
const struct bContext *C,
|
||||
struct PointerRNA *fileptr);
|
||||
|
||||
/**
|
||||
* Draw the attribute remapping related properties of the CacheFile.
|
||||
*/
|
||||
void uiTemplateCacheFileAttributeRemapping(uiLayout *layout,
|
||||
const struct bContext *C,
|
||||
struct PointerRNA *fileptr);
|
||||
|
||||
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
|
||||
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
|
||||
enum uiTemplateListFlags {
|
||||
|
@@ -1477,6 +1477,9 @@ void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot);
|
||||
|
||||
struct uiListType *UI_UL_asset_view(void);
|
||||
|
||||
/* interface_templates.c */
|
||||
struct uiListType *UI_UL_cache_file_attribute_mappings(void);
|
||||
|
||||
/**
|
||||
* For use with #ui_rna_collection_search_update_fn.
|
||||
*/
|
||||
|
@@ -1309,6 +1309,7 @@ void ED_uilisttypes_ui()
|
||||
{
|
||||
WM_uilisttype_add(UI_UL_asset_view());
|
||||
WM_uilisttype_add(UI_UL_cache_file_layers());
|
||||
WM_uilisttype_add(UI_UL_cache_file_attribute_mappings());
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -6505,6 +6505,63 @@ bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRN
|
||||
return true;
|
||||
}
|
||||
|
||||
static void cache_file_attribute_mapping_item(uiList *UNUSED(ui_list),
|
||||
bContext *UNUSED(C),
|
||||
uiLayout *layout,
|
||||
PointerRNA *UNUSED(dataptr),
|
||||
PointerRNA *itemptr,
|
||||
int UNUSED(icon),
|
||||
PointerRNA *UNUSED(active_dataptr),
|
||||
const char *UNUSED(active_propname),
|
||||
int UNUSED(index),
|
||||
int UNUSED(flt_flag))
|
||||
{
|
||||
uiLayout *row = uiLayoutRow(layout, true);
|
||||
uiItemR(row, itemptr, "name", UI_ITEM_R_NO_BG, "", ICON_NONE);
|
||||
uiItemR(row, itemptr, "mapping", UI_ITEM_R_NO_BG, "", ICON_NONE);
|
||||
uiItemR(row, itemptr, "domain", UI_ITEM_R_NO_BG, "", ICON_NONE);
|
||||
}
|
||||
|
||||
uiListType *UI_UL_cache_file_attribute_mappings()
|
||||
{
|
||||
uiListType *list_type = (uiListType *)MEM_callocN(sizeof(*list_type), __func__);
|
||||
|
||||
BLI_strncpy(list_type->idname, "UI_UL_cache_file_attribute_mappings", sizeof(list_type->idname));
|
||||
list_type->draw_item = cache_file_attribute_mapping_item;
|
||||
|
||||
return list_type;
|
||||
}
|
||||
|
||||
void uiTemplateCacheFileAttributeRemapping(uiLayout *layout,
|
||||
const bContext *C,
|
||||
PointerRNA *fileptr)
|
||||
{
|
||||
/* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
|
||||
uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
|
||||
|
||||
uiLayout *row = uiLayoutRow(layout, false);
|
||||
uiLayout *col = uiLayoutColumn(row, true);
|
||||
|
||||
uiTemplateList(col,
|
||||
(bContext *)C,
|
||||
"UI_UL_cache_file_attribute_mappings",
|
||||
"cache_file_attribute_mappings",
|
||||
fileptr,
|
||||
"attribute_mappings",
|
||||
fileptr,
|
||||
"active_attribute_mapping_index",
|
||||
"",
|
||||
1,
|
||||
5,
|
||||
UILST_LAYOUT_DEFAULT,
|
||||
1,
|
||||
UI_TEMPLATE_LIST_FLAG_NONE);
|
||||
|
||||
col = uiLayoutColumn(row, true);
|
||||
uiItemO(col, "", ICON_ADD, "cachefile.attribute_mapping_add");
|
||||
uiItemO(col, "", ICON_REMOVE, "cachefile.attribute_mapping_remove");
|
||||
}
|
||||
|
||||
void uiTemplateCacheFile(uiLayout *layout,
|
||||
const bContext *C,
|
||||
PointerRNA *ptr,
|
||||
|
@@ -312,3 +312,78 @@ void CACHEFILE_OT_layer_move(wmOperatorType *ot)
|
||||
"Direction",
|
||||
"Direction to move the active vertex group towards");
|
||||
}
|
||||
|
||||
/* ***************************** Add Attribute Mapping Operator **************************** */
|
||||
|
||||
static bool cachefile_attribute_mapping_poll(bContext *C)
|
||||
{
|
||||
return CTX_data_edit_cachefile(C) != NULL;
|
||||
}
|
||||
|
||||
static int cachefile_attribute_mapping_add_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
CacheFile *cache_file = CTX_data_edit_cachefile(C);
|
||||
|
||||
if (!cache_file) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_cachefile_add_attribute_mapping(
|
||||
cache_file, NULL, CACHEFILE_ATTRIBUTE_MAP_NONE, CACHEFILE_ATTR_MAP_DOMAIN_AUTO);
|
||||
|
||||
/* Since the mapping is not initialized, adding a mapping does not trigger a CacheFile update. */
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void CACHEFILE_OT_attribute_mapping_add(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Add Attribute Mapping";
|
||||
ot->description = "Add an attribute mapping for this CacheFile";
|
||||
ot->idname = __func__;
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = cachefile_attribute_mapping_add_exec;
|
||||
ot->poll = cachefile_attribute_mapping_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ***************************** Remove Attribute Mapping Operator **************************** */
|
||||
|
||||
static int cachefile_attribute_mapping_remove_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
CacheFile *cache_file = CTX_data_edit_cachefile(C);
|
||||
|
||||
if (!cache_file) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
CacheAttributeMapping *mapping = BKE_cachefile_get_active_attribute_mapping(cache_file);
|
||||
|
||||
if (!mapping) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_cachefile_remove_attribute_mapping(cache_file, mapping);
|
||||
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
BKE_cachefile_reload(depsgraph, cache_file);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void CACHEFILE_OT_attribute_mapping_remove(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Remove Attribute Mapping";
|
||||
ot->description = "Remove an attribute mapping from this CacheFile";
|
||||
ot->idname = __func__;
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = cachefile_attribute_mapping_remove_exec;
|
||||
ot->poll = cachefile_attribute_mapping_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
@@ -15,3 +15,6 @@ void CACHEFILE_OT_reload(struct wmOperatorType *ot);
|
||||
void CACHEFILE_OT_layer_add(struct wmOperatorType *ot);
|
||||
void CACHEFILE_OT_layer_remove(struct wmOperatorType *ot);
|
||||
void CACHEFILE_OT_layer_move(struct wmOperatorType *ot);
|
||||
|
||||
void CACHEFILE_OT_attribute_mapping_add(struct wmOperatorType *ot);
|
||||
void CACHEFILE_OT_attribute_mapping_remove(struct wmOperatorType *ot);
|
||||
|
@@ -58,5 +58,8 @@ void ED_operatortypes_io(void)
|
||||
WM_operatortype_append(CACHEFILE_OT_layer_remove);
|
||||
WM_operatortype_append(CACHEFILE_OT_layer_move);
|
||||
|
||||
WM_operatortype_append(CACHEFILE_OT_attribute_mapping_add);
|
||||
WM_operatortype_append(CACHEFILE_OT_attribute_mapping_remove);
|
||||
|
||||
WM_operatortype_append(WM_OT_obj_export);
|
||||
}
|
||||
|
@@ -14,6 +14,8 @@ extern "C" {
|
||||
struct CacheArchiveHandle;
|
||||
struct CacheFileLayer;
|
||||
struct CacheReader;
|
||||
struct Curves;
|
||||
struct GeometrySet;
|
||||
struct ListBase;
|
||||
struct Main;
|
||||
struct Mesh;
|
||||
@@ -99,15 +101,23 @@ void ABC_get_transform(struct CacheReader *reader,
|
||||
float time,
|
||||
float scale);
|
||||
|
||||
/* Either modifies existing_mesh in-place or constructs a new mesh. */
|
||||
struct Mesh *ABC_read_mesh(struct CacheReader *reader,
|
||||
struct Object *ob,
|
||||
struct Mesh *existing_mesh,
|
||||
float time,
|
||||
const char **err_str,
|
||||
int read_flags,
|
||||
const char *velocity_name,
|
||||
float velocity_scale);
|
||||
typedef struct ABCReadParams {
|
||||
float time;
|
||||
int read_flags;
|
||||
const char *velocity_name;
|
||||
float velocity_scale;
|
||||
|
||||
ListBase *mappings;
|
||||
} ABCReadParams;
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* Either modifies the existing geometry component, or create a new one. */
|
||||
void ABC_read_geometry(CacheReader *reader,
|
||||
Object *ob,
|
||||
GeometrySet &geometry_set,
|
||||
const ABCReadParams *params,
|
||||
const char **err_str);
|
||||
#endif
|
||||
|
||||
bool ABC_mesh_topology_changed(struct CacheReader *reader,
|
||||
struct Object *ob,
|
||||
|
@@ -7,9 +7,11 @@ set(INC
|
||||
../../blenkernel
|
||||
../../blenlib
|
||||
../../blenloader
|
||||
../../blentranslation
|
||||
../../bmesh
|
||||
../../depsgraph
|
||||
../../editors/include
|
||||
../../functions
|
||||
../../makesdna
|
||||
../../makesrna
|
||||
../../windowmanager
|
||||
@@ -30,6 +32,8 @@ set(SRC
|
||||
intern/abc_reader_archive.cc
|
||||
intern/abc_reader_camera.cc
|
||||
intern/abc_reader_curves.cc
|
||||
intern/abc_reader_instance.cc
|
||||
intern/abc_reader_manager.cc
|
||||
intern/abc_reader_mesh.cc
|
||||
intern/abc_reader_nurbs.cc
|
||||
intern/abc_reader_object.cc
|
||||
@@ -60,6 +64,8 @@ set(SRC
|
||||
intern/abc_reader_archive.h
|
||||
intern/abc_reader_camera.h
|
||||
intern/abc_reader_curves.h
|
||||
intern/abc_reader_instance.h
|
||||
intern/abc_reader_manager.h
|
||||
intern/abc_reader_mesh.h
|
||||
intern/abc_reader_nurbs.h
|
||||
intern/abc_reader_object.h
|
||||
|
@@ -76,6 +76,12 @@ static void get_loop_normals(struct Mesh *mesh,
|
||||
ABCGenericMeshWriter::ABCGenericMeshWriter(const ABCWriterConstructorArgs &args)
|
||||
: ABCAbstractWriter(args), is_subd_(false)
|
||||
{
|
||||
attribute_exporter_ = nullptr;
|
||||
}
|
||||
|
||||
ABCGenericMeshWriter::~ABCGenericMeshWriter()
|
||||
{
|
||||
delete_attribute_exporter(attribute_exporter_);
|
||||
}
|
||||
|
||||
void ABCGenericMeshWriter::create_alembic_objects(const HierarchyContext *context)
|
||||
@@ -254,10 +260,6 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
|
||||
mesh_sample.setNormals(normals_sample);
|
||||
}
|
||||
|
||||
if (args_.export_params->orcos) {
|
||||
write_generated_coordinates(abc_poly_mesh_schema_.getArbGeomParams(), m_custom_data_config);
|
||||
}
|
||||
|
||||
if (get_velocities(mesh, velocities)) {
|
||||
mesh_sample.setVelocities(V3fArraySample(velocities));
|
||||
}
|
||||
@@ -266,7 +268,6 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
|
||||
mesh_sample.setSelfBounds(bounding_box_);
|
||||
|
||||
abc_poly_mesh_schema_.set(mesh_sample);
|
||||
|
||||
write_arb_geo_params(mesh);
|
||||
}
|
||||
|
||||
@@ -308,10 +309,6 @@ void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *me
|
||||
abc_subdiv_schema_.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV);
|
||||
}
|
||||
|
||||
if (args_.export_params->orcos) {
|
||||
write_generated_coordinates(abc_subdiv_schema_.getArbGeomParams(), m_custom_data_config);
|
||||
}
|
||||
|
||||
if (!edge_crease_indices.empty()) {
|
||||
subdiv_sample.setCreaseIndices(Int32ArraySample(edge_crease_indices));
|
||||
subdiv_sample.setCreaseLengths(Int32ArraySample(edge_crease_lengths));
|
||||
@@ -347,8 +344,15 @@ void ABCGenericMeshWriter::write_face_sets(Object *object, struct Mesh *mesh, Sc
|
||||
|
||||
void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me)
|
||||
{
|
||||
int64_t cd_mask = CD_MASK_ALL;
|
||||
if (!args_.export_params->vcolors) {
|
||||
return;
|
||||
cd_mask &= ~CD_MASK_MCOL;
|
||||
}
|
||||
if (!args_.export_params->uvs) {
|
||||
cd_mask &= ~CD_MASK_MLOOPUV;
|
||||
}
|
||||
if (!args_.export_params->orcos) {
|
||||
cd_mask &= ~CD_MASK_ORCO;
|
||||
}
|
||||
|
||||
OCompoundProperty arb_geom_params;
|
||||
@@ -358,7 +362,13 @@ void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me)
|
||||
else {
|
||||
arb_geom_params = abc_poly_mesh_.getSchema().getArbGeomParams();
|
||||
}
|
||||
write_custom_data(arb_geom_params, m_custom_data_config, &me->ldata, CD_MLOOPCOL);
|
||||
|
||||
if (!attribute_exporter_) {
|
||||
attribute_exporter_ = make_attribute_exporter(&me->id, cd_mask, arb_geom_params);
|
||||
}
|
||||
|
||||
set_timesample_index(attribute_exporter_, m_custom_data_config.timesample_index);
|
||||
attribute_exporter_->export_attributes();
|
||||
}
|
||||
|
||||
bool ABCGenericMeshWriter::get_velocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels)
|
||||
|
@@ -34,9 +34,13 @@ class ABCGenericMeshWriter : public ABCAbstractWriter {
|
||||
|
||||
CDStreamConfig m_custom_data_config;
|
||||
|
||||
GenericAttributeExporter *attribute_exporter_;
|
||||
|
||||
public:
|
||||
explicit ABCGenericMeshWriter(const ABCWriterConstructorArgs &args);
|
||||
|
||||
~ABCGenericMeshWriter();
|
||||
|
||||
virtual void create_alembic_objects(const HierarchyContext *context) override;
|
||||
virtual Alembic::Abc::OObject get_alembic_object() const override;
|
||||
Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override;
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -11,17 +11,29 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_listbase_wrapper.hh"
|
||||
#include "BLI_math_vec_types.hh"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
struct CacheAttributeMapping;
|
||||
struct CustomData;
|
||||
struct ID;
|
||||
struct MLoop;
|
||||
struct MLoopUV;
|
||||
struct MPoly;
|
||||
struct MVert;
|
||||
struct Mesh;
|
||||
struct MCol;
|
||||
|
||||
using Alembic::Abc::ICompoundProperty;
|
||||
using Alembic::Abc::OCompoundProperty;
|
||||
namespace blender::io::alembic {
|
||||
|
||||
class AttributeSelector;
|
||||
|
||||
struct UVSample {
|
||||
std::vector<Imath::V2f> uvs;
|
||||
std::vector<uint32_t> indices;
|
||||
@@ -43,10 +55,12 @@ struct CDStreamConfig {
|
||||
|
||||
bool pack_uvs;
|
||||
|
||||
/* TODO(kevin): might need a better way to handle adding and/or updating
|
||||
* custom data such that it updates the custom data holder and its pointers properly. */
|
||||
/* NOTE: the mesh is mostly used for iterating over loops for loop attributes (UVs, MCol, etc.).
|
||||
* It would be nice to remove it, in favor of a more generic way to iterate valid attribute
|
||||
* indices.
|
||||
*/
|
||||
Mesh *mesh;
|
||||
void *(*add_customdata_cb)(Mesh *mesh, const char *name, int data_type);
|
||||
ID *id;
|
||||
|
||||
float weight;
|
||||
float time;
|
||||
@@ -57,6 +71,13 @@ struct CDStreamConfig {
|
||||
|
||||
const char **modifier_error_message;
|
||||
|
||||
DomainInfo domain_info[ATTR_DOMAIN_NUM];
|
||||
|
||||
/* For error reporting when reading vertex colors. */
|
||||
std::string iobject_full_name;
|
||||
|
||||
const AttributeSelector *attr_selector;
|
||||
|
||||
/* Alembic needs Blender to keep references to C++ objects (the destructors finalize the writing
|
||||
* to ABC). The following fields are all used to keep these references. */
|
||||
|
||||
@@ -78,12 +99,12 @@ struct CDStreamConfig {
|
||||
totvert(0),
|
||||
pack_uvs(false),
|
||||
mesh(NULL),
|
||||
add_customdata_cb(NULL),
|
||||
weight(0.0f),
|
||||
time(0.0f),
|
||||
index(0),
|
||||
ceil_index(0),
|
||||
modifier_error_message(NULL)
|
||||
modifier_error_message(NULL),
|
||||
attr_selector(nullptr)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -94,38 +115,126 @@ struct CDStreamConfig {
|
||||
* For now the active layer is used, maybe needs a better way to choose this. */
|
||||
const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data);
|
||||
|
||||
void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config);
|
||||
|
||||
void read_generated_coordinates(const ICompoundProperty &prop,
|
||||
const CDStreamConfig &config,
|
||||
const Alembic::Abc::ISampleSelector &iss);
|
||||
|
||||
void write_custom_data(const OCompoundProperty &prop,
|
||||
CDStreamConfig &config,
|
||||
CustomData *data,
|
||||
int data_type);
|
||||
|
||||
void read_custom_data(const std::string &iobject_full_name,
|
||||
const ICompoundProperty &prop,
|
||||
const CDStreamConfig &config,
|
||||
const Alembic::Abc::ISampleSelector &iss);
|
||||
|
||||
typedef enum {
|
||||
ABC_UV_SCOPE_NONE,
|
||||
ABC_UV_SCOPE_LOOP,
|
||||
ABC_UV_SCOPE_VERTEX,
|
||||
} AbcUvScope;
|
||||
|
||||
/**
|
||||
* UVs can be defined per-loop (one value per vertex per face), or per-vertex (one value per
|
||||
* vertex). The first case is the most common, as this is the standard way of storing this data
|
||||
* given that some vertices might be on UV seams and have multiple possible UV coordinates; the
|
||||
* second case can happen when the mesh is split according to the UV islands, in which case storing
|
||||
* a single UV value per vertex allows to de-duplicate data and thus to reduce the file size since
|
||||
* vertices are guaranteed to only have a single UV coordinate.
|
||||
/* Need special handling for:
|
||||
* - creases (vertex/edge)
|
||||
* - velocity
|
||||
* - generated coordinate
|
||||
* - UVs
|
||||
* - vertex colors
|
||||
*/
|
||||
AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
|
||||
const CDStreamConfig &config,
|
||||
const Alembic::AbcGeom::UInt32ArraySamplePtr &indices);
|
||||
class GenericAttributeExporter {
|
||||
ID *m_id;
|
||||
int64_t cd_mask = CD_MASK_ALL;
|
||||
|
||||
public:
|
||||
GenericAttributeExporter(ID *id, int64_t cd_mask_) : m_id(id), cd_mask(cd_mask_)
|
||||
{
|
||||
}
|
||||
|
||||
void export_attributes();
|
||||
|
||||
protected:
|
||||
virtual void export_attribute(blender::Span<bool> span,
|
||||
const std::string &name,
|
||||
AttributeDomain domain) = 0;
|
||||
|
||||
virtual void export_attribute(blender::Span<char> span,
|
||||
const std::string &name,
|
||||
AttributeDomain domain) = 0;
|
||||
|
||||
virtual void export_attribute(blender::Span<int> span,
|
||||
const std::string &name,
|
||||
AttributeDomain domain) = 0;
|
||||
|
||||
virtual void export_attribute(blender::Span<float> span,
|
||||
const std::string &name,
|
||||
AttributeDomain domain) = 0;
|
||||
|
||||
virtual void export_attribute(blender::Span<float2> span,
|
||||
const std::string &name,
|
||||
AttributeDomain domain) = 0;
|
||||
|
||||
virtual void export_attribute(blender::Span<float3> span,
|
||||
const std::string &name,
|
||||
AttributeDomain domain) = 0;
|
||||
|
||||
virtual void export_attribute(blender::Span<ColorGeometry4f> span,
|
||||
const std::string &name,
|
||||
AttributeDomain domain) = 0;
|
||||
|
||||
virtual void export_attribute(blender::Span<MLoopUV> span,
|
||||
const std::string &name,
|
||||
AttributeDomain domain) = 0;
|
||||
|
||||
virtual void export_attribute(blender::Span<MCol> span,
|
||||
const std::string &name,
|
||||
AttributeDomain domain) = 0;
|
||||
|
||||
template<typename BlenderDataType>
|
||||
void export_customdata_layer(CustomDataLayer *layer, DomainInfo info, AttributeDomain domain)
|
||||
{
|
||||
BlenderDataType *data = static_cast<BlenderDataType *>(layer->data);
|
||||
int64_t size = static_cast<int64_t>(info.length);
|
||||
blender::Span<BlenderDataType> data_span(data, size);
|
||||
this->export_attribute(data_span, layer->name, domain);
|
||||
}
|
||||
|
||||
void export_generated_coordinates(CustomDataLayer *layer,
|
||||
DomainInfo info,
|
||||
AttributeDomain domain);
|
||||
|
||||
void export_attribute_for_domain(DomainInfo info, AttributeDomain domain);
|
||||
};
|
||||
|
||||
GenericAttributeExporter *make_attribute_exporter(ID *id,
|
||||
int64_t cd_mask,
|
||||
OCompoundProperty &prop);
|
||||
|
||||
void set_timesample_index(GenericAttributeExporter *exporter, int timesample_index);
|
||||
|
||||
void delete_attribute_exporter(GenericAttributeExporter *exporter);
|
||||
|
||||
class AttributeSelector {
|
||||
/* Name of the velocity attribute, it is ignored since we deal with separately. */
|
||||
std::string velocity_attribute = "";
|
||||
|
||||
int read_flags = 0;
|
||||
|
||||
ListBaseWrapper<const CacheAttributeMapping> mappings;
|
||||
|
||||
public:
|
||||
AttributeSelector(ListBase *mappings_) : mappings(mappings_)
|
||||
{
|
||||
}
|
||||
|
||||
void set_velocity_attribute(const char *name);
|
||||
|
||||
void set_read_flags(int flags);
|
||||
|
||||
const CacheAttributeMapping *get_mapping(const std::string &attr_name) const;
|
||||
|
||||
const std::string &velocity_name() const;
|
||||
|
||||
bool uvs_requested() const;
|
||||
|
||||
bool vertex_colors_requested() const;
|
||||
|
||||
bool original_coordinates_requested() const;
|
||||
|
||||
bool select_attribute(const std::string &attr_name) const;
|
||||
};
|
||||
|
||||
void read_arbitrary_attributes(const CDStreamConfig &config,
|
||||
const ICompoundProperty &schema,
|
||||
const Alembic::AbcGeom::IV2fGeomParam &primary_uvs,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
float velocity_scale);
|
||||
|
||||
bool has_animated_attributes(const ICompoundProperty &arb_geom_params);
|
||||
|
||||
} // namespace blender::io::alembic
|
||||
|
@@ -59,7 +59,9 @@ bool AbcCameraReader::accepts_object_type(
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbcCameraReader::readObjectData(Main *bmain, const ISampleSelector &sample_sel)
|
||||
void AbcCameraReader::readObjectData(Main *bmain,
|
||||
const AbcReaderManager & /*manager*/,
|
||||
const ISampleSelector &sample_sel)
|
||||
{
|
||||
Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, m_data_name.c_str()));
|
||||
|
||||
|
@@ -20,7 +20,9 @@ class AbcCameraReader final : public AbcObjectReader {
|
||||
const Object *const ob,
|
||||
const char **err_str) const override;
|
||||
|
||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
void readObjectData(Main *bmain,
|
||||
const AbcReaderManager &manager,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
};
|
||||
|
||||
} // namespace blender::io::alembic
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "abc_reader_curves.h"
|
||||
#include "abc_axis_conversion.h"
|
||||
#include "abc_customdata.h"
|
||||
#include "abc_reader_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
@@ -14,14 +15,17 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_curves_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_curves.h"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_spline.hh"
|
||||
|
||||
using Alembic::Abc::FloatArraySamplePtr;
|
||||
using Alembic::Abc::Int32ArraySamplePtr;
|
||||
@@ -66,7 +70,7 @@ bool AbcCurveReader::accepts_object_type(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ob->type != OB_CURVES_LEGACY) {
|
||||
if (ob->type != OB_CURVES) {
|
||||
*err_str = "Object type mismatch, Alembic object path points to Curves.";
|
||||
return false;
|
||||
}
|
||||
@@ -74,36 +78,234 @@ bool AbcCurveReader::accepts_object_type(
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
|
||||
void AbcCurveReader::readObjectData(Main *bmain,
|
||||
const AbcReaderManager & /*manager*/,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||
{
|
||||
Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVES_LEGACY);
|
||||
Curves *curves = static_cast<Curves *>(BKE_curves_add(bmain, m_data_name.c_str()));
|
||||
|
||||
cu->flag |= CU_3D;
|
||||
cu->actvert = CU_ACT_NONE;
|
||||
cu->resolu = 1;
|
||||
m_object = BKE_object_add_only_object(bmain, OB_CURVES, m_object_name.c_str());
|
||||
m_object->data = curves;
|
||||
|
||||
ICompoundProperty user_props = m_curves_schema.getUserProperties();
|
||||
if (user_props) {
|
||||
const PropertyHeader *header = user_props.getPropertyHeader(ABC_CURVE_RESOLUTION_U_PROPNAME);
|
||||
if (header != nullptr && header->isScalar() && IInt16Property::matches(*header)) {
|
||||
IInt16Property resolu(user_props, header->getName());
|
||||
cu->resolu = resolu.getValue(sample_sel);
|
||||
}
|
||||
}
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_CURVES_LEGACY, m_object_name.c_str());
|
||||
m_object->data = cu;
|
||||
|
||||
read_curve_sample(cu, m_curves_schema, sample_sel);
|
||||
read_curves_sample(curves, m_curves_schema, sample_sel);
|
||||
|
||||
if (m_settings->always_add_cache_reader || has_animations(m_curves_schema, m_settings)) {
|
||||
addCacheModifier();
|
||||
}
|
||||
}
|
||||
|
||||
void AbcCurveReader::read_curve_sample(Curve *cu,
|
||||
const ICurvesSchema &schema,
|
||||
const ISampleSelector &sample_sel)
|
||||
static short get_curve_resolution(const ICurvesSchema &schema,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||
{
|
||||
ICompoundProperty user_props = schema.getUserProperties();
|
||||
if (user_props) {
|
||||
const PropertyHeader *header = user_props.getPropertyHeader(ABC_CURVE_RESOLUTION_U_PROPNAME);
|
||||
if (header != nullptr && header->isScalar() && IInt16Property::matches(*header)) {
|
||||
IInt16Property resolu(user_props, header->getName());
|
||||
return resolu.getValue(sample_sel);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static short get_curve_order(Alembic::AbcGeom::CurveType abc_curve_type,
|
||||
const UcharArraySamplePtr orders,
|
||||
size_t curve_index)
|
||||
{
|
||||
switch (abc_curve_type) {
|
||||
case Alembic::AbcGeom::kCubic:
|
||||
return 4;
|
||||
case Alembic::AbcGeom::kVariableOrder:
|
||||
if (orders && orders->size() > curve_index) {
|
||||
return static_cast<short>((*orders)[curve_index]);
|
||||
}
|
||||
ATTR_FALLTHROUGH;
|
||||
case Alembic::AbcGeom::kLinear:
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_curve_overlap(Alembic::AbcGeom::CurvePeriodicity periodicity,
|
||||
const P3fArraySamplePtr positions,
|
||||
int idx,
|
||||
int num_verts,
|
||||
short order)
|
||||
{
|
||||
if (periodicity == Alembic::AbcGeom::kPeriodic) {
|
||||
/* Check the number of points which overlap, we don't have
|
||||
* overlapping points in Blender, but other software do use them to
|
||||
* indicate that a curve is actually cyclic. Usually the number of
|
||||
* overlapping points is equal to the order/degree of the curve.
|
||||
*/
|
||||
|
||||
const int start = idx;
|
||||
const int end = idx + num_verts;
|
||||
int overlap = 0;
|
||||
|
||||
for (int j = start, k = end - order; j < order; j++, k++) {
|
||||
const Imath::V3f &p1 = (*positions)[j];
|
||||
const Imath::V3f &p2 = (*positions)[k];
|
||||
|
||||
if (p1 != p2) {
|
||||
break;
|
||||
}
|
||||
|
||||
overlap++;
|
||||
}
|
||||
|
||||
/* TODO: Special case, need to figure out how it coincides with knots. */
|
||||
if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
|
||||
overlap = 1;
|
||||
}
|
||||
|
||||
/* There is no real cycles. */
|
||||
return overlap;
|
||||
}
|
||||
|
||||
/* kNonPeriodic is always assumed to have no overlap. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int abc_curves_get_total_point_size(const Int32ArraySamplePtr num_vertices)
|
||||
{
|
||||
if (!num_vertices) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
for (size_t i = 0; i < num_vertices->size(); i++) {
|
||||
result += (*num_vertices)[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void read_curves_sample_ex(Curves *curves,
|
||||
const ICurvesSchema &schema,
|
||||
const ICurvesSchema::Sample &smp,
|
||||
const ISampleSelector sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
const float velocity_scale,
|
||||
const char **err_str)
|
||||
{
|
||||
bke::CurvesGeometry &geometry = bke::CurvesGeometry::wrap(curves->geometry);
|
||||
MutableSpan<int> offsets = geometry.offsets();
|
||||
MutableSpan<float3> positions_ = geometry.positions();
|
||||
MutableSpan<bool> cyclic = geometry.cyclic();
|
||||
|
||||
float *curves_weights = nullptr;
|
||||
int *curves_orders = nullptr;
|
||||
|
||||
int *curves_resolution = static_cast<int *>(CustomData_add_layer_named(&geometry.curve_data,
|
||||
CD_PROP_INT32,
|
||||
CD_DEFAULT,
|
||||
nullptr,
|
||||
geometry.curve_size,
|
||||
"resolution"));
|
||||
|
||||
const int resolution = get_curve_resolution(schema, sample_sel);
|
||||
for (int64_t i : geometry.curves_range()) {
|
||||
curves_resolution[i] = resolution;
|
||||
}
|
||||
|
||||
if (!geometry.radius) {
|
||||
geometry.radius = static_cast<float *>(CustomData_add_layer_named(
|
||||
&geometry.point_data, CD_PROP_FLOAT, CD_DEFAULT, nullptr, geometry.point_size, "radius"));
|
||||
}
|
||||
|
||||
/* Knots are not imported anymore. */
|
||||
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
|
||||
const P3fArraySamplePtr positions = smp.getPositions();
|
||||
const FloatArraySamplePtr weights = smp.getPositionWeights();
|
||||
const CurvePeriodicity periodicity = smp.getWrap();
|
||||
const UcharArraySamplePtr orders = smp.getOrders();
|
||||
|
||||
const IFloatGeomParam widths_param = schema.getWidthsParam();
|
||||
FloatArraySamplePtr radiuses;
|
||||
|
||||
if (widths_param.valid()) {
|
||||
IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
|
||||
radiuses = wsample.getVals();
|
||||
}
|
||||
|
||||
const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
|
||||
float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f;
|
||||
|
||||
const bool do_weights = (weights != nullptr) && (weights->size() > 1);
|
||||
if (do_weights) {
|
||||
curves_weights = static_cast<float *>(CustomData_add_layer_named(&geometry.point_data,
|
||||
CD_PROP_FLOAT,
|
||||
CD_DEFAULT,
|
||||
nullptr,
|
||||
geometry.point_size,
|
||||
"nurbs_weight"));
|
||||
}
|
||||
|
||||
const bool do_curves_orders = (orders != nullptr) && (orders->size() > 1);
|
||||
if (do_curves_orders) {
|
||||
curves_orders = static_cast<int *>(CustomData_add_layer_named(&geometry.curve_data,
|
||||
CD_PROP_INT32,
|
||||
CD_DEFAULT,
|
||||
nullptr,
|
||||
geometry.curve_size,
|
||||
"nurbs_order"));
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
size_t position_offset = 0;
|
||||
for (size_t i = 0; i < num_vertices->size(); i++) {
|
||||
const int num_verts = (*num_vertices)[i];
|
||||
offsets[i] = offset;
|
||||
|
||||
const int curve_order = get_curve_order(smp.getType(), orders, i);
|
||||
if (do_curves_orders) {
|
||||
curves_orders[i] = curve_order;
|
||||
}
|
||||
|
||||
/* Check if the curve is cyclic. */
|
||||
const int overlap = get_curve_overlap(
|
||||
periodicity, positions, position_offset, num_verts, curve_order);
|
||||
|
||||
const bool is_cyclic = overlap != 0;
|
||||
cyclic[i] = is_cyclic;
|
||||
|
||||
for (int j = 0; j < num_verts - overlap; j++, position_offset++) {
|
||||
const Imath::V3f &pos = (*positions)[position_offset];
|
||||
|
||||
copy_zup_from_yup(positions_[position_offset], pos.getValue());
|
||||
|
||||
if (do_radius) {
|
||||
radius = (*radiuses)[position_offset];
|
||||
}
|
||||
geometry.radius[position_offset] = radius;
|
||||
|
||||
if (do_weights) {
|
||||
curves_weights[position_offset] = (*weights)[position_offset];
|
||||
}
|
||||
}
|
||||
|
||||
offset += num_verts;
|
||||
/* Skip duplicate positions due to cyclicity. */
|
||||
position_offset += overlap;
|
||||
}
|
||||
|
||||
offsets[geometry.curve_size] = offset;
|
||||
|
||||
/* Attributes. */
|
||||
CDStreamConfig config;
|
||||
config.id = &curves->id;
|
||||
config.attr_selector = attribute_selector;
|
||||
config.time = sample_sel.getRequestedTime();
|
||||
config.modifier_error_message = err_str;
|
||||
BKE_id_attribute_get_domains(config.id, config.domain_info);
|
||||
|
||||
read_arbitrary_attributes(config, schema, {}, sample_sel, velocity_scale);
|
||||
}
|
||||
|
||||
void AbcCurveReader::read_curves_sample(Curves *curves,
|
||||
const ICurvesSchema &schema,
|
||||
const ISampleSelector &sample_sel)
|
||||
{
|
||||
ICurvesSchema::Sample smp;
|
||||
try {
|
||||
@@ -120,150 +322,22 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
|
||||
|
||||
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
|
||||
const P3fArraySamplePtr positions = smp.getPositions();
|
||||
const FloatArraySamplePtr weights = smp.getPositionWeights();
|
||||
const FloatArraySamplePtr knots = smp.getKnots();
|
||||
const CurvePeriodicity periodicity = smp.getWrap();
|
||||
const UcharArraySamplePtr orders = smp.getOrders();
|
||||
|
||||
const IFloatGeomParam widths_param = schema.getWidthsParam();
|
||||
FloatArraySamplePtr radiuses;
|
||||
const int point_size = abc_curves_get_total_point_size(num_vertices);
|
||||
const int curve_size = static_cast<int>(num_vertices->size());
|
||||
|
||||
if (widths_param.valid()) {
|
||||
IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
|
||||
radiuses = wsample.getVals();
|
||||
}
|
||||
bke::CurvesGeometry &geometry = bke::CurvesGeometry::wrap(curves->geometry);
|
||||
geometry.resize(point_size, curve_size);
|
||||
|
||||
int knot_offset = 0;
|
||||
|
||||
size_t idx = 0;
|
||||
for (size_t i = 0; i < num_vertices->size(); i++) {
|
||||
const int num_verts = (*num_vertices)[i];
|
||||
|
||||
Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
|
||||
nu->resolu = cu->resolu;
|
||||
nu->resolv = cu->resolv;
|
||||
nu->pntsu = num_verts;
|
||||
nu->pntsv = 1;
|
||||
nu->flag |= CU_SMOOTH;
|
||||
|
||||
switch (smp.getType()) {
|
||||
case Alembic::AbcGeom::kCubic:
|
||||
nu->orderu = 4;
|
||||
break;
|
||||
case Alembic::AbcGeom::kVariableOrder:
|
||||
if (orders && orders->size() > i) {
|
||||
nu->orderu = static_cast<short>((*orders)[i]);
|
||||
break;
|
||||
}
|
||||
ATTR_FALLTHROUGH;
|
||||
case Alembic::AbcGeom::kLinear:
|
||||
default:
|
||||
nu->orderu = 2;
|
||||
}
|
||||
|
||||
if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
|
||||
nu->flagu |= CU_NURB_ENDPOINT;
|
||||
}
|
||||
else if (periodicity == Alembic::AbcGeom::kPeriodic) {
|
||||
nu->flagu |= CU_NURB_CYCLIC;
|
||||
|
||||
/* Check the number of points which overlap, we don't have
|
||||
* overlapping points in Blender, but other software do use them to
|
||||
* indicate that a curve is actually cyclic. Usually the number of
|
||||
* overlapping points is equal to the order/degree of the curve.
|
||||
*/
|
||||
|
||||
const int start = idx;
|
||||
const int end = idx + num_verts;
|
||||
int overlap = 0;
|
||||
|
||||
for (int j = start, k = end - nu->orderu; j < nu->orderu; j++, k++) {
|
||||
const Imath::V3f &p1 = (*positions)[j];
|
||||
const Imath::V3f &p2 = (*positions)[k];
|
||||
|
||||
if (p1 != p2) {
|
||||
break;
|
||||
}
|
||||
|
||||
overlap++;
|
||||
}
|
||||
|
||||
/* TODO: Special case, need to figure out how it coincides with knots. */
|
||||
if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
|
||||
overlap = 1;
|
||||
}
|
||||
|
||||
/* There is no real cycles. */
|
||||
if (overlap == 0) {
|
||||
nu->flagu &= ~CU_NURB_CYCLIC;
|
||||
nu->flagu |= CU_NURB_ENDPOINT;
|
||||
}
|
||||
|
||||
nu->pntsu -= overlap;
|
||||
}
|
||||
|
||||
const bool do_weights = (weights != nullptr) && (weights->size() > 1);
|
||||
float weight = 1.0f;
|
||||
|
||||
const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
|
||||
float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f;
|
||||
|
||||
nu->type = CU_NURBS;
|
||||
|
||||
nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb"));
|
||||
BPoint *bp = nu->bp;
|
||||
|
||||
for (int j = 0; j < nu->pntsu; j++, bp++, idx++) {
|
||||
const Imath::V3f &pos = (*positions)[idx];
|
||||
|
||||
if (do_radius) {
|
||||
radius = (*radiuses)[idx];
|
||||
}
|
||||
|
||||
if (do_weights) {
|
||||
weight = (*weights)[idx];
|
||||
}
|
||||
|
||||
copy_zup_from_yup(bp->vec, pos.getValue());
|
||||
bp->vec[3] = weight;
|
||||
bp->f1 = SELECT;
|
||||
bp->radius = radius;
|
||||
bp->weight = 1.0f;
|
||||
}
|
||||
|
||||
if (knots && knots->size() != 0) {
|
||||
nu->knotsu = static_cast<float *>(
|
||||
MEM_callocN(KNOTSU(nu) * sizeof(float), "abc_setsplineknotsu"));
|
||||
|
||||
/* TODO: second check is temporary, for until the check for cycles is rock solid. */
|
||||
if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) {
|
||||
/* Skip first and last knots. */
|
||||
for (size_t i = 1; i < knots->size() - 1; i++) {
|
||||
nu->knotsu[i - 1] = (*knots)[knot_offset + i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* TODO: figure out how to use the knots array from other
|
||||
* software in this case. */
|
||||
BKE_nurb_knot_calc_u(nu);
|
||||
}
|
||||
|
||||
knot_offset += knots->size();
|
||||
}
|
||||
else {
|
||||
BKE_nurb_knot_calc_u(nu);
|
||||
}
|
||||
|
||||
BLI_addtail(BKE_curve_nurbs_get(cu), nu);
|
||||
}
|
||||
read_curves_sample_ex(curves, m_curves_schema, smp, sample_sel, nullptr, 0.0f, nullptr);
|
||||
}
|
||||
|
||||
Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
|
||||
const ISampleSelector &sample_sel,
|
||||
int /*read_flag*/,
|
||||
const char * /*velocity_name*/,
|
||||
const float /*velocity_scale*/,
|
||||
const char **err_str)
|
||||
void AbcCurveReader::read_geometry(GeometrySet &geometry_set,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
int /*read_flag*/,
|
||||
const float velocity_scale,
|
||||
const char **err_str)
|
||||
{
|
||||
ICurvesSchema::Sample sample;
|
||||
|
||||
@@ -277,61 +351,22 @@ Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
|
||||
m_curves_schema.getName().c_str(),
|
||||
sample_sel.getRequestedTime(),
|
||||
ex.what());
|
||||
return existing_mesh;
|
||||
return;
|
||||
}
|
||||
|
||||
const P3fArraySamplePtr &positions = sample.getPositions();
|
||||
const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices();
|
||||
const P3fArraySamplePtr positions = sample.getPositions();
|
||||
|
||||
int vertex_idx = 0;
|
||||
int curve_idx;
|
||||
Curve *curve = static_cast<Curve *>(m_object->data);
|
||||
Curves *curves = geometry_set.get_curves_for_write();
|
||||
|
||||
const int curve_count = BLI_listbase_count(&curve->nurb);
|
||||
bool same_topology = curve_count == num_vertices->size();
|
||||
const int point_size = abc_curves_get_total_point_size(num_vertices);
|
||||
const int curve_size = static_cast<int>(num_vertices->size());
|
||||
|
||||
if (same_topology) {
|
||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
||||
for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
|
||||
const int num_in_alembic = (*num_vertices)[curve_idx];
|
||||
const int num_in_blender = nurbs->pntsu;
|
||||
bke::CurvesGeometry &geometry = bke::CurvesGeometry::wrap(curves->geometry);
|
||||
geometry.resize(point_size, curve_size);
|
||||
|
||||
if (num_in_alembic != num_in_blender) {
|
||||
same_topology = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!same_topology) {
|
||||
BKE_nurbList_free(&curve->nurb);
|
||||
read_curve_sample(curve, m_curves_schema, sample_sel);
|
||||
}
|
||||
else {
|
||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
||||
for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
|
||||
const int totpoint = (*num_vertices)[curve_idx];
|
||||
|
||||
if (nurbs->bp) {
|
||||
BPoint *point = nurbs->bp;
|
||||
|
||||
for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
|
||||
const Imath::V3f &pos = (*positions)[vertex_idx];
|
||||
copy_zup_from_yup(point->vec, pos.getValue());
|
||||
}
|
||||
}
|
||||
else if (nurbs->bezt) {
|
||||
BezTriple *bezier = nurbs->bezt;
|
||||
|
||||
for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
|
||||
const Imath::V3f &pos = (*positions)[vertex_idx];
|
||||
copy_zup_from_yup(bezier->vec[1], pos.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BKE_mesh_new_nomain_from_curve(m_object);
|
||||
read_curves_sample_ex(
|
||||
curves, m_curves_schema, sample, sample_sel, attribute_selector, velocity_scale, err_str);
|
||||
}
|
||||
|
||||
} // namespace blender::io::alembic
|
||||
|
@@ -9,7 +9,7 @@
|
||||
#include "abc_reader_mesh.h"
|
||||
#include "abc_reader_object.h"
|
||||
|
||||
struct Curve;
|
||||
struct Curves;
|
||||
|
||||
#define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution"
|
||||
|
||||
@@ -26,7 +26,10 @@ class AbcCurveReader final : public AbcObjectReader {
|
||||
const Object *const ob,
|
||||
const char **err_str) const override;
|
||||
|
||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
void readObjectData(Main *bmain,
|
||||
const AbcReaderManager &manager,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
|
||||
/**
|
||||
* \note Alembic only stores data about control points, but the Mesh
|
||||
* passed from the cache modifier contains the #DispList, which has more data
|
||||
@@ -34,16 +37,16 @@ class AbcCurveReader final : public AbcObjectReader {
|
||||
* object directly and create a new Mesh from that. Also we might need to
|
||||
* create new or delete existing NURBS in the curve.
|
||||
*/
|
||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
int read_flag,
|
||||
const char *velocity_name,
|
||||
float velocity_scale,
|
||||
const char **err_str) override;
|
||||
void read_geometry(GeometrySet &geometry_set,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
int read_flag,
|
||||
const float velocity_scale,
|
||||
const char **err_str) override;
|
||||
|
||||
void read_curve_sample(Curve *cu,
|
||||
const Alembic::AbcGeom::ICurvesSchema &schema,
|
||||
const Alembic::Abc::ISampleSelector &sample_selector);
|
||||
void read_curves_sample(Curves *curves,
|
||||
const Alembic::AbcGeom::ICurvesSchema &schema,
|
||||
const Alembic::Abc::ISampleSelector &sample_selector);
|
||||
};
|
||||
|
||||
} // namespace blender::io::alembic
|
||||
|
60
source/blender/io/alembic/intern/abc_reader_instance.cc
Normal file
60
source/blender/io/alembic/intern/abc_reader_instance.cc
Normal file
@@ -0,0 +1,60 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "abc_reader_instance.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_assert.h"
|
||||
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_remap.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "abc_reader_manager.h"
|
||||
|
||||
namespace blender::io::alembic {
|
||||
|
||||
AbcInstanceReader::AbcInstanceReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
|
||||
: AbcObjectReader(object, settings)
|
||||
{
|
||||
}
|
||||
|
||||
bool AbcInstanceReader::valid() const
|
||||
{
|
||||
// TODO(kevindietrich)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbcInstanceReader::accepts_object_type(
|
||||
const Alembic::AbcCoreAbstract::ObjectHeader & /*alembic_header*/,
|
||||
const Object *const /*ob*/,
|
||||
const char ** /*err_str*/) const
|
||||
{
|
||||
/* TODO(kevindietrich) */
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbcInstanceReader::readObjectData(Main *bmain,
|
||||
const AbcReaderManager &manager,
|
||||
const Alembic::Abc::ISampleSelector & /* sample_sel */)
|
||||
{
|
||||
/* For reference on duplication, see ED_object_add_duplicate_linked.
|
||||
*
|
||||
* In this function, we only duplicate the object, as the rest (adding to view layer, tagging the
|
||||
* depsgraph, etc.) is done at the end of the import.
|
||||
*/
|
||||
|
||||
Object *ob = manager.get_blender_object_for_path(m_iobject.instanceSourcePath());
|
||||
BLI_assert(ob);
|
||||
/* 0 = linked */
|
||||
uint dupflag = 0;
|
||||
uint duplicate_options = LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID;
|
||||
|
||||
m_object = static_cast<Object *>(
|
||||
ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options)));
|
||||
|
||||
/* link own references to the newly duplicated data T26816. */
|
||||
BKE_libblock_relink_to_newid(bmain, &m_object->id, 0);
|
||||
}
|
||||
|
||||
} // namespace blender::io::alembic
|
28
source/blender/io/alembic/intern/abc_reader_instance.h
Normal file
28
source/blender/io/alembic/intern/abc_reader_instance.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup balembic
|
||||
*/
|
||||
|
||||
#include "abc_reader_object.h"
|
||||
|
||||
namespace blender::io::alembic {
|
||||
|
||||
class AbcInstanceReader final : public AbcObjectReader {
|
||||
public:
|
||||
AbcInstanceReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const override;
|
||||
|
||||
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
|
||||
const Object *const ob,
|
||||
const char **err_str) const override;
|
||||
|
||||
void readObjectData(Main *bmain,
|
||||
const AbcReaderManager &manager,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
};
|
||||
|
||||
} // namespace blender::io::alembic
|
41
source/blender/io/alembic/intern/abc_reader_manager.cc
Normal file
41
source/blender/io/alembic/intern/abc_reader_manager.cc
Normal file
@@ -0,0 +1,41 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup balembic
|
||||
*/
|
||||
|
||||
#include "abc_reader_manager.h"
|
||||
|
||||
#include "abc_reader_instance.h"
|
||||
|
||||
namespace blender::io::alembic {
|
||||
|
||||
AbcObjectReader *AbcReaderManager::create_instance_reader(Alembic::Abc::v12::IObject iobject,
|
||||
ImportSettings &settings)
|
||||
{
|
||||
std::cerr << "Creating an instance reader...\n";
|
||||
AbcObjectReader *reader = new AbcInstanceReader(iobject, settings);
|
||||
m_instance_readers.push_back(reader);
|
||||
m_readers_all.push_back(reader);
|
||||
return reader;
|
||||
}
|
||||
|
||||
Object *AbcReaderManager::get_blender_object_for_path(const std::string &path) const
|
||||
{
|
||||
AbcObjectReader *reader = get_object_reader_for_path(path);
|
||||
if (!reader) {
|
||||
return nullptr;
|
||||
}
|
||||
return reader->object();
|
||||
}
|
||||
|
||||
AbcObjectReader *AbcReaderManager::get_object_reader_for_path(const std::string &path) const
|
||||
{
|
||||
MapIteratorType iter = m_readers_map.find(path);
|
||||
if (iter == m_readers_map.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
} // namespace blender::io::alembic
|
64
source/blender/io/alembic/intern/abc_reader_manager.h
Normal file
64
source/blender/io/alembic/intern/abc_reader_manager.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup balembic
|
||||
*/
|
||||
|
||||
#include "abc_reader_object.h"
|
||||
|
||||
namespace blender::io::alembic {
|
||||
|
||||
class AbcReaderManager {
|
||||
using MapType = std::map<std::string, AbcObjectReader *>;
|
||||
using MapIteratorType = MapType::const_iterator;
|
||||
std::map<std::string, AbcObjectReader *> m_readers_map{};
|
||||
|
||||
AbcObjectReader::ptr_vector m_readers;
|
||||
AbcObjectReader::ptr_vector m_readers_all;
|
||||
AbcObjectReader::ptr_vector m_instance_readers;
|
||||
|
||||
public:
|
||||
template<typename ReaderType>
|
||||
AbcObjectReader *create(Alembic::Abc::IObject iobject, ImportSettings &settings)
|
||||
{
|
||||
static_assert(
|
||||
std::is_base_of_v<AbcObjectReader, ReaderType>,
|
||||
"Trying to create a reader from a class which does not derive from AbcObjectReader !");
|
||||
|
||||
if (iobject.isInstanceRoot()) {
|
||||
return create_instance_reader(iobject, settings);
|
||||
}
|
||||
|
||||
ReaderType *reader = new ReaderType(iobject, settings);
|
||||
m_readers_map[iobject.getFullName()] = reader;
|
||||
m_readers.push_back(reader);
|
||||
m_readers_all.push_back(reader);
|
||||
return reader;
|
||||
}
|
||||
|
||||
AbcObjectReader *create_instance_reader(Alembic::Abc::IObject iobject, ImportSettings &settings);
|
||||
|
||||
Object *get_blender_object_for_path(const std::string &path) const;
|
||||
|
||||
const AbcObjectReader::ptr_vector &all_readers() const
|
||||
{
|
||||
return m_readers_all;
|
||||
}
|
||||
|
||||
const AbcObjectReader::ptr_vector &instance_readers() const
|
||||
{
|
||||
return m_instance_readers;
|
||||
}
|
||||
|
||||
const AbcObjectReader::ptr_vector &data_readers() const
|
||||
{
|
||||
return m_readers;
|
||||
}
|
||||
|
||||
private:
|
||||
AbcObjectReader *get_object_reader_for_path(const std::string &path) const;
|
||||
};
|
||||
|
||||
} // namespace blender::io::alembic
|
@@ -24,7 +24,7 @@
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_geom.h"
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_mesh.h"
|
||||
@@ -112,10 +112,6 @@ struct AbcMeshData {
|
||||
|
||||
P3fArraySamplePtr positions;
|
||||
P3fArraySamplePtr ceil_positions;
|
||||
|
||||
AbcUvScope uv_scope;
|
||||
V2fArraySamplePtr uvs;
|
||||
UInt32ArraySamplePtr uvs_indices;
|
||||
};
|
||||
|
||||
static void read_mverts_interp(MVert *mverts,
|
||||
@@ -175,21 +171,12 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
|
||||
{
|
||||
MPoly *mpolys = config.mpoly;
|
||||
MLoop *mloops = config.mloop;
|
||||
MLoopUV *mloopuvs = config.mloopuv;
|
||||
|
||||
const Int32ArraySamplePtr &face_indices = mesh_data.face_indices;
|
||||
const Int32ArraySamplePtr &face_counts = mesh_data.face_counts;
|
||||
const V2fArraySamplePtr &uvs = mesh_data.uvs;
|
||||
const size_t uvs_size = uvs == nullptr ? 0 : uvs->size();
|
||||
|
||||
const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices;
|
||||
|
||||
const bool do_uvs = (mloopuvs && uvs && uvs_indices);
|
||||
const bool do_uvs_per_loop = do_uvs && mesh_data.uv_scope == ABC_UV_SCOPE_LOOP;
|
||||
BLI_assert(!do_uvs || mesh_data.uv_scope != ABC_UV_SCOPE_NONE);
|
||||
unsigned int loop_index = 0;
|
||||
unsigned int rev_loop_index = 0;
|
||||
unsigned int uv_index = 0;
|
||||
bool seen_invalid_geometry = false;
|
||||
|
||||
for (int i = 0; i < face_counts->size(); i++) {
|
||||
@@ -217,19 +204,6 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
|
||||
seen_invalid_geometry = true;
|
||||
}
|
||||
last_vertex_index = loop.v;
|
||||
|
||||
if (do_uvs) {
|
||||
MLoopUV &loopuv = mloopuvs[rev_loop_index];
|
||||
uv_index = (*uvs_indices)[do_uvs_per_loop ? loop_index : loop.v];
|
||||
|
||||
/* Some Alembic files are broken (or at least export UVs in a way we don't expect). */
|
||||
if (uv_index >= uvs_size) {
|
||||
continue;
|
||||
}
|
||||
|
||||
loopuv.uv[0] = (*uvs)[uv_index][0];
|
||||
loopuv.uv[1] = (*uvs)[uv_index][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,68 +311,6 @@ static void process_normals(CDStreamConfig &config,
|
||||
}
|
||||
}
|
||||
|
||||
BLI_INLINE void read_uvs_params(CDStreamConfig &config,
|
||||
AbcMeshData &abc_data,
|
||||
const IV2fGeomParam &uv,
|
||||
const ISampleSelector &selector)
|
||||
{
|
||||
if (!uv.valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
IV2fGeomParam::Sample uvsamp;
|
||||
uv.getIndexed(uvsamp, selector);
|
||||
|
||||
UInt32ArraySamplePtr uvs_indices = uvsamp.getIndices();
|
||||
|
||||
const AbcUvScope uv_scope = get_uv_scope(uv.getScope(), config, uvs_indices);
|
||||
|
||||
if (uv_scope == ABC_UV_SCOPE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
abc_data.uv_scope = uv_scope;
|
||||
abc_data.uvs = uvsamp.getVals();
|
||||
abc_data.uvs_indices = uvs_indices;
|
||||
|
||||
std::string name = Alembic::Abc::GetSourceName(uv.getMetaData());
|
||||
|
||||
/* According to the convention, primary UVs should have had their name
|
||||
* set using Alembic::Abc::SetSourceName, but you can't expect everyone
|
||||
* to follow it! :) */
|
||||
if (name.empty()) {
|
||||
name = uv.getName();
|
||||
}
|
||||
|
||||
void *cd_ptr = config.add_customdata_cb(config.mesh, name.c_str(), CD_MLOOPUV);
|
||||
config.mloopuv = static_cast<MLoopUV *>(cd_ptr);
|
||||
}
|
||||
|
||||
static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
|
||||
{
|
||||
CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
|
||||
void *cd_ptr;
|
||||
CustomData *loopdata;
|
||||
int numloops;
|
||||
|
||||
/* unsupported custom data type -- don't do anything. */
|
||||
if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
loopdata = &mesh->ldata;
|
||||
cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name);
|
||||
if (cd_ptr != nullptr) {
|
||||
/* layer already exists, so just return it. */
|
||||
return cd_ptr;
|
||||
}
|
||||
|
||||
/* Create a new layer. */
|
||||
numloops = mesh->totloop;
|
||||
cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, nullptr, numloops, name);
|
||||
return cd_ptr;
|
||||
}
|
||||
|
||||
static void get_weight_and_index(CDStreamConfig &config,
|
||||
Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling,
|
||||
size_t samples_number)
|
||||
@@ -411,65 +323,7 @@ static void get_weight_and_index(CDStreamConfig &config,
|
||||
config.ceil_index = i1;
|
||||
}
|
||||
|
||||
static V3fArraySamplePtr get_velocity_prop(const ICompoundProperty &schema,
|
||||
const ISampleSelector &selector,
|
||||
const std::string &name)
|
||||
{
|
||||
for (size_t i = 0; i < schema.getNumProperties(); i++) {
|
||||
const PropertyHeader &header = schema.getPropertyHeader(i);
|
||||
|
||||
if (header.isCompound()) {
|
||||
const ICompoundProperty &prop = ICompoundProperty(schema, header.getName());
|
||||
|
||||
if (has_property(prop, name)) {
|
||||
/* Header cannot be null here, as its presence is checked via has_property, so it is safe
|
||||
* to dereference. */
|
||||
const PropertyHeader *header = prop.getPropertyHeader(name);
|
||||
if (!IV3fArrayProperty::matches(*header)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(prop, name, 0);
|
||||
if (velocity_prop) {
|
||||
return velocity_prop.getValue(selector);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (header.isArray()) {
|
||||
if (header.getName() == name && IV3fArrayProperty::matches(header)) {
|
||||
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(schema, name, 0);
|
||||
return velocity_prop.getValue(selector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return V3fArraySamplePtr();
|
||||
}
|
||||
|
||||
static void read_velocity(const V3fArraySamplePtr &velocities,
|
||||
const CDStreamConfig &config,
|
||||
const float velocity_scale)
|
||||
{
|
||||
const int num_velocity_vectors = static_cast<int>(velocities->size());
|
||||
if (num_velocity_vectors != config.mesh->totvert) {
|
||||
/* Files containing videogrammetry data may be malformed and export velocity data on missing
|
||||
* frames (most likely by copying the last valid data). */
|
||||
return;
|
||||
}
|
||||
|
||||
CustomDataLayer *velocity_layer = BKE_id_attribute_new(
|
||||
&config.mesh->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT, nullptr);
|
||||
float(*velocity)[3] = (float(*)[3])velocity_layer->data;
|
||||
|
||||
for (int i = 0; i < num_velocity_vectors; i++) {
|
||||
const Imath::V3f &vel_in = (*velocities)[i];
|
||||
copy_zup_from_yup(velocity[i], vel_in.getValue());
|
||||
mul_v3_fl(velocity[i], velocity_scale);
|
||||
}
|
||||
}
|
||||
|
||||
static void read_mesh_sample(const std::string &iobject_full_name,
|
||||
ImportSettings *settings,
|
||||
static void read_mesh_sample(ImportSettings *settings,
|
||||
const IPolyMeshSchema &schema,
|
||||
const ISampleSelector &selector,
|
||||
CDStreamConfig &config)
|
||||
@@ -489,13 +343,8 @@ static void read_mesh_sample(const std::string &iobject_full_name,
|
||||
abc_mesh_data.ceil_positions = ceil_sample.getPositions();
|
||||
}
|
||||
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
|
||||
read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
|
||||
}
|
||||
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
|
||||
read_mverts(config, abc_mesh_data);
|
||||
read_generated_coordinates(schema.getArbGeomParams(), config, selector);
|
||||
}
|
||||
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
|
||||
@@ -503,25 +352,21 @@ static void read_mesh_sample(const std::string &iobject_full_name,
|
||||
process_normals(config, schema.getNormalsParam(), selector);
|
||||
}
|
||||
|
||||
if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
|
||||
read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector);
|
||||
}
|
||||
|
||||
if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) {
|
||||
V3fArraySamplePtr velocities = get_velocity_prop(schema, selector, settings->velocity_name);
|
||||
if (velocities) {
|
||||
read_velocity(velocities, config, settings->velocity_scale);
|
||||
}
|
||||
}
|
||||
read_arbitrary_attributes(
|
||||
config, schema, schema.getUVsParam(), selector, settings->velocity_scale);
|
||||
}
|
||||
|
||||
CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation)
|
||||
CDStreamConfig get_config(Mesh *mesh,
|
||||
const AttributeSelector *attr_selector,
|
||||
const std::string &iobject_full_name,
|
||||
const bool use_vertex_interpolation)
|
||||
{
|
||||
CDStreamConfig config;
|
||||
|
||||
BLI_assert(mesh->mvert || mesh->totvert == 0);
|
||||
|
||||
config.mesh = mesh;
|
||||
config.id = &mesh->id;
|
||||
config.mvert = mesh->mvert;
|
||||
config.mloop = mesh->mloop;
|
||||
config.mpoly = mesh->mpoly;
|
||||
@@ -529,8 +374,10 @@ CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation)
|
||||
config.totloop = mesh->totloop;
|
||||
config.totpoly = mesh->totpoly;
|
||||
config.loopdata = &mesh->ldata;
|
||||
config.add_customdata_cb = add_customdata_cb;
|
||||
config.use_vertex_interpolation = use_vertex_interpolation;
|
||||
config.attr_selector = attr_selector;
|
||||
config.iobject_full_name = iobject_full_name;
|
||||
BKE_id_attribute_get_domains(config.id, config.domain_info);
|
||||
|
||||
return config;
|
||||
}
|
||||
@@ -553,39 +400,6 @@ bool AbcMeshReader::valid() const
|
||||
return m_schema.valid();
|
||||
}
|
||||
|
||||
template<class typedGeomParam>
|
||||
bool is_valid_animated(const ICompoundProperty arbGeomParams, const PropertyHeader &prop_header)
|
||||
{
|
||||
if (!typedGeomParam::matches(prop_header)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
typedGeomParam geom_param(arbGeomParams, prop_header.getName());
|
||||
return geom_param.valid() && !geom_param.isConstant();
|
||||
}
|
||||
|
||||
static bool has_animated_geom_params(const ICompoundProperty arbGeomParams)
|
||||
{
|
||||
if (!arbGeomParams.valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int num_props = arbGeomParams.getNumProperties();
|
||||
for (int i = 0; i < num_props; i++) {
|
||||
const PropertyHeader &prop_header = arbGeomParams.getPropertyHeader(i);
|
||||
|
||||
/* These are interpreted as vertex colors later (see 'read_custom_data'). */
|
||||
if (is_valid_animated<IC3fGeomParam>(arbGeomParams, prop_header)) {
|
||||
return true;
|
||||
}
|
||||
if (is_valid_animated<IC4fGeomParam>(arbGeomParams, prop_header)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Specialization of #has_animations() as defined in abc_reader_object.h. */
|
||||
template<> bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, ImportSettings *settings)
|
||||
{
|
||||
@@ -604,21 +418,30 @@ template<> bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, Import
|
||||
}
|
||||
|
||||
ICompoundProperty arbGeomParams = schema.getArbGeomParams();
|
||||
if (has_animated_geom_params(arbGeomParams)) {
|
||||
if (has_animated_attributes(arbGeomParams)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
|
||||
void AbcMeshReader::readObjectData(Main *bmain,
|
||||
const AbcReaderManager & /*manager*/,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||
{
|
||||
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
|
||||
m_object->data = mesh;
|
||||
|
||||
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr);
|
||||
/* Default AttributeSelector to ensure that at least UVs and vertex colors are read. To load
|
||||
* other attributes, a modifier should be added as there are no clear conventions for them. */
|
||||
ListBase lb = {nullptr, nullptr};
|
||||
AttributeSelector attr_selector(&lb);
|
||||
attr_selector.set_read_flags(MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR);
|
||||
|
||||
Mesh *read_mesh = this->read_mesh(
|
||||
mesh, sample_sel, &attr_selector, MOD_MESHSEQ_READ_ALL, 0.0f, nullptr);
|
||||
if (read_mesh != mesh) {
|
||||
/* XXX FIXME: after 2.80; mesh->flag isn't copied by #BKE_mesh_nomain_to_mesh(). */
|
||||
/* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
|
||||
@@ -683,10 +506,31 @@ bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector
|
||||
face_indices->size() != existing_mesh->totloop;
|
||||
}
|
||||
|
||||
void AbcMeshReader::read_geometry(GeometrySet &geometry_set,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
int read_flag,
|
||||
const float velocity_scale,
|
||||
const char **err_str)
|
||||
{
|
||||
Mesh *mesh = geometry_set.get_mesh_for_write();
|
||||
|
||||
if (mesh == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Mesh *new_mesh = read_mesh(
|
||||
mesh, sample_sel, attribute_selector, read_flag, velocity_scale, err_str);
|
||||
|
||||
if (new_mesh != mesh) {
|
||||
geometry_set.replace_mesh(new_mesh);
|
||||
}
|
||||
}
|
||||
|
||||
Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
|
||||
const ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
const int read_flag,
|
||||
const char *velocity_name,
|
||||
const float velocity_scale,
|
||||
const char **err_str)
|
||||
{
|
||||
@@ -730,7 +574,6 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
|
||||
/* Only read point data when streaming meshes, unless we need to create new ones. */
|
||||
ImportSettings settings;
|
||||
settings.read_flag |= read_flag;
|
||||
settings.velocity_name = velocity_name;
|
||||
settings.velocity_scale = velocity_scale;
|
||||
|
||||
if (topology_changed(existing_mesh, sample_sel)) {
|
||||
@@ -757,11 +600,12 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
|
||||
|
||||
Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
|
||||
const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
|
||||
CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation);
|
||||
CDStreamConfig config = get_config(
|
||||
mesh_to_export, attribute_selector, m_iobject.getFullName(), use_vertex_interpolation);
|
||||
config.time = sample_sel.getRequestedTime();
|
||||
config.modifier_error_message = err_str;
|
||||
|
||||
read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config);
|
||||
read_mesh_sample(&settings, m_schema, sample_sel, config);
|
||||
|
||||
if (new_mesh) {
|
||||
/* Here we assume that the number of materials doesn't change, i.e. that
|
||||
@@ -848,8 +692,7 @@ BLI_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void read_subd_sample(const std::string &iobject_full_name,
|
||||
ImportSettings *settings,
|
||||
static void read_subd_sample(ImportSettings *settings,
|
||||
const ISubDSchema &schema,
|
||||
const ISampleSelector &selector,
|
||||
CDStreamConfig &config)
|
||||
@@ -869,10 +712,6 @@ static void read_subd_sample(const std::string &iobject_full_name,
|
||||
abc_mesh_data.ceil_positions = ceil_sample.getPositions();
|
||||
}
|
||||
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
|
||||
read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
|
||||
}
|
||||
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
|
||||
read_mverts(config, abc_mesh_data);
|
||||
}
|
||||
@@ -885,16 +724,8 @@ static void read_subd_sample(const std::string &iobject_full_name,
|
||||
process_no_normals(config);
|
||||
}
|
||||
|
||||
if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
|
||||
read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector);
|
||||
}
|
||||
|
||||
if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) {
|
||||
V3fArraySamplePtr velocities = get_velocity_prop(schema, selector, settings->velocity_name);
|
||||
if (velocities) {
|
||||
read_velocity(velocities, config, settings->velocity_scale);
|
||||
}
|
||||
}
|
||||
read_arbitrary_attributes(
|
||||
config, schema, schema.getUVsParam(), selector, settings->velocity_scale);
|
||||
}
|
||||
|
||||
static void read_vertex_creases(Mesh *mesh,
|
||||
@@ -995,14 +826,23 @@ bool AbcSubDReader::accepts_object_type(
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
|
||||
void AbcSubDReader::readObjectData(Main *bmain,
|
||||
const AbcReaderManager & /*manager*/,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||
{
|
||||
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
|
||||
m_object->data = mesh;
|
||||
|
||||
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr);
|
||||
/* Default AttributeSelector to ensure that at least UVs and vertex colors are read. To load
|
||||
* other attributes, a modifier should be added as there are no clear conventions for them. */
|
||||
ListBase lb = {nullptr, nullptr};
|
||||
AttributeSelector attr_selector(&lb);
|
||||
attr_selector.set_read_flags(MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR);
|
||||
|
||||
Mesh *read_mesh = this->read_mesh(
|
||||
mesh, sample_sel, &attr_selector, MOD_MESHSEQ_READ_ALL, 0.0f, nullptr);
|
||||
if (read_mesh != mesh) {
|
||||
BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true);
|
||||
}
|
||||
@@ -1035,8 +875,8 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
|
||||
|
||||
Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
|
||||
const ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
const int read_flag,
|
||||
const char *velocity_name,
|
||||
const float velocity_scale,
|
||||
const char **err_str)
|
||||
{
|
||||
@@ -1064,7 +904,6 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
|
||||
|
||||
ImportSettings settings;
|
||||
settings.read_flag |= read_flag;
|
||||
settings.velocity_name = velocity_name;
|
||||
settings.velocity_scale = velocity_scale;
|
||||
|
||||
if (existing_mesh->totvert != positions->size()) {
|
||||
@@ -1092,11 +931,33 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
|
||||
/* Only read point data when streaming meshes, unless we need to create new ones. */
|
||||
Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
|
||||
const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
|
||||
CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation);
|
||||
CDStreamConfig config = get_config(
|
||||
mesh_to_export, attribute_selector, m_iobject.getFullName(), use_vertex_interpolation);
|
||||
config.time = sample_sel.getRequestedTime();
|
||||
read_subd_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config);
|
||||
read_subd_sample(&settings, m_schema, sample_sel, config);
|
||||
|
||||
return mesh_to_export;
|
||||
}
|
||||
|
||||
void AbcSubDReader::read_geometry(GeometrySet &geometry_set,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
int read_flag,
|
||||
const float velocity_scale,
|
||||
const char **err_str)
|
||||
{
|
||||
Mesh *mesh = geometry_set.get_mesh_for_write();
|
||||
|
||||
if (mesh == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Mesh *new_mesh = read_mesh(
|
||||
mesh, sample_sel, attribute_selector, read_flag, velocity_scale, err_str);
|
||||
|
||||
if (new_mesh != mesh) {
|
||||
geometry_set.replace_mesh(new_mesh);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::io::alembic
|
||||
|
@@ -24,17 +24,20 @@ class AbcMeshReader final : public AbcObjectReader {
|
||||
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
|
||||
const Object *const ob,
|
||||
const char **err_str) const override;
|
||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
void readObjectData(Main *bmain,
|
||||
const AbcReaderManager &manager,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
|
||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
int read_flag,
|
||||
const char *velocity_name,
|
||||
float velocity_scale,
|
||||
const char **err_str) override;
|
||||
bool topology_changed(Mesh *existing_mesh,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
|
||||
void read_geometry(GeometrySet &geometry_set,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
int read_flag,
|
||||
const float velocity_scale,
|
||||
const char **err_str) override;
|
||||
|
||||
private:
|
||||
void readFaceSetsSample(Main *bmain,
|
||||
Mesh *mesh,
|
||||
@@ -44,6 +47,13 @@ class AbcMeshReader final : public AbcObjectReader {
|
||||
MPoly *mpoly,
|
||||
int totpoly,
|
||||
std::map<std::string, int> &r_mat_map);
|
||||
|
||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
const int read_flag,
|
||||
const float velocity_scale,
|
||||
const char **err_str);
|
||||
};
|
||||
|
||||
class AbcSubDReader final : public AbcObjectReader {
|
||||
@@ -58,19 +68,33 @@ class AbcSubDReader final : public AbcObjectReader {
|
||||
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
|
||||
const Object *const ob,
|
||||
const char **err_str) const override;
|
||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
void readObjectData(Main *bmain,
|
||||
const AbcReaderManager &manager,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
|
||||
void read_geometry(GeometrySet &geometry_set,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
int read_flag,
|
||||
const float velocity_scale,
|
||||
const char **err_str) override;
|
||||
|
||||
private:
|
||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
int read_flag,
|
||||
const char *velocity_name,
|
||||
float velocity_scale,
|
||||
const char **err_str) override;
|
||||
const AttributeSelector *attribute_selector,
|
||||
const int read_flag,
|
||||
const float velocity_scale,
|
||||
const char **err_str);
|
||||
};
|
||||
|
||||
void read_mverts(Mesh &mesh,
|
||||
const Alembic::AbcGeom::P3fArraySamplePtr positions,
|
||||
const Alembic::AbcGeom::N3fArraySamplePtr normals);
|
||||
|
||||
CDStreamConfig get_config(struct Mesh *mesh, bool use_vertex_interpolation);
|
||||
CDStreamConfig get_config(struct Mesh *mesh,
|
||||
const AttributeSelector *attr_selector,
|
||||
const std::string &iobject_full_name,
|
||||
bool use_vertex_interpolation);
|
||||
|
||||
} // namespace blender::io::alembic
|
||||
|
@@ -94,7 +94,9 @@ static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbcNurbsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
|
||||
void AbcNurbsReader::readObjectData(Main *bmain,
|
||||
const AbcReaderManager & /*manager*/,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||
{
|
||||
Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, m_data_name.c_str(), OB_SURF));
|
||||
cu->actvert = CU_ACT_NONE;
|
||||
|
@@ -21,7 +21,9 @@ class AbcNurbsReader final : public AbcObjectReader {
|
||||
const Object *const ob,
|
||||
const char **err_str) const override;
|
||||
|
||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
void readObjectData(Main *bmain,
|
||||
const AbcReaderManager &manager,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
|
||||
private:
|
||||
void getNurbsPatches(const Alembic::Abc::IObject &obj);
|
||||
|
@@ -130,16 +130,6 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time)
|
||||
return s0.getMatrix();
|
||||
}
|
||||
|
||||
struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
|
||||
const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
|
||||
int UNUSED(read_flag),
|
||||
const char *UNUSED(velocity_name),
|
||||
const float UNUSED(velocity_scale),
|
||||
const char **UNUSED(err_str))
|
||||
{
|
||||
return existing_mesh;
|
||||
}
|
||||
|
||||
bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/,
|
||||
const Alembic::Abc::ISampleSelector & /*sample_sel*/)
|
||||
{
|
||||
@@ -148,6 +138,16 @@ bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/,
|
||||
return false;
|
||||
}
|
||||
|
||||
void AbcObjectReader::read_geometry(GeometrySet &UNUSED(geometry_set),
|
||||
const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
|
||||
const AttributeSelector *UNUSED(attribute_selector),
|
||||
int UNUSED(read_flag),
|
||||
const float UNUSED(velocity_scale),
|
||||
const char **UNUSED(err_str))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void AbcObjectReader::setupObjectTransform(const float time)
|
||||
{
|
||||
bool is_constant = false;
|
||||
@@ -166,16 +166,32 @@ void AbcObjectReader::setupObjectTransform(const float time)
|
||||
BKE_object_to_mat4(m_object, m_object->obmat);
|
||||
|
||||
if (!is_constant || m_settings->always_add_cache_reader) {
|
||||
bConstraint *con = BKE_constraint_add_for_object(
|
||||
m_object, nullptr, CONSTRAINT_TYPE_TRANSFORM_CACHE);
|
||||
bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
|
||||
BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
|
||||
|
||||
data->cache_file = m_settings->cache_file;
|
||||
id_us_plus(&data->cache_file->id);
|
||||
bTransformCacheConstraint *constraint = getOrCreateConstraint();
|
||||
BLI_strncpy(constraint->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
bTransformCacheConstraint *AbcObjectReader::getOrCreateConstraint()
|
||||
{
|
||||
if (m_iobject.isInstanceRoot()) {
|
||||
/* As this is an instance we may already have created a constraint when duplicating the source
|
||||
* object, if so return it. Note that it is possible for an instance to have an animated
|
||||
* transform, but not for the source object. */
|
||||
bConstraint *constraint = static_cast<bConstraint *>(m_object->constraints.last);
|
||||
if (constraint && constraint->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) {
|
||||
return static_cast<bTransformCacheConstraint *>(constraint->data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a new constraint. */
|
||||
bConstraint *constraint = BKE_constraint_add_for_object(
|
||||
m_object, nullptr, CONSTRAINT_TYPE_TRANSFORM_CACHE);
|
||||
bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(constraint->data);
|
||||
data->cache_file = m_settings->cache_file;
|
||||
id_us_plus(&data->cache_file->id);
|
||||
return data;
|
||||
}
|
||||
|
||||
Alembic::AbcGeom::IXform AbcObjectReader::xform()
|
||||
{
|
||||
/* Check that we have an empty object (locator, bone head/tail...). */
|
||||
|
@@ -10,7 +10,9 @@
|
||||
|
||||
#include "DNA_ID.h"
|
||||
|
||||
struct bTransformCacheConstraint;
|
||||
struct CacheFile;
|
||||
struct GeometrySet;
|
||||
struct Main;
|
||||
struct Mesh;
|
||||
struct Object;
|
||||
@@ -19,6 +21,9 @@ using Alembic::AbcCoreAbstract::chrono_t;
|
||||
|
||||
namespace blender::io::alembic {
|
||||
|
||||
class AbcReaderManager;
|
||||
class AttributeSelector;
|
||||
|
||||
struct ImportSettings {
|
||||
bool do_convert_mat;
|
||||
float conversion_mat[4][4];
|
||||
@@ -37,7 +42,6 @@ struct ImportSettings {
|
||||
int read_flag;
|
||||
|
||||
/* From CacheFile and MeshSeqCacheModifierData */
|
||||
std::string velocity_name;
|
||||
float velocity_scale;
|
||||
|
||||
bool validate_meshes;
|
||||
@@ -55,7 +59,6 @@ struct ImportSettings {
|
||||
sequence_len(1),
|
||||
sequence_offset(0),
|
||||
read_flag(0),
|
||||
velocity_name(""),
|
||||
velocity_scale(1.0f),
|
||||
validate_meshes(false),
|
||||
always_add_cache_reader(false),
|
||||
@@ -131,17 +134,20 @@ class AbcObjectReader {
|
||||
const Object *const ob,
|
||||
const char **err_str) const = 0;
|
||||
|
||||
virtual void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) = 0;
|
||||
virtual void readObjectData(Main *bmain,
|
||||
const AbcReaderManager &manager,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel) = 0;
|
||||
|
||||
virtual struct Mesh *read_mesh(struct Mesh *mesh,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
int read_flag,
|
||||
const char *velocity_name,
|
||||
float velocity_scale,
|
||||
const char **err_str);
|
||||
virtual bool topology_changed(Mesh *existing_mesh,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel);
|
||||
|
||||
virtual void read_geometry(GeometrySet &geometry_set,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
int read_flag,
|
||||
const float velocity_scale,
|
||||
const char **err_str);
|
||||
|
||||
/** Reads the object matrix and sets up an object transform if animated. */
|
||||
void setupObjectTransform(float time);
|
||||
|
||||
@@ -159,6 +165,9 @@ class AbcObjectReader {
|
||||
protected:
|
||||
/** Determine whether we can inherit our parent's XForm. */
|
||||
void determine_inherits_xform();
|
||||
|
||||
private:
|
||||
bTransformCacheConstraint *getOrCreateConstraint();
|
||||
};
|
||||
|
||||
Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, float time);
|
||||
|
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "abc_reader_points.h"
|
||||
#include "abc_axis_conversion.h"
|
||||
#include "abc_reader_mesh.h"
|
||||
#include "abc_reader_transform.h"
|
||||
#include "abc_util.h"
|
||||
@@ -13,15 +14,21 @@
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_pointcloud_types.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_pointcloud.h"
|
||||
|
||||
using Alembic::AbcGeom::kWrapExisting;
|
||||
using Alembic::AbcGeom::N3fArraySamplePtr;
|
||||
using Alembic::AbcGeom::P3fArraySamplePtr;
|
||||
|
||||
using namespace Alembic::AbcGeom;
|
||||
|
||||
using Alembic::AbcGeom::ICompoundProperty;
|
||||
using Alembic::AbcGeom::IN3fArrayProperty;
|
||||
using Alembic::AbcGeom::IPoints;
|
||||
@@ -55,7 +62,7 @@ bool AbcPointsReader::accepts_object_type(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ob->type != OB_MESH) {
|
||||
if (ob->type != OB_POINTCLOUD) {
|
||||
*err_str = "Object type mismatch, Alembic object path points to Points.";
|
||||
return false;
|
||||
}
|
||||
@@ -63,58 +70,89 @@ bool AbcPointsReader::accepts_object_type(
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
|
||||
void AbcPointsReader::readObjectData(Main *bmain,
|
||||
const AbcReaderManager & /*manager*/,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel)
|
||||
{
|
||||
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
|
||||
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, 0, "", 0.0f, nullptr);
|
||||
PointCloud *point_cloud = static_cast<PointCloud *>(
|
||||
BKE_pointcloud_add_default(bmain, m_data_name.c_str()));
|
||||
|
||||
if (read_mesh != mesh) {
|
||||
BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true);
|
||||
GeometrySet geometry_set = GeometrySet::create_with_pointcloud(point_cloud,
|
||||
GeometryOwnershipType::Editable);
|
||||
read_geometry(geometry_set, sample_sel, nullptr, 0, 0.0f, nullptr);
|
||||
|
||||
PointCloud *read_point_cloud =
|
||||
geometry_set.get_component_for_write<PointCloudComponent>().release();
|
||||
|
||||
if (read_point_cloud != point_cloud) {
|
||||
BKE_pointcloud_nomain_to_pointcloud(read_point_cloud, point_cloud, true);
|
||||
}
|
||||
|
||||
if (m_settings->validate_meshes) {
|
||||
BKE_mesh_validate(mesh, false, false);
|
||||
}
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
|
||||
m_object->data = mesh;
|
||||
m_object = BKE_object_add_only_object(bmain, OB_POINTCLOUD, m_object_name.c_str());
|
||||
m_object->data = point_cloud;
|
||||
|
||||
if (m_settings->always_add_cache_reader || has_animations(m_schema, m_settings)) {
|
||||
addCacheModifier();
|
||||
}
|
||||
}
|
||||
|
||||
void read_points_sample(const IPointsSchema &schema,
|
||||
const ISampleSelector &selector,
|
||||
CDStreamConfig &config)
|
||||
static void read_points_interp(const P3fArraySamplePtr positions,
|
||||
const P3fArraySamplePtr ceil_positions,
|
||||
const float weight,
|
||||
float3 *r_points)
|
||||
{
|
||||
float3 tmp;
|
||||
for (size_t i = 0; i < positions->size(); i++) {
|
||||
const Imath::V3f &floor_pos = (*positions)[i];
|
||||
const Imath::V3f &ceil_pos = (*ceil_positions)[i];
|
||||
interp_v3_v3v3(tmp, floor_pos.getValue(), ceil_pos.getValue(), weight);
|
||||
copy_zup_from_yup(r_points[i], (*positions)[i].getValue());
|
||||
}
|
||||
}
|
||||
|
||||
static void read_points(const P3fArraySamplePtr positions, float3 *r_points)
|
||||
{
|
||||
for (size_t i = 0; i < positions->size(); i++) {
|
||||
copy_zup_from_yup(r_points[i], (*positions)[i].getValue());
|
||||
}
|
||||
}
|
||||
|
||||
static void read_points_sample(const IPointsSchema &schema,
|
||||
const ISampleSelector &selector,
|
||||
CDStreamConfig &config,
|
||||
float3 *r_points)
|
||||
{
|
||||
Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
|
||||
|
||||
const P3fArraySamplePtr &positions = sample.getPositions();
|
||||
|
||||
ICompoundProperty prop = schema.getArbGeomParams();
|
||||
N3fArraySamplePtr vnormals;
|
||||
|
||||
if (has_property(prop, "N")) {
|
||||
const Alembic::Util::uint32_t itime = static_cast<Alembic::Util::uint32_t>(
|
||||
selector.getRequestedTime());
|
||||
const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", itime);
|
||||
Alembic::AbcGeom::index_t i0, i1;
|
||||
const float weight = get_weight_and_index(
|
||||
config.time, schema.getTimeSampling(), schema.getNumSamples(), i0, i1);
|
||||
|
||||
if (normals_prop) {
|
||||
vnormals = normals_prop.getValue(selector);
|
||||
}
|
||||
if (config.use_vertex_interpolation && weight != 0.0f) {
|
||||
Alembic::AbcGeom::IPointsSchema::Sample ceil_sample;
|
||||
schema.get(ceil_sample, Alembic::Abc::ISampleSelector(i1));
|
||||
P3fArraySamplePtr ceil_positions = ceil_sample.getPositions();
|
||||
|
||||
read_points_interp(positions, ceil_positions, weight, r_points);
|
||||
return;
|
||||
}
|
||||
|
||||
read_mverts(*config.mesh, positions, vnormals);
|
||||
read_points(positions, r_points);
|
||||
}
|
||||
|
||||
struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh,
|
||||
const ISampleSelector &sample_sel,
|
||||
int read_flag,
|
||||
const char * /*velocity_name*/,
|
||||
const float /*velocity_scale*/,
|
||||
const char **err_str)
|
||||
void AbcPointsReader::read_geometry(GeometrySet &geometry_set,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
int read_flag,
|
||||
const float velocity_scale,
|
||||
const char **err_str)
|
||||
{
|
||||
assert(geometry_set.has_pointcloud());
|
||||
|
||||
IPointsSchema::Sample sample;
|
||||
try {
|
||||
sample = m_schema.getValue(sample_sel);
|
||||
@@ -126,23 +164,64 @@ struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh,
|
||||
m_schema.getName().c_str(),
|
||||
sample_sel.getRequestedTime(),
|
||||
ex.what());
|
||||
return existing_mesh;
|
||||
return;
|
||||
}
|
||||
|
||||
PointCloud *existing_point_cloud = geometry_set.get_pointcloud_for_write();
|
||||
PointCloud *point_cloud = existing_point_cloud;
|
||||
|
||||
const P3fArraySamplePtr &positions = sample.getPositions();
|
||||
|
||||
Mesh *new_mesh = nullptr;
|
||||
const IFloatGeomParam widths_param = m_schema.getWidthsParam();
|
||||
FloatArraySamplePtr radiuses;
|
||||
|
||||
if (existing_mesh->totvert != positions->size()) {
|
||||
new_mesh = BKE_mesh_new_nomain(positions->size(), 0, 0, 0, 0);
|
||||
if (widths_param.valid()) {
|
||||
IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
|
||||
radiuses = wsample.getVals();
|
||||
}
|
||||
|
||||
Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
|
||||
const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
|
||||
CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation);
|
||||
read_points_sample(m_schema, sample_sel, config);
|
||||
if (point_cloud->totpoint != positions->size()) {
|
||||
point_cloud = BKE_pointcloud_new_nomain(positions->size());
|
||||
}
|
||||
|
||||
return mesh_to_export;
|
||||
CDStreamConfig config;
|
||||
config.id = &point_cloud->id;
|
||||
BKE_id_attribute_get_domains(config.id, config.domain_info);
|
||||
config.attr_selector = attribute_selector;
|
||||
config.time = sample_sel.getRequestedTime();
|
||||
config.use_vertex_interpolation = (read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES) != 0;
|
||||
config.modifier_error_message = err_str;
|
||||
|
||||
read_points_sample(m_schema, sample_sel, config, reinterpret_cast<float3 *>(point_cloud->co));
|
||||
|
||||
if (radiuses) {
|
||||
for (size_t i = 0; i < radiuses->size(); i++) {
|
||||
point_cloud->radius[i] = (*radiuses)[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < point_cloud->totpoint; i++) {
|
||||
point_cloud->radius[i] = 0.01f;
|
||||
}
|
||||
}
|
||||
|
||||
UInt64ArraySamplePtr ids = sample.getIds();
|
||||
if (ids && ids->size() == positions->size()) {
|
||||
CustomDataLayer *ids_layer = BKE_id_attribute_ensure(
|
||||
&point_cloud->id, "ids", CD_PROP_INT32, ATTR_DOMAIN_POINT, nullptr);
|
||||
int *ids_layer_data = static_cast<int *>(ids_layer->data);
|
||||
|
||||
for (size_t i = 0; i < ids->size(); i++) {
|
||||
ids_layer_data[i] = static_cast<int>((*ids)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Attributes */
|
||||
read_arbitrary_attributes(config, m_schema, {}, sample_sel, velocity_scale);
|
||||
|
||||
if (point_cloud != existing_point_cloud) {
|
||||
geometry_set.replace_pointcloud(point_cloud);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::io::alembic
|
||||
|
@@ -23,18 +23,16 @@ class AbcPointsReader final : public AbcObjectReader {
|
||||
const Object *const ob,
|
||||
const char **err_str) const override;
|
||||
|
||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
void readObjectData(Main *bmain,
|
||||
const AbcReaderManager &manager,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
|
||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
int read_flag,
|
||||
const char *velocity_name,
|
||||
float velocity_scale,
|
||||
const char **err_str) override;
|
||||
void read_geometry(GeometrySet &geometry_set,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel,
|
||||
const AttributeSelector *attribute_selector,
|
||||
int read_flag,
|
||||
const float velocity_scale,
|
||||
const char **err_str) override;
|
||||
};
|
||||
|
||||
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
|
||||
const Alembic::AbcGeom::ISampleSelector &selector,
|
||||
CDStreamConfig &config);
|
||||
|
||||
} // namespace blender::io::alembic
|
||||
|
@@ -55,7 +55,9 @@ bool AbcEmptyReader::accepts_object_type(
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbcEmptyReader::readObjectData(Main *bmain, const ISampleSelector &UNUSED(sample_sel))
|
||||
void AbcEmptyReader::readObjectData(Main *bmain,
|
||||
const AbcReaderManager & /*manager*/,
|
||||
const ISampleSelector &UNUSED(sample_sel))
|
||||
{
|
||||
m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str());
|
||||
m_object->data = nullptr;
|
||||
|
@@ -22,7 +22,9 @@ class AbcEmptyReader final : public AbcObjectReader {
|
||||
const Object *const ob,
|
||||
const char **err_str) const override;
|
||||
|
||||
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
void readObjectData(Main *bmain,
|
||||
const AbcReaderManager &manager,
|
||||
const Alembic::Abc::ISampleSelector &sample_sel) override;
|
||||
};
|
||||
|
||||
} // namespace blender::io::alembic
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "abc_reader_archive.h"
|
||||
#include "abc_reader_camera.h"
|
||||
#include "abc_reader_curves.h"
|
||||
#include "abc_reader_manager.h"
|
||||
#include "abc_reader_mesh.h"
|
||||
#include "abc_reader_nurbs.h"
|
||||
#include "abc_reader_points.h"
|
||||
@@ -211,7 +212,7 @@ static void find_iobject(const IObject &object, IObject &ret, const std::string
|
||||
* Generates an AbcObjectReader for this Alembic object and its children.
|
||||
*
|
||||
* \param object: The Alembic IObject to visit.
|
||||
* \param readers: The created AbcObjectReader * will be appended to this vector.
|
||||
* \param manager: The manager responsible for creating the readers.
|
||||
* \param settings: Import settings, not used directly but passed to the
|
||||
* AbcObjectReader subclass constructors.
|
||||
* \param r_assign_as_parent: Return parameter, contains a list of reader
|
||||
@@ -229,7 +230,7 @@ static void find_iobject(const IObject &object, IObject &ret, const std::string
|
||||
* them in sync. */
|
||||
static std::pair<bool, AbcObjectReader *> visit_object(
|
||||
const IObject &object,
|
||||
AbcObjectReader::ptr_vector &readers,
|
||||
AbcReaderManager &manager,
|
||||
ImportSettings &settings,
|
||||
AbcObjectReader::ptr_vector &r_assign_as_parent)
|
||||
{
|
||||
@@ -254,7 +255,7 @@ static std::pair<bool, AbcObjectReader *> visit_object(
|
||||
|
||||
/* TODO: When we only support C++11, use std::tie() instead. */
|
||||
std::pair<bool, AbcObjectReader *> child_result;
|
||||
child_result = visit_object(ichild, readers, settings, assign_as_parent);
|
||||
child_result = visit_object(ichild, manager, settings, assign_as_parent);
|
||||
|
||||
bool child_claims_this_object = child_result.first;
|
||||
AbcObjectReader *child_reader = child_result.second;
|
||||
@@ -299,15 +300,15 @@ static std::pair<bool, AbcObjectReader *> visit_object(
|
||||
}
|
||||
|
||||
if (create_empty) {
|
||||
reader = new AbcEmptyReader(object, settings);
|
||||
reader = manager.create<AbcEmptyReader>(object, settings);
|
||||
}
|
||||
}
|
||||
else if (IPolyMesh::matches(md)) {
|
||||
reader = new AbcMeshReader(object, settings);
|
||||
reader = manager.create<AbcMeshReader>(object, settings);
|
||||
parent_is_part_of_this_object = true;
|
||||
}
|
||||
else if (ISubD::matches(md)) {
|
||||
reader = new AbcSubDReader(object, settings);
|
||||
reader = manager.create<AbcSubDReader>(object, settings);
|
||||
parent_is_part_of_this_object = true;
|
||||
}
|
||||
else if (INuPatch::matches(md)) {
|
||||
@@ -318,16 +319,16 @@ static std::pair<bool, AbcObjectReader *> visit_object(
|
||||
* Blender. Need to figure out exactly how these points are
|
||||
* duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
|
||||
* Until this is fixed, disabling NURBS reading. */
|
||||
reader = new AbcNurbsReader(object, settings);
|
||||
reader = manager.create<AbcNurbsReader>(object, settings);
|
||||
parent_is_part_of_this_object = true;
|
||||
#endif
|
||||
}
|
||||
else if (ICamera::matches(md)) {
|
||||
reader = new AbcCameraReader(object, settings);
|
||||
reader = manager.create<AbcCameraReader>(object, settings);
|
||||
parent_is_part_of_this_object = true;
|
||||
}
|
||||
else if (IPoints::matches(md)) {
|
||||
reader = new AbcPointsReader(object, settings);
|
||||
reader = manager.create<AbcPointsReader>(object, settings);
|
||||
parent_is_part_of_this_object = true;
|
||||
}
|
||||
else if (IMaterial::matches(md)) {
|
||||
@@ -340,7 +341,7 @@ static std::pair<bool, AbcObjectReader *> visit_object(
|
||||
/* Pass, those are handled in the mesh reader. */
|
||||
}
|
||||
else if (ICurves::matches(md)) {
|
||||
reader = new AbcCurveReader(object, settings);
|
||||
reader = manager.create<AbcCurveReader>(object, settings);
|
||||
parent_is_part_of_this_object = true;
|
||||
}
|
||||
else {
|
||||
@@ -353,7 +354,6 @@ static std::pair<bool, AbcObjectReader *> visit_object(
|
||||
* not claimed as part of any child Alembic object. */
|
||||
BLI_assert(claiming_child_readers.empty());
|
||||
|
||||
readers.push_back(reader);
|
||||
reader->incref();
|
||||
|
||||
CacheObjectPath *abc_path = static_cast<CacheObjectPath *>(
|
||||
@@ -423,7 +423,7 @@ struct ImportJobData {
|
||||
ImportSettings settings;
|
||||
|
||||
ArchiveReader *archive;
|
||||
std::vector<AbcObjectReader *> readers;
|
||||
AbcReaderManager reader_manager;
|
||||
|
||||
short *stop;
|
||||
short *do_update;
|
||||
@@ -475,7 +475,8 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
|
||||
|
||||
/* Parse Alembic Archive. */
|
||||
AbcObjectReader::ptr_vector assign_as_parent;
|
||||
visit_object(archive->getTop(), data->readers, data->settings, assign_as_parent);
|
||||
IObject root = archive->getTop();
|
||||
visit_object(archive->getTop(), data->reader_manager, data->settings, assign_as_parent);
|
||||
|
||||
/* There shouldn't be any orphans. */
|
||||
BLI_assert(assign_as_parent.empty());
|
||||
@@ -490,19 +491,16 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
|
||||
|
||||
/* Create objects and set scene frame range. */
|
||||
|
||||
const float size = static_cast<float>(data->readers.size());
|
||||
const float size = static_cast<float>(data->reader_manager.all_readers().size());
|
||||
size_t i = 0;
|
||||
|
||||
chrono_t min_time = std::numeric_limits<chrono_t>::max();
|
||||
chrono_t max_time = std::numeric_limits<chrono_t>::min();
|
||||
|
||||
ISampleSelector sample_sel(0.0f);
|
||||
std::vector<AbcObjectReader *>::iterator iter;
|
||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
||||
AbcObjectReader *reader = *iter;
|
||||
|
||||
for (AbcObjectReader *reader : data->reader_manager.data_readers()) {
|
||||
if (reader->valid()) {
|
||||
reader->readObjectData(data->bmain, sample_sel);
|
||||
reader->readObjectData(data->bmain, data->reader_manager, sample_sel);
|
||||
|
||||
min_time = std::min(min_time, reader->minTime());
|
||||
max_time = std::max(max_time, reader->maxTime());
|
||||
@@ -537,8 +535,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
|
||||
}
|
||||
|
||||
/* Setup parenthood. */
|
||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
||||
const AbcObjectReader *reader = *iter;
|
||||
for (AbcObjectReader *reader : data->reader_manager.data_readers()) {
|
||||
const AbcObjectReader *parent_reader = reader->parent_reader;
|
||||
Object *ob = reader->object();
|
||||
|
||||
@@ -552,8 +549,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
|
||||
|
||||
/* Setup transformations and constraints. */
|
||||
i = 0;
|
||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
||||
AbcObjectReader *reader = *iter;
|
||||
for (AbcObjectReader *reader : data->reader_manager.data_readers()) {
|
||||
reader->setupObjectTransform(0.0f);
|
||||
|
||||
*data->progress = 0.7f + 0.3f * (++i / size);
|
||||
@@ -572,12 +568,10 @@ static void import_endjob(void *user_data)
|
||||
|
||||
ImportJobData *data = static_cast<ImportJobData *>(user_data);
|
||||
|
||||
std::vector<AbcObjectReader *>::iterator iter;
|
||||
|
||||
/* Delete objects on cancellation. */
|
||||
if (data->was_cancelled) {
|
||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
||||
Object *ob = (*iter)->object();
|
||||
for (AbcObjectReader *reader : data->reader_manager.all_readers()) {
|
||||
Object *ob = reader->object();
|
||||
|
||||
/* It's possible that cancellation occurred between the creation of
|
||||
* the reader and the creation of the Blender object. */
|
||||
@@ -598,8 +592,8 @@ static void import_endjob(void *user_data)
|
||||
|
||||
lc = BKE_layer_collection_get_active(view_layer);
|
||||
|
||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
||||
Object *ob = (*iter)->object();
|
||||
for (AbcObjectReader *reader : data->reader_manager.data_readers()) {
|
||||
Object *ob = reader->object();
|
||||
|
||||
BKE_collection_object_add(data->bmain, lc->collection, ob);
|
||||
|
||||
@@ -614,6 +608,24 @@ static void import_endjob(void *user_data)
|
||||
ID_RECALC_BASE_FLAGS);
|
||||
}
|
||||
|
||||
/* Finally, create instances. */
|
||||
for (AbcObjectReader *reader : data->reader_manager.instance_readers()) {
|
||||
if (!reader->valid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
reader->readObjectData(data->bmain, data->reader_manager, {});
|
||||
/* We assume that the instance's parent is the same as that of the source object, so we do
|
||||
* not setup parenthood. */
|
||||
reader->setupObjectTransform(0.0f);
|
||||
|
||||
Object *ob = reader->object();
|
||||
BKE_collection_object_add(data->bmain, lc->collection, ob);
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
|
||||
BKE_main_id_newptr_and_tag_clear(data->bmain);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&data->scene->id, ID_RECALC_BASE_FLAGS);
|
||||
DEG_relations_tag_update(data->bmain);
|
||||
|
||||
@@ -624,8 +636,7 @@ static void import_endjob(void *user_data)
|
||||
}
|
||||
}
|
||||
|
||||
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
|
||||
AbcObjectReader *reader = *iter;
|
||||
for (AbcObjectReader *reader : data->reader_manager.all_readers()) {
|
||||
reader->decref();
|
||||
|
||||
if (reader->refcount() == 0) {
|
||||
@@ -781,23 +792,28 @@ static ISampleSelector sample_selector_for_time(float time)
|
||||
return ISampleSelector(time, ISampleSelector::kFloorIndex);
|
||||
}
|
||||
|
||||
Mesh *ABC_read_mesh(CacheReader *reader,
|
||||
Object *ob,
|
||||
Mesh *existing_mesh,
|
||||
const float time,
|
||||
const char **err_str,
|
||||
const int read_flag,
|
||||
const char *velocity_name,
|
||||
const float velocity_scale)
|
||||
void ABC_read_geometry(CacheReader *reader,
|
||||
Object *ob,
|
||||
GeometrySet &geometry_set,
|
||||
const ABCReadParams *params,
|
||||
const char **err_str)
|
||||
{
|
||||
AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
|
||||
if (abc_reader == nullptr) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
ISampleSelector sample_sel = sample_selector_for_time(time);
|
||||
return abc_reader->read_mesh(
|
||||
existing_mesh, sample_sel, read_flag, velocity_name, velocity_scale, err_str);
|
||||
AttributeSelector attribute_selector(params->mappings);
|
||||
attribute_selector.set_velocity_attribute(params->velocity_name);
|
||||
attribute_selector.set_read_flags(params->read_flags);
|
||||
|
||||
ISampleSelector sample_sel = sample_selector_for_time(params->time);
|
||||
abc_reader->read_geometry(geometry_set,
|
||||
sample_sel,
|
||||
&attribute_selector,
|
||||
params->read_flags,
|
||||
params->velocity_scale,
|
||||
err_str);
|
||||
}
|
||||
|
||||
bool ABC_mesh_topology_changed(
|
||||
|
@@ -25,6 +25,7 @@ set(INC
|
||||
../../bmesh
|
||||
../../depsgraph
|
||||
../../editors/include
|
||||
../../functions
|
||||
../../makesdna
|
||||
../../makesrna
|
||||
../../windowmanager
|
||||
|
@@ -420,20 +420,20 @@ static USDPrimReader *get_usd_reader(CacheReader *reader, Object * /* ob */, con
|
||||
return usd_reader;
|
||||
}
|
||||
|
||||
struct Mesh *USD_read_mesh(struct CacheReader *reader,
|
||||
struct Object *ob,
|
||||
struct Mesh *existing_mesh,
|
||||
const float time,
|
||||
const char **err_str,
|
||||
const int read_flag)
|
||||
void USD_read_geometry(CacheReader *reader,
|
||||
Object *ob,
|
||||
GeometrySet &geometry_set,
|
||||
const float time,
|
||||
const char **err_str,
|
||||
const int read_flag)
|
||||
{
|
||||
USDGeomReader *usd_reader = dynamic_cast<USDGeomReader *>(get_usd_reader(reader, ob, err_str));
|
||||
|
||||
if (usd_reader == nullptr) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
return usd_reader->read_mesh(existing_mesh, time, read_flag, err_str);
|
||||
return usd_reader->read_geometry(geometry_set, time, read_flag, err_str);
|
||||
}
|
||||
|
||||
bool USD_mesh_topology_changed(
|
||||
|
@@ -5,8 +5,10 @@
|
||||
#include "usd_reader_curve.h"
|
||||
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_spline.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
@@ -161,15 +163,39 @@ void USDCurvesReader::read_curve_sample(Curve *cu, const double motionSampleTime
|
||||
}
|
||||
}
|
||||
|
||||
Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh,
|
||||
const double motionSampleTime,
|
||||
const int /* read_flag */,
|
||||
const char ** /* err_str */)
|
||||
static bool topology_changed(CurveEval *curve_eval, const pxr::VtIntArray &usdCounts)
|
||||
{
|
||||
if (!curve_prim_) {
|
||||
return existing_mesh;
|
||||
if (!curve_eval) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (curve_eval->splines().size() != usdCounts.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int curve_idx = 0;
|
||||
for (const SplinePtr &spline : curve_eval->splines()) {
|
||||
const int num_in_usd = usdCounts[curve_idx++];
|
||||
const int num_in_blender = spline->positions().size();
|
||||
|
||||
if (num_in_usd != num_in_blender) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void USDCurvesReader::read_geometry(GeometrySet &geometry_set,
|
||||
double motionSampleTime,
|
||||
int /* read_flag */,
|
||||
const char ** /* err_str */)
|
||||
{
|
||||
if (!curve_prim_) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
pxr::UsdAttribute widthsAttr = curve_prim_.GetWidthsAttr();
|
||||
pxr::UsdAttribute vertexAttr = curve_prim_.GetCurveVertexCountsAttr();
|
||||
pxr::UsdAttribute pointsAttr = curve_prim_.GetPointsAttr();
|
||||
@@ -177,62 +203,37 @@ Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh,
|
||||
pxr::VtIntArray usdCounts;
|
||||
|
||||
vertexAttr.Get(&usdCounts, motionSampleTime);
|
||||
int num_subcurves = usdCounts.size();
|
||||
|
||||
pxr::VtVec3fArray usdPoints;
|
||||
pointsAttr.Get(&usdPoints, motionSampleTime);
|
||||
|
||||
int vertex_idx = 0;
|
||||
int curve_idx;
|
||||
Curve *curve = static_cast<Curve *>(object_->data);
|
||||
CurveEval *curve_eval = geometry_set.get_curve_for_write();
|
||||
|
||||
const int curve_count = BLI_listbase_count(&curve->nurb);
|
||||
bool same_topology = curve_count == num_subcurves;
|
||||
|
||||
if (same_topology) {
|
||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
||||
for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
|
||||
const int num_in_usd = usdCounts[curve_idx];
|
||||
const int num_in_blender = nurbs->pntsu;
|
||||
|
||||
if (num_in_usd != num_in_blender) {
|
||||
same_topology = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!same_topology) {
|
||||
if (blender::io::usd::topology_changed(curve_eval, usdCounts)) {
|
||||
Curve *curve = static_cast<Curve *>(object_->data);
|
||||
BKE_nurbList_free(&curve->nurb);
|
||||
read_curve_sample(curve, motionSampleTime);
|
||||
|
||||
std::unique_ptr<CurveEval> new_curve_eval = curve_eval_from_dna_curve(*curve);
|
||||
geometry_set.replace_curve(new_curve_eval.release(), GeometryOwnershipType::Editable);
|
||||
}
|
||||
else {
|
||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
||||
for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
|
||||
const int totpoint = usdCounts[curve_idx];
|
||||
BLI_assert_msg(curve_eval, "curve_eval is null although the topology is the same !");
|
||||
const int curve_count = curve_eval->splines().size();
|
||||
for (curve_idx = 0; curve_idx < curve_count; curve_idx++) {
|
||||
Spline *spline = curve_eval->splines()[curve_idx].get();
|
||||
|
||||
if (nurbs->bp) {
|
||||
BPoint *point = nurbs->bp;
|
||||
|
||||
for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
|
||||
point->vec[0] = usdPoints[vertex_idx][0];
|
||||
point->vec[1] = usdPoints[vertex_idx][1];
|
||||
point->vec[2] = usdPoints[vertex_idx][2];
|
||||
}
|
||||
}
|
||||
else if (nurbs->bezt) {
|
||||
BezTriple *bezier = nurbs->bezt;
|
||||
|
||||
for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
|
||||
bezier->vec[1][0] = usdPoints[vertex_idx][0];
|
||||
bezier->vec[1][1] = usdPoints[vertex_idx][1];
|
||||
bezier->vec[1][2] = usdPoints[vertex_idx][2];
|
||||
}
|
||||
for (float3 &position : spline->positions()) {
|
||||
position.x = usdPoints[vertex_idx][0];
|
||||
position.y = usdPoints[vertex_idx][0];
|
||||
position.z = usdPoints[vertex_idx][0];
|
||||
vertex_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BKE_mesh_new_nomain_from_curve(object_);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
@@ -35,10 +35,10 @@ class USDCurvesReader : public USDGeomReader {
|
||||
|
||||
void read_curve_sample(Curve *cu, double motionSampleTime);
|
||||
|
||||
Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||
double motionSampleTime,
|
||||
int read_flag,
|
||||
const char **err_str) override;
|
||||
void read_geometry(GeometrySet &geometry_set,
|
||||
double motionSampleTime,
|
||||
int read_flag,
|
||||
const char **err_str) override;
|
||||
};
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include "usd.h"
|
||||
#include "usd_reader_xform.h"
|
||||
|
||||
struct GeometrySet;
|
||||
struct Mesh;
|
||||
|
||||
namespace blender::io::usd {
|
||||
@@ -19,10 +20,10 @@ class USDGeomReader : public USDXformReader {
|
||||
{
|
||||
}
|
||||
|
||||
virtual Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||
double motionSampleTime,
|
||||
int read_flag,
|
||||
const char **err_str) = 0;
|
||||
virtual void read_geometry(GeometrySet &geometry_set,
|
||||
double motionSampleTime,
|
||||
int read_flag,
|
||||
const char **err_str) = 0;
|
||||
|
||||
virtual bool topology_changed(Mesh * /* existing_mesh */, double /* motionSampleTime */)
|
||||
{
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include "usd_reader_material.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_mesh.h"
|
||||
@@ -866,4 +867,17 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
|
||||
return active_mesh;
|
||||
}
|
||||
|
||||
void USDMeshReader::read_geometry(GeometrySet &geometry_set,
|
||||
double motionSampleTime,
|
||||
int read_flag,
|
||||
const char **err_str)
|
||||
{
|
||||
Mesh *existing_mesh = geometry_set.get_mesh_for_write();
|
||||
Mesh *new_mesh = read_mesh(existing_mesh, motionSampleTime, read_flag, err_str);
|
||||
|
||||
if (new_mesh != existing_mesh) {
|
||||
geometry_set.replace_mesh(new_mesh);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
@@ -48,10 +48,10 @@ class USDMeshReader : public USDGeomReader {
|
||||
void create_object(Main *bmain, double motionSampleTime) override;
|
||||
void read_object_data(Main *bmain, double motionSampleTime) override;
|
||||
|
||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||
double motionSampleTime,
|
||||
int read_flag,
|
||||
const char **err_str) override;
|
||||
void read_geometry(GeometrySet &geometry_set,
|
||||
double motionSampleTime,
|
||||
int read_flag,
|
||||
const char **err_str) override;
|
||||
|
||||
bool topology_changed(Mesh *existing_mesh, double motionSampleTime) override;
|
||||
|
||||
@@ -75,6 +75,11 @@ class USDMeshReader : public USDGeomReader {
|
||||
Mesh *mesh,
|
||||
double motionSampleTime,
|
||||
bool new_mesh);
|
||||
|
||||
struct Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||
double motionSampleTime,
|
||||
int read_flag,
|
||||
const char **err_str);
|
||||
};
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
@@ -5,8 +5,10 @@
|
||||
#include "usd_reader_nurbs.h"
|
||||
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_spline.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
@@ -164,11 +166,35 @@ void USDNurbsReader::read_curve_sample(Curve *cu, const double motionSampleTime)
|
||||
}
|
||||
}
|
||||
|
||||
Mesh *USDNurbsReader::read_mesh(struct Mesh * /* existing_mesh */,
|
||||
const double motionSampleTime,
|
||||
const int /* read_flag */,
|
||||
const char ** /* err_str */)
|
||||
static bool topology_changed(CurveEval *curve_eval, const pxr::VtIntArray &usdCounts)
|
||||
{
|
||||
if (!curve_eval) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (curve_eval->splines().size() != usdCounts.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int curve_idx = 0;
|
||||
for (const SplinePtr &spline : curve_eval->splines()) {
|
||||
const int num_in_usd = usdCounts[curve_idx++];
|
||||
const int num_in_blender = spline->positions().size();
|
||||
|
||||
if (num_in_usd != num_in_blender) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void USDNurbsReader::read_geometry(GeometrySet &geometry_set,
|
||||
double motionSampleTime,
|
||||
int /* read_flag */,
|
||||
const char ** /* err_str */)
|
||||
{
|
||||
#if 0
|
||||
pxr::UsdGeomCurves curve_prim_(prim_);
|
||||
|
||||
pxr::UsdAttribute widthsAttr = curve_prim_.GetWidthsAttr();
|
||||
@@ -178,62 +204,37 @@ Mesh *USDNurbsReader::read_mesh(struct Mesh * /* existing_mesh */,
|
||||
pxr::VtIntArray usdCounts;
|
||||
|
||||
vertexAttr.Get(&usdCounts, motionSampleTime);
|
||||
int num_subcurves = usdCounts.size();
|
||||
|
||||
pxr::VtVec3fArray usdPoints;
|
||||
pointsAttr.Get(&usdPoints, motionSampleTime);
|
||||
|
||||
int vertex_idx = 0;
|
||||
int curve_idx;
|
||||
Curve *curve = static_cast<Curve *>(object_->data);
|
||||
CurveEval *curve_eval = geometry_set.get_curve_for_write();
|
||||
|
||||
const int curve_count = BLI_listbase_count(&curve->nurb);
|
||||
bool same_topology = curve_count == num_subcurves;
|
||||
|
||||
if (same_topology) {
|
||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
||||
for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
|
||||
const int num_in_usd = usdCounts[curve_idx];
|
||||
const int num_in_blender = nurbs->pntsu;
|
||||
|
||||
if (num_in_usd != num_in_blender) {
|
||||
same_topology = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!same_topology) {
|
||||
if (blender::io::usd::topology_changed(curve_eval, usdCounts)) {
|
||||
Curve *curve = static_cast<Curve *>(object_->data);
|
||||
BKE_nurbList_free(&curve->nurb);
|
||||
read_curve_sample(curve, motionSampleTime);
|
||||
|
||||
std::unique_ptr<CurveEval> new_curve_eval = curve_eval_from_dna_curve(*curve);
|
||||
geometry_set.replace_curve(new_curve_eval.release(), GeometryOwnershipType::Editable);
|
||||
}
|
||||
else {
|
||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
||||
for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
|
||||
const int totpoint = usdCounts[curve_idx];
|
||||
BLI_assert_msg(curve_eval, "curve_eval is null although the topology is the same !");
|
||||
const int curve_count = curve_eval->splines().size();
|
||||
for (curve_idx = 0; curve_idx < curve_count; curve_idx++) {
|
||||
Spline *spline = curve_eval->splines()[curve_idx].get();
|
||||
|
||||
if (nurbs->bp) {
|
||||
BPoint *point = nurbs->bp;
|
||||
|
||||
for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
|
||||
point->vec[0] = usdPoints[vertex_idx][0];
|
||||
point->vec[1] = usdPoints[vertex_idx][1];
|
||||
point->vec[2] = usdPoints[vertex_idx][2];
|
||||
}
|
||||
}
|
||||
else if (nurbs->bezt) {
|
||||
BezTriple *bezier = nurbs->bezt;
|
||||
|
||||
for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
|
||||
bezier->vec[1][0] = usdPoints[vertex_idx][0];
|
||||
bezier->vec[1][1] = usdPoints[vertex_idx][1];
|
||||
bezier->vec[1][2] = usdPoints[vertex_idx][2];
|
||||
}
|
||||
for (float3 &position : spline->positions()) {
|
||||
position.x = usdPoints[vertex_idx][0];
|
||||
position.y = usdPoints[vertex_idx][0];
|
||||
position.z = usdPoints[vertex_idx][0];
|
||||
vertex_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BKE_mesh_new_nomain_from_curve(object_);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
@@ -35,10 +35,10 @@ class USDNurbsReader : public USDGeomReader {
|
||||
|
||||
void read_curve_sample(Curve *cu, double motionSampleTime);
|
||||
|
||||
Mesh *read_mesh(struct Mesh *existing_mesh,
|
||||
double motionSampleTime,
|
||||
int read_flag,
|
||||
const char **err_str) override;
|
||||
void read_geometry(GeometrySet &geometry_set,
|
||||
double motionSampleTime,
|
||||
int read_flag,
|
||||
const char **err_str) override;
|
||||
};
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
@@ -12,6 +12,8 @@ extern "C" {
|
||||
struct CacheArchiveHandle;
|
||||
struct CacheFile;
|
||||
struct CacheReader;
|
||||
struct GeometrySet;
|
||||
struct Mesh;
|
||||
struct Object;
|
||||
struct bContext;
|
||||
|
||||
@@ -90,13 +92,14 @@ void USD_free_handle(struct CacheArchiveHandle *handle);
|
||||
|
||||
void USD_get_transform(struct CacheReader *reader, float r_mat[4][4], float time, float scale);
|
||||
|
||||
/* Either modifies current_mesh in-place or constructs a new mesh. */
|
||||
struct Mesh *USD_read_mesh(struct CacheReader *reader,
|
||||
struct Object *ob,
|
||||
struct Mesh *existing_mesh,
|
||||
float time,
|
||||
const char **err_str,
|
||||
int read_flag);
|
||||
#ifdef __cplusplus
|
||||
void USD_read_geometry(CacheReader *reader,
|
||||
Object *ob,
|
||||
GeometrySet &geometry_set,
|
||||
const float time,
|
||||
const char **err_str,
|
||||
const int read_flag);
|
||||
#endif
|
||||
|
||||
bool USD_mesh_topology_changed(struct CacheReader *reader,
|
||||
struct Object *ob,
|
||||
|
@@ -55,6 +55,44 @@ typedef struct CacheFileLayer {
|
||||
int _pad;
|
||||
} CacheFileLayer;
|
||||
|
||||
/* CacheAttributeMapping::mapping */
|
||||
enum {
|
||||
/* Default mapping, so we do not make an arbitrary decision as to what is the default. Also used
|
||||
* to mark the mapping as ignored. */
|
||||
CACHEFILE_ATTRIBUTE_MAP_NONE,
|
||||
CACHEFILE_ATTRIBUTE_MAP_TO_UVS,
|
||||
CACHEFILE_ATTRIBUTE_MAP_TO_VERTEX_COLORS,
|
||||
CACHEFILE_ATTRIBUTE_MAP_TO_WEIGHT_GROUPS,
|
||||
CACHEFILE_ATTRIBUTE_MAP_TO_FLOAT2,
|
||||
CACHEFILE_ATTRIBUTE_MAP_TO_FLOAT3,
|
||||
CACHEFILE_ATTRIBUTE_MAP_TO_COLOR,
|
||||
};
|
||||
|
||||
/* CacheAttributeMapping::domain */
|
||||
enum {
|
||||
/* Try to automatically map the attribute to the right domain (default behavior without mapping.)
|
||||
*/
|
||||
CACHEFILE_ATTR_MAP_DOMAIN_AUTO,
|
||||
CACHEFILE_ATTR_MAP_DOMAIN_POINT,
|
||||
CACHEFILE_ATTR_MAP_DOMAIN_FACE_CORNER,
|
||||
CACHEFILE_ATTR_MAP_DOMAIN_FACE,
|
||||
CACHEFILE_ATTR_MAP_DOMAIN_CURVE,
|
||||
};
|
||||
|
||||
/* Custom data mapping for the attributes in the CacheFile. Since there might not be a standard way
|
||||
* of expressing what an attribute should be (e.g. is this float2 attribute a UV map?), and since
|
||||
* some software might write multi-dimensionnal data as arrays of 1D element (although the size of
|
||||
* the array will be N-time its expected size were it written as N-D data), we delegate to the user
|
||||
* the task of telling us what is supposed to be what through these mappings. */
|
||||
typedef struct CacheAttributeMapping {
|
||||
struct CacheAttributeMapping *next, *prev;
|
||||
|
||||
char name[64];
|
||||
char mapping;
|
||||
char domain;
|
||||
char _pad[6];
|
||||
} CacheAttributeMapping;
|
||||
|
||||
/* CacheFile::velocity_unit
|
||||
* Determines what temporal unit is used to interpret velocity vectors for motion blur effects. */
|
||||
enum {
|
||||
@@ -85,7 +123,8 @@ typedef struct CacheFile {
|
||||
/** The frame offset to subtract. */
|
||||
float frame_offset;
|
||||
|
||||
char _pad[4];
|
||||
/** Index of the currently selected attribute mapping in the UI, starts at 1 */
|
||||
int active_attribute_mapping;
|
||||
|
||||
/** Animation flag. */
|
||||
short flag;
|
||||
@@ -116,6 +155,8 @@ typedef struct CacheFile {
|
||||
/* Name of the velocity property in the archive. */
|
||||
char velocity_name[64];
|
||||
|
||||
ListBase attribute_mappings;
|
||||
|
||||
/* Runtime */
|
||||
struct CacheArchiveHandle *handle;
|
||||
char handle_filepath[1024];
|
||||
|
@@ -92,6 +92,7 @@ extern StructRNA RNA_ByteColorAttribute;
|
||||
extern StructRNA RNA_ByteColorAttributeValue;
|
||||
extern StructRNA RNA_ByteIntAttribute;
|
||||
extern StructRNA RNA_ByteIntAttributeValue;
|
||||
extern StructRNA RNA_CacheAttributeMapping;
|
||||
extern StructRNA RNA_CacheFile;
|
||||
extern StructRNA RNA_CacheFileLayer;
|
||||
extern StructRNA RNA_Camera;
|
||||
|
@@ -47,6 +47,16 @@ static void rna_CacheFileLayer_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
|
||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
||||
}
|
||||
|
||||
static void rna_CacheFile_attribute_mapping_update(Main *UNUSED(bmain),
|
||||
Scene *UNUSED(scene),
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||
|
||||
DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
||||
}
|
||||
|
||||
static void rna_CacheFile_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
rna_CacheFile_update(bmain, scene, ptr);
|
||||
@@ -144,6 +154,87 @@ static void rna_CacheFile_layer_remove(CacheFile *cache_file, bContext *C, Point
|
||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
||||
}
|
||||
|
||||
static CacheAttributeMapping *rna_CacheFile_attribute_mapping_new(CacheFile *cache_file,
|
||||
bContext *C,
|
||||
ReportList *reports,
|
||||
const char *name,
|
||||
const int mapping_type,
|
||||
const int domain)
|
||||
{
|
||||
CacheAttributeMapping *mapping = BKE_cachefile_add_attribute_mapping(
|
||||
cache_file, name, mapping_type, domain);
|
||||
if (mapping == NULL) {
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"Cannot add an attribute mapping to CacheFile '%s'",
|
||||
cache_file->id.name + 2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
BKE_cachefile_reload(depsgraph, cache_file);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
static void rna_CacheFile_attribute_mapping_remove(CacheFile *cache_file,
|
||||
bContext *C,
|
||||
PointerRNA *mapping_ptr)
|
||||
{
|
||||
CacheAttributeMapping *mapping = mapping_ptr->data;
|
||||
BKE_cachefile_remove_attribute_mapping(cache_file, mapping);
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
BKE_cachefile_reload(depsgraph, cache_file);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
|
||||
}
|
||||
|
||||
static PointerRNA rna_CacheFile_active_attribute_mapping_get(PointerRNA *ptr)
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||
return rna_pointer_inherit_refine(
|
||||
ptr, &RNA_CacheAttributeMapping, BKE_cachefile_get_active_attribute_mapping(cache_file));
|
||||
}
|
||||
|
||||
static void rna_CacheFile_active_attribute_mapping_set(PointerRNA *ptr,
|
||||
PointerRNA value,
|
||||
struct ReportList *reports)
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||
int index = BLI_findindex(&cache_file->attribute_mappings, value.data);
|
||||
if (index == -1) {
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"Attribute mapping '%s' not found in object '%s'",
|
||||
((CacheAttributeMapping *)value.data)->name,
|
||||
cache_file->id.name + 2);
|
||||
cache_file->active_attribute_mapping = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
cache_file->active_attribute_mapping = index + 1;
|
||||
}
|
||||
|
||||
static int rna_CacheFile_active_attribute_mapping_index_get(PointerRNA *ptr)
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||
return cache_file->active_attribute_mapping - 1;
|
||||
}
|
||||
|
||||
static void rna_CacheFile_active_attribute_mapping_index_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||
cache_file->active_attribute_mapping = value + 1;
|
||||
}
|
||||
|
||||
static void rna_CacheFile_active_attribute_mapping_index_range(
|
||||
PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)ptr->owner_id;
|
||||
|
||||
*min = 0;
|
||||
*max = max_ii(0, BLI_listbase_count(&cache_file->attribute_mappings) - 1);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* cachefile.object_paths */
|
||||
@@ -163,6 +254,148 @@ static void rna_def_alembic_object_path(BlenderRNA *brna)
|
||||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
static const EnumPropertyItem rna_enum_cache_attribute_mapping_items[] = {
|
||||
{CACHEFILE_ATTRIBUTE_MAP_NONE, "MAP_NONE", 0, "None", ""},
|
||||
{CACHEFILE_ATTRIBUTE_MAP_TO_UVS,
|
||||
"MAP_TO_UVS",
|
||||
0,
|
||||
"UVs",
|
||||
"Read the attribute as a UV map of the same name"},
|
||||
{CACHEFILE_ATTRIBUTE_MAP_TO_VERTEX_COLORS,
|
||||
"MAP_TO_VERTEX_COLORS",
|
||||
0,
|
||||
"Vertex Colors",
|
||||
"Read the attribute as a vertex color layer of the same name"},
|
||||
{CACHEFILE_ATTRIBUTE_MAP_TO_WEIGHT_GROUPS,
|
||||
"MAP_TO_WEIGHT_GROUPS",
|
||||
0,
|
||||
"Weight Group",
|
||||
"Read the attribute as a weight group channel of the same name"},
|
||||
{CACHEFILE_ATTRIBUTE_MAP_TO_FLOAT2,
|
||||
"MAP_TO_FLOAT2",
|
||||
0,
|
||||
"2D Vector",
|
||||
"Interpret the attribute's data as generic 2D vectors"},
|
||||
{CACHEFILE_ATTRIBUTE_MAP_TO_FLOAT3,
|
||||
"MAP_TO_FLOAT3",
|
||||
0,
|
||||
"3D Vector",
|
||||
"Interpret the attribute's data as generic 3D vectors"},
|
||||
{CACHEFILE_ATTRIBUTE_MAP_TO_COLOR,
|
||||
"MAP_TO_COLOR",
|
||||
0,
|
||||
"Color",
|
||||
"Interpret the attribute's data as colors (RGBA)"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem rna_enum_cache_attribute_domain_items[] = {
|
||||
{CACHEFILE_ATTR_MAP_DOMAIN_AUTO,
|
||||
"AUTO",
|
||||
0,
|
||||
"Automatic",
|
||||
"Try to automatically determine the domain of the attribute"},
|
||||
{CACHEFILE_ATTR_MAP_DOMAIN_POINT,
|
||||
"POINT",
|
||||
0,
|
||||
"Point",
|
||||
"The attribute is defined for each point"},
|
||||
{CACHEFILE_ATTR_MAP_DOMAIN_FACE_CORNER,
|
||||
"FACE_CORNER",
|
||||
0,
|
||||
"Face Corner",
|
||||
"The attribute is defined for each face corner"},
|
||||
{CACHEFILE_ATTR_MAP_DOMAIN_FACE, "FACE", 0, "Face", "The attribute is defined for each face"},
|
||||
{CACHEFILE_ATTR_MAP_DOMAIN_CURVE,
|
||||
"CURVE",
|
||||
0,
|
||||
"Curve",
|
||||
"The attribute is defined for each curve"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static void rna_def_cachefile_attribute_mapping(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna = RNA_def_struct(brna, "CacheAttributeMapping", NULL);
|
||||
RNA_def_struct_sdna(srna, "CacheAttributeMapping");
|
||||
RNA_def_struct_ui_text(
|
||||
srna,
|
||||
"Cache Attribute Mapping",
|
||||
"Attribute Mappin of the cache, used to define how to interpret certain attributes");
|
||||
|
||||
PropertyRNA *prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Name", "Name of the attribute to map");
|
||||
RNA_def_property_update(prop, 0, "rna_CacheFile_attribute_mapping_update");
|
||||
|
||||
prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_cache_attribute_mapping_items);
|
||||
RNA_def_property_update(prop, 0, "rna_CacheFile_attribute_mapping_update");
|
||||
RNA_def_property_ui_text(prop, "Data Type", "Define the data type of the attribute");
|
||||
|
||||
prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_cache_attribute_domain_items);
|
||||
RNA_def_property_update(prop, 0, "rna_CacheFile_attribute_mapping_update");
|
||||
RNA_def_property_ui_text(prop, "Domain", "Define the domain on which the attribute is written");
|
||||
}
|
||||
|
||||
static void rna_def_cachefile_attribute_mappings(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
{
|
||||
RNA_def_property_srna(cprop, "CacheAttributeMappings");
|
||||
StructRNA *srna = RNA_def_struct(brna, "CacheAttributeMappings", NULL);
|
||||
RNA_def_struct_sdna(srna, "CacheFile");
|
||||
RNA_def_struct_ui_text(
|
||||
srna, "Cache Attribute Mappings", "Collection of cache attribute mappings");
|
||||
|
||||
PropertyRNA *prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "CacheAttributeMapping");
|
||||
RNA_def_property_pointer_funcs(prop,
|
||||
"rna_CacheFile_active_attribute_mapping_get",
|
||||
"rna_CacheFile_active_attribute_mapping_set",
|
||||
NULL,
|
||||
NULL);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Active Attribute Mapping", "Active attribute mapping of the CacheFile");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Active Attribute Mapping Index", "Active index in attribute mappings array");
|
||||
|
||||
FunctionRNA *func;
|
||||
PropertyRNA *parm;
|
||||
|
||||
/* Add a mapping. */
|
||||
func = RNA_def_function(srna, "new", "rna_CacheFile_attribute_mapping_new");
|
||||
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
|
||||
RNA_def_function_ui_description(func, "Add a new attribute mapping");
|
||||
/* Optional parameters. */
|
||||
parm = RNA_def_string(func, "name", "Name", 64, "Name", "Name of the attribute to remap");
|
||||
parm = RNA_def_enum(func,
|
||||
"mapping_type",
|
||||
rna_enum_cache_attribute_mapping_items,
|
||||
CACHEFILE_ATTRIBUTE_MAP_NONE,
|
||||
"Mapping Type",
|
||||
"Type of the mapping");
|
||||
parm = RNA_def_enum(func,
|
||||
"domain",
|
||||
rna_enum_cache_attribute_domain_items,
|
||||
CACHEFILE_ATTR_MAP_DOMAIN_AUTO,
|
||||
"Domain",
|
||||
"Original domain of the attribute to remap");
|
||||
/* Return type. */
|
||||
parm = RNA_def_pointer(
|
||||
func, "mapping", "CacheAttributeMapping", "", "Newly created attribute mapping");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
/* Remove a mapping. */
|
||||
func = RNA_def_function(srna, "remove", "rna_CacheFile_attribute_mapping_remove");
|
||||
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
||||
RNA_def_function_ui_description(func,
|
||||
"Remove an existing attribute mapping from the cache file");
|
||||
parm = RNA_def_pointer(
|
||||
func, "mapping", "CacheAttributeMapping", "", "Attribute mapping to remove");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
|
||||
}
|
||||
|
||||
/* cachefile.object_paths */
|
||||
static void rna_def_cachefile_object_paths(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
{
|
||||
@@ -255,6 +488,18 @@ static void rna_def_cachefile(BlenderRNA *brna)
|
||||
"Alembic data themselves if possible");
|
||||
RNA_def_property_update(prop, 0, "rna_CacheFile_dependency_update");
|
||||
|
||||
static const EnumPropertyItem cache_file_type_items[] = {
|
||||
{CACHE_FILE_TYPE_INVALID, "INVALID", 0, "Invalid", ""},
|
||||
{CACHEFILE_TYPE_ALEMBIC, "ALEMBIC", 0, "Alembic", ""},
|
||||
{CACHEFILE_TYPE_USD, "USD", 0, "USD", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, cache_file_type_items);
|
||||
RNA_def_property_ui_text(prop, "Type", "Type of the file used for storing data");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
|
||||
/* ----------------- For Scene time ------------------- */
|
||||
|
||||
prop = RNA_def_property(srna, "override_frame", PROP_BOOLEAN, PROP_NONE);
|
||||
@@ -384,6 +629,23 @@ static void rna_def_cachefile(BlenderRNA *brna)
|
||||
"rna_CacheFile_active_layer_index_set",
|
||||
"rna_CacheFile_active_layer_index_range");
|
||||
|
||||
/* ----------------- Attribute Mappings ----------------- */
|
||||
|
||||
prop = RNA_def_property(srna, "attribute_mappings", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, NULL, "attribute_mappings", NULL);
|
||||
RNA_def_property_struct_type(prop, "CacheAttributeMapping");
|
||||
RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
|
||||
RNA_def_property_ui_text(prop, "Cache Attribute Mappings", "Attribute mappings of the cache");
|
||||
rna_def_cachefile_attribute_mappings(brna, prop);
|
||||
|
||||
prop = RNA_def_property(srna, "active_attribute_mapping_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "active_attribute_mapping");
|
||||
RNA_def_property_int_funcs(prop,
|
||||
"rna_CacheFile_active_attribute_mapping_index_get",
|
||||
"rna_CacheFile_active_attribute_mapping_index_set",
|
||||
"rna_CacheFile_active_attribute_mapping_index_range");
|
||||
|
||||
RNA_define_lib_overridable(false);
|
||||
|
||||
rna_def_cachefile_object_paths(brna, prop);
|
||||
@@ -396,6 +658,7 @@ void RNA_def_cachefile(BlenderRNA *brna)
|
||||
rna_def_cachefile(brna);
|
||||
rna_def_alembic_object_path(brna);
|
||||
rna_def_cachefile_layer(brna);
|
||||
rna_def_cachefile_attribute_mapping(brna);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -59,7 +59,7 @@ set(SRC
|
||||
intern/MOD_meshcache_pc2.c
|
||||
intern/MOD_meshcache_util.c
|
||||
intern/MOD_meshdeform.c
|
||||
intern/MOD_meshsequencecache.c
|
||||
intern/MOD_meshsequencecache.cc
|
||||
intern/MOD_mirror.c
|
||||
intern/MOD_multires.c
|
||||
intern/MOD_nodes.cc
|
||||
|
@@ -25,11 +25,14 @@
|
||||
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_curve_to_mesh.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_lib_query.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_screen.h"
|
||||
#include "BKE_spline.hh"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
@@ -79,7 +82,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
|
||||
|
||||
BKE_modifier_copydata_generic(md, target, flag);
|
||||
|
||||
tmcmd->reader = NULL;
|
||||
tmcmd->reader = nullptr;
|
||||
tmcmd->reader_object_path[0] = '\0';
|
||||
}
|
||||
|
||||
@@ -100,7 +103,41 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
|
||||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
||||
|
||||
/* leave it up to the modifier to check the file is valid on calculation */
|
||||
return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0');
|
||||
return (mcmd->cache_file == nullptr) || (mcmd->object_path[0] == '\0');
|
||||
}
|
||||
|
||||
/* If this invocation is for the ORCO mesh, and the mesh hasn't changed topology, we
|
||||
* must return the mesh as-is instead of deforming it. */
|
||||
static bool need_orco_mesh(MeshSeqCacheModifierData *mcmd,
|
||||
const ModifierEvalContext *ctx,
|
||||
Mesh *mesh,
|
||||
float time,
|
||||
const char **err_str)
|
||||
{
|
||||
CacheFile *cache_file = mcmd->cache_file;
|
||||
|
||||
if (ctx->flag & MOD_APPLY_ORCO) {
|
||||
switch (cache_file->type) {
|
||||
case CACHEFILE_TYPE_ALEMBIC:
|
||||
#ifdef WITH_ALEMBIC
|
||||
if (!ABC_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, err_str)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case CACHEFILE_TYPE_USD:
|
||||
#ifdef WITH_USD
|
||||
if (!USD_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, err_str)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case CACHE_FILE_TYPE_INVALID:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh)
|
||||
@@ -141,20 +178,103 @@ static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void modifyGeometry(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
GeometrySet &geometry_set)
|
||||
{
|
||||
#ifdef WITH_ALEMBIC
|
||||
MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
|
||||
|
||||
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
|
||||
CacheFile *cache_file = mcmd->cache_file;
|
||||
const float frame = DEG_get_ctime(ctx->depsgraph);
|
||||
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
|
||||
const char *err_str = nullptr;
|
||||
|
||||
if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) {
|
||||
STRNCPY(mcmd->reader_object_path, mcmd->object_path);
|
||||
BKE_cachefile_reader_open(cache_file, &mcmd->reader, ctx->object, mcmd->object_path);
|
||||
if (!mcmd->reader) {
|
||||
BKE_modifier_set_error(
|
||||
ctx->object, md, "Could not create Alembic reader for file %s", cache_file->filepath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (geometry_set.has_mesh()) {
|
||||
Mesh *mesh = geometry_set.get_mesh_for_write();
|
||||
if (need_orco_mesh(mcmd, ctx, mesh, time, &err_str)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not process data if using a render procedural, return a box instead for displaying in the
|
||||
* viewport. */
|
||||
if (BKE_cache_file_uses_render_procedural(cache_file, scene, DEG_get_mode(ctx->depsgraph))) {
|
||||
Mesh *org_mesh = nullptr;
|
||||
if (geometry_set.has_mesh()) {
|
||||
org_mesh = geometry_set.get_mesh_for_write();
|
||||
}
|
||||
|
||||
Mesh *bbox = generate_bounding_box_mesh(ctx->object, org_mesh);
|
||||
geometry_set = GeometrySet::create_with_mesh(bbox, GeometryOwnershipType::Editable);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Time (in frames or seconds) between two velocity samples. Automatically computed to
|
||||
* scale the velocity vectors at render time for generating proper motion blur data. */
|
||||
float velocity_scale = mcmd->velocity_scale;
|
||||
if (mcmd->cache_file->velocity_unit == CACHEFILE_VELOCITY_UNIT_FRAME) {
|
||||
velocity_scale *= FPS;
|
||||
}
|
||||
|
||||
switch (cache_file->type) {
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
# ifdef WITH_ALEMBIC
|
||||
case CACHEFILE_TYPE_ALEMBIC: {
|
||||
ABCReadParams params;
|
||||
params.time = time;
|
||||
params.read_flags = mcmd->read_flag;
|
||||
params.velocity_name = mcmd->cache_file->velocity_name;
|
||||
params.velocity_scale = velocity_scale;
|
||||
params.mappings = &mcmd->cache_file->attribute_mappings;
|
||||
ABC_read_geometry(mcmd->reader, ctx->object, geometry_set, ¶ms, &err_str);
|
||||
break;
|
||||
}
|
||||
# endif
|
||||
# ifdef WITH_USD
|
||||
case CACHEFILE_TYPE_USD: {
|
||||
USD_read_geometry(mcmd->reader, ctx->object, geometry_set, time, &err_str, mcmd->read_flag);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
if (err_str) {
|
||||
BKE_modifier_set_error(ctx->object, md, "%s", err_str);
|
||||
}
|
||||
|
||||
#else
|
||||
UNUSED_VARS(ctx, md, geometry_set);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
|
||||
{
|
||||
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
|
||||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
||||
|
||||
/* Only used to check whether we are operating on org data or not... */
|
||||
Mesh *me = (ctx->object->type == OB_MESH) ? ctx->object->data : NULL;
|
||||
Mesh *me = (ctx->object->type == OB_MESH) ? static_cast<Mesh *>(ctx->object->data) : nullptr;
|
||||
Mesh *org_mesh = mesh;
|
||||
|
||||
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
|
||||
CacheFile *cache_file = mcmd->cache_file;
|
||||
const float frame = DEG_get_ctime(ctx->depsgraph);
|
||||
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
|
||||
const char *err_str = NULL;
|
||||
const char *err_str = nullptr;
|
||||
|
||||
if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) {
|
||||
STRNCPY(mcmd->reader_object_path, mcmd->object_path);
|
||||
@@ -172,30 +292,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
||||
return generate_bounding_box_mesh(ctx->object, org_mesh);
|
||||
}
|
||||
|
||||
/* If this invocation is for the ORCO mesh, and the mesh hasn't changed topology, we
|
||||
* must return the mesh as-is instead of deforming it. */
|
||||
if (ctx->flag & MOD_APPLY_ORCO) {
|
||||
switch (cache_file->type) {
|
||||
case CACHEFILE_TYPE_ALEMBIC:
|
||||
# ifdef WITH_ALEMBIC
|
||||
if (!ABC_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, &err_str)) {
|
||||
return mesh;
|
||||
}
|
||||
# endif
|
||||
break;
|
||||
case CACHEFILE_TYPE_USD:
|
||||
# ifdef WITH_USD
|
||||
if (!USD_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, &err_str)) {
|
||||
return mesh;
|
||||
}
|
||||
# endif
|
||||
break;
|
||||
case CACHE_FILE_TYPE_INVALID:
|
||||
break;
|
||||
}
|
||||
if (need_orco_mesh(mcmd, ctx, mesh, time, &err_str)) {
|
||||
return mesh;
|
||||
}
|
||||
|
||||
if (me != NULL) {
|
||||
if (me != nullptr) {
|
||||
MVert *mvert = mesh->mvert;
|
||||
MEdge *medge = mesh->medge;
|
||||
MPoly *mpoly = mesh->mpoly;
|
||||
@@ -204,53 +305,46 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
||||
* flags) and duplicate those too. */
|
||||
if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
|
||||
/* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
|
||||
mesh = (Mesh *)BKE_id_copy_ex(NULL,
|
||||
mesh = (Mesh *)BKE_id_copy_ex(nullptr,
|
||||
&mesh->id,
|
||||
NULL,
|
||||
nullptr,
|
||||
LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
|
||||
LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW);
|
||||
}
|
||||
}
|
||||
|
||||
Mesh *result = NULL;
|
||||
Mesh *result = nullptr;
|
||||
|
||||
switch (cache_file->type) {
|
||||
case CACHEFILE_TYPE_ALEMBIC: {
|
||||
# ifdef WITH_ALEMBIC
|
||||
/* Time (in frames or seconds) between two velocity samples. Automatically computed to
|
||||
* scale the velocity vectors at render time for generating proper motion blur data. */
|
||||
float velocity_scale = mcmd->velocity_scale;
|
||||
if (mcmd->cache_file->velocity_unit == CACHEFILE_VELOCITY_UNIT_FRAME) {
|
||||
velocity_scale *= FPS;
|
||||
}
|
||||
GeometrySet geometry_set;
|
||||
|
||||
result = ABC_read_mesh(mcmd->reader,
|
||||
ctx->object,
|
||||
mesh,
|
||||
time,
|
||||
&err_str,
|
||||
mcmd->read_flag,
|
||||
mcmd->cache_file->velocity_name,
|
||||
velocity_scale);
|
||||
# endif
|
||||
break;
|
||||
/* if (ctx->object->type == OB_CURVES_LEGACY) {
|
||||
std::unique_ptr<CurveEval> curve_eval = curve_eval_from_dna_curve(
|
||||
*static_cast<Curve *>(ctx->object->data));
|
||||
geometry_set = GeometrySet::create_with_curve(curve_eval.release(),
|
||||
GeometryOwnershipType::Editable);
|
||||
}
|
||||
case CACHEFILE_TYPE_USD:
|
||||
# ifdef WITH_USD
|
||||
result = USD_read_mesh(
|
||||
mcmd->reader, ctx->object, mesh, time * FPS, &err_str, mcmd->read_flag);
|
||||
# endif
|
||||
break;
|
||||
case CACHE_FILE_TYPE_INVALID:
|
||||
break;
|
||||
else */
|
||||
{
|
||||
geometry_set = GeometrySet::create_with_mesh(mesh, GeometryOwnershipType::Editable);
|
||||
}
|
||||
|
||||
if (err_str) {
|
||||
BKE_modifier_set_error(ctx->object, md, "%s", err_str);
|
||||
modifyGeometry(md, ctx, geometry_set);
|
||||
|
||||
/* if (ctx->object->type == OB_CURVES_LEGACY) {
|
||||
CurveEval *curve_eval = geometry_set.get_component_for_write<CurveComponent>().release();
|
||||
|
||||
if (curve_eval) {
|
||||
result = blender::bke::curve_to_wire_mesh(*curve_eval);
|
||||
delete curve_eval;
|
||||
}
|
||||
}
|
||||
else */
|
||||
{
|
||||
result = geometry_set.get_component_for_write<MeshComponent>().release();
|
||||
}
|
||||
|
||||
if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) {
|
||||
BKE_id_free(NULL, mesh);
|
||||
if (!ELEM(result, nullptr, mesh) && (mesh != org_mesh)) {
|
||||
BKE_id_free(nullptr, mesh);
|
||||
mesh = org_mesh;
|
||||
}
|
||||
|
||||
@@ -261,6 +355,13 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
||||
#endif
|
||||
}
|
||||
|
||||
static void modifyGeometrySet(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
GeometrySet *geometry_set)
|
||||
{
|
||||
modifyGeometry(md, ctx, *geometry_set);
|
||||
}
|
||||
|
||||
static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mode)
|
||||
{
|
||||
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
|
||||
@@ -285,7 +386,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
|
||||
{
|
||||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
||||
|
||||
if (mcmd->cache_file != NULL) {
|
||||
if (mcmd->cache_file != nullptr) {
|
||||
DEG_add_object_cache_relation(
|
||||
ctx->node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File");
|
||||
}
|
||||
@@ -306,12 +407,13 @@ static void panel_draw(const bContext *C, Panel *panel)
|
||||
uiTemplateCacheFile(layout, C, ptr, "cache_file");
|
||||
|
||||
if (has_cache_file) {
|
||||
uiItemPointerR(layout, ptr, "object_path", &cache_file_ptr, "object_paths", NULL, ICON_NONE);
|
||||
uiItemPointerR(
|
||||
layout, ptr, "object_path", &cache_file_ptr, "object_paths", nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
if (RNA_enum_get(&ob_ptr, "type") == OB_MESH) {
|
||||
uiItemR(layout, ptr, "read_data", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
|
||||
uiItemR(layout, ptr, "use_vertex_interpolation", 0, NULL, ICON_NONE);
|
||||
uiItemR(layout, ptr, "read_data", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
|
||||
uiItemR(layout, ptr, "use_vertex_interpolation", 0, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
modifier_panel_end(layout, ptr);
|
||||
@@ -331,10 +433,42 @@ static void velocity_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiTemplateCacheFileVelocity(layout, &fileptr);
|
||||
uiItemR(layout, ptr, "velocity_scale", 0, NULL, ICON_NONE);
|
||||
uiItemR(layout, ptr, "velocity_scale", 0, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
static void time_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
static void attribute_remapping_panel_draw(const bContext *C, Panel *panel)
|
||||
{
|
||||
uiLayout *layout = panel->layout;
|
||||
|
||||
PointerRNA ob_ptr;
|
||||
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||
|
||||
PointerRNA fileptr;
|
||||
if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiTemplateCacheFileAttributeRemapping(layout, C, &fileptr);
|
||||
}
|
||||
|
||||
static void override_layers_panel_draw(const bContext *C, Panel *panel)
|
||||
{
|
||||
uiLayout *layout = panel->layout;
|
||||
|
||||
PointerRNA ob_ptr;
|
||||
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||
|
||||
PointerRNA fileptr;
|
||||
if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiTemplateCacheFileLayers(layout, C, &fileptr);
|
||||
}
|
||||
|
||||
static void time_settings_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
{
|
||||
uiLayout *layout = panel->layout;
|
||||
|
||||
@@ -366,47 +500,42 @@ static void render_procedural_panel_draw(const bContext *C, Panel *panel)
|
||||
uiTemplateCacheFileProcedural(layout, C, &fileptr);
|
||||
}
|
||||
|
||||
static void override_layers_panel_draw(const bContext *C, Panel *panel)
|
||||
{
|
||||
uiLayout *layout = panel->layout;
|
||||
|
||||
PointerRNA ob_ptr;
|
||||
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||
|
||||
PointerRNA fileptr;
|
||||
if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiTemplateCacheFileLayers(layout, C, &fileptr);
|
||||
}
|
||||
|
||||
static void panelRegister(ARegionType *region_type)
|
||||
{
|
||||
PanelType *panel_type = modifier_panel_register(
|
||||
region_type, eModifierType_MeshSequenceCache, panel_draw);
|
||||
modifier_subpanel_register(region_type, "time", "Time", NULL, time_panel_draw, panel_type);
|
||||
modifier_subpanel_register(region_type,
|
||||
"time_settings",
|
||||
"Time Settings",
|
||||
nullptr,
|
||||
time_settings_panel_draw,
|
||||
panel_type);
|
||||
modifier_subpanel_register(region_type,
|
||||
"render_procedural",
|
||||
"Render Procedural",
|
||||
NULL,
|
||||
nullptr,
|
||||
render_procedural_panel_draw,
|
||||
panel_type);
|
||||
modifier_subpanel_register(
|
||||
region_type, "velocity", "Velocity", NULL, velocity_panel_draw, panel_type);
|
||||
modifier_subpanel_register(region_type,
|
||||
"override_layers",
|
||||
"Override Layers",
|
||||
NULL,
|
||||
nullptr,
|
||||
override_layers_panel_draw,
|
||||
panel_type);
|
||||
modifier_subpanel_register(
|
||||
region_type, "velocity", "Velocity", nullptr, velocity_panel_draw, panel_type);
|
||||
modifier_subpanel_register(region_type,
|
||||
"attribute_remapping",
|
||||
"Attribute Remapping",
|
||||
nullptr,
|
||||
attribute_remapping_panel_draw,
|
||||
panel_type);
|
||||
}
|
||||
|
||||
static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
|
||||
{
|
||||
MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
|
||||
msmcd->reader = NULL;
|
||||
msmcd->reader = nullptr;
|
||||
msmcd->reader_object_path[0] = '\0';
|
||||
}
|
||||
|
||||
@@ -416,29 +545,30 @@ ModifierTypeInfo modifierType_MeshSequenceCache = {
|
||||
/* structSize */ sizeof(MeshSeqCacheModifierData),
|
||||
/* srna */ &RNA_MeshSequenceCacheModifier,
|
||||
/* type */ eModifierTypeType_Constructive,
|
||||
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs,
|
||||
/* flags */
|
||||
static_cast<ModifierTypeFlag>(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs),
|
||||
/* icon */ ICON_MOD_MESHDEFORM, /* TODO: Use correct icon. */
|
||||
|
||||
/* copyData */ copyData,
|
||||
|
||||
/* deformVerts */ NULL,
|
||||
/* deformMatrices */ NULL,
|
||||
/* deformVertsEM */ NULL,
|
||||
/* deformMatricesEM */ NULL,
|
||||
/* deformVerts */ nullptr,
|
||||
/* deformMatrices */ nullptr,
|
||||
/* deformVertsEM */ nullptr,
|
||||
/* deformMatricesEM */ nullptr,
|
||||
/* modifyMesh */ modifyMesh,
|
||||
/* modifyGeometrySet */ NULL,
|
||||
/* modifyGeometrySet */ modifyGeometrySet,
|
||||
|
||||
/* initData */ initData,
|
||||
/* requiredDataMask */ NULL,
|
||||
/* requiredDataMask */ nullptr,
|
||||
/* freeData */ freeData,
|
||||
/* isDisabled */ isDisabled,
|
||||
/* updateDepsgraph */ updateDepsgraph,
|
||||
/* dependsOnTime */ dependsOnTime,
|
||||
/* dependsOnNormals */ NULL,
|
||||
/* dependsOnNormals */ nullptr,
|
||||
/* foreachIDLink */ foreachIDLink,
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
/* foreachTexLink */ nullptr,
|
||||
/* freeRuntimeData */ nullptr,
|
||||
/* panelRegister */ panelRegister,
|
||||
/* blendWrite */ NULL,
|
||||
/* blendWrite */ nullptr,
|
||||
/* blendRead */ blendRead,
|
||||
};
|
Reference in New Issue
Block a user