Object tracking: object with object solver constraint is now parented to scene's camera
Made Object Solver operator parent object to scene's camera. Behavior is pretty much familiar to Child Of constraint -- it stores inverted transformation matrix which gives constant offset in parent's space. Current files would open incorrect, to make object aligned well again, just press "Set Inverse" button in Object Solver constraint. Fixed orientation operators so now they should work in all cases. Also changed behavior of Set Origin operator which now sets origin to the median point of all selected tracks/
This commit is contained in:
parent
deb95ddb44
commit
ba16e7d631
|
@ -784,6 +784,10 @@ class ConstraintButtonsPanel():
|
|||
|
||||
layout.prop(con, "object")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("constraint.objectsolver_set_inverse")
|
||||
row.operator("constraint.objectsolver_clear_inverse")
|
||||
|
||||
layout.operator("clip.constraint_to_fcurve")
|
||||
|
||||
def SCRIPT(self, context, layout, con):
|
||||
|
|
|
@ -825,7 +825,7 @@ static void childof_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *ta
|
|||
{
|
||||
bChildOfConstraint *data= con->data;
|
||||
bConstraintTarget *ct= targets->first;
|
||||
|
||||
|
||||
/* only evaluate if there is a target */
|
||||
if (VALID_CONS_TARGET(ct)) {
|
||||
float parmat[4][4];
|
||||
|
@ -4183,20 +4183,21 @@ static void objectsolver_evaluate (bConstraint *con, bConstraintOb *cob, ListBas
|
|||
object= BKE_tracking_named_object(tracking, data->object);
|
||||
|
||||
if(object) {
|
||||
float mat[4][4], obmat[4][4], imat[4][4], cammat[4][4], camimat[4][4];
|
||||
float mat[4][4], obmat[4][4], imat[4][4], cammat[4][4], camimat[4][4], parmat[4][4];
|
||||
|
||||
where_is_object_mat(scene, scene->camera, cammat);
|
||||
|
||||
BKE_tracking_get_interpolated_camera(tracking, object, scene->r.cfra, mat);
|
||||
|
||||
invert_m4_m4(camimat, cammat);
|
||||
mul_m4_m4m4(parmat, data->invmat, cammat);
|
||||
|
||||
copy_m4_m4(cammat, scene->camera->obmat);
|
||||
copy_m4_m4(obmat, cob->matrix);
|
||||
|
||||
invert_m4_m4(imat, mat);
|
||||
|
||||
mul_serie_m4(cob->matrix, cammat, imat, camimat, obmat, NULL, NULL, NULL, NULL);
|
||||
mul_serie_m4(cob->matrix, cammat, imat, camimat, parmat, obmat, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -195,8 +195,14 @@ void mul_m3_m3m3(float m1[][3], float m3_[][3], float m2_[][3])
|
|||
m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2];
|
||||
}
|
||||
|
||||
void mul_m4_m4m3(float (*m1)[4], float (*m3)[4], float (*m2)[3])
|
||||
void mul_m4_m4m3(float (*m1)[4], float (*m3_)[4], float (*m2_)[3])
|
||||
{
|
||||
float m2[3][3], m3[4][4];
|
||||
|
||||
/* copy so it works when m1 is the same pointer as m2 or m3 */
|
||||
copy_m3_m3(m2, m2_);
|
||||
copy_m4_m4(m3, m3_);
|
||||
|
||||
m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0];
|
||||
m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1];
|
||||
m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2];
|
||||
|
|
|
@ -12689,6 +12689,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
|
|||
/* put compatibility code here until next subversion bump */
|
||||
{
|
||||
MovieClip *clip;
|
||||
Object *ob;
|
||||
|
||||
for (clip= main->movieclip.first; clip; clip= clip->id.next) {
|
||||
MovieTracking *tracking= &clip->tracking;
|
||||
|
@ -12696,6 +12697,23 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
|
|||
if(tracking->objects.first == NULL)
|
||||
BKE_tracking_new_object(tracking, "Camera");
|
||||
}
|
||||
|
||||
for (ob= main->object.first; ob; ob= ob->id.next) {
|
||||
bConstraint *con;
|
||||
for (con= ob->constraints.first; con; con=con->next) {
|
||||
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
|
||||
|
||||
if(!cti)
|
||||
continue;
|
||||
|
||||
if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
|
||||
bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
|
||||
|
||||
if(data->invmat[3][3]==0.0f)
|
||||
unit_m4(data->invmat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
|
||||
|
|
|
@ -697,25 +697,13 @@ void CONSTRAINT_OT_limitdistance_reset (wmOperatorType *ot)
|
|||
|
||||
/* ------------- Child-Of Constraint ------------------ */
|
||||
|
||||
/* ChildOf Constraint - set inverse callback */
|
||||
static int childof_set_inverse_exec (bContext *C, wmOperator *op)
|
||||
static void child_get_inverse_matrix (Scene *scene, Object *ob, bConstraint *con, float invmat[4][4])
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
Object *ob = ED_object_active_context(C);
|
||||
bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF);
|
||||
bChildOfConstraint *data= (con) ? (bChildOfConstraint *)con->data : NULL;
|
||||
bConstraint *lastcon = NULL;
|
||||
bPoseChannel *pchan= NULL;
|
||||
|
||||
/* despite 3 layers of checks, we may still not be able to find a constraint */
|
||||
if (data == NULL) {
|
||||
printf("DEBUG: Child-Of Set Inverse - object = '%s'\n", (ob)? ob->id.name+2 : "<None>");
|
||||
BKE_report(op->reports, RPT_ERROR, "Couldn't find constraint data for Child-Of Set Inverse");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* nullify inverse matrix first */
|
||||
unit_m4(data->invmat);
|
||||
unit_m4(invmat);
|
||||
|
||||
/* try to find a pose channel - assume that this is the constraint owner */
|
||||
// TODO: get from context instead?
|
||||
|
@ -761,7 +749,7 @@ static int childof_set_inverse_exec (bContext *C, wmOperator *op)
|
|||
*/
|
||||
invert_m4_m4(imat, pchan->pose_mat);
|
||||
mul_m4_m4m4(tmat, imat, pmat);
|
||||
invert_m4_m4(data->invmat, tmat);
|
||||
invert_m4_m4(invmat, tmat);
|
||||
|
||||
/* 5. restore constraints */
|
||||
pchan->constraints.last = lastcon;
|
||||
|
@ -783,9 +771,27 @@ static int childof_set_inverse_exec (bContext *C, wmOperator *op)
|
|||
|
||||
/* use what_does_parent to find inverse - just like for normal parenting */
|
||||
what_does_parent(scene, ob, &workob);
|
||||
invert_m4_m4(data->invmat, workob.obmat);
|
||||
invert_m4_m4(invmat, workob.obmat);
|
||||
}
|
||||
}
|
||||
|
||||
/* ChildOf Constraint - set inverse callback */
|
||||
static int childof_set_inverse_exec (bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
Object *ob = ED_object_active_context(C);
|
||||
bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF);
|
||||
bChildOfConstraint *data= (con) ? (bChildOfConstraint *)con->data : NULL;
|
||||
|
||||
/* despite 3 layers of checks, we may still not be able to find a constraint */
|
||||
if (data == NULL) {
|
||||
printf("DEBUG: Child-Of Set Inverse - object = '%s'\n", (ob)? ob->id.name+2 : "<None>");
|
||||
BKE_report(op->reports, RPT_ERROR, "Couldn't find constraint data for Child-Of Set Inverse");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
child_get_inverse_matrix(scene, ob, con, data->invmat);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
|
@ -859,6 +865,96 @@ void CONSTRAINT_OT_childof_clear_inverse (wmOperatorType *ot)
|
|||
edit_constraint_properties(ot);
|
||||
}
|
||||
|
||||
/* ------------- Object Solver Constraint ------------------ */
|
||||
|
||||
static int objectsolver_set_inverse_exec (bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
Object *ob = ED_object_active_context(C);
|
||||
bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER);
|
||||
bObjectSolverConstraint *data= (con) ? (bObjectSolverConstraint *)con->data : NULL;
|
||||
|
||||
/* despite 3 layers of checks, we may still not be able to find a constraint */
|
||||
if (data == NULL) {
|
||||
printf("DEBUG: Child-Of Set Inverse - object = '%s'\n", (ob)? ob->id.name+2 : "<None>");
|
||||
BKE_report(op->reports, RPT_ERROR, "Couldn't find constraint data for Child-Of Set Inverse");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
child_get_inverse_matrix(scene, ob, con, data->invmat);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int objectsolver_set_inverse_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
|
||||
{
|
||||
if (edit_constraint_invoke_properties(C, op))
|
||||
return objectsolver_set_inverse_exec(C, op);
|
||||
else
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void CONSTRAINT_OT_objectsolver_set_inverse (wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Set Inverse";
|
||||
ot->idname= "CONSTRAINT_OT_objectsolver_set_inverse";
|
||||
ot->description= "Set inverse correction for ObjectSolver constraint";
|
||||
|
||||
ot->exec= objectsolver_set_inverse_exec;
|
||||
ot->invoke= objectsolver_set_inverse_invoke;
|
||||
ot->poll= edit_constraint_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
edit_constraint_properties(ot);
|
||||
}
|
||||
|
||||
static int objectsolver_clear_inverse_exec (bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = ED_object_active_context(C);
|
||||
bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER);
|
||||
bObjectSolverConstraint *data= (con) ? (bObjectSolverConstraint *)con->data : NULL;
|
||||
|
||||
if(data==NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Childof constraint not found");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* simply clear the matrix */
|
||||
unit_m4(data->invmat);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int objectsolver_clear_inverse_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
|
||||
{
|
||||
if (edit_constraint_invoke_properties(C, op))
|
||||
return objectsolver_clear_inverse_exec(C, op);
|
||||
else
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void CONSTRAINT_OT_objectsolver_clear_inverse (wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Clear Inverse";
|
||||
ot->idname= "CONSTRAINT_OT_objectsolver_clear_inverse";
|
||||
ot->description= "Clear inverse correction for ObjectSolver constraint";
|
||||
|
||||
ot->exec= objectsolver_clear_inverse_exec;
|
||||
ot->invoke= objectsolver_clear_inverse_invoke;
|
||||
ot->poll= edit_constraint_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
edit_constraint_properties(ot);
|
||||
}
|
||||
|
||||
/***************************** BUTTONS ****************************/
|
||||
|
||||
void ED_object_constraint_set_active(Object *ob, bConstraint *con)
|
||||
|
|
|
@ -185,6 +185,8 @@ void CONSTRAINT_OT_stretchto_reset(struct wmOperatorType *ot);
|
|||
void CONSTRAINT_OT_limitdistance_reset(struct wmOperatorType *ot);
|
||||
void CONSTRAINT_OT_childof_set_inverse(struct wmOperatorType *ot);
|
||||
void CONSTRAINT_OT_childof_clear_inverse(struct wmOperatorType *ot);
|
||||
void CONSTRAINT_OT_objectsolver_set_inverse(struct wmOperatorType *ot);
|
||||
void CONSTRAINT_OT_objectsolver_clear_inverse (struct wmOperatorType *ot);
|
||||
|
||||
/* object_vgroup.c */
|
||||
void OBJECT_OT_vertex_group_add(struct wmOperatorType *ot);
|
||||
|
|
|
@ -161,6 +161,8 @@ void ED_operatortypes_object(void)
|
|||
WM_operatortype_append(CONSTRAINT_OT_limitdistance_reset);
|
||||
WM_operatortype_append(CONSTRAINT_OT_childof_set_inverse);
|
||||
WM_operatortype_append(CONSTRAINT_OT_childof_clear_inverse);
|
||||
WM_operatortype_append(CONSTRAINT_OT_objectsolver_set_inverse);
|
||||
WM_operatortype_append(CONSTRAINT_OT_objectsolver_clear_inverse);
|
||||
|
||||
WM_operatortype_append(OBJECT_OT_vertex_group_add);
|
||||
WM_operatortype_append(OBJECT_OT_vertex_group_remove);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_movieclip_types.h"
|
||||
#include "DNA_object_types.h" /* SELECT */
|
||||
|
@ -45,6 +46,7 @@
|
|||
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_movieclip.h"
|
||||
#include "BKE_tracking.h"
|
||||
#include "BKE_global.h"
|
||||
|
@ -1938,6 +1940,29 @@ static int count_selected_bundles(bContext *C)
|
|||
return tot;
|
||||
}
|
||||
|
||||
static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4])
|
||||
{
|
||||
Object *cam= scene->camera;
|
||||
bConstraint *con;
|
||||
|
||||
where_is_object_mat(scene, cam, invmat);
|
||||
|
||||
for (con= ob->constraints.first; con; con=con->next) {
|
||||
bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
|
||||
|
||||
if(!cti)
|
||||
continue;
|
||||
|
||||
if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
|
||||
bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
|
||||
|
||||
mul_m4_m4m4(invmat, data->invmat, invmat);
|
||||
}
|
||||
}
|
||||
|
||||
invert_m4(invmat);
|
||||
}
|
||||
|
||||
static int set_origin_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
SpaceClip *sc= CTX_wm_space_clip(C);
|
||||
|
@ -1948,10 +1973,11 @@ static int set_origin_exec(bContext *C, wmOperator *op)
|
|||
Scene *scene= CTX_data_scene(C);
|
||||
Object *object;
|
||||
ListBase *tracksbase;
|
||||
float mat[4][4], vec[3];
|
||||
float mat[4][4], vec[3], median[3];
|
||||
int selected_count= count_selected_bundles(C);
|
||||
|
||||
if(count_selected_bundles(C)!=1) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define origin position");
|
||||
if(selected_count==0) {
|
||||
BKE_report(op->reports, RPT_ERROR, "At least one track with bundle should be selected to define origin position");
|
||||
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
@ -1969,21 +1995,28 @@ static int set_origin_exec(bContext *C, wmOperator *op)
|
|||
tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
|
||||
|
||||
track= tracksbase->first;
|
||||
zero_v3(median);
|
||||
while(track) {
|
||||
if(TRACK_VIEW_SELECTED(sc, track))
|
||||
break;
|
||||
if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE)) {
|
||||
add_v3_v3(median, track->bundle_pos);
|
||||
}
|
||||
|
||||
track= track->next;
|
||||
}
|
||||
mul_v3_fl(median, 1.0f/selected_count);
|
||||
|
||||
BKE_get_tracking_mat(scene, NULL, mat);
|
||||
|
||||
mul_v3_m4v3(vec, mat, track->bundle_pos);
|
||||
mul_v3_m4v3(vec, mat, median);
|
||||
|
||||
if(tracking_object->flag&TRACKING_OBJECT_CAMERA)
|
||||
if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
|
||||
sub_v3_v3(object->loc, vec);
|
||||
else
|
||||
}
|
||||
else {
|
||||
object_solver_inverted_matrix(scene, object, mat);
|
||||
mul_v3_m4v3(vec, mat, vec);
|
||||
copy_v3_v3(object->loc, vec);
|
||||
}
|
||||
|
||||
DAG_id_tag_update(&clip->id, 0);
|
||||
DAG_id_tag_update(&object->id, OB_RECALC_OB);
|
||||
|
@ -2007,6 +2040,9 @@ void CLIP_OT_set_origin(wmOperatorType *ot)
|
|||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
RNA_def_boolean(ot->srna, "use_median", 0, "Use Median", "Set origin to median point of selected bundles");
|
||||
}
|
||||
|
||||
/********************** set floor operator *********************/
|
||||
|
@ -2027,6 +2063,9 @@ static void set_axis(Scene *scene, Object *ob, MovieTrackingObject *tracking_ob
|
|||
if(!is_camera) {
|
||||
float imat[4][4];
|
||||
|
||||
object_solver_inverted_matrix(scene, ob, imat);
|
||||
mul_v3_m4v3(vec, imat, vec);
|
||||
|
||||
invert_m4_m4(imat, obmat);
|
||||
mul_v3_m4v3(dvec, imat, vec);
|
||||
|
||||
|
@ -2094,23 +2133,22 @@ static void set_axis(Scene *scene, Object *ob, MovieTrackingObject *tracking_ob
|
|||
mul_m4_m4m4(mat, obmat, mat);
|
||||
}
|
||||
else {
|
||||
float lmat[4][4], ilmat[4][4], m[4][4];
|
||||
|
||||
unit_m4(lmat);
|
||||
copy_v3_v3(lmat[3], obmat[3]);
|
||||
invert_m4_m4(ilmat, lmat);
|
||||
|
||||
if(!flip) {
|
||||
float rmat[3][3], tmat[4][4];
|
||||
float lmat[4][4], ilmat[4][4], rmat[3][3];
|
||||
|
||||
object_rot_to_mat3(ob, rmat);
|
||||
copy_m4_m3(tmat, rmat);
|
||||
invert_m4(tmat);
|
||||
invert_m3(rmat);
|
||||
mul_m4_m4m3(mat, mat, rmat);
|
||||
|
||||
mul_m4_m4m4(mat, mat, tmat);
|
||||
unit_m4(lmat);
|
||||
copy_v3_v3(lmat[3], obmat[3]);
|
||||
invert_m4_m4(ilmat, lmat);
|
||||
|
||||
mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
mul_m4_m4m4(mat, mat, obmat);
|
||||
}
|
||||
|
||||
mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
object_apply_mat4(ob, mat, 0, 0);
|
||||
|
|
|
@ -6820,7 +6820,20 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
|
|||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
if ((curcon->flag & CONSTRAINT_EXPAND) && (cti) && (cti->get_constraint_targets)) {
|
||||
if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
|
||||
/* special case for object solver constraint because it doesn't fill
|
||||
constraint targets properly (design limitation -- scene is needed for
|
||||
it's target but it can't be accessed from get_targets callvack) */
|
||||
if(scene->camera) {
|
||||
setlinestyle(3);
|
||||
glBegin(GL_LINES);
|
||||
glVertex3fv(scene->camera->obmat[3]);
|
||||
glVertex3fv(ob->obmat[3]);
|
||||
glEnd();
|
||||
setlinestyle(0);
|
||||
}
|
||||
}
|
||||
else if ((curcon->flag & CONSTRAINT_EXPAND) && (cti) && (cti->get_constraint_targets)) {
|
||||
cti->get_constraint_targets(curcon, &targets);
|
||||
|
||||
for (ct= targets.first; ct; ct= ct->next) {
|
||||
|
|
|
@ -4196,6 +4196,7 @@ static short constraints_list_needinv(TransInfo *t, ListBase *list)
|
|||
if (con->type == CONSTRAINT_TYPE_CHILDOF) return 1;
|
||||
if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) return 1;
|
||||
if (con->type == CONSTRAINT_TYPE_CLAMPTO) return 1;
|
||||
if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) return 1;
|
||||
|
||||
/* constraints that require this only under special conditions */
|
||||
if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
|
||||
|
|
|
@ -426,6 +426,7 @@ typedef struct bObjectSolverConstraint {
|
|||
struct MovieClip *clip;
|
||||
int flag, pad;
|
||||
char object[24];
|
||||
float invmat[4][4]; /* parent-inverse matrix to use */
|
||||
} bObjectSolverConstraint;
|
||||
|
||||
/* ------------------------------------------ */
|
||||
|
|
Loading…
Reference in New Issue