Création d'une interface 2D dans une application 3D (tutoriel FireMonkey 3D)

De Appmethod Topics
Aller à : navigation, rechercher

Remonter à Tutoriel : Création d'une application 3D FireMonkey


Une application 3D ne peut pas utiliser directement les composants 2D tels que les boutons ou les listes. Si un composant 2D est glissé et déposé sur un conteneur 3D, le composant ne sera pas restitué mais il apparaîtra dans la vue Structure sous la forme d'un contrôle enfant. Toutefois, un moyen simple de traiter ce problème consiste à créer un pont entre les scènes 3D et 2D. FireMonkey fournit le composant FMX.Layers3D.TLayer3D à cet effet.

Ajout et ajustement d'une surface 2D (TLayer3D) et d'un TButton

  1. Avec la fiche du tutoriel précédent sélectionnée dans l'inspecteur d'objets ou la vue Structure, double-cliquez sur TLayer3D dans la Palette d'outils.
    Layer 3D In Form.png
  2. Vous pouvez maintenant utiliser le composant TLayer3D en tant que surface pour les composants FireMonkey 2D.
    Avec TLayer3D sélectionné dans la vue Structure ou l'inspecteur d'objets, ajoutez un TButton. Dans la vue Structure, assurez-vous que le bouton est l'enfant de la couche, et pas un enfant de la fiche (si vous avez besoin de corriger la hiérarchie, faites glisser le TButton et déposez-le sur la couche).
    Layer 3D with Button In Form.png
  3. Pour simuler une surface 2D, changez le type Projection du composant TLayer3D. Dans l'inspecteur d'objets, définissez la propriété suivante de la couche :
    Projection = Screen
    Une projection d'écran est une projection pixel-à-pixel du plan d'écran avec une caméra fixe (invisible), et l'avant-plan du champ de vue 3d est maintenant un plan d'écran. Chaque objet est toujours 3D, mais il peut être manipulé comme s'il était 2D.
    Votre application 3D devrait maintenant ressembler à la figure suivante :
    Layer with project screen.png
  4. Comme vous le voyez, le composant TLayer3D a éclipsé la scène, en n'en laissant apparaître qu'une partie. Dans l'inspecteur d'objets, avec TLayer3D détenant la focalisation, définissez les propriétés suivantes :
    • Align sur MostRight (ou tout autre alignement de votre choix)
    • Width sur 150 (ou toute autre largeur de votre choix, spécifiée en pixels)
    Par exemple :
    Aligned Layer.png

Ajout et arrangement des composants 2D

