4
$\begingroup$

OK, so I am rendering a rigged hand model for a project. I need to create a constraint that will stop any model self-intersections. I've looked everywhere and can't find a solution.

I need to stop situations where: Fingers go inside of fingers/ fingers go inside of the palm.

**Is there a solution that will move the armature to similar a non-intersecting pose? Or a constraint that will not allow for intersections?

Thanks for the help! self intersection problem

$\endgroup$
  • 3
    $\begingroup$ That looks painful. $\endgroup$ – Jacob Jones Feb 17 '17 at 21:31
  • $\begingroup$ This paper looks like a potential general direction for any mesh self-intersection problem. It is a bit of over-kill for my problem. cs.cornell.edu/projects/escc/escc.pdf $\endgroup$ – user35878 Feb 23 '17 at 16:56
  • $\begingroup$ This paper tries to solve a variation of this problem in robotics: kuffner.org/james/papers/kuffner_icra2002.pdf $\endgroup$ – user35878 Feb 23 '17 at 17:30
2
$\begingroup$

This solution really worked great for me. It is developed in python, the code is kind of long but the ideas are pretty simple.

First I found the global head and tail locations of each bone.

My solution to self-intersection detection between fingers and the palm is pretty straightforward. I checked the distance of each fingertip tail bone to a plane created from three points in the palm. This is the function that I built.

def getPointToSurfDist(testBone, triBones):
    #points for surface
    p1 = getBoneGlobalTailLocation(getBoneObByName(triBones[0]))
    p2 = getBoneGlobalTailLocation(getBoneObByName(triBones[1]))
    p3 = getBoneGlobalTailLocation(getBoneObByName(triBones[2]))
    #vectors
    v1 = p2-p1
    v2 = p3-p1
    #3D plane
    s1 = v1.cross(v2)
    #test point
    p4 = getBoneGlobalTailLocation(getBoneObByName(testBone))
    dis = (s1.x*p4.x + s1.y*p4.y + s1.z*p4.z)/math.sqrt(math.pow(s1.x,2)+math.pow(s1.y,2)+math.pow(s1.z,2))
    return dis

If the distance was below a certain threshold the fingers were considered to intersect the palm.

My solution to the finger-to-finger intersection is a bit more interesting and less trivial. I decided to look at each armature bone as a finite segment. Then I check the distance between each segment and all of the other segments. I have about 20 armature bones, translating into a cap of approximately 400 calculations (not too bad, very fast). If the minimum distance between two armature bones was under a given threshold it would be considered intersecting.

I translated the dist3D_Segment_to_Segment() function from: http://geomalgorithms.com/a07-_distance.html to python and applied in my code. (look here to further understand the code.)

def getSeg2SegDistance(hs1,ts1,hs2,ts2):
    #implementation converted from C: http://geomalgorithms.com/a07-_distance.html
    #input heads and tails of both segments (head s1, tail s1, head s2, tail s2)
    #initialize vectors
    u = ts1 - hs1
    v = ts2 - hs2
    w = hs1 - hs2
    a = u.dot(u)
    b = u.dot(v)
    c = v.dot(v)
    d = u.dot(w)
    e = v.dot(w)
    D = a*c - b*b
    sc, sN, sD = [D, D, D]
    tc, tN, tD = [D, D, D]
    #compute the line parameters of the two closest points
    smallApproxErr = 0.01
    if D < smallApproxErr: #lines approx parallel
        sN = 0.0
        sD = 1.0
        tN = e
        tD = c
    else:               #closest point on infinite lines
        sN = b*e - c*d
        tN = a*e - b*d
        if sN<0.0:      #sc<0 -> s=0
            sN = 0.0
            tN = e
            tD = c
        elif sN > sD:   #sc>1 -> s=1
            sN = sD
            tN = e + b
            tD = c
    if tN < 0.0:        #tc<0 -> t=0
        tN = 0.0
        if (-d<0.0):
            sN = 0.0
        elif (-d>a):
            sN = sD
        else:
            sN = -d
            sD = a
    elif tN > tD:       #tc>1 -> t=1
        tN = tD
        if -d + b < 0.0:
            sN = 0
        elif -d +b > a:
            sN = sD
        else:
            sN = -d + b
            sD = a
    #division to get sc and tc
    if abs(sN) < smallApproxErr:
        sc = 0
    else:
        sc = sN/sD
    if abs(tN) < smallApproxErr:
        tc = 0
    else:
        tc = tN/tD

    dP = w + sc*u - tc*v
    return math.sqrt(dP.dot(dP))

This intersection detection works great. It is not a general solution to every armature rig self-intersection detection, yet for hands/ arms/ machines (with bars or pipes) this would work great. The idea can further be generalized taking into account the 'Envelope Radius' of the bones to effect the thresholding. It is useful to think about the distance calculation from the body you are rigging.

This solution is python based and really gets into the geometry. A simple solution from within the blender platform would still be nice

Good luck!

| improve this answer | |
$\endgroup$
0
$\begingroup$

I don't think there is a simple way to detect mesh collision but you can use limit rotation constraints for example. If you know exactly what rotations cause the self-intersection. This is a very manual approach.

You can also use action constaints and make sure there is no collision in your action. This will constrain your range of motion. The action constraints principle is explained here: https://www.youtube.com/watch?v=MQTREfQSlBU

A full and general solution has not yet been found.

| improve this answer | |
$\endgroup$
  • $\begingroup$ Thanks for the response. Could you explain more in detail what you mean by 'action constraints'? I searched for a solution in that direction and wasn't able to find one. $\endgroup$ – user35878 Feb 18 '17 at 12:10
  • $\begingroup$ You can watch this tutorial explaining how to rig fingers with action constraints youtube.com/watch?v=MQTREfQSlBU $\endgroup$ – christopheS Feb 18 '17 at 15:56
  • $\begingroup$ Thanks. This didn't really solve my intersection problem, but it was useful for something else I was working on. $\endgroup$ – user35878 Feb 18 '17 at 17:01
  • $\begingroup$ @GilElbaz You shouldn't generally edit an answer to say that it wasn't what you were looking for. That's what comments are for. $\endgroup$ – Jacob Jones Mar 4 '17 at 1:10
  • $\begingroup$ @JacobJones I agree, but that was not my reasoning. I clarified the English and clarified what the link contains. I am happy that I got an answer, yet it was not very relevant to the problem at hand. For some reason people upvoted it, potentially stopping future users from providing a useful response. It was important to clarify that this is not a real solution to the problem (so that people do not continue to upvote it, just because it was upvoted in the past). In the end, I solved the problem geometrically with python, yet a Blender based solution would still be great. Have a nice day $\endgroup$ – user35878 Mar 5 '17 at 15:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy