1
1

Compare commits

...

40 Commits

Author SHA1 Message Date
b2e596a7cd Bendy Bones: Cleaning up version patching for latest version 2016-05-18 02:30:14 +12:00
fd95b6f82e Bendy Bones: Fix for Clear Rotation/Scale not affecting the Bendy Bone settings
* These operators were still clearing the pchan->bone (i.e. restpose values) instead
  of the pchan values, which may have messed things up quite a bit.
* I've also now included the curve x/y stuff in rotation. While the transform being
  applied to the handles is more like translation, the effect is actually closer
  to rotation of the bone segments. So, on balance, let's try it this way.
2016-05-18 02:29:06 +12:00
d7331aa217 Bendy Bones: Tweak UI for custom reference bones to be tider 2016-05-18 02:29:05 +12:00
c0615ac687 Bendy Bones: Code Cleanup - Use const for all these intermediate values too 2016-05-18 02:29:04 +12:00
821828e812 Bendy Bones: Option to treat disconnected bbone start/end reference locations as relative
This is an experimental option for use with the previous commit. It's an attempt
at making these bone references more useful when there's a big gap between the
reference bone being used, and the bone it's controlling.
2016-05-18 02:29:04 +12:00
12a7eb69c7 Bendy Bones: Added ability to add custom reference prev/next bones for controlling handles
This is an experimental option which makes it possible to specify which bone
to use as the reference handle for the previous/next bones, instead of only
using those that are directly connected on either end.

To use:
* Enable the "Use Custom Handle References" option in the Bendy Bones panel
* Set Start and/or End bones accordingly. If both are left blank, then the BBone
  will only respond to whatever offsets have been set by the animator
* Be careful when positioning the start/end bones! It will use the bone position
  as the point at which the handle currently sits - best results seem be when these
  bones are in line with the bbone to start with.

Why (according to @jpbouza):
When you have a very long chain of bbones, as they are all parented, when you rotate
the first bone in the chain (Y rotation, like twisting the chain), all the child
bones rotate. So the only way to avoid this is to add a copy rotation constraint to
each bone in the chain in order to override their parent rotation, thus achieving
control over twisting of each segment of the chain.

This commit makes it possible to have a bone (that is not a parent or child of the bone
being affected) to influence the bbone curvature as if they were.
2016-05-18 02:29:03 +12:00
f480973654 Bendy Bones: RNA Cleanup - Naming, tooltips, ranges
* Improved naming of BBone properties to be less clunky

* Rewrote all the tooltips to be more descriptive about what they do
  (and hopefully, to give an idea of how they can be used)

* Improved the ranges on all the properties
  - Curve X/Y now has a range of +/- 5 (vs +/- 2 before)
  - Scale In/Out now has a range of 0-5 (vs 0-2 before)

  The extra flexibility doesn't seem to lead to any ill effects; instead,
  at least in my tests so far, they instead give more leeway for creative
  posing.

* Set defaults for the scale properties (1.0)
2016-05-18 02:29:02 +12:00
d96c69259f Bendy Bones: Fix for "flattening out" glitch when scaling up the bone
The fix here is to apply a scaling correction to the offsets we're applying
if the do_scale flag gets set. For whatever reason (I'm guessing floating point
precision errors), when the scale factor gets to around 8.15/8.16, there's a bit
more of a difference between x/y or y/z scale factors, leading to everything
needing to get scaled up 8 times (i.e. the bone length for the calculations is
8.16 not 1.0 as per usual). If we don't scale the offsets being applied to
compensate for this, the effect of the offsets will be less (i.e. the handles move
less), hence the bbone flattening out.
2016-05-18 02:29:02 +12:00
21d8ff3229 Bendy Bones: Adding a bit of documentation to the code to show what's happening 2016-05-18 02:29:01 +12:00
38ac8a9551 Bendy Bones: Fix for "double transform" caused by bendy bone values being set in editmode
The restpose/editmode values should still be applied during "rest",
so that their effects will not be factored into the final "deform"
that gets applied via the bones. However, we still need to have
these restpose values applied at some point to the bones, so that
in the viewport we get the offset values on top of the base.
2016-05-18 02:29:01 +12:00
e7407b0f09 Bendy Bones: Keying Set support
* Added a "BBone Shape" Keying Set to make it easier to key all these properties at once
* Made "Whole Character" Keying Set aware of these properties
2016-05-18 02:29:00 +12:00
b288b55087 Bendy Bones: Breakdowner + Pose Slide tools support for these properties
The Breakdowner and Pose Sliding tools (Push/Relax) now have support for the
bbone properties too, making it possible to use these tools for playing with
them like another other part of the pose.

Implementation Note:
I've ended up reusing a bunch of flags which we don't use, and haven't used
for at least a decade (and which were if 0'd out). When they were in use,
they would have been for runtime purposes anyway. Just to be safe, the version
patch in modern Blender will clear out all those flags so that we can use them.
2016-05-18 02:28:59 +12:00
79673ef3e2 Bendy Bones: Code Cleanup/Scaling Fix
* Changed num_segments from n - 1 to just n. Previously, it ended up just looking
  odd, as everything would change, up till but not including the last one, when
  playing with the "scale in" setting.

* Removed the before calculating scaleFactorIn/Out - these were always true!
2016-05-18 02:28:59 +12:00
1e0eac56d7 Bendy Bones: Code Cleanup - More steps to simplify + clarify the scaling code 2016-05-18 02:28:58 +12:00
d7926e9893 Bendy Bones: Code Cleanup - Simplify float conversions here to be easier to follow 2016-05-18 02:28:57 +12:00
e36402ecff Bendy Bones: Fix behaviour of scale in/out in editmode preview too 2016-05-18 02:28:57 +12:00
a34eb614e9 Bendy Bones: Remove all the remaining BBone options from the Deform panel
These are no longer deform-only, as a non-deform bone could be used for
controlling constraints.
2016-05-18 02:28:56 +12:00
b69196da5e Bendy Bones: Copy/Paste pose now copies these settings over to
Copying poses now copies the bendy bone settings (posebone not bone ones).
By and large this should work fine now, though the behaviour for "paste flipped"
might need further checking.
2016-05-18 02:28:55 +12:00
650cdf6c36 Bendy Bones: Tweak to try and get rid of shearing issues when scaling bones
Looks like we shouldn't be applying the inverse matrix here...
2016-05-18 02:28:55 +12:00
f1515ce051 Constraints: BBones Head/Tail Interpolation is now optional
To preserve backwards compat with old rigs, the behaviour to use the BBone
shape when interpolating Head/Tail values will now only be performed when
the "curve" toggle beside the head/tail slider is enabled.

TODO: Make this toggle only show up when the target is actually a bbone
2016-05-18 02:28:54 +12:00
808bfc86ce Fix for Constraints Head/Tail on BBones
Last segment needs special handling, as the values there are a little wonky...
2016-05-18 02:28:53 +12:00
4e70ec8fdd Constraints: Head/Tail interpolation follows bbone shape, instead of doing straight-line interpolation
This can be used to reduce the complexity of rigs, by reducing the number of extra bones
that may have otherwise been needed to accomplish a similar effect.
2016-05-18 02:28:52 +12:00
c54e28aba1 Bendy Bones: Fix - Scale In/Out not being initialised for new pose bones 2016-05-18 02:28:51 +12:00
3a6cc8105c Bendy Bones: Tweaks to UI layout for Bendy Bones panel
* Disable all properties if no segments
* Better labels and spacing of items
* Changed order of things to have a better layout
* Moved "inherit endroll" option into this panel too
2016-05-18 02:28:51 +12:00
418ca5ab67 Bendy Bones: Code Cleanup - Expose equalize_bezier() as equalize_bbone_bezier() 2016-05-18 02:28:50 +12:00
ed376e3595 Bendy Bones: Curved Bone settings in EditMode act as "Rest Pose" (Experimental)
The bendy bone settings (curve in/out, etc.) now exist on both Bone and PoseBone
levels. What this means is that the "Bone" level settings (i.e. what we had before)
are used for defining the rest pose curve for the bone (i.e. to fit things like
curved eyebrows, and so forth), while the "PoseBone" level settings (i.e. new stuff)
will be what animators play with to animate their characters.


Implementation Notes:
* All the BBone settings are now found in a new "Curved Bones" panel. This is located
  just below the Transform properties panels (instead of by "Deform"), so that it's
  easier to reach for animating.

  The segments and ease in+out settings are still also located in the "Deform" panel.
  I'm still unsure whether to remove them for good from there. For now, I've duplicated
  them, to be more convenient for animation tweaking (though it might also be a bit
  confusing)

* Ease In/Out is still a bone-level setting only (i.e. no posemode offsets/override).
  This may be subject to change still, but more investigation will be needed first.

* Scale In/Out is handled multiplicatively. That is,
  scaleIn_final = bone->scaleIn * pbone->scaleIn

* I've added a hacky "stripped down" copy of b_bone_spline_setup() for drawing
  the editmode previews of these bbone settings. Whether this is the final approach
  used is still open to debate. Better suggestions welcome, though this seems to be
  the simplest (least overhead) solution currently.
2016-05-18 02:28:50 +12:00
e62aab8981 Bendy Bones: Fix tooltip for "Inherit End Roll" to be a bit more descriptive 2016-05-18 02:28:49 +12:00
0d07ee84fb Bendy Bones: Restore bone->ease1/2 for hlength1/2 calcs
It turns out that this wasn't changed in the patch after all...
2016-05-18 02:28:48 +12:00
980c7af04a Bendy Bones: Fix for crash when enabling "Inherit EndRoll" 2016-05-18 02:28:48 +12:00
4e90c52213 Bendy Bones: Code Cleanup - Remove all the unnecessary prints + debug code leftover 2016-05-18 02:28:47 +12:00
5ed997d7b4 Bendy Bones: At last, it works!
I've gone through making a bunch of changes (mostly, just reverting quite a few
things back to their pre-patch state, and adding in a few other bits), and it
finally looks like it actually works for both BlenRig and the test files. Yay!