Supprimez maintenant le bouton ajouté, pour ajouter d'autres composants à travers lesquels les objets 3D de la fiche sont pivotés, déplacés ou redimensionnés.

  1. Avec TLayer3D détenant la focalisation, ajoutez cinq TGroupBox.
    1. Sélectionnez toutes les zones de groupe dans la vue Structure en appuyant sur CTRL et en cliquant avec la souris, et dans l'inspecteur d'objets, définissez Align sur Top.
    2. Sélectionnez les trois premières zones de groupe dans la partie supérieure, et dans l'inspecteur d'objets, définissez Height sur 70 (ou sur une autre valeur qui vous semble mieux convenir à la disposition finale).
    3. Sélectionnez chaque TGroupBox et définissez :
      • La propriété Text sur Width, Height, Depth, Move et Rotate
      • La propriété Name sur WidthGroupBox, HeightGroupBox, DepthGroupBox, MoveGroupBox et RotateGroupBox. Assurez-vous que les propriétés Name et Text sont bien associées.
      • La propriété Enabled sur False.
    4. Ajoutez des paires de boutons aux trois premiers TGroupBox. Un bouton est utilisé pour augmenter la largeur, la hauteur et la profondeur, et un autre bouton pour les diminuer.
      Changez les noms des paires de boutons comme suit :
      • IncreaseWidthButton et DecreaseWidthButton
      • IncreaseHeightButton et DecreaseHeightButton
      • IncreaseDepthButton et DecreaseDepthButton
      Changez Text en concordance avec le nom du bouton.
    5. Ajoutez trois jeux de paires de boutons dans les zones de groupe Move.
      Changez les noms des paires de boutons comme suit :
      • MoveRightButton et MoveLeftButton
      • MoveDownButton et MoveUpButton
      • MoveBackButton et MoveFrontButton
      Changez Text en concordance avec le nom du bouton.
    6. Ajoutez trois composants TTrackBar, utilisés pour pivoter l'objet 3D sur chaque axe, à la zone de groupe Rotate.
    7. Définissez les noms des TTrackBar sur RotateXTrackBar, RotateYTrackBar et RotateZTrackBar.
    8. Dans l'inspecteur d'objets définissez, pour chaque barre de suivi, la propriété Min sur -360, et la propriété Max sur 360.
  2. Ajoutez un autre TLayer3D à la fiche.
    1. Avec le nouveau TLayer3D détenant la focalisation, dans l'inspecteur d'objets, définissez la propriété Projection sur Screen, et la propriété Align sur Top.
    2. Ajoutez deux composants TGroupBox au nouveau TLayer3D.
    3. Sélectionnez chaque TGroupBox et définissez :
      • La propriété Text sur Item to be Manipulated et Light On/off.
      • La propriété Name sur ManipulateItemGroupBox et LightGroupBox. Assurez-vous que les propriétés Name et Text sont bien associées.
    4. Ajoutez trois TRadioButton au ManipulateItemGroupBox, un pour chaque objet 3D dans la scène.
    5. Sélectionnez chaque TRadioButton et définissez :
      • La propriété Text sur Cube1, Cube2 et Light.
      • La propriété Name sur Cube1RadioButton, Cube2RadioButton et LigthRadioButton. Assurez-vous que les propriétés Name et Text sont bien associées.
    6. Ajoutez un TButton au LightGroupBox.
    7. Sélectionnez le bouton et définissez :
      • La propriété Text sur OFF.
      • La propriété Name sur LightOnOffButton.

La disposition finale doit ressembler à ceci :

FinalInaterface.png

Ajout d'événements et de gestionnaires d'événements

Vous disposez maintenant d'une simple scène 3D dans laquelle vous pouvez facilement assigner des événements aux objets.

1. Pour obtenir l'objet 3D qui doit être manipulé, déclarez une variable chaîne globale afin de conserver le nom de l'objet.

La barre de suivi offre la possibilité de pivoter l'objet détenant la focalisation sur l'événement OnChange. Pour éviter la mise à jour des angles de rotation pour l'objet précédent quand un autre objet est sélectionné, ajoutez une variable booléenne RotateFlag. Si elle est définie sur False, le code du gestionnaire d'événements OnChange ne se déclenchera pas.

 //Delphi declaration
 var
   Form1: TForm1;
   ManipulatedItem: String;
   RotateFlag: boolean;
 // C++ declaration
 TForm3D1 *Form3D1;
 System::UnicodeString ManipulatedItem;
 bool RotateFlag;
2. Ajoutez des gestionnaires d'événements OnChange aux boutons radio en double-cliquant sur chacun d'eux. Voici ci-dessous le code Object Pascal et C++ pour Cube1RadioButton. Le code pour Cube2RadioButton est le même, sauf que Cube2 est utilisé au lieu de Cube1.
 // The Delphi implementation for the radio button OnChange event
   procedure TForm1.Cube1RadioButtonChange(Sender: TObject);
   begin
   //enables the group boxes to manipulate Cube1
     WidthGroupBox.Enabled := True;
     HeightGroupBox.Enabled := True;
     DepthGroupBox.Enabled := True;
     MoveGroupBox.Enabled := True;
     RotateGroupBox.Enabled := True;
   //updates the values for the track bars to display the current value of the Cube1.RotationAngle
     RotateFlag:=false;
     RotateXTrackBar.Value := Cube1.RotationAngle.X;
     RotateYTrackBar.Value := Cube1.RotationAngle.Y;
     RotateZTrackBar.Value := Cube1.RotationAngle.Z;
     RotateFlag:=True;
   //Saves the name of the 3D object to be manipulated
     ManipulatedItem:=Cube1.Name;
 end;
 // The C++ implementation for the radio button OnChange event
  void __fastcall TForm3D1::Cube1RadioButtonChange(TObject *Sender)
 {
   //enables the group boxes to manipulate Cube1
   WidthGroupBox->Enabled = true;
   HeightGroupBox->Enabled = true;
   DepthGroupBox->Enabled = true;
 
   MoveGroupBox->Enabled = true;
   RotateGroupBox->Enabled = true;
   //updates the values for the track bars to display the current value of the Cube1.RotationAngle
   RotateFlag = false;
   RotateXTrackBar->Value = Cube1->RotationAngle->X;
   RotateYTrackBar->Value = Cube1->RotationAngle->Y;
   RotateZTrackBar->Value = Cube1->RotationAngle->Z;
   RotateFlag = true;
   //Saves the name of the 3D object to be manipulated
   ManipulatedItem = Cube1->Name;
 }

