3D アプリケーション内に 2D インターフェイスを作成する(FireMonkey 3D チュートリアル)

提供: RAD Studio
移動先: 案内検索

チュートリアル:FireMonkey 3D アプリケーションを作成する への移動


3D アプリケーションでは、ボタンやリストといった 2D コンポーネントを直接使用することができません。2D コンポーネントを 3D コンテナ上にドラッグ アンド ドロップした場合、コンポーネントは描画されませんが、[構造]ビューには子コントロールとして表示されます。ただし、この問題に簡単に対処する方法があります。3D シーンと 2D シーンの間を橋渡しする方法です。FireMonkey では、そのために FMX.Layers3D.TLayer3D コンポーネントを用意しています。

2D 表面(TLayer3D)と TButton の追加と調整

  1. 前のチュートリアルで作成したフォームを[オブジェクト インスペクタ]または[構造]ビューで選択し、[ツール パレット]TLayer3D をダブルクリックします。
    Layer 3D In Form.png
  2. この TLayer3D コンポーネントを FireMonkey 2D コンポーネント用の描画面として使用することができます。
    [構造]ビューまたは[オブジェクト インスペクタ]TLayer3D を選択した状態で、TButton を追加します。ボタンがフォームではなくレイヤの子になっていることを[構造]ビューで確認してください(階層を修正する必要があれば、TButton をドラッグしてレイヤ上にドロップします)。
    Layer 3D with Button In Form.png
  3. 2D 平面をシミュレートするために、TLayer3D コンポーネントの Projection の種類を変更します。[オブジェクト インスペクタ]で、レイヤの次のプロパティを設定します。
    Projection = Screen
    画面投影は、固定の(目に見えない)カメラでピクセル単位で投影した画面平面であり、これで 3D 錐台の前方平面が画面平面になります。どのオブジェクトも 3D のままですが、2D として操作することができます。
    これで 3D アプリケーションは次の図のようになっているはずです。
    Layer with project screen.png
  4. 図を見ると、TLayer3D コンポーネントによって、シーンが隠されてしまっています。TLayer3D を選択し、[オブジェクト インスペクタ]で以下のプロパティを設定します。
    • AlignMostRight(またはその他の任意の位置揃え)に。
    • Width150(またはその他の任意の幅。ピクセル単位で指定)に。
    たとえば、次のようになります。
    Aligned Layer.png

2D コンポーネントの追加と配置

ここで、先ほど追加したボタンを削除し、代わりにフォーム上の 3D オブジェクトを回転、移動、サイズ変更するための他のコンポーネントを追加します。

  1. TLayer3D を選択した状態で、5 つの TGroupBoxe を追加します。
    1. Ctrl キーを押しながらマウスをクリックしてすべてのグループ ボックス[構造]ビューで選択し、[オブジェクト インスペクタ]AlignTop に設定します。
    2. 上から 3 つのグループ ボックスを選択し、[オブジェクト インスペクタ]Height70(または最終的なレイアウトに合う別の値)に設定します。
    3. TGroupBox を順に選択して次のように設定します。
      • Text を「Width」、「Height」、「Depth」、「Move」、「Rotate」に。
      • Name を「WidthGroupBox」、「HeightGroupBox」、「DepthGroupBox」、「MoveGroupBox」、「RotateGroupBox」に。NameText がずれないように気を付けてください。
      • Enabled プロパティを False に。
    4. 2 つ一組のボタンを最初の 3 つの TGroupBox にそれぞれ追加します。1 つのボタンは幅、高さ、奥行きを増加させるために、もう 1 つのボタンは減少させるために使用します。
      それぞれの組のボタンの名前を次のように変更します。
      • IncreaseWidthButton」と「DecreaseWidthButton
      • IncreaseHeightButton」と「DecreaseHeightButton
      • IncreaseDepthButton」と「DecreaseDepthButton
      ボタン名に合わせて Text を変更します。
    5. 2 つ一組のボタンを 3 組、Move グループ ボックスに追加します。
      それぞれの組のボタンの名前を次のように変更します。
      • MoveRightButton」と「MoveLeftButton
      • MoveDownButton」と「MoveUpButton
      • MoveBackButton」と「MoveFrontButton
      ボタン名に合わせて Text を変更します。
    6. 3D オブジェクトをそれぞれの軸で回転させるための 3 つの TTrackBar コンポーネントを Rotate グループ ボックスに追加します。
    7. TTrackBar の名前を、それぞれ「RotateXTrackBar」、「RotateYTrackBar」、「RotateZTrackBar」に変更します。
    8. [オブジェクト インスペクタ]で、それぞれのトラック バーの Min プロパティを -360 に、Max プロパティを 360 に設定します。
  2. TLayer3D をもう 1 つフォームに追加します。
    1. 新しい TLayer3D を選択し、[オブジェクト インスペクタ]Projection プロパティを Screen に、Align プロパティを Top に設定します。
    2. 新しい TLayer3D に 2 つの TGroupBox コンポーネントを追加します。
    3. TGroupBox を順に選択して次のように設定します。
      • Text を「Item to be Manipulated」と「Light On/off」に。
      • Name を「ManipulateItemGroupBox」と「LightGroupBox」に。NameText がずれないように気を付けてください。
    4. シーン中の 3D オブジェクトごとに 1 つずつ、合計 3 つの TRadioButtonManipulateItemGroupBox に追加します。
    5. TRadioButton を順に選択して次のように設定します。
      • Text を「Cube1」、「Cube2」、「Light」に。
      • Name を「Cube1RadioButton」、「Cube2RadioButton」、「LigthRadioButton」に。NameText がずれないように気を付けてください。
    6. TButton を 1 つ LightGroupBox に追加します。
    7. ボタンを選択して次のように設定します。
      • Text を「OFF」に。
      • Name を「LightOnOffButton」に。

