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, animations, lights and cameras, defined in the source file / stream, are loaded too. In case you are using explicit animation files (only for DAE and FBX 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.

Tutorial

Supported file formats

Currently it is allowed to use the following file-formats:

Format MeshData Materials Animations Lights Cameras Physics Shaders Export Version Notice
G3D 1, 2
DAE 1.4+
FBX 7.1 - 7.7 only binary format, animation import for 7.3 - 7.7
glTF/GLB 2.0 only glTF 2.0 format
OBJ only ascii format
STL 1.0 ascii and binary format, Standard + Solidworks-Format
X3D deprecated
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+)

The framework offers various ways to load model data into your project. Basically you need to decide when to load the data.

Design-Time

It is possible to load model data at design time in the IDE form editor. Simple drop a TGorillaModel from component palette onto your form.

The component should be placed inside a TGorillaViewport component or as child of another component inside the viewport.

You have the choice between embedding your model in the formular data (*.fmx file) or loading it dynamically from an assets package.

Embedded Model

Embedding models will store complete model data with hierarchy, animations, materials and textures into binary storage inside of your formular *.fmx file. The framework is able to load that data again.

Use the following steps:

  1. Drop a TGorillaModel component into your viewport
  2. Choose the “Source” property in the object inspector and open its dialog by “[…]”
  3. Select your model file (Please check the supported file formats!)
  4. An options dialog will open to configure your loading options
  5. All model data will be stored inside the *.fmx file of your form

When the loading options dialog appears you can configure the import process. But not all options are available for all formats.

  • Ignore importing animations
  • Animation caching settings
  • Ignore importing lights or cameras
  • Directly import additional animation files without an extra call
  • Limit texture size, in case you have a memory-sensitive application

Afterwards the IDE will show up a loading window while importing.

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 model data with textures.

Using Packages

To load model data from an assets package at design time, you will need a TGorillaAssetsManager component and a TGorillaModel component.

  1. Drop a TGorillaAssetsManager component onto your form
  2. Open the “Packages” collection
  3. Add a new package to the list
  4. Give it a DisplayName and a file location (during development we recommend a general location like “C:\Temp\assets.zip”)
  5. Drop a TGorillaModel component onto your viewport
  6. Link the TGorillaAssetsManager component to the TGorillaModel.AssetsManager property
  7. Type in the name of your package (DisplayName) into the “PackageName” property
  8. Type in the model asset name in your package into the “Source” property or load from disk
  9. If the package does not contain the model data yet, it will automatically add it to the archive

The IDE will show up a load-options dialog if the model data did not already exist.

If it was already available in the archive the IDE will show a loading-dialog while importing the data into cache.

Notice: The IDE will reload the model data from package on each refresh! So the loading window may appear multiple times during development.

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 model data.

Sketchfab Import

A great feature of Gorilla3D is the integrated Sketchfab support at design time, which can be accessed by the TGorillaPrefabManager component.

To take advantage of that feature:

  1. Drop a TGorillaPrefabManager component onto your form
  2. Select the component in structure view and right click onto it
  3. A popup menu appears with an “Import from Sketchfab” option.
  4. Another dialogue will open to search for your specific model

The plugin will download the model as glTF file from Sketchfab into:

C:\Users\Public\Documents\Gorilla3D\

Afterwards it will automatically create a new embedded TGorillaModel instance for you.

WARNING: We do not recommend to embed large models or models with many large textures. This will increase memory usage and size of DFM-data, which slows down the IDE!

NOTICE: Not all models on Sketchfab are fully compatible. The platform automatically converts models to glTF format, which sometimes destroys the model data.

WARNING: (2023-02-28) Due to some security issues we had to disable the Sketchfab plugin. We are sorry and we will try to fix the problem with the next update.

Runtime

Besides the user-friendly loading at design time, we of course support the model loading from file or stream.

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.FBX.Loader,  
  Gorilla.GLTF.Loader,
  Gorilla.GLB.Loader,    
  Gorilla.OBJ.Loader,
  Gorilla.STL.Loader,
  Gorilla.Babylon.Loader,
  Gorilla.PLY.Loader,
  Gorilla.SKP.Loader,
  Gorilla.X3D.Loader, 
  Gorilla.X3DZ.Loader,   
  Gorilla.X3DVZ.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.

