2008-04-25 18:22:20 +00:00
/**
* shrinkwrap . c
*
* * * * * * 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 . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*
* The Original Code is Copyright ( C ) Blender Foundation .
* All rights reserved .
*
* The Original Code is : all of this file .
*
2008-05-07 12:45:02 +00:00
* Contributor ( s ) : André Pinto
2008-04-25 18:22:20 +00:00
*
* * * * * * END GPL LICENSE BLOCK * * * * *
*/
# include <string.h>
# include <float.h>
2008-04-27 19:29:40 +00:00
# include <math.h>
2008-06-17 19:00:21 +00:00
# include <memory.h>
2008-04-27 19:29:40 +00:00
# include <stdio.h>
2008-05-01 01:00:01 +00:00
# include <time.h>
2008-08-14 03:05:13 +00:00
# include <assert.h>
2008-04-25 18:22:20 +00:00
# include "DNA_object_types.h"
# include "DNA_modifier_types.h"
# include "DNA_meshdata_types.h"
2008-08-14 03:05:13 +00:00
# include "DNA_mesh_types.h"
2008-04-25 18:22:20 +00:00
# include "BKE_shrinkwrap.h"
# include "BKE_DerivedMesh.h"
2008-11-03 23:17:36 +00:00
# include "BKE_lattice.h"
2008-04-25 18:22:20 +00:00
# include "BKE_utildefines.h"
# include "BKE_deform.h"
# include "BKE_cdderivedmesh.h"
2008-07-21 18:12:02 +00:00
# include "BKE_displist.h"
2008-04-27 19:29:40 +00:00
# include "BKE_global.h"
2008-08-14 03:05:13 +00:00
# include "BKE_subsurf.h"
2009-05-18 08:46:04 +00:00
# include "BKE_mesh.h"
# include "BKE_tessmesh.h"
2008-04-25 18:22:20 +00:00
# include "BLI_arithb.h"
2008-05-01 01:00:01 +00:00
# include "BLI_kdtree.h"
2008-05-14 18:25:23 +00:00
# include "BLI_kdopbvh.h"
2009-03-30 07:28:37 +00:00
# include "BLI_editVert.h"
2008-04-25 18:22:20 +00:00
2008-05-02 00:16:48 +00:00
# include "RE_raytrace.h"
2008-05-07 12:45:02 +00:00
# include "MEM_guardedalloc.h"
2008-04-30 17:55:26 +00:00
2009-03-30 07:28:37 +00:00
# include "ED_mesh.h"
2008-05-07 12:45:02 +00:00
/* Util macros */
2008-05-01 01:00:01 +00:00
# define TO_STR(a) #a
# define JOIN(a,b) a##b
2008-05-02 00:16:48 +00:00
# define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
2008-05-01 01:00:01 +00:00
/* Benchmark macros */
2008-08-22 00:35:14 +00:00
# if !defined(_WIN32) && 0
2008-05-01 01:00:01 +00:00
2008-08-06 15:46:38 +00:00
# include <sys/time.h>
# define BENCH(a) \
do { \
double _t1 , _t2 ; \
struct timeval _tstart , _tend ; \
2008-08-07 14:26:27 +00:00
clock_t _clock_init = clock ( ) ; \
2008-08-06 15:46:38 +00:00
gettimeofday ( & _tstart , NULL ) ; \
( a ) ; \
gettimeofday ( & _tend , NULL ) ; \
_t1 = ( double ) _tstart . tv_sec + ( double ) _tstart . tv_usec / ( 1000 * 1000 ) ; \
_t2 = ( double ) _tend . tv_sec + ( double ) _tend . tv_usec / ( 1000 * 1000 ) ; \
2008-08-07 14:26:27 +00:00
printf ( " %s: %fs (real) %fs (cpu) \n " , # a , _t2 - _t1 , ( float ) ( clock ( ) - _clock_init ) / CLOCKS_PER_SEC ) ; \
2008-08-06 15:46:38 +00:00
} while ( 0 )
2008-05-01 01:00:01 +00:00
# else
# define BENCH(a) (a)
# endif
2008-04-30 17:55:26 +00:00
typedef void ( * Shrinkwrap_ForeachVertexCallback ) ( DerivedMesh * target , float * co , float * normal ) ;
2008-07-21 18:12:02 +00:00
/* get derived mesh */
//TODO is anyfunction that does this? returning the derivedFinal witouth we caring if its in edit mode or not?
2009-01-04 14:14:06 +00:00
static DerivedMesh * object_get_derived_final ( struct Scene * scene , Object * ob , CustomDataMask dataMask )
2008-07-21 18:12:02 +00:00
{
2008-12-31 17:11:42 +00:00
Mesh * me = ob - > data ;
2009-05-18 08:46:04 +00:00
BMEditMesh * em = me - > edit_btmesh ;
2009-03-30 07:28:37 +00:00
if ( em )
2008-07-21 18:12:02 +00:00
{
DerivedMesh * final = NULL ;
2009-05-16 16:18:08 +00:00
editbmesh_get_derived_cage_and_final ( scene , ob , em , & final , dataMask ) ;
2009-03-30 07:28:37 +00:00
2008-07-21 18:12:02 +00:00
return final ;
}
else
2009-01-04 14:14:06 +00:00
return mesh_get_derived_final ( scene , ob , dataMask ) ;
2008-07-21 18:12:02 +00:00
}
2008-07-22 11:50:50 +00:00
2008-07-18 22:24:20 +00:00
/* Space transform */
2008-07-25 18:48:24 +00:00
void space_transform_from_matrixs ( SpaceTransform * data , float local [ 4 ] [ 4 ] , float target [ 4 ] [ 4 ] )
2008-07-18 22:24:20 +00:00
{
2008-07-25 18:48:24 +00:00
float itarget [ 4 ] [ 4 ] ;
2008-08-12 20:43:10 +00:00
Mat4Invert ( itarget , target ) ;
2008-07-25 18:48:24 +00:00
Mat4MulSerie ( data - > local2target , itarget , local , 0 , 0 , 0 , 0 , 0 , 0 ) ;
2008-07-18 22:24:20 +00:00
Mat4Invert ( data - > target2local , data - > local2target ) ;
}
2008-07-19 15:22:38 +00:00
void space_transform_apply ( const SpaceTransform * data , float * co )
2008-07-18 22:24:20 +00:00
{
2008-08-22 18:28:34 +00:00
VecMat4MulVecfl ( co , ( ( SpaceTransform * ) data ) - > local2target , co ) ;
2008-07-18 22:24:20 +00:00
}
2008-07-19 15:22:38 +00:00
void space_transform_invert ( const SpaceTransform * data , float * co )
2008-07-18 22:24:20 +00:00
{
2008-08-22 18:28:34 +00:00
VecMat4MulVecfl ( co , ( ( SpaceTransform * ) data ) - > target2local , co ) ;
2008-07-18 22:24:20 +00:00
}
2009-01-04 14:14:06 +00:00
static void space_transform_apply_normal ( const SpaceTransform * data , float * no )
2008-07-18 22:24:20 +00:00
{
2008-08-22 18:28:34 +00:00
Mat4Mul3Vecfl ( ( ( SpaceTransform * ) data ) - > local2target , no ) ;
2008-07-18 22:24:20 +00:00
Normalize ( no ) ; // TODO: could we just determine de scale value from the matrix?
}
2009-01-04 14:14:06 +00:00
static void space_transform_invert_normal ( const SpaceTransform * data , float * no )
2008-07-18 22:24:20 +00:00
{
2008-08-22 18:28:34 +00:00
Mat4Mul3Vecfl ( ( ( SpaceTransform * ) data ) - > target2local , no ) ;
2008-07-18 22:24:20 +00:00
Normalize ( no ) ; // TODO: could we just determine de scale value from the matrix?
}
2008-05-25 15:43:18 +00:00
/*
* Returns the squared distance between two given points
*/
static float squared_dist ( const float * a , const float * b )
{
float tmp [ 3 ] ;
VECSUB ( tmp , a , b ) ;
return INPR ( tmp , tmp ) ;
}
2008-07-25 18:48:24 +00:00
2008-05-02 00:16:48 +00:00
/*
* Shrinkwrap to the nearest vertex
*
* it builds a kdtree of vertexs we can attach to and then
2008-08-12 20:43:10 +00:00
* for each vertex performs a nearest vertex search on the tree
2008-05-02 00:16:48 +00:00
*/
2009-01-04 14:14:06 +00:00
static void shrinkwrap_calc_nearest_vertex ( ShrinkwrapCalcData * calc )
2008-05-01 01:00:01 +00:00
{
int i ;
2008-08-04 14:27:25 +00:00
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh ;
BVHTreeNearest nearest = NULL_BVHTreeNearest ;
2008-05-14 18:25:23 +00:00
2008-05-25 15:43:18 +00:00
2008-08-06 15:46:38 +00:00
BENCH ( bvhtree_from_mesh_verts ( & treeData , calc - > target , 0.0 , 2 , 6 ) ) ;
2008-10-21 23:07:09 +00:00
if ( treeData . tree = = NULL )
{
OUT_OF_MEMORY ( ) ;
return ;
}
2008-05-01 01:00:01 +00:00
2008-05-27 18:40:33 +00:00
//Setup nearest
2008-05-25 15:43:18 +00:00
nearest . index = - 1 ;
nearest . dist = FLT_MAX ;
2009-01-02 19:10:35 +00:00
# ifndef __APPLE__
2008-08-13 01:38:13 +00:00
# pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData,calc) schedule(static)
2009-01-02 19:10:35 +00:00
# endif
2008-08-06 15:46:38 +00:00
for ( i = 0 ; i < calc - > numVerts ; + + i )
2008-05-01 01:00:01 +00:00
{
2008-08-06 15:46:38 +00:00
float * co = calc - > vertexCos [ i ] ;
2008-07-25 18:48:24 +00:00
float tmp_co [ 3 ] ;
2008-11-03 23:17:36 +00:00
float weight = vertexgroup_get_vertex_weight ( calc - > dvert , i , calc - > vgroup ) ;
2008-05-02 00:16:48 +00:00
if ( weight = = 0.0f ) continue ;
2008-07-25 18:48:24 +00:00
VECCOPY ( tmp_co , co ) ;
2008-08-12 20:43:10 +00:00
space_transform_apply ( & calc - > local2target , tmp_co ) ; //Convert the coordinates to the tree coordinates
2008-05-25 15:43:18 +00:00
2008-07-25 18:48:24 +00:00
//Use local proximity heuristics (to reduce the nearest search)
2008-08-12 20:43:10 +00:00
//
//If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
//so we can initiate the "nearest.dist" with the expected value to that last hit.
//This will lead in prunning of the search tree.
2008-05-25 15:43:18 +00:00
if ( nearest . index ! = - 1 )
2008-07-19 15:22:38 +00:00
nearest . dist = squared_dist ( tmp_co , nearest . co ) ;
2008-07-25 18:48:24 +00:00
else
nearest . dist = FLT_MAX ;
2008-05-25 15:43:18 +00:00
2008-08-12 20:43:10 +00:00
BLI_bvhtree_find_nearest ( treeData . tree , tmp_co , & nearest , treeData . nearest_callback , & treeData ) ;
2008-05-25 15:43:18 +00:00
2008-08-12 20:43:10 +00:00
//Found the nearest vertex
if ( nearest . index ! = - 1 )
2008-05-14 18:25:23 +00:00
{
2008-08-13 17:34:09 +00:00
//Adjusting the vertex weight, so that after interpolating it keeps a certain distance from the nearest position
2008-08-12 20:43:10 +00:00
float dist = sasqrt ( nearest . dist ) ;
2008-08-13 17:34:09 +00:00
if ( dist > FLT_EPSILON ) weight * = ( dist - calc - > keepDist ) / dist ;
2008-08-07 14:26:27 +00:00
2008-08-12 20:43:10 +00:00
//Convert the coordinates back to mesh coordinates
2008-07-19 15:22:38 +00:00
VECCOPY ( tmp_co , nearest . co ) ;
2008-07-18 22:24:20 +00:00
space_transform_invert ( & calc - > local2target , tmp_co ) ;
2008-08-12 20:43:10 +00:00
2008-07-25 18:48:24 +00:00
VecLerpf ( co , co , tmp_co , weight ) ; //linear interpolation
2008-05-14 18:25:23 +00:00
}
2008-05-01 01:00:01 +00:00
}
2008-08-07 15:18:47 +00:00
free_bvhtree_from_mesh ( & treeData ) ;
2008-05-01 01:00:01 +00:00
}
2008-04-30 17:55:26 +00:00
2008-07-18 22:24:20 +00:00
/*
* This function raycast a single vertex and updates the hit if the " hit " is considered valid .
* Returns TRUE if " hit " was updated .
* Opts control whether an hit is valid or not
* Supported options are :
* MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE ( front faces hits are ignored )
* MOD_SHRINKWRAP_CULL_TARGET_BACKFACE ( back faces hits are ignored )
*/
2008-07-25 18:48:24 +00:00
int normal_projection_project_vertex ( char options , const float * vert , const float * dir , const SpaceTransform * transf , BVHTree * tree , BVHTreeRayHit * hit , BVHTree_RayCastCallback callback , void * userdata )
2008-07-18 22:24:20 +00:00
{
float tmp_co [ 3 ] , tmp_no [ 3 ] ;
2008-07-19 15:22:38 +00:00
const float * co , * no ;
2008-07-18 22:24:20 +00:00
BVHTreeRayHit hit_tmp ;
2008-08-04 14:27:25 +00:00
//Copy from hit (we need to convert hit rays from one space coordinates to the other
2008-07-18 22:24:20 +00:00
memcpy ( & hit_tmp , hit , sizeof ( hit_tmp ) ) ;
//Apply space transform (TODO readjust dist)
if ( transf )
{
VECCOPY ( tmp_co , vert ) ;
space_transform_apply ( transf , tmp_co ) ;
2008-07-19 15:22:38 +00:00
co = tmp_co ;
2008-07-18 22:24:20 +00:00
VECCOPY ( tmp_no , dir ) ;
space_transform_apply_normal ( transf , tmp_no ) ;
2008-07-19 15:22:38 +00:00
no = tmp_no ;
2008-08-22 18:28:34 +00:00
hit_tmp . dist * = Mat4ToScalef ( ( ( SpaceTransform * ) transf ) - > local2target ) ;
2008-07-19 15:22:38 +00:00
}
else
{
co = vert ;
no = dir ;
2008-07-18 22:24:20 +00:00
}
hit_tmp . index = - 1 ;
2008-09-13 18:09:41 +00:00
BLI_bvhtree_ray_cast ( tree , co , no , 0.0f , & hit_tmp , callback , userdata ) ;
2008-07-18 22:24:20 +00:00
if ( hit_tmp . index ! = - 1 )
{
float dot = INPR ( dir , hit_tmp . no ) ;
2008-08-13 01:38:13 +00:00
if ( ( ( options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE ) & & dot < = 0.0f )
| | ( ( options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE ) & & dot > = 0.0f ) )
2008-07-18 22:24:20 +00:00
return FALSE ; //Ignore hit
2008-07-19 15:22:38 +00:00
//Inverting space transform (TODO make coeherent with the initial dist readjust)
2008-07-18 22:24:20 +00:00
if ( transf )
{
space_transform_invert ( transf , hit_tmp . co ) ;
space_transform_invert_normal ( transf , hit_tmp . no ) ;
2008-07-19 15:22:38 +00:00
2008-08-22 18:28:34 +00:00
hit_tmp . dist = VecLenf ( ( float * ) vert , hit_tmp . co ) ;
2008-07-18 22:24:20 +00:00
}
memcpy ( hit , & hit_tmp , sizeof ( hit_tmp ) ) ;
return TRUE ;
}
return FALSE ;
}
2008-05-02 00:16:48 +00:00
2009-01-04 14:14:06 +00:00
static void shrinkwrap_calc_normal_projection ( ShrinkwrapCalcData * calc , struct Scene * scene )
2008-07-09 19:43:09 +00:00
{
int i ;
2008-08-12 20:43:10 +00:00
//Options about projection direction
2008-08-13 01:38:13 +00:00
const char use_normal = calc - > smd - > shrinkOpts ;
2008-08-12 20:43:10 +00:00
float proj_axis [ 3 ] = { 0.0f , 0.0f , 0.0f } ;
MVert * vert = NULL ; //Needed in case of vertex normal
2008-08-14 03:05:13 +00:00
DerivedMesh * ss_mesh = NULL ;
2008-07-18 22:24:20 +00:00
2008-08-12 20:43:10 +00:00
//Raycast and tree stuff
BVHTreeRayHit hit ;
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh ; //target
//auxiliar target
DerivedMesh * aux_mesh = NULL ;
BVHTreeFromMesh auxData = NULL_BVHTreeFromMesh ;
SpaceTransform local2aux ;
2008-08-14 03:05:13 +00:00
do
{
2008-08-12 20:43:10 +00:00
//Prepare data to retrieve the direction in which we should project each vertex
if ( calc - > smd - > projAxis = = MOD_SHRINKWRAP_PROJECT_OVER_NORMAL )
2008-07-25 18:48:24 +00:00
{
2008-08-14 03:05:13 +00:00
//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 ;
2008-08-12 20:43:10 +00:00
}
else
{
//The code supports any axis that is a combination of X,Y,Z.. altought currently UI only allows to set the 3 diferent axis
if ( calc - > smd - > projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS ) proj_axis [ 0 ] = 1.0f ;
if ( calc - > smd - > projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS ) proj_axis [ 1 ] = 1.0f ;
if ( calc - > smd - > projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS ) proj_axis [ 2 ] = 1.0f ;
Normalize ( proj_axis ) ;
2008-08-14 03:05:13 +00:00
//Invalid projection direction: jump to "free memory and return" part
if ( INPR ( proj_axis , proj_axis ) < FLT_EPSILON ) break ;
2008-07-25 18:48:24 +00:00
}
2008-07-09 19:43:09 +00:00
2008-08-12 20:43:10 +00:00
//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 )
2008-08-14 03:05:13 +00:00
break ; //jump to "free memory and return" part
2008-08-12 20:43:10 +00:00
2008-07-25 18:48:24 +00:00
2008-08-12 20:43:10 +00:00
//Build target tree
2008-08-13 17:34:09 +00:00
BENCH ( bvhtree_from_mesh_faces ( & treeData , calc - > target , calc - > keepDist , 4 , 6 ) ) ;
2008-08-14 03:05:13 +00:00
if ( treeData . tree = = NULL )
break ; //jump to "free memory and return" part
2008-07-09 19:43:09 +00:00
2008-08-12 20:43:10 +00:00
//Build auxiliar target
if ( calc - > smd - > auxTarget )
2008-07-18 22:24:20 +00:00
{
2008-08-12 20:43:10 +00:00
space_transform_setup ( & local2aux , calc - > ob , calc - > smd - > auxTarget ) ;
2008-07-22 11:50:50 +00:00
2009-01-04 14:14:06 +00:00
aux_mesh = CDDM_copy ( object_get_derived_final ( scene , calc - > smd - > auxTarget , CD_MASK_BAREMESH ) ) ; //TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array
2008-08-12 20:43:10 +00:00
if ( aux_mesh )
BENCH ( bvhtree_from_mesh_faces ( & auxData , aux_mesh , 0.0 , 4 , 6 ) ) ;
2008-07-22 11:50:50 +00:00
else
2008-08-12 20:43:10 +00:00
printf ( " Auxiliar target finalDerived mesh is null \n " ) ;
2008-07-18 22:24:20 +00:00
}
2008-07-09 19:43:09 +00:00
2008-08-12 20:43:10 +00:00
//Now, everything is ready to project the vertexs!
2009-01-02 19:10:35 +00:00
# ifndef __APPLE__
2008-08-13 19:22:35 +00:00
# pragma omp parallel for private(i,hit) schedule(static)
2009-01-02 19:10:35 +00:00
# endif
2008-08-06 15:46:38 +00:00
for ( i = 0 ; i < calc - > numVerts ; + + i )
2008-07-09 19:43:09 +00:00
{
2008-08-06 15:46:38 +00:00
float * co = calc - > vertexCos [ i ] ;
2008-07-09 19:43:09 +00:00
float tmp_co [ 3 ] , tmp_no [ 3 ] ;
2008-08-22 00:35:14 +00:00
float lim = 10000.0f ; //TODO: we should use FLT_MAX here, but sweepsphere code isnt prepared for that
2008-11-03 23:17:36 +00:00
float weight = vertexgroup_get_vertex_weight ( calc - > dvert , i , calc - > vgroup ) ;
2008-07-09 19:43:09 +00:00
if ( weight = = 0.0f ) continue ;
2008-08-14 03:05:13 +00:00
if ( ss_mesh )
{
VECCOPY ( tmp_co , vert [ i ] . co ) ;
}
else
{
VECCOPY ( tmp_co , co ) ;
}
2008-08-12 20:43:10 +00:00
if ( vert )
NormalShortToFloat ( tmp_no , vert [ i ] . no ) ;
else
VECCOPY ( tmp_no , proj_axis ) ;
2008-07-18 22:24:20 +00:00
2008-07-09 19:43:09 +00:00
hit . index = - 1 ;
2008-07-18 22:24:20 +00:00
hit . dist = lim ;
2008-07-09 19:43:09 +00:00
2008-07-19 15:22:38 +00:00
2008-08-12 20:43:10 +00:00
//Project over positive direction of axis
if ( use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR )
2008-07-09 19:43:09 +00:00
{
2008-07-25 18:48:24 +00:00
2008-08-12 20:43:10 +00:00
if ( auxData . tree )
normal_projection_project_vertex ( 0 , tmp_co , tmp_no , & local2aux , auxData . tree , & hit , auxData . raycast_callback , & auxData ) ;
2008-07-19 15:22:38 +00:00
2008-08-12 20:43:10 +00:00
normal_projection_project_vertex ( calc - > smd - > shrinkOpts , tmp_co , tmp_no , & calc - > local2target , treeData . tree , & hit , treeData . raycast_callback , & treeData ) ;
2008-07-09 19:43:09 +00:00
}
2008-08-12 20:43:10 +00:00
//Project over negative direction of axis
if ( use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR )
2008-07-09 19:43:09 +00:00
{
2008-07-18 22:24:20 +00:00
float inv_no [ 3 ] = { - tmp_no [ 0 ] , - tmp_no [ 1 ] , - tmp_no [ 2 ] } ;
2008-07-19 15:22:38 +00:00
2008-07-25 18:48:24 +00:00
2008-08-12 20:43:10 +00:00
if ( auxData . tree )
normal_projection_project_vertex ( 0 , tmp_co , inv_no , & local2aux , auxData . tree , & hit , auxData . raycast_callback , & auxData ) ;
2008-07-25 18:48:24 +00:00
2008-08-12 20:43:10 +00:00
normal_projection_project_vertex ( calc - > smd - > shrinkOpts , tmp_co , inv_no , & calc - > local2target , treeData . tree , & hit , treeData . raycast_callback , & treeData ) ;
2008-07-09 19:43:09 +00:00
}
2008-07-18 22:24:20 +00:00
2008-07-09 19:43:09 +00:00
if ( hit . index ! = - 1 )
{
2008-07-25 18:48:24 +00:00
VecLerpf ( co , co , hit . co , weight ) ;
2008-07-09 19:43:09 +00:00
}
}
2008-08-12 20:43:10 +00:00
2008-08-14 03:05:13 +00:00
//Simple do{} while(0) structure to allow to easily jump to the "free memory and return" part
} while ( 0 ) ;
2008-08-12 20:43:10 +00:00
//free data structures
2008-08-07 15:18:47 +00:00
free_bvhtree_from_mesh ( & treeData ) ;
2008-08-12 20:43:10 +00:00
free_bvhtree_from_mesh ( & auxData ) ;
2008-07-21 18:12:02 +00:00
2008-08-12 20:43:10 +00:00
if ( aux_mesh )
aux_mesh - > release ( aux_mesh ) ;
2008-08-14 03:05:13 +00:00
if ( ss_mesh )
ss_mesh - > release ( ss_mesh ) ;
2008-07-09 19:43:09 +00:00
}
2008-05-26 21:57:53 +00:00
/*
* Shrinkwrap moving vertexs to the nearest surface point on the target
*
* it builds a BVHTree from the target mesh and then performs a
* NN matchs for each vertex
*/
2009-01-04 14:14:06 +00:00
static void shrinkwrap_calc_nearest_surface_point ( ShrinkwrapCalcData * calc )
2008-05-26 21:57:53 +00:00
{
int i ;
2008-08-06 15:46:38 +00:00
2008-08-04 14:27:25 +00:00
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh ;
BVHTreeNearest nearest = NULL_BVHTreeNearest ;
2008-05-26 21:57:53 +00:00
//Create a bvh-tree of the given target
2008-08-06 15:46:38 +00:00
BENCH ( bvhtree_from_mesh_faces ( & treeData , calc - > target , 0.0 , 2 , 6 ) ) ;
2008-10-21 23:07:09 +00:00
if ( treeData . tree = = NULL )
{
OUT_OF_MEMORY ( ) ;
return ;
}
2008-05-26 21:57:53 +00:00
2008-05-27 18:40:33 +00:00
//Setup nearest
2008-05-26 21:57:53 +00:00
nearest . index = - 1 ;
nearest . dist = FLT_MAX ;
2008-08-14 03:05:13 +00:00
//Find the nearest vertex
2009-01-02 19:10:35 +00:00
# ifndef __APPLE__
2008-08-13 01:38:13 +00:00
# pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc,treeData) schedule(static)
2009-01-02 19:10:35 +00:00
# endif
2008-08-06 15:46:38 +00:00
for ( i = 0 ; i < calc - > numVerts ; + + i )
2008-05-26 21:57:53 +00:00
{
2008-08-06 15:46:38 +00:00
float * co = calc - > vertexCos [ i ] ;
2008-07-25 18:48:24 +00:00
float tmp_co [ 3 ] ;
2008-11-03 23:17:36 +00:00
float weight = vertexgroup_get_vertex_weight ( calc - > dvert , i , calc - > vgroup ) ;
2008-05-26 21:57:53 +00:00
if ( weight = = 0.0f ) continue ;
2008-08-13 01:38:13 +00:00
//Convert the vertex to tree coordinates
2008-07-25 18:48:24 +00:00
VECCOPY ( tmp_co , co ) ;
2008-07-18 22:24:20 +00:00
space_transform_apply ( & calc - > local2target , tmp_co ) ;
2008-05-26 21:57:53 +00:00
2008-08-13 01:38:13 +00:00
//Use local proximity heuristics (to reduce the nearest search)
//
//If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
//so we can initiate the "nearest.dist" with the expected value to that last hit.
//This will lead in prunning of the search tree.
2008-05-26 21:57:53 +00:00
if ( nearest . index ! = - 1 )
2008-07-19 15:22:38 +00:00
nearest . dist = squared_dist ( tmp_co , nearest . co ) ;
2008-08-13 01:38:13 +00:00
else
nearest . dist = FLT_MAX ;
2008-05-26 21:57:53 +00:00
2008-08-13 01:38:13 +00:00
BLI_bvhtree_find_nearest ( treeData . tree , tmp_co , & nearest , treeData . nearest_callback , & treeData ) ;
2008-05-26 21:57:53 +00:00
2008-08-13 01:38:13 +00:00
//Found the nearest vertex
2008-08-14 03:05:13 +00:00
if ( nearest . index ! = - 1 )
2008-05-26 21:57:53 +00:00
{
2008-08-13 17:34:09 +00:00
if ( calc - > smd - > shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE )
2008-07-18 22:24:20 +00:00
{
2008-08-13 01:38:13 +00:00
//Make the vertex stay on the front side of the face
2008-08-13 17:34:09 +00:00
VECADDFAC ( tmp_co , nearest . co , nearest . no , calc - > keepDist ) ;
2008-07-18 22:24:20 +00:00
}
else
{
2008-08-13 17:34:09 +00:00
//Adjusting the vertex weight, so that after interpolating it keeps a certain distance from the nearest position
2008-08-07 14:26:27 +00:00
float dist = sasqrt ( nearest . dist ) ;
2008-08-12 20:43:10 +00:00
if ( dist > FLT_EPSILON )
2008-08-13 17:34:09 +00:00
VecLerpf ( tmp_co , tmp_co , nearest . co , ( dist - calc - > keepDist ) / dist ) ; //linear interpolation
2008-08-12 20:43:10 +00:00
else
VECCOPY ( tmp_co , nearest . co ) ;
2008-07-18 22:24:20 +00:00
}
2008-08-13 01:38:13 +00:00
//Convert the coordinates back to mesh coordinates
2008-07-18 22:24:20 +00:00
space_transform_invert ( & calc - > local2target , tmp_co ) ;
2008-07-25 18:48:24 +00:00
VecLerpf ( co , co , tmp_co , weight ) ; //linear interpolation
2008-05-26 21:57:53 +00:00
}
}
2008-08-13 01:38:13 +00:00
2008-08-07 15:18:47 +00:00
free_bvhtree_from_mesh ( & treeData ) ;
2008-05-26 21:57:53 +00:00
}
2008-05-02 00:16:48 +00:00
2009-01-04 14:14:06 +00:00
/* Main shrinkwrap function */
void shrinkwrapModifier_deform ( ShrinkwrapModifierData * smd , struct Scene * scene , Object * ob , DerivedMesh * dm , float ( * vertexCos ) [ 3 ] , int numVerts )
{
ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData ;
//remove loop dependencies on derived meshs (TODO should this be done elsewhere?)
if ( smd - > target = = ob ) smd - > target = NULL ;
if ( smd - > auxTarget = = ob ) smd - > auxTarget = NULL ;
//Configure Shrinkwrap calc data
calc . smd = smd ;
calc . ob = ob ;
calc . original = dm ;
calc . numVerts = numVerts ;
calc . vertexCos = vertexCos ;
//DeformVertex
calc . vgroup = get_named_vertexgroup_num ( calc . ob , calc . smd - > vgroup_name ) ;
if ( calc . original )
{
calc . dvert = calc . original - > getVertDataArray ( calc . original , CD_MDEFORMVERT ) ;
}
else if ( calc . ob - > type = = OB_LATTICE )
{
calc . dvert = lattice_get_deform_verts ( calc . ob ) ;
}
if ( smd - > target )
{
//TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array
calc . target = CDDM_copy ( object_get_derived_final ( scene , smd - > target , CD_MASK_BAREMESH ) ) ;
//TODO there might be several "bugs" on non-uniform scales matrixs.. because it will no longer be nearest surface, not sphere projection
//because space has been deformed
space_transform_setup ( & calc . local2target , ob , smd - > target ) ;
calc . keepDist = smd - > keepDist ; //TODO: smd->keepDist is in global units.. must change to local
}
//Projecting target defined - lets work!
if ( calc . target )
{
switch ( smd - > shrinkType )
{
case MOD_SHRINKWRAP_NEAREST_SURFACE :
BENCH ( shrinkwrap_calc_nearest_surface_point ( & calc ) ) ;
break ;
case MOD_SHRINKWRAP_PROJECT :
BENCH ( shrinkwrap_calc_normal_projection ( & calc , scene ) ) ;
break ;
case MOD_SHRINKWRAP_NEAREST_VERTEX :
BENCH ( shrinkwrap_calc_nearest_vertex ( & calc ) ) ;
break ;
}
}
//free memory
if ( calc . target )
calc . target - > release ( calc . target ) ;
}