Blender OGRE export script that fixes "warning: vertex with more than four boneassignment" error

Hi,



I’m going to finish this 3d character that I made. It’s the 3rd time I make the same character because I’v lost

the previous copy TWICE!



So now I’ll publish it for sale on a website, securing that I can get it back anytime.

But to do that I wish to convert to ogre format aswell. But I can’t because I get the error:

warning: vertex with more than four boneassignment

If I dont remember wrong, this will make those vertices unmoveable by the skelleton in jme.
So I need to fix that error.
By simply weight painting by hand is not an opption. Idk which verts causing this but there are too many to be fixed.
Also when I weight paint by hand it looks horrible and not at all smooth.

But I remember fixing this problem before. I ran some python script that fixed so that there was no more than 4 bones/vert. But now I'v
searched for 2 days the web and have not yet found it.
Any of you any idea what script I'm talking about?

P.S I run Blender 2.49 and hate the new confusing version.

there is a weight normalizer script for the 2.49 version once u install it u will see it available in the weighting tools search on google for it



edit didn’t read your message completely the python code hope that helps

[java]#!BPY

“”"

Name: ‘Normalize/Scale Weight…’

Blender: 245

Group: ‘WeightPaint’

Tooltip: ‘Normalize the weight of the active weightgroup.’

“”"



author = “Campbell Barton aka ideasman42”

url = [“www.blender.org”, “blenderartists.org”, “www.python.org”]

version = “0.1”

bpydoc = “”"



Normalize Weights



This Script is to be used only in weight paint mode,

It Normalizes the weights of the current group, to the desired peak

optionaly scaling groups that are shared by these verts so the

proportion of the veighting is unchanged.

“”"


***** BEGIN GPL LICENSE BLOCK *****

#

Script copyright © Campbell J Barton

#

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 *****



from Blender import Scene, Draw, Object, Modifier
import BPyMesh
SMALL_NUM= 0.000001

def getArmatureGroups(ob, me):

arm_obs = []

arm = ob.parent
if arm and arm.type == 'Armature' and ob.parentType == Object.ParentTypes.ARMATURE:
arm_obs.append(arm)

for m in ob.modifiers:
if m.type== Modifier.Types.ARMATURE:
arm = m[Modifier.Settings.OBJECT]
if arm:
arm_obs.append(arm)

# convert to a dict and back, should be a set! :/ - python 2.3 dosnt like.
return dict([ (bonename, None) for arm in arm_obs for bonename in arm.data.bones.keys() ]).keys()



def actWeightNormalize(me, ob, PREF_PEAKWEIGHT, PREF_ACTIVE_ONLY, PREF_ARMATURE_ONLY, PREF_KEEP_PROPORTION):

groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
new_weight= max_weight= -1.0
act_group= me.activeGroup

if PREF_ACTIVE_ONLY:
normalizeGroups = [act_group]
else:
normalizeGroups = groupNames[:]

if PREF_ARMATURE_ONLY:

armature_groups = getArmatureGroups(ob, me)

i = len(normalizeGroups)
while i:
i-=1
if not normalizeGroups in armature_groups:
del normalizeGroups


for act_group in normalizeGroups:
vWeightDictUsed=[False] * len(vWeightDict)

for i, wd in enumerate(vWeightDict):
try:
new_weight= wd[act_group]
if new_weight > max_weight:
max_weight= new_weight
vWeightDictUsed=wd
except:
pass

# These can be skipped for now, they complicate things when using multiple vgroups,
'''
if max_weight < SMALL_NUM or new_weight == -1:
Draw.PupMenu('No verts to normalize. exiting.')
#return

if abs(max_weight-PREF_PEAKWEIGHT) < SMALL_NUM:
Draw.PupMenu('Vert Weights are alredy normalized.')
#return
'''
max_weight= max_weight/PREF_PEAKWEIGHT

if PREF_KEEP_PROPORTION:
# TODO, PROPORTIONAL WEIGHT SCALING.
for wd in vWeightDictUsed:
if wd: # not false.
if len(wd) == 1:
# Only 1 group for thsi vert. Simple
wd[act_group] /= max_weight
else:
# More then 1 group. will need to scale all users evenly.
if PREF_ARMATURE_ONLY:
local_maxweight= max([v for k, v in wd.iteritems() if k in armature_groups]) / PREF_PEAKWEIGHT
if local_maxweight > 0.0:
# So groups that are not used in any bones are ignored.
for weight in wd.iterkeys():
if weight in armature_groups:
wd[weight] /= local_maxweight
else:
local_maxweight= max(wd.itervalues()) / PREF_PEAKWEIGHT
for weight in wd.iterkeys():
wd[weight] /= local_maxweight

else: # Simple, just scale the weights up. we alredy know this is in an armature group (if needed)
for wd in vWeightDictUsed:
if wd: # not false.
wd[act_group] /= max_weight

