Index: release/scripts/ui/properties_data_modifier.py =================================================================== --- release/scripts/ui/properties_data_modifier.py (Revision 32473) +++ release/scripts/ui/properties_data_modifier.py (Arbeitskopie) @@ -451,6 +451,15 @@ def PARTICLE_SYSTEM(self, layout, ob, md): layout.label(text="See Particle panel.") + + def RESTORE_VOLUME(self, layout, ob, md): + layout.prop(md, "volume") + layout.prop_search(md, "vertex_group", ob, "vertex_groups") + + layout.label("Calculation Steps:") + row = layout.row() + row.prop(md, "steps") + row.prop(md, "render_steps") def SCREW(self, layout, ob, md): split = layout.split() Index: source/blender/modifiers/intern/MOD_restorevolume.c =================================================================== --- source/blender/modifiers/intern/MOD_restorevolume.c (Revision 0) +++ source/blender/modifiers/intern/MOD_restorevolume.c (Revision 0) @@ -0,0 +1,315 @@ +/* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* The Original Code is Copyright (C) 2005 by the Blender Foundation. +* All rights reserved. +* +* Contributor(s): Daniel Dunbar +* Ton Roosendaal, +* Ben Batt, +* Brecht Van Lommel, +* Campbell Barton +* +* ***** END GPL LICENSE BLOCK ***** +* +*/ +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BLI_math.h" + +#include "BKE_cdderivedmesh.h" +#include "BKE_lattice.h" +#include "BKE_modifier.h" +#include "BKE_deform.h" +#include "BKE_shrinkwrap.h" +#include "BKE_utildefines.h" + +#include "depsgraph_private.h" + +#include "MOD_util.h" + +/** + * Computes the volume (times 6) between a triangle defined by points a, b, c + * and it's projection onto the yz-plane. + */ +float triangleProjectionVolume(float *a, float *b, float *c) { + float e1y = b[1] - a[1]; + float e1z = b[2] - a[2]; + float e2y = c[1] - a[1]; + float e2z = c[2] - a[2]; + float nx = e1y * e2z - e1z * e2y; + return nx * (a[0] + b[0] + c[0]); +} + +/** + * Computes the volume (times 6) from the mesh of an object in localespace. + * To work properbly the mesh has to be closed and normals have to point + * outward. + */ +double volumeOb(Object *ob) { + Mesh *mesh = (Mesh*) ob->data; + MFace *faces = mesh->mface; + MFace *face; + MVert *vertices = mesh->mvert; + MVert *v1, *v2, *v3, *v4; + int i; + int faceCount = mesh->totface; + double volume = 0.0; + + for (i=0; iv1]; + v2 = &vertices[face->v2]; + v3 = &vertices[face->v3]; + if (face->v4 == 0) { // triangle + volume += triangleProjectionVolume((float *) &v1->co, (float *) &v2->co, (float *) &v3->co); + } else { // quad + v4 = &vertices[face->v4]; + volume += triangleProjectionVolume((float *) &v1->co, (float *) &v2->co, (float *) &v3->co); + volume += triangleProjectionVolume((float *) &v1->co, (float *) &v3->co, (float *) &v4->co); + } + } + return volume; +} + +/** + * Computes the volume (times 6) from the given derived mesh. + * To work properbly the mesh has to be closed and normals have to point + * outward. + */ +double volumeDm(DerivedMesh *mesh) { + MFace *faces = mesh->getFaceArray(mesh); + MFace *face; + MVert *verts = mesh->getVertArray(mesh); + float *v1, *v2, *v3, *v4; + int faceCount = mesh->getNumFaces(mesh); + int i; + double volume = 0.0; + + for (i=0; iv1].co); + v2 = (float*) &(verts[face->v2].co); + v3 = (float*) &(verts[face->v3].co); + if (face->v4) { // quad + v4 = (float*) &(verts[face->v4].co); + volume += triangleProjectionVolume(v1,v2,v3); + volume += triangleProjectionVolume(v1,v3,v4); + } else { // tri + volume += triangleProjectionVolume(v1,v2,v3); + } + } + return volume; +} + +/** + * Grows given mesh by g along the normals in multiple steps. Using vertex + * group, if present. + */ +void adjustVolume(DerivedMesh *mesh, float g, MDeformVert *dvert, int vgroup, int steps) { + MVert *verts = mesh->getVertArray(mesh); + MVert *vert; + int numVerts = mesh->getNumVerts(mesh); + int i, j; + float fac = g / steps / 32767.0f; + float *weights = NULL; + + weights = (float *) malloc(sizeof(float)*numVerts); + + for (i=0; ico[0] += weights[j] * vert->no[0]; + vert->co[1] += weights[j] * vert->no[1]; + vert->co[2] += weights[j] * vert->no[2]; + } + } + + free(weights); +} + +/** + * Copies vertice locations from mesh to verts. + */ +void copyDataToVerts(DerivedMesh *mesh, float (*verts)[3], int numVerts) { + MVert *mverts = mesh->getVertArray(mesh); + int i; + for (i=0; ico[0]; + verts[i][1] = mvert->co[1]; + verts[i][2] = mvert->co[2]; + } +} + +/** + * Copies vertice locations from verts to mesh. + */ +void copyVertsToData(float (*verts)[3], int numVerts, DerivedMesh *mesh) { + MVert *mverts = mesh->getVertArray(mesh); + int i; + for (i=0; ico[0] = verts[i][0]; + mvert->co[1] = verts[i][1]; + mvert->co[2] = verts[i][2]; + } +} + +void RestoreVolumeModifier_do(RestoreVolumeModifierData *rvd, Object *ob, DerivedMesh *dm, struct EditMesh *em, float (*vertexCos)[3], int numVerts, int render) { + MDeformVert *dvert = NULL; + DerivedMesh *cdMesh; + int vgroup = 0; + int iter = 0; + int maxIter = 30; + int steps; + double originalVolume, derivedVolume, tempVolume, vDiff, vDelta, maxDelta; + float g = 1.0; + + vgroup = 0; + if (rvd->vgroup_name[0]) { + vgroup = defgroup_name_index(ob, rvd->vgroup_name); + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + } + + if (render) + steps = rvd->render_steps; + else + steps = rvd->steps; + + originalVolume = volumeOb(ob) * rvd->volume; + derivedVolume = volumeDm(dm); + vDiff = originalVolume - derivedVolume; + vDelta = fabs(vDiff); + maxDelta = (fabs(originalVolume) * 0.01 > 0.0001) ? fabs(originalVolume) * 0.01 : 0.0001; + + cdMesh = CDDM_copy(dm); + + while (vDelta > maxDelta && iter < maxIter) { + double diff; + if (iter) + copyVertsToData(vertexCos, numVerts, cdMesh); + iter++; + adjustVolume(cdMesh, g, dvert, vgroup, steps); + tempVolume = volumeDm(cdMesh); + diff = derivedVolume - tempVolume; + if (diff == 0.0) // to prevent division by 0 if exact solution was found + break; + g = (float) (- g * vDiff / diff); + vDelta = fabs(originalVolume - tempVolume); + } + + if (iter > 0 && iter < maxIter) { + copyDataToVerts(cdMesh, vertexCos, numVerts); + } + + cdMesh->release(cdMesh); +} + +/* Restore Volume Modifier */ +static void initData(ModifierData *md) { + RestoreVolumeModifierData *rvd = (RestoreVolumeModifierData*) md; + rvd->volume = 1.0; + rvd->steps = 2; + rvd->render_steps = 8; +} + +static void copyData(ModifierData *md, ModifierData *target) +{ + RestoreVolumeModifierData *rvd_md = (RestoreVolumeModifierData*) md; + RestoreVolumeModifierData *rvd_target = (RestoreVolumeModifierData*) target; + rvd_target->volume = rvd_md->volume; + rvd_target->steps = rvd_md->steps; + rvd_target->render_steps = rvd_md->render_steps; + strcpy(rvd_target->vgroup_name, rvd_md->vgroup_name); +} + +static int dependsOnNormals(ModifierData *md) +{ + return 1; +} + +static CustomDataMask requiredDataMask(Object *ob, ModifierData *md) +{ + RestoreVolumeModifierData *rvd = (RestoreVolumeModifierData*) md; + CustomDataMask dataMask = 0; + if (rvd->vgroup_name[0]) + dataMask |= (1 << CD_MDEFORMVERT); // requires vgroups if entered by user + return dataMask; +} + +static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) +{ + if (ob->type == OB_MESH) { + DerivedMesh *dm = derivedData; + dm = get_cddm(ob, NULL, dm, vertexCos); + + RestoreVolumeModifier_do((RestoreVolumeModifierData*) md, ob, dm, NULL, vertexCos, numVerts, useRenderParams); + + if (dm != derivedData) + dm->release(dm); + } +} + +static void deformVertsEM(ModifierData *md, Object *ob, struct EditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + if (ob->type == OB_MESH) { + DerivedMesh *dm = derivedData; + dm = get_cddm(ob, editData, dm, vertexCos); + + RestoreVolumeModifier_do((RestoreVolumeModifierData*) md, ob, dm, editData, vertexCos, numVerts, 0); + + if (dm != derivedData) + dm->release(dm); + } +} + + +ModifierTypeInfo modifierType_RestoreVolume = { + /* name */ "RestoreVolume", + /* structName */ "RestoreVolumeModifierData", + /* structSize */ sizeof(RestoreVolumeModifierData), + /* type */ eModifierTypeType_OnlyDeform, + + /* flags */ eModifierTypeFlag_AcceptsMesh, + //| eModifierTypeFlag_AcceptsCVs (curves don't have volume) + //| eModifierTypeFlag_SupportsEditmode useless, since original will be used after leaving + //| eModifierTypeFlag_EnableInEditmode edit-mode, instead of adjusted mesh :-( + + /* copyData */ copyData, + /* deformVerts */ deformVerts, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ 0, + /* applyModifier */ 0, + /* applyModifierEM */ 0, + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ 0, + /* isDisabled */ 0, + /* updateDepgraph */ 0, + /* dependsOnTime */ 0, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ 0, + /* foreachIDLink */ 0, +}; Index: source/blender/modifiers/intern/MOD_util.c =================================================================== --- source/blender/modifiers/intern/MOD_util.c (Revision 32473) +++ source/blender/modifiers/intern/MOD_util.c (Arbeitskopie) @@ -176,6 +176,7 @@ INIT_TYPE(Fluidsim); INIT_TYPE(Mask); INIT_TYPE(SimpleDeform); + INIT_TYPE(RestoreVolume); INIT_TYPE(Multires); INIT_TYPE(Surface); INIT_TYPE(Smoke); Index: source/blender/modifiers/MOD_modifiertypes.h =================================================================== --- source/blender/modifiers/MOD_modifiertypes.h (Revision 32473) +++ source/blender/modifiers/MOD_modifiertypes.h (Arbeitskopie) @@ -61,6 +61,7 @@ extern ModifierTypeInfo modifierType_Fluidsim; extern ModifierTypeInfo modifierType_Mask; extern ModifierTypeInfo modifierType_SimpleDeform; +extern ModifierTypeInfo modifierType_RestoreVolume; extern ModifierTypeInfo modifierType_Multires; extern ModifierTypeInfo modifierType_Surface; extern ModifierTypeInfo modifierType_Smoke; Index: source/blender/makesdna/DNA_modifier_types.h =================================================================== --- source/blender/makesdna/DNA_modifier_types.h (Revision 32473) +++ source/blender/makesdna/DNA_modifier_types.h (Arbeitskopie) @@ -69,6 +69,7 @@ /* placeholder, keep this so durian files load in * trunk with the correct modifier once its merged */ eModifierType_Warp, + eModifierType_RestoreVolume, NUM_MODIFIER_TYPES } ModifierType; @@ -615,6 +616,17 @@ struct PointCache *point_cache; /* definition is in DNA_object_force.h */ } FluidsimModifierData; +typedef struct RestoreVolumeModifierData { + ModifierData modifier; + + char vgroup_name[32]; /* vertexgroup defining wich areas can grow/shrink */ + float volume; /* volumescaling */ + char pad1[4]; + short steps; /* growsteps in editor */ + short render_steps; /* growsteps while rendering */ + char pad2[4]; +} RestoreVolumeModifierData; + typedef struct ShrinkwrapModifierData { ModifierData modifier; Index: source/blender/makesrna/intern/rna_modifier.c =================================================================== --- source/blender/makesrna/intern/rna_modifier.c (Revision 32473) +++ source/blender/makesrna/intern/rna_modifier.c (Arbeitskopie) @@ -71,6 +71,7 @@ {eModifierType_Hook, "HOOK", ICON_HOOK, "Hook", ""}, {eModifierType_Lattice, "LATTICE", ICON_MOD_LATTICE, "Lattice", ""}, {eModifierType_MeshDeform, "MESH_DEFORM", ICON_MOD_MESHDEFORM, "Mesh Deform", ""}, + {eModifierType_RestoreVolume, "RESTORE_VOLUME", ICON_MOD_PHYSICS, "Restore Volume", ""}, {eModifierType_Shrinkwrap, "SHRINKWRAP", ICON_MOD_SHRINKWRAP, "Shrinkwrap", ""}, {eModifierType_SimpleDeform, "SIMPLE_DEFORM", ICON_MOD_SIMPLEDEFORM, "Simple Deform", ""}, {eModifierType_Smooth, "SMOOTH", ICON_MOD_SMOOTH, "Smooth", ""}, @@ -163,6 +164,8 @@ return &RNA_FluidSimulationModifier; case eModifierType_Mask: return &RNA_MaskModifier; + case eModifierType_RestoreVolume: + return &RNA_RestoreVolumeModifier; case eModifierType_SimpleDeform: return &RNA_SimpleDeformModifier; case eModifierType_Multires: @@ -289,6 +292,12 @@ rna_object_vgroup_name_index_set(ptr, value, &emd->vgroup); } +static void rna_RestoreVolumeModifier_vgroup_set(PointerRNA *ptr, const char *value) +{ + RestoreVolumeModifierData *rvd= (RestoreVolumeModifierData*)ptr->data; + rna_object_vgroup_name_set(ptr, value, rvd->vgroup_name, sizeof(rvd->vgroup_name)); +} + static void rna_SimpleDeformModifier_vgroup_set(PointerRNA *ptr, const char *value) { SimpleDeformModifierData *smd= (SimpleDeformModifierData*)ptr->data; @@ -2011,6 +2020,42 @@ RNA_def_property_update(prop, 0, "rna_Modifier_update"); } +static void rna_def_modifier_restorevolume(BlenderRNA* brna) +{ + StructRNA* srna; + PropertyRNA* prop; + + srna = RNA_def_struct(brna, "RestoreVolumeModifier", "Modifier"); + RNA_def_struct_ui_text(srna, "Restore Volume Modifier", "Grows or Shrinks a closed mesh until it reaches the original volume"); + RNA_def_struct_sdna(srna, "RestoreVolumeModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_PARTICLES); + + prop = RNA_def_property(srna, "volume", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.01, FLT_MAX); + RNA_def_property_ui_range(prop, 0.01, 2, 0.05, 4); + RNA_def_property_ui_text(prop, "Volume Correction", "Volume offset relative to original volume"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "vgroup_name"); + RNA_def_property_ui_text(prop, "Vertex Group:", "Name of vertex group defining which parts of the mesh are used for correction"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_RestoreVolumeModifier_vgroup_set"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "steps", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 1, 10); + RNA_def_property_ui_range(prop, 1, 10, 1, 10); + RNA_def_property_ui_text(prop, "View", "Number of calculation steps during volume adjustment"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "render_steps", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 1, 20); + RNA_def_property_ui_range(prop, 1, 20, 1, 5); + RNA_def_property_ui_text(prop, "Render", "Number of calculation steps during volume adjustment while rendering"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + +} + static void rna_def_modifier_simpledeform(BlenderRNA *brna) { StructRNA *srna; @@ -2328,6 +2373,7 @@ rna_def_modifier_fluidsim(brna); rna_def_modifier_mask(brna); rna_def_modifier_simpledeform(brna); + rna_def_modifier_restorevolume(brna); rna_def_modifier_multires(brna); rna_def_modifier_surface(brna); rna_def_modifier_smoke(brna); Index: source/blender/makesrna/RNA_access.h =================================================================== --- source/blender/makesrna/RNA_access.h (Revision 32473) +++ source/blender/makesrna/RNA_access.h (Arbeitskopie) @@ -379,6 +379,7 @@ extern StructRNA RNA_RenderPass; extern StructRNA RNA_RenderResult; extern StructRNA RNA_RenderSettings; +extern StructRNA RNA_RestoreVolumeModifier; extern StructRNA RNA_RGBANodeSocket; extern StructRNA RNA_RigidBodyJointConstraint; extern StructRNA RNA_Scene;