Skocz do zawartości

Mirror weights


Temporal

Rekomendowane odpowiedzi

Da sie w blenderze, tak jak w maxie zmirrorowac wagi z jednej strony na druga? Wiem, ze moge pokopiowac grupy i pozniej zrobic mirrora, ale chcialbym szybciej bez takich zabaw. Przyjmujemy ze tworzylem wagi bez wlaczonego mirror X, wiec malowalem wagi tylko po jednej stronie majac gdzies druga. Skonczlem cala lewa strone symetrycznego modelu i teraz chcialbym za pomoca jakies funkcji skopiowac to na prawa. Jest funkcja mirror ktora przerzuca nam z jednej strony na druga, co wiaze sie wlasnie z kopiowaniem wszystkich wag. Oczywiscie wszystkie kosci mam ponazywane wedlug schematu XXXX.L i XXXX.R

Odnośnik do komentarza
Udostępnij na innych stronach

  • Odpowiedzi 7
  • Created
  • Ostatniej odpowiedzi

Top Posters In This Topic

Nie znalazłem takiej opcji, ani w standardzie ani w addonie. Dziwne, to musi być częsty problem. Za to mam trick który ci usprawni proces.

 

Załóżmy że malowałeś Lewą stronę.

1. Zduplikuj obiekt gdzieś obok.

2. Na duplikacie odpal Mirror Weights z opcjami: All Groups i Flip names.

Zmirroruje ci wszystkie wagi i przeniesie na grupy z Rką. Teraz tylko musisz połączyć grupy z obu obiektów.

3. Nadal na duplikacie. Kasujesz manualnie (niestety..) wszystkie grupy z Lką, bo je już masz namalowane na bazowym obiekcie.

4. Zaznaczasz duplikat a oryginał zaznaczasz jako ostatni (active). Odpalasz Transfer Weights z opcją Vertex Index.

 

Przetestuj ten transfer. Możliwe że obejdzie się bez kasowania rzeczy. Nie wiem.

Edytowane przez Monio
Odnośnik do komentarza
Udostępnij na innych stronach

@Monio no nawet to jest jakis pomysl, dzieki.

@Zuorion zerowa sila robi to, ze nic nie robi. Trzeba dac jakas minmalna wartosc ponad zero, w niektorych przypadkach dziala pieknie, w innym jakimims cudem drastycznie zmienia kolor/wage na obu stronach. Coz... chyba najlepiej jednak wyrobic sobie nawyk, by na starcie miec wlaczony mirror X i malowac/przypisywac wagi rownolegle na obu stronach.

Odnośnik do komentarza
Udostępnij na innych stronach

Może i działa ale nie rozumiem jaki to ma sens. Temporal musiałby z osoba zaznaczyć każdą grupę i obmalować cały model. Nadal jest szansa na artefakty. Prościej zaznaczyć każdą grupę i dwoma klikami ją skopiować i zmirrorować. Można to jeszcze sobie przyśpieszyć n-razy z tym moim patentem z paru postów wyżej.

Odnośnik do komentarza
Udostępnij na innych stronach

Nawyk dobra rzecz, ale czasem trzeba jakoś wybrnąć, szkoda, że nie można tego w standardzie zrobić na wielu vertex grupach. Ten skrypt poniżej był niezły i powinien nadal działać w B 2.72. (o tyle fajny, że można wybrać oś lokalną) Źródło: http://blenderartists.org/forum/showthread.php?272153-Copy-and-Mirror-Weight-vertex Poza tym z tego co przeglądam moje zakładki odnośnie wag to był jeszcze płatny addon http://blog.machinimatrix.org/sparkles/smart-mirror-weight-copy/ z dodatkowym algorytmem, ale tego nie używałem nigdy, bo skrypt poniżej mi wystarczył. Testuj ostrożnie, ale powinien działać, wprowadzałem kiedyś jakieś modyfikacje w tym kodzie albo jego starszej wersji na własny użytek, ale nie mogę już odnaleźć pliku.

 

