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.

  1. Link the TGorillaAssetsManager component to the TGorillaModel.AssetsManager property
  2. Type in the name of your package (DisplayName) into the “PackageName” property
  3. 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:

  1. Open the file dialog of the “Source” property in the object inspector
  2. Select your model file (Please check the supported file formats)
  3. 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.

https://sketchfab.com/

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