rename numInstances to initialInstances in loadGltf methods.

when initialInstances > 0, don't wait for createInstance to be called to create corresponding GltfSceneAsset
This commit is contained in:
Nick Fisher
2025-06-26 09:20:37 +08:00
parent b983c6bb90
commit ccc0a53abc
9 changed files with 49 additions and 46 deletions

View File

@@ -890,7 +890,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
///
Future<ThermionAsset> loadGltfFromBuffer(
Uint8List data, Pointer animationManager,
{int numInstances = 1,
{int initialInstances = 1,
bool keepData = false,
int priority = 4,
int layer = 0,
@@ -914,7 +914,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
var filamentAsset = await withPointerCallback<TFilamentAsset>((cb) =>
GltfAssetLoader_loadRenderThread(engine, gltfAssetLoader,
data.address, data.length, numInstances, cb));
data.address, data.length, initialInstances, cb));
if (filamentAsset == nullptr) {
throw Exception("An error occurred loading the asset");

View File

@@ -6,7 +6,6 @@ import 'package:thermion_dart/src/filament/src/interface/scene.dart';
import 'package:thermion_dart/thermion_dart.dart';
export 'geometry.dart';
export 'gltf.dart';
///
/// A high-level interface for a renderable object

View File

@@ -291,11 +291,11 @@ abstract class FilamentApp<T> {
Future setClearOptions(double r, double g, double b, double a,
{int clearStencil = 0, bool discard = false, bool clear = true});
///
/// See [FilamentViewerFFI.loadGltf] for details.
///
///
Future<ThermionAsset> loadGltfFromBuffer(Uint8List data, T animationManager,
{int numInstances = 1,
{int initialInstances = 1,
bool keepData = false,
int priority = 4,
int layer = 0,

View File

@@ -1,6 +0,0 @@
class GLTF {
final String uri;
final int numInstances;
GLTF(this.uri, this.numInstances);
}

View File

@@ -457,7 +457,7 @@ class ThermionViewerFFI extends ThermionViewer {
Future<ThermionAsset> loadGltf(
String path, {
bool addToScene = true,
int numInstances = 1,
int initialInstances = 1,
bool keepData = false,
String? resourceUri,
bool loadAsync = false,
@@ -475,7 +475,7 @@ class ThermionViewerFFI extends ThermionViewer {
return loadGltfFromBuffer(
data,
addToScene: addToScene,
numInstances: numInstances,
initialInstances: initialInstances,
keepData: keepData,
resourceUri: resourceUri,
loadResourcesAsync: loadAsync,
@@ -489,7 +489,7 @@ class ThermionViewerFFI extends ThermionViewer {
Future<ThermionAsset> loadGltfFromBuffer(
Uint8List data, {
bool addToScene = true,
int numInstances = 1,
int initialInstances = 1,
bool keepData = false,
int priority = 4,
int layer = 0,
@@ -499,7 +499,7 @@ class ThermionViewerFFI extends ThermionViewer {
var asset = await FilamentApp.instance!.loadGltfFromBuffer(
data,
animationManager,
numInstances: numInstances,
initialInstances: initialInstances,
keepData: keepData,
priority: priority,
layer: layer,

View File

@@ -151,37 +151,38 @@ abstract class ThermionViewer {
/// If [addToScene] is [true], all renderable entities (including lights)
/// in the asset will be added to the scene.
///
/// If you want to dynamically create instances of this asset after it is
/// instantiated, pass [kee]
/// Alternatively, specifying [numInstances] will pre-allocate the specified
/// number of instances. This is more efficient than dynamically instantating at a later time.
/// You can then retrieve the created instances with [getInstances].
///
/// If [keepData] is false and [numInstances] is 1,
/// the source glTF data will be released and [createInstance]
/// will throw an exception.
/// The [initialInstances] argument determines the number of
/// instances created when the asset is first instantiated. If [keepData] is
/// false, no further instances will be able to be created.
///
/// If [keepData] is true, additional instances can be created by calling
/// [createInstance] on the returned asset.
///
/// Creating instances at asset load time is more efficient than dynamically
/// instantating at a later time.
///
/// Instances can be retrieved with [getInstances].
///
/// If [loadResourcesAsync] is true, resources (textures, materials, etc) will
/// be loaded asynchronously. Some material/texture pop-in is expected.
///
Future<ThermionAsset> loadGltf(String uri,
{bool addToScene = true,
int numInstances = 1,
int initialInstances = 1,
bool keepData = false,
String? resourceUri,
bool loadAsync = false});
///
/// Load the .glb asset from the specified buffer, adding all entities to the scene.
/// Specify [numInstances] to create multiple instances (this is more efficient than dynamically instantating at a later time). You can then retrieve the created instances with [getInstances].
/// If you want to be able to call [createInstance] at a later time, you must pass true for [keepData].
/// If [keepData] is false, the source glTF data will be released and [createInstance] will throw an exception.
/// If [loadResourcesAsync] is true, resources (textures, materials, etc) will
/// be loaded asynchronously (so expect some material/texture pop-in);
/// Loads a gltf asset from the specified buffer (which contains the contents
/// of a .glb file).
///
/// See the [loadGltf] method for documentation on arguments.
///
///
Future<ThermionAsset> loadGltfFromBuffer(Uint8List data,
{String? resourceUri,
int numInstances = 1,
int initialInstances = 1,
bool keepData = false,
int priority = 4,
int layer = 0,

View File

@@ -33,8 +33,7 @@ namespace thermion
Engine *engine,
utils::NameComponentManager* ncm,
MaterialInstance **materialInstances = nullptr,
size_t materialInstanceCount = 0,
int instanceIndex = 0);
size_t materialInstanceCount = 0);
~GltfSceneAsset();

View File

@@ -33,15 +33,16 @@ namespace thermion
Engine *engine,
utils::NameComponentManager* ncm,
MaterialInstance **materialInstances,
size_t materialInstanceCount,
int instanceIndex) : _asset(asset),
size_t materialInstanceCount) : _asset(asset),
_assetLoader(assetLoader),
_engine(engine),
_ncm(ncm),
_materialInstances(materialInstances),
_materialInstanceCount(materialInstanceCount)
{
createInstance();
for(int i = 0; i < asset->getAssetInstanceCount(); i++) {
createInstance();
}
TRACE("Created GltfSceneAsset from FilamentAsset %d with %d reserved instances", asset, asset->getAssetInstanceCount());
}

View File

@@ -56,11 +56,20 @@ void main() async {
}, bg: kRed);
});
test('gltf assets always create one instance', () async {
test('gltf assets are created with initialInstances instances', () async {
await testHelper.withViewer((viewer) async {
var asset =
await viewer.loadGltf("file://${testHelper.testDir}/assets/cube.glb");
var asset = await viewer.loadGltf(
"file://${testHelper.testDir}/assets/cube.glb",
initialInstances: 1);
expect(await asset.getInstanceCount(), 1);
asset = await viewer.loadGltf(
"file://${testHelper.testDir}/assets/cube.glb",
initialInstances: 2);
expect(await asset.getInstanceCount(), 2);
await expectLater(asset.createInstance(), throwsA(isA<Exception>()));
});
});
@@ -77,11 +86,12 @@ void main() async {
var asset = await viewer.loadGltf(
"file://${testHelper.testDir}/assets/cube.glb",
addToScene: false,
numInstances: 2, keepData: true);
initialInstances: 2,
keepData: true);
var defaultInstance = await asset.getInstance(0);
await viewer.addToScene(defaultInstance);
await testHelper.capture(viewer.view, "gltf_without_instance");
var instance = await asset.createInstance();
await instance.setTransform(Matrix4.translation(Vector3(1, 0, 0)));
await testHelper.capture(viewer.view, "gltf_instance_created");
@@ -91,13 +101,12 @@ void main() async {
await testHelper.capture(viewer.view, "gltf_instance_remove_from_scene");
// above, we pre-allocated two instances and have used all of them
// calling createInstance now will still create another instance, but will be slower than allocating.
// calling createInstance now will still create another instance, but
// will be slower than specifying initialInstances on load.
var instance2 = await asset.createInstance();
await instance2.setTransform(Matrix4.translation(Vector3(-1, 0, 0)));
await viewer.addToScene(instance2);
await testHelper.capture(viewer.view, "gltf_instance2_add_to_scene");
}, addSkybox: true);
});