add TextureProjection class

This commit is contained in:
Nick Fisher
2025-03-25 11:33:07 +08:00
parent 6c25a3c405
commit 7d5b183dea

View File

@@ -0,0 +1,118 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_view.dart';
import 'package:thermion_dart/thermion_dart.dart';
class TextureProjection {
final SwapChain swapChain;
final Material projectionMaterial;
final MaterialInstance projectionMaterialInstance;
final Material depthWriteMaterial;
final MaterialInstance depthWriteMaterialInstance;
final Texture texture;
final View depthView;
final View projectionView;
TextureProjection._(
{required this.swapChain,
required this.projectionMaterial,
required this.projectionMaterialInstance,
required this.depthWriteMaterial,
required this.depthWriteMaterialInstance,
required this.texture,
required this.depthView,
required this.projectionView}) {}
static Future<TextureProjection> create(
View sourceView, SwapChain swapChain) async {
final viewport = await sourceView.getViewport();
var depthWriteMat = await FilamentApp.instance!.createMaterial(
File(
"/Users/nickfisher/Documents/thermion/materials/linear_depth.filamat",
).readAsBytesSync(),
);
var depthWriteMi = await depthWriteMat.createInstance();
final depthWriteView = await FilamentApp.instance!.createView() as FFIView;
await depthWriteView.setFrustumCullingEnabled(false);
await depthWriteView.setPostProcessing(false);
await depthWriteView.setViewport(viewport.width, viewport.height);
await depthWriteView.setBlendMode(BlendMode.opaque);
final color = await (await sourceView.getRenderTarget())!.getColorTexture();
final depth =
await (await depthWriteView.getRenderTarget())!.getColorTexture();
var captureMat = await FilamentApp.instance!.createMaterial(
File(
"/Users/nickfisher/Documents/thermion/materials/capture_uv.filamat",
).readAsBytesSync(),
);
var captureMi = await captureMat.createInstance();
await captureMi.setParameterBool("flipUVs", true);
await captureMi.setParameterTexture(
"color", color, await FilamentApp.instance!.createTextureSampler());
await captureMi.setParameterTexture(
"depth", depth, await FilamentApp.instance!.createTextureSampler());
await captureMi.setParameterBool("useDepth", true);
final projectionView = await FilamentApp.instance!.createView() as FFIView;
await projectionView.setFrustumCullingEnabled(false);
await projectionView.setPostProcessing(false);
await projectionView.setViewport(viewport.width, viewport.height);
final depthWriteColorTexture = await FilamentApp.instance!
.createTexture(viewport.width, viewport.height,
flags: {
TextureUsage.TEXTURE_USAGE_COLOR_ATTACHMENT,
TextureUsage.TEXTURE_USAGE_SAMPLEABLE,
TextureUsage.TEXTURE_USAGE_BLIT_SRC
},
textureFormat: TextureFormat.R32F);
await depthWriteView
.setRenderTarget(await FilamentApp.instance!.createRenderTarget(
viewport.width,
viewport.height,
color: depthWriteColorTexture,
) as FFIRenderTarget);
await FilamentApp.instance!.register(swapChain, depthWriteView);
await FilamentApp.instance!.register(swapChain, projectionView);
return TextureProjection._(
swapChain: swapChain,
depthView: depthWriteView,
projectionView: projectionView,
projectionMaterial: captureMat,
projectionMaterialInstance: captureMi,
depthWriteMaterial: depthWriteMat,
depthWriteMaterialInstance: depthWriteMi,
texture: depthWriteColorTexture);
}
Future destroy() async {
await projectionMaterialInstance.destroy();
await projectionMaterial.destroy();
await FilamentApp.instance!.destroyView(depthView);
await FilamentApp.instance!.destroyView(projectionView);
}
Future<Uint8List> execute(ThermionAsset target, View view) async {
var originalMi = await target.getMaterialInstanceAt();
var pixelBuffers = await FilamentApp.instance!
.capture(swapChain, view: view, beforeRender: (view) async {
if (view == depthView) {
await target.setMaterialInstanceAt(depthWriteMaterialInstance);
} else if (view == projectionView) {
await target.setMaterialInstanceAt(projectionMaterialInstance);
}
},
pixelDataFormat: PixelDataFormat.RGBA,
pixelDataType: PixelDataType.FLOAT);
await target.setMaterialInstanceAt(originalMi);
return pixelBuffers.firstWhere((pb) => pb.$1 == projectionView).$2;
}
}