(Things are still quite messy, with a lot of commented out leftovers and stuff
to deal with, which I'll clean up in a moment after verifying that it all actually
works for real)
2016-05-18 02:28:46 +12:00
c0e7b67243 BendyBones WIP - Temporarily knocked out change to the matrix multiplication final step
If we use the old formula (currently enabled), old rigs work, but new options don't.

However, if we use the new one (without tmat == inverse mats[0]), old rigs
(blenrig) breaks, while the new options don't really work that great.
2016-05-18 02:28:46 +12:00
6d439b878a BendyBones - Note about potential cause of segment length + blenrig bugs 2016-05-18 02:28:45 +12:00
9eb8efe56a Code Cleanup - Remove some more leftover gunk 2016-05-18 02:28:45 +12:00
7fbe91e300 Version patching fixes for the new bbone settings 2016-05-18 02:28:44 +12:00
70c9af3b38 Code Cleanup: Removed some obsolete code that seems to be left over from previous experiments 2016-05-18 02:27:27 +12:00
8524aab99b Code Cleanup - More style cleanups and removing unneeded extra steps 2016-05-18 02:27:26 +12:00
96e6d12c53 UI Tweak: Rename labels to be easier to read with typical panel widths 2016-05-18 02:27:25 +12:00
acd85889e2 Code Cleanup
* Roll angles should be stored in radians, and displayed using the appropriate
  RNA type instead
* Some general code cleanup work (style, avoid type conversions, etc.)
2016-05-18 02:27:25 +12:00
d8ef9ec1a8 Initial patch for improved bendy bones
Author: Jose Molina
Idea: Daniel M Lara (pepeland)
2016-05-18 02:27:24 +12:00
27 changed files with 829 additions and 117 deletions

View File

@@ -28,11 +28,14 @@ __all__ = (
"RKS_POLL_selected_objects",
"RKS_POLL_selected_bones",
"RKS_POLL_selected_items",
"RKS_ITER_selected_object",
"RKS_ITER_selected_bones",
"RKS_ITER_selected_item",
"RKS_GEN_available",
"RKS_GEN_location",
"RKS_GEN_rotation",
"RKS_GEN_scaling",
"RKS_GEN_bendy_bones",
)
import bpy
@@ -93,11 +96,17 @@ def RKS_ITER_selected_item(ksi, context, ks):
ksi.generate(context, ks, ob)
# all select objects only
# all selected objects only
def RKS_ITER_selected_objects(ksi, context, ks):
for ob in context.selected_objects:
ksi.generate(context, ks, ob)
# all seelcted bones only
def RKS_ITER_selected_bones(ksi, context, ks):
for bone in context.selected_pose_bones:
ksi.generate(context, ks, bone)
###########################
# Generate Callbacks
@@ -207,3 +216,43 @@ def RKS_GEN_scaling(ksi, context, ks, data):
ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
else:
ks.paths.add(id_block, path)
# ------
# Property identifiers for Bendy Bones
bbone_property_ids = (
"bbone_curveinx",
"bbone_curveiny",
"bbone_curveoutx",
"bbone_curveouty",
"bbone_rollin",
"bbone_rollout",
"bbone_scalein",
"bbone_scaleout",
# NOTE: These are in the nested bone struct
# Do it this way to force them to be included
# in whatever actions are being keyed here
"bone.bbone_in",
"bone.bbone_out",
)
# Add Keying Set entries for bendy bones
def RKS_GEN_bendy_bones(ksi, context, ks, data):
# get id-block and path info
# NOTE: This assumes that we're dealing with a bone here...
id_block, base_path, grouping = get_transform_generators_base_info(data)
# for each of the bendy bone properties, add a Keying Set entry for it...
for propname in bbone_property_ids:
# add the property name to the base path
path = path_add_property(base_path, propname)
# add Keying Set entry for this...
if grouping:
ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
else:
ks.paths.add(id_block, path)

View File

@@ -65,9 +65,10 @@ class ConstraintButtonsPanel:
layout.prop_search(con, "subtarget", con.target.data, "bones", text="Bone")
if hasattr(con, "head_tail"):
row = layout.row()
row = layout.row(align=True)
row.label(text="Head/Tail:")
row.prop(con, "head_tail", text="")
row.prop(con, "use_bbone_shape", text="", icon='IPO_BEZIER') # XXX icon, and only when bone has segments?
elif con.target.type in {'MESH', 'LATTICE'}:
layout.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")

View File

