Mélanger des objets : partie 2

Ce didacticiel suppose que vous connaissiez la définitions des différents noeuds, events et spécifications de base du VRML97.
Vous pourrez trouver toutes ces infos (en français) sur le site de 3Dnet.
N'oubliez pas que tous les ROUTE doivent se trouver tout à la fin du fichier.

But :

Cet exercice est une suite. Je vous conseil de bien étudier comment fonctionne la première partie, sinon vous risquer de ne rien comprendre à ce que se raconte ici...
Dans la première partie, nous avons créez un sytème qui permet de mélanger des objets aléatoirement en cliquant sur n'importe lequel d'entre eux.

Voir la scène

Ici, nous allons compliqué la chose en ajoutant une attribution aléatoire d'apparence à ces objets. Au final, les objets seront placés aléatoirement, et leur apparence sera attribuée elle aussi aléatoirement.

En pratique :

Copier Coller dans un fichier le source qui se trouve ici : Voir le source

Pour chacun des noeuds Shape, nous rajoutons une apparence et un material. Nous nommerons ces apparences avec DEF.

DEF pos1 Transform {
	children DEF geomN Shape {
		geometry Box {}
		appearance DEF appN Appearance {
			material Material {
				diffuseColor .8 0 0
				specularColor .5 .5 .5
				emissiveColor .15 0 0
				ambientIntensity 0
			}
		}
	}
}....

Quand on clique sur un des objet, il change de position mais garde la même apparence.

Voir la scène Voir le source

Nous allons utiliser le même principe que pour la distribution des géomètries. Petit rappel du script qui gère tout ça :

DEF permut Script {
  eventIn	SFTime touch
  field MFNode pos [USE pos1 USE pos2 USE pos3 USE pos4 USE pos5 USE pos6 ]
  field MFNode enfants [USE geom1 USE geom2 USE geom3 USE geom4 USE geom5 USE geom6 ]
  field SFNode temp NULL
  url "javascript:
	function touch(){
		for (j = 0; j < pos.length; j++) {
			k = Math.floor(Math.random() * pos.length);
			temp = enfants [ j ] ;
			enfants [ j ] = enfants [ k ] ;
			enfants [ k ] = temp ;
		}
		for (i=0;i<pos.length;i++){
			pos [ i ] .children [ 0 ] = enfants [ i ] ;
		}
  	}
  	function initialize(){
		touch();
  	}
"
}

Rappeler vous du principe de mélange adopté dans la première partie.

Il nous faut une liste de toutes ces apparences. Nous rajoutons un champ MFNode que nous appellerons apps

field MFNode apps [USE app1 USE app2 USE app3 USE app4 USE app5 USE app6 ]

Pour appliquer ces matériaux au geométries, nous utilisons une boucle pour tous les enfants. Vu que nous avons déjà une boucle pour affecter une géomètrie à chacune des positions, nous rajoutons simplement une instruction pour affecter les matériaux dans cette boucle. (le nombre de positons, géomètrie et matériaux étant égal.)

for (i=0;i<pos.length;i++){
	pos [ i ] .children [ 0 ] = enfants [ i ] ;
	enfants[i].appearance = apps [i];
}

Voir la scène Voir le source

Il y a encore un petit truc qui ne va pas : les géomètries changent, mais les matériaux sont liés aux positions. C'est parce que pour l'instant, ni les positions, ni les matériaux ne sont mélangés. Nous avons vu dans la première partie que nous ne touchons pas au positions. Nous allons donc mélanger les matériaux.

Nous récréons une boucle pour mélanger les matériaux.

for (j = 0; j < pos.length; j++) {
	k = Math.floor(Math.random() * pos.length);
	temp = apps [ j ] ;
	apps [ j ] = apps [ k ] ;
	apps [ k ] = apps ;
}

C'est exactement la même que celle pour le mélange des géomètries. C'est bêtes de faire deux boucles de durée égale (j = nombre de positions= nombre degéomètries= nombre d'apparences).
Il y a moyen de grouper nos deux boucles dans une seule :

for (j = 0; j < pos.length; j++) {
	k = Math.floor(Math.random() * pos.length);
	temp = enfants [ j ] ;
	enfants [ j ] = enfants [ k ] ;
	enfants [ k ] = temp ;
	k = Math.floor(Math.random() * pos.length);
	temp = apps [ j ] ;
	apps [ j ] = apps [ k ] ;
	apps [ k ] = temp;
}

A chaque boucle, k prend une valeur aléatoire. Suit l'intervertion de deux enfants de la liste enfants.Un nouveau nombre k est généré, puis vient l'intervertion de deux apparance de la liste apps. Ainsi, les géomètries et les apparences sont mélangés de façon différentes.

Maintenant que les apparences sont mélangées, il faut les appliquer aux géomètries. Nous le ferons dans la même boucles que celle qui affecte les géomètries aux positions.

pos [ i ] .children [ 0 ].appearance = apps[i];

Nous affectons l'apparence i à l'apparence du 1er enfant de la pos i

Voilà le script final :

DEF permut Script {
  eventIn SFTime touch
  field MFNode pos [USE pos1 USE pos2 USE pos3 USE pos4 USE pos5 USE pos6 ]
  field MFNode enfants [USE geom1 USE geom2 USE geom3 USE geom4 USE geom5 USE geom6 ]
  field MFNode apps [USE app1 USE app2 USE app3 USE app4 USE app5 USE app6 ]
  field SFNode temp NULL
  field SFNode tempap NULL
  url "javascript:
  function touch(){
	for (j = 0; j < pos.length; j++) {
		k = Math.floor(Math.random() * pos.length);
		temp = enfants [ j ] ;
		enfants [ j ] = enfants [ k ] ;
		enfants [ k ] = temp ;
		k = Math.floor(Math.random() * pos.length);
		temp= apps [ j ] ;
		apps [ j ] = apps [ k ] ;
		apps [ k ] = temp ;
	}
	for (i=0;i<pos.length;i++){
		pos [ i ] .children [ 0 ] = enfants [ i ] ;
		pos [ i ] .children [ 0 ].appearance = apps[i];
	}
  }
  function initialize(){
	touch();
  }
" 
}

La function initialize qui se lance au chargement de la scène exécute la fonction touch. A chaque ouverture de la scène, les objets sont placés différemments ou ont une couleur différente...

Voir la scène Voir le source

Surprise :

Si vous êtes rendus jusque là, c'est vraiment que vous aimez vous torturer l'esprit ! (ou alors que vous aimer programmer ;-)

Il y a toujours la petite question subsidiaire pour départager les ex-aequos :
De combien de façon différentes la scène peut-elle s'ouvrir si on ne tient pas compte des objets bleus ?

1 296 360 86 400 518 400 3 600
Solution
Valid XHTML 1.0 Strict Valid CSS!