Pour LightRadioButton, le code n'active pas toutes les zones de groupe de manipulation. Le déplacement et le redimensionnement du TLight a maintenant des effets visuels sur la scène. L'implémentation pour LightRadioButton est :

 // The Delphi implementation for the radio button OnChange event
   procedure TForm1.LightRadioButtonChange(Sender: TObject);
   begin
   //disables the group boxes that move and resize the light
     WidthGroupBox.Enabled := False;
     HeightGroupBox.Enabled := False;
     DepthGroupBox.Enabled := False;
     MoveGroupBox.Enabled := False;
   // the light is manipulated only if it is on
     if(Light1.Enabled=True) then
     begin
       RotateGroupBox.Enabled := True;
       //updates the values for the track bars to display the current value of the Light1.RotationAngle
       RotateFlag:=false;
       RotateXTrackBar.Value := Light1.RotationAngle.X;
       RotateYTrackBar.Value := Light1.RotationAngle.Y;
       RotateZTrackBar.Value := Light1.RotationAngle.Z;
       RotateFlag:=True;
       //saves the name of the 3D object to be manipulated
       ManipulatedItem:=Cube1.Name;
    end
    else
       RotateGroupBox.Enabled := false;
    end;
 end;
 // The C++ implementation for the radio button OnChange event
  void __fastcall TForm3D1::LightRadioButtonChange(TObject *Sender)
 {
 //disables the group boxes that move and resize the light
     WidthGroupBox->Enabled = false;
     HeightGroupBox->Enabled = false;
     DepthGroupBox->Enabled = false;
     MoveGroupBox->Enabled = false;
   // the light is manipulated only if it is on
     if (Light1->Enabled == true)
     {
       RotateGroupBox->Enabled = true;
       //updates the values for the track bars to display the current value of the Light1.RotationAngle
       RotateFlag = false;
       RotateXTrackBar->Value = Light1->RotationAngle->X;
       RotateYTrackBar->Value = Light1->RotationAngle->Y;
       RotateZTrackBar->Value = Light1->RotationAngle->Z;
       RotateFlag = true;
       //saves the name of the 3D object to be manipulated
       ManipulatedItem=Cube1->Name;
    }
    else
       RotateGroupBox->Enabled = false;
 }
3. Implémentation du bouton LightOnOffButton :
 procedure TForm1.LightOnOffButtonClick(Sender: TObject);
   begin
     if Light1.Enabled = True then
     begin
       Light1.Enabled := False;
       LightOnOffButton.Text := 'ON';
       if(LightRadioButton.IsChecked) then
         RotateGroupBox.Enabled:=False;
     end
     else
     begin
       Light1.Enabled := True;
       LightOnOffButton.Text := 'OFF';
       if(LightRadioButton.IsChecked) then
       RotateGroupBox.Enabled:=True;
    end;
 end;
 void __fastcall TForm3D1::LightOnOffButtonClick(TObject *Sender)
 {
   if (Light1->Enabled == true)
   {
     Light1->Enabled = false;
     LightOnOffButton->Text = "ON";
     if (LightRadioButton->IsChecked)
       RotateGroupBox->Enabled = false;
   }
   else
   {
     Light1->Enabled = true;
     LightOnOffButton->Text = "OFF";
     if (LightRadioButton->IsChecked)
       RotateGroupBox->Enabled = true;
   }
 }