import bpy, bmesh
import datetime
from bpy.props import *
from bpy.types import Operator, Panel

def copy_mirror_weight(Axis,Way,Pattern,special_pattern,left_side,right_side,tolerance):
   start = (datetime.datetime.now())
   print('start')


   #items = [('4', '_l and _r', '4'),('3', '_L and _R', '3'),('2', '.l and .r', '2'),('1', '.L and .R', '1')])
   L_side=''
   R_side=''
   ori_side=''
   dest_side=''

   if Pattern=='1':
       L_side='.L'
       R_side='.R'     
   if Pattern=='2':
       L_side='.l'
       R_side='.r' 
   if Pattern=='3':
       L_side='_L'
       R_side='_R'
   if Pattern=='4':
       L_side='_l'
       R_side='_r' 

   if special_pattern==True:
       ori_side=left_side
       dest_side=right_side 

   obj = bpy.context.active_object
   mesh = bpy.data.objects[obj.name].data.name

   x_multiply = 1
   y_multiply = 1
   z_multiply = 1

   if Axis == 'X':
       axis_num = 0
       x_multiply = -1
   if Axis == 'Y':
       axis_num = 1
       y_multiply = -1
   if Axis == 'Z':
       axis_num = 2
       z_multiply = -1


   ## create the dict for the groups attache the index to the name
   DictGroup = {} ##ask the index it will give you the name
   DictGroupINV = {} ## ask the name, it will give you the index
   i=0
   for group in bpy.context.active_object.vertex_groups:
       DictGroup[i]=group.name
       i+=1

   for item in DictGroup:
       DictGroupINV[DictGroup[item]]=item


   #for each vertices of the mesh
   DictVertexOri = {}
   DictVertexDest = {}
   DictMirror = {}
   L_side_count = 0
   R_side_count = 0
   for vertex in bpy.data.meshes[mesh].vertices:
       #create the dicts for the good side
       #print (vertex.co[axis_num])
       if (vertex.co[axis_num]>tolerance and Way=='normal') or (vertex.co[axis_num]            
           DictVertexOri[vertex.index]=vertex.co

       #create the dicts for the mirror side
       if (vertex.co[axis_num]-tolerance and Way=='reverse'):#compare with the tolerance and position of the origin
           #print("MIRROR")
           DictVertexDest[vertex.index]=vertex.co

   for vertex in DictVertexOri:      

       for groups in bpy.data.meshes[mesh].vertices[vertex].groups: #when it's the automatic pattern, it checks the most used on the original side .L or .R and assign them after

           if obj.vertex_groups[groups.group].name.find(L_side)>-1:
               L_side_count+=1
           if obj.vertex_groups[groups.group].name.find(R_side)>-1:
               R_side_count+=1

       if L_side_count>R_side_count and special_pattern==False:
           ori_side=L_side
           dest_side=R_side    
       if R_side_count>L_side_count and special_pattern==False:        
           ori_side=R_side
           dest_side=L_side    


       vertexCoXOri = DictVertexOri[vertex][0]
       vertexCoYOri = DictVertexOri[vertex][1]
       vertexCoZOri = DictVertexOri[vertex][2]

       for vertexMirror in DictVertexDest: #check the coordinates of each axis, the multiply is inversing the mirror axes from -x.xxxx to x.xxxx so that the side doesn't matter
           if vertexCoXOri-tolerance                if vertexCoYOri-tolerance                    if vertexCoZOri-tolerance                        DictMirror[vertex]=vertexMirror



   for vertex in DictMirror:
       myGroupVertex = {}
       myMirrorGroupVertex = {}
       for groups in bpy.data.meshes[mesh].vertices[vertex].groups:
           myGroupVertex[groups.group] = groups.weight #create a dictionary nameGroup = weight

           for OneGroup in myGroupVertex: #create a new dictionnary with the name mirror
               if obj.vertex_groups[OneGroup].name.find(ori_side)>-1:
                   mirror_normal_group_name = obj.vertex_groups[OneGroup].name.replace(ori_side,dest_side)
                   if mirror_normal_group_name in DictGroupINV:
                       myMirrorGroupVertex[DictGroupINV[mirror_normal_group_name]] = myGroupVertex[OneGroup]
                   else:
                       #if this group doesn't exist yet add it to the group and the dictionnary                                                    
                       length=len(DictGroup)
                       bpy.context.active_object.vertex_groups.new(name=mirror_normal_group_name)
                       DictGroup[length] = mirror_normal_group_name
                       DictGroupINV[mirror_normal_group_name]=length


               if obj.vertex_groups[OneGroup].name.find(dest_side)>-1:
                   mirror_normal_group_name = obj.vertex_groups[OneGroup].name.replace(dest_side,ori_side)
                   if mirror_normal_group_name in DictGroupINV:
                       myMirrorGroupVertex[DictGroupINV[mirror_normal_group_name]] = myGroupVertex[OneGroup]
                   else:
                       #if this group doesn't exist yet add it to the group and the dictionnary                                                    
                       length=len(DictGroup)
                       bpy.context.active_object.vertex_groups.new(name=mirror_normal_group_name)
                       DictGroup[length] = mirror_normal_group_name
                       DictGroupINV[mirror_normal_group_name]=length


               if obj.vertex_groups[OneGroup].name.find(ori_side)==-1 and obj.vertex_groups[OneGroup].name.find(dest_side)==-1:
                   myMirrorGroupVertex[OneGroup] = myGroupVertex[OneGroup]


       ##remove the older group
       for group in bpy.data.meshes[mesh].vertices[DictMirror[vertex]].groups:
           print(DictGroup[group.group])
           print(DictMirror[vertex])
           obj.vertex_groups[DictGroup[group.group]].remove([DictMirror[vertex]])


       #add the new ones
       for OneGroupVertex in myMirrorGroupVertex.keys():
           obj.vertex_groups[DictGroup[OneGroupVertex]].add([DictMirror[vertex]],myMirrorGroupVertex[OneGroupVertex],'REPLACE')




   print('end')
   end = (datetime.datetime.now())
   timing = end-start
   print(timing)

def window_mirror(): 
   class DialogOperator(bpy.types.Operator):
       bl_idname = "object.dialog_operator"
       bl_label = "Copy Mirror Weight - WARNING USE LOCAL AXES"

       enum_Axis = EnumProperty(name="On Which Axis?", default='X',
           items = [('Z', 'Z axis', 'Z'),('Y', 'Y axis', 'Y'),('X', 'X axis', 'X')])

       enum_Way = EnumProperty(name="Which Way?", default='normal',
           items = [('reverse', '(-) to (+)', 'reverse'),('normal', '(+) to (-)', 'normal')])

       enum_Pattern = EnumProperty(name="Which Pattern?", default='1',
           items = [('4', '_l and _r', '4'),('3', '_L and _R', '3'),('2', '.l and .r', '2'),('1', '.L and .R', '1')])

       special_pattern = BoolProperty(name="or... Use my own patter")      

       left_side = StringProperty(name="My own Patter, Left Side",default=".Left")
       right_side = StringProperty(name="My own Patter, Right Side",default=".Right")

       tolerance = FloatProperty(name="Tolerance", min=0, max=100, precision=3, default=0.001)


       def execute(self, context):
           copy_mirror_weight(self.enum_Axis,self.enum_Way,self.enum_Pattern,self.special_pattern,self.left_side,self.right_side,self.tolerance)
           return {'FINISHED'}

       def invoke(self, context, event):
           return context.window_manager.invoke_props_dialog(self)


   bpy.utils.register_class(DialogOperator)

   # Invoke the dialog when loading
   bpy.ops.object.dialog_operator('INVOKE_DEFAULT')

window_mirror()

Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się



×
×
  • Dodaj nową pozycję...

Powiadomienie o plikach cookie

Wykorzystujemy cookies. Przeczytaj więcej Polityka prywatności