PDA

Voir la version complète : Position aléatoire dans un objet



valkaari
18/09/2012, 15h27
Bonjour,

Je cherchais ces derniers jours comment générer une/des positions aléatoires à l'intérieur d'un objet.
Donc j'ai trouvé qu'en triangulant l'objet puis en calculant sur un polygon pris au hasard des coordonnées barycentriques au hasard (x+y+z = 1)
(ça fait beaucoup de hasard tout ça)

Puis en envoyant un rayon dans le sens de la normal pour aller toucher la surface de l'autre coté, et prendre un point aléatoire sur cette ligne, ça donnait un résultat relativement convenable.

Par contre j'ai encore des points qui restent en dehors. Le problème vient certainement des collisions du rayon.

SI vous avez des idées pour optimiser je suis preneur

Code commenté :


import c4d
import random
from c4d import utils
import time

#Welcome to the world of Python


def main():
#lancement du chrono
start = time.time()
#creation d'un null parent pour récolter toutes les positions
NullParent = c4d.BaseObject(c4d.Onull)

#Récupération de l'objet enfant
#trianguler l'objet également après l'avoir cloné.
original = op.GetDown()
if not original:return
child = original.GetClone()
if not child:return

ret = c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_TRIANGULATE,

list = [child])
if ret == False:
return

#initialisation du collider
Collide = c4d.utils.GeRayCollider()
Collide.Init(child)

# NombreObj -> Nombre d'objets crée , TotalPos -> Nombre de position à générer
NombreObj = 0
TotalPos = 10000

#récupération du nombre de polygons dans l'objet et de sa plus longue distance pour
#être certain que le rayon traverse tout l'objet.
pcnt =child.GetPolygonCount()
childDim = child.GetRad()
RayLenght = childDim.x
if childDim.y > RayLenght:
RayLenght = childDim.y
if childDim.z > RayLenght:
RayLenght = childDim.z
RayLenght *= 2


#boucle sur le nombre total de position à trouver

for cpt in xrange(TotalPos):
#on prend un poly au hasard
polyNb = random.randint(0,pcnt-1)
polygon = child.GetPolygon(polyNb)

#on récupère la position des 3 premiers points
A = child.GetPoint(polygon.a)
B = child.GetPoint(polygon.b)
C = child.GetPoint(polygon.c)

#calcul des vecteurs
AB = c4d.Vector(B.x - A.x, B.y - A.y , B.z - A.z)
AC = c4d.Vector(C.x - A.x, C.y - A.y , C.z - A.z)
#calcul de la normal du poly avec un CrossProduct
normal = AB.Cross(AC)
normal.Normalize()

#on inverse la normal pour aller vers l'intérieur
normal = -normal

#création de coordonées barycentrique aléatoire
#pa + pb + pc = 1

pa = random.random()
pb = random.uniform(0,1.0-pa)
pc = 1.0 - pa - pb

#création du point et ajout de 1/10 de la normal pour ne pas être collé au poly
SPoint = c4d.Vector( A*pa + B*pb + C*pc )
SPoint+=normal/10.0

#lancement d'un rayon à partir de cette position en direction de la normal pour
#trouver le point oposé
Collide.Intersect (SPoint, normal, RayLenght)
if Collide.GetIntersectionCount() == 0:
continue

Intersect = Collide.GetNearestIntersection(0)
OutPoint = Intersect['hitpos']

#calcul d'un point aléatoire entre les deux points
pa = random.random()
InsidePoint = SPoint*pa + OutPoint* (1-pa)

#création de l'objet neutre à la position généré.
Null = c4d.BaseObject(c4d.Onull)
Null[c4d.NULLOBJECT_DISPLAY] = 0
Null[c4d.NULLOBJECT_RADIUS] = 4

Null[c4d.NULLOBJECT_ORIENTATION] =1
Null.SetMg(c4d.utils.HPBToMatrix(c4d.utils.VectorT oHPB (normal)))
Null.SetAbsPos(InsidePoint)
Null.InsertUnder(NullParent)
#ajouter 1 au nombre d'objet crée
NombreObj+=1
#fin du chornomètre et affichage d'information dans la console
end = time.time() - start
print "temps d'execution ", end , " Nombre de position : " , NombreObj , " sur ", TotalPos

#retourner le Nullparent
return NullParent

xs_yann
18/09/2012, 16h27
Salut val,

Merci pour le partage, ton code à l'air plutôt cool et l'algorithme bien pensé. :thumbup1:


SI vous avez des idées pour optimiser je suis preneur

J'ai pas trop regardé au niveau de l'execution mais au niveau du code tu as déjà ça que tu peux simplifier :


childDim = child.GetRad()
RayLenght = childDim.x
if childDim.y > RayLenght:
RayLenght = childDim.y
if childDim.z > RayLenght:
RayLenght = childDim.z


c4d.utils.VectorMax(vec)


Les normes de programmation conseillent de ne pas utiliser de majuscules au début d'un nom de variable, c'est réservé aux classes, structures, modules, namespaces, etc

Pour être très rigoureux : http://www.python.org/dev/peps/pep-0008/
Je n'applique pas tous ces conseils d'une part pour garder une homogénéité avec le code du SDK et d'autre part parce que j'ai plus l'habitude d'utiliser les conventions C++ (bon et aussi parce que je l'ai lu il y a longtemps...)