Salut la french,
Aujourd'hui je reviens avec un problème xpresso pour lequel vous aurez 2 sujets au choix. La calculatrice et un pack de bière sont autorisés.
Un arbre doit osciller suivant un axe de rotation variable.
Sujet 1 :
je souhaite déplacer l'axe d'un objet via xpresso afin de pouvoir contrôler son axe de rotation via xpresso et une donnée utilisateur, comment fais-je ?
Sujet 2 :
Comme vous n'arrivez pas à faire le sujet 1, comment attribuer un parent (A, B, ou C) via xpresso et une donnée utilisateur à un objet de manière à affecter sa rotation ?
Vous avez 2 jours.
Je viens d'essayer une solution qui semblait prometteuse mais qui est partie en cacahuète :
mes repères ABC on une contrainte (personnage) au cube, mon cube à trois contraintes à A,B et C. je bouge le cube les repères bougent avec, je sélectionne l'un autre des repères le cube bouge conformément aux repère sélectionnés.
Bon ça me va à peu, je dis à peu près car on sent bien que le procédé pète les élastiques après quelques manipulations un peu fortes. Les mouvements semblent soudain appliqués en mode multiplication à tel point que mon objet se retrouve en y -5000, les repères perdent peu à peu leur position d'origine.
Pire à chaque clic souris sans manipulation sur les repère dans la scène ou dans le GO, C4D fait un refresh et ça bouge tout seul de quelques pixels. Donc début de piste, mais pas encore une vraie solution…
Dernière modification par iolofato ; 21/06/2014 à 08h22.
idem, je suis parti sur une même piste et en récupérant les positions de ABC via Xpresso, et le noeud mélange, j'ai bien pu piloter le B afin qu'il se place à X% entre entra A et B.. maintenant ce que je n'arrive pas à faire, c'est de placer l'axe du cube aux coordonnées de B afin que si je tourne B ( mis en contrainte ), le cube tourne en fonction de B.
Il faudrait un moyen de changer dynamiquement l'axe d'un objet via XPresso, mais ça je ne sais pas faire
kenavo !! // Pinterest KAMIGAZ®
Salut Aurety,
Merci pour tes essais, et en effet l'idéal serait de pouvoir bouger dynamique l'axe, ce que je souhaitais en première lieu mais j'ai rien trouvé ou alors si mais sur un forum english ou le gars s'emmêlait les pinceaux dans ces explications. Je suis parti sur ces histoires de parents mais ça par en live, en fait il faudrait à défaut de pouvoir déplacer dynamiquement l'axe, ou au moins pouvoir activer/désactiver le parent. Histoire que les 2 autres non utilisés viennent pas polluer le calcul…
Salut,
Un exemple d'axes controlés par Xpresso : http://www.xsyann.com/fc4d/axis_xpresso.c4d
Pour un script / plugin :Code PHP:
def setAxis(obj, m):
"""Set obj axis to Matrix m.
"""
inv = ~m * obj.GetMg()
for i, point in enumerate(obj.GetAllPoints()):
obj.SetPoint(i, point * inv)
obj.Message (c4d.MSG_UPDATE)
obj.SetMg(m)
Bonne journée.Code PHP:
def setAxis(obj, m):
"""Set object axis to Matrix m.
"""
doc.StartUndo()
inv = ~m * obj.GetMg()
for i, point in enumerate(obj.GetAllPoints()):
doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)
object.SetPoint(i, point * inv)
doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)
obj.Message (c4d.MSG_UPDATE)
obj.SetMg(m)
doc.EndUndo()
En bonus le sujet 2 : http://www.xsyann.com/fc4d/parent_switch.c4d
En gros t'as un noeud python où tu lui passe le parent que tu veux, l'enfant et la liste des parents (pour ranger l'ancien parent).
Y'a une DU de type lien sur le Null Xpresso pour choisir le parent.
Il faut juste faire attention à ne pas impliquer l'objet avec l'Xpresso dans le processus (un objet porteur d'Xpresso n'aime pas se supprimer lui même).
Les étapes illustrées sur une pseudo hiérarchie :
Code:Parents - parent.1 - parent.2 default - object ———————————— child.Remove() Parents - parent.1 - parent.2 default ———————————— child.InsertAfter(oldParent) Parents - parent.1 - parent.2 default object ———————————— oldParent.Remove() Parents - parent.1 - parent.2 object ———————————— oldParent.InsertUnder(parents) Parents - default - parent.1 - parent.2 object ———————————— parent.Remove() Parents - default - parent.2 object ———————————— parent.InsertBefore(child) Parents - default - parent.2 parent.1 object ———————————— child.Remove() Parents - default - parent.2 parent.1 ———————————— child.InsertUnder(parent) Parents - default - parent.2 parent.1 - object
Dernière modification par xs_yann ; 21/06/2014 à 14h06.
J'ai une calculatrice mais j'ai oublié le pack de bière à la maison, c'est possible de s'en faire prêter un ?
-
Une dernière solution, un peu un mix des deux, c'est de contrôler l'axe d'un null parent (ça permet de ne pas être limité à un objet polygonal).
Le principe est le même que pour bouger l'axe (où l'on bouge l'objet et ensuite tout ses points en sens inverse). Ici on bouge le null à la position cible et on applique la translation inverse aux enfants du null pour qu'ils conservent leur position :
http://www.xsyann.com/fc4d/null_axis_xpresso.c4dCode PHP:
import c4d
def setNullAxis(null, m):
"""Set null axis to Matrix m.
"""
inv = ~m * null.GetMg()
for child in null.GetChildren():
child.SetMg(child.GetMg() * inv)
null.Message (c4d.MSG_UPDATE)
null.SetMg(m)
def main():
global Source
global Matrix
source, matrix = Source, Matrix
if source.CheckType(c4d.Onull):
setNullAxis(source, matrix)
Salut xs_Yann,
Merci je suis tout bête devant tant de code merci pour ton investissement. C'est dans ces situations où je vois clairement où mes compétence s'arrêtent .
Par contre je crois que je me suis mal expliqué, voici une vidéo de la solution trouvée avec contrainte personnage, c'est gégène mais c'est exactement ce dont j'ai besoin, l'inertie liée à la priorité en moins et le démarrage en vrille dès qu'on est extrême. En gros ma solution sur le fond ça fonctionne mais ce n'est ni stable ni fiable :
- un bête clic sur les objets dans le GO fait un refresh sur la scène et les objets bougent tous seuls
- impossible d'enregistrer des images clés, l'animation part en live
www.3zigs.com/download/frenchc4d/Change-parent-contrainte.mov
J'ajoute le fichier c4d de test
https://dl.dropboxusercontent.com/u/...est-parent.zip
Salut,
Je crois avoir un peu mieux compris.
La démo :
Il y a peut-être plus simple, mais c'est un très bon exercice de calcul matriciel.
Le principe :
- Bouger l'axe de l'objet aux coordonnées du contrôleur sélectionné
- Appliquer les transformations du contrôleur à l'objet (rotation, position, etc...)
- Appliquer la même transformation aux autres contrôleurs comme s'ils étaient enfant du contrôleur sélectionné
obj : l'objet à contrôlerCode:multiControllers(doc, obj, controllers, lockControllers)
controllers : la liste des contrôleurs
lockControllers : True pour verrouiller la position des contrôleurs
http://www.xsyann.com/fc4d/multicontroller_python.c4dCode PHP:
import c4d
def infantilize(child, parent, previousMatrix):
"""Position 'child' as if it was a child of 'parent'.
'previousMatrix' is the previous position of the parent.
"""
parentMg = parent.GetMg()
deltaMatrix = ~previousMatrix * parentMg
# Put child in parent local space
child.SetMg(~parentMg * child.GetMg())
# Rotation matrix = delta matrix without offset
deltaRotMat = c4d.Matrix(c4d.Vector(), deltaMatrix.v1, deltaMatrix.v2, deltaMatrix.v3)
childMg = deltaMatrix * child.GetMg() # Child Rotation
childMg.off = (child.GetMg().off * deltaRotMat) + deltaMatrix.off # Child Position
child.SetMg(childMg)
# Put child in global space
child.SetMg(parentMg * child.GetMg())
def setParentPos(parent, pos):
"""Set 'parent' position to 'pos' without moving children.
"""
mov = pos - parent.GetMg().off
for child in parent.GetChildren():
childMg = child.GetMg()
childMg.off -= mov
child.SetMg(childMg)
mg = parent.GetMg()
mg.off = pos
parent.SetMg(mg)
def multiControllers(doc, obj, controllers, lockControllers):
"""Allow obj to be controlled by 'controllers' list.
"""
activeController = doc.GetActiveObject()
if not activeController or not activeController in controllers:
return
# Move obj axes if a new controller is selected or if lockControllers is False
# Otherwise move the object
# GetAllBits is used to avoid an undo bug on BaseObject.__eq__
stored, active = multiControllers.current, activeController
if (stored and stored.GetAllBits() != active.GetAllBits() and stored.GetMg() != active.GetMg()) or not lockControllers:
setParentPos(obj, activeController.GetMg().off)
multiControllers.current = activeController
previousMatrix = obj.GetMg()
obj.SetMg(activeController.GetMg())
# Make the others controllers follow the transformation
for controller in controllers:
if controller != activeController:
infantilize(controller, activeController, previousMatrix)
multiControllers.current = None
def main():
obj = op.GetObject()
axisListUD = op[c4d.ID_USERDATA,1]
lockControllers = op[c4d.ID_USERDATA,2]
controllers = []
for i in xrange(axisListUD.GetObjectCount()):
controllers.append(axisListUD.ObjectFromIndex(doc, i))
if controllers:
multiControllers(doc, obj, controllers, lockControllers)
Une autre version, sans bouger les axes d'origine de l'objet.
http://www.xsyann.com/fc4d/multicontroller_python1.c4d
Ici au lieu de faire :Code PHP:
import c4d
def infantilize(child, parent, previousMatrix, pos=True):
"""Position 'child' as if it was a child of 'parent'.
'previousMatrix' is the previous position of the parent.
"""
parentMg = parent.GetMg()
if not pos:
parentMg.off = previousMatrix.off
deltaMatrix = ~previousMatrix * parentMg
# Put child in parent local space
child.SetMg(~parentMg * child.GetMg())
# Rotation matrix = delta matrix without offset
deltaRotMat = c4d.Matrix(c4d.Vector(), deltaMatrix.v1, deltaMatrix.v2, deltaMatrix.v3)
childMg = deltaMatrix * child.GetMg() # Child Rotation
childMg.off = (child.GetMg().off * deltaRotMat) + deltaMatrix.off # Child Position
child.SetMg(childMg)
# Put child in global space
child.SetMg(parentMg * child.GetMg())
def multiControllers(doc, obj, controllers, lockControllers):
"""Allow obj to be controlled by 'controllers' list.
"""
activeController = doc.GetActiveObject()
if not activeController or not activeController in controllers:
return
# Move obj axes if a new controller is selected or if lockControllers is False
# Otherwise move the object
# GetAllBits is used to avoid an undo bug on BaseObject.__eq__
stored, active = multiControllers.current, activeController
if (stored and (stored.GetAllBits() == active.GetAllBits() or stored.GetMg() == active.GetMg())):
if multiControllers.currentMat:
infantilize(obj, activeController, multiControllers.currentMat, lockControllers)
# Make the others controllers follow the transformation
for controller in controllers:
if controller != activeController:
infantilize(controller, activeController, multiControllers.currentMat, lockControllers)
multiControllers.current = activeController
multiControllers.currentMat = activeController.GetMg()
multiControllers.current = None
multiControllers.currentPos = None
def main():
obj = op.GetObject()
axisListUD = op[c4d.ID_USERDATA,1]
lockControllers = op[c4d.ID_USERDATA,2]
controllers = []
for i in xrange(axisListUD.GetObjectCount()):
controllers.append(axisListUD.ObjectFromIndex(doc, i))
if controllers:
multiControllers(doc, obj, controllers, lockControllers)
- Bouger l'axe de l'objet aux coordonnées du contrôleur sélectionné
- Appliquer les transformations du contrôleur à l'objet (rotation, position, etc...)
- Appliquer la même transformation aux autres contrôleurs comme s'ils étaient enfant du contrôleur sélectionné
on fait :
- Appliquer la transformation du contrôleur à l'objet comme s'il était enfant du contrôleur
- Appliquer la transformation aux autres contrôleurs comme s'ils étaient enfants du contrôleur sélectionné
edit : C'est pas très animable étant donné que je me base sur l'objet actif pour connaître le contrôleur courant... Y'a des corrections à faire...
Dernière modification par xs_yann ; 22/06/2014 à 21h18.
Salut xs_yann,
un vrai grand merci pour ton aide, et le temps passé. Je ne pensais pas que cela demanderait autant de code pour obtenir cette fonction. J'étais persuadé qu'il y avait un nœud xpresso ou pour le moins une combinaison qui permettait de le faire .
En tout cas je teste l'avant dernière version et ça colle tout à fait
Par contre je viens de constater que c'était pas animable dans la timeline, dès qu'on met des images clé y a plus rien qui fonctionne c'est ce que tu sous entend dans "C'est pas très animable étant donné que je me base sur l'objet actif pour connaître le contrôleur courant... Y'a des corrections à faire…"
Si ça te prend trop de temps laisse tomber je ferai une anim à l'os
ah ah je viens de trouver une solution… toute faite… merci Nitro :
http://nitro4d.com/blog/freebie/easy-parent/
Je testerai ça ce soir mais ça me semble coller merci encore pour vos réponses, je vous tiens au jus pour confirmer que ça fonctionne ;-)
Alors voilà La solution de Nitro fonctionne, c'est pas la panacée mais c'est stable et ça sera amplement suffisant pour mon animation. Je vous en mettrai une tranche courant de journée.
Ceci dit ça met en lumière une sacrée lacune dans c4d, un "bête" nœud axis serait pas de trop là