Index: release/scripts/ui/properties_data_modifier.py =================================================================== --- release/scripts/ui/properties_data_modifier.py (Revision 32429) +++ release/scripts/ui/properties_data_modifier.py (Arbeitskopie) @@ -451,7 +451,17 @@ def PARTICLE_SYSTEM(self, layout, ob, md): layout.label(text="See Particle panel.") + + def RESTORE_VOLUME(self, layout, ob, md): # TODO nyabot (STEP 10) + 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,293 @@ +/* +* $Id: MOD_simpledeform.c 32209 2010-09-30 10:51:36Z campbellbarton $ +* +* ***** 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" // for access to original mesh (Mesh) +#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" + + +double triangleProjectionVolume(float *a, float *b, float *c) { + double e1y = b[1] - a[1]; + double e1z = b[2] - a[2]; + double e2y = c[1] - a[1]; + double e2z = c[2] - a[2]; + double nx = e1y * e2z - e1z * e2y; + return nx * (a[0] + b[0] + c[0]); +} + +double volumeOb(Object *ob) { + Mesh *mesh = (Mesh*) ob->data; + MFace *faces = mesh->mface; + MVert *vertices = mesh->mvert; + unsigned int i; + unsigned int faceCount = (unsigned int) mesh->totface; + MFace *face; + MVert *v1, *v2, *v3, *v4; + 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 / 6.0; +} + +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 / 6.0; +} + +void adjustVolume(DerivedMesh *mesh, float g, MDeformVert *dvert, int vgroup, int steps) { + MVert *verts = mesh->getVertArray(mesh); + int numVerts = mesh->getNumVerts(mesh); + int i, j; + float fac = 1.0 / steps; + + for (j=0; jco[0] += f * (vert->no[0] / 32767.0f); + vert->co[1] += f * (vert->no[1] / 32767.0f); + vert->co[2] += f * (vert->no[2] / 32767.0f); + } + } else { + float f = g * fac; + for (i=0; ico[0] += f * (vert->no[0] / 32767.0f); + vert->co[1] += f * (vert->no[1] / 32767.0f); + vert->co[2] += f * (vert->no[2] / 32767.0f); + } + } + // recompute normals, for better growing shrinking + CDDM_calc_normals(mesh); + } +} + +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]; + } +} + +void RestoreVolumeModifier_do(RestoreVolumeModifierData *rvd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, int render) { + MDeformVert *dvert = NULL; + DerivedMesh *copy; + int vgroup, steps, iter, maxIter; + double originalVolume, derivedVolume, tempVolume, vDiff, vDelta, maxDelta; + float g; + + vgroup = 0; + if (rvd->vgroup_name[0]) { + vgroup = defgroup_name_index(ob, rvd->vgroup_name); + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + } + + steps = rvd->steps; + if (render) + steps = rvd->render_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; + maxIter = 20; + iter = 0; + g = 1.0; + + printf("originalVolume: %f\n", originalVolume); fflush(stdout); + printf("derivedVolume: %f\n", derivedVolume); fflush(stdout); + printf("vDiff: %f vDelta: %f maxDelta: %f\n", vDiff, vDelta, maxDelta); fflush(stdout); + + printf("i: %i g: %f v-delta: %f\n", iter, g, vDelta); fflush(stdout); + + while (vDelta > maxDelta && iter < maxIter) { + double diff; + iter++; + copy = CDDM_copy(dm); + adjustVolume(copy, g, dvert, vgroup, steps); + tempVolume = volumeDm(copy); + diff = derivedVolume - tempVolume; + if (diff == 0.0) // to prevent division by 0 + break; + g = (float) (- g * vDiff / diff); + vDelta = fabs(originalVolume - tempVolume); + copy->release(copy); + printf("i: %i g: %f v: %f v-delta: %f\n", iter, g, tempVolume, vDelta); fflush(stdout); + } + if (iter > 0) { + copy = CDDM_copy(dm); + adjustVolume(copy, g, dvert, vgroup, steps); + copyDataToVerts(copy, vertexCos, numVerts); + copy->release(copy); + } +} + +//== Implementation of needed functions ======================================== + +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; // always depends on them +} + +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 + dataMask |= (1 << CD_NORMAL); // always requiers normals + 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(md->scene, ob, NULL, dm, vertexCos); + + RestoreVolumeModifier_do((RestoreVolumeModifierData*) md, ob, dm, 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(md->scene, ob, NULL, dm, vertexCos); + + RestoreVolumeModifier_do((RestoreVolumeModifierData*) md, ob, dm, 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 + | eModifierTypeFlag_SupportsEditmode + /*| eModifierTypeFlag_EnableInEditmode*/, + + /* copyData */ copyData, + /* deformVerts */ deformVerts, + /* deformVertsEM */ deformVertsEM, + /* deformMatricesEM */ 0, + /* applyModifier */ 0, + /* applyModifierEM */ 0, + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ 0, + /* isDisabled */ 0, // not usable, since object is not passed. + /* updateDepgraph */ 0, // updateDepgraph, + /* dependsOnTime */ 0, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ 0, // foreachObjectLink, + /* foreachIDLink */ 0, +}; Index: source/blender/modifiers/intern/MOD_util.c =================================================================== --- source/blender/modifiers/intern/MOD_util.c (Revision 32429) +++ source/blender/modifiers/intern/MOD_util.c (Arbeitskopie) @@ -176,6 +176,7 @@ INIT_TYPE(Fluidsim); INIT_TYPE(Mask); INIT_TYPE(SimpleDeform); + INIT_TYPE(RestoreVolume); // TODO nyabot (STEP 1) INIT_TYPE(Multires); INIT_TYPE(Surface); INIT_TYPE(Smoke); Index: source/blender/modifiers/MOD_modifiertypes.h =================================================================== --- source/blender/modifiers/MOD_modifiertypes.h (Revision 32429) +++ 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; // TODO nyabot (STEP 2) 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 32429) +++ 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, // TODO nyabot (Step 4) Must be added at last, to ensure compatibility to older files NUM_MODIFIER_TYPES } ModifierType; @@ -615,6 +616,18 @@ struct PointCache *point_cache; /* definition is in DNA_object_force.h */ } FluidsimModifierData; +// TODO nyabot (Step 5) +typedef struct RestoreVolumeModifierData { + ModifierData modifier; + // own data + char vgroup_name[32]; /* name of vertexgroup that defines wich areas can grow/shrink */ + float volume; /* volume that mesh should have after applying modifier */ + char pad1[4]; + short steps; + short render_steps; + 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 32429) +++ 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", ""}, // TODO nyabot (STEP 6) {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: // TODO nyabot (STEP 7) + return &RNA_RestoreVolumeModifier; case eModifierType_SimpleDeform: return &RNA_SimpleDeformModifier; case eModifierType_Multires: @@ -289,6 +292,13 @@ rna_object_vgroup_name_index_set(ptr, value, &emd->vgroup); } +// TODO nyabot (STEP A) +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 +2021,43 @@ RNA_def_property_update(prop, 0, "rna_Modifier_update"); } +// TODO nyabot (STEP 8) +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 +2375,7 @@ rna_def_modifier_fluidsim(brna); rna_def_modifier_mask(brna); rna_def_modifier_simpledeform(brna); + rna_def_modifier_restorevolume(brna); // TODO nyabot (STEP 9) 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 32429) +++ 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; // TODO nyabot (STEP 3) extern StructRNA RNA_RGBANodeSocket; extern StructRNA RNA_RigidBodyJointConstraint; extern StructRNA RNA_Scene;