Added subsurface levels option to normal projection.

Now when doing normal projeciton is possible to ask it to project along the normals
that the vertex would have if it was subsurfaced... this gives "better" projections on
low polys.

Point of this commit is to add the feature request from Eclectiel
http://blenderartists.org/forum/showpost.php?p=1181531&postcount=9

workflow as Eclectiel wanted is now possible:

to archieve a nice low-res retopology that aproximates a high-res mesh when subsurfaced:
1 - make base low-poly retopo
2 - apply a shrinkwrap with projection along normal.. and with SS level = N (where N>0)
3 - add a Subsurface with level N
4 - run bretch's script (ss_fit)
This commit is contained in:
Andre Susano Pinto 2008-08-14 03:05:13 +00:00
parent 89be876f96
commit 8da4ad74e9
4 changed files with 81 additions and 13 deletions

@ -7316,7 +7316,7 @@ static void shrinkwrapModifier_deformVertsEM(ModifierData *md, Object *ob, EditM
if(dataMask) if(dataMask)
{ {
if(derivedData) dm = CDDM_copy(derivedData); if(derivedData) dm = CDDM_copy(derivedData);
else if(ob->type==OB_MESH) dm = CDDM_from_editmesh(editData, ob); else if(ob->type==OB_MESH) dm = CDDM_from_editmesh(editData, ob->data);
else return; else return;
if(dataMask & CD_MVERT) if(dataMask & CD_MVERT)

@ -32,10 +32,12 @@
#include <memory.h> #include <memory.h>
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#include <assert.h>
#include "DNA_object_types.h" #include "DNA_object_types.h"
#include "DNA_modifier_types.h" #include "DNA_modifier_types.h"
#include "DNA_meshdata_types.h" #include "DNA_meshdata_types.h"
#include "DNA_mesh_types.h"
#include "BKE_shrinkwrap.h" #include "BKE_shrinkwrap.h"
#include "BKE_DerivedMesh.h" #include "BKE_DerivedMesh.h"
@ -44,6 +46,7 @@
#include "BKE_cdderivedmesh.h" #include "BKE_cdderivedmesh.h"
#include "BKE_displist.h" #include "BKE_displist.h"
#include "BKE_global.h" #include "BKE_global.h"
#include "BKE_subsurf.h"
#include "BLI_arithb.h" #include "BLI_arithb.h"
#include "BLI_kdtree.h" #include "BLI_kdtree.h"
@ -344,6 +347,7 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
const char use_normal = calc->smd->shrinkOpts; const char use_normal = calc->smd->shrinkOpts;
float proj_axis[3] = {0.0f, 0.0f, 0.0f}; float proj_axis[3] = {0.0f, 0.0f, 0.0f};
MVert *vert = NULL; //Needed in case of vertex normal MVert *vert = NULL; //Needed in case of vertex normal
DerivedMesh* ss_mesh = NULL;
//Vertex group data //Vertex group data
const int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name); const int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name);
@ -359,11 +363,46 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
BVHTreeFromMesh auxData= NULL_BVHTreeFromMesh; BVHTreeFromMesh auxData= NULL_BVHTreeFromMesh;
SpaceTransform local2aux; SpaceTransform local2aux;
do
{
//Prepare data to retrieve the direction in which we should project each vertex //Prepare data to retrieve the direction in which we should project each vertex
if(calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) if(calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL)
{ {
vert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MVERT) : NULL; //No Mvert information: jump to "free memory and return" part
if(calc->original == NULL) break;
if(calc->smd->subsurfLevels)
{
SubsurfModifierData smd;
memset(&smd, 0, sizeof(smd));
smd.subdivType = ME_CC_SUBSURF; //catmull clark
smd.levels = calc->smd->subsurfLevels; //levels
ss_mesh = subsurf_make_derived_from_derived(calc->original, &smd, FALSE, NULL, 0, 0);
if(ss_mesh)
{
vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT);
if(vert)
{
//TRICKY: this code assumes subsurface will have the transformed original vertices
//in their original order at the end of the vert array.
vert = vert
+ ss_mesh->getNumVerts(ss_mesh)
- calc->original->getNumVerts(calc->original);
}
}
//To make sure we are not letting any memory behind
assert(smd.emCache == NULL);
assert(smd.mCache == NULL);
}
else
vert = calc->original->getVertDataArray(calc->original, CD_MVERT);
//Not able to get vert information: jump to "free memory and return" part
if(vert == NULL) break;
} }
else else
{ {
@ -373,22 +412,21 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
if(calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) proj_axis[2] = 1.0f; if(calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) proj_axis[2] = 1.0f;
Normalize(proj_axis); Normalize(proj_axis);
}
if(vert == NULL && (INPR(proj_axis, proj_axis) < FLT_EPSILON)) //Invalid projection direction: jump to "free memory and return" part
{ if(INPR(proj_axis, proj_axis) < FLT_EPSILON) break;
printf("Shrinkwrap can't project witouth normal information");
return;
} }
//If the user doesn't allows to project in any direction of projection axis... then theres nothing todo. //If the user doesn't allows to project in any direction of projection axis... then theres nothing todo.
if((use_normal & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0) if((use_normal & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
return; break; //jump to "free memory and return" part
//Build target tree //Build target tree
BENCH(bvhtree_from_mesh_faces(&treeData, calc->target, calc->keepDist, 4, 6)); BENCH(bvhtree_from_mesh_faces(&treeData, calc->target, calc->keepDist, 4, 6));
if(treeData.tree == NULL) return OUT_OF_MEMORY(); if(treeData.tree == NULL)
break; //jump to "free memory and return" part
//Build auxiliar target //Build auxiliar target
if(calc->smd->auxTarget) if(calc->smd->auxTarget)
@ -414,7 +452,15 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
if(weight == 0.0f) continue; if(weight == 0.0f) continue;
VECCOPY(tmp_co, co); if(ss_mesh)
{
VECCOPY(tmp_co, vert[i].co);
}
else
{
VECCOPY(tmp_co, co);
}
if(vert) if(vert)
NormalShortToFloat(tmp_no, vert[i].no); NormalShortToFloat(tmp_no, vert[i].no);
@ -456,6 +502,9 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
} }
//Simple do{} while(0) structure to allow to easily jump to the "free memory and return" part
} while(0);
//free data structures //free data structures
free_bvhtree_from_mesh(&treeData); free_bvhtree_from_mesh(&treeData);
@ -463,6 +512,9 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
if(aux_mesh) if(aux_mesh)
aux_mesh->release(aux_mesh); aux_mesh->release(aux_mesh);
if(ss_mesh)
ss_mesh->release(ss_mesh);
} }
/* /*
@ -492,7 +544,7 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
nearest.dist = FLT_MAX; nearest.dist = FLT_MAX;
//Find the nearest vertex //Find the nearest vertex
#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc,treeData) schedule(static) #pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc,treeData) schedule(static)
for(i = 0; i<calc->numVerts; ++i) for(i = 0; i<calc->numVerts; ++i)
{ {
@ -518,7 +570,7 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData); BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData);
//Found the nearest vertex //Found the nearest vertex
if(nearest.index) if(nearest.index != -1)
{ {
if(calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) if(calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE)
{ {

@ -502,7 +502,15 @@ typedef struct ShrinkwrapModifierData {
short shrinkType; /* shrink type projection */ short shrinkType; /* shrink type projection */
short shrinkOpts; /* shrink options */ short shrinkOpts; /* shrink options */
char projAxis; /* axis to project over */ char projAxis; /* axis to project over */
char pad[7];
/*
* if using projection over vertex normal this controls the
* the level of subsurface that must be done before getting the
* vertex coordinates and normal
*/
char subsurfLevels;
char pad[6];
} ShrinkwrapModifierData; } ShrinkwrapModifierData;