Différence entre "Light on" et "Light off" :

LightON.png LightOFF.png

4. Le redimensionnement des boutons a une implémentation similaire. Voici ci-dessous l'implémentation de l'augmentation et de la diminution de la largeur de l'objet 3D.
 //Increasing and decreasing the Width of the 3D object
   procedure TForm1.IncreaseWidthButtonClick(Sender: TObject);
   begin
     TControl3D(FindComponent(ManipulatedItem)).Width:=TControl3D(FindComponent(ManipulatedItem)).Width+1;
   end;
 
   procedure TForm1.DecreaseWidthButtonClick(Sender: TObject);
   begin
     TControl3D(FindComponent(ManipulatedItem)).Width:=TControl3D(FindComponent(ManipulatedItem)).Width-1;
   end;
 void __fastcall TForm3D1::IncreaseWidthButtonClick(TObject *Sender)
 {
  ((TControl3D*)(FindComponent(ManipulatedItem)))->Width=((TControl3D*)(FindComponent(ManipulatedItem)))->Width+1;
 }
 void __fastcall TForm3D1::DecreaseWidthButtonClick(TObject *Sender)
 {
  ((TControl3D*)(FindComponent(ManipulatedItem)))->Width=((TControl3D*)(FindComponent(ManipulatedItem)))->Width-1;
 }
5. Le déplacement des boutons a une implémentation similaire. Voici ci-dessous l'implémentation du déplacement de l'objet 3D vers la droite et la gauche.
 procedure TForm1.MoveRightButtonClick(Sender: TObject);
   begin
     TControl3D(FindComponent(ManipulatedItem)).Position.X:=TControl3D(FindComponent(ManipulatedItem)).Position.X+1;
   end;
 
   procedure TForm1.MoveLeftButtonClick(Sender: TObject);
   begin
     TControl3D(FindComponent(ManipulatedItem)).Position.X:=TControl3D(FindComponent(ManipulatedItem)).Position.X-1;
   end;
 void __fastcall TForm3D1::MoveRightButtonClick(TObject *Sender)
 {
  ((TControl3D*)(FindComponent(ManipulatedItem)))->Position->X=((TControl3D*)(FindComponent(ManipulatedItem)))->Position->X+1;
 }
 void __fastcall TForm3D1::MoveLeftButtonClick(TObject *Sender)
 {
  ((TControl3D*)(FindComponent(ManipulatedItem)))->Position->X=((TControl3D*)(FindComponent(ManipulatedItem)))->Position->X-1;
 }
6. La rotation des barres de suivi a une implémentation similaire. Voici ci-dessous l'implémentation de la rotation de l'objet 3D autour de l'axe X.
 procedure TForm1.RotateXTrackBarChange(Sender: TObject);
   begin
     if (ManipulatedItem<>'') and (RotateFlag=True) then
      TControl3D(FindComponent(ManipulatedItem)).RotationAngle.X:= RotateXTrackBar.Value;
   end;
 void __fastcall TForm3D1::RotateXTrackBarChange(TObject *Sender)
 {
   if (ManipulatedItem!="" && RotateFlag==true)
      ((TControl3D*)(FindComponent(ManipulatedItem)))->RotationAngle->X=RotateXTrackBar->Value;
 }
7. Exécutez le projet en appuyant sur F9.
LightON.png
  • Vérifiez Cube1Radiobutton. Quand vous cliquez sur les boutons Increase/Decrease, la taille du cube change.
    Cub1Risezed.png
  • Vérifiez Cube1Radiobutton. Quand vous cliquez sur les boutons Left / Right, la position du cube change.
    Cub2Moved.png
  • Vérifiez Cube1Radiobutton. Quand vous augmentez la valeur des barres de suivi, le cube subit une rotation dans le sens des aiguilles d'une montre. Si la valeur est diminuée, le cube subit une rotation dans le sens contraire des aiguilles d'une montre.
    Cub2Rotates.png
  • Vérifiez LightRadiobutton. Quand vous augmentez la valeur des barres de suivi, la lumière subit une rotation et son effet peut être vu sur Cube2.
    LightRotates.png

Précédent

Voir aussi