@@ -146,6 +146,81 @@ class BONE_PT_transform_locks(BoneButtonsPanel, Panel):
sub.prop(pchan, "lock_rotation_w", text="W")
class BONE_PT_curved(BoneButtonsPanel, Panel):
bl_label = "Bendy Bones"
#bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
ob = context.object
bone = context.bone
arm = context.armature
pchan = None
if ob and bone:
pchan = ob.pose.bones[bone.name]
bbone = pchan
elif bone is None:
bone = context.edit_bone
bbone = bone
else:
bbone = bone
layout = self.layout
layout.prop(bone, "bbone_segments", text="Segments")
col = layout.column()
col.active = bone.bbone_segments > 1
row = col.row()
sub = row.column(align=True)
sub.label(text="Curve XY Offsets:")
sub.prop(bbone, "bbone_curveinx", text="In X")
sub.prop(bbone, "bbone_curveiny", text="In Y")
sub.prop(bbone, "bbone_curveoutx", text="Out X")
sub.prop(bbone, "bbone_curveouty", text="Out Y")
sub = row.column(align=True)
sub.label("Roll:")
sub.prop(bbone, "bbone_rollin", text="In")
sub.prop(bbone, "bbone_rollout", text="Out")
sub.prop(bone, "use_endroll_as_inroll")
row = col.row()
sub = row.column(align=True)
sub.label(text="Scale:")
sub.prop(bbone, "bbone_scalein", text="Scale In")
sub.prop(bbone, "bbone_scaleout", text="Scale Out")
sub = row.column(align=True)
sub.label("Easing:")
if pchan:
# XXX: have these also be an overlay?
sub.prop(bbone.bone, "bbone_in", text="Ease In")
sub.prop(bbone.bone, "bbone_out", text="Ease Out")
else:
sub.prop(bone, "bbone_in", text="Ease In")
sub.prop(bone, "bbone_out", text="Ease Out")
if pchan:
layout.separator()
col = layout.column()
col.prop(pchan, "use_bbone_custom_handles")
row = col.row()
row.active = pchan.use_bbone_custom_handles
sub = row.column(align=True)
sub.label(text="In:")
sub.prop_search(pchan, "bbone_custom_handle_start", ob.pose, "bones", text="")
sub.prop(pchan, "use_bbone_relative_start_handle", text="Relative")
sub = row.column(align=True)
sub.label(text="Out:")
sub.prop_search(pchan, "bbone_custom_handle_end", ob.pose, "bones", text="")
sub.prop(pchan, "use_bbone_relative_end_handle", text="Relative")
class BONE_PT_relations(BoneButtonsPanel, Panel):
bl_label = "Relations"
@@ -193,6 +268,7 @@ class BONE_PT_relations(BoneButtonsPanel, Panel):
sub.prop(bone, "use_local_location")
class BONE_PT_display(BoneButtonsPanel, Panel):
bl_label = "Display"
@@ -348,28 +424,18 @@ class BONE_PT_deform(BoneButtonsPanel, Panel):
layout.active = bone.use_deform
split = layout.split()
row = layout.row()
col = split.column()
col = row.column(align=True)
col.label(text="Envelope:")
sub = col.column(align=True)
sub.prop(bone, "envelope_distance", text="Distance")
sub.prop(bone, "envelope_weight", text="Weight")
col.prop(bone, "envelope_distance", text="Distance")
col.prop(bone, "envelope_weight", text="Weight")
col.prop(bone, "use_envelope_multiply", text="Multiply")
sub = col.column(align=True)
sub.label(text="Radius:")
sub.prop(bone, "head_radius", text="Head")
sub.prop(bone, "tail_radius", text="Tail")
col = split.column()
col.label(text="Curved Bones:")
sub = col.column(align=True)
sub.prop(bone, "bbone_segments", text="Segments")
sub.prop(bone, "bbone_in", text="Ease In")
sub.prop(bone, "bbone_out", text="Ease Out")
col = row.column(align=True)
col.label(text="Envelope Radius:")
col.prop(bone, "head_radius", text="Head")
col.prop(bone, "tail_radius", text="Tail")
class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, Panel):

View File

@@ -175,6 +175,22 @@ class BUILTIN_KSI_RotScale(KeyingSetInfo):
# ------------
# Bendy Bones
class BUILTIN_KSI_BendyBones(KeyingSetInfo):
"""Insert a keyframe for each of the BBone shape properties"""
bl_label = "BBone Shape"
# poll - use callback for selected bones
poll = keyingsets_utils.RKS_POLL_selected_bones
# iterator - use callback for selected bones
iterator = keyingsets_utils.RKS_ITER_selected_bones
# generator - use generator for bendy bone properties
generate = keyingsets_utils.RKS_GEN_bendy_bones
# ------------
# VisualLocation
class BUILTIN_KSI_VisualLoc(KeyingSetInfo):
@@ -387,6 +403,9 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
ksi.doRot3d(ks, bone)
ksi.doScale(ks, bone)
# bbone properties?
ksi.doBBone(context, ks, bone)
# custom props?
ksi.doCustomProps(ks, bone)
@@ -466,6 +485,19 @@ class BUILTIN_KSI_WholeCharacter(KeyingSetInfo):
# ----------------
# bendy bone properties
def doBBone(ksi, context, ks, pchan):
bone = pchan.bone
# This check is crude, but is the best we can do for now
# It simply adds all of these if the bbone has segments
# (and the bone is a control bone). This may lead to some
# false positives...
if bone.bbone_segments > 1:
keyingsets_utils.RKS_GEN_bendy_bones(ksi, context, ks, pchan)
# ----------------
# custom properties
def doCustomProps(ksi, ks, bone):

View File

@@ -79,12 +79,15 @@ typedef enum eAction_TransformFlags {
ACT_TRANS_ROT = (1 << 1),
/* scaling */
ACT_TRANS_SCALE = (1 << 2),
/* bbone shape - for all the parameters, provided one is set */
ACT_TRANS_BBONE = (1 << 3),
/* strictly not a transform, but custom properties are also
* quite often used in modern rigs
*/
ACT_TRANS_PROP = (1 << 3),
ACT_TRANS_PROP = (1 << 4),
/* all flags */
ACT_TRANS_ONLY = (ACT_TRANS_LOC | ACT_TRANS_ROT | ACT_TRANS_SCALE),
ACT_TRANS_ALL = (ACT_TRANS_ONLY | ACT_TRANS_PROP)

View File

@@ -135,6 +135,7 @@ typedef struct Mat4 {
float mat[4][4];
} Mat4;
void equalize_bbone_bezier(float *data, int desired);
void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]);
/* like EBONE_VISIBLE */

View File

