feat: remove bounding box from SceneAsset and create renderable wireframe bounding box in ThermionAsset

This commit is contained in:
Nick Fisher
2024-12-21 07:45:50 +08:00
parent 51bdca7158
commit 8d8acef481
13 changed files with 274 additions and 53 deletions

View File

@@ -16,9 +16,10 @@ class FFIAsset extends ThermionAsset {
final bool isInstance;
late final ThermionEntity entity;
final ThermionViewer viewer;
FFIAsset(
this.pointer, this.sceneManager, this.engine, this._unlitMaterialProvider,
FFIAsset(this.pointer, this.sceneManager, this.engine,
this._unlitMaterialProvider, this.viewer,
{this.isInstance = false}) {
entity = SceneAsset_getEntity(pointer);
}
@@ -41,7 +42,8 @@ class FFIAsset extends ThermionAsset {
if (instance == nullptr) {
throw Exception("No instance available at index $index");
}
return FFIAsset(instance, sceneManager, engine, _unlitMaterialProvider);
return FFIAsset(
instance, sceneManager, engine, _unlitMaterialProvider, viewer);
}
///
@@ -71,7 +73,8 @@ class FFIAsset extends ThermionAsset {
if (created == FILAMENT_ASSET_ERROR) {
throw Exception("Failed to create instance");
}
return FFIAsset(created, sceneManager, engine, _unlitMaterialProvider);
return FFIAsset(
created, sceneManager, engine, _unlitMaterialProvider, viewer);
}
///
@@ -90,7 +93,7 @@ class FFIAsset extends ThermionAsset {
var count = await getInstanceCount();
final result = List<ThermionAsset>.generate(count, (i) {
return FFIAsset(SceneAsset_getInstance(pointer, i), sceneManager, engine,
_unlitMaterialProvider);
_unlitMaterialProvider, viewer);
});
return result;
@@ -184,4 +187,100 @@ class FFIAsset extends ThermionAsset {
SceneManager_removeFromScene(sceneManager, child);
}
}
ThermionAsset? _boundingBoxAsset;
Aabb3 getBoundingBox() {
final aabb3 = SceneManager_getRenderableBoundingBox(sceneManager, entity);
return aabb3;
}
@override
Future<void> setBoundingBoxVisibility(bool visible) async {
if (_boundingBoxAsset == null) {
final boundingBox = await getBoundingBox();
final min = [
boundingBox.centerX - boundingBox.halfExtentX,
boundingBox.centerY - boundingBox.halfExtentY,
boundingBox.centerZ - boundingBox.halfExtentZ
];
final max = [
boundingBox.centerX + boundingBox.halfExtentX,
boundingBox.centerY + boundingBox.halfExtentY,
boundingBox.centerZ + boundingBox.halfExtentZ
];
// Create vertices for the bounding box wireframe
// 8 vertices for a cube
final vertices = Float32List(8 * 3);
// Bottom vertices
vertices[0] = min[0];
vertices[1] = min[1];
vertices[2] = min[2]; // v0
vertices[3] = max[0];
vertices[4] = min[1];
vertices[5] = min[2]; // v1
vertices[6] = max[0];
vertices[7] = min[1];
vertices[8] = max[2]; // v2
vertices[9] = min[0];
vertices[10] = min[1];
vertices[11] = max[2]; // v3
// Top vertices
vertices[12] = min[0];
vertices[13] = max[1];
vertices[14] = min[2]; // v4
vertices[15] = max[0];
vertices[16] = max[1];
vertices[17] = min[2]; // v5
vertices[18] = max[0];
vertices[19] = max[1];
vertices[20] = max[2]; // v6
vertices[21] = min[0];
vertices[22] = max[1];
vertices[23] = max[2]; // v7
// Indices for lines (24 indices for 12 lines)
final indices = [
// Bottom face
0, 1, 1, 2, 2, 3, 3, 0,
// Top face
4, 5, 5, 6, 6, 7, 7, 4,
// Vertical edges
0, 4, 1, 5, 2, 6, 3, 7
];
// Create unlit material instance for the wireframe
final materialInstancePtr =
await withPointerCallback<TMaterialInstance>((cb) {
final key = Struct.create<TMaterialKey>();
MaterialProvider_createMaterialInstanceRenderThread(
_unlitMaterialProvider, key.address, cb);
});
final material = FFIMaterialInstance(materialInstancePtr, sceneManager);
await material.setParameterFloat4(
"baseColorFactor", 1.0, 1.0, 0.0, 1.0); // Yellow wireframe
// Create geometry for the bounding box
final geometry = Geometry(
vertices,
indices,
primitiveType: PrimitiveType.LINES,
);
_boundingBoxAsset = await viewer.createGeometry(
geometry,
materialInstances: [material],
keepData: false,
);
}
if (visible) {
await _boundingBoxAsset!.addToScene();
} else {
await _boundingBoxAsset!.removeFromScene();
}
}
}

View File