For loading model data from package, you need to setup an assets manager with a package item. You can then request a model file by its filename.

If the model data already exists, it will be loaded, otherwise it will be automatically added to the package.

Form1.pas
uses
  Gorilla.DefTypes,
  Gorilla.G3D.Loader,
  Gorilla.DAE.Loader,
  Gorilla.FBX.Loader,  
  Gorilla.GLTF.Loader,
  Gorilla.GLB.Loader,    
  Gorilla.OBJ.Loader,
  Gorilla.STL.Loader,
  Gorilla.Babylon.Loader,
  Gorilla.PLY.Loader,
  Gorilla.SKP.Loader,
  Gorilla.X3D.Loader, 
  Gorilla.X3DZ.Loader,   
  Gorilla.X3DVZ.Loader, 
  Gorilla.AssetsManager,
  Gorilla.Model;
 
[...]
 
var FAssetsManager : TGorillaAssetsManager;
    FPackage : TGorillaAssetsPackage;
 
// in our form (TForm1) we added a field named "FModel"
procedure TForm1.FormCreate(Sender: TObject);
var LPath : String;
    LModel : TGorillaModel;    
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';
 
  // loading the model from package
  LPath := 'c:\my3dfile.dae';
  LModel:= TGorillaModel.LoadNewModelFromFile(GorillaViewport1, FPackage {!}, LPath, GORILLA_ANIMATION_CACHING_DEFAULT);
  LModel.Parent := GorillaViewport1;
end;

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. LoadFromFile() will remove previously created model data inside the instance before loading.

Form1.pas
uses
  Gorilla.DefTypes,
  Gorilla.G3D.Loader,
  Gorilla.DAE.Loader,
  Gorilla.FBX.Loader,  
  Gorilla.GLTF.Loader,
  Gorilla.GLB.Loader,    
  Gorilla.OBJ.Loader,
  Gorilla.STL.Loader,
  Gorilla.Babylon.Loader,
  Gorilla.PLY.Loader,
  Gorilla.SKP.Loader,
  Gorilla.X3D.Loader, 
  Gorilla.X3DZ.Loader,   
  Gorilla.X3DVZ.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 intended format unit:

  • Gorilla.G3D.Loader
  • Gorilla.DAE.Loader
  • Gorilla.FBX.Loader
  • Gorilla.GLTF.Loader
  • Gorilla.GLB.Loader
  • Gorilla.OBJ.Loader
  • Gorilla.STL.Loader
  • Gorilla.Babylon.Loader
  • Gorilla.Sketchfab.Loader (uses glTF format)
  • Gorilla.X3D.Loader
  • Gorilla.X3DZ.Loader
  • Gorilla.X3DVZ.Loader
  • Gorilla.PLY.Loader
  • Gorilla.SKP.Loader

Only then the format loader is able to load the specific file.

The Better Loading

Configured loading is the better way of loading model data into your application at runtime.

It gives you the opportunity to tell the loader how to import data.

For example:

  • You can choose to ignore importing lights or cameras
  • You can directly import additional animation files without an extra call
  • You can limit texture size, in case you have a memory-sensitive application
  • You can define a status callback function (“TGorillaLoadingStatus = procedure(ALoader : TObject) of object;”)
  • You can link to a specific model asset inside of package for fast model data reusage

Loading options can be submitted as argument to the LoadNewModelFromFile() or LoadFromFile() method.

In the following example we demonstrate the usage at runtime:

uses
  Gorilla.DefTypes,
  Gorilla.Model,
  Gorilla.FBX.Loader;
 
  [...]
 
  var LOpts : TGorillaLoadOptions;
  LMdlPath := IncludeTrailingPathDelimiter('C:\Temp\PACKAGETEST\ASSETS\Astronaut');
  LOpts := TGorillaLoadOptions.Create(LMdlPath + 'Astronaut.fbx');
 
  // only allow this exact filename and no automated lookup
  LOpts.FileInfo.StrictFilename := true;
 
  // link to a package and/or to a specific asset inside of a package
  LOpts.Package := nil;
  LOpts.Asset := nil;
 
  // limit to a max. size of textures (textures will be resized in aspect ratio)
  LOpts.TextureLimits := Point(512, 512);
 
  // ignore lights and camera for import
  LOpts.ImportLights := false;
  LOpts.ImportCameras := false;
 
  // user defined animation import
  LOpts.ImportAnimations := true;
  LOpts.AddAnimation(LMdlPath + 'Astronaut-idle.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-floating.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-hit.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-jump.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-punch-1.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-punch-2.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-walk-forward.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-walk-backward.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-walk-left.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-walk-right.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-run-forward.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-run-backward.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-run-left.fbx');
  LOpts.AddAnimation(LMdlPath + 'Astronaut-run-right.fbx');
 
  FModel := TGorillaModel.LoadNewModelFromFile(GorillaViewport1, LOpts);
  FModel.Parent := GorillaViewport1;