@ -1903,7 +1903,10 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md;
height = 86 + 3; height = 86 + 3;
if (smd->shrinkType == MOD_SHRINKWRAP_PROJECT) if (smd->shrinkType == MOD_SHRINKWRAP_PROJECT)
{
height += 19*5; height += 19*5;
if(smd->projAxis == 0) height += 19;
}
else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE) else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE)
height += 19; height += 19;
@ -2556,6 +2559,11 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
/* UI for projection axis */ /* UI for projection axis */
uiBlockBeginAlign(block); uiBlockBeginAlign(block);
uiDefButC(block, ROW, B_MODIFIER_RECALC, "Normal" , lx,(cy-=19),buttonWidth,19, &smd->projAxis, 18.0, MOD_SHRINKWRAP_PROJECT_OVER_NORMAL, 0, 0, "Projection over X axis"); uiDefButC(block, ROW, B_MODIFIER_RECALC, "Normal" , lx,(cy-=19),buttonWidth,19, &smd->projAxis, 18.0, MOD_SHRINKWRAP_PROJECT_OVER_NORMAL, 0, 0, "Projection over X axis");
if(smd->projAxis == 0)
{
uiDefButC(block, NUM, B_MODIFIER_RECALC, "SS Levels:", lx, (cy-=19), buttonWidth,19, &smd->subsurfLevels, 0, 6, 0, 0, "This indicates the number of CCSubdivisions that must be performed before extracting vertexs positions and normals");
}
uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS, B_MODIFIER_RECALC, "X", lx+buttonWidth/3*0,(cy-=19),buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over X axis"); uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS, B_MODIFIER_RECALC, "X", lx+buttonWidth/3*0,(cy-=19),buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over X axis");
uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS, B_MODIFIER_RECALC, "Y", lx+buttonWidth/3*1,cy,buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over Y axis"); uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS, B_MODIFIER_RECALC, "Y", lx+buttonWidth/3*1,cy,buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over Y axis");
uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS, B_MODIFIER_RECALC, "Z", lx+buttonWidth/3*2,cy,buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over Z axis"); uiDefButBitC(block, TOG, MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS, B_MODIFIER_RECALC, "Z", lx+buttonWidth/3*2,cy,buttonWidth/3,19, &smd->projAxis, 0, 0, 0, 0, "Projection over Z axis");