@@ -493,6 +493,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
unit_axis_angle(chan->rotAxis, &chan->rotAngle);
chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
chan->scaleIn = chan->scaleOut = 1.0f;
chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -180.0f;
chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = 180.0f;
chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
@@ -1280,6 +1282,18 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
}
}
if ((curves) || (flags & ACT_TRANS_BBONE) == 0) {
/* bbone shape properties */
pPtr = strstr(bPtr, "bbone_");
if (pPtr) {
flags |= ACT_TRANS_BBONE;
if (curves)
BLI_addtail(curves, BLI_genericNodeN(fcu));
continue;
}
}
if ((curves) || (flags & ACT_TRANS_PROP) == 0) {
/* custom properties only */
pPtr = strstr(bPtr, "[\""); /* extra '"' comment here to keep my texteditor functionlist working :) */

View File

@@ -429,7 +429,7 @@ int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short a
/* ************* B-Bone support ******************* */
/* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */
static void equalize_bezier(float *data, int desired)
void equalize_bbone_bezier(float *data, int desired)
{
float *fp, totdist, ddist, dist, fac1, fac2;
float pdist[MAX_BBONE_SUBDIV + 1];
@@ -499,13 +499,21 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
hlength1 = bone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
hlength2 = bone->ease2 * length * 0.390464f;
/* evaluate next and prev bones */
if (bone->flag & BONE_CONNECTED)
prev = pchan->parent;
else
prev = NULL;
/* get "next" and "prev" bones - these are used for handle calculations */
if (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) {
/* use the provided bones as the next/prev - leave blank to eliminate this effect altogether */
prev = pchan->bbone_prev;
next = pchan->bbone_next;
}
else {
/* evaluate next and prev bones */
if (bone->flag & BONE_CONNECTED)
prev = pchan->parent;
else
prev = NULL;
next = pchan->child;
next = pchan->child;
}
/* find the handle points, since this is inside bone space, the
* first point = (0, 0, 0)
@@ -525,10 +533,27 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
float difmat[4][4], result[3][3], imat3[3][3];
/* transform previous point inside this bone space */
if (rest)
copy_v3_v3(h1, prev->bone->arm_head);
else
copy_v3_v3(h1, prev->pose_head);
if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
(pchan->bboneflag & PCHAN_BBONE_CUSTOM_START_REL))
{
/* Use delta movement (from restpose), and apply this relative to the current bone's head */
if (rest) {
/* in restpose, arm_head == pose_head */
h1[0] = h1[1] = h1[2] = 0.0f;
}
else {
float delta[3];
sub_v3_v3v3(delta, prev->pose_head, prev->bone->arm_head);
sub_v3_v3v3(h1, pchan->pose_head, delta);
}
}
else {
/* Use bone head as absolute position */
if (rest)
copy_v3_v3(h1, prev->bone->arm_head);
else
copy_v3_v3(h1, prev->pose_head);
}
mul_m4_v3(imat, h1);
if (prev->bone->segments > 1) {
@@ -564,10 +589,27 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
float difmat[4][4], result[3][3], imat3[3][3];
/* transform next point inside this bone space */
if (rest)
copy_v3_v3(h2, next->bone->arm_tail);
else
copy_v3_v3(h2, next->pose_tail);
if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
(pchan->bboneflag & PCHAN_BBONE_CUSTOM_END_REL))
{
/* Use delta movement (from restpose), and apply this relative to the current bone's tail */
if (rest) {
/* in restpose, arm_tail == pose_tail */
h2[0] = h2[1] = h2[2] = 0.0f;
}
else {
float delta[3];
sub_v3_v3v3(delta, next->pose_tail, next->bone->arm_tail);
add_v3_v3v3(h2, pchan->pose_tail, delta);
}
}
else {
/* Use bone tail as absolute position */
if (rest)
copy_v3_v3(h2, next->bone->arm_tail);
else
copy_v3_v3(h2, next->pose_tail);
}
mul_m4_v3(imat, h2);
/* if next bone is B-bone too, use average handle direction */
@@ -601,6 +643,50 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
roll2 = 0.0;
}
/* Add effects from bbone properties over the top
* - These properties allow users to hand-animate the
* bone curve/shape, without having to resort to using
* extra bones
* - The "bone" level offsets are for defining the restpose
* shape of the bone (e.g. for curved eyebrows for example).
* -> In the viewport, it's needed to define what the rest pose
* looks like
* -> For "rest == 0", we also still need to have it present
* so that we can "cancel out" this restpose when it comes
* time to deform some geometry, it won't cause double transforms.
* - The "pchan" level offsets are the ones that animators actually
* end up animating
*/
{
/* add extra rolls */
roll1 += bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
roll2 += bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
if (prev) {
if (prev->bone)
roll1 += prev->bone->roll2;
if (!rest)
roll1 += prev->roll2;
}
}
/* extra curve x / y */
/* NOTE: Scale correction factors here are to compensate for some random floating-point glitches
* when scaling up the bone or it's parent by a factor of approximately 8.15/6, which results
* in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out.
*/
const float xscale_correction = (do_scale) ? scale[0] : 1.0f;
const float yscale_correction = (do_scale) ? scale[2] : 1.0f;
h1[0] += (bone->curveInX + (!rest ? pchan->curveInX : 0.0f)) * xscale_correction;
h1[2] += (bone->curveInY + (!rest ? pchan->curveInY : 0.0f)) * yscale_correction;
h2[0] += (bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f)) * xscale_correction;
h2[2] += (bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f)) * yscale_correction;
}
/* make curve */
if (bone->segments > MAX_BBONE_SUBDIV)
bone->segments = MAX_BBONE_SUBDIV;
@@ -610,20 +696,45 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
equalize_bezier(data[0], bone->segments); /* note: does stride 4! */
equalize_bbone_bezier(data[0], bone->segments); /* note: does stride 4! */
/* make transformation matrices for the segments for drawing */
for (a = 0, fp = data[0]; a < bone->segments; a++, fp += 4) {
sub_v3_v3v3(h1, fp + 4, fp);
vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
copy_m4_m3(result_array[a].mat, mat3);
copy_v3_v3(result_array[a].mat[3], fp);
if (do_scale) {
/* correct for scaling when this matrix is used in scaled space */
mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat);
}
/* BBone scale... */
{
const int num_segments = bone->segments;
const float scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
const float scaleFactorIn = 1.0f + (scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
const float scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
const float scaleFactorOut = 1.0f + (scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
const float scalefac = scaleFactorIn * scaleFactorOut;
float bscalemat[4][4], bscale[3];
bscale[0] = scalefac;
bscale[1] = 1.0f;
bscale[2] = scalefac;
size_to_mat4(bscalemat, bscale);
/* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */
/*mul_m4_series(result_array[a].mat, ibscalemat, result_array[a].mat, bscalemat);*/
mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
}
}
}
@@ -669,7 +780,6 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info
float tmat[4][4];
invert_m4_m4(tmat, b_bone_rest[a].mat);
mul_m4_series(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat);
if (use_quaternion)
@@ -683,10 +793,10 @@ static void b_bone_deform(bPoseChanDeform *pdef_info, Bone *bone, float co[3], D
float (*mat)[4] = b_bone[0].mat;
float segment, y;
int a;
/* need to transform co back to bonespace, only need y */
y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1];
/* now calculate which of the b_bones are deforming this */
segment = bone->length / ((float)bone->segments);
a = (int)(y / segment);

View File