Loading a model from package source

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.

NOTICE: This will trigger design time dialogs on loading data. If you don't want that dialogs to appear, please use LoadNewModelFromFile() or LoadFromFile().

Form1.pas
uses
  Gorilla.DefTypes,
  Gorilla.G3D.Loader,
  Gorilla.DAE.Loader,
  Gorilla.FBX.Loader,  
  Gorilla.GLTF.Loader,
  Gorilla.GLB.Loader,    
  Gorilla.OBJ.Loader,
  Gorilla.STL.Loader,
  Gorilla.Babylon.Loader,
  Gorilla.PLY.Loader,
  Gorilla.SKP.Loader,
  Gorilla.X3D.Loader, 
  Gorilla.X3DZ.Loader,   
  Gorilla.X3DVZ.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;

Sketchfab Runtime Support

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.

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, stream or 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.

Instancing / Cloning

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).

At DesignTime

We offer a collection property called “Instances” in the TGorillaModel/TGorillaMesh component.

You can simply add instances at design time with their transformation information.

NOTICE: The transformation information (position, rotation and scale) is absolute and not depending on the owner mesh.

At Runtime

For better usability TGorillaMesh/TGorillaModel components provide the collection property “Instances”. Internally it will be cached in buffer for fast GPU transmission.

This brings new opportunities, especially for instancing a very large number, f.e. you don't want to setup a single TCollectionItem to render 100.000 grass blades.

In that case you want to ignore the collection and simply add those instances to the buffer. Therefore please use the AddInstance() method

function AddInstance(const ATransform : TMatrix3D; const ACreateItem : Boolean;
        AName : String = '') : Integer;
/// we create 4 instances in a row
GorillaModel1.AddInstance(TMatrix3D.CreateTranslation(Point3D(-10, 0, 0)), false);
GorillaModel1.AddInstance(TMatrix3D.CreateTranslation(Point3D(-5, 0, 0)), false);
GorillaModel1.AddInstance(TMatrix3D.CreateTranslation(Point3D(5, 0, 0)), false);
GorillaModel1.AddInstance(TMatrix3D.CreateTranslation(Point3D(10, 0, 0)), false);
 
/// 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;

WARNING: Only use one of the functionalities: Collection / Buffering. When adding collection items again, the instance buffer will be refreshed and previously added instances will be cleared.

Cloning

Instancing can be done by GPU and providing different transformation matrices like above or by cloning the visual component with all of it's data. Both ways have their advantages and disadvantages.

  • Use instancing if you want to re-render a mesh multiple times
  • Use cloning if you need different visual feedback (like animations or materials), but if you want to reuse the vertex data itself

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;

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;

OBJ Export

The OBJ exporter is capable of exporting multiple meshes and hierarchies into a *.obj file and to store material information in a separated *.mtl file.

The MTL file will automatically be stored at the same location as the *.obj file with the *.obj.mtl extension.

uses
  Gorilla.OBJ.Exporter;
 
procedure TForm1.MenuItem1Click(Sender: TObject);
var LOBJExp : TGorillaOBJExporter;
begin    
  if Assigned(FModel) then
  begin
    if SaveDialog1.Execute() then
    begin
        LOBJExp := TGorillaOBJExporter.Create();
        try
          LOBJExp.SaveToFile(FModel.Def as TModelDef, SaveDialog1.FileName);
        finally
          FreeAndNil(LOBJExp);
        end;
 
        ShowMessage('File successfully stored:'#13#10+
          SaveDialog1.FileName);
      end;
  end;
end;

Next step: Animations