3D アプリケーション内に 2D インターフェイスを作成する(FireMonkey 3D チュートリアル)
チュートリアル:FireMonkey 3D アプリケーションを作成する への移動
3D アプリケーションでは、ボタンやリストといった 2D コンポーネントを直接使用することができません。2D コンポーネントを 3D コンテナ上にドラッグ アンド ドロップした場合、コンポーネントは描画されませんが、[構造]ビューには子コントロールとして表示されます。ただし、この問題に簡単に対処する方法があります。3D シーンと 2D シーンの間を橋渡しする方法です。FireMonkey では、そのために FMX.Layers3D.TLayer3D コンポーネントを用意しています。
目次
2D 表面(TLayer3D)と TButton の追加と調整
- 前のチュートリアルで作成したフォームを[オブジェクト インスペクタ]または[構造]ビューで選択し、[ツール パレット]で TLayer3D をダブルクリックします。
- この TLayer3D コンポーネントを FireMonkey 2D コンポーネント用の描画面として使用することができます。
- 2D 平面をシミュレートするために、TLayer3D コンポーネントの Projection の種類を変更します。[オブジェクト インスペクタ]で、レイヤの次のプロパティを設定します。
- Projection = Screen
- 画面投影は、固定の(目に見えない)カメラでピクセル単位で投影した画面平面であり、これで 3D 錐台の前方平面が画面平面になります。どのオブジェクトも 3D のままですが、2D として操作することができます。
- これで 3D アプリケーションは次の図のようになっているはずです。
- 図を見ると、TLayer3D コンポーネントによって、シーンが隠されてしまっています。TLayer3D を選択し、[オブジェクト インスペクタ]で以下のプロパティを設定します。
2D コンポーネントの追加と配置
ここで、先ほど追加したボタンを削除し、代わりにフォーム上の 3D オブジェクトを回転、移動、サイズ変更するための他のコンポーネントを追加します。
- TLayer3D を選択した状態で、5 つの TGroupBoxe を追加します。
- Ctrl キーを押しながらマウスをクリックしてすべてのグループ ボックスを[構造]ビューで選択し、[オブジェクト インスペクタ]で Align を
Top
に設定します。 - 上から 3 つのグループ ボックスを選択し、[オブジェクト インスペクタ]で Height を
70
(または最終的なレイアウトに合う別の値)に設定します。 - TGroupBox を順に選択して次のように設定します。
- 2 つ一組のボタンを最初の 3 つの TGroupBox にそれぞれ追加します。1 つのボタンは幅、高さ、奥行きを増加させるために、もう 1 つのボタンは減少させるために使用します。
- それぞれの組のボタンの名前を次のように変更します。
- 「IncreaseWidthButton」と「DecreaseWidthButton」
- 「IncreaseHeightButton」と「DecreaseHeightButton」
- 「IncreaseDepthButton」と「DecreaseDepthButton」
- ボタン名に合わせて Text を変更します。
- 2 つ一組のボタンを 3 組、Move グループ ボックスに追加します。
- それぞれの組のボタンの名前を次のように変更します。
- 「MoveRightButton」と「MoveLeftButton」
- 「MoveDownButton」と「MoveUpButton」
- 「MoveBackButton」と「MoveFrontButton」
- ボタン名に合わせて Text を変更します。
- 3D オブジェクトをそれぞれの軸で回転させるための 3 つの TTrackBar コンポーネントを Rotate グループ ボックスに追加します。
- TTrackBar の名前を、それぞれ「RotateXTrackBar」、「RotateYTrackBar」、「RotateZTrackBar」に変更します。
- [オブジェクト インスペクタ]で、それぞれのトラック バーの Min プロパティを
-360
に、Max プロパティを360
に設定します。
- Ctrl キーを押しながらマウスをクリックしてすべてのグループ ボックスを[構造]ビューで選択し、[オブジェクト インスペクタ]で Align を
- TLayer3D をもう 1 つフォームに追加します。
- 新しい TLayer3D を選択し、[オブジェクト インスペクタ]で Projection プロパティを
Screen
に、Align プロパティをTop
に設定します。 - 新しい TLayer3D に 2 つの TGroupBox コンポーネントを追加します。
- TGroupBox を順に選択して次のように設定します。
- シーン中の 3D オブジェクトごとに 1 つずつ、合計 3 つの TRadioButton を ManipulateItemGroupBox に追加します。
- TRadioButton を順に選択して次のように設定します。
- TButton を 1 つ LightGroupBox に追加します。
- ボタンを選択して次のように設定します。
- 新しい TLayer3D を選択し、[オブジェクト インスペクタ]で Projection プロパティを
最終的なレイアウトは次のようになります。
イベントおよびイベント ハンドラの追加
これで簡単な 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;
}
}
光をオンおよびオフにした場合の違いは次のようになります。
- 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;
}
前のチュートリアル
関連項目
サンプル
- FireMonkey 3D 矢印サンプル
- FireMonkey First App3D サンプル
- FireMonkey GUI3d サンプル
- FireMonkey 3D サンプル