@@ -32,6 +32,7 @@ class FFIGizmo extends FFIAsset implements GizmoAsset {
super.sceneManager,
super.renderableManager,
super.unlitMaterialProvider,
super.viewer,
this.gizmoEntities) {
_nativeCallback =
NativeCallable<GizmoPickCallbackFunction>.listener(_onPickResult);

View File

@@ -230,6 +230,22 @@ external void MaterialInstance_setStencilWriteMask(
int mask,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TMaterialInstance>, ffi.UnsignedInt)>(
symbol: "MaterialInstance_setTransparencyMode", isLeaf: true)
external void _MaterialInstance_setTransparencyMode(
ffi.Pointer<TMaterialInstance> materialInstance,
int transparencyMode,
);
void MaterialInstance_setTransparencyMode(
ffi.Pointer<TMaterialInstance> materialInstance,
TTransparencyMode transparencyMode,
) =>
_MaterialInstance_setTransparencyMode(
materialInstance,
transparencyMode.value,
);
@ffi.Native<
ffi.Pointer<TViewer> Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Char>)>(isLeaf: true)
@@ -741,6 +757,12 @@ external void View_setFrustumCullingEnabled(
bool enabled,
);
@ffi.Native<ffi.Pointer<TRenderTarget> Function(ffi.Pointer<TView>)>(
isLeaf: true)
external ffi.Pointer<TRenderTarget> View_getRenderTarget(
ffi.Pointer<TView> tView,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Bool)>(isLeaf: true)
external void View_setPostProcessing(
ffi.Pointer<TView> tView,
@@ -1310,6 +1332,15 @@ external void Viewer_createRenderTargetRenderThread(
onComplete,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TViewer>, ffi.Pointer<TRenderTarget>,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void Viewer_destroyRenderTargetRenderThread(
ffi.Pointer<TViewer> viewer,
ffi.Pointer<TRenderTarget> tRenderTarget,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> onComplete,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TEngine>,
@@ -2730,6 +2761,30 @@ enum TCullingMode {
};
}
enum TTransparencyMode {
/// ! the transparent object is drawn honoring the raster state
DEFAULT(0),
/// the transparent object is first drawn in the depth buffer,
/// then in the color buffer, honoring the culling mode, but ignoring the depth test function
TWO_PASSES_ONE_SIDE(1),
/// the transparent object is drawn twice in the color buffer,
/// first with back faces only, then with front faces; the culling
/// mode is ignored. Can be combined with two-sided lighting
TWO_PASSES_TWO_SIDES(2);
final int value;
const TTransparencyMode(this.value);
static TTransparencyMode fromValue(int value) => switch (value) {
0 => DEFAULT,
1 => TWO_PASSES_ONE_SIDE,
2 => TWO_PASSES_TWO_SIDES,
_ => throw ArgumentError("Unknown value for TTransparencyMode: $value"),
};
}
typedef EntityId = ffi.Int32;
typedef DartEntityId = int;

View File

@@ -511,7 +511,7 @@ class ThermionViewerFFI extends ThermionViewer {
}
var thermionAsset =
FFIAsset(asset, _sceneManager!, _engine!, _unlitMaterialProvider!);
FFIAsset(asset, _sceneManager!, _engine!, _unlitMaterialProvider!, this);
return thermionAsset;
}
@@ -551,7 +551,7 @@ class ThermionViewerFFI extends ThermionViewer {
throw Exception("An error occurred loading GLB from buffer");
}
return FFIAsset(
assetPtr, _sceneManager!, _engine!, _unlitMaterialProvider!);
assetPtr, _sceneManager!, _engine!, _unlitMaterialProvider!, this);
}
///
@@ -573,7 +573,7 @@ class ThermionViewerFFI extends ThermionViewer {
}
return FFIAsset(
assetPtr, _sceneManager!, _engine!, _unlitMaterialProvider!);
assetPtr, _sceneManager!, _engine!, _unlitMaterialProvider!, this);
}
///
@@ -1642,7 +1642,7 @@ class ThermionViewerFFI extends ThermionViewer {
}
var asset =
FFIAsset(assetPtr, _sceneManager!, _engine!, _unlitMaterialProvider!);
FFIAsset(assetPtr, _sceneManager!, _engine!, _unlitMaterialProvider!, this);
return asset;
}
@@ -1760,7 +1760,7 @@ class ThermionViewerFFI extends ThermionViewer {
_sceneManager!, material.pointer, cb);
}
});
_grid = FFIAsset(ptr, _sceneManager!, _engine!, _unlitMaterialProvider!);
_grid = FFIAsset(ptr, _sceneManager!, _engine!, _unlitMaterialProvider!, this);
}
await _grid!.addToScene();
await setLayerVisibility(VisibilityLayers.OVERLAY, true);
@@ -2093,6 +2093,7 @@ class ThermionViewerFFI extends ThermionViewer {
_sceneManager!,
_engine!,
nullptr,
this,
gizmoEntities.toSet()
..add(SceneAsset_getEntity(gizmo.cast<TSceneAsset>())));
}

View File

@@ -12,9 +12,8 @@ export 'light_options.dart';
typedef ThermionEntity = int;
abstract class ThermionAsset {
ThermionEntity get entity;
Future<List<ThermionEntity>> getChildEntities();
///
@@ -28,6 +27,11 @@ abstract class ThermionAsset {
///
Future removeStencilHighlight();
///
/// When visible is [true], renders the bounding box.
///
Future setBoundingBoxVisibility(bool visible);
///
///
///