# Copy weights back to the mesh.
BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)


def main():
scn= Scene.GetCurrent()
ob= scn.objects.active

if not ob or ob.type != 'Mesh':
Draw.PupMenu('Error, no active mesh object, aborting.')
return

me= ob.getData(mesh=1)

PREF_PEAKWEIGHT= Draw.Create(1.0)
PREF_ACTIVE_ONLY= Draw.Create(1)
PREF_KEEP_PROPORTION= Draw.Create(1)
PREF_ARMATURE_ONLY= Draw.Create(0)

pup_block= [
('Peak Weight:', PREF_PEAKWEIGHT, 0.01, 1.0, 'Upper weight for normalizing.'),
('Active Only', PREF_ACTIVE_ONLY, 'Only Normalize groups that have matching bones in an armature (when an armature is used).'),
('Proportional', PREF_KEEP_PROPORTION, 'Scale other weights so verts (Keep weights with other groups in proportion).'),
('Armature Only', PREF_ARMATURE_ONLY, 'Only Normalize groups that have matching bones in an armature (when an armature is used).'),
]

if not Draw.PupBlock('Clean Selected Meshes...', pup_block):
return

actWeightNormalize(me, ob, PREF_PEAKWEIGHT.val, PREF_ACTIVE_ONLY.val, PREF_ARMATURE_ONLY.val, PREF_KEEP_PROPORTION.val)

if __name__=='__main__':
main()[/java]
1 Like

Incredible! I found it!!

Thanks mcbeth!



Heres the code:

[xml]

TLW_LimitBoneCount.py, python script for Blender 2.49b

Normalizes bone vertex weights and removes bone weights when the influence count exceeds

MAX_BONESPERVERTEX (i.e. most game engines have a limit of 4 bones per vertex)

Vertices that belong to groups which aren’t bones are left untouched.


# HOW TO USE:
# Select an object that has an active armature modifier. Load this script in the text editor
# from Blender, and press Alt+P to turn the script. Modify MAX_BONESPERVERTEX below to change
# the threshold

MAX_BONESPERVERTEX = 4

# TLW_LimitBoneCount.py, python script for Blender 2.49b
# Copyright (C) 2011 Matias N. Goldberg ("dark_sylinc")
#
# 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 3 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, see <http://www.gnu.org/licenses/>.

import Blender
from Blender import *
from bpy import *

editmode = Window.EditMode() # are we in edit mode? If not so ...
if editmode: Window.EditMode(0) # leave edit mode before getting the mesh

#Iterates through the modifier stack to get the armature. Assumes it has
#only one armature modifier (otherwise the first seen is taken)
def getArmature( obj ):
mods = obj.modifiers
for mod in mods:
if mod.type == Modifier.Types.ARMATURE:
return mod[Modifier.Settings.OBJECT].getData()
return 0

class GroupData:
def __init__( self, weight, groupName ):
self.weight = weight
self.groupName = groupName

#Helper container to organize those objects without parent but are instanced.
for obj in Object.GetSelected():
armature = getArmature( obj )

md = obj.getData( False, True )

for vertex in md.verts:
vertexGroup = []
for groupName in md.getVertGroupNames():
try:
weight = md.getVertsFromGroup( groupName, True, [vertex.index] )[0][1]
except IndexError:
# vertex not in group groupName
pass
else:
#print type( armature.bones.keys() )
try:
armature.bones[ groupName ]
except KeyError:
# Group name doesn't refer to a bone in the armature
pass
else:
vertexGroup.append( GroupData( weight, groupName ) )

if( len( vertexGroup ) > MAX_BONESPERVERTEX ):
print 'Vertex with more than ', MAX_BONESPERVERTEX, ' bones found, collapsing bones with lowest weights'

#Sort it, lower weights first
vertexGroup = sorted( vertexGroup, key=lambda groupData: groupData.weight )
for groupData in vertexGroup:
#Remove the extra bones
md.removeVertsFromGroup( groupData.groupName, [vertex.index] )
vertexGroup.pop(0)
if( len( vertexGroup ) < MAX_BONESPERVERTEX ):
break

#Normalize weights for ALL vertices (not just the ones that have more bones than usual)
weightSum = 0
for groupData in vertexGroup: weightSum += groupData.weight
for groupData in vertexGroup:
groupData.weight /= weightSum
md.assignVertsToGroup( groupData.groupName, [vertex.index], groupData.weight, Mesh.AssignModes.REPLACE )

#Enter and leave edit mode to refresh the changes
Window.EditMode(1)
Window.EditMode(0)

print 'Normalizing vertex weights and removing extra bone influences finished.'
[/xml]
Found here:
http://www.ogre3d.org/forums/viewtopic.php?f=8&t=64887

THERE!
Now I will never forget this again :P

Is there something like this for Blender 2.63?