Loading models
You can find the model component in the toolbar under Gorilla3D > TGorillaModel
A TGorillaModel component automatically manages sub-meshes, materials and animations for you. So this is the best component for loading complex mesh data.
Every model contains a number of TGorillaMesh instances which holds the vertex data of a specific child mesh. At least one mesh will be available in a valid model.
When loading models from file / stream, all materials and animations, defined in the source file / stream, are loaded too. In case you are using explicit animation files (only for Collada DAE format), you need to load them afterwards by AddAnimationFromFile().
A TGorillaModel instance needs to be a child / sub-child of a TGorillaViewport instance, otherwise it will not be displayed.
Supported file formats
Currently it is allowed to use the following file-formats: G3D, DAE, OBJ, STL, FBX, X3D, glTF (modified: 2020-10-02)
Format | MeshData | Materials | Animations | Lights | Cameras | Physics | Shaders | Export | Version | Notice |
---|---|---|---|---|---|---|---|---|---|---|
G3D | ✔ | ✔ | ✔ | ✔ | ✔ | ✘ | ✘ | ✔ | 1, 2 | |
DAE | ✔ | ✔ | ✔ | ✔ | ✔ | ✘ | ✘ | ✘ | 1.4+ | |
OBJ | ✔ | ✔ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | only ascii format | |
STL | ✔ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✔ | 1.0 | ascii and binary format, Standard + Solidworks-Format |
FBX | ✔ | ✔ | ✔ | ✘ | ✘ | ✘ | ✘ | ✘ | 7.1 - 7.5 | only binary (v0.8.3.1931+). Animation import for 7.3-7.4 validated, 7.5 not working properly yet |
X3D | ✔ | ✔ | ✔ | ✘ | ✘ | ✘ | ✘ | ✘ | deprecated | |
glTF | ✔ | ✔ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | 2.0 | only glTF json format, not glb |
Babylon | ✔ | ✔ | ✘ | ✔ | ✘ | ✘ | ✘ | ✘ | 4.x | |
Sketchfab | ✔ | ✔ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | glTF 2.0 | |
PLY | ✔ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | 1.0 | ascii and binary format (since v0.8.3.1966+) |
SketchUp | ✔ | ✔ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | v2020 | only Win64 binaries available (since v0.8.3.1966+) |
Components
Because model files mostly do not only contain a single element, but instead a complex hierarchy, we do provide various components to allow those structures.
TGorillaModel
A TGorillaModel is the head component for loaded models from file/asset. Even it's inherited from TGorillaMesh, it's not renderable. Instead it is just a container, managing sub-meshes, animations and materials. So a TGorillaModel needs to contain at least one TGorillaMesh in it's Meshes list.
TGorillaMesh
A TGorillaMesh is visual representation for geometry data allowing to render shapes. It can contain further sub-meshes. Each TGorillaMesh can be rendered by a different TMaterialSource. It is allowed to use TGorillaMesh as standalone component for rendering (without a parent TGorillaModel). This is already used in our primitives: TGorillaCube, TGorillaSphere and so on. You need to create at least a TMeshDef instance for the “Def” property.
constructor TMyMesh.Create(AOwner: TComponent); begin inherited; // create a logical mesh definition instance FDef := TMeshDef.Create(nil); RebuildMesh(); end; procedure TMyMesh.RebuildMesh(AIsStatic : Boolean = true); begin // setup vertex and index data here [...] // push mesh data to our mesh-definition and create a static GPU buffer if AIsStatic then CreateStaticBuffer(); end; procedure TMyMesh.CreateStaticBuffer(); var LMeshDef : TMeshDef; LMeshData : TMeshData; begin LMeshDef := TMeshDef(FDef); LMeshDef.IsStatic := false; try LMeshData := Self.MeshData; // update rendering list and bounding box LMeshData.BoundingBoxNeedsUpdate(); LMeshData.GetBoundingBox(); DoUpdateParentRenderList(Parent); // copy vertices to mesh definition LMeshDef.ApplyFromMeshData(LMeshData); LMeshData.VertexBuffer.Length := 0; LMeshData.IndexBuffer.Length := 0; finally // we need to reset the "IsStatic" value to create a buffer object LMeshDef.IsStatic := true; end; end;
TGorillaVertexGroup
A TGorillaVertexGroup is inherited from TGorillaMesh, but renders differently. A vertex group allows to group a number of triangles, referred in an owner mesh, to a virtual mesh.
You are able to render only this specific triangle group by a specific material. To setup a vertex group you need to have separated indexbuffer in you MeshData and a parent mesh with corresponding vertex data.
In some cases this helps to improve memory usage. While declaring vertex data in a parent mesh, those virtual meshes can reuse the same vertices for their triangle rendering, instead of duplicating them.
CAUTION: TGorillaVertexGroup needs to be attached to an owner TGorillaMesh as child, with the relevant vertex data.
WARNING: Currently it is not recommended to setup a TGorillaVertexGroup yourself. Instead use the definition hierarchy by TVertexGroupDef inside of TMeshDef. By TGorillaModel.LoadNewModelFromDef() you are able to build visual components from your definitions.
TGorillaGroup
A TGorillaGroup is just a simple transformable element used to group sub-meshes. A group itself is not renderable.
Loading a models at designtime
Since v0.8.3.2265 Gorilla3D is able to load model in designtime editor.
We provide different ways to do it.
Loading a model from an assets package
In case you have already set up an assets package with the assets manager in your form, you can link a TGorillaModal to that.
- Link the TGorillaAssetsManager component to the TGorillaModel.AssetsManager property
- Type in the name of your package (DisplayName) into the “PackageName” property
- Type in the model asset name in your package into the “Source” property
The IDE will show up a loading window while it's setting up the model.
The framework will generate TGorillaModel data from the linked package. It will repeat to load the model when starting the application. The data is not stored again in the formular *.fmx file, it only restores it from package information.
WARNING*: Your IDE memory is limited to 3GB, which can be exceeded very fast due to cached data by the IDE.
Loading a model from binary storage
It is also possible to store and load complete model data (incl. textures) from binary storage inside of your formular *.fmx file.
To do so, simply:
- Open the file dialog of the “Source” property in the object inspector
- Select your model file (Please check the supported file formats)
- All model data will be stored inside the *.fmx file of your form
The IDE will show up a loading window while it's setting up the model. Because the data + textures are stored in the *.fmx of your form, it can become very large. This may slow down the performance of the IDE.
WARNING*: Your IDE memory is limited to 3GB, which can be exceeded very fast due to cached data by the IDE and model data with textures.
Loading a model from at runtime
Besides the user-friendly loading at runtime, we of course support the model loading from file or stream.
You can also take advantage of the designtime mechanisms at runtime.
Loading a new model from file
Creating a model instance at runtime is very easy and often very helpful for creating dynamically loaded scenes.
- Form1.pas
uses Gorilla.DefTypes, Gorilla.G3D.Loader, Gorilla.DAE.Loader, Gorilla.OBJ.Loader, Gorilla.STL.Loader, Gorilla.FBX.Loader, Gorilla.GLTF.Loader, Gorilla.Babylon.Loader, Gorilla.PLY.Loader, Gorilla.SKP.Loader, Gorilla.Model; // in our form (TForm1) we added a field named "FModel" procedure TForm1.FormCreate(Sender: TObject); var LPath : String; LAssetPckg : TGorillaAssetPackage; begin LPath := 'c:\my3dfile.dae'; LAssetPckg := nil; FModel := TGorillaModel.LoadNewModelFromFile(FGorilla, LAssetPckg, OpenDialog1.FileName, GORILLA_ANIMATION_CACHING_DEFAULT); FModel.Parent := FGorilla; end;
For the moment you can ignore the last parameter “GORILLA_ANIMATION_CACHING_DEFAULT” of the LoadNewModelFromFile() call. We will explain this in the Animations section.
You also can ignore the AssetPckg parameter currently. We will explain assets management in the AssetsManager section.
Loading into an existing TGorillaModel instance
In case you've dragged a TGorillaModel component onto your viewport, you can load the model by the following method.
- Form1.pas
uses Gorilla.G3D.Loader, Gorilla.DAE.Loader, Gorilla.OBJ.Loader, Gorilla.STL.Loader, Gorilla.FBX.Loader, Gorilla.GLTF.Loader, Gorilla.Babylon.Loader, Gorilla.PLY.Loader, Gorilla.SKP.Loader, Gorilla.Model; // in our form (TForm1) we added a field named "FModel" procedure TForm1.FormCreate(Sender: TObject); var LPath : String; LAssetPckg : TGorillaAssetPackage; begin LPath := 'c:\my3dfile.dae'; LAssetPckg := nil; GorillaModel1.LoadFromFile(LAssetPckg, OpenDialog1.FileName, GORILLA_ANIMATION_CACHING_DEFAULT); end;
To load a specific file format you need to include the format unit:
- Gorilla.G3D.Loader
- Gorilla.DAE.Loader
- Gorilla.OBJ.Loader
- Gorilla.STL.Loader
- Gorilla.FBX.Loader (bugfixes and animations since v0.8.3.1966+)
- Gorilla.GLTF.Loader
- Gorilla.Babylon.Loader
- Gorilla.Sketchfab.Loader (uses glTF format)
- Gorilla.X3D.Loader
- Gorilla.X3DZ.Loader
- Gorilla.X3DVZ.Loader
- Gorilla.PLY.Loader (v0.8.3.1966+)
- Gorilla.SKP.Loader (v0.8.3.1966+)
Only then the format loader is able to load the specific file.
Loading a model from package
To adopt the behaviour used in the IDE at design time, you can load model data from assets package also at runtime by the following method.
- Form1.pas
uses Gorilla.DefTypes, Gorilla.G3D.Loader, Gorilla.DAE.Loader, Gorilla.OBJ.Loader, Gorilla.STL.Loader, Gorilla.FBX.Loader, Gorilla.GLTF.Loader, Gorilla.Babylon.Loader, Gorilla.PLY.Loader, Gorilla.SKP.Loader, Gorilla.AssetsManager, Gorilla.Model; [...] var FAssetsManager : TGorillaAssetsManager; FPackage : TGorillaAssetsPackage; FModel : TGorillaModel; // in our form (TForm1) we added a field named "FModel" procedure TForm1.FormCreate(Sender: TObject); begin // setup the assets manager and load an existing package from file FAssetsManager := TGorillaAssetsManager.Create(Self); FPackage := FAssetsManager.LoadPackageFromFile('C:\Temp\mypackage.zip'); FPackage.DisplayName := 'MyPackage'; // prepare the model for loading from package FModel := TGorillaModel.Create(GorillaViewport1); FModel.Parent := GorillaViewport1; // start linking to assets manager like at designtime FModel.AssetsManager := FAssetsManager; FModel.PackageName := 'MyPackage'; FModel.Source := 'myfile.dae'; end;
Loading a model from source
This is another way to load model data from file at runtime. The difference to LoadFromFile() and LoadNewModelFromFile() is, that it will store model data in the BinaryData property too.
- Form1.pas
uses Gorilla.DefTypes, Gorilla.G3D.Loader, Gorilla.DAE.Loader, Gorilla.OBJ.Loader, Gorilla.STL.Loader, Gorilla.FBX.Loader, Gorilla.GLTF.Loader, Gorilla.Babylon.Loader, Gorilla.PLY.Loader, Gorilla.SKP.Loader, Gorilla.AssetsManager, Gorilla.Model; [...] var FModel : TGorillaModel; // in our form (TForm1) we added a field named "FModel" procedure TForm1.FormCreate(Sender: TObject); begin // prepare the model for loading from package FModel := TGorillaModel.Create(GorillaViewport1); FModel.Parent := GorillaViewport1; FModel.Source := 'c:\Temp\myfile.dae'; end;
Instancing / Model duplication
Instanced Rendering
Since 0.8.3.2265 instanced rendering of the same mesh for x-times was implemented.
Use this method to render for example grass or trees. It is not recommended to use it for animated charaters, because they would be rendered the same (with the same animation frame).
You can simply setup instanced rendering in your TGorillaModel or TGorillaMesh object.
/// we create 4 instances in a row GorillaModel1.AddInstance(TMatrix3D.CreateTranslation(Point3D(-10, 0, 0))); GorillaModel1.AddInstance(TMatrix3D.CreateTranslation(Point3D(-5, 0, 0))); GorillaModel1.AddInstance(TMatrix3D.CreateTranslation(Point3D(5, 0, 0))); GorillaModel1.AddInstance(TMatrix3D.CreateTranslation(Point3D(10, 0, 0))); /// afterwards we can modify a specific instance var LTransf : TMatrix3D; LTransf := TMatrix3D.CreateScaling(Point3D(2, 2, 2)); LTransf := LTransf * TMatrix3D.CreateRotationY(DegToRad(90)); LTransf := LTransf * TMatrix3D.CreateScaling(Point3D(2, 2, 2)); GorillaModel1.Instances[2] := LTransf;
Instancing by template (TModelDef)
Since 0.8.3.1966+ we've refactored the way to instanciate models. The previous method was incomplete in handling animated models. In the following example we show how to load a complex animated model with multiple meshes and animations. We will load up a template (TModelDef), which will be used for duplication. The template (TModelDef) itself will not be rendered in our example, but of course that's possible too.
Each duplicated model will run a different animation to show instanciating is still fast, but allows to handle models differently. This demo code uses cached animations (GORILLA_ANIMATION_CACHING_DEFAULT), otherwise 32 animated instances will not render properly anymore, due to many vertex operations.
procedure TForm1.InstanciateModel(AModelsPath : String); const NUM_OF_MODELS = 32; MODELS_SPACE = 8; var LAnim : TGorillaAnimation; LMdlPath : String; I : Integer; LPlayInst : TGorillaModel; LOfs : Single; begin LAnim := nil; // load player model LMdlPath := IncludeTrailingPathDelimiter(AModelsPath) + IncludeTrailingPathDelimiter('archer'); FPlayerTemplate := TGorillaModel.LoadNewModelFromFile(FGorilla, FPackage, LMdlPath + 'archer.dae', GORILLA_ANIMATION_CACHING_DEFAULT); FPlayerTemplate.Parent := FGorilla; FPlayerTemplate.Scale.Point := Point3D(0.05, 0.05, 0.05); FPlayerTemplate.SetHitTestValue(false); // add various animations FPlayerTemplate.AddAnimationFromFile(LMdlPath + 'archer-aim-idle.dae', GORILLA_ANIMATION_CACHING_DEFAULT); FPlayerTemplate.AddAnimationFromFile(LMdlPath + 'archer-idle2.dae', GORILLA_ANIMATION_CACHING_DEFAULT); FPlayerTemplate.AddAnimationFromFile(LMdlPath + 'archer-idle3.dae', GORILLA_ANIMATION_CACHING_DEFAULT); FPlayerTemplate.AddAnimationFromFile(LMdlPath + 'archer-crouch-idle.dae', GORILLA_ANIMATION_CACHING_DEFAULT); // now create instances FPlayerInstances := TObjectList<TGorillaModel>.Create(false); I := 0; for I := 0 to NUM_OF_MODELS - 1 do begin // perform a real duplication of visual components by **FALSE** for the second parameter // if second parameter is **TRUE**, only proxy components will be produced LPlayInst := FPlayerTemplate.Duplicate(FGorilla, false) as TGorillaModel; FPlayerInstances.Add(LPlayInst); LPlayInst.Parent := FGorilla; // line up characters in a row LOfs := -(NUM_OF_MODELS div 2) * MODELS_SPACE; LPlayInst.Position.Point := Point3D(LOfs + (I * MODELS_SPACE), 0, 0); LPlayInst.RotationAngle.X := 180; // select one of the available animations - so characters animate differently case I mod 4 of 0 : LAnim := LPlayInst.AnimationManager.Animations.Items['archer-aim-idle.dae']; 1 : LAnim := LPlayInst.AnimationManager.Animations.Items['archer-idle2.dae']; 2 : LAnim := LPlayInst.AnimationManager.Animations.Items['archer-idle3.dae']; else LAnim := LPlayInst.AnimationManager.Animations.Items['archer-crouch-idle.dae']; end; // start the duplicated character animation if Assigned(LAnim) then LAnim.Start(); end; // we ignore the template for rendering FPlayerTemplate.Visible := false; end;
Plugins
Sketchfab Plugin
Since 0.8.2.1675 we provide a Sketchfab plugin directly by using our loading mechanism. Before implementation you'll need to ensure you've got a valid Sketchfab account with username and password.
Remarks: You'll also need a new clientid and clientsecret for your application. To request those credentials contact support at https://sketchfab.com/developers/oauth#registering-your-app
The usage of the plugin is simular to other file formats in Gorilla3D. But instead of using the simple method headers, you'll have to use the extended method call with a TGorillaLoadOptions parameter.
// setup loading options to connect to sketchfab LOpts := TGorillaLoadOptions.Create(FUID, '.sketchfab', FPackage); LOpts.FileInfo.OpenFormat := TGorillaFileOpenFormat.fofDownload; LOpts.FileInfo.URL := Gorilla.Sketchfab.Loader.GORILLA_SKETCHFAB_URL; LOpts.FileInfo.ClientId := <YOUR_CLIENT_ID>; LOpts.FileInfo.ClientSecret := <YOUR_CLIENT_SECRET>; LOpts.FileInfo.Username := <YOUR_USERNAME>; LOpts.FileInfo.Password := <YOUR_PASSWORD>; // set an individual download folder, where data is written to // leave empty to use system temporary folders LOpts.ExtractDirectory := ''; try // try loading sketchfab model FModel := TGorillaModel.LoadNewModelFromFile(GorillaViewport1, LOpts); if Assigned(FModel) then FModel.Parent := GorillaViewport1; except on E:Exception do ShowMessage('Failed to load Sketchfab model: ' + E.Message); end;
The plugin will automatically download a zip-archive with a glTF file to your preferred folder (“ExtractDirectory”). On successful download it extracts this data and tries to load the contained model. Before requesting Sketchfab, the loader checks the ExtractDirectory for an already existing download of UID. If a zip and gltf file already exists it will directly load it, instead of downloading again.
You have to take care yourself in case a previous download is invalid or decprecated.
Exporting a model
We provide 2 export formats at the moment: G3D and STL, which are easy to use.
G3D Export
uses Gorilla.G3D.Exporter; procedure TForm1.MenuItem1Click(Sender: TObject); var LG3DExp : TGorillaG3DExporter; LToBinary : Boolean; LZipped : Boolean; LBeautified : Boolean; begin LToBinary := true; LZipped := true; LBeautified := true; if Assigned(fModel) then begin if SaveDialog1.Execute() then begin LG3DExp := TGorillaG3DExporter.Create(); try if LToBinary then LG3DExp.Format := TGorillaG3DFormat.BSONFormat else LG3DExp.Format := TGorillaG3DFormat.JSONFormat; LG3DExp.Zipped := LZipped; LG3DExp.Beautified := LBeautified; LG3DExp.SaveToFile(fModel.Def as TModelDef, SaveDialog1.FileName); finally FreeAndNil(LG3DExp); end; ShowMessage('File successfully stored:'#13#10+ SaveDialog1.FileName); end; end; end;
STL Export
<file pascal> uses Gorilla.STL.Exporter; procedure TForm1.MenuItem1Click(Sender: TObject); var LSTLExp : TGorillaSTLExporter; LToBinary : Boolean; LAllowMultipleMeshes : Boolean; LUseMultipleFiles : Boolean; begin // ascii and binary format supported LToBinary := true; // because STL supports only single meshes per file (per default), // we can split up a model with multiple meshes into multiple files LAllowMultipleMeshes := true; // but this exporter also allows to export multiple meshes to a single file // just set UseMultipleFiles to false LUseMultipleFiles := true; if Assigned(FModel) then begin if SaveDialog1.Execute() then begin LSTLExp := TGorillaSTLExporter.Create(); try LSTLExp.Binary := LToBinary; LSTLExp.AllowMultipleMeshes := LAllowMultipleMeshes; LSTLExp.UseMultipleFiles := LUseMultipleFiles; LSTLExp.SaveToFile(FModel.Def as TModelDef, SaveDialog1.FileName); finally FreeAndNil(LSTLExp); end; ShowMessage('File successfully stored:'#13#10+ SaveDialog1.FileName); end; end; end;
Next step: Animations