update TextureProjection to accept material instances and render multiple target entities

This commit is contained in:
Nick Fisher
2025-06-23 12:38:06 +08:00
parent 18b6b2e5f0
commit 69400f8b68

View File

@@ -31,13 +31,13 @@ class TextureProjection {
required this.depthWriteColorTexture, required this.depthWriteColorTexture,
required this.sampler}) {} required this.sampler}) {}
static Future<TextureProjection> create(View sourceView) async { static Future<TextureProjection> create(View sourceView, Uint8List depthWriteMaterial, Uint8List captureUvMaterial) async {
final viewport = await sourceView.getViewport(); final viewport = await sourceView.getViewport();
var depthWriteMat = await FilamentApp.instance!.createMaterial( var depthWriteMat = await FilamentApp.instance!.createMaterial(depthWriteMaterial);
File( // File(
"/Users/nickfisher/Documents/thermion/materials/linear_depth.filamat", // "/Users/nickfisher/Documents/thermion/materials/linear_depth.filamat",
).readAsBytesSync(), // ).readAsBytesSync(),
); // );
var depthWriteMi = await depthWriteMat.createInstance(); var depthWriteMi = await depthWriteMat.createInstance();
final depthView = await FilamentApp.instance!.createView() as FFIView; final depthView = await FilamentApp.instance!.createView() as FFIView;
@@ -62,11 +62,11 @@ class TextureProjection {
) as FFIRenderTarget; ) as FFIRenderTarget;
await depthView.setRenderTarget(depthWriteRenderTarget); await depthView.setRenderTarget(depthWriteRenderTarget);
final captureMat = await FilamentApp.instance!.createMaterial( final captureMat = await FilamentApp.instance!.createMaterial(captureUvMaterial)
File( // File(
"/Users/nickfisher/Documents/thermion/materials/capture_uv.filamat", // "/Users/nickfisher/Documents/thermion/materials/capture_uv.filamat",
).readAsBytesSync(), // ).readAsBytesSync(),
) as FFIMaterial; as FFIMaterial;
var captureMi = await captureMat.createInstance() as FFIMaterialInstance; var captureMi = await captureMat.createInstance() as FFIMaterialInstance;
await captureMi.setParameterBool("flipUVs", true); await captureMi.setParameterBool("flipUVs", true);
@@ -117,23 +117,35 @@ class TextureProjection {
/// b) colors each fragment blue /// b) colors each fragment blue
/// 5) Use the render target color buffer as the input to a /// 5) Use the render target color buffer as the input to a
/// 6) Render this "projection view" and capture the output /// 6) Render this "projection view" and capture the output
Future<TextureProjectionResult> project(Texture texture, ThermionAsset target, Future<TextureProjectionResult> project(
{bool renderSourceView = true}) async { Texture texture, List<ThermionEntity> targets) async {
await FilamentApp.instance!.setClearOptions(0, 0, 0, 1,
clearStencil: 0, discard: false, clear: true);
final viewport = await sourceView.getViewport(); final viewport = await sourceView.getViewport();
final originalMi = await target.getMaterialInstanceAt();
final camera = (await sourceView.getCamera()) as FFICamera; final camera = (await sourceView.getCamera()) as FFICamera;
final originalScene = await sourceView.getScene() as FFIScene; final originalScene = await sourceView.getScene() as FFIScene;
// since we will be creating a single (unlit) scene, we need
// to replace the target asset's material with an unlit material
// (otherwise nothing will be visible in the initial output colour buffer).
final unlit = await FilamentApp.instance!.createUnlitMaterialInstance()
as FFIMaterialInstance;
await unlit.setParameterFloat4("baseColorFactor", 1.0, 1.0, 1.0, 1.0);
final projectionScene = final projectionScene =
(await FilamentApp.instance!.createScene()) as FFIScene; (await FilamentApp.instance!.createScene()) as FFIScene;
await projectionScene.add(target as FFIAsset);
await sourceView.setScene(projectionScene); final restoreMaterials = <ThermionEntity, List<MaterialInstance>>{};
for (final target in targets) {
await projectionScene.addEntity(target);
restoreMaterials[target] = [];
for (int i = 0;
i < await FilamentApp.instance!.getPrimitiveCount(target);
i++) {
final mi = await FilamentApp.instance!.getMaterialInstanceAt(target, i);
restoreMaterials[target]!.add(mi);
await FilamentApp.instance!.setMaterialInstanceAt(target, i, unlit);
}
}
await depthView.setCamera(camera); await depthView.setCamera(camera);
await depthView.setScene(projectionScene); await depthView.setScene(projectionScene);
@@ -141,40 +153,68 @@ class TextureProjection {
await projectionView.setCamera(camera); await projectionView.setCamera(camera);
await projectionView.setScene(projectionScene); await projectionView.setScene(projectionScene);
await projectionView.setViewport(viewport.width, viewport.height);
var _pixelBuffers = <View, Uint8List>{}; var sourceViewCapture = (await FilamentApp.instance!
.capture(null, view: sourceView, captureRenderTarget: true))
if (renderSourceView) {
_pixelBuffers[sourceView] =
(await FilamentApp.instance!.capture(null, view: sourceView))
.first .first
.$2; .$2;
for (final target in targets) {
for (int i = 0;
i < await FilamentApp.instance!.getPrimitiveCount(target);
i++) {
await FilamentApp.instance!
.setMaterialInstanceAt(target, i, depthWriteMaterialInstance);
}
} }
await target.setMaterialInstanceAt(depthWriteMaterialInstance); var depthViewCapture =
_pixelBuffers[depthView] =
(await FilamentApp.instance!.capture(null, view: depthView)).first.$2; (await FilamentApp.instance!.capture(null, view: depthView)).first.$2;
await projectionMaterialInstance.setParameterTexture( await projectionMaterialInstance.setParameterTexture(
"color", texture as FFITexture, sampler); "color", texture as FFITexture, sampler);
await target.setMaterialInstanceAt(projectionMaterialInstance);
_pixelBuffers[projectionView] = for (final target in targets) {
(await FilamentApp.instance!.capture(null, view: projectionView)).first.$2; for (int i = 0;
i < await FilamentApp.instance!.getPrimitiveCount(target);
i++) {
await FilamentApp.instance!
.setMaterialInstanceAt(target, i, projectionMaterialInstance);
}
}
final projectionViewCaptures = <Uint8List>[];
await target.setMaterialInstanceAt(originalMi as FFIMaterialInstance); var projectionViewCapture =
(await FilamentApp.instance!.capture(null, view: projectionView))
.first
.$2;
projectionViewCaptures.add(projectionViewCapture);
for (final target in targets) {
await projectionScene.removeEntity(target);
for (int i = 0;
i < await FilamentApp.instance!.getPrimitiveCount(target);
i++) {
await FilamentApp.instance!
.setMaterialInstanceAt(target, i, restoreMaterials[target]![i]);
}
}
await sourceView.setScene(originalScene); await sourceView.setScene(originalScene);
return TextureProjectionResult(_pixelBuffers[sourceView],
_pixelBuffers[depthView]!, _pixelBuffers[projectionView]!); await FilamentApp.instance!.destroyScene(projectionScene);
return TextureProjectionResult(
sourceViewCapture, depthViewCapture, projectionViewCaptures);
} }
} }
class TextureProjectionResult { class TextureProjectionResult {
final Uint8List? sourceView; final Uint8List? sourceView;
final Uint8List depth; final Uint8List depth;
final Uint8List projected; final List<Uint8List> projected;
TextureProjectionResult(this.sourceView, this.depth, this.projected); TextureProjectionResult(this.sourceView, this.depth, this.projected);
} }