@@ -535,7 +535,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
/* generic function to get the appropriate matrix for most target cases */
/* The cases where the target can be object data have not been implemented */
static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, float headtail)
static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, short flag, float headtail)
{
/* Case OBJECT */
if (substring[0] == '\0') {
@@ -573,6 +573,58 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m
/* skip length interpolation if set to head */
mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
}
else if ((pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE)) {
/* use point along bbone */
Mat4 bbone[MAX_BBONE_SUBDIV];
float tempmat[4][4];
float loc[3], fac;
/* get bbone segments */
b_bone_spline_setup(pchan, 0, bbone);
/* figure out which segment(s) the headtail value falls in */
fac = (float)pchan->bone->segments * headtail;
if (fac >= pchan->bone->segments - 1) {
/* special case: end segment doesn't get created properly... */
float pt[3], sfac;
int index;
/* bbone points are in bonespace, so need to move to posespace first */
index = pchan->bone->segments - 1;
mul_v3_m4v3(pt, pchan->pose_mat, bbone[index].mat[3]);
/* interpolate between last segment point and the endpoint */
sfac = fac - (float)(pchan->bone->segments - 1); /* fac is just the "leftover" between penultimate and last points */
interp_v3_v3v3(loc, pt, pchan->pose_tail, sfac);
}
else {
/* get indices for finding interpolating between points along the bbone */
float pt_a[3], pt_b[3], pt[3];
int index_a, index_b;
index_a = floorf(fac);
CLAMP(index_a, 0, MAX_BBONE_SUBDIV - 1);
index_b = ceilf(fac);
CLAMP(index_b, 0, MAX_BBONE_SUBDIV - 1);
/* interpolate between these points */
copy_v3_v3(pt_a, bbone[index_a].mat[3]);
copy_v3_v3(pt_b, bbone[index_b].mat[3]);
interp_v3_v3v3(pt, pt_a, pt_b, fac - floorf(fac));
/* move the point from bone local space to pose space... */
mul_v3_m4v3(loc, pchan->pose_mat, pt);
}
/* use interpolated distance for subtarget */
copy_m4_m4(tempmat, pchan->pose_mat);
copy_v3_v3(tempmat[3], loc);
mul_m4_m4m4(mat, ob->obmat, tempmat);
}
else {
float tempmat[4][4], loc[3];
@@ -634,7 +686,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
{
if (VALID_CONS_TARGET(ct))
constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
else if (ct)
unit_m4(ct->matrix);
}
@@ -1102,7 +1154,7 @@ static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstrai
bKinematicConstraint *data = con->data;
if (VALID_CONS_TARGET(ct))
constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
else if (ct) {
if (data->flag & CONSTRAINT_IK_AUTO) {
Object *ob = cob->ob;
@@ -1985,7 +2037,7 @@ static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTa
/* firstly calculate the matrix the normal way, then let the py-function override
* this matrix if it needs to do so
*/
constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
/* only execute target calculation if allowed */
#ifdef WITH_PYTHON
@@ -2097,7 +2149,7 @@ static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintT
unit_m4(ct->matrix);
/* get the transform matrix of the target */
constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
/* determine where in transform range target is */
/* data->type is mapped as follows for backwards compatibility:

View File

@@ -4926,6 +4926,9 @@ static void direct_link_pose(FileData *fd, bPose *pose)
pchan->child = newdataadr(fd, pchan->child);
pchan->custom_tx = newdataadr(fd, pchan->custom_tx);
pchan->bbone_prev = newdataadr(fd, pchan->bbone_prev);
pchan->bbone_next = newdataadr(fd, pchan->bbone_next);
direct_link_constraints(fd, &pchan->constraints);
pchan->prop = newdataadr(fd, pchan->prop);

View File

@@ -34,6 +34,7 @@
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
@@ -161,6 +162,16 @@ static void do_version_action_editor_properties_region(ListBase *regionbase)
}
}
static void do_version_bones_super_bbone(ListBase *lb)
{
for (Bone *bone = lb->first; bone; bone = bone->next) {
bone->scaleIn = 1.0f;
bone->scaleOut = 1.0f;
do_version_bones_super_bbone(&bone->childbase);
}
}
void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
if (!MAIN_VERSION_ATLEAST(main, 270, 0)) {
@@ -1151,4 +1162,32 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
if (!MAIN_VERSION_ATLEAST(main, 277, 2)) {
if (!DNA_struct_elem_find(fd->filesdna, "Bone", "float", "scaleIn")) {
for (bArmature *arm = main->armature.first; arm; arm = arm->id.next) {
do_version_bones_super_bbone(&arm->bonebase);
}
}
if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "scaleIn")) {
for (Object *ob = main->object.first; ob; ob = ob->id.next) {
if (ob->pose) {
for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* see do_version_bones_super_bbone()... */
pchan->scaleIn = 1.0f;
pchan->scaleOut = 1.0f;
/* also make sure some legacy (unused for over a decade) flags are unset,
* so that we can reuse them for stuff that matters now...
* (i.e. POSE_IK_MAT, (unknown/unused x 4), POSE_HAS_IK)
*
* These seem to have been runtime flags used by the IK solver, but that stuff
* should be able to be recalculated automatically anyway, so it should be fine.
*/
pchan->flag &= ~((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8));
}
}
}
}
}
}

View File

@@ -83,6 +83,15 @@ EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name)
bone->segments = 1;
bone->layer = arm->layer;
bone->roll1 = 0.0f;
bone->roll2 = 0.0f;
bone->curveInX = 0.0f;
bone->curveInY = 0.0f;
bone->curveOutX = 0.0f;
bone->curveOutY = 0.0f;
bone->scaleIn = 1.0f;
bone->scaleOut = 1.0f;
return bone;
}
@@ -890,6 +899,16 @@ static int armature_extrude_exec(bContext *C, wmOperator *op)
newbone->segments = 1;
newbone->layer = ebone->layer;
newbone->roll1 = ebone->roll1;
newbone->roll2 = ebone->roll2;
newbone->curveInX = ebone->curveInX;
newbone->curveInY = ebone->curveInY;
newbone->curveOutX = ebone->curveOutX;
newbone->curveOutY = ebone->curveOutY;
newbone->scaleIn = ebone->scaleIn;
newbone->scaleOut = ebone->scaleOut;
BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
if (flipbone && forked) { // only set if mirror edit

View File

@@ -170,6 +170,11 @@ typedef struct tPChanFCurveLink {
float oldangle;
float oldaxis[3];
float roll1, roll2; /* old bbone values (to be restored along with the transform properties) */
float curveInX, curveInY; /* (NOTE: we haven't renamed these this time, as their names are already long enough) */
float curveOutX, curveOutY;
float scaleIn, scaleOut;
struct IDProperty *oldprops; /* copy of custom properties at start of operator (to be restored before each modal step) */
} tPChanFCurveLink;

View File

@@ -456,7 +456,16 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
eBone->rad_tail = curBone->rad_tail;
eBone->segments = curBone->segments;
eBone->layer = curBone->layer;
eBone->roll1 = curBone->roll1;
eBone->roll2 = curBone->roll2;
eBone->curveInX = curBone->curveInX;
eBone->curveInY = curBone->curveInY;
eBone->curveOutX = curBone->curveOutX;
eBone->curveOutY = curBone->curveOutY;
eBone->scaleIn = curBone->scaleIn;
eBone->scaleOut = curBone->scaleOut;
if (curBone->prop)
eBone->prop = IDP_CopyProperty(curBone->prop);
@@ -611,7 +620,17 @@ void ED_armature_from_edit(bArmature *arm)
newBone->rad_tail = eBone->rad_tail;
newBone->segments = eBone->segments;
newBone->layer = eBone->layer;
newBone->roll1 = eBone->roll1;
newBone->roll2 = eBone->roll2;
newBone->curveInX = eBone->curveInX;
newBone->curveInY = eBone->curveInY;
newBone->curveOutX = eBone->curveOutX;
newBone->curveOutY = eBone->curveOutY;
newBone->scaleIn = eBone->scaleIn;
newBone->scaleOut = eBone->scaleOut;
if (eBone->prop)
newBone->prop = IDP_CopyProperty(eBone->prop);
}

View File

@@ -1451,6 +1451,15 @@ static EditBone *add_editbonetolist(char *name, ListBase *list)
bone->segments = 1;
bone->layer = 1; //arm->layer;
bone->roll1 = 0.0f;
bone->roll2 = 0.0f;
bone->curveInX = 0.0f;
bone->curveInY = 0.0f;
bone->curveOutX = 0.0f;
bone->curveOutY = 0.0f;
bone->scaleIn = 1.0f;
bone->scaleOut = 1.0f;
return bone;
}
#endif

View File

