0
$\begingroup$

I'm stuck, Trying to roll a pose bone while staying in the Head and Tail vector. When I use axis angle or any other rotation, it doesn't stay in place and it goes off its vector.

Vector shouldn't change and rolling angle is the variable. enter image description here

$\endgroup$
0

2 Answers 2

2
$\begingroup$

Rolling a pose bone.

Using python, how do you get the "roll" of a pose_bone?

IMO this is simply a case of rotating the bone around any pivot point that is on a line parallel to y axis vector passing thru points head and tail.

Matrix math to translate, rotate, scale with respect to a pivot point in Object mode

import bpy
from mathutils import Matrix


def rollposebone(pb, roll):
    R = (
         Matrix.Translation(pb.head) @ 
         Matrix.Rotation(roll, 4, pb.y_axis) @
         Matrix.Translation(-pb.head)
         )
    pb.matrix = R @ pb.matrix


# test call, roll 3 degrees.
from math import radians
context = bpy.context
    
rollposebone(context.active_pose_bone, radians(3))

Please also note that blender natively uses radians, as does math and numpy. Recommend using as above, ie if you wish to pass a value like 90 degrees pass via radians(90) rather than converting to and fro in code. If making a UI give any angle property a `unit = 'ROTATION`` and it will be displayed in the chosen rotation unit, which is by default degrees.

$\endgroup$
0
0
$\begingroup$
import bpy
import math
import numpy as np
from mathutils import Vector 

context = bpy.context
scene = context.scene
RobloxRig = bpy.context.scene.objects['__Rig'] 
UpperRightArm_bone = RobloxRig.pose.bones["RightUpperArm"]


def angle(v1, v2, acute):
# v1 is your first vector
# v2 is your second vector
    angle = np.arccos(np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2)))
    if (acute == True):
        return angle
    else:
        return 2 * np.pi - angle
    
def RollBone(bone,Degrees):
    vdir = Vector(bone.tail - bone.head)
    BoneXVec = Vector((0,vdir.y,vdir.z))
    Xangle = math.degrees(angle(Vector((0, 0, 1)), BoneXVec, True))

    xAbs = vdir.y 
    xsign = 0

    if xAbs > 0:
        xsign = -math.radians(Xangle)
    
    if xAbs < 0:
        xsign = math.radians(Xangle)

    #Center X
    bpy.ops.transform.rotate(value= xsign, orient_axis='X', orient_type='GLOBAL')

    bpy.context.view_layer.update()

    vdir = Vector(bone.tail - bone.head)
    BoneXVec = Vector((vdir.x,0,vdir.z))
    Yangle = math.degrees(angle(Vector((1, 0, 0)), BoneXVec, True))
    yAbs = vdir.z 
    ysign = 0

    if yAbs > 0:
        ysign = -math.radians(Yangle) + math.radians(90)
    
    if yAbs < 0:
        ysign = math.radians(Yangle)  + math.radians(90)
   
    #Center Y
    bpy.ops.transform.rotate(value=ysign, orient_axis='Y', orient_type='GLOBAL')
    bpy.context.view_layer.update()
    
    #Roll on Z
    bpy.ops.transform.rotate(value=math.radians(Degrees), orient_axis='Z', orient_type='GLOBAL')
    bpy.context.view_layer.update()
    
    #Return Rotation
    bpy.ops.transform.rotate(value=-ysign, orient_axis='Y', orient_type='GLOBAL')
    bpy.ops.transform.rotate(value= -xsign, orient_axis='X', orient_type='GLOBAL')




if __name__ == "__main__":
    RollBone(UpperRightArm_bone,90)

I used bpy.ops.transform.rotate to rotate the bone to its normal x and y vector, then I rotate z to the desired angle. Lastly I use the inverse of x and y rotations to set it back to the space it was at.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .