ROBOTICA

video
immagini
papers
progettati
costruiti
toolbox
vrml
simulatori

links

 

Papers
meccanica
sistemi
documents

Capitolo 31° Prototyping Capitolo 33°

Fino ad ora abbiamo visto diversi aspetti della specifica 2.0 di Vrml e abbiamo analizzato la maggior parte dei nodi. Ne mancano ancora alcuni, come per esempio i vari PlaneSensor, SphereSensor...; altri sono stati analizzati solo in parte: mi riferisco in particolare al nodo Material, di cui abbiamo analizzato solo pochissime componenti, al nodo Transform e altri che presentano fields che non ho preso in considerazione nelle passate lezioni.

Salvo eventuali future lezioni, non intendo affrontare questi argomenti, sperando che a questo punto abbiate gli stimoli giusti per andare a cercare direttamente nelle specifiche quando incontrate qualche problema o avete qualche particolare effetto da inserire nel vostro mondo. In ogni caso potete anche chiedere tramite email; solitamente sono abbastanza celere nel rispondere.

Fatta questa piccola prefazione, passiamo ora all'argomento della lezione. Con il comando PROTO il programmatore VRML puo' crearsi nuovi nodi, diversi da quelli previsti dalla specifica. Ci si potrebbe domandare il perche' di questa azione; in particolare questo consente un maggiore riutilizzo del codice, cosa che peraltro era possibile anche nel caso del comando USE.
Ma c'e' una sostanziale differenza tra i due casi. Con il comando USE il nodo (o gruppi di nodi) identificato viene riutilizzato tale e quale nel punto in cui viene invocato. Con il comando PROTO posso invece definire un nuovo nodo il quale avra' dei campi il cui valore sara' settato dall'utente...

Vediamo di chiarire meglio il concetto. Supponiamo di avere un sorgente VRML che definisce un oggetto che ha la forma di un libro. Supponiamo che il colore associato al libro sia rosso. Supponiamo ora che dobbiamo inserire nel nostro mondo almeno una decina di questi libri, ma ognuno di essi con un colore diverso (blu, verde, giallo...).
Come fare con il comando USE? Con USE semplicemente si replica il nodo identificato dal nome che segue USE. E quindi si replica anche il relativo colore!

La soluzione in questo caso viene fornita dal comando PROTO. Sarebbe molto comodo il poter definire un nuovo nodo che chiameremo Libro. Questo nodo avra' un solo campo che ne specifichera' il colore. L'utilizzo del nodo sara' come quello di un nodo qualunque:

Transform {
  translation -10 0 0 
  children [
    Libro {
      colore 0 0 1      # qui ci metto un libro blu
    }
   ]
}
Transform {
  translation 10 0 0
  children [
    Libro {
      colore 0 1 0       # qui ci metto un libro verde
    }
   ]
}

Come si vede si compatta di molto il codice VRML (replicare il sorgente e modificare la sola componente di colore sarebbe inimmaginabile appena dobbiamo inserire due o tre di questi libri... figuriamoci se dobbiamo simulare una biblioteca!!!).

Facciamo un ultimo esempio. Supponiamo di avere un oggetto di forma umana. Presumibilmente sara' molto complicato, soprattutto in considerazione del fatto che lo vogliamo animare. E supponiamo di volere realizzare una staffetta 4x100 con una decina di squadre. Dobbiamo insomma modellizzare 40 atleti! Il vero problema non e' tanto l'aspetto fisico che vogliamo che vari... per esempio le diverse squadre portano divise diverse.
Il fatto e' che ogni concorrente deve muoversi in modo diverso dagli altri. Non tanto nella tecnica di corsa, quella possiamo assumerla uguale per tutti... ma ci sara' qualcuno che corre piu' in fretta di un altro. La soluzione sara' quella di creare dei nuovi campi che contengano le informazioni opportune per far correre il concorrente in modo piu' o meno veloce rispetto agli altri. L'esempio e' abbastanza complesso. Ne vedremo una semplificazione nella lezione successiva, che sara' tutta dedicata all'esempio stesso.

Ok... convinti tutti della utilita' del comando PROTO? allora possiamo passare dal lato di creazione del nuovo nodo.

Vediamo in cosa consiste la definizione di un prototipo. Si comincia indicando la parola chiave PROTO seguita dal nome da associare al nuovo nodo.
Successivamente si indica la prototype declaration, la quale contiene i singoli campi che fanno parte del nodo. Questi campi potranno essere field, eventIn, eventOut o exposedField.
Segue la prototype definition che contiene un insieme di nodi che definiscono che cosa il nuovo nodo fara'. All'interno di questa definizione serve un meccanismo per riferirsi ai valori passati nei parametri. Questo viene realizzato tramite la parola chiave IS.
Per esempio:

        ...
        translation IS spostamento    
        ...

dove 'spostamento' e'  il nome del campo passato. 

Vediamo dunque la sintassi di PROTO:

PROTO nome [
        eventIn         tipo    nome
        eventOut        tipo    nome
        exposedField    tipo    nome     valore di default
        field           tipo    nome     valore di default
] {
        insieme di nodi
        eventuali ROUTE
}

Ovviamente il tipo sara' uno dei soliti tipi visti sino ad ora: SFBool, SFVec3f, SFRotation e cosi' via.
I nomi dei campi devono essere unici all'interno dello stesso PROTO.

Fate attenzione che in questo modo non avete creato nulla sullo schermo. Abbiamo semplicemente un nuovo nodo. Quando lo richiameremo, il relativo effetto si ripercuotera' sul mondo VRML.

Vediamo un semplice esempio di utilizzo con il quale concludo questa lezione (rimandando poi al secondo esempio nella prossima).

Supponiamo di volere realizzare un piccolo quartiere con alcune (piccole) case.

Per mantenerci focalizzati sugli aspetti nuovi della lezione, le case verranno mantenute molto semplici; in particolare utilizzeremo un modello identico a quello realizzato in una precedente lezione: vale a dire una box con una piramide sopra. Non volendo avere case tutte dello stesso colore, non possiamo fare ricorso al comando USE.

I campi che mi interessa specificare sono i seguenti:

In questo modo terremo il tutto molto semplice.

Vediamo dunque il file VRML relativo.

#VRML V2.0 utf8
#semplice esempio di utilizzo del comando PROTO
PROTO House [
        exposedField SFColor color_house  1 1 1
        exposedField SFColo  color_roof   1 0 0
] {
  Transform {
    translation 0 0 3
    children [
      Shape {
       appearance Appearance {
        material Material { 
         diffuseColor IS color_house
        }
       }
       geometry Box { size 6 6 6 }
      }
      Transform {
       translation 0 0 3
       children [
        Shape {
         appearance Appearance {
          material Material {
           diffuseColor IS color_roof
          }
         }
         geometry IndexedFaceSet {
          coord Coordinate {
            point [ -3 0 3, 3 0 3, 3 0 -3, -3 0 -3, 0 3 0 ]
          }
          coordIndex [
            0,3,2,1,-1,
            0,1,4,-1,
            1,2,4,-1,
            2,3,4,-1,
            3,0,4,-1,
          ]
         }
        } # end of Shape
       ]
      } # end of roof
     } # end of shape
    ]
  } # end of house
} # END OF PROTO
# adesso posso liberamente utilizzare il nuovo nodo.
#definisco un piano su cui mettere le varie case.
Shape {
 appearance Appearance {
  material Material { diffuseColor .5 .5 .5 }
 }
 geometry Box { size 100 .01 100 }  
  # avrei tranquillamente potuto usare un IndexedFaceSet 
  # per creare un piano.
}
#prima casa!
Transform {
 translation -40 0 -40
 children [
   House {
     color_house 0 1 0
     color_roof  1 0 0
   }
  ]
}
#seconda casa
Transform {
  translation - 30 0 0 
  scale 1 1 2       # per ottenere case di dimensioni diverse
  children [
    House {
      color_house 1 1 1 
      color_roof .5 0 0
    }
  ]
}
Transform {
  translation -40 0 -30
  scale 1 2 2
  children [
    House {
      color_house .5 .5 0
      color_roof .8 .8 .8
    }
   ]
}
Transform {
  translation 0 0 -30 
  scale 3 0 0 
  children [
    House {
      color_house 1 0 0 
      color_roof .4 .4 .4
    }
  ]
}
Transform {
  translation 40 0 -30
  scale 1.5 5 2
  children [
    House {
      color_house 1 1 1 
      color_roof .8 0 0
    }
  ]
}
Transform {
  translation 30 0 0
  scale 1 2 3 
  children [
   House {
     color_house 0 .5 0
     color_roof .5 0 .1 
   }
  ]
}
#ultima casa!
Transform {
  translation 0 0 -30
  scale 3 .6 1
  children [
    House {
      color_house .6 0 0
      color_roof .4 .4 .4 
    }
   ]
}
 
Paesino 

Un paio di osservazioni conclusive.

Si noti bene che posso utilizzare un prototype solo dove potrebbe esserre impiegato il primo nodo della definizione. In pratica il primo nodo contenuto nella definizione definisce il tipo del prototype.

Nel nostro caso, House ha come primo nodo un nodo Transform e quindi puo' essere liberamente utilizzato in qualsiasi parte un nodo Transform potrebbe essere impiegato. Se il PROTO definisce un nodo di tipo Material, potra' essere impiegato solo all'interno del nodo Appearance.

Per ulteriori informazioni, soprattutto sulla possibilita' di innestare PROTO all'interno di altri PROTO, vi rimando alle specifiche.

Nella lezione successiva viene analizzato un esempio un po' piu' complesso. Sicuramente il piu' complesso visto sino a questo punto. L'attenzione sara' posta soprattutto sugli aspetti di dinamicita' e animazione della scena.

Dopo avere affrontato l'esempio vedremo di dare una rapida occhiata a EXTERNPROTO e quindi passeremo all'interazione tra JAVA e VRML (dove ci sara' da divertirsi).