@@ -303,8 +303,8 @@ static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, floa
MEM_freeN(path);
}
/* helper for apply() - perform sliding for custom properties */
static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
/* helper for apply() - perform sliding for custom properties or bbone properties */
static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, const char prop_prefix[])
{
PointerRNA ptr = {{NULL}};
LinkData *ld;
@@ -313,8 +313,10 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
/* setup pointer RNA for resolving paths */
RNA_pointer_create(NULL, &RNA_PoseBone, pfl->pchan, &ptr);
/* custom properties are just denoted using ["..."][etc.] after the end of the base path,
* so just check for opening pair after the end of the path
/* - custom properties are just denoted using ["..."][etc.] after the end of the base path,
* so just check for opening pair after the end of the path
* - bbone properties are similar, but they always start with a prefix "bbone_*",
* so a similar method should work here for those too
*/
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
FCurve *fcu = (FCurve *)ld->data;
@@ -328,7 +330,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
* - pPtr is the chunk of the path which is left over
*/
bPtr = strstr(fcu->rna_path, pfl->pchan_path) + len;
pPtr = strstr(bPtr, "[\""); /* dummy " for texteditor bugs */
pPtr = strstr(bPtr, prop_prefix);
if (pPtr) {
/* use RNA to try and get a handle on this property, then, assuming that it is just
@@ -517,9 +519,16 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
}
}
if (pchan->flag & POSE_BBONE_SHAPE) {
/* bbone properties - they all start a "bbone_" prefix */
pose_slide_apply_props(pso, pfl, "bbone_");
}
if (pfl->oldprops) {
/* not strictly a transform, but contributes to the pose produced in many rigs */
pose_slide_apply_props(pso, pfl);
/* not strictly a transform, but custom properties contribute to the pose produced in many rigs
* (e.g. the facial rigs used in Sintel)
*/
pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */
}
}

View File

@@ -367,10 +367,26 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo
axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
}
/* B-Bone posing options should also be included... */
pchan->curveInX = chan->curveInX;
pchan->curveInY = chan->curveInY;
pchan->curveOutX = chan->curveOutX;
pchan->curveOutY = chan->curveOutY;
pchan->roll1 = chan->roll1;
pchan->roll2 = chan->roll2;
pchan->scaleIn = chan->scaleIn;
pchan->scaleOut = chan->scaleOut;
/* paste flipped pose? */
if (flip) {
pchan->loc[0] *= -1;
pchan->curveInX *= -1;
pchan->curveOutX *= -1;
pchan->roll1 *= -1; // XXX?
pchan->roll2 *= -1; // XXX?
/* has to be done as eulers... */
if (pchan->rotmode > 0) {
pchan->eul[1] *= -1;
@@ -540,6 +556,9 @@ static void pchan_clear_scale(bPoseChannel *pchan)
pchan->size[1] = 1.0f;
if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0)
pchan->size[2] = 1.0f;
pchan->scaleIn = 1.0f;
pchan->scaleOut = 1.0f;
}
/* clear location of pose-channel */
@@ -650,6 +669,15 @@ static void pchan_clear_rot(bPoseChannel *pchan)
zero_v3(pchan->eul);
}
}
/* Clear also Bendy Bone stuff - Roll is obvious, but Curve X/Y stuff is also kindof rotational in nature... */
pchan->roll1 = 0.0f;
pchan->roll2 = 0.0f;
pchan->curveInX = 0.0f;
pchan->curveInY = 0.0f;
pchan->curveOutX = 0.0f;
pchan->curveOutY = 0.0f;
}
/* clear loc/rot/scale of pose-channel */

View File

@@ -71,7 +71,7 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
ListBase curves = {NULL, NULL};
int transFlags = action_get_item_transforms(act, ob, pchan, &curves);
pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
/* check if any transforms found... */
if (transFlags) {
@@ -96,6 +96,8 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
pchan->flag |= POSE_ROT;
if (transFlags & ACT_TRANS_SCALE)
pchan->flag |= POSE_SIZE;
if (transFlags & ACT_TRANS_BBONE)
pchan->flag |= POSE_BBONE_SHAPE;
/* store current transforms */
copy_v3_v3(pfl->oldloc, pchan->loc);
@@ -105,6 +107,16 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
copy_v3_v3(pfl->oldaxis, pchan->rotAxis);
pfl->oldangle = pchan->rotAngle;
/* store current bbone values */
pfl->roll1 = pchan->roll1;
pfl->roll2 = pchan->roll2;
pfl->curveInX = pchan->curveInX;
pfl->curveInY = pchan->curveInY;
pfl->curveOutX = pchan->curveOutX;
pfl->curveOutY = pchan->curveOutY;
pfl->scaleIn = pchan->scaleIn;
pfl->scaleOut = pchan->scaleOut;
/* make copy of custom properties */
if (pchan->prop && (transFlags & ACT_TRANS_PROP))
pfl->oldprops = IDP_CopyProperty(pchan->prop);
@@ -133,6 +145,7 @@ void poseAnim_mapping_get(bContext *C, ListBase *pfLinks, Object *ob, bAction *a
fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
}
CTX_DATA_END;
}
}
@@ -199,6 +212,16 @@ void poseAnim_mapping_reset(ListBase *pfLinks)
copy_v3_v3(pchan->rotAxis, pfl->oldaxis);
pchan->rotAngle = pfl->oldangle;
/* store current bbone values */
pchan->roll1 = pfl->roll1;
pchan->roll2 = pfl->roll2;
pchan->curveInX = pfl->curveInX;
pchan->curveInY = pfl->curveInY;
pchan->curveOutX = pfl->curveOutX;
pchan->curveOutY = pfl->curveOutY;
pchan->scaleIn = pfl->scaleIn;
pchan->scaleOut = pfl->scaleOut;
/* just overwrite values of properties from the stored copies (there should be some) */
if (pfl->oldprops)
IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops);

View File

@@ -74,7 +74,10 @@ typedef struct EditBone {
float xwidth, length, zwidth; /* put them in order! transform uses this as scale */
float ease1, ease2;
float rad_head, rad_tail;
float roll1, roll2;
float curveOutX, curveOutY;
float curveInX, curveInY;
float scaleIn, scaleOut;
float oldlength; /* for envelope scaling */
short segments;

View File

@@ -53,6 +53,7 @@
#include "BKE_global.h"
#include "BKE_modifier.h"
#include "BKE_nla.h"
#include "BKE_curve.h"
#include "BIF_gl.h"
@@ -1093,20 +1094,101 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
glPopMatrix();
}
static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, float xwidth, float length, float zwidth)
/* A partial copy of b_bone_spline_setup(), with just the parts for previewing editmode curve settings
*
* This assumes that prev/next bones don't have any impact (since they should all still be in the "straight"
* position here anyway), and that we can simply apply the bbone settings to get the desired effect...
*/
static void ebone_spline_preview(EditBone *ebone, Mat4 result_array[MAX_BBONE_SUBDIV])
{
float h1[3], h2[3], length, hlength1, hlength2, roll1 = 0.0f, roll2 = 0.0f;
float mat3[3][3];
float data[MAX_BBONE_SUBDIV + 1][4], *fp;
int a;
length = ebone->length;
hlength1 = ebone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
hlength2 = ebone->ease2 * length * 0.390464f;
/* find the handle points, since this is inside bone space, the
* first point = (0, 0, 0)
* last point = (0, length, 0)
*
* we also just apply all the "extra effects", since they're the whole reason we're doing this...
*/
h1[0] = ebone->curveInX;
h1[1] = hlength1;
h1[2] = ebone->curveInY;
roll1 = ebone->roll1;
h2[0] = ebone->curveOutX;
h2[1] = -hlength2;
h2[2] = ebone->curveOutY;
roll2 = ebone->roll2;
/* make curve */
if (ebone->segments > MAX_BBONE_SUBDIV)
ebone->segments = MAX_BBONE_SUBDIV;
BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
equalize_bbone_bezier(data[0], ebone->segments); /* note: does stride 4! */
/* make transformation matrices for the segments for drawing */
for (a = 0, fp = data[0]; a < ebone->segments; a++, fp += 4) {
sub_v3_v3v3(h1, fp + 4, fp);
vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
copy_m4_m3(result_array[a].mat, mat3);
copy_v3_v3(result_array[a].mat[3], fp);
/* "extra" scale facs... */
{
const int num_segments = ebone->segments;
const float scaleFactorIn = 1.0f + (ebone->scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
const float scaleFactorOut = 1.0f + (ebone->scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
const float scalefac = scaleFactorIn * scaleFactorOut;
float bscalemat[4][4], bscale[3];
bscale[0] = scalefac;
bscale[1] = 1.0f;
bscale[2] = scalefac;
size_to_mat4(bscalemat, bscale);
/* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */
mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
}
}
}
static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, EditBone *ebone, float xwidth, float length, float zwidth)
{
int segments = 0;
if (pchan)
segments = pchan->bone->segments;
else if (ebone)
segments = ebone->segments;
if ((segments > 1) && (pchan)) {
if (segments > 1) {
float dlen = length / (float)segments;
Mat4 bbone[MAX_BBONE_SUBDIV];
int a;
b_bone_spline_setup(pchan, 0, bbone);
if (pchan) {
b_bone_spline_setup(pchan, 0, bbone);
}
else if (ebone) {
ebone_spline_preview(ebone, bbone);
}
for (a = 0; a < segments; a++) {
glPushMatrix();
glMultMatrixf(bbone[a].mat);
@@ -1177,7 +1259,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
else
UI_ThemeColor(TH_BONE_SOLID);
draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth);
draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth);
/* disable solid drawing */
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
@@ -1190,7 +1272,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
glEnable(GL_BLEND);
draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth);
draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth);
glDisable(GL_BLEND);
}
@@ -1200,7 +1282,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
}
}
draw_b_bone_boxes(OB_WIRE, pchan, xwidth, length, zwidth);
draw_b_bone_boxes(OB_WIRE, pchan, ebone, xwidth, length, zwidth);
}
}

