test updates
This commit is contained in:
@@ -2,17 +2,9 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
import 'dart:typed_data';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'package:thermion_dart/src/utils/src/texture_projection.dart';
|
import 'package:thermion_dart/src/utils/src/texture_projection.dart';
|
||||||
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
|
|
||||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart';
|
|
||||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_camera.dart';
|
|
||||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
|
||||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart';
|
|
||||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart';
|
|
||||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart';
|
|
||||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart';
|
|
||||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_view.dart';
|
|
||||||
import 'package:thermion_dart/thermion_dart.dart';
|
import 'package:thermion_dart/thermion_dart.dart';
|
||||||
import 'helpers.dart';
|
import 'helpers.dart';
|
||||||
|
|
||||||
@@ -49,6 +41,8 @@ void main() async {
|
|||||||
final camera = await viewer.getActiveCamera();
|
final camera = await viewer.getActiveCamera();
|
||||||
await viewer.view.setFrustumCullingEnabled(false);
|
await viewer.view.setFrustumCullingEnabled(false);
|
||||||
await camera.setLensProjection(near: 0.75, far: 100);
|
await camera.setLensProjection(near: 0.75, far: 100);
|
||||||
|
final vp = await viewer.view.getViewport();
|
||||||
|
final (width, height) = (vp.width, vp.height);
|
||||||
final dist = 5.0;
|
final dist = 5.0;
|
||||||
await camera.lookAt(
|
await camera.lookAt(
|
||||||
Vector3(
|
Vector3(
|
||||||
@@ -74,13 +68,15 @@ void main() async {
|
|||||||
|
|
||||||
final divisions = 8;
|
final divisions = 8;
|
||||||
final projectedImage =
|
final projectedImage =
|
||||||
await FilamentApp.instance!.createImage(512, 512, 4);
|
await FilamentApp.instance!.createImage(width, height, 4);
|
||||||
final projectedTexture = await FilamentApp.instance!.createTexture(
|
final projectedTexture = await FilamentApp.instance!.createTexture(
|
||||||
512,
|
width,
|
||||||
512,
|
height,
|
||||||
textureFormat: TextureFormat.RGBA32F,
|
textureFormat: TextureFormat.RGBA32F,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var images = <Float32List>[];
|
||||||
|
|
||||||
for (int i = 0; i < divisions; i++) {
|
for (int i = 0; i < divisions; i++) {
|
||||||
await camera.lookAt(
|
await camera.lookAt(
|
||||||
Vector3(
|
Vector3(
|
||||||
@@ -93,15 +89,17 @@ void main() async {
|
|||||||
await textureProjection.project(cube);
|
await textureProjection.project(cube);
|
||||||
final depth = textureProjection.getDepthWritePixelBuffer();
|
final depth = textureProjection.getDepthWritePixelBuffer();
|
||||||
await savePixelBufferToBmp(
|
await savePixelBufferToBmp(
|
||||||
depth, 512, 512, "${testHelper.outDir.path}/depth_$i.bmp");
|
depth, width, height, "${testHelper.outDir.path}/depth_$i.bmp");
|
||||||
final projected = textureProjection.getProjectedPixelBuffer();
|
final projected = textureProjection.getProjectedPixelBuffer();
|
||||||
await savePixelBufferToBmp(
|
await savePixelBufferToBmp(projected, width, height,
|
||||||
depth, 512, 512, "${testHelper.outDir.path}/projected_$i.bmp");
|
"${testHelper.outDir.path}/projected_$i.bmp");
|
||||||
await cube.setMaterialInstanceAt(ubershader);
|
await cube.setMaterialInstanceAt(ubershader);
|
||||||
|
|
||||||
final data = await projectedImage.getData();
|
final data = await projectedImage.getData();
|
||||||
data.setRange(0, data.length, projected.buffer.asFloat32List());
|
data.setRange(0, data.length, projected.buffer.asFloat32List());
|
||||||
|
|
||||||
|
images.add(projected.buffer.asFloat32List());
|
||||||
|
|
||||||
await projectedTexture.setLinearImage(
|
await projectedTexture.setLinearImage(
|
||||||
projectedImage,
|
projectedImage,
|
||||||
PixelDataFormat.RGBA,
|
PixelDataFormat.RGBA,
|
||||||
@@ -119,6 +117,97 @@ void main() async {
|
|||||||
await ubershader.setParameterTexture(
|
await ubershader.setParameterTexture(
|
||||||
"baseColorMap", originalTexture, sampler);
|
"baseColorMap", originalTexture, sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Improved blending - treating black pixels as transparent
|
||||||
|
final blendedImage = Float32List(width * height * 4);
|
||||||
|
final weightSums = List<double>.filled(width * height, 0.0);
|
||||||
|
|
||||||
|
// For each image
|
||||||
|
for (final image in images) {
|
||||||
|
// For each pixel in the image
|
||||||
|
for (int p = 0; p < width * height; p++) {
|
||||||
|
final baseIdx = p * 4;
|
||||||
|
final r = image[baseIdx];
|
||||||
|
final g = image[baseIdx + 1];
|
||||||
|
final b = image[baseIdx + 2];
|
||||||
|
final alpha = image[baseIdx + 3];
|
||||||
|
|
||||||
|
// Check if pixel is black (all color channels near zero)
|
||||||
|
final isBlack = (r < 0.01 && g < 0.01 && b < 0.01);
|
||||||
|
|
||||||
|
// Only include pixels that are non-black AND have non-zero alpha
|
||||||
|
if (!isBlack && alpha > 0) {
|
||||||
|
// Weight contribution by alpha value
|
||||||
|
final weight = alpha;
|
||||||
|
blendedImage[baseIdx] += r * weight;
|
||||||
|
blendedImage[baseIdx + 1] += g * weight;
|
||||||
|
blendedImage[baseIdx + 2] += b * weight;
|
||||||
|
blendedImage[baseIdx + 3] += weight;
|
||||||
|
|
||||||
|
// Track total weights for normalization
|
||||||
|
weightSums[p] += weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize by the accumulated weights
|
||||||
|
for (int p = 0; p < width * height; p++) {
|
||||||
|
final baseIdx = p * 4;
|
||||||
|
final weightSum = weightSums[p];
|
||||||
|
|
||||||
|
if (weightSum > 0) {
|
||||||
|
blendedImage[baseIdx] /= weightSum;
|
||||||
|
blendedImage[baseIdx + 1] /= weightSum;
|
||||||
|
blendedImage[baseIdx + 2] /= weightSum;
|
||||||
|
// Set alpha to full for pixels that had contributions
|
||||||
|
blendedImage[baseIdx + 3] = 1.0;
|
||||||
|
} else {
|
||||||
|
// For pixels with no contributions, ensure they're fully transparent
|
||||||
|
blendedImage[baseIdx] = 0;
|
||||||
|
blendedImage[baseIdx + 1] = 0;
|
||||||
|
blendedImage[baseIdx + 2] = 0;
|
||||||
|
blendedImage[baseIdx + 3] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set the blended data to the projectedImage
|
||||||
|
final data = await projectedImage.getData();
|
||||||
|
data.setRange(0, data.length, blendedImage);
|
||||||
|
|
||||||
|
await savePixelBufferToBmp(blendedImage.buffer.asUint8List(), width,
|
||||||
|
height, "${testHelper.outDir.path}/blended.bmp",
|
||||||
|
hasAlpha: true, isFloat: true);
|
||||||
|
|
||||||
|
// Update the texture with the blended image
|
||||||
|
await projectedTexture.setLinearImage(
|
||||||
|
projectedImage,
|
||||||
|
PixelDataFormat.RGBA,
|
||||||
|
PixelDataType.FLOAT,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set the blended texture as the material parameter
|
||||||
|
await ubershader.setParameterTexture(
|
||||||
|
"baseColorMap",
|
||||||
|
projectedTexture,
|
||||||
|
sampler,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Capture 120 frames orbiting around the cube
|
||||||
|
final orbitFrames = 120;
|
||||||
|
for (int frame = 0; frame < orbitFrames; frame++) {
|
||||||
|
// Calculate camera position based on frame
|
||||||
|
final angle = frame / orbitFrames * 2 * pi;
|
||||||
|
await camera.lookAt(
|
||||||
|
Vector3(
|
||||||
|
sin(angle) * dist,
|
||||||
|
dist * 0.8, // Slightly lower height
|
||||||
|
cos(angle) * dist,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Capture each frame with a sequential number
|
||||||
|
await testHelper.capture(viewer.view,
|
||||||
|
"capture_uv_blended_orbit_${frame.toString().padLeft(3, '0')}");
|
||||||
|
}
|
||||||
}, createRenderTarget: true);
|
}, createRenderTarget: true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:thermion_dart/src/filament/src/light_options.dart';
|
||||||
import 'package:thermion_dart/thermion_dart.dart';
|
import 'package:thermion_dart/thermion_dart.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
@@ -5,15 +8,17 @@ import 'helpers.dart';
|
|||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
final testHelper = TestHelper("material");
|
final testHelper = TestHelper("material");
|
||||||
|
await testHelper.setup();
|
||||||
|
|
||||||
group("shadow tests", () {
|
group("shadow tests", () {
|
||||||
test('enable/disable shadows', () async {
|
test('enable/disable shadows', () async {
|
||||||
await testHelper.withViewer((viewer) async {
|
await testHelper.withViewer((viewer) async {
|
||||||
await viewer.setPostProcessing(true);
|
await viewer.setShadowsEnabled(false);
|
||||||
await viewer.setShadowsEnabled(true);
|
|
||||||
await viewer.setShadowType(ShadowType.PCF);
|
await viewer.setShadowType(ShadowType.PCF);
|
||||||
var materialInsance = await viewer.createUbershaderMaterialInstance();
|
var materialInstance =
|
||||||
await materialInsance.setParameterFloat4(
|
await FilamentApp.instance!.createUbershaderMaterialInstance();
|
||||||
|
await materialInstance.setCullingMode(CullingMode.NONE);
|
||||||
|
await materialInstance.setParameterFloat4(
|
||||||
"baseColorFactor", 0.0, 1.0, 0.0, 1.0);
|
"baseColorFactor", 0.0, 1.0, 0.0, 1.0);
|
||||||
await viewer.addDirectLight(DirectLight.sun(
|
await viewer.addDirectLight(DirectLight.sun(
|
||||||
intensity: 50000,
|
intensity: 50000,
|
||||||
@@ -23,22 +28,25 @@ void main() async {
|
|||||||
final plane = await viewer.createGeometry(
|
final plane = await viewer.createGeometry(
|
||||||
GeometryHelper.plane(
|
GeometryHelper.plane(
|
||||||
normals: true, uvs: true, width: 10, height: 10),
|
normals: true, uvs: true, width: 10, height: 10),
|
||||||
materialInstances: [materialInsance]);
|
materialInstances: [materialInstance]);
|
||||||
expect(await viewer.isCastShadowsEnabled(plane.entity), true);
|
// await plane.setTransform(Matrix4.rotationX(pi));
|
||||||
expect(await viewer.isReceiveShadowsEnabled(plane.entity), true);
|
// await viewer.addToScene(plane);
|
||||||
await viewer.createGeometry(
|
expect(await plane.isCastShadowsEnabled(), true);
|
||||||
|
expect(await plane.isReceiveShadowsEnabled(), true);
|
||||||
|
final cube = await viewer.createGeometry(
|
||||||
GeometryHelper.cube(
|
GeometryHelper.cube(
|
||||||
normals: true,
|
normals: true,
|
||||||
uvs: true,
|
uvs: true,
|
||||||
),
|
),
|
||||||
materialInstances: [materialInsance]);
|
materialInstances: [materialInstance]);
|
||||||
|
await viewer.setShadowsEnabled(true);
|
||||||
|
|
||||||
await testHelper.capture(viewer, "shadows_enabled");
|
await testHelper.capture(viewer.view, "shadows_enabled");
|
||||||
|
|
||||||
await viewer.setShadowsEnabled(false);
|
await viewer.setShadowsEnabled(false);
|
||||||
|
|
||||||
await testHelper.capture(viewer, "shadows_disabled");
|
await testHelper.capture(viewer.view, "shadows_disabled");
|
||||||
}, bg: kRed);
|
}, bg: kRed, createRenderTarget: true, postProcessing: true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('enable/disable cast shadows', () async {
|
test('enable/disable cast shadows', () async {
|
||||||
@@ -46,8 +54,11 @@ void main() async {
|
|||||||
await viewer.setPostProcessing(true);
|
await viewer.setPostProcessing(true);
|
||||||
await viewer.setShadowsEnabled(true);
|
await viewer.setShadowsEnabled(true);
|
||||||
await viewer.setShadowType(ShadowType.PCF);
|
await viewer.setShadowType(ShadowType.PCF);
|
||||||
var materialInsance = await viewer.createUbershaderMaterialInstance();
|
var materialInstance =
|
||||||
await materialInsance.setParameterFloat4(
|
await FilamentApp.instance!.createUbershaderMaterialInstance();
|
||||||
|
await materialInstance.setCullingMode(CullingMode.NONE);
|
||||||
|
|
||||||
|
await materialInstance.setParameterFloat4(
|
||||||
"baseColorFactor", 0.0, 1.0, 0.0, 1.0);
|
"baseColorFactor", 0.0, 1.0, 0.0, 1.0);
|
||||||
await viewer.addDirectLight(DirectLight.sun(
|
await viewer.addDirectLight(DirectLight.sun(
|
||||||
intensity: 50000,
|
intensity: 50000,
|
||||||
@@ -57,22 +68,22 @@ void main() async {
|
|||||||
final plane = await viewer.createGeometry(
|
final plane = await viewer.createGeometry(
|
||||||
GeometryHelper.plane(
|
GeometryHelper.plane(
|
||||||
normals: true, uvs: true, width: 10, height: 10),
|
normals: true, uvs: true, width: 10, height: 10),
|
||||||
materialInstances: [materialInsance]);
|
materialInstances: [materialInstance]);
|
||||||
|
|
||||||
final cube = await viewer.createGeometry(
|
final cube = await viewer.createGeometry(
|
||||||
GeometryHelper.cube(
|
GeometryHelper.cube(
|
||||||
normals: true,
|
normals: true,
|
||||||
uvs: true,
|
uvs: true,
|
||||||
),
|
),
|
||||||
materialInstances: [materialInsance]);
|
materialInstances: [materialInstance]);
|
||||||
|
|
||||||
expect(await viewer.isCastShadowsEnabled(cube.entity), true);
|
expect(await cube.isCastShadowsEnabled(), true);
|
||||||
await testHelper.capture(viewer, "cast_shadows_enabled");
|
await testHelper.capture(viewer.view, "cast_shadows_enabled");
|
||||||
|
|
||||||
await viewer.setCastShadows(cube.entity, false);
|
await cube.setCastShadows(false);
|
||||||
expect(await viewer.isCastShadowsEnabled(cube.entity), false);
|
expect(await cube.isCastShadowsEnabled(), false);
|
||||||
await testHelper.capture(viewer, "cast_shadows_disabled");
|
await testHelper.capture(viewer.view, "cast_shadows_disabled");
|
||||||
}, bg: kRed);
|
}, bg: kRed, createRenderTarget: true, postProcessing: true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('enable/disable receive shadows', () async {
|
test('enable/disable receive shadows', () async {
|
||||||
@@ -80,9 +91,12 @@ void main() async {
|
|||||||
await viewer.setPostProcessing(true);
|
await viewer.setPostProcessing(true);
|
||||||
await viewer.setShadowsEnabled(true);
|
await viewer.setShadowsEnabled(true);
|
||||||
await viewer.setShadowType(ShadowType.PCF);
|
await viewer.setShadowType(ShadowType.PCF);
|
||||||
var materialInsance = await viewer.createUbershaderMaterialInstance();
|
var materialInstance =
|
||||||
await materialInsance.setParameterFloat4(
|
await FilamentApp.instance!.createUbershaderMaterialInstance();
|
||||||
|
await materialInstance.setParameterFloat4(
|
||||||
"baseColorFactor", 0.0, 1.0, 0.0, 1.0);
|
"baseColorFactor", 0.0, 1.0, 0.0, 1.0);
|
||||||
|
await materialInstance.setCullingMode(CullingMode.NONE);
|
||||||
|
|
||||||
await viewer.addDirectLight(DirectLight.sun(
|
await viewer.addDirectLight(DirectLight.sun(
|
||||||
intensity: 50000,
|
intensity: 50000,
|
||||||
castShadows: true,
|
castShadows: true,
|
||||||
@@ -91,22 +105,22 @@ void main() async {
|
|||||||
final plane = await viewer.createGeometry(
|
final plane = await viewer.createGeometry(
|
||||||
GeometryHelper.plane(
|
GeometryHelper.plane(
|
||||||
normals: true, uvs: true, width: 10, height: 10),
|
normals: true, uvs: true, width: 10, height: 10),
|
||||||
materialInstances: [materialInsance]);
|
materialInstances: [materialInstance]);
|
||||||
|
|
||||||
final cube = await viewer.createGeometry(
|
final cube = await viewer.createGeometry(
|
||||||
GeometryHelper.cube(
|
GeometryHelper.cube(
|
||||||
normals: true,
|
normals: true,
|
||||||
uvs: true,
|
uvs: true,
|
||||||
),
|
),
|
||||||
materialInstances: [materialInsance]);
|
materialInstances: [materialInstance]);
|
||||||
|
|
||||||
expect(await viewer.isReceiveShadowsEnabled(plane.entity), true);
|
expect(await plane.isReceiveShadowsEnabled(), true);
|
||||||
await testHelper.capture(viewer, "receive_shadows_enabled");
|
await testHelper.capture(viewer.view, "receive_shadows_enabled");
|
||||||
|
|
||||||
await viewer.setReceiveShadows(plane.entity, false);
|
await plane.setReceiveShadows(false);
|
||||||
expect(await viewer.isReceiveShadowsEnabled(plane.entity), false);
|
expect(await plane.isReceiveShadowsEnabled(), false);
|
||||||
await testHelper.capture(viewer, "receive_shadows_disabled");
|
await testHelper.capture(viewer.view, "receive_shadows_disabled");
|
||||||
}, bg: kRed);
|
}, bg: kRed, createRenderTarget: true, postProcessing: true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user