forked from bartvdbraak/blender
Add Custom Loop Normals to Data Transfer.
Titles says everything, just two notes: * We have to actually transfer plain *normals*, not 'compressed' clnors, so had to add pre/post process to transfer to make the conversions. * Also added interpolation and advanced copy/mixing to CD_NORMAL, for same reasons.
This commit is contained in:
parent
138c9dba9b
commit
2c3e4fbd7e
@ -397,6 +397,8 @@ enum {
|
||||
CD_FAKE_BWEIGHT = CD_FAKE | CD_BWEIGHT, /* *sigh*. */
|
||||
CD_FAKE_UV = CD_FAKE | CD_MLOOPUV, /* UV flag, because we handle both loop's UVs and poly's textures. */
|
||||
|
||||
CD_FAKE_LNOR = CD_FAKE | CD_CUSTOMLOOPNORMAL, /* Because we play with clnor and temp lnor layers here. */
|
||||
|
||||
CD_FAKE_SHARP = CD_FAKE | 200, /* Sharp flag for edges, smooth flag for faces. */
|
||||
};
|
||||
|
||||
|
@ -57,6 +57,7 @@ enum {
|
||||
DT_TYPE_FREESTYLE_EDGE = 1 << 12,
|
||||
|
||||
DT_TYPE_VCOL = 1 << 16,
|
||||
DT_TYPE_LNOR = 1 << 17,
|
||||
|
||||
DT_TYPE_UV = 1 << 24,
|
||||
DT_TYPE_SHARP_FACE = 1 << 25,
|
||||
@ -67,7 +68,7 @@ enum {
|
||||
DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT,
|
||||
DT_TYPE_EDGE_ALL = DT_TYPE_SHARP_EDGE | DT_TYPE_SEAM | DT_TYPE_CREASE | DT_TYPE_BWEIGHT_EDGE |
|
||||
DT_TYPE_FREESTYLE_EDGE,
|
||||
DT_TYPE_LOOP_ALL = DT_TYPE_VCOL | DT_TYPE_UV,
|
||||
DT_TYPE_LOOP_ALL = DT_TYPE_VCOL | DT_TYPE_LNOR | DT_TYPE_UV,
|
||||
DT_TYPE_POLY_ALL = DT_TYPE_UV | DT_TYPE_SHARP_FACE | DT_TYPE_FREESTYLE_FACE,
|
||||
};
|
||||
|
||||
@ -85,7 +86,7 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type);
|
||||
#define DT_DATATYPE_IS_EDGE(_dt) \
|
||||
ELEM(_dt, DT_TYPE_CREASE, DT_TYPE_SHARP_EDGE, DT_TYPE_SEAM, DT_TYPE_BWEIGHT_EDGE, DT_TYPE_FREESTYLE_EDGE)
|
||||
#define DT_DATATYPE_IS_LOOP(_dt) \
|
||||
ELEM(_dt, DT_TYPE_UV, DT_TYPE_VCOL)
|
||||
ELEM(_dt, DT_TYPE_UV, DT_TYPE_VCOL, DT_TYPE_LNOR)
|
||||
#define DT_DATATYPE_IS_POLY(_dt) \
|
||||
ELEM(_dt, DT_TYPE_UV, DT_TYPE_SHARP_FACE, DT_TYPE_FREESTYLE_FACE)
|
||||
|
||||
|
@ -300,6 +300,49 @@ static void layerInterp_mdeformvert(void **sources, const float *weights,
|
||||
}
|
||||
}
|
||||
|
||||
static void layerInterp_normal(void **sources, const float *weights,
|
||||
const float *UNUSED(sub_weights), int count, void *dest)
|
||||
{
|
||||
float no[3] = {0.0f};
|
||||
|
||||
while (count--) {
|
||||
madd_v3_v3fl(no, (float *)sources[count], weights[count]);
|
||||
}
|
||||
|
||||
copy_v3_v3((float *)dest, no);
|
||||
}
|
||||
|
||||
static void layerCopyValue_normal(const void *source, void *dest, const int mixmode, const float mixfactor)
|
||||
{
|
||||
const float *no_src = source;
|
||||
float *no_dst = dest;
|
||||
float no_tmp[3];
|
||||
|
||||
if (ELEM(mixmode, CDT_MIX_NOMIX, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
|
||||
/* Above/below threshold modes are not supported here, fallback to nomix (just in case). */
|
||||
copy_v3_v3(no_dst, no_src);
|
||||
}
|
||||
else { /* Modes that support 'real' mix factor. */
|
||||
/* Since we normalize in the end, MIX and ADD are the same op here. */
|
||||
if (ELEM(mixmode, CDT_MIX_MIX, CDT_MIX_ADD)) {
|
||||
add_v3_v3v3(no_tmp, no_dst, no_src);
|
||||
normalize_v3(no_tmp);
|
||||
}
|
||||
else if (mixmode == CDT_MIX_SUB) {
|
||||
sub_v3_v3v3(no_tmp, no_dst, no_src);
|
||||
normalize_v3(no_tmp);
|
||||
}
|
||||
else if (mixmode == CDT_MIX_MUL) {
|
||||
mul_v3_v3v3(no_tmp, no_dst, no_src);
|
||||
normalize_v3(no_tmp);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(no_tmp, no_src);
|
||||
}
|
||||
interp_v3_v3v3_slerp_safe(no_dst, no_dst, no_tmp, mixfactor);
|
||||
}
|
||||
}
|
||||
|
||||
static void layerCopy_tface(const void *source, void *dest, int count)
|
||||
{
|
||||
const MTFace *source_tf = (const MTFace *)source;
|
||||
@ -1165,7 +1208,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
||||
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex},
|
||||
/* 8: CD_NORMAL */
|
||||
/* 3 floats per normal vector */
|
||||
{sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
{sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, layerInterp_normal, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, layerCopyValue_normal},
|
||||
/* 9: CD_POLYINDEX (deprecated) */
|
||||
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
/* 10: CD_PROP_FLT */
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "BKE_data_transfer.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_mapping.h"
|
||||
#include "BKE_mesh_remap.h"
|
||||
#include "BKE_object.h"
|
||||
@ -79,6 +80,9 @@ CustomDataMask BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types
|
||||
else if (cddata_type == CD_FAKE_UV) {
|
||||
cddata_mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV;
|
||||
}
|
||||
else if (cddata_type == CD_FAKE_LNOR) {
|
||||
cddata_mask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
return cddata_mask;
|
||||
@ -143,6 +147,10 @@ bool BKE_object_data_transfer_get_dttypes_capacity(
|
||||
*r_threshold = true;
|
||||
ret = true;
|
||||
break;
|
||||
case DT_TYPE_LNOR:
|
||||
*r_advanced_mixing = true;
|
||||
ret = true;
|
||||
break;
|
||||
case DT_TYPE_SHARP_FACE:
|
||||
*r_threshold = true;
|
||||
ret = true;
|
||||
@ -217,6 +225,8 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
|
||||
|
||||
case DT_TYPE_VCOL:
|
||||
return CD_MLOOPCOL;
|
||||
case DT_TYPE_LNOR:
|
||||
return CD_FAKE_LNOR;
|
||||
|
||||
default:
|
||||
BLI_assert(0);
|
||||
@ -242,6 +252,105 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type)
|
||||
|
||||
/* ********** */
|
||||
|
||||
/* Generic pre/post processing, only used by custom loop normals currently. */
|
||||
|
||||
static void data_transfer_dtdata_type_preprocess(
|
||||
Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst,
|
||||
const int dtdata_type, const bool dirty_nors_dst, const bool use_split_nors_src, const float split_angle_src)
|
||||
{
|
||||
if (dtdata_type == DT_TYPE_LNOR) {
|
||||
/* Compute custom normals into regular loop normals, which will be used for the transfer. */
|
||||
MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
|
||||
const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
|
||||
MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
|
||||
const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
|
||||
MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
|
||||
const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
|
||||
MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
|
||||
const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
|
||||
CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
|
||||
CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
|
||||
|
||||
const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
|
||||
const float split_angle_dst = me_dst->smoothresh;
|
||||
|
||||
dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src);
|
||||
|
||||
if (dm_dst) {
|
||||
dm_dst->calcLoopNormals(dm_dst, use_split_nors_dst, split_angle_dst);
|
||||
}
|
||||
else {
|
||||
float (*poly_nors_dst)[3];
|
||||
float (*loop_nors_dst)[3];
|
||||
short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
|
||||
|
||||
/* Cache poly nors into a temp CDLayer. */
|
||||
poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
|
||||
if (dirty_nors_dst || !poly_nors_dst) {
|
||||
if (!poly_nors_dst) {
|
||||
poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
|
||||
CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
|
||||
}
|
||||
BKE_mesh_calc_normals_poly(verts_dst, num_verts_dst, loops_dst, polys_dst,
|
||||
num_loops_dst, num_polys_dst, poly_nors_dst, true);
|
||||
}
|
||||
/* Cache loop nors into a temp CDLayer. */
|
||||
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
|
||||
if (dirty_nors_dst || loop_nors_dst) {
|
||||
if (!loop_nors_dst) {
|
||||
loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst);
|
||||
CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
|
||||
}
|
||||
BKE_mesh_normals_loop_split(verts_dst, num_verts_dst, edges_dst, num_edges_dst,
|
||||
loops_dst, loop_nors_dst, num_loops_dst,
|
||||
polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst,
|
||||
use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void data_transfer_dtdata_type_postprocess(
|
||||
Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *UNUSED(dm_src), DerivedMesh *dm_dst, Mesh *me_dst,
|
||||
const int dtdata_type, const bool changed)
|
||||
{
|
||||
if (dtdata_type == DT_TYPE_LNOR) {
|
||||
/* Bake edited destination loop normals into custom normals again. */
|
||||
MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
|
||||
const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
|
||||
MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
|
||||
const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
|
||||
MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
|
||||
const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
|
||||
MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
|
||||
const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
|
||||
CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
|
||||
CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
|
||||
|
||||
const float (*poly_nors_dst)[3] = CustomData_get_layer(pdata_dst, CD_NORMAL);
|
||||
float (*loop_nors_dst)[3] = CustomData_get_layer(ldata_dst, CD_NORMAL);
|
||||
short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
|
||||
|
||||
BLI_assert(poly_nors_dst);
|
||||
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!custom_nors_dst) {
|
||||
custom_nors_dst = CustomData_add_layer(ldata_dst, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops_dst);
|
||||
}
|
||||
|
||||
/* Note loop_nors_dst contains our custom normals as transferred from source... */
|
||||
BKE_mesh_normals_loop_custom_set(verts_dst, num_verts_dst, edges_dst, num_edges_dst,
|
||||
loops_dst, loop_nors_dst, num_loops_dst,
|
||||
polys_dst, poly_nors_dst, num_polys_dst,
|
||||
custom_nors_dst);
|
||||
}
|
||||
}
|
||||
|
||||
/* ********** */
|
||||
|
||||
static MeshRemapIslandsCalc data_transfer_get_loop_islands_generator(const int cddata_type)
|
||||
{
|
||||
switch (cddata_type) {
|
||||
@ -805,6 +914,10 @@ static bool data_transfer_layersmapping_generate(
|
||||
if (cddata_type == CD_FAKE_UV) {
|
||||
cddata_type = CD_MLOOPUV;
|
||||
}
|
||||
else if (cddata_type == CD_FAKE_LNOR) {
|
||||
/* Preprocess should have generated it, Postprocess will convert it back to CD_CUSTOMLOOPNORMAL. */
|
||||
cddata_type = CD_NORMAL;
|
||||
}
|
||||
|
||||
if (!(cddata_type & CD_FAKE)) {
|
||||
cd_src = dm_src->getLoopDataLayout(dm_src);
|
||||
@ -1023,6 +1136,10 @@ bool BKE_object_data_transfer_dm(
|
||||
continue;
|
||||
}
|
||||
|
||||
data_transfer_dtdata_type_preprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst,
|
||||
dtdata_type, dirty_nors_dst,
|
||||
(me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh);
|
||||
|
||||
cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
|
||||
|
||||
fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type);
|
||||
@ -1217,6 +1334,8 @@ bool BKE_object_data_transfer_dm(
|
||||
BLI_freelistN(&lay_map);
|
||||
}
|
||||
}
|
||||
|
||||
data_transfer_dtdata_type_postprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, changed);
|
||||
}
|
||||
|
||||
for (i = 0; i < DATAMAX; i++) {
|
||||
|
@ -83,6 +83,7 @@ static EnumPropertyItem DT_layer_items[] = {
|
||||
{DT_TYPE_BWEIGHT_EDGE, "BEVEL_WEIGHT_EDGE", 0, "Bevel Weight", "Transfer bevel weights"},
|
||||
{DT_TYPE_FREESTYLE_EDGE, "FREESTYLE_EDGE", 0, "Freestyle Mark", "Transfer Freestyle edge mark"},
|
||||
{0, "", 0, "Face Corner Data", ""},
|
||||
{DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"},
|
||||
{DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"},
|
||||
{DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"},
|
||||
{0, "", 0, "Face Data", ""},
|
||||
|
@ -4148,6 +4148,7 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
|
||||
};
|
||||
|
||||
static EnumPropertyItem DT_layer_loop_items[] = {
|
||||
{DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
static EnumPropertyItem DT_layer_loop_vcol_items[] = {
|
||||
|
Loading…
Reference in New Issue
Block a user