3D Objects are like wrapped papers in 3D form. They consist of points which shape a polygon. It’s very rare to use anything other than triangles, and more complex shapes are decomposed into multiple triangles. Our 3D objects are stored with these points, data that which points are shaping polygons. In modern application development most of these objects are generated by a 3D Designer Software with their own 3d Object standards and these are displayed or animated in mechanics by a 3D Engine. In C++ Builder you can directly create your own 3D objects, you can animate them on runtime.
In C++ Builder, Viewport3D (TViewportd3D) component in C++ Builder FireMonkey projects is good to display many basic 3D Objects like Plane, Cube, Sphere, Cone, Plane, Ellipse3D etc. You can also easily load your 3D objects into Viewport3D by using Model3D (TModel3D).
How to create specific 3D objects in modern C++?
To create a 3D object to be used in Viewport3D we need to use TMesh classes. TMesh is a custom 3D shape that can be customized by drawing 3D shapes. It is a class publishes a set of properties from its ancestor, TCustomMesh, in order to let you design new 3D shapes at design time from within the IDE, through the Object Inspector. Use the Data property to specify the points, normals and textures for each point, and the order in which the resulting triangles are drawn. The designed shape is filled with the material specified through MaterialSource property. If no material is specified, then the shape is filled with red color.
1.Create a new Multi-Device C++ Builder Firemonkey project, Save all unit and project files into a folder.
2. Drag a Viewport3D from Tool Palette on to Form. We will use this to display our 3D Mesh object. Add Light, Dummy Object, Color Material.
3. Add a Button to generate mesh when button is pressed.
3. Go to Unit1.h, lets define our TMesh pointer in public section of Form as below;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//--------------------------------------------------------------------------- #ifndef Unit1H #define Unit1H //--------------------------------------------------------------------------- #include <System.Classes.hpp> #include <FMX.Controls.hpp> #include <FMX.Forms.hpp> //--------------------------------------------------------------------------- class TForm1 : public TForm { __published: // IDE-managed Components private: // User declarations public: // User declarations __fastcall TForm1(TComponent* Owner); TMesh *mesh; }; //--------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif |
4. Back to Form design, and double click to Button1, add these variables.
1 2 3 4 5 6 |
TPoint3D P0,P1,P2,P3; int NP=0; // Number of Points int NI=0; // Number of Indexes int i, numofplanes=2; |
5. And add these lines (Step 5,6,7) to setup our new mesh. Note that Parent object must be defined to be displayed. Here our parent object will be Dummy1. You can set to ViewPort3D1 too.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
if(mesh!=NULL) mesh->Free(); // delete mesh from memory every press mesh=new TMesh(Form1); // create a new Mesh in memory mesh->Parent=Dummy1; // Parent Object of Mesh MUST be defined, otherwise it is not displayed // Setting 3D Size of our 3D object mesh->Width=1; mesh->Height=1; mesh->Depth=1; // Setting 3D Position of our 3D object mesh->Position->X=0; mesh->Position->Y=0; mesh->Position->Z=0; // Setting Scale of our 3D Object mesh->Scale->X=1; mesh->Scale->Y=1; mesh->Scale->Z=1; // Setting Rotation of our 3D Object in X Y Z Angles mesh->RotationAngle->X=0; mesh->RotationAngle->Y=0; mesh->RotationAngle->Z=0; // Setting RotationCenter of our 3D Object mesh->RotationCenter->X=0; mesh->RotationCenter->Y=0; mesh->RotationCenter->Z=0; // Setting some specifics mesh->WrapMode=TMeshWrapMode::Original; mesh->TwoSide=true; mesh->Visible=true; mesh->Opacity=1.0; // Setting Mesh Data that contains 3D Points and Polygons mesh->Data->Clear(); mesh->Data->VertexBuffer->Length=4*(numofplanes); mesh->Data->IndexBuffer->Length= 6*(numofplanes); |
Here above, we used 4 and 6 magic numbers to create VertexBuffer and IndexBuffer,
1 2 3 4 |
mesh->Data->VertexBuffer->Length=4*(numofplanes); mesh->Data->IndexBuffer->Length= 6*(numofplanes); |
Mesh Data has 4 parameters, these are P0, P1, P2, P3 nodes;
1 2 3 4 5 6 |
mesh->Data->VertexBuffer->Vertices[NP+0] = P0; mesh->Data->VertexBuffer->Vertices[NP+1] = P1; mesh->Data->VertexBuffer->Vertices[NP+2] = P2; mesh->Data->VertexBuffer->Vertices[NP+3] = P3; |
and Index Buffer has 6 params, because 4 nodes creates 2 faces and we can define each of them by 3 poins
1 2 3 4 5 6 7 8 9 |
mesh->Data->IndexBuffer->Indices[NI+0] =NP+0; mesh->Data->IndexBuffer->Indices[NI+1] =NP+2; mesh->Data->IndexBuffer->Indices[NI+2] =NP+1; mesh->Data->IndexBuffer->Indices[NI+3] =NP+0; mesh->Data->IndexBuffer->Indices[NI+4] =NP+3; mesh->Data->IndexBuffer->Indices[NI+5] =NP+2; |
maybe this gives more help to understand, https://vulkan-tutorial.com/Vertex_buffers/Index_buffer
6. Now let’s add our Points and Polygons to Mesh Data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
//Add Some Points P0.X=100; P0.Y=100; P0.Z=50; P1.X=200; P1.Y=200; P1.Z=55; P2.X=150; P2.Y=180; P2.Z=60; P3.X=220; P3.Y=190; P3.Z=58; // Add Points to Mesh Data in its NP Number mesh->Data->VertexBuffer->Vertices[NP+0] = P0; mesh->Data->VertexBuffer->Vertices[NP+1] = P1; mesh->Data->VertexBuffer->Vertices[NP+2] = P2; mesh->Data->VertexBuffer->Vertices[NP+3] = P3; // Add Texture Coords mesh->Data->VertexBuffer->TexCoord0[NP+0] =PointF(0, (P0.Y+35)/45); mesh->Data->VertexBuffer->TexCoord0[NP+1] =PointF(0, (P0.Y+35)/45); mesh->Data->VertexBuffer->TexCoord0[NP+2] =PointF(0, (P0.Y+35)/45); mesh->Data->VertexBuffer->TexCoord0[NP+3] =PointF(0, (P0.Y+35)/45); // Add Normals if you need, or let it default // mesh->Data->Normals="....."; // Add Polygons shaped with 3 points mesh->Data->IndexBuffer->Indices[NI+0] =NP+0; mesh->Data->IndexBuffer->Indices[NI+1] =NP+2; mesh->Data->IndexBuffer->Indices[NI+2] =NP+1; mesh->Data->IndexBuffer->Indices[NI+3] =NP+0; mesh->Data->IndexBuffer->Indices[NI+4] =NP+3; mesh->Data->IndexBuffer->Indices[NI+5] =NP+2; // We added 4 Points and 6 Indicies, lets add this, so we can keep using codes above on new definitions. NP+=4; NI+=6; // if you have more polygons keep adding points and all as same above here |
7. Finally let’s setup our mesh Material and some other specifics.
1 2 3 4 5 6 |
mesh->MaterialSource=TextureMaterialSource1; mesh->MaterialSource->Material>FillMode= fmWireFrame; mesh->Data->CalcFaceNormals(true); mesh->Repaint(); |
8. Don’t forget to free mesh from the memory when user close your application.
1 2 3 4 5 6 |
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { if(mesh!=NULL) mesh->Free(); } |
C++ Builder is the easiest and fastest C and C++ compiler and IDE for building simple or professional applications on the Windows operating system. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for UIs.
There is a free C++ Builder Community Edition for students, beginners, and startups; it can be downloaded from here. For professional developers, there are Professional, Architect, or Enterprise versions of C++ Builder and there is a trial version you can download from here.