Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTon Roosendaal <ton@blender.org>2006-10-31 18:51:57 +0300
committerTon Roosendaal <ton@blender.org>2006-10-31 18:51:57 +0300
commit35d6c6e695351051febf7d6aa84761db1d733295 (patch)
treea23a19bcff44113fe830c92b9c71fa9539cbef76 /source/blender/blenkernel
parent52c20fecba07fecb4964d1ef310eb944bccd68ea (diff)
Two wonderful new NLA & Armature editing features!
- FORWARD CYCLING & MATCHING Up to no now, adding multiple actions in NLA with walkcycles required to animate them standing still, as if walking on a conveyor belt. The stride option then makes the object itself move forward, trying to keep the foot stuck on the floor (with poor results!). This option now allows to make walk cycles moving forward. By indicating a reference Offset Bone, the NLA system will use that bone to detect the correct offset for the Armature Pose to make it seamlessly going forward. Best of all, this option works as for cyclic Action Strips as well as for individual Action Strips. Note that for individual strips, you have to set the strip on "Hold". (Might become automatic detected later). Here's an example edit image for NLA: http://www.blender.org/bf/nla_match-cycle.jpg And the animation for it: http://download.blender.org/demo/test/2.43/0001_0150_match.avi Blender file: http://download.blender.org/demo/test/2.43/mancandy_matching.blend Using this kind of cycling works pretty straightforward, and is a lot easier to setup than Stride Bones. To be further tested: - Blending cycles - matching rotation for the bones as well. - ACTION MODIFIERS (motion deformors) The above option was actually required for this feature. Typically walk cycles are constructed with certain Bones to be the handles, controlling for example the torso or feet. An Action Modifier allows you to use a Curve Path to deform the motion of these controlling bones. This uses the existing Curve Deformation option. Modifiers can be added per Action Strip, each controlling a channel (bone) by choice, and even allows to layer multiple modifiers on top of each other (several paths deforming motion). This option is using the dependency graph, so editing the Curve will give realtime changes in the Armature. The previous walkcycle, controlled by two curves: http://download.blender.org/demo/test/2.43/0001_0150_deform.avi Blender file: http://download.blender.org/demo/test/2.43/mancandy_actiondeform.blend Action Modifiers can be added in the NLA Properties Panel. Per Modifier you have to indicate the channel and a Curve Object. You can copy modifiers from one strip to another using CTRL+C (only copies to active Object strips). Setting up a correct Curve Path has to be carefully done: - Use SHIFT+A "Curve Path" in top view, or ensure the path is not rotated. - make sure the center point of the Curve Object is at the center of the Armature (or above) - move the first point of the curve to the center point as well. - check if the path starts from this first point, you can change it using (in Curve EditMode) the option Wkey -> "Switch Direction" - Make sure alignment uses the correct axis; if the Armature walks into the negative Y direction, you have to set in Object Buttons, "Anim settings" Panel, the correct Track option. (Note; option will probably move to the Modifier later). This is a good reason to make such paths automatic (on a command). Is on the todo list. Also note this: - the Curve Path extends in beginning and ending, that's (for now) the default, and allows to use multiple paths. Make sure paths begin and end horizontal. - Moving the Curve in Object Mode will change the "mapping" (as if the landscape a character walks over moves). Moving the Curve in Edit Mode will change the actual position of the deformation. - Speed (Ipos) on paths is not supported yet, will be done. - The Curve "Stretch" deform option doesn't work. - Modifiers are executed *after* all actions in NLA are evaluated, there's no support yet for blending multiple strips with Modifiers. - This doesn't work yet for time-mapping... This commit is mostly for review by character animators... some details or working methods might change. This feature can also be used for other modifiers, such as noise (Perlin) or the mythical "Oomph" (frequency control) and of course Python. Special thanks to Bassam & Matt for research & design help. Have fun!
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_lattice.h7
-rw-r--r--source/blender/blenkernel/intern/action.c308
-rw-r--r--source/blender/blenkernel/intern/armature.c37
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c11
-rw-r--r--source/blender/blenkernel/intern/lattice.c89
-rw-r--r--source/blender/blenkernel/intern/nla.c16
-rw-r--r--source/blender/blenkernel/intern/object.c7
7 files changed, 375 insertions, 100 deletions
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 6e738bd53fb..bcf65fcd540 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -53,7 +53,12 @@ void calc_latt_deform(float *co, float weight);
void end_latt_deform(void);
int object_deform_mball(struct Object *ob);
void outside_lattice(struct Lattice *lt);
-void curve_deform_verts(struct Object *cuOb, struct Object *target, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis);
+void curve_deform_verts(struct Object *cuOb, struct Object *target,
+ struct DerivedMesh *dm, float (*vertexCos)[3],
+ int numVerts, char *vgroup, short defaxis);
+void curve_deform_vector(struct Object *cuOb, struct Object *target,
+ float *orco, float *vec, float mat[][3], int no_rot_axis);
+
void lattice_deform_verts(struct Object *laOb, struct Object *target,
struct DerivedMesh *dm, float (*vertexCos)[3],
int numVerts, char *vgroup);
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 08462472406..6d0a5f672cc 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -57,6 +57,7 @@
#include "BKE_global.h"
#include "BKE_ipo.h"
#include "BKE_key.h"
+#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -386,6 +387,68 @@ bActionChannel *verify_action_channel(bAction *act, const char *name)
return chan;
}
+/* ************** time ****************** */
+
+static bActionStrip *get_active_strip(Object *ob)
+{
+ bActionStrip *strip;
+
+ if(ob->action==NULL)
+ return NULL;
+
+ for (strip=ob->nlastrips.first; strip; strip=strip->next)
+ if(strip->flag & ACTSTRIP_ACTIVE)
+ break;
+
+ if(strip && strip->act==ob->action)
+ return strip;
+ return NULL;
+}
+
+/* non clipped mapping of strip */
+static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert)
+{
+ float length, actlength, repeat;
+
+ if (strip->flag & ACTSTRIP_USESTRIDE)
+ repeat= 1.0f;
+ else
+ repeat= strip->repeat;
+
+ length = strip->end-strip->start;
+ if(length==0.0f)
+ length= 1.0f;
+ actlength = strip->actend-strip->actstart;
+
+
+
+ if(invert)
+ return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start;
+ else
+ return repeat*actlength*(cframe - strip->start)/length + strip->actstart;
+}
+
+/* if the conditions match, it converts current time to strip time */
+float get_action_frame(Object *ob, float cframe)
+{
+ bActionStrip *strip= get_active_strip(ob);
+
+ if(strip)
+ return get_actionstrip_frame(strip, cframe, 0);
+ return cframe;
+}
+
+/* inverted, strip time to current time */
+float get_action_frame_inv(Object *ob, float cframe)
+{
+ bActionStrip *strip= get_active_strip(ob);
+
+ if(strip)
+ return get_actionstrip_frame(strip, cframe, 1);
+ return cframe;
+}
+
+
/* ************************ Blending with NLA *************** */
static void blend_pose_strides(bPose *dst, bPose *src, float srcweight, short mode)
@@ -406,6 +469,87 @@ static void blend_pose_strides(bPose *dst, bPose *src, float srcweight, short mo
VecLerpf(dst->stride_offset, dst->stride_offset, src->stride_offset, srcweight);
}
+
+/*
+
+bone matching diagram, strips A and B
+
+ .------------------------.
+ | A |
+ '------------------------'
+ . . b2
+ . .-------------v----------.
+ . | B . |
+ . '------------------------'
+ . . .
+ . . .
+offset: . 0 . A-B . A-b2+B
+ . . .
+
+*/
+
+
+static void blend_pose_offset_bone(bActionStrip *strip, bPose *dst, bPose *src, float srcweight, short mode)
+{
+ /* matching offset bones */
+ /* take dst offset, and put src on on that location */
+
+ if(strip->offs_bone[0]==0)
+ return;
+
+ /* are we also blending with matching bones? */
+ if(strip->prev && strip->start>=strip->prev->start) {
+ bPoseChannel *dpchan= get_pose_channel(dst, strip->offs_bone);
+ if(dpchan) {
+ bPoseChannel *spchan= get_pose_channel(src, strip->offs_bone);
+ if(spchan) {
+ float vec[3];
+
+ /* dst->ctime has the internal strip->prev action time */
+ /* map this time to nla time */
+
+ float ctime= get_actionstrip_frame(strip, src->ctime, 1);
+
+ if( ctime > strip->prev->end) {
+ bActionChannel *achan;
+
+ /* add src to dest, minus the position of src on strip->prev->end */
+
+ ctime= get_actionstrip_frame(strip, strip->prev->end, 0);
+
+ achan= get_action_channel(strip->act, strip->offs_bone);
+ if(achan && achan->ipo) {
+ bPoseChannel pchan;
+ /* Evaluates and sets the internal ipo value */
+ calc_ipo(achan->ipo, ctime);
+ /* This call also sets the pchan flags */
+ execute_action_ipo(achan, &pchan);
+
+ /* store offset that moves src to location of pchan */
+ VecSubf(vec, dpchan->loc, pchan.loc);
+
+ Mat4Mul3Vecfl(dpchan->bone->arm_mat, vec);
+ }
+ }
+ else {
+ /* store offset that moves src to location of dst */
+
+ VecSubf(vec, dpchan->loc, spchan->loc);
+ Mat4Mul3Vecfl(dpchan->bone->arm_mat, vec);
+ }
+
+ /* if blending, we only add with factor scrweight */
+ VecMulf(vec, srcweight);
+
+ VecAddf(dst->cyclic_offset, dst->cyclic_offset, vec);
+ }
+ }
+ }
+
+ VecAddf(dst->cyclic_offset, dst->cyclic_offset, src->cyclic_offset);
+}
+
+
/* Only allowed for Poses with identical channels */
void blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
{
@@ -457,6 +601,9 @@ void blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight;
}
}
+
+ /* this pose is now in src time */
+ dst->ctime= src->ctime;
}
@@ -545,6 +692,8 @@ void extract_pose_from_action(bPose *pose, bAction *act, float ctime)
do_constraint_channels(&pchan->constraints, &achan->constraintChannels, ctime);
}
}
+
+ pose->ctime= ctime; /* used for cyclic offset matching */
}
/* for do_all_pose_actions, clears the pose */
@@ -556,17 +705,16 @@ static void rest_pose(bPose *pose)
if (!pose)
return;
- pose->stride_offset[0]= 0.0f;
- pose->stride_offset[1]= 0.0f;
- pose->stride_offset[2]= 0.0f;
+ memset(pose->stride_offset, 0, sizeof(pose->stride_offset));
+ memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset));
- for (pchan=pose->chanbase.first; pchan; pchan=pchan->next){
- for (i=0; i<3; i++){
- pchan->loc[i]=0.0;
- pchan->quat[i+1]=0.0;
- pchan->size[i]=1.0;
+ for (pchan=pose->chanbase.first; pchan; pchan= pchan->next){
+ for (i=0; i<3; i++) {
+ pchan->loc[i]= 0.0f;
+ pchan->quat[i+1]= 0.0f;
+ pchan->size[i]= 1.0f;
}
- pchan->quat[0]=1.0;
+ pchan->quat[0]= 1.0f;
pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
}
@@ -685,69 +833,7 @@ static void execute_ipochannels(ListBase *lb)
}
}
-
-/* ************** time ****************** */
-
-static bActionStrip *get_active_strip(Object *ob)
-{
- bActionStrip *strip;
-
- if(ob->action==NULL)
- return NULL;
-
- for (strip=ob->nlastrips.first; strip; strip=strip->next)
- if(strip->flag & ACTSTRIP_ACTIVE)
- break;
-
- if(strip && strip->act==ob->action)
- return strip;
- return NULL;
-}
-
-/* non clipped mapping of strip */
-static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert)
-{
- float length, actlength, repeat;
-
- if (strip->flag & ACTSTRIP_USESTRIDE)
- repeat= 1.0f;
- else
- repeat= strip->repeat;
-
- length = strip->end-strip->start;
- if(length==0.0f)
- length= 1.0f;
- actlength = strip->actend-strip->actstart;
-
-
-
- if(invert)
- return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start;
- else
- return repeat*actlength*(cframe - strip->start)/length + strip->actstart;
-}
-
-/* if the conditions match, it converts current time to strip time */
-float get_action_frame(Object *ob, float cframe)
-{
- bActionStrip *strip= get_active_strip(ob);
-
- if(strip)
- return get_actionstrip_frame(strip, cframe, 0);
- return cframe;
-}
-
-/* inverted, strip time to current time */
-float get_action_frame_inv(Object *ob, float cframe)
-{
- bActionStrip *strip= get_active_strip(ob);
-
- if(strip)
- return get_actionstrip_frame(strip, cframe, 1);
- return cframe;
-}
-
-
+/* nla timing */
/* this now only used for repeating cycles, to enable fields and blur. */
/* the whole time control in blender needs serious thinking... */
@@ -840,6 +926,54 @@ static float stridechannel_frame(Object *ob, float sizecorr, bActionStrip *strip
return 0.0f;
}
+static void cyclic_offs_bone(Object *ob, bPose *pose, bActionStrip *strip, float time)
+{
+
+ if(time > 1.0f) {
+ bActionChannel *achan= get_action_channel(strip->act, strip->offs_bone);
+
+ if(achan && achan->ipo) {
+ IpoCurve *icu= NULL;
+ Bone *bone;
+ float min[3]={0.0f, 0.0f, 0.0f}, max[3]={0.0f, 0.0f, 0.0f};
+ int index=0, foundvert= 0;
+
+ /* calculate the min/max */
+ for (icu=achan->ipo->curve.first; icu; icu=icu->next) {
+ if(icu->totvert>1) {
+
+ if(icu->adrcode==AC_LOC_X)
+ index= 0;
+ else if(icu->adrcode==AC_LOC_Y)
+ index= 1;
+ else if(icu->adrcode==AC_LOC_Z)
+ index= 2;
+ else
+ continue;
+
+ foundvert= 1;
+ min[index]= icu->bezt[0].vec[1][1];
+ max[index]= icu->bezt[icu->totvert-1].vec[1][1];
+ }
+ }
+ if(foundvert) {
+ /* bring it into armature space */
+ VecSubf(min, max, min);
+ bone= get_named_bone(ob->data, strip->offs_bone); /* weak */
+ Mat4Mul3Vecfl(bone->arm_mat, min);
+
+ /* dominant motion, cyclic_offset was cleared in rest_pose */
+ if( fabs(min[0]) >= fabs(min[1]) && fabs(min[0]) >= fabs(min[2]))
+ pose->cyclic_offset[0]= time*min[0];
+ else if( fabs(min[1]) >= fabs(min[0]) && fabs(min[1]) >= fabs(min[2]))
+ pose->cyclic_offset[1]= time*min[1];
+ else
+ pose->cyclic_offset[2]= time*min[2];
+ }
+ }
+ }
+}
+
/* simple case for now; only the curve path with constraint value > 0.5 */
/* blending we might do later... */
static Object *get_parent_path(Object *ob)
@@ -917,7 +1051,7 @@ static void do_nla(Object *ob, int blocktype)
actlength = strip->actend-strip->actstart;
striptime = (scene_cfra-(strip->start)) / length;
stripframe = (scene_cfra-(strip->start)) ;
-
+
if (striptime>=0.0){
if(blocktype==ID_AR)
@@ -982,25 +1116,32 @@ static void do_nla(Object *ob, int blocktype)
/* Mod to repeat */
if(strip->repeat!=1.0f) {
- striptime*= strip->repeat;
- striptime = (float)fmod (striptime, 1.0f + 0.1f/length);
+ float cycle= striptime*strip->repeat;
+
+ striptime = (float)fmod (cycle, 1.0f + 0.1f/length);
+ cycle-= striptime;
+
+ if(blocktype==ID_AR)
+ cyclic_offs_bone(ob, tpose, strip, cycle);
}
frametime = (striptime * actlength) + strip->actstart;
frametime= nla_time(frametime, (float)strip->repeat);
- if(blocktype==ID_AR)
+ if(blocktype==ID_AR) {
extract_pose_from_action (tpose, strip->act, frametime);
+ }
else if(blocktype==ID_OB) {
extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime);
if(key)
extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime);
- }
+ }
+
doit=1;
}
}
/* Handle extend */
- else{
+ else {
if (strip->flag & ACTSTRIP_HOLDLASTFRAME){
/* we want the strip to hold on the exact fraction of the repeat value */
@@ -1015,6 +1156,13 @@ static void do_nla(Object *ob, int blocktype)
if(key)
extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime);
}
+
+ /* handle cycle hold */
+ if(strip->repeat!=1.0f) {
+ if(blocktype==ID_AR)
+ cyclic_offs_bone(ob, tpose, strip, strip->repeat-1.0f);
+ }
+
doit=1;
}
}
@@ -1033,6 +1181,9 @@ static void do_nla(Object *ob, int blocktype)
blendfac = 1;
if(blocktype==ID_AR) {/* Blend this pose with the accumulated pose */
+ /* offset bone, for matching cycles */
+ blend_pose_offset_bone (strip, ob->pose, tpose, blendfac, strip->mode);
+
blend_poses (ob->pose, tpose, blendfac, strip->mode);
if(dostride)
blend_pose_strides (ob->pose, tpose, blendfac, strip->mode);
@@ -1061,7 +1212,6 @@ static void do_nla(Object *ob, int blocktype)
}
if(chanbase.first)
BLI_freelistN(&chanbase);
-
}
void do_all_pose_actions(Object *ob)
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index aaa8e638ec9..fe703007e50 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -43,6 +43,7 @@
#include "DNA_mesh_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_nla_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
@@ -58,6 +59,7 @@
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_object.h"
@@ -1592,6 +1594,35 @@ static void do_local_constraint(bPoseChannel *pchan, bConstraint *con)
}
}
+static void do_strip_modifiers(Object *armob, Bone *bone, bPoseChannel *pchan)
+{
+ bActionModifier *amod;
+ bActionStrip *strip;
+ float scene_cfra= G.scene->r.cfra;
+
+ for (strip=armob->nlastrips.first; strip; strip=strip->next) {
+ if(scene_cfra>=strip->start && scene_cfra<=strip->end) {
+
+ for(amod= strip->modifiers.first; amod; amod= amod->next) {
+ if(amod->type==ACTSTRIP_MOD_DEFORM) {
+ /* validate first */
+ if(amod->ob && amod->ob->type==OB_CURVE && amod->channel[0]) {
+
+ if( strcmp(pchan->name, amod->channel)==0 ) {
+ float mat4[4][4], mat3[3][3];
+
+ curve_deform_vector(amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis);
+ Mat4CpyMat4(mat4, pchan->pose_mat);
+ Mat4MulMat34(pchan->pose_mat, mat3, mat4);
+
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
/* The main armature solver, does all constraints excluding IK */
/* pchan is validated, as having bone and parent pointer */
@@ -1657,9 +1688,13 @@ static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime)
else
Mat4MulSerie(pchan->pose_mat, parchan->pose_mat, offs_bone, pchan->chan_mat, NULL, NULL, NULL, NULL, NULL);
}
- else
+ else {
Mat4MulMat4(pchan->pose_mat, pchan->chan_mat, bone->arm_mat);
+ /* only rootbones get the cyclic offset */
+ VecAddf(pchan->pose_mat[3], pchan->pose_mat[3], ob->pose->cyclic_offset);
+ }
+ do_strip_modifiers(ob, bone, pchan);
/* Do constraints */
if(pchan->constraints.first) {
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 5847b913004..c65e9363274 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -389,7 +389,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int
}
}
- /* driver dependencies */
+ /* driver dependencies, nla modifiers */
if(ob->ipo)
dag_add_driver_relation(ob->ipo, dag, node, 0);
@@ -416,6 +416,15 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int
for (chan = strip->act->chanbase.first; chan; chan=chan->next)
if(chan->ipo)
dag_add_driver_relation(chan->ipo, dag, node, 1);
+ if(strip->modifiers.first) {
+ bActionModifier *amod;
+ for(amod= strip->modifiers.first; amod; amod= amod->next) {
+ if(amod->ob) {
+ node2 = dag_get_node(dag, amod->ob);
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+ }
+ }
+ }
}
}
if (ob->modifiers.first) {
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 3d8fd7d1311..d751169d115 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -450,19 +450,25 @@ void end_latt_deform()
*/
typedef struct {
float dmin[3], dmax[3], dsize, dloc[3];
- float curvespace[4][4], objectspace[4][4];
+ float curvespace[4][4], objectspace[4][4], objectspace3[3][3];
+ int no_rot_axis;
} CurveDeform;
-static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd)
+static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd, int dloc)
{
Mat4Invert(ob->imat, ob->obmat);
Mat4MulMat4(cd->objectspace, par->obmat, ob->imat);
Mat4Invert(cd->curvespace, cd->objectspace);
-
+ Mat3CpyMat4(cd->objectspace3, cd->objectspace);
+
// offset vector for 'no smear'
- Mat4Invert(par->imat, par->obmat);
- VecMat4MulVecfl(cd->dloc, par->imat, ob->obmat[3]);
-
+ if(dloc) {
+ Mat4Invert(par->imat, par->obmat);
+ VecMat4MulVecfl(cd->dloc, par->imat, ob->obmat[3]);
+ }
+ else cd->dloc[0]=cd->dloc[1]=cd->dloc[2]= 0.0f;
+
+ cd->no_rot_axis= 0;
}
/* this makes sure we can extend for non-cyclic. *vec needs 4 items! */
@@ -508,10 +514,12 @@ static int where_on_path_deform(Object *ob, float ctime, float *vec, float *dir)
/* for each point, rotate & translate to curve */
/* use path, since it has constant distances */
/* co: local coord, result local too */
-static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd)
+ /* returns quaternion for rotation, using cd->no_rot_axis */
+ /* axis is using another define!!! */
+static float *calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd)
{
Curve *cu= par->data;
- float fac, loc[4], dir[3], *quat, q[4], mat[3][3], cent[3];
+ float fac, loc[4], dir[3], cent[3];
short upflag, index;
if(axis==MOD_CURVE_POSX || axis==MOD_CURVE_NEGX) {
@@ -538,17 +546,33 @@ static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *c
/* to be sure, mostly after file load */
if(cu->path==NULL) {
makeDispListCurveTypes(par, 0);
- if(cu->path==NULL) return; // happens on append...
+ if(cu->path==NULL) return NULL; // happens on append...
}
+
/* options */
- if(cu->flag & CU_STRETCH)
- fac= (co[index]-cd->dmin[index])/(cd->dmax[index] - cd->dmin[index]);
- else
- fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist);
+ if(ELEM3(axis, OB_NEGX, OB_NEGY, OB_NEGZ)) {
+ if(cu->flag & CU_STRETCH)
+ fac= (-co[index]-cd->dmax[index])/(cd->dmax[index] - cd->dmin[index]);
+ else
+ fac= (cd->dloc[index])/(cu->path->totdist) - (co[index]-cd->dmax[index])/(cu->path->totdist);
+ }
+ else {
+ if(cu->flag & CU_STRETCH)
+ fac= (co[index]-cd->dmin[index])/(cd->dmax[index] - cd->dmin[index]);
+ else
+ fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist);
+ }
+
if( where_on_path_deform(par, fac, loc, dir)) { /* returns OK */
-
- quat= vectoquat(dir, axis-1, upflag); /* -1 for compatibility with old track defines */
+ float q[4], mat[3][3];
+ float *quat;
+
+ if(cd->no_rot_axis) /* set by caller */
+ dir[cd->no_rot_axis-1]= 0.0f;
+
+ /* -1 for compatibility with old track defines */
+ quat= vectoquat(dir, axis-1, upflag); /* gives static quat */
/* the tilt */
if(loc[3]!=0.0) {
@@ -568,8 +592,9 @@ static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *c
/* translation */
VECADD(co, cent, loc);
+ return quat;
}
-
+ return NULL;
}
void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis)
@@ -581,7 +606,7 @@ void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*v
cu->flag |= (CU_PATH|CU_FOLLOW); // needed for path & bevlist
- init_curve_deform(cuOb, target, &cd);
+ init_curve_deform(cuOb, target, &cd, (cu->flag & CU_STRETCH)==0);
/* check whether to use vertex groups (only possible if target is a Mesh)
* we want either a Mesh with no derived data, or derived data with
@@ -658,6 +683,36 @@ void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*v
cu->flag = flag;
}
+/* input vec and orco = local coord in armature space */
+/* orco is original not-animated or deformed reference point */
+/* result written in vec and mat */
+void curve_deform_vector(Object *cuOb, Object *target, float *orco, float *vec, float mat[][3], int no_rot_axis)
+{
+ CurveDeform cd;
+ float *quat;
+
+ init_curve_deform(cuOb, target, &cd, 0); /* 0 no dloc */
+ cd.no_rot_axis= no_rot_axis; /* option to only rotate for XY, for example */
+
+ VECCOPY(cd.dmin, orco);
+ VECCOPY(cd.dmax, orco);
+
+ Mat4MulVecfl(cd.curvespace, vec);
+
+ quat= calc_curve_deform(cuOb, vec, target->trackflag+1, &cd);
+ if(quat) {
+ float qmat[3][3];
+
+ QuatToMat3(quat, qmat);
+ Mat3MulMat3(mat, qmat, cd.objectspace3);
+ }
+ else
+ Mat3One(mat);
+
+ Mat4MulVecfl(cd.objectspace, vec);
+
+}
+
void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts, char *vgroup)
{
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index a8f1f2406f1..a348aef0399 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -74,6 +74,11 @@ void copy_actionstrip (bActionStrip **dst, bActionStrip **src){
if (dstrip->ipo)
dstrip->ipo->id.us++;
+
+ if (dstrip->modifiers.first) {
+ duplicatelist (&dstrip->modifiers, &sstrip->modifiers);
+ }
+
}
void copy_nlastrips (ListBase *dst, ListBase *src)
@@ -93,6 +98,11 @@ void copy_nlastrips (ListBase *dst, ListBase *src)
strip->act->id.us++;
if (strip->ipo)
strip->ipo->id.us++;
+ if (strip->modifiers.first) {
+ ListBase listb;
+ duplicatelist (&listb, &strip->modifiers);
+ strip->modifiers= listb;
+ }
}
}
@@ -139,7 +149,7 @@ bActionStrip *convert_action_to_strip (Object *ob)
}
-
+/* not strip itself! */
void free_actionstrip(bActionStrip* strip)
{
if (!strip)
@@ -153,6 +163,10 @@ void free_actionstrip(bActionStrip* strip)
strip->ipo->id.us--;
strip->ipo = NULL;
}
+ if (strip->modifiers.first) {
+ BLI_freelistN(&strip->modifiers);
+ }
+
}
void free_nlastrips (ListBase *nlalist)
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index fd0bd47430e..a7404fa8f51 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -333,6 +333,13 @@ void unlink_object(Object *ob)
for(strip= ob->nlastrips.first; strip; strip= strip->next) {
if(strip->object==ob)
strip->object= NULL;
+
+ if(strip->modifiers.first) {
+ bActionModifier *amod;
+ for(amod= strip->modifiers.first; amod; amod= amod->next)
+ if(amod->ob==ob)
+ amod->ob= NULL;
+ }
}
}
obt= obt->id.next;