最終的なレイアウトは次のようになります。

FinalInaterface.png

イベントおよびイベント ハンドラの追加

これで簡単な 3D シーンができました。そこで簡単にイベントをオブジェクトに割り当てることができます。

1. どの 3D オブジェクトが操作対象かを取得できるよう、オブジェクトの名前を保持するためのグローバルな文字列変数を宣言します。

トラック バーは、OnChange イベントの発生時にフォーカスが当たっているオブジェクトを回転させるためのものです。別のオブジェクトが選択されたときに前のオブジェクトの回転角を更新することがないよう、論理型の変数 RotateFlag を追加します。これが False に設定されていると、OnChange イベント ハンドラ内のコードは実行されません。

//Delphi declaration
var
  Form1: TForm1;
  ManipulatedItem: String;
  RotateFlag: boolean;
  // C++ declaration
TForm3D1 *Form3D1;
System::UnicodeString ManipulatedItem;
bool RotateFlag;
2. ラジオ ボタンをそれぞれダブルクリックして、OnChange イベント ハンドラを追加します。以下に示すのは、Cube1RadioButton の Delphi および C++ のコードです。Cube2RadioButton のコードも、Cube1 の代わりに Cube2 が使われる以外は同じです。
  // 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;
}

LightRadioButton の場合、コードですべての操作用グループ ボックスを有効にするわけではありません。TLight を移動したりサイズ変更すると、シーンに視覚的な影響が生じます。LightRadioButton の実装は次のとおりです。

  // 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. 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;
  }
}

光をオンおよびオフにした場合の違いは次のようになります。

LightON.png LightOFF.png

4. サイズ変更ボタンを同様に実装します。次に示すのは、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. 移動ボタンを同様に実装します。次に示すのは、3D オブジェクトを左右に移動するための実装です。
  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. 回転用のトラック バーを同様に実装します。次に示すのは、X 軸を中心に 3D オブジェクトを回転させるための実装です。
  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. F9 キーを押して、プロジェクトを実行します。
LightON.png
  • Cube1Radiobutton をチェックします。[Increase]ボタンや[Decrease]ボタンをクリックすると、立方体のサイズが変化します。
    Cub1Risezed.png
  • Cube1Radiobutton をチェックします。 [Left]ボタンや[Right]ボタンをクリックすると、立方体の位置が変わります。
    Cub2Moved.png
  • Cube1Radiobutton を選択します。トラック バーの値を増加させると、立方体は時計回りに回転します。値を減少させると、立方体は反時計回りに回転します。
    Cub2Rotates.png
  • LightRadiobutton を選択します。トラック バーの値を増加させると、光が回転し、その効果が Cube2 で見てとれます。
    LightRotates.png

前のチュートリアル

関連項目

サンプル