FireMonkey 提供了便捷的 3D 渲染功能,讓開發者能輕鬆建立 3D 應用程式。本文將逐步引導讀者使用 FireMonkey 進行 3D 渲染,並開發自訂的線框元件。首先,我們會使用內建的 TStrokeCube 元件快速渲染一個立方體,藉此瞭解 FireMonkey 的 3D 繪圖機制。接著,我們將深入研究如何開發一個名為 TWireframe 的自訂線框元件,並以金字塔模型的建構為例,示範如何定義頂點、邊線以及渲染流程。最後,我們將探討如何將這個自訂元件應用於實際場景,並提供程式碼範例和詳細的解說,幫助讀者快速掌握 FireMonkey 3D 開發的技巧。
使用 FireMonkey 進行 3D 渲染的自訂元件開發
簡介
本章節主要探討如何使用 FireMonkey 進行 3D 渲染,並開發自訂的 3D 元件。首先,我們將透過一個簡單的範例展示如何直接使用 Context3D 進行 3D 繪圖,接著介紹如何利用 FireMonkey 的元件進行 3D 渲染,最後開發一個自訂的線框元件。
使用 TStrokeCube 元件
在開始自訂元件開發之前,我們先來看看如何使用 FireMonkey 提供的 TStrokeCube 元件來渲染一個 3D 立方體。
- 建立一個新的 3D 應用程式專案,命名為
CubeWithComp。 - 將
TStrokeCube元件拖曳到表單上。 - 設定
TStrokeCube的Color屬性為黑色,並將Width、Height和Depth設定為 10。
這樣,我們就建立了一個簡單的 3D 立方體,而無需寫任何程式碼。執行應用程式後,我們可以看到與之前範例相同的線框立方體。
程式碼解析
檢視 TStrokeCube 的 Render 方法,我們可以看到它呼叫了 Context.DrawCube 方法來繪製立方體。
procedure TStrokeCube.Render;
begin
Context.DrawCube(
TPoint3D.Zero,
TPoint3D.Create(Width, Height, Depth),
AbsoluteOpacity, FColor);
end;
內容解密:
Context.DrawCube是 FireMonkey 用於繪製立方體的方法。TPoint3D.Zero表示立方體的中心點。TPoint3D.Create(Width, Height, Depth)定義了立方體的大小。AbsoluteOpacity和FColor用於控制立方體的透明度和顏色。
開發自訂線框元件
接下來,我們將開發一個自訂的線框元件,名為 TWireframe,用於渲染任意的線框模型。
定義資料結構
首先,我們需要定義兩個資料結構:TPoints3D 用於儲存 3D 空間中的點,TEdges 用於儲存線段。
type
TPoints3D = class(TList<TPoint3D>);
TEdge = record
A, B: Integer;
end;
TEdges = class(TList<TEdge>)
procedure AddEdge(PStart, PEnd: Integer);
end;
實作 TWireframe 元件
TWireframe 元件繼承自 TControl3D,並覆寫了 Render 方法。
type
TWireframe = class(TControl3D)
private
FDrawColor: TAlphaColor;
FEdges: TEdges;
FPoints3D: TPoints3D;
FDisplayed: Boolean;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Render; override;
property DrawColor: TAlphaColor read FDrawColor write FDrawColor;
property Points3D: TPoints3D read FPoints3D;
property Edges: TEdges read FEdges;
property Displayed: Boolean read FDisplayed write FDisplayed;
end;
Render 方法實作
在 Render 方法中,我們遍歷 Edges 列表,並使用 Context.DrawLine 方法繪製線段。
procedure TWireframe.Render;
var
Edge: TEdge;
begin
if Displayed then
for Edge in Edges do
Context.DrawLine(Points3D[Edge.A], Points3D[Edge.B], 1, DrawColor);
end;
內容解密:
Context.DrawLine用於繪製線段。Points3D[Edge.A]和Points3D[Edge.B]分別表示線段的起點和終點。DrawColor控制線段的顏色。
使用 TWireframe 元件
最後,我們在表單上使用 TWireframe 元件來渲染一個金字塔模型。
procedure TFormWireframe.CreatePyramid;
begin
with FWireframe do
begin
Points3D.Add(Point3D(-2,-2,0)); // 0
Points3D.Add(Point3D(2,-2,0)); // 1
Points3D.Add(Point3D(-2,2,0)); // 2
Points3D.Add(Point3D(2,2,0)); // 3
Points3D.Add(Point3D(0,0,6)); // 4
Edges.AddEdge(0,1);
Edges.AddEdge(1,3);
Edges.AddEdge(3,2);
Edges.AddEdge(2,0);
Edges.AddEdge(0,4);
Edges.AddEdge(1,4);
Edges.AddEdge(2,4);
Edges.AddEdge(3,4);
end;
end;
圖表翻譯:
此圖示呈現了金字塔模型的頂點和邊的定義,清楚地展示了模型的結構。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title FireMonkey 3D渲染自訂元件開發
package "FireMonkey 3D 開發" {
package "內建元件" {
component [TStrokeCube] as cube
component [Context3D] as ctx
component [TPoint3D] as point
}
package "自訂元件" {
component [TWireframe] as wire
component [頂點定義] as vertex
component [邊線繪製] as edge
}
package "渲染流程" {
component [Render 方法] as render
component [DrawCube] as draw
component [金字塔模型] as pyramid
}
}
cube --> ctx : 3D 繪圖
ctx --> draw : 呼叫繪製
point --> vertex : 座標系統
vertex --> edge : 連接頂點
edge --> wire : 線框模型
wire --> render : 自訂渲染
render --> pyramid : 建模應用
note right of cube : Color, Opacity\nWidth, Height, Depth
note right of wire : 自訂頂點\n邊線連接
@enduml
此圖表表示金字塔的結構,其中節點代表頂點,邊代表連線頂點的線段。
在FireMonkey中建立3D應用程式:基礎與實作
建立3D線框模型
要建立一個簡單的金字塔線框模型,需要定義五個點,分別代表金字塔底部的四個角和頂部的一個點。然後,需要繪製連線四個底部角的邊,以及從每個底部角到頂部的四條邊。
// 定義金字塔的五個點
Context.BeginScene;
try
Context.Clear(TAlphaColorRec.White);
// 設定金字塔的五個頂點
Points[0] := TPoint3D.Create(-0.5, -0.5, 0.5); // 底部左前
Points[1] := TPoint3D.Create(0.5, -0.5, 0.5); // 底部右前
Points[2] := TPoint3D.Create(0.5, -0.5, -0.5); // 底部右後
Points[3] := TPoint3D.Create(-0.5, -0.5, -0.5); // 底部左後
Points[4] := TPoint3D.Create(0, 0.5, 0); // 頂部
// 繪製金字塔的邊
Context.DrawLine(Points[0], Points[1], 1);
Context.DrawLine(Points[1], Points[2], 1);
Context.DrawLine(Points[2], Points[3], 1);
Context.DrawLine(Points[3], Points[0], 1);
Context.DrawLine(Points[0], Points[4], 1);
Context.DrawLine(Points[1], Points[4], 1);
Context.DrawLine(Points[2], Points[4], 1);
Context.DrawLine(Points[3], Points[4], 1);
finally
Context.EndScene;
end;
內容解密:
這段程式碼首先初始化了一個3D渲染上下文,並清除了背景。然後定義了金字塔的五個頂點,分別是底部的四個角和頂部的一個點。接著,使用DrawLine方法繪製了金字塔的邊,包括底部的四條邊和連線底部與頂部的四條邊。
使用現成的3D物件
FireMonkey提供了多種現成的3D物件,從簡單的TStrokeCube或TGrid3D到更複雜的元件,這些元件維護自己的頂點和索引緩衝區,用於繪製複雜的幾何形狀。
所有3D物件都繼承自TControl3D類別,該類別引入了3D空間中的位置和變換,並透過實作不同的滑鼠事件為所有3D控制項增加了互動性。
建立互動式3D地球視覺化
接下來,我們將建立一個互動式的3D地球視覺化。首先,建立一個新的Delphi多裝置專案,並選擇3D應用程式作為應用程式型別。
設定表單和新增TDummy元件
將表單的Name屬性設定為FormEarth,並將其Color設定為黑色。然後,在表單上新增一個TDummy元件,並將其Name屬性設定為DummyScene。
新增TSphere元件和材質
在表單上新增一個TSphere元件,並確保它屬於根虛擬控制項。將球體重新命名為SphereEarth。然後,新增一個TTextureMaterialSource元件,並使用SphereEarth物件的MaterialSource屬性將其連線到球體。
// 設定SphereEarth的材質源
SphereEarth.MaterialSource := TextureMaterialSource1;
載入地球紋理
點選Texture屬性旁邊的省略號按鈕,然後點選“編輯”以載入用於紋理的點陣圖。可以從網上下載免費的地球紋理,例如NASA的Visible Earth網站。
新增動畫
在表單上新增一個TFloatAnimation元件,並將其拖到結構檢視中的EarthSphere元件上,以實作地球的旋轉動畫。
使用FireMonkey建立互動式3D應用程式
FireMonkey是一個強大的跨平台框架,能夠讓開發者輕鬆建立具有豐富視覺效果的應用程式。本篇文章將介紹如何使用FireMonkey建立互動式的3D應用程式。
建立旋轉的地球
首先,我們將建立一個簡單的3D應用程式,顯示一個旋轉的地球。我們將使用TSphere元件來代表地球,並使用TFloatAnimation元件來實作旋轉動畫。
- 建立一個新的Delphi多裝置專案,並選擇3D應用程式範本。
- 將
TSphere元件拖曳到3D檢視中,並將其Name屬性設為SphereEarth。 - 展開
SphereEarth的PropertyName屬性,並選擇RotationAngle.Y屬性。 - 將
TFloatAnimation元件拖曳到SphereEarth上,並設定其屬性:Enabled:TrueLoop:TrueDuration:5秒StopValue:-360
這樣,地球就會繞其垂直軸旋轉。
新增互動功能
接下來,我們將新增互動功能,讓使用者可以透過點選地球來改變其與螢幕的距離。
- 雙擊
SphereEarth的OnClick事件,並輸入以下程式碼:
procedure TFormEarth.SphereEarthClick(Sender: TObject);
begin
if SphereEarth.Position.Z < 0 then
TAnimator.AnimateFloat(SphereEarth, 'Position.Z', 1, 0.2)
else
TAnimator.AnimateFloat(SphereEarth, 'Position.Z', -1, 0.2);
end;
內容解密:
這段程式碼檢查地球的Position.Z屬性。如果它小於0,則將其動畫到1,否則將其動畫到-1。動畫持續0.2秒。
這樣,當使用者點選地球時,它就會移動到螢幕的前方或後方。
建立互動式3D坐標系
接下來,我們將建立一個互動式的3D坐標系,使用三個3D箭頭來表示坐標軸的方向和原點。
- 建立一個新的Delphi多裝置專案,並選擇空白應用程式範本。
- 將
TViewport3D元件拖曳到表單上,並將其對齊到客戶端。 - 將
TDummy元件拖曳到表單上,並將其Name屬性設為DummyCamera。 - 將
TCamera元件拖曳到表單上,並將其Name屬性設為CameraZ。 - 在結構檢視中,將
CameraZ拖曳到DummyCamera上。
這樣,我們就可以透過改變DummyCamera的旋轉角度來改變相機的位置和方向。
新增互動功能
接下來,我們將新增互動功能,讓使用者可以透過手勢來改變相機的位置和方向。
使用者可以透過水平移動手指來改變相機的旋轉角度,透過垂直移動手指來改變相機的傾斜角度,透過縮放手勢來改變相機的距離。
// 程式碼範例
procedure TFormArrows3D.Viewport3D1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
// 處理滑鼠按下事件
end;
procedure TFormArrows3D.Viewport3D1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
begin
// 處理滑鼠移動事件
end;
procedure TFormArrows3D.Viewport3D1Gesture(Sender: TObject; const EventInfo: TGestureEventInfo; var Handled: Boolean);
begin
// 處理手勢事件
end;
內容解密:
這些事件處理程式碼將用於處理使用者的互動操作,例如滑鼠按下、移動和手勢事件。具體實作細節將取決於應用程式的需求。