Sign in Join
Wiki copytemporary

BGRABitmap tutorial 15: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: BGRABitmap tutorial 15

OldNewLine
1+This tutorial shows how to render 3D objects using the TBGRAScene3D object.
2+
3+## Scene object
4+
5+The scene object is in the BGRAScene3D unit. Here is a simple example:
6+
7+``` pascal
8+uses BGRAScene3D, BGRABitmap, BGRABitmapTypes;
9+
10+procedure TForm1.FormPaint(Sender: TObject);
11+var
12+ scene: TBGRAScene3D;
13+ bmp: TBGRABitmap;
14+ base: array of IBGRAVertex3D;
15+ topV: IBGRAVertex3D;
16+begin
17+ bmp := TBGRABitmap.Create(ClientWidth,ClientHeight,BGRABlack);
18+
19+ scene := TBGRAScene3D.Create(bmp);
20+ //create a pyramid
21+ with scene.CreateObject(BGRA(255,240,128)) do
22+ begin
23+ //create vertices
24+ topV := MainPart.Add(0,-15,0);
25+ //pyramid base is in a clockwise order if we look at the pyramid from below
26+ base := MainPart.Add([-20,15,-20, 20,15,-20, 20,15,20, -20,15,20]);
27+
28+ AddFace(base);
29+ //add four faces, the three vertices are in a clockwise order
30+ AddFace([base[0],topV,base[1]]);
31+ AddFace([base[1],topV,base[2]]);
32+ AddFace([base[2],topV,base[3]]);
33+ AddFace([base[3],topV,base[0]]);
34+ topV := nil;
35+ base := nil;
36+ end;
37+ scene.Render;
38+ scene.Free;
39+
40+ bmp.Draw(Canvas,0,0);
41+ bmp.Free;
42+end;
43+```
44+
45+The scene object draws itself on a TBGRABitmap object. You can either pass the bitmap as a parameter when creating the object, as done here, or assign the Surface property afterwards. The scene is automatically centered in the bitmap.
46+
47+The scene object provides the CreateObject function, which returns an interface to the created object. Objects inside a scene are freed automatically when you free the scene.
48+
49+An object has a MainPart property which allows you to create and access vertices. Coordinates can be given as three single values, TPoint3D records, or an array of single values which length must be a multiple of 3. When you create a vertex, you receive an IBGRAVertex3D interface which can be used to create faces. You can add sub parts inside MainPart by using the CreatePart method. There can be nested subparts, each being rotated with its own matrix relative to the main part.
50+
51+The X axis points to the right, the Y axis points to bottom, and the Z axis points forward (behind the screen). It means that XY works the same way as in a bitmap, and there is a depth value. The faces must be in clockwise order to be visible.
52+
53+Here the color is set for the whole object when creating it, but you can set it individually for each face, or for each vertex.
54+
55+<figure>
56+<img src="BGRATutorial15a.png" title="BGRATutorial15a.png" />
57+<figcaption>BGRATutorial15a.png</figcaption>
58+</figure>
59+
60+As you can see, the pyramid is viewed from one side, so we can only see one face. There is no lighting either.
61+
62+In the 'with' block, add the following lines:
63+
64+``` pascal
65+ MainPart.Scale(1.3);
66+ MainPart.RotateYDeg(30);
67+ MainPart.RotateXDeg(20);
68+ MainPart.Translate(0,-5,0);
69+```
70+
71+The first line makes the object a little bigger. Then two rotations are applied. The first is around the Y axis and the second around the X axis. To figure out the rotation sign, imagine you are looking in the direction of the axis. A positive value in degrees means a clockwise rotation, and a positive value in radians means an anti-clockwise rotation.
72+
73+Finally a vertical translation is applied to center the object.
74+
75+<figure>
76+<img src="BGRATutorial15b.png" title="BGRATutorial15b.png" />
77+<figcaption>BGRATutorial15b.png</figcaption>
78+</figure>
79+
80+Now let's add some lighting:
81+
82+``` pascal
83+ //set ambiant lightness to dark (1 is normal lightness, 2 is complete whiteness)
84+ scene.AmbiantLightness := 0.5;
85+ //add a directional light from top-left, maximum lightness will be 0.5 + 1 = 1.5
86+ scene.AddDirectionalLight(Point3D(1,1,1), 1);
87+```
88+
89+The example uses lightness values. 0 means black, 1 means unchanged color, and 2 means white. The directional takes a Point3D parameter to indicate the direction of the ray. It does not need to be normalized.
90+
91+<figure>
92+<img src="BGRATutorial15c.png" title="BGRATutorial15c.png" />
93+<figcaption>BGRATutorial15c.png</figcaption>
94+</figure>
95+
96+## Deriving from TBGRAScene3D
97+
98+The scene code can be embedded in an object. Here is the previous example in a single unit:
99+
100+``` pascal
101+unit ex1;
102+
103+{$mode objfpc}{$H+}
104+
105+interface
106+
107+uses
108+ Classes, SysUtils, BGRAScene3D, BGRABitmapTypes;
109+
110+type
111+
112+ { TExample1 }
113+
114+ TExample1 = class(TBGRAScene3D)
115+ SandColor: TBGRAPixel;
116+ constructor Create;
117+ procedure Render; override;
118+ end;
119+
120+implementation
121+
122+{ TExample1 }
123+
124+constructor TExample1.Create;
125+var
126+ base: array of IBGRAVertex3D;
127+ top: IBGRAVertex3D;
128+begin
129+ inherited Create;
130+
131+ SandColor := BGRA(255,240,128);
132+
133+ //create a pyramid
134+ with CreateObject(SandColor) do
135+ begin
136+ top := MainPart.Add(0,-15,0);
137+ //pyramid base is in a clockwise order if we look at the pyramid from below
138+ base := MainPart.Add([-20,15,-20, 20,15,-20, 20,15,20, -20,15,20]);
139+ AddFace(base);
140+ //add four faces, the three vertices are in a clockwise order
141+ AddFace([base[0],top,base[1]]);
142+ AddFace([base[1],top,base[2]]);
143+ AddFace([base[2],top,base[3]]);
144+ AddFace([base[3],top,base[0]]);
145+
146+ MainPart.Scale(1.3);
147+ MainPart.RotateYDeg(30);
148+ MainPart.RotateXDeg(20);
149+ MainPart.Translate(0,-5,0);
150+ end;
151+
152+ //set ambiant lightness to dark (1 is normal lightness, 2 is complete whiteness)
153+ AmbiantLightness := 0.5;
154+ //add a directional light from top-left, maximum lightness will be 0.5 + 1 = 1.5
155+ AddDirectionalLight(Point3D(1,1,1),1);
156+
157+ //we can have antialiasing because it is a simple scene
158+ Antialiasing := True;
159+end;
160+
161+procedure TExample1.Render;
162+begin
163+ //fill background
164+ Surface.GradientFill(0,0,Surface.Width,Surface.Height,SandColor,MergeBGRA(SandColor,BGRABlack), gtRadial,PointF(0,0),PointF(Surface.Width,Surface.Height),dmSet);
165+
166+ inherited Render;
167+end;
168+
169+end.
170+```
171+
172+Now, to draw the scene, simply do:
173+
174+``` pascal
175+uses BGRABitmap, BGRABitmapTypes, BGRAScene3D, ex1;
176+
177+procedure TForm1.FormPaint(Sender: TObject);
178+var
179+ bmp: TBGRABitmap;
180+ scene: TBGRAScene3D;
181+begin
182+ bmp := TBGRABitmap.Create(ClientWidth,ClientHeight,BGRABlack);
183+
184+ scene := TExample1.Create;
185+ scene.Surface := bmp;
186+ scene.Render;
187+ scene.Free;
188+
189+ bmp.Draw(Canvas,0,0);
190+ bmp.Free;
191+end;
192+```
193+
194+By the way, antialiasing and a background have been added. Note that antialiasing works only for simple scenes. Complex scenes with texture and transparent colors may not render correctly.
195+
196+<figure>
197+<img src="BGRATutorial15d.png" title="BGRATutorial15d.png" />
198+<figcaption>BGRATutorial15d.png</figcaption>
199+</figure>
200+
201+[[BGRABitmap tutorial 14|Previous tutorial (canvas 2D)]] \| [[BGRABitmap tutorial 16|Next tutorial (textures with 3D objects)]]
202+
203+---
204+*From the Free Pascal wiki, page "BGRABitmap tutorial 15", as it stood on 2020-01-05 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
205+Category: BGRABitmap
206+Category: Graphics

Back to history