View File

@@ -199,7 +199,8 @@ typedef struct bPoseChannel {
char constflag; /* for quick detecting which constraints affect this channel */
char selectflag; /* copy of bone flag, so you can work with library armatures, not for runtime use */
char drawflag;
char pad0[5];
char bboneflag;
char pad0[4];
struct Bone *bone; /* set on read file or rebuild pose */
struct bPoseChannel *parent; /* set on read file or rebuild pose */
@@ -242,7 +243,16 @@ typedef struct bPoseChannel {
float ikstretch;
float ikrotweight; /* weight of joint rotation constraint */
float iklinweight; /* weight of joint stretch constraint */
/* curved bones settings - these are for animating, and are applied on top of the copies in pchan->bone */
float roll1, roll2;
float curveInX, curveInY;
float curveOutX, curveOutY;
float scaleIn, scaleOut;
struct bPoseChannel *bbone_prev; /* next/prev bones to use as handle references when calculating bbones (optional) */
struct bPoseChannel *bbone_next;
void *temp; /* use for outliner */
} bPoseChannel;
@@ -253,17 +263,17 @@ typedef enum ePchan_Flag {
POSE_LOC = (1 << 0),
POSE_ROT = (1 << 1),
POSE_SIZE = (1 << 2),
/* old IK/cache stuff... */
#if 0
POSE_IK_MAT = (1 << 3),
POSE_UNUSED2 = (1 << 4),
POSE_UNUSED3 = (1 << 5),
POSE_UNUSED4 = (1 << 6),
POSE_UNUSED5 = (1 << 7),
/* has Standard IK */
POSE_HAS_IK = (1 << 8),
#endif
/* IK/Pose solving*/
/* old IK/cache stuff
* - used to be here from (1 << 3) to (1 << 8)
* but has been repurposed since 2.77.2
* as they haven't been used in over 10 years
*/
/* has BBone deforms */
POSE_BBONE_SHAPE = (1 << 3),
/* IK/Pose solving */
POSE_CHAIN = (1 << 9),
POSE_DONE = (1 << 10),
/* visualization */
@@ -318,6 +328,16 @@ typedef enum ePchan_DrawFlag {
#define PCHAN_CUSTOM_DRAW_SIZE(pchan) \
(pchan)->custom_scale * (((pchan)->drawflag & PCHAN_DRAW_NO_CUSTOM_BONE_SIZE) ? 1.0f : (pchan)->bone->length)
/* PoseChannel->bboneflag */
typedef enum ePchan_BBoneFlag {
/* Use custom reference bones (for roll and handle alignment), instead of immediate neighbours */
PCHAN_BBONE_CUSTOM_HANDLES = (1 << 1),
/* Evaluate start handle as being "relative" */
PCHAN_BBONE_CUSTOM_START_REL = (1 << 2),
/* Evaluate end handle as being "relative" */
PCHAN_BBONE_CUSTOM_END_REL = (1 << 3),
} ePchan_BBoneFlag;
/* PoseChannel->rotmode and Object->rotmode */
typedef enum eRotationModes {
/* quaternion rotations (default, and for older Blender versions) */

View File

@@ -68,11 +68,18 @@ typedef struct Bone {
float xwidth, length, zwidth; /* width: for block bones. keep in this order, transform! */
float ease1, ease2; /* length of bezier handles */
float rad_head, rad_tail; /* radius for head/tail sphere, defining deform as well, parent->rad_tip overrides rad_head */
float roll1, roll2; /* curved bones settings - these define the "restpose" for a curved bone */
float curveInX, curveInY;
float curveOutX, curveOutY;
float scaleIn, scaleOut;
float size[3]; /* patch for upward compat, UNUSED! */
int layer; /* layers that bone appears on */
short segments; /* for B-bones */
short pad[1];
short pad1;
} Bone;
typedef struct bArmature {
@@ -204,7 +211,8 @@ typedef enum eBone_Flag {
BONE_TRANSFORM_CHILD = (1 << 20), /* Indicates that a parent is also being transformed */
BONE_UNSELECTABLE = (1 << 21), /* bone cannot be selected */
BONE_NO_LOCAL_LOCATION = (1 << 22), /* bone location is in armature space */
BONE_RELATIVE_PARENTING = (1 << 23) /* object child will use relative transform (like deform) */
BONE_RELATIVE_PARENTING = (1 << 23), /* object child will use relative transform (like deform) */
BONE_ADD_PARENT_END_ROLL = (1 << 24) /* it will add the parent end roll to the inroll */
} eBone_Flag;

View File

@@ -516,7 +516,9 @@ typedef enum eBConstraint_Flags {
/* indicates that constraint was added locally (i.e. didn't come from the proxy-lib) */
CONSTRAINT_PROXY_LOCAL = (1<<8),
/* indicates that constraint is temporarily disabled (only used in GE) */
CONSTRAINT_OFF = (1<<9)
CONSTRAINT_OFF = (1<<9),
/* use bbone curve shape when calculating headtail values */
CONSTRAINT_BBONE_SHAPE = (1<<10),
} eBConstraint_Flags;
/* bConstraint->ownspace/tarspace */

View File

@@ -482,6 +482,82 @@ static void rna_Armature_transform(struct bArmature *arm, float *mat)
#else
/* Settings for curved bbone settings - The posemode values get applied over the top of the editmode ones */
void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
{
#define RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone) \
{ \
if (is_posebone) \
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); \
else \
RNA_def_property_update(prop, 0, "rna_Armature_update_data"); \
} (void)0;
PropertyRNA *prop;
/* Roll In/Out */
prop = RNA_def_property(srna, "bbone_rollin", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "roll1");
RNA_def_property_range(prop, -M_PI * 2.0f, M_PI * 2.0f);
RNA_def_property_ui_text(prop, "Roll In", "Roll offset for the start of the B-Bone, adjusts twist");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
prop = RNA_def_property(srna, "bbone_rollout", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "roll2");
RNA_def_property_range(prop, -M_PI * 2.0f, M_PI * 2.0f);
RNA_def_property_ui_text(prop, "Roll Out", "Roll offset for the end of the B-Bone, adjusts twist");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
if (is_posebone == false) {
prop = RNA_def_property(srna, "use_endroll_as_inroll", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Inherit End Roll", "Use Roll Out of parent bone as Roll In of its children");
RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_ADD_PARENT_END_ROLL);
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
}
/* Curve X/Y Offsets */
prop = RNA_def_property(srna, "bbone_curveinx", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "curveInX");
RNA_def_property_range(prop, -5.0f, 5.0f);
RNA_def_property_ui_text(prop, "In X", "X-axis handle offset for start of the B-Bone's curve, adjusts curvature");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
prop = RNA_def_property(srna, "bbone_curveiny", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "curveInY");
RNA_def_property_range(prop, -5.0f, 5.0f);
RNA_def_property_ui_text(prop, "In Y", "Y-axis handle offset for start of the B-Bone's curve, adjusts curvature");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
prop = RNA_def_property(srna, "bbone_curveoutx", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "curveOutX");
RNA_def_property_range(prop, -5.0f, 5.0f);
RNA_def_property_ui_text(prop, "Out X", "X-axis handle offset for end of the B-Bone's curve, adjusts curvature");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
prop = RNA_def_property(srna, "bbone_curveouty", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "curveOutY");
RNA_def_property_range(prop, -5.0f, 5.0f);
RNA_def_property_ui_text(prop, "Out Y", "Y-axis handle offset for end of the B-Bone's curve, adjusts curvature");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
/* Scale In/Out */
prop = RNA_def_property(srna, "bbone_scalein", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scaleIn");
RNA_def_property_range(prop, 0.0f, 5.0f);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Scale In", "Scale factor for start of the B-Bone, adjusts thickness (for tapering effects)");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
prop = RNA_def_property(srna, "bbone_scaleout", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scaleOut");
RNA_def_property_range(prop, 0.0f, 5.0f);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Scale Out", "Scale factor for end of the B-Bone, adjusts thickness (for tapering effects)");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
#undef RNA_DEF_CURVEBONE_UPDATE
}
static void rna_def_bone_common(StructRNA *srna, int editbone)
{
PropertyRNA *prop;
@@ -653,6 +729,7 @@ static void rna_def_bone(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Children", "Bones which are children of this bone");
rna_def_bone_common(srna, 0);
rna_def_bone_curved_common(srna, 0);
/* XXX should we define this in PoseChannel wrapping code instead?
* But PoseChannels directly get some of their flags from here... */
@@ -766,6 +843,7 @@ static void rna_def_edit_bone(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Armature_editbone_transform_update");
rna_def_bone_common(srna, 1);
rna_def_bone_curved_common(srna, 0);
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_HIDDEN_A);

View File

@@ -483,6 +483,21 @@ static EnumPropertyItem constraint_distance_items[] = {
};
static void rna_def_constraint_headtail_common(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "use_bbone_shape", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, "bConstraint", "flag", CONSTRAINT_BBONE_SHAPE);
RNA_def_property_ui_text(prop, "Follow B-Bone", "Follow shape of B-Bone segments when calculating Head/Tail position");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
static void rna_def_constrainttarget(BlenderRNA *brna)
{
StructRNA *srna;
@@ -787,10 +802,7 @@ static void rna_def_constraint_track_to(BlenderRNA *brna)
srna = RNA_def_struct(brna, "TrackToConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Track To Constraint", "Aim the constrained object toward the target");
prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bTrackToConstraint", "data");
@@ -831,10 +843,7 @@ static void rna_def_constraint_locate_like(BlenderRNA *brna)
srna = RNA_def_struct(brna, "CopyLocationConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Copy Location Constraint", "Copy the location of the target");
prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bLocateLikeConstraint", "data");
@@ -1022,10 +1031,7 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
srna = RNA_def_struct(brna, "CopyTransformsConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Copy Transforms Constraint", "Copy all the transforms of the target");
prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bTransLikeConstraint", "data");
@@ -1200,10 +1206,7 @@ static void rna_def_constraint_locked_track(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Locked Track Constraint",
"Point toward the target along the track axis, while locking the other axis");
prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bLockTrackConstraint", "data");
@@ -1327,10 +1330,7 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna)
srna = RNA_def_struct(brna, "StretchToConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Stretch To Constraint", "Stretch to meet the target object");
prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bStretchToConstraint", "data");
@@ -2122,10 +2122,7 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna)
srna = RNA_def_struct(brna, "LimitDistanceConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Limit Distance Constraint", "Limit the distance from target object");
prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bDistLimitConstraint", "data");
@@ -2236,10 +2233,7 @@ static void rna_def_constraint_damped_track(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Damped Track Constraint",
"Point toward target by taking the shortest rotation path");
prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bDampTrackConstraint", "data");
@@ -2396,10 +2390,7 @@ static void rna_def_constraint_pivot(BlenderRNA *brna)
srna = RNA_def_struct(brna, "PivotConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Pivot Constraint", "Rotate around a different point");
prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
rna_def_constraint_headtail_common(srna);
RNA_def_struct_sdna_from(srna, "bPivotConstraint", "data");

View File

@@ -197,6 +197,8 @@ void rna_def_animdata_common(struct StructRNA *srna);
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
void rna_def_bone_curved_common(struct StructRNA *srna, bool is_posebone);
void rna_def_texmat_common(struct StructRNA *srna, const char *texspace_editable);
void rna_def_mtex_common(struct BlenderRNA *brna, struct StructRNA *srna, const char *begin, const char *activeget,
const char *activeset, const char *activeeditable, const char *structname,

View File

@@ -872,6 +872,50 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Rotation Mode", "");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
/* Curved bones settings - Applied on top of restpose values */
rna_def_bone_curved_common(srna, true);
/* Custom BBone next/prev sources */
prop = RNA_def_property(srna, "use_bbone_custom_handles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_HANDLES);
RNA_def_property_ui_text(prop, "Use Custom Handle References",
"Use custom reference bones as handles for B-Bones instead of next/previous bones, "
"leave these blank to use only B-Bone offset properties to control the shape");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
prop = RNA_def_property(srna, "bbone_custom_handle_start", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "bbone_prev");
RNA_def_property_struct_type(prop, "PoseBone");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "B-Bone Start Handle",
"Bone that serves as the start handle for the B-Bone curve");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
prop = RNA_def_property(srna, "use_bbone_relative_start_handle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_START_REL);
RNA_def_property_ui_text(prop, "Relative B-Bone Start Handle",
"Use treat custom start handle position as a relative value");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
prop = RNA_def_property(srna, "bbone_custom_handle_end", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "bbone_next");
RNA_def_property_struct_type(prop, "PoseBone");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "B-Bone End Handle",
"Bone that serves as the end handle for the B-Bone curve");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
prop = RNA_def_property(srna, "use_bbone_relative_end_handle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_END_REL);
RNA_def_property_ui_text(prop, "Relative B-Bone End Handle",
"Use treat custom end handle position as a relative value");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
/* transform matrices - should be read-only since these are set directly by AnimSys evaluation */
prop = RNA_def_property(srna, "matrix_channel", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "chan_mat");