Hello
Je vais récupérer une séquence de nuages de points, et il faut que je transforme ça en une séquence de maillage animé.
Alors transformer un nuage de point en maillage, avec meshlab je sais faire.
Lire une séquence de nuage de point dans C4D, je sais faire.
Mais transformer une séquence de nuages de points, en séquence de maillage animé !
Est ce qu'il y en a parmi vous qui aurai des idées pour faire ça efficacement.
Le format de départ est .xyz, c'est à dire de simples fichier texte numéroté.
Ce sont des données de type terrain ce qui peu un peu faciliter les choses.
Un de mes principaux objectifs en programmation est justement de trianguler un nuage de points, car ça ouvrirait plein de possibilités de modules super intéressants !
Concrètement : un nuage de point en diagramme de Voronoï suivi d'une triangulation de Delaunay. Mais le bloque sur l'algo et ne trouve pas d'explication vraiment claire sur internet, ou alors c'est qu'en 2D.
Bref, ça ne t'aide pas, mais le sujet m'intéresse grandement. ^^
Est ce que tu connais qhull.
C'est une librairie en c sur le sujet.
Sinon de mon coté je creuse. C'est pas si simple. Enfin, si j'ai pas envie de me cogner la conversion manuellement des centaines de fichiers !
Et j'ai pas envie
Les différentes piste.
recuperer les datas dans x-particles et utilser son mesher. Mais je sais pas comment !
importer les datas dans realflow qui peu lire des fichiers au format asc. de là générer la sequence de mesh.
Mais apparement ca nécessite l'ecriture d'un script.
Je pense qu'avec houdini il doit aussi y avoir moyen.
Sinon je me suis rendu compte que les datas son sous forme de grille (mais il faut que je me fasse confirmer la cohérence de l'ordre des points au long de la squence).
du coup ça peu être plus simple. l'idée serait de convertir le fichier xyz en un simple bitmap avec le y en niveau de gris.
en faire un "height field", que je pourrai lire comme une simple sequence animée avec displace deformer sur un plan
Apres c'est plus qu'une histoire de calage de la grille en x et z.
Dernière modification par Floc ; 08/11/2016 à 00h19.
@ César : si jamais il y a une bibliothèque C++ qui à l'air de faire ce genre de truc : CGAL avec des exemples plus liés à la reconstruction 3D. Il y a un "bindings" python que je n'ai jamais réussi à installer correctement (c'est un des trucs qui me donne envie de me remettre au c++).
@ Floc : pour ton problème, si c'est bien des fichiers xyz de type terrain, le script ci-dessous devrait t'importer un modèle. Après pour le problème d'animation, ce ne serait pas trop dur d'adapter le script pour pour que les points se mettent à jour à chaque frame, ou si ce n'est pas un terrain faire des particules ...
Code PHP:
import c4d
def main():
#fn = '/Users/donzeo/Documents/Mandats/Nyon/SIG/test_mnt.xyz'
fn = c4d.storage.LoadDialog()
if not fn : return
#Recuperation des POINTS
pts = []
with open(fn) as f :
for l in f:
x,y,z =[float(val) for val in l.split()]
#attention dans c4d le y=z et et z=y
pt = c4d.Vector(x,z,y)
pts.append(pt)
#POLYGONES
#calcul du nombre de colonne
#on prend la valeur z du premier point...
z_pred = pts[0].z
nb_colonnes = 0
for pt in pts[1:]:
#...tant qu'on a la même valeur z on incrémente...
if pt.z == z_pred: nb_colonnes+=1
#...sinon on quitte la boucle
else: break
#nombre de lignes
nb_lignes = (len(pts)/(nb_colonnes+1))-1
nb_polygones = nb_lignes *nb_colonnes
doc.StartUndo()
#créataion de l'objet polygonal
poly = c4d.PolygonObject(len(pts),nb_polygones)
poly.SetAllPoints(pts)
# double boucle pour le calcul des polygones
id_poly = 0
for i in xrange(nb_lignes):
for n in xrange(nb_colonnes):
a = i*(nb_colonnes+1) + n
b = a+1
c = b+(nb_colonnes+1)
d = c-1
poly.SetPolygon(id_poly,c4d.CPolygon(a,b,c,d))
id_poly+=1
poly.Message(c4d.MSG_UPDATE)
doc.InsertObject(poly)
doc.AddUndo(c4d.UNDOTYPE_NEW,poly)
doc.EndUndo()
c4d.EventAdd()
if __name__=='__main__':
main()
Dernière modification par oli_d ; 08/11/2016 à 05h43.
wow, merci beaucoup.
C'est bien un sorte de terrain, mais en evolution, d’après des données scientifique.
Alors ça marche mais les polygones ne sont pas créés.
Pourtant la boucle des polys passe bien. ils sont juste pas créés, ou pas visible je sais pas.
Pour l'animation il vaudrait mieux utiliser un python generator non ?
Merci Oli_D, je vais regarder ça !
ok ça marche.
Le problème venait de la boucle qui calcule le nombre de colonne.
En fait dans mon fichier c'est d'abord les colonnes. Donc j'ai juste modifié pour chercher en x plutot qu'en z.
Bien cool au passage l'astuce.
Et 2 à 3s pour des fichiers de 410000pts, c'est assez rapide je trouve. Je pensai que ça ramerai plus.
Merci encore oli_d
Cesar la ça fonctionne car les points sont plus ou moins rangé
Pour du delaunay j'avais regardé cette vidéo il y à quelque temps https://www.youtube.com/watch?v=tWf1z9i-ORg ça explique pas trop mal et c'est "facilement" adaptable à de la 3D. En tout cas c'est cl'air qu'avoir un système de retriangulation à la volé serais top !
SDK Specialist
MAXON Computer GmbH
Salut Floc
il n'est pas donne mais LazPoint de Paul Everett est dédie a la gestion et au rendu des nuages de points… mais ne semble pas générer de mesh (?)
sinon, il y a Thinkbox Sequoia qui semblerait faire ça… apres pour animer (en morph j'imagine ?) ça risque d'être tricky sur le nombre et la correspondance des points ...
a suivre ...
Hello
J'ai adapté le script (qu'avait généreusement fourni Oli_D plus haut), dans un PythonTag, pour pouvoir lire une sequence xyz.
Ca marche parfaitement sauf que bizarement si j'essaye de faire un rendu via le pictureViewer à la frame disons 500, C4D relis toutes les frames. Dans le viewport ce n'est pas le cas et si j'en fais un rendu, il n'y a pas de souci. Avec un petit objet ce n'est pas tres grave, mais avec le fichier que j'ai et à la frame 1000 ca prend 5 bonnes minutes.
J'ai donc fait un export alembic et je m'en sors comme ça, mais je serai quand même curieux de savoir pourquoi le tag force C4D a relire toute la timeline uniquement dans un rendu via pictureViewer.
Je joins le fichier, (qui peu aussi dépanner si quelqu'un a besoin de lire une sequence de point a partir d'un fichier texte).
Si vous lancez un rendu à la frame 7, le mesh etant tres leger, en apparence pas de souci, mais si vous ouvrez la console vous verrez que C4D a bien relu toutes les frames.
xyz_seq_importer.zip
Pas sur qu'avec un tag tu puisse palier ce problème. En gros c4d à un système de cache très puissant. Hors quand tu modifies un objet via un tag(ce qui est as proscrire sois dis en passant).Tu ne re-écrit pas le cache de l'objet. Mais il recalcule tout.
Du coup en enregistrant ton propre objet je pense que ça devrais fonctionner.
Après je me trompe peux être mais je testerais si tu veux quand j'aurais un peu de temps.
SDK Specialist
MAXON Computer GmbH
Ne t'embete pas, c'est plus pour ma "culture personelle". Apres convertion en alembic il n'y a plus de souci.
Mais merci quand même.
Mais alors du coup quel est la bonne methode pour modifier un mesh en animation avec python ?.
Parce que j'avais bien essayé avec un python generator. Ca fonctionnais aussi mais par contre ça crashait très vite. (le vrai modèle comporte 450000 points).
Si ça rame tu peux essayer de créer des clés d'animation PLA plutôt qu'un tag.
Pour la création des clés je me suis inspiré de ce post sur plugincafe
Il faut sélectionner un objet polygonal qui a le même nombre de points que tous les fichiers xyz contenus dans le dossier et le script répartira les clés en fonction du nombre de frames du doc.
Code PHP:
import c4d
from glob import glob
def ptsXYZ(fn):
res = []
with open(fn) as f:
for l in f:
x,y,z =[float(val) for val in l.split()]
pt = c4d.Vector(x,y,z)
res.append(pt)
return res
def main():
#Récupération des fichiers avec l'extension .xyz
path = '/Chemin/a/adapter/test_xyz/*.xyz'
files = glob(path)
if not files : return
doc.StartUndo()
did = c4d.DescID(c4d.DescLevel(c4d.CTpla, c4d.CTpla, 0))
track = op.FindCTrack(did)
doc.AddUndo(c4d.UNDOTYPE_CHANGE,op)
if not track:
track = c4d.CTrack(op, did)
op.InsertTrackSorted(track)
else:
track.FlushData()
curve = track.GetCurve()
curve.FlushKeys()
#calcul de l'intervalle entre les clés
fps = doc.GetFps()
start = doc.GetMinTime().GetFrame(fps) #set min time
end = doc.GetMaxTime().GetFrame(fps) #set max time
intervalle = c4d.BaseTime()
intervalle.SetNumerator((end-start)/(len(files)-1))
intervalle.SetDenominator(doc.GetFps())
time = doc.GetMinTime()
#parcours des fichiers xyz
for f in files:
pts = ptsXYZ(f)
key = curve.AddKey(time)['key']
op.SetAllPoints(pts)
op.Message(c4d.MSG_UPDATE)
track.FillKey(doc,op,key)
time+= intervalle
doc.EndUndo()
c4d.EventAdd()
if __name__=='__main__':
main()
D'une certaine manière c'est ce que j'ai fait en faisant un alambic.
Mais c'est cool quand même, car j'avais bien pensé a un système à base de keyframe, mais je ne voyait pas trop comment faire.
Du coup ma "culture personnelle" va faire un bon en avant.
Et aussi ça évite de générer un fichier intermédiaire. L'alambic il fait pas loin de 20 G° quand même.
Merci oli_D