forked from bartvdbraak/blender
rewrote this script, it was the most out of date script and had some errors that are solved in the new script.
- moved to the weightpaint menu - Use a group for envelope objects, no special names. - Can use non mesh data for envalopes (anything that can be converted into a mesh - metaballs, text, surface) - Dosnt rely on applying loc/size/rot for it to work properly - Uses a good point-inside-mesh method (optimized with mesh and face bounding checks) - uses Mesh instead of NMesh todo, only update active vgroup
This commit is contained in:
parent
79fd2a2ae4
commit
60ebff78ab
@ -1,234 +0,0 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Envelope Assignment'
|
||||
Blender: 234
|
||||
Group: 'Animation'
|
||||
Tooltip: 'Assigns weights to vertices via envelopes'
|
||||
"""
|
||||
|
||||
__author__ = "Jonas Petersen"
|
||||
__url__ = ("blender", "elysiun", "Script's homepage, http://www.mindfloaters.de/blender/", "thread at blender.org, http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewtopic&t=4858")
|
||||
__version__ = "0.9 2004-11-10"
|
||||
__doc__ = """\
|
||||
This script creates vertex groups from a set of envelopes.
|
||||
|
||||
"Envelopes" are Mesh objects with names following this naming convention:
|
||||
|
||||
<bone name>:<float value>
|
||||
|
||||
Notes:<br>
|
||||
- All existing vertex groups of the target Mesh will be deleted.
|
||||
|
||||
Please check the script's homepage and the thread at blender.org (last link button above) for more info.
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# "Armature Symmetry" by Jonas Petersen
|
||||
# Version 0.9 - 10th November 2004 - first public release
|
||||
# --------------------------------------------------------------------------
|
||||
#
|
||||
# A script that creates vertex groups from a set of envelopes.
|
||||
#
|
||||
# Envelopes are Mesh objects with names that follow the following
|
||||
# naming convention (syntax):
|
||||
#
|
||||
# <bone name>:<float value>
|
||||
#
|
||||
# All existing vertex groups of the target Mesh will be deleted.
|
||||
#
|
||||
# Find the latest version at: http://www.mindfloaters.de/blender/
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# $Id$
|
||||
# --------------------------------------------------------------------------
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2004: Jonas Petersen, jonas at mindfloaters dot de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# CONFIGURATION
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# Note: Theses values will later be editable via a gui interface
|
||||
# within Blender.
|
||||
|
||||
# SEPARATOR is the character used to delimit the bone name and the weight
|
||||
# in the envelope name.
|
||||
SEPARATOR = ":"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# END OF CONFIGURATION
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
import Blender, math, sys, string
|
||||
from Blender import Mathutils
|
||||
from Blender.Mathutils import *
|
||||
|
||||
def run(target_obj):
|
||||
target_mesh = target_obj.getData()
|
||||
|
||||
num_verts = len(target_mesh.verts)
|
||||
warn_count = 0
|
||||
main_obj_loc = Vector(list(target_obj.getLocation()))
|
||||
|
||||
Blender.Window.EditMode(0)
|
||||
|
||||
def vertGroupExist(group):
|
||||
global vert_group_names;
|
||||
for name in target_mesh.getVertGroupNames():
|
||||
if group == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def isInside(point, envl_data):
|
||||
for i in range(len(envl_data['normals'])):
|
||||
vec = point - envl_data['points'][i]
|
||||
if DotVecs(envl_data['normals'][i], vec) > 0.0:
|
||||
return False
|
||||
return True
|
||||
|
||||
envls = {}
|
||||
|
||||
Blender.Window.DrawProgressBar(0.0, "Parsing Zones")
|
||||
|
||||
# go through all envelopes and fill the 'envls' dict with points, normals
|
||||
# and weights of the box faces
|
||||
for obj in Blender.Object.Get():
|
||||
if obj.getType() == "Mesh":
|
||||
name = obj.getName()
|
||||
pos = name.find(SEPARATOR)
|
||||
if (pos > -1):
|
||||
mesh = obj.getData()
|
||||
loc = Vector(list(obj.getLocation()))
|
||||
|
||||
bone_name = name[0:pos]
|
||||
try:
|
||||
weight = float(name[pos+1:len(name)])
|
||||
except ValueError:
|
||||
print "WARNING: invalid syntax in envelope name \"%s\" - syntax: \"<bone name>:<float value>\""%(obj.getName())
|
||||
warn_count += 1
|
||||
weight = 0.0
|
||||
|
||||
envl_data = {'points': [], 'normals': [], 'weight': weight}
|
||||
for face in mesh.faces:
|
||||
envl_data['normals'].append(Vector(list(face.normal)))
|
||||
envl_data['points'].append(Vector(list(face.v[0].co)) + loc)
|
||||
|
||||
if not envls.has_key(bone_name):
|
||||
# add as first data set
|
||||
envls[bone_name] = [envl_data]
|
||||
else:
|
||||
# add insert in sorted list of data sets
|
||||
inserted = False
|
||||
for i in range(len(envls[bone_name])):
|
||||
if envl_data['weight'] > envls[bone_name][i]['weight']:
|
||||
envls[bone_name].insert(i, envl_data)
|
||||
inserted = True
|
||||
if not inserted:
|
||||
envls[bone_name].append(envl_data)
|
||||
|
||||
Blender.Window.DrawProgressBar(0.33, "Parsing Vertices")
|
||||
|
||||
assign_count = 0
|
||||
vert_groups = {}
|
||||
|
||||
# go throug all vertices of the target mesh
|
||||
for vert in target_mesh.verts:
|
||||
point = Vector(list(vert.co)) + main_obj_loc
|
||||
|
||||
vert.sel = 1
|
||||
counted = False
|
||||
|
||||
for bone_name in envls.keys():
|
||||
for envl_data in envls[bone_name]:
|
||||
|
||||
if (isInside(point, envl_data)):
|
||||
|
||||
if (not vert_groups.has_key(bone_name)):
|
||||
vert_groups[bone_name] = {}
|
||||
|
||||
if (not vert_groups[bone_name].has_key(envl_data['weight'])):
|
||||
vert_groups[bone_name][envl_data['weight']] = []
|
||||
|
||||
vert_groups[bone_name][envl_data['weight']].append(vert.index)
|
||||
|
||||
vert.sel = 0
|
||||
|
||||
if not counted:
|
||||
assign_count += 1
|
||||
counted = True
|
||||
|
||||
break
|
||||
|
||||
|
||||
Blender.Window.DrawProgressBar(0.66, "Writing Groups")
|
||||
|
||||
vert_group_names = target_mesh.getVertGroupNames()
|
||||
|
||||
# delete all vertices in vertex groups
|
||||
for group in vert_group_names:
|
||||
try:
|
||||
v = target_mesh.getVertsFromGroup(group)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
# target_mesh.removeVertsFromGroup(group) without second argument doesn't work
|
||||
#print "removing", len(v), "vertices from group \"",group,"\""
|
||||
target_mesh.removeVertsFromGroup(group, v)
|
||||
|
||||
# delete all vertex groups
|
||||
for group in vert_group_names:
|
||||
target_mesh.removeVertGroup(group)
|
||||
|
||||
# create new vertex groups and fill them
|
||||
if 1:
|
||||
for bone_name in vert_groups.keys():
|
||||
# add vertex group
|
||||
target_mesh.addVertGroup(bone_name)
|
||||
|
||||
for weight in vert_groups[bone_name]:
|
||||
print "name: ", bone_name, ": ", weight, "len: ", len(vert_groups[bone_name][weight])
|
||||
index_list = vert_groups[bone_name][weight]
|
||||
target_mesh.assignVertsToGroup(bone_name, index_list, weight, 'replace')
|
||||
|
||||
target_mesh.update(0)
|
||||
|
||||
Blender.Window.DrawProgressBar(1.0, "")
|
||||
|
||||
if assign_count < num_verts:
|
||||
Blender.Window.EditMode(1)
|
||||
print '\a'
|
||||
if warn_count: warn_msg = " There is also %d warning(s) in the console."%(warn_count)
|
||||
else: warn_msg = ""
|
||||
Blender.Draw.PupMenu("Envelope Assignment%%t|%d vertices were not assigned.%s"%(num_verts-assign_count, warn_msg))
|
||||
elif warn_count:
|
||||
print '\a'
|
||||
Blender.Draw.PupMenu("Envelope Assignment%%t|There is %d warning(s) in the console."%(warn_count))
|
||||
|
||||
sel_objs = Blender.Object.GetSelected()
|
||||
if len(sel_objs) != 1 or sel_objs[0].getType() != "Mesh":
|
||||
print '\a'
|
||||
Blender.Draw.PupMenu("Envelope Assignment%t|Please select 1 Mesh object to assign vertex groups to!")
|
||||
else:
|
||||
if string.find(sel_objs[0].getName(), SEPARATOR) > -1:
|
||||
print '\a'
|
||||
Blender.Draw.PupMenu("Envelope Assignment%t|Don't use the command on the envelopes themselves!")
|
||||
else:
|
||||
run(sel_objs[0])
|
204
release/scripts/weightpaint_envelope_assign.py
Normal file
204
release/scripts/weightpaint_envelope_assign.py
Normal file
@ -0,0 +1,204 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Envelope via Group Objects'
|
||||
Blender: 242
|
||||
Group: 'WeightPaint'
|
||||
Tooltip: 'Assigns weights to vertices via object envelopes'
|
||||
"""
|
||||
|
||||
__author__ = ["Campbell Barton"]
|
||||
__url__ = ("blender", "blenderartist.org")
|
||||
__version__ = "0.1"
|
||||
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
def intersection_data(ob):
|
||||
'''
|
||||
Takes an object and returns raw triangles and tri bounds.
|
||||
returns a list of (v1,v2,v3, xmin, ymin, xmax, ymax)
|
||||
... to be used for ray intersection
|
||||
'''
|
||||
global tot_ymin, tot_xmin, tot_ymax, tot_xmax, tot_zmin, tot_zmax
|
||||
tot_zmin = tot_ymin = tot_xmin = 100000000.0
|
||||
tot_zmax = tot_ymax = tot_xmax = -100000000.0
|
||||
|
||||
def tribounds_xy(v1,v2,v3):
|
||||
'''
|
||||
return the 3 vecs with bounds, also update tot_*min/max
|
||||
'''
|
||||
global tot_ymin, tot_xmin, tot_ymax, tot_xmax, tot_zmin, tot_zmax
|
||||
xmin = xmax = v1.x
|
||||
ymin = ymax = v1.y
|
||||
|
||||
x = v2.x
|
||||
y = v2.y
|
||||
if x>xmax: xmax = x
|
||||
if y>ymax: ymax = y
|
||||
if x<xmin: xmin = x
|
||||
if y<ymin: ymin = y
|
||||
|
||||
|
||||
x = v3.x
|
||||
y = v3.y
|
||||
if x>xmax: xmax = x
|
||||
if y>ymax: ymax = y
|
||||
if x<xmin: xmin = x
|
||||
if y<ymin: ymin = y
|
||||
|
||||
# totbounds
|
||||
for z in v1.z, v2.z, v3.z:
|
||||
if z>tot_zmax: tot_zmax = z
|
||||
if z<tot_zmin: tot_zmin = z
|
||||
|
||||
# maintain global min/max for x and y
|
||||
if xmax>tot_xmax: tot_xmax = xmax
|
||||
if xmin<tot_xmin: tot_xmin = xmin
|
||||
|
||||
if ymax>tot_ymax: tot_ymax = ymax
|
||||
if ymin<tot_ymin: tot_ymin = ymin
|
||||
|
||||
return v1,v2,v3, xmin, ymin, xmax, ymax
|
||||
|
||||
me = BPyMesh.getMeshFromObject(ob)
|
||||
|
||||
if not me:
|
||||
return []
|
||||
|
||||
me.transform(ob.matrixWorld)
|
||||
|
||||
mesh_data = []
|
||||
|
||||
# copy all the vectors so when the mesh is free'd we still have access.
|
||||
mesh_vert_cos= [v.co.copy() for v in me.verts]
|
||||
|
||||
for f in me.faces:
|
||||
f_v = [mesh_vert_cos[v.index] for v in f]
|
||||
mesh_data.append( tribounds_xy(f_v[0], f_v[1], f_v[2]) )
|
||||
if len(f) == 4:
|
||||
mesh_data.append( tribounds_xy(f_v[0], f_v[2], f_v[3]) )
|
||||
|
||||
me.verts = None # free some memory
|
||||
|
||||
return ob.name, mesh_data, tot_xmin, tot_ymin, tot_zmin, tot_xmax, tot_ymax, tot_zmax
|
||||
|
||||
from Blender import *
|
||||
ray = Mathutils.Vector(0,0,-1)
|
||||
def point_in_data(point, mesh_data_tuple):
|
||||
ob_name, mesh_data, tot_xmin, tot_ymin, tot_zmin, tot_xmax, tot_ymax, tot_zmax = mesh_data_tuple
|
||||
|
||||
Intersect = Mathutils.Intersect
|
||||
x = point.x
|
||||
y = point.y
|
||||
z = point.z
|
||||
|
||||
# Bouds check for all mesh data
|
||||
if not (\
|
||||
tot_zmin < z < tot_zmax and\
|
||||
tot_ymin < y < tot_ymax and\
|
||||
tot_xmin < x < tot_xmax\
|
||||
):
|
||||
return False
|
||||
|
||||
def isect(tri_data):
|
||||
v1,v2,v3, xmin, ymin, xmax, ymax = tri_data
|
||||
if not (xmin < x < xmax and ymin < y < ymax):
|
||||
return False
|
||||
|
||||
if v1.z < z and v2.z < z and v3.z < z:
|
||||
return False
|
||||
|
||||
isect = Intersect(v1, v2,v3, ray, point, 1) # Clipped.
|
||||
if isect and isect.z > z: # This is so the ray only counts if its above the point.
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# return len([None for tri_data in mesh_data if isect(tri_data)]) % 2
|
||||
return len( filter(isect, mesh_data) ) % 2
|
||||
|
||||
import BPyMesh
|
||||
def env_from_group(ob_act, grp, PREF_OVERWRITE=True):
|
||||
# get intersection data
|
||||
# group_isect_data = [intersection_data(ob) for ob in group.objects]
|
||||
group_isect_data = []
|
||||
for ob in grp.objects:
|
||||
if ob != ob_act: # in case we're in the group.
|
||||
gid = intersection_data(ob)
|
||||
if gid[1]: # has some triangles?
|
||||
group_isect_data.append( gid )
|
||||
|
||||
# sort by name
|
||||
group_isect_data.sort()
|
||||
|
||||
group_names = [gid[0] for gid in group_isect_data]
|
||||
|
||||
me = ob_act.getData(mesh=1)
|
||||
len_group_names= len(group_names)
|
||||
vweight_list= [[0.0]*len_group_names for i in xrange(len(me.verts))]
|
||||
|
||||
ob_act_mat = ob_act.matrixWorld
|
||||
for vi, v in enumerate(me.verts):
|
||||
# Get all the groups for this vert
|
||||
co = v.co * ob_act_mat
|
||||
for group_index, group_isect in enumerate(group_isect_data):
|
||||
if point_in_data(co, group_isect):
|
||||
vweight_list[vi][group_index] = 1.0
|
||||
|
||||
BPyMesh.list2MeshWeight(me, group_names, vweight_list)
|
||||
|
||||
|
||||
import BPyMessages
|
||||
def main():
|
||||
|
||||
scn= Scene.GetCurrent()
|
||||
ob_act = scn.objects.active
|
||||
if not ob_act or ob_act.type != 'Mesh':
|
||||
BPyMessages.Error_NoMeshActive()
|
||||
return
|
||||
|
||||
PREF_ENV_GROUPNAME= Draw.Create('')
|
||||
PREF_OVERWRITE= Draw.Create(False)
|
||||
pup_block= [\
|
||||
'Group Name',\
|
||||
('GR:', PREF_ENV_GROUPNAME, 0, 21, 'The name of an existing groups to '),\
|
||||
#('Overwrite', PREF_OVERWRITE, 'Overwrite existing vertex groups.'),\
|
||||
]
|
||||
|
||||
if not Draw.PupBlock('Envalope From Group...', pup_block):
|
||||
return
|
||||
|
||||
try:
|
||||
grp = Group.Get(PREF_ENV_GROUPNAME.val)
|
||||
except:
|
||||
Draw.PupMenu('Error%t|Group "' + PREF_ENV_GROUPNAME.val + '" does not exist.')
|
||||
return
|
||||
|
||||
PREF_ENV_GROUPNAME= PREF_ENV_GROUPNAME.val
|
||||
PREF_OVERWRITE= PREF_OVERWRITE.val
|
||||
|
||||
Window.WaitCursor(1)
|
||||
t = sys.time()
|
||||
env_from_group(ob_act, grp, PREF_OVERWRITE)
|
||||
print 'assigned envelopes in:', sys.time() - t
|
||||
Window.WaitCursor(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue
Block a user