this is a simple script i wrote to sculpt a narrow blendshape using python scripting for spherical mouth in Blender 2.79 (the script may need to be edited to work in higher Blender versions. also it might be better to use bmesh). it takes the mesh name (object name) and need to specify grow (how many loops should be affected in sculpt beginning from innermost selected. The scale parameters tell how much scaling should happen at ends of shape. it needs the innermost vertex loop selected in edit mode. in the snippet to run in blender need to replace the path to the python file with where the code was saved. (modify use at your own risk).
(it needs the innermost vertex loop selected in edit mode)
"""to test in blender
import imp
testTool = imp.load_source("tool","/Users/Nathaniel/Documents/src_blender/python/snippets/testingStuff/narrowShape.py") #change to path to python file that has class
shp = testTool.NarrowShapeTask(mesh = 'Sphere')
shp.build( grow = 5, max_scale = 0.2, min_scale = 0.9 )
"""
import bpy
import numpy
class NarrowShapeTask(object):
"""simple class to help make narrow shape on spherical or torus mesh
grow selection a few times each time scaling the edgeloops. want a smooth falloff
little error checking
"""
def __init__(self, mesh):
self.mesh = mesh
def build(self, grow = 4, max_scale = 0.3, min_scale = 0.9 ):
"""sculpt the (narrow) shape
@param grow - times to grow inital selection. example 2 would say give me first two edgeloops. should be 2 or more
@param max_scale - most amount to scale. for the inner most loop
@param min_scale - smallest amount to scale. for the outermost loop
"""
vertexIdLoops = self.getEachVertexLoop(grow = grow)
falloffs = list(numpy.linspace(max_scale, min_scale, grow)) #get evenly spaced scales from start to end value. want first value scaled down the most for innermost part of narrow shape
#assumes both lengths should be equal
#change size of the loops smoothly
for i in range(0,grow):
vloop = vertexIdLoops[i]
falloff = falloffs[i]
self.selectMeshLoop( vertexLoop = vloop )
self.scaleSelectedMeshLoop(value = falloff)
print("NarrowShapeTask >>> build success")
return True
def getEachVertexLoop( self, grow = 4 ):
"""get list where each element are verts(ids) in that loop. should be ordered. each element is a list
assumes innermost edgeloop selected in edit mode
@param mesh - data object name for mesh
@param grow - times to grow inital selection. example 2 would say give me first two edgeloops. should be 2 or more
@return [list] - each element are verts(ids) in that loop. should be ordered. each element is a list
"""
result = []
#check grow is 2 or more
meshObj = bpy.data.objects[self.mesh]
#for first loop dont need to do anything fancy
curSel = []
self._refreshSelection() #i think can move this and below line into own method later
curSel = [ v.index for v in meshObj.data.vertices if v.select ]
result.append(curSel)
for i in range(1,grow):
self._refreshSelection()
prevSel = [ v.index for v in meshObj.data.vertices if v.select ]
bpy.ops.mesh.select_more()
self._refreshSelection()
curSel = [ v.index for v in meshObj.data.vertices if v.select ]
loopVertexIds = list(set(curSel)-set(prevSel))
result.append(loopVertexIds)
return result
def scaleSelectedMeshLoop(self, value = 1.0):
"""scale the currently selected vertex loop. assumes in edit mode
@param value - the scale amount
"""
bpy.ops.transform.resize( value=(value,value,value) ) #scale by same amount in all axis
def selectMeshLoop( self, vertexLoop = [] ):
"""select given vertex ids. replaces selection. assumes in edit mode
ex: shp.selectMeshLoop( vertexLoop = [80] )
@param vertexLoop - list of vertex ids
"""
#print("vertexLoop",vertexLoop)
meshObj = bpy.data.objects[self.mesh]
#deselect all vertices
bpy.ops.mesh.select_all(action='DESELECT')
#need to be in object mode
bpy.ops.object.mode_set(mode="OBJECT")
#select the loop
loop = [ meshObj.data.vertices[vid] for vid in vertexLoop]
for v in loop:
#print("v>>",v.index)
v.select = True
self._refreshSelection() #so vertex selection is registered
def _refreshSelection(self):
"""need to toggle in and out of object mode so vertex selection is registered
"""
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.mode_set(mode="EDIT")
#tried first making methods > then later made into class(on the side i'm trying to learn c/c++ and i'm finding it helpful to learn from other's examples for example on blender git source by making a list of lines do not understand the syntax. then searching google example stackoverflow to find out what that line syntax means. kindof like a way of breaking down the problem into smaller manageable chunks. i think reading code is a great way to begin learning how to write code.)

