DazHead property is set wrong when I import daz armatures (not figures) with off-zero object coordinates

Issue #1826 resolved
Rakete created an issue

What a mouthful of a title again. So I have an object that has a daz armature, it is not a figure but a cupboard. I can import that cupboard and then open the doors by moving the bones of the armature.

When I put the cupboard into the scene and leave it at zero and save and import that, everything works fine. But, if I move the cupboard to off zero coordinates and open the door and save and apply the pose, the door detaches from the cupboard and flies of.

The reason for that is that DazHead on the edit bone is set incorrectly. At least I can see that that is the only real difference, and when I go and manually correct the DazHead property of all bones, it works.

To correct it I simply take the object position * 100 and subtract it from DazHead. So I move the cupboard on the X axis to -150 in daz, then it will end up at -1.5 in blender. Then my bone has a DazHead like (-100.707, 43.0, 28.7086) and I just subtract (-150, 0, 0) ending up with (49.293, 43.0, 28.7086) and everything works.

Comments (6)

  1. Rakete reporter

    What I said isn’t entirely accurate, to reproduce my problem:

    1. load cupboard into Daz
    2. move cupboard to off-zero coordinates
    3. load into Blender
    4. open the door by moving the door bone in Blender
    5. save pose
    6. apply pose in Daz
    7. see doors flying off

    If you don’t move the cupboard to off-zero coordinates in 2. it works fine.

  2. Rakete reporter

    I found out that in DazHead is set in bone.py buildBoneProps from the head that getHeadTail returns:

    head,tail,orient,xyz,wsmat = self.getHeadTail(center)
    head0,tail0,orient0,xyz0,wsmat0 = self.getHeadTail(center, False)
    bone.DazHead = head
    

    and getHeadTail just gets it from restdata and doesn’t really do much other then that with it, but then restdata is filled in objfile.py loadDbzFile and there you take head from the ws_transform of the bone. Now I am kind of wondering why even use the world space transform for bones? Shouldn’t it be the local transform, as in local to the current armature? But I tried that and it failed completely so I guess I am not going to question using the world space transform there as long as it works.

    However for the DazHead I noticed I really just need to keep the original head that you get from bone[“center_point”] in the loadDbzFile function here:

    for bone in figure["bones"]:
                head = Vector(bone["center_point"])
                daz_head = head
                tail = Vector(bone["end_point"])
                vec = tail - head
                if "ws_transform" in bone.keys():
                    ws = bone["ws_transform"]
                    wsmat = Matrix([ws[0:3], ws[3:6], ws[6:9]])
                    head = Vector(ws[9:12])
                    tail = head + vec @ wsmat
                else:
                    head = Vector(bone["ws_pos"])
                    x,y,z,w = bone["ws_rot"]
                    quat = Quaternion((w,x,y,z))
                    rmat = quat.to_matrix().to_3x3()
                    ws = bone["ws_scale"]
                    smat = Matrix([ws[0:3], ws[3:6], ws[6:9]])
                    tail = head + vec @ smat @ rmat
                    wsmat = smat @ rmat
                if "orientation" in bone.keys():
                    orient = bone["orientation"]
                    xyz = bone["rotation_order"]
                    origin = bone["origin"]
                else:
                    orient = xyz = origin = None
                bname = bone["name"]
                rmat = wsmat.to_4x4()
                rmat.col[3][0:3] = LS.scale*head
                restdata[bname] = (head, tail, orient, xyz, origin, wsmat, daz_head)
                transforms[bname] = (rmat, head, rmat.to_euler(), (1,1,1))
    

    and I already added the change I made to fix the problem for me to the code: I just assign daz_head = Vector(bone["center_point"]) and put that into restdata[bname] and then in buildBoneProps I do this:

    head,tail,orient,xyz,wsmat,daz_head = self.getHeadTail(center)
    head0,tail0,orient0,xyz0,wsmat0,daz_head0 = self.getHeadTail(center, False)
    bone.DazHead = daz_head
    

    and now everything works correctly as far as I can tell.

  3. Thomas Larsson repo owner

    The world space location combines bone proportions and object transformations. It would be desireable to only include the former, but afaiu it is not possible to extract that information from DS. The data that is available are the unmorphed bones at rest, and the morphed bones with object transformation which DS uses to draw the viewport and rendering. If you use dbz fitting use get both, which work best if the character is in rest pose. Morphed fitting may be an alternative.

  4. Thomas Larsson repo owner

    Forget what I wrote above. The center-point is indeed the location of the bone in armature space and can be used for the DazHead variable. Your suggestion has been implemented.

  5. Log in to comment