Skip to content
This repository was archived by the owner on Oct 7, 2021. It is now read-only.
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions scripts/mgear/rigbits/facial_rigger/eye_rigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ def rig(eyeMesh=None,
edgeList = extr_v[4]
vertexList = extr_v[5]

# Fix for tilted eyes or asian eyes where the mid-point is not the highest altitude vertex
if all([customCorner, intCorner, extCorner]):
upperEdges, lowerEdges = getUpperAndLowerHalfsFromEdgeLoop(edgeLoopList, intCorner, extCorner)
upPos = getMidPointFromEdgeList(upperEdges, pm.MeshVertex(intCorner), pm.MeshVertex(extCorner))
lowPos = getMidPointFromEdgeList(lowerEdges, pm.MeshVertex(intCorner), pm.MeshVertex(extCorner))

# Detect the side L or R from the x value
if inPos.getPosition(space='world')[0] < 0.0:
side = "R"
Expand Down Expand Up @@ -909,6 +915,99 @@ def setName(name, ind=None):
nw=1,
n='skinClsEye')



def getUpperAndLowerHalfsFromEdgeLoop(inputEdges, start, end):
"""
For eye-rigger. Given a list of edges that form a loop and two vertices,
two contiguous edge-lists are returned, sorted by overall height in world-space,
i.e. the upper and lower halfs respectively.

:param inputEdges (list of pm.MeshEdge): Loop-edges
:param start (pm.MeshVertex): Start-vertex (interior eyelid corner)
:param end (pm.MeshVertex): End-vertex (exterior eyelid corner)

:returns (tuple): The upper- and lower edge-lists
"""

start = pm.MeshVertex(start) if isinstance(start, basestring) else start
end = pm.MeshVertex(end) if isinstance(end, basestring) else end

startEdge = None
secondVert = None
for edg in inputEdges:
connections = edg.connectedVertices()
if start in connections:
secondVert = connections[1] if connections[0] == start else connections[0]
startEdge = edg
break

secondEdge = None
for edg in inputEdges:
if secondVert in edg.connectedVertices():
if edg != startEdge:
secondEdge = edg
break

currentEdge = secondEdge
edges = [startEdge, secondEdge]
if not all([startEdge, secondEdge]):
return (None, None, None)

midOffset = None
while True:
for edg in inputEdges:
if edg in edges:
continue
if edg in currentEdge.connectedEdges():
edges.append(edg)
currentEdge = edg
if end in edg.connectedVertices():
midOffset = len(edges) - 1
break
else:
break

half1 = edges[midOffset:]
half2 = edges[:midOffset]

height1 = sum([edge.getPoint(0, "world")[1] for edge in half1])
height2 = sum([edge.getPoint(0, "world")[1] for edge in half2])

return (half1, half2) if height1 > height2 else (half2, half1)


def getMidPointFromEdgeList(edgeList, inPos, outPos):
"""
Returns the vertex closest to the middle between inPos and outPos

:param edgeList (list of pm.MeshEdge): Unordered edges
:param inPos (pm.MeshVertex): Interior eye corner
:param outPos (pm.MeshVertex): Exterior eye corner

:returns: pm.MeshVertex
"""
verts = set()
for edg in edgeList:
for vert in edg.connectedVertices():
verts.add(vert)

start = inPos.getPosition()
end = outPos.getPosition()
middle = (start - end) * 0.5 + end

candidates = []
for vertex in verts:
distance = middle.distanceTo(vertex.getPosition())
candidates.append((distance, vertex))

if not candidates:
return None

dist, vertex = sorted(candidates)[0]
return vertex


##########################################################
# Eye Rig UI
##########################################################
Expand Down