Piglet is a Unity asset that allows you to load 3D models from glTF files, both in the Editor and at runtime. This gives you the ability to import 3D models while your game is running, and also gives you access to a huge collection of free/paid glTF models from Sketchfab.
Visit the Web Demo1 to try Piglet before you buy it.
.gltf
, .glb
, or .zip
files, using file paths or HTTP URLsThe glTF format supports “extensions”, in order to provide functionality that goes beyond the standard capabilities of glTF. For sample models that test/demonstrate specific glTF features and extensions, see glTF 2.0 Sample Models.
The table below shows the most common glTF extensions, and indicates which ones are currently supported by Piglet. For a more comprehensive list of glTF extensions, see the glTF Extension Registry.
This table was last updated in June 2022, for Piglet version 1.3.7.
Extension | Supported? | Notes |
---|---|---|
KHR_draco_mesh_compression | YES | Requires Draco for Unity (see Installing Draco for Unity). |
KHR_lights_punctual | NO | |
KHR_materials_clearcoat | NO | |
KHR_materials_ior | NO | |
KHR_materials_sheen | NO | |
KHR_materials_specular | NO | |
KHR_materials_transmission | NO | |
KHR_materials_unlit | YES | |
KHR_materials_variants | YES | See Selecting Materials Variants and Runtime Materials Variants Tutorial |
KHR_materials_volume | NO | |
KHR_mesh_quantization | NO | |
KHR_texture_basisu | YES | Requires Ktx for Unity (see Installing Ktx for Unity). |
KHR_texture_transform | YES* | *Only scale and offset transformations are supported (no rotations). |
KHR_xmp_json_ld | NO | |
EXT_lights_image_based | NO | |
EXT_mesh_gpu_instancing | NO | |
EXT_meshopt_compression | NO | |
EXT_texture_webp | NO | |
KHR_materials_pbrSpecularGlossiness | YES |
Runtime imports may stall the main Unity thread. I have done my best to minimize interruptions to the main Unity thread during runtime glTF imports. However, one significant issue is that Unity uploads textures to the GPU synchronously, and this can cause FPS drops when importing high resolution textures at runtime. For now, the best way to work around this issue is to either: (1) convert your textures to KTX2/BasisU format (see Supercompressed Textures (Unity 2020.3+)), or (2) lower the resolution/quality of your textures.
Many glTF extensions are not supported (yet!). I am steadily chipping away at this. See Supported glTF Extensions for details about which extensions are currently supported.
Piglet does not create humanoid avatar mappings (yet!). For the time being, there is no easy way to retarget humanoid animations (e.g. Mixamo) onto glTF models. This is a highly requested feature and I do plan to implement it.
Piglet cannot export glTF files (yet!). So far, Piglet does not have any glTF export capabilities, neither in the Editor nor at runtime. This is a highly requested feature and I do plan to implement it.
To set up Piglet in your project, purchase and install Piglet from the Asset Store page. Piglet works with Unity 2018.4 or later, and does not require installation of any third-party assets/dependencies.
Piglet bundles the following libraries:
Library | Author | License | Path |
---|---|---|---|
Newtonsoft.Json-for-Unity | Newtonsoft/jilleJr@github | MIT License | Assets/Piglet/Dependencies/Json.NET 2 |
SharpZipLib | icsharpcode@github | MIT License | Assets/Piglet/Dependencies/SharpZipLib |
UnityGLTF | Khronos/Sketchfab | MIT License | Assets/Piglet/Dependencies/UnityGLTF 3 |
Once you have installed Piglet from the Unity Asset Store, you can import glTF models into your Unity project by either:
.gltf
/.glb
/.zip
file from a file browser application (e.g. Windows File Explorer) into the Unity Project Browser (Figure 1), OR.gltf
/.glb
/.zip
file directly into your Assets folder from an external program (e.g. Blender).For a video demonstration of the drag-and-drop method, see the Editor Import Demo video.
In general, saving glTF files directly into your Assets folder is a more efficient workflow, especially if you are working on a model in Blender and frequently re-exporting it to glTF. However, one important caveat is that the updated glTF file will not be reimported until you switch focus back to Unity (e.g. Alt-Tab). Unfortunately, Unity does not respond to project file changes while it is in the background.
After an Editor glTF import completes, an output folder is created in your project with the same name as the input .gltf
/.glb
/.zip
file, minus the file extension. This folder contains a Unity prefab for the imported model, as well as Unity assets for the individual textures, materials, meshes, and animation clips (Figure 1). To use the imported model in your game, you can simply drag-and-drop the prefab into your Unity scene(s).
There may be circumstances where you want copy a .gltf
/.glb
/.zip
file into your project without automatically converting it to a Unity prefab. You can bypass/disable Piglet’s automatic glTF imports by either:
Control
or Command
key while dragging-and-dropping the .gltf
/.glb
/.zip
into the Unity Project Browser, OREnable glTF imports in Editor
in the Piglet Options window, located under Window => Piglet Options
in the Unity menu.Piglet supports the KHR_materials_variants extension, which allows a glTF file to provide multiple visual styles (“variants”) for the same model. The mesh data is shared among all variants, but each variant applies a different set of materials (textures) to the mesh.
Whenever a glTF model uses the KHR_materials_variants extension, the user can switch between the available variants using the drop-down menu on the MaterialsVariantsSelector
component, attached to the root GameObject of the model (Figure 2). The last item of the drop-down menu is always the special “default” element, which resets all materials to their initial state when the model was first loaded. (The default materials used by a model does not necessarily correspond to any particular variant.)
It is also possible to switch materials variants at runtime. For instructions, please see the Runtime Materials Variants Tutorial.
Piglet can import and play animations from glTF files, both in the Editor and at runtime. This section demonstrates how to preview animation clips created during Editor imports, and how to play them back from runtime scripts. For a video version of this section, see the Editor Animation Tutorial video.
If a glTF file contains animations, Piglet will create an Animations
subdirectory under the main import directory containing: (1) an AnimatorController
asset (“controller”) for playing the animations at runtime, (2) a “Static Pose” AnimationClip
for resetting the model to its default pose, and (3) an AnimationClip
asset for each animation from the glTF file (Figure 3). The “controller” asset is not needed for previewing animations but is further explained in Playing (Mecanim) Animations at Runtime.
To preview an glTF animation in the Editor, first select the AnimationClip asset in the Project Browser window (Figure 3). This will cause a blank Animation Preview Area to appear in the Inspector window with the message No model is available for preview. Please drag a model into this Preview Area
. Next, drag the prefab for the imported glTF model (located one level up from the Animations
folder) onto the Animation Preview Area. You should then be able to click the Play button to view the animation in the Editor.
This section demonstrates how play animation clip assets from runtime scripts. By default, Editor glTF imports create Mecanim animation clips, and the instructions in this section are specific to Mecanim4 5. For details about playing Legacy animation clips at runtime, see the Runtime Animation Tutorial section of this manual6.
When a glTF file contains one or more animations, Piglet will attach two additional components to the root GameObject
of the model: (1) an Animator
component for controlling playback of the animation clips, and (2) an AnimationList
component with an ordered list of the animation clips (Figure 4). The AnimationList
component allows users to access the animation clips by their original index in the glTF file. More importantly, it provides access to the .name
field of each animation clip, which is needed for play that clip with the Animator
component.
Every Animator
component depends on a state machine called an AnimatorController
, that determines which animation clip to play at any given time (Figure 5). In most cases, there is a one-to-one correspondence between AnimatorController
states and animation clips. In order to start playing a particular clip at runtime, we just need to activate the correct state in the AnimatorController
and start the Animator
playing. Both of these tasks are accomplished by calling the Animator.Play
method.
Listing 1 shows an example script that plays a Mecanim animation clip as soon as Unity enters Play Mode. We start the animation by calling the Animator.Play
method, passing in the initial AnimatorController
state and layer7 as arguments. By convention, Piglet uses the .name
field of an AnimationClip
for the corresponding state name in the AnimatorController
, and thus we can get the state name by accessing the target clip by index in the AnimationList
component. Note that Listing 1 accesses the clip at index 1 in the AnimationList
, rather than index 0, because index 0 is reserved for the special “Static Pose” clip that resets the model to its default pose8. As such, the animations imported from the glTF file always start at index 1. For the layer argument to Animator.Play
, we simply pass in 0, because the controller generated by Piglet only uses the default layer.
using UnityEngine;
using Piglet;
public class AnimationBehaviour : MonoBehaviour
{void Start()
{var anim = GetComponent<Animator>();
var animList = GetComponent<AnimationList>();
// Note: Imported animation clips always start
// at index 1, because index "0" is reserved for
// the "Static Pose" clip.
var stateName = animList.Clips[1].name;
// Note: We use 0 for the layer index argument
// because the AnimatorController generated by
// Piglet only uses the default layer.
Play(stateName, 0);
anim.
} }
Listing 1: A minimal script for playing an Editor-imported (Mecanim) animation clip at runtime. When this script is attached to the root GameObject
of the model, it plays the first animation from the glTF file, immediately after Unity enters Play Mode. Note that the imported animations always begin at index 1 in the AnimationList
, because index 0 is reserved for the “Static Pose” clip.
A number of options controlling Editor glTF imports can be set in the Piglet Options window, located under Window => Piglet Options
in the Unity menu.
Option | Description |
---|---|
Enable glTF imports in Editor |
Enable/disable automatic glTF imports when adding new .gltf/.glb/.zip files to the project |
Log import progress in Console |
Log progress messages to Unity Console window during glTF imports (useful for debugging) |
Option | Description |
---|---|
Scale model to standard size |
Enable/disable automatic resizing of imported model |
Size |
Target size of model, along its longest dimension |
Import animations |
Enable/disable import of glTF animations as Unity AnimationClip assets |
Animation clip type |
“Mecanim” or “Legacy” |
Ensure quaternion continuity |
Enable/disable AnimationClip.EnsureQuaternionContinuity() after importing each animation clip |
Option | Description |
---|---|
Prompt before overwriting files |
Show confirmation prompt if glTF import directory already exists |
Copy source glTF files into project |
Copy dragged-and-dropped glTF file/folder into project before performing glTF import. By default, only the Piglet-generated import directory is added to the project. |
Option | Description |
---|---|
Select prefab in Project Browser |
After a glTF import has completed, select/highlight the generated prefab in the Project Browser window |
Open prefab in Scene View |
After a glTF import has completed, open the generated prefab in the Scene View tab. (This is equivalent to double-clicking the prefab in the Project Browser.) |
Piglet can import a glTF model at runtime from a file path, an HTTP URL, or a byte[]
array containing the raw byte content of a .gltf/.glb/.zip file. Runtime imports are performed incrementally, with minimum possible interruption to the main Unity thread.
This section walks through example code for importing a glTF model at runtime. For a video version of this section, see the Runtime Import Tutorial video. In addition, the example code in this section is included with Piglet under Assets/Piglet/Examples/RuntimeImport
.
As our example glTF model, we will use the .glb
file for Sir Piggleston (the Piglet mascot), which may be downloaded from https://awesomesaucelabs.github.io/piglet-webgl-demo/StreamingAssets/piggleston.glb. The minimal code to import the model at runtime is as follows:
using Piglet;
using UnityEngine;
/// <summary>
/// This MonoBehaviour provides a minimal example for using
/// Piglet to import glTF models at runtime.
/// </summary>
public class RuntimeImportBehaviour : MonoBehaviour
{/// <summary>
/// The currently running glTF import task.
/// </summary>
private GltfImportTask _task;
/// <summary>
/// Unity callback that is invoked before the first frame.
/// Create the glTF import task.
/// </summary>
void Start()
{// Note: To import a local .gltf/.glb/.zip file, you may
// instead pass an absolute file path to GetImportTask
// (e.g. "C:/Users/Joe/Desktop/piggleston.glb"), or a byte[]
// array containing the raw byte content of the file.
GetImportTask(
_task = RuntimeGltfImporter."https://awesomesaucelabs.github.io/piglet-webgl-demo/StreamingAssets/piggleston.glb");
}
/// <summary>
/// Unity callback that is invoked after every frame.
/// Here we call MoveNext() to advance execution
/// of the glTF import task.
/// </summary>
void Update()
{// advance execution of glTF import task
MoveNext();
_task.
} }
Listing 2: Minimal code to import a glTF file at runtime.
As shown in Listing 2, a runtime glTF import happens in two parts. First, we create an import task by calling RuntimeGltfImporter.GetImportTask
, passing in the URL of the glTF model as a parameter. To load a local .gltf/.glb/.zip file, we may instead pass GetImportTask
an absolute file path (e.g. “C:/Users/Joe/Desktop/piggleston.glb”) or a byte[]
array containing the raw byte content of the file. Second, we advance the execution of the import task by repeatedly calling MoveNext()
on the task. A convenient place to call MoveNext()
is in the Update()
method, which is called by Unity once per frame. Continuing to call MoveNext()
after the import has completed does no harm.
Attaching the script from Listing 2 to any game object in your Unity scene is sufficient to import a glTF model at runtime. However, in a real game/application, you will probably want tighter integration between your own code and the importer. For example, you may want to show progress messages while the model is loading, or to attach custom MonoBehaviours to the model once it has loaded. To achieve these types of behaviours, GltfImportTask
provides callback hooks for: progress messages (OnProgress
), user cancelation (OnAborted
), import errors (OnException
), and successful completion (OnCompleted
).
As a first example of callback usage, we’ll extend the example script from Listing 2 to print progress messages during the glTF import. We can achieve this by assigning a custom method to the OnProgress
callback for the import task, as shown in Listing 3.
using Piglet;
using UnityEngine;
/// <summary>
/// This MonoBehaviour provides a minimal example for using
/// Piglet to import glTF models at runtime.
/// </summary>
public class RuntimeImportBehaviour : MonoBehaviour
{/// <summary>
/// The currently running glTF import task.
/// </summary>
private GltfImportTask _task;
/// <summary>
/// Unity callback that is invoked before the first frame.
/// Create the glTF import task.
/// </summary>
void Start()
{// Note: To import a local .gltf/.glb/.zip file, you may
// instead pass an absolute file path to GetImportTask
// (e.g. "C:/Users/Joe/Desktop/piggleston.glb"), or a byte[]
// array containing the raw byte content of the file.
GetImportTask(
_task = RuntimeGltfImporter."https://awesomesaucelabs.github.io/piglet-webgl-demo/StreamingAssets/piggleston.glb");
OnProgress = OnProgress;
_task.
}
/// <summary>
/// Callback that is invoked by the glTF import task
/// to report intermediate progress.
/// </summary>
/// <param name="step">
/// The current step of the glTF import process. Each step imports
/// a different type of glTF entity (e.g. textures, materials).
/// </param>
/// <param name="completed">
/// The number of glTF entities (e.g. textures, materials) that have been
/// successfully imported for the current import step.
/// </param>
/// <param name="total">
/// The total number of glTF entities (e.g. textures, materials) that will
/// be imported for the current import step.
/// </param>
private void OnProgress(GltfImportStep step, int completed, int total)
{LogFormat("{0}: {1}/{2}", step, completed, total);
Debug.
}
/// <summary>
/// Unity callback that is invoked after every frame.
/// Here we call MoveNext() to advance execution
/// of the glTF import task.
/// </summary>
void Update()
{// advance execution of glTF import task
MoveNext();
_task.
} }
Listing 3: An extension of the runtime import script from Listing 2 that prints progress messages to the Unity console. In comparison to Listing 2, the new parts of the code are the OnProgress
method and the assignment of OnProgress
to _task.OnProgress
in Start
.
Another important use of callbacks is to run custom code after a glTF import has successfully completed. For example, you might want to automatically resize the model, parent the model to another game object, or attach a custom MonoBehaviour
to the model. These types of tasks can be accomplished using the OnCompleted
callback. To demonstrate, the example script in Listing 4 uses the OnCompleted
callback to obtain a reference to the imported model, then uses that reference to continually spin the model about the y-axis as if it were on a record turntable.
The example in Listing 4 marks the end of this tutorial. Good luck and happy coding!
using Piglet;
using UnityEngine;
/// <summary>
/// This MonoBehaviour provides a minimal example for using
/// Piglet to import glTF models at runtime.
/// </summary>
public class RuntimeImportBehaviour : MonoBehaviour
{/// <summary>
/// The currently running glTF import task.
/// </summary>
private GltfImportTask _task;
/// <summary>
/// Root GameObject of the imported glTF model.
/// </summary>
private GameObject _model;
/// <summary>
/// Unity callback that is invoked before the first frame.
/// Create the glTF import task.
/// </summary>
void Start()
{// Note: To import a local .gltf/.glb/.zip file, you may
// instead pass an absolute file path to GetImportTask
// (e.g. "C:/Users/Joe/Desktop/piggleston.glb"), or a byte[]
// array containing the raw byte content of the file.
GetImportTask(
_task = RuntimeGltfImporter."https://awesomesaucelabs.github.io/piglet-webgl-demo/StreamingAssets/piggleston.glb");
OnCompleted = OnComplete;
_task.
}
/// <summary>
/// Callback that is invoked by the glTF import task
/// after it has successfully completed.
/// </summary>
/// <param name="importedModel">
/// the root GameObject of the imported glTF model
/// </param>
private void OnComplete(GameObject importedModel)
{
_model = importedModel;Log("Success!");
Debug.
}
/// <summary>
/// Unity callback that is invoked after every frame.
/// Here we call MoveNext() to advance execution
/// of the glTF import task.
/// </summary>
void Update()
{// advance execution of glTF import task
MoveNext();
_task.
// spin model about y-axis
if (_model != null)
transform.Rotate(0, 1, 0);
_model.
} }
Listing 4: An extension of the runtime import script from Listing 2 that spins the imported model about the y-axis. In comparison to Listing 2, the new parts of the code are the OnComplete
method, the assignment of OnComplete
to _task.OnCompleted
in Start
, and the call to _model.transform.Rotate
in Update
.
Piglet supports the KHR_materials_variants extension, which allows a glTF file to provide multiple visual styles (“variants”) for the same model. The mesh data is shared among all variants, but each variant applies a different set of materials (textures) to the mesh.
Piglet provides an example scene under Assets/Piglet/Examples/RuntimeMaterialsVariants
, which demonstrates how to query and select materials variants at runtime. The example allows the user switch between variants of the MaterialsVariantsShoe model, by clicking the buttons along the top of the window (Figure 6).
The code for the example scene is reproduced in Listing 5. (This code is highly similar to the examples from the Runtime Import Tutorial section, so the explanations provided in that section may also be helpful.) After importing the model, we get a reference to the MaterialsVariantsSelector
component on the root GameObject, from inside the OnCompleted
callback. The MaterialsVariantsSelector
component is automatically attached to any glTF model that uses the KHR_materials_variants
extension, and will be absent otherwise.
The MaterialsVariantsSelector
component has two public fields, VariantNames
and VariantIndex
, which can be used for querying and setting the materials variants, respectively. VariantNames
is an ordered list of human-readable names for each variant, where the position of each variant in the list corresponds to its index in the glTF file. To select a particular variant, we simply assign its index to the VariantIndex
field. The call to GUI.Toolbar
in OnGUI
handles drawing a button for each element of the VariantNames
array, and updating value of VariantIndex
whenever one of the buttons gets clicked.
The reader may wonder which materials variant is selected by default, when the model is first loaded. The answer is “none”! Every model has a default set of materials before any variant is selected, and this default set of materials does not necessarily correspond to any particular variant. (In the case of the example shoe model, the default materials exactly match the “midnight” variant.) In order to reset the model to its default state, the user can call the ResetMaterials
method of the MaterialsVariantsSelector
component, or equivalently, they may assign a value of VariantNames.Length - 1
to VariantIndex
. The last element of the VariantNames
array is always the special “default” element, that resets the model to its default materials. In Listing 5, there is no need to explicitly call ResetMaterials
because GUI.Toolbar
creates a button for the “default” element.
using Piglet;
using UnityEngine;
/// <summary>
/// This MonoBehaviour provides a minimal example of switching
/// materials variants at runtime, for glTF models that use the
/// `KHR_materials_variants` extension.
/// </summary>
public class RuntimeMaterialsVariantsBehaviour : MonoBehaviour
{/// <summary>
/// The currently running glTF import task.
/// </summary>
private GltfImportTask _task;
/// <summary>
/// Root GameObject of the imported glTF model.
/// </summary>
private GameObject _model;
/// <summary>
/// MonoBehaviour on the root GameObject of the imported
/// model, which allows the user to select the active materials
/// variant.
/// </summary>
private MaterialsVariantsSelector _variantsSelector;
/// <summary>
/// Unity callback that is invoked before the first frame.
/// Create the glTF import task and register a callback
/// method to be invoked when the glTF import completes.
/// </summary>
void Start()
{// The default size of the shoe model is too small.
//
// Uniformly scale the model such that the longest
// dimension of its world-space axis-aligned bounding
// box becomes 4.0 units.
var importOptions = new GltfImportOptions();
AutoScale = true;
importOptions.AutoScaleSize = 4.0f;
importOptions.
// Note: To import a local .gltf/.glb/.zip file, you may
// instead pass an absolute file path to GetImportTask
// (e.g. "C:/Users/Joe/Desktop/piggleston.glb"), or a byte[]
// array containing the raw byte content of the file.
GetImportTask(
_task = RuntimeGltfImporter."https://awesomesaucelabs.github.io/piglet-webgl-demo/StreamingAssets/shoe.glb",
importOptions);
// Method to be invoked when the glTF import successfully
// completes.
OnCompleted = OnComplete;
_task.
}
/// <summary>
/// Callback that is invoked by the glTF import task
/// after it has successfully completed.
/// </summary>
/// <param name="importedModel">
/// the root GameObject of the imported glTF model
/// </param>
private void OnComplete(GameObject importedModel)
{
_model = importedModel;GetComponent<MaterialsVariantsSelector>();
_variantsSelector = _model.
}
/// <summary>
/// Unity callback that is invoked after every frame.
/// Here we call MoveNext() to advance execution
/// of the glTF import task. Once the model has been successfully
/// imported, we auto-spin the model about the y-axis.
/// </summary>
void Update()
{// advance execution of glTF import task
MoveNext();
_task.
// spin model about y-axis
if (_model != null)
transform.Rotate(0.0f, 0.25f, 0.0f);
_model.
}
void OnGUI()
{// Add some buttons along the top of the screen, which allow
// the user to select the active materials variant.
//
// Note: `_variantsSelector` will be null until the model has
// been successfully imported.
if (_variantsSelector != null)
{VariantIndex = GUI.Toolbar(
_variantsSelector.new Rect(25, 25, 500, 30),
VariantIndex,
_variantsSelector.VariantNames);
_variantsSelector.
}
} }
Listing 5: Example code for importing a glTF model at runtime and selecting materials variants. This code is included with Piglet under Assets/Piglet/Examples/RuntimeMaterialsVariants
.
This section demonstrates how to import and play animations from a glTF file at runtime. For a video version of this section, see the Runtime Animation Tutorial video.
Runtime glTF imports always use the Legacy animation system, because Mecanim cannot create animation clips at runtime9 (as of December 2020). In practice, I have not found this to be an issue – for simple playback of glTF animations, the Legacy system works very well.
When Piglet imports a glTF model with one or more animations at runtime, it attaches two additional components to the root GameObject
of the model: (1) an Animation
component for controlling playback of the animation clips, and (2) an AnimationList
component containing an ordered list of the animation clips (Figure 7). The AnimationList
component allows users to access the imported animation clips by their original index in the glTF file. More importantly, it provides access to the .name
field of each animation clip, which is needed for playing the clip with the Animation
component.
Listing 6 shows an example script that imports a glTF model with an animation at runtime, and then immediately plays the animation. The basic steps for importing an animated glTF model are the same as for static models: (1) create a GltfImportTask
in the Start
method, and (2) advance execution of the task by calling GltfImportTask.MoveNext
in Update
.
To play the animation after the model has finished loading, we assign the OnComplete
method to _task.OnCompleted
in Start
. Piglet passes the root GameObject
of the imported model as an argument to OnComplete
, which we then use to obtain a reference to the Animation
component for playing the animation. Since an Animation
component can hold any number of animation clips, we need to provide a string-based key to Animation.Play
that identifies the clip to play. By convention, Piglet uses the .name
field of each animation clip as its key, and so we can obtain the desired key by accessing the animation clip (by index) from the AnimationList
component. Note that the animation clips imported from glTF file always begin at index 1 of the AnimationList
, because index 0 is reserved for the “Static Pose” clip.
using Piglet;
using UnityEngine;
/// <summary>
/// This MonoBehaviour provides a minimal example for
/// importing and playing glTF animations at runtime.
/// </summary>
public class RuntimeAnimationBehaviour : MonoBehaviour
{/// <summary>
/// The currently running glTF import task.
/// </summary>
private GltfImportTask _task;
/// <summary>
/// Unity callback that is invoked before the first frame.
/// Create the glTF import task and set up callback for
/// successful completion.
/// </summary>
void Start()
{// Uniformly scale the model such that the longest
// dimension of its world-space axis-aligned bounding
// box becomes 4.0 units.
var importOptions = new GltfImportOptions();
AutoScale = true;
importOptions.AutoScaleSize = 4.0f;
importOptions.
// Note: To import a local .gltf/.glb/.zip file, you may
// instead pass an absolute file path to GetImportTask
// (e.g. "C:/Users/Joe/Desktop/piggleston.glb"), or a byte[]
// array containing the raw byte content of the file.
GetImportTask(
_task = RuntimeGltfImporter."https://awesomesaucelabs.github.io/piglet-webgl-demo/StreamingAssets/cartoon_hartman.zip",
importOptions);
OnCompleted = OnComplete;
_task.
}
/// <summary>
/// Callback that is invoked by the glTF import task
/// after it has successfully completed.
/// </summary>
/// <param name="importedModel">
/// the root GameObject of the imported glTF model
/// </param>
private void OnComplete(GameObject importedModel)
{var anim = importedModel.GetComponent<Animation>();
var animList = importedModel.GetComponent<AnimationList>();
// Note: Imported animation clips always start
// at index 1, because index "0" is reserved for
// the "Static Pose" clip.
var clipKey = animList.Clips[1].name;
Play(clipKey);
anim.
Log("Success!");
Debug.
}
/// <summary>
/// Unity callback that is invoked after every frame.
/// Here we call MoveNext() to advance execution
/// of the glTF import task.
/// </summary>
void Update()
{// advance execution of glTF import task
MoveNext();
_task.
} }
Listing 6: An example script that performs runtime import of a glTF model with an animation, then immediately plays that animation. Attribution: This script uses the “Cartoon Hartman” model by Willy Decarpentrie, skudgee@sketchfab, CC Attribution License.
In Piglet, a runtime glTF import is accomplished by the following steps:
GltfImportTask
by calling RuntimeGltfImporter.GetImportTask
, passing in the file path, URL, or raw byte content of the input .gltf
/.glb
/.zip
file as a parameter. See Creating a GltfImportTask for details.GltfImportTask
to execute custom code for success/failure/progress events (optional). See Configuring Callbacks on a GltfImportTask for details.GltfImportTask
by calling MoveNext()
until the import has completed. See Executing a GltfImportTask for details.For concrete code examples demonstrating the above steps, see the Runtime Import Tutorial.
RuntimeGltfImporter
provides the following static methods for creating a GltfImportTask
:
Method | Return Type | Description |
---|---|---|
GetImportTask(string uri, GltfImportOptions options=null) |
GltfImportTask |
Create an import task that imports the glTF model from uri , where uri is an absolute file path, HTTP(S) URL, or Android content URI that points to a .gltf /.glb /.zip file. |
GetImportTask(Uri uri, GltfImportOptions options=null) |
GltfImportTask |
Create an import task that imports the glTF model from uri , where uri is an absolute file path, HTTP(S) URL, or Android content URI that points to a .gltf /.glb /.zip file. |
GetImportTask(byte[] data, GltfImportOptions options=null) |
GltfImportTask |
Create an import task that imports from the raw byte content of a .gltf /.glb /.zip file. |
All versions of GetImportTask
accept an instance of GltfImportOptions
as an optional second argument. See Runtime Import Options for a description of the available options.
You can assign callback methods to delegate members of a GltfImportTask
, in order to run custom code for success/failure/progress events. For example, callbacks can be used to position a successfully imported model within a scene or to attach a custom MonoBehaviour
.
Callback | Description |
---|---|
OnProgress |
Invoked at regular intervals to report progress of GltfImportTask |
OnAborted |
Invoked when Abort() is called on GltfImportTask |
OnException |
Invoked when GltfImportTask throws an exception (e.g. file not found) |
OnCompleted |
Invoked when GltfImportTask completes successfully |
GltfImportTask
provides the following methods for controlling its own execution:
Method | Description |
---|---|
MoveNext() |
Advance execution of the import task by a small increment. This method should be called repeatedly until the import task has completed. |
Abort() |
Abort the import task. This method should typically be called in response to a user action, such as pressing a “Cancel” button. |
Piglet supports a number of options for controlling runtime glTF imports. To configure these options, users may pass a GltfImportOptions
object as an optional second argument to RuntimeGltfImporter.GetImportTask
. (See Creating a GltfImportTask.)
For a concrete example of GltfImportOptions
usage, see Listing 6 from the Runtime Animation Tutorial section.
Currently, GltfImportOptions
provides the following options:
Option | Default | Description |
---|---|---|
ShowModelAfterImport |
true |
Automatically unhide the model after a successful glTF import, by calling SetActive(true) on the root GameObject. Users might want to keep the model hidden until they have completed their own post-processing on the model (e.g. adding colliders). |
AutoScale |
false |
Automatically resize the model after a successful glTF import |
AutoScaleSize |
1.0 |
Target size of model along its longest dimension |
ImportAnimations |
true |
Import glTF animations as Legacy animation clips |
EnsureQuaternionContinuity |
true |
Call AnimationClip.EnsureQuaternionContinuity() after importing each animation clip. |
CreateMipmaps |
false |
Create mipmaps for PNG/JPG textures during runtime glTF imports. This option is false by default because it roughly doubles the texture import time and increases the probability of FPS drops. This option has no effect on the creation of mipmaps for KTX2/BasisU textures, since mipmaps are always created in that case without any additional overhead. Likewise, mipmaps are always created during Editor glTF imports for all texture formats (PNG, JPG, KTX2/BasisU). |
ZipPassword |
null |
The password used to unpack encrypted .zip files. |
Piglet can load glTF files that contain supercompressed textures10 in KTX2/ETC1S or KTX2/UASTC format11 (i.e. Basis Universal texture formats in a KTX 2.0 container). The main advantages of supercompressed textures are that: (1) textures load faster, and (2) glTF files are smaller. The main disadvantage is loss of image quality, which can give textures a “blocky” appearance. Depending on your application, the loss of image quality may not be noticeable, whereas the performance benefits are usually significant.
For a practical demonstration of the trade-offs, compare the ordinary and KTX2/ETC1S versions of the sample models at the Piglet Web Demo. Note the differences in appearance, loading times, and file sizes.
Before Piglet can load glTF files with supercompressed textures, you will need to install the Ktx for Unity package into your Unity project (see Installing Ktx for Unity). If you attempt to load a glTF file that contains supercompressed textures without installing Ktx for Unity, the textures will simply load as solid white, and Piglet will issue warnings on the Unity Console about failing to load the textures.
Finally, if you plan to use supercompressed textures with your models, you will probably need to preprocess the glTF files yourself. At the time of writing (Feb 2021), most glTF files on the web use PNG or JPEG textures, including the glTF files downloaded from Sketchfab. I recommend using the gltf-transform command line tool to compress the textures in your glTF files, as described in Supercompressing Your glTF Textures.
To load glTF files with supercompressed textures, you will need to install the KTX for Unity package, by following the installation instructions here. And that’s it! After installing the package, you should be able to successfully load glTF files containing supercompressed textures (i.e. textures in KTX/BasisU format).
The remainder of this section provides the legacy installation instructions for KtxUnity, which is an older version of the KTX for Unity package. You can safely ignore these instructions if you are using the KTX for Unity package instead.
To install KtxUnity, first determine the correct version of KtxUnity for your current version of Unity, using the table below. (Note: This table was last updated in May 2024.)
Unity Version | Compatible KtxUnity Versions | Recommended KtxUnity Version |
---|---|---|
2019.2 or older | not supported | not supported |
2019.3 through 2021.1 | 0.9.1 through 1.1.2 | 1.1.2 |
2021.2 through 2022.1 | 2.0.0 or newer | 2.2.3 |
2022.2 or newer | not supported | not supported |
Since KtxUnity is hosted by a third-party package registry (OpenUPM), you will need to tell Unity where to download the package by adding a scoped registry to the Packages/manifest.json
file under your Unity project directory. You can do that by making the edits shown in Listing 7 and then restarting Unity. In addition, remember to change the KtxUnity version in Listing 7 to your required KtxUnity version. If you want to perform the same edits in an automated fashion, you can instead install the OpenUPM CLI tool and run openupm add com.atteneder.ktx@1.1.2
(or similar).
Note!: I don’t recommend using the “Installer Package” link from the KtxUnity README.md, since it is just a more convoluted and fragile method for performing the text edits shown in Listing 7. While the installer link is more automatic, it prevents the user from understanding what is really going on under the hood. Another advantage of manually editing manifest.json
is that you can pin KtxUnity to a specific version (if desired).
In addition, please note the following “gotcha” when installing KtxUnity:
Architecture
from x86
to x86_64
. Otherwise, the native DLL for KtxUnity (ktx_unity.dll
) will not be included in the build, and you may get a DllNotFoundException
when you run your application.{
"dependencies" : {
"com.unity.collab-proxy" : "1.2.16",
"com.unity.ide.rider" : "1.1.4",
"com.unity.ide.vscode" : "1.2.0",
"com.unity.test-framework" : "1.1.13",
"com.unity.textmeshpro" : "2.0.1",
"com.unity.timeline" : "1.2.14",
"com.unity.ugui" : "1.0.0",
"com.unity.modules.ai" : "1.0.0",
"com.unity.modules.androidjni" : "1.0.0",
"com.unity.modules.animation" : "1.0.0",
"com.unity.modules.assetbundle" : "1.0.0",
"com.unity.modules.audio" : "1.0.0",
"com.unity.modules.cloth" : "1.0.0",
"com.unity.modules.director" : "1.0.0",
"com.unity.modules.imageconversion" : "1.0.0",
"com.unity.modules.imgui" : "1.0.0",
"com.unity.modules.jsonserialize" : "1.0.0",
"com.unity.modules.particlesystem" : "1.0.0",
"com.unity.modules.physics" : "1.0.0",
"com.unity.modules.physics2d" : "1.0.0",
"com.unity.modules.screencapture" : "1.0.0",
"com.unity.modules.terrain" : "1.0.0",
"com.unity.modules.terrainphysics" : "1.0.0",
"com.unity.modules.tilemap" : "1.0.0",
"com.unity.modules.ui" : "1.0.0",
"com.unity.modules.uielements" : "1.0.0",
"com.unity.modules.umbra" : "1.0.0",
"com.unity.modules.unityanalytics" : "1.0.0",
"com.unity.modules.unitywebrequest" : "1.0.0",
"com.unity.modules.unitywebrequestassetbundle" : "1.0.0",
"com.unity.modules.unitywebrequestaudio" : "1.0.0",
"com.unity.modules.unitywebrequesttexture" : "1.0.0",
"com.unity.modules.unitywebrequestwww" : "1.0.0",
"com.unity.modules.vehicles" : "1.0.0",
"com.unity.modules.video" : "1.0.0",
"com.unity.modules.vr" : "1.0.0",
"com.unity.modules.wind" : "1.0.0",
"com.unity.modules.xr" : "1.0.0",
"com.atteneder.ktx" : "1.1.2"
},
"scopedRegistries" : [
{
"name" : "OpenUPM",
"url" : "https://package.openupm.com",
"scopes" : [
"com.atteneder"
]
}
]
}
Listing 7: Example edits to Packages/manifest.json
in order to install KtxUnity. After adding the highlighted text, restart Unity to install the package.
Most glTF files store their textures in PNG or JPEG format. To convert the textures in your glTF files to KTX2/ETC1S or KTX2/UASTC, I recommend using the gltf-transform command line tool.
In order to supercompress your textures with gltf-transform
, you will first need to install:
toktx
program that is invoked by gltf-transform
. To install the software, go to the GitHub releases page, click/expand “Assets” at the bottom of the release notes, and choose the appropriate package/installer for your O/S. Note that if you are using Windows, you will also need to add C:\Program Files\KTX-Software\bin
to your Path
, so that gltf-transform
can find the toktx
binary.Once you have installed the above prerequisites, you will be able to install gltf-transform
by running:
npm install --global @gltf-transform/cli
You will then be able to convert the textures in a glTF file to KTX2/ETC1S by running:
gltf-transform etc1s input.glb output.glb
or to KTX2/UASTC by running:
gltf-transform uastc input.glb output.glb
The gltf-transform
program provides options for restricting the conversion to specific textures (“slots”), adjusting quality settings, and more. See gltf-transform etc1s --help
or gltf-transform uastc --help
for further details.
Piglet can load glTF files that use Draco mesh compression12. The main benefit of using Draco compression is that it can substantially reduce the size of your glTF files (e.g. 20% of original size), especially if your model contains large/complex meshes. While using Draco compression does introduce some computational overhead, the impact on model loading times is usually neglible.
For a practical demonstration of the benefits, compare the ordinary and Draco-compressed versions of the models at the Piglet Web Demo. Note the large differences in file sizes and the small differences in loading times. For further examples of real-world Draco compression results, see Draco Compressed Meshes with glTF and 3D Tiles.
Before Piglet can load Draco-compressed glTF files, you will need to install the Draco for Unity package into your Unity project (see Installing Draco for Unity). If you attempt to load a Draco-compressed glTF file without installing Draco for Unity, the glTF import will fail with an error in the Unity console.
Finally, if you plan to use Draco-compressed meshes for your models, you will probably need to preprocess the glTF files yourself. At the time of writing (May 2021), most glTF files available on the web use uncompressed meshes, including the glTF files downloaded from Sketchfab. I recommend using the gltf-transform command line tool to compress the meshes in your glTF files, as detailed in Draco-compressing Your glTF Meshes.
To load glTF files that use Draco mesh compression, you will need to install the Draco for Unity package, by following the instructions here. And that’s it! After installing the package, you should be able to successfully load glTF files containing Draco-compressed meshes.
The remainder of this section provides the legacy installation instructions for DracoUnity, which is an older version of the Draco for Unity package. You can safely ignore these instructions if you are using the Draco for Unity package instead.
To install DracoUnity, first determine the correct DracoUnity version for your current version of Unity, using the table below. (Note: This table was last updated in May 2024.)
Unity Version | Compatible DracoUnity Versions | Recommended DracoUnity Version |
---|---|---|
2019.2 or older | not supported | not supported |
2019.3 through 2021.1 | 1.1.0 through 3.3.2 | 3.3.2 |
2021.2 through 2022.1 | 4.0.0 or newer | 4.1.0 |
2022.2 or newer | not supported | not supported |
Since DracoUnity is hosted by a third-party package registry (OpenUPM), you will need to tell Unity where to download the package by adding a scoped registry to the Packages/manifest.json
under your Unity project directory. You can do that by making the edits shown in Listing 8 and then restarting Unity. In addition, remember to change the DracoUnity version in Listing 8 to your required DracoUnity version. If you want to perform the same edits in an automated fashion, you can instead install the OpenUPM CLI tool and run openupm add com.atteneder.draco@3.3.2
(or similar).
Note!: I don’t recommend using the “Installer Package” link from the DracoUnity README.md, since that is just a more convoluted and fragile method for performing the text edits shown in Listing 8. While the installer link is more automatic, it prevents the user from understanding what is really going on under the hood. Another advantage of manually editing manifest.json
is that you can pin DracoUnity to a specific version (if desired).
In addition, please note the following “gotcha” when installing DracoUnity:
Architecture
from x86
to x86_64
. Otherwise, the native DLL for DracoUnity (draco_unity.dll
) will not be included in the build, and you may get a DllNotFoundException
when you run your application.{
"dependencies" : {
"com.unity.collab-proxy" : "1.2.16",
"com.unity.ide.rider" : "1.1.4",
"com.unity.ide.vscode" : "1.2.0",
"com.unity.test-framework" : "1.1.13",
"com.unity.textmeshpro" : "2.0.1",
"com.unity.timeline" : "1.2.14",
"com.unity.ugui" : "1.0.0",
"com.unity.modules.ai" : "1.0.0",
"com.unity.modules.androidjni" : "1.0.0",
"com.unity.modules.animation" : "1.0.0",
"com.unity.modules.assetbundle" : "1.0.0",
"com.unity.modules.audio" : "1.0.0",
"com.unity.modules.cloth" : "1.0.0",
"com.unity.modules.director" : "1.0.0",
"com.unity.modules.imageconversion" : "1.0.0",
"com.unity.modules.imgui" : "1.0.0",
"com.unity.modules.jsonserialize" : "1.0.0",
"com.unity.modules.particlesystem" : "1.0.0",
"com.unity.modules.physics" : "1.0.0",
"com.unity.modules.physics2d" : "1.0.0",
"com.unity.modules.screencapture" : "1.0.0",
"com.unity.modules.terrain" : "1.0.0",
"com.unity.modules.terrainphysics" : "1.0.0",
"com.unity.modules.tilemap" : "1.0.0",
"com.unity.modules.ui" : "1.0.0",
"com.unity.modules.uielements" : "1.0.0",
"com.unity.modules.umbra" : "1.0.0",
"com.unity.modules.unityanalytics" : "1.0.0",
"com.unity.modules.unitywebrequest" : "1.0.0",
"com.unity.modules.unitywebrequestassetbundle" : "1.0.0",
"com.unity.modules.unitywebrequestaudio" : "1.0.0",
"com.unity.modules.unitywebrequesttexture" : "1.0.0",
"com.unity.modules.unitywebrequestwww" : "1.0.0",
"com.unity.modules.vehicles" : "1.0.0",
"com.unity.modules.video" : "1.0.0",
"com.unity.modules.vr" : "1.0.0",
"com.unity.modules.wind" : "1.0.0",
"com.unity.modules.xr" : "1.0.0",
"com.atteneder.draco" : "3.3.2"
},
"scopedRegistries" : [
{
"name" : "OpenUPM",
"url" : "https://package.openupm.com",
"scopes" : [
"com.atteneder"
]
}
]
}
Listing 8: Example edits to Packages/manifest.json
in order to install DracoUnity. After adding the highlighted text, restart Unity to install the package.
Most glTF files store their meshes in standard uncompressed form. To Draco-compress the meshes in your glTF files, I recommend using the gltf-transform command line tool.
In order to install gltf-transform
, you will first need to install NodeJS and NPM. Then you will be able to install gltf-transform
by running:
npm install --global @gltf-transform/cli
Once gltf-transform
is installed, you will be able to Draco-compress your glTF files by running:
gltf-transform draco input.glb output.glb
The gltf-transform draco
command provides various options for controlling compression and quantization. See gltf-transform draco --help
for further details.
Piglet supports the Universal Render Pipeline (URP) in Unity 2019.3 or newer. To use Piglet with a URP-based project, unpack the shaders from the appropriate .unitypackage
file in Assets/Piglet/Extras
. For Unity versions 2019.3.0f6 through 2020.1.x, use URP-Shaders-2019.3.unitypackage
. For Unity 2020.2.0b14 or newer, use URP-Shaders-2020.2.unitypackage
.
The shader files will be unpacked into Assets/Piglet/Resources/Shaders/URP
. If you to forget unpack the shaders before performing an Editor or runtime glTF import, Piglet will fail with an error reminding you to install the shaders.
PigletViewer is a sample application which uses Piglet to view 3D models from glTF files (`.gltf`, `.glb`, or `.zip`), and which is used for the Piglet Web Demo. For the benefit of Piglet customers, I have published the source code and documentation for PigletViewer online at https://github.com/AwesomesauceLabs/piglet-viewer, under an MIT license. PigletViewer currently supports builds for Windows, Mac, Android, iOS, and WebGL, and thus it may be a useful reference for Piglet users developing for those platforms. In general, I recommend looking at the Runtime Import Tutorial before exploring the PigletViewer code, as the tutorial provides a much more succinct introduction to the Piglet API.
Added:
Fixed:
Added:
KHR_materials_variants
. See the “Selecting Materials Variants” and “Runtime Materials Variants Tutorial” in the manual for usage details.Fixed:
KHR_texture_basisu
: “This model requires support for the KHR_texture_basisu
glTF extension, but Piglet does not yet support that extension.” Piglet does support KHR_texture_basisu
, if the user installs the KtxUnity
package! (See “Supercompressed Textures” in the Piglet manual for instructions.)Added:
KHR_texture_transform
.KHR_materials_unlit
.CreateMipmaps
option to create mipmaps for PNG/JPG textures during runtime glTF imports. This option is disabled by default because the wallclock time for importing textures is roughly doubled. The CreateMipmaps
option has no effect on Editor glTF imports because mipmaps are always created in that case.EnsureQuaternionContinuity
option for both Editor and runtime glTF imports. This option is enabled by default, but disabling it sometimes solves minor animation glitches.ZipPassword
for decrypting password-protected zip files (runtime glTF imports only).Fixed:
baseColorFactor
, emissiveFactor
). Unity expects Color
shader properties to be provided in Gamma space, whereas I was directly passing through the linear color values from the glTF file. As a result, the colors for untextured glTF models were too dark/saturated. Most textured glTF models will be unaffected by this change, since they typically use the default white/black values for the color factors.VoxEdit
-generated glTF files as solid black. This problem was caused by my use of negative UV coords, in order to fix the orientation of upside-down PNG/JPG textures. (For some reason, Unity’s texture loading APIs load PNG/JPG images into textures upside-down.) I have now updated the code to use equivalent UV coords in the [0,1] range, so that textures render correctly with both Repeat
and Clamp
modes.The Animator Controller (controller) you have used is not valid. Animations will not play
, when importing animations in the Editor.KHR_mesh_quantization
) that is not implemented by Piglet. Previously, Piglet would continue importing the file anyway, and then crash or produce incorrect results. Failing with an error message is better because it lets the user know the exact cause of the problem.doubleSided
flag of the glTF material. Unfortunately, the URP shaders are still hardcoded to use double-sided rendering, since Unity’s shader graphs do not provide any way to control single-sided/double-sided rendering via script.mesh.weights
is not explicitly set by the glTF file. According to the glTF spec, mesh.weights
should be treated as an array of zeroes when not explicitly set, and I have changed the Piglet code to behave accordingly.Fixed:
Newtonsoft.Json.dll
and Unity’s “Newtonsoft Json” package (hurray!). To address this issue, I forked the Newtonsoft.Json-for-Unity
project, moved all of the C# classes from namespace Newtonsoft.Json
-> Piglet.Newtonsoft.Json
, and renamed the output DLL file from Newtonsoft.Json.dll
-> Piglet.Newtonsoft.Json.dll
. You can see the exact changes I made at: https://github.com/AwesomesauceLabs/Newtonsoft.Json-for-Unity/commits/pigletNewtonsoft.Json-for-Unity
wiki: https://github.com/jilleJr/Newtonsoft.Json-for-Unity/wiki/What-even-is-AOTFixed:
Hotfix release for Piglet 1.3.3.
Fixed:
Added:
Assets
from an external program (e.g. Blender)! Please note that you need to switch application focus back to Unity (e.g. Alt-Tab) before the new/changed glTF file gets imported.Changed:
GltfImportTask.MillisecondsPerYield
to maximize the work done per frame.AssetDatabase.StartAssetEditing
/ AssetDatabase.StopAssetEditing
. For glTF files with a large number textures/materials/meshes/animations, the speedup is dramatic (e.g. 10X).Assets
, some of the old options no longer made sense.Assets/Piglet/Dependencies/UnityGLTF
from UnityGLTF
namespace -> Piglet.UnityGLTF
namespace, so that Piglet and Khronos UnityGLTF importers can be used in the same project.Fixed:
NullReferenceException
when a mesh does not specify a material in URP projects..zip
files generated by some compression programs.sRGB
flag setting on texture assets after Editor glTF imports. Editor glTF imports now work correctly in linear color mode.Bugfix release.
Assets/Piglet/Dependencies/Json.NET
when Piglet is installed with Unity 2020.3.10+ or Unity 2021.1.9+com.unity.nuget.newtonsoft-json
) by default when creating a new project. Including Assets/Piglet/Dependencies/Json.NET
was causing a second copy of Newtonsoft.Json.dll
to be added to the project, resulting in compile errors.Bugfix release.
This release finally adds support for Draco mesh compression!
Bugfixes also included in this release:
Bugfix release.
Compatibility fix for Unity 2021.1.1f1:
This release adds support for “supercompressed” textures in KTX2/ETC1S and KTX2/UASTC formats:
Bugfixes:
alpha:auto
-> alpha:fade
in MetallicRoughnessBlend
and SpecularGlossinessBlend
shaders.).meta
files for non-existing folders, whenever an Editor glTF import overwrites an existing folder.Bugfix release:
Major release!
This release adds animation support:
Minor features:
RuntimeGltfImporter.GetGltfImportTask
methods now accepts an optional GltfImportOptions
argumentBugfixes:
Documentation:
pandoc
and classless.css
Added support for URP in Unity 2019.3+:
Bugfixes:
Bugfix release.
GltfImporter:
Bugfix release.
ChangeLog.txt [new]:
GltfImporter:
UnityGLTF:
Bugfixes:
First release!
I have tested the Piglet Web Demo with Firefox and Google Chrome on Windows 10 64-bit. If you are using Google Chrome, you can improve performance of the demo by turning on hardware acceleration (i.e. GPU acceleration) in the browser settings. Currently this option is disabled in Chrome by default.↩︎
To prevent DLL conflicts with Unity’s “Newtonsoft Json” package, which is automatically installed in new Unity projects since Unity 2020.3.10f1, I have forked the Newtonsoft.Json-for-Unity project and compiled my own DLL (Assets/Piglet/Dependencies/Json.NET/Piglet.Newtonsoft.Json.dll
). In addition to renaming the DLL from Newtonsoft.Json.dll
-> Piglet.Newtonsoft.Json.dll
, I changed the namespace of all C# classes from Newtonsoft.Json
-> Piglet.Newtonsoft.Json
and disabled some optional Json.NET features to reduce the file size of the DLL. You can see the changes I’ve made by looking at the commits on the piglet
branch of my Newtonsoft.Json-for-Unity fork.↩︎
The Assets/Piglet/Dependencies/UnityGLTF
folder does not include the full set of source files from the Sketchfab/UnityGLTF project. Piglet is actually a (heavily modified) fork of Sketchfab/UnityGLTF starting at commit c54fd45, and the Assets/Piglet/Dependencies/UnityGLTF
folder only contains the subset of the source files that have remained (mostly) unchanged since the fork. I’ve changed the namespace of all C# classes from GLTF
-> Piglet.GLTF
to prevent code conflicts in Unity projects that want to use both Piglet and UnityGLTF at the same time.↩︎
As of December 2020, Unity has two animation systems: Mecanim and Legacy. While Unity recommends that new projects use Mecanim, each system has its own advantages and drawbacks. Briefly, Mecanim is a newer system that has more features than Legacy (e.g. blending, retargeting), but has a steeper learning curve and does not (yet) provide an API for creating animations at runtime. On the other hand, the Legacy animation system is simpler, easier to learn, and supports creating animations at runtime. You should not let the name “Legacy” discourage you from using the Legacy animation system if it is a good fit for your project. Unity has continued to support and maintain the Legacy system since the introduction of Mecanim in Unity 4 (November 2012), and it is unlikely that the Legacy system will be removed until Mecanim supports runtime creation of animation clips.↩︎
If you are new to the Mecanim animation system, I highly recommend watching a series of videos called Controlling Animation on Unity Learn. These videos provide a very concise introduction to the capabilities and use of Mecanim.↩︎
Runtime glTF imports use the Legacy animation system because Mecanim is not capable of creating animation clips at runtime.↩︎
AnimatorController
layers have not been mentioned up to this point, because the controllers generated by Piglet only use the default layer (i.e. layer 0, “Base Layer”). An AnimatorController
can (optionally) be split into multiple layers, where each layer has its own state machine, for the purpose of blending multiple animations for the same mode (e.g. a running and shooting animation for a humanoid character). For further information, see the “Animator Controllers Layers” video from the Controlling Animation video series on Unity Learn.↩︎
The “Static Pose” clip (a.k.a “Bind Pose” or “T-Pose”) is useful because playing an animation clip permanently changes the transforms (translation/rotation/scale) of the game objects in the model. Users can play the “Static Pose” clip to return the transforms to their original state.↩︎
The main limitation is that AnimationClip.SetCurve only works at runtime for Legacy animation clips.↩︎
For the motivation behind supercompressed textures, see Basis Universal texture format introduction (Atteneder, 2019). For a more detailed technical explanation, see GST: GPU-decodable Supercompressed Textures (Krajcevski et al., 2016).↩︎
KTX2/ETC1S is more commonly used than KTX2/UASTC because it provides a higher data compression rate (at the cost of image quality).↩︎
For an introduction to the ideas behind Draco mesh compression, see Edgebreaker, the Heart of Google Draco. For a detailed description of the algorithm, see Edgebreaker: Connectivity compression for triangle meshes (Rossignac, 1999) and the follow-up paper 3D Compression Made Simple: Edgebreaker on a Corner-Table (Rossignac et al., 2001).↩︎