split stencil/depth tests from unlit material tests
This commit is contained in:
85
thermion_dart/test/material_depth_buffer_tests.dart
Normal file
85
thermion_dart/test/material_depth_buffer_tests.dart
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
import 'package:thermion_dart/thermion_dart.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
import 'helpers.dart';
|
||||||
|
|
||||||
|
Future<
|
||||||
|
({
|
||||||
|
ThermionAsset blueCube,
|
||||||
|
MaterialInstance blueMaterialInstance,
|
||||||
|
ThermionAsset greenCube,
|
||||||
|
MaterialInstance greenMaterialInstance
|
||||||
|
})> setup(ThermionViewer viewer) async {
|
||||||
|
var blueMaterialInstance =
|
||||||
|
await FilamentApp.instance!.createUnlitMaterialInstance();
|
||||||
|
final blueCube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||||
|
materialInstances: [blueMaterialInstance]);
|
||||||
|
await blueMaterialInstance.setParameterFloat4(
|
||||||
|
"baseColorFactor", 0.0, 0.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
// Position blue cube slightly behind/below/right
|
||||||
|
await blueCube.setTransform(Matrix4.translation(Vector3(1.0, -1.0, -1.0)));
|
||||||
|
|
||||||
|
var greenMaterialInstance =
|
||||||
|
await FilamentApp.instance!.createUnlitMaterialInstance();
|
||||||
|
final greenCube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||||
|
materialInstances: [greenMaterialInstance]);
|
||||||
|
await greenMaterialInstance.setParameterFloat4(
|
||||||
|
"baseColorFactor", 0.0, 1.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
blueCube: blueCube,
|
||||||
|
blueMaterialInstance: blueMaterialInstance,
|
||||||
|
greenCube: greenCube,
|
||||||
|
greenMaterialInstance: greenMaterialInstance
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
final testHelper = TestHelper("material");
|
||||||
|
|
||||||
|
await testHelper.setup();
|
||||||
|
|
||||||
|
test('disable depth write', () async {
|
||||||
|
await testHelper.withViewer((viewer) async {
|
||||||
|
final (
|
||||||
|
:blueCube,
|
||||||
|
:blueMaterialInstance,
|
||||||
|
:greenCube,
|
||||||
|
:greenMaterialInstance
|
||||||
|
) = await setup(viewer);
|
||||||
|
|
||||||
|
// With depth write enabled on both materials, green cube renders behind the blue cube
|
||||||
|
await testHelper.capture(
|
||||||
|
viewer.view, "material_instance_depth_write_enabled");
|
||||||
|
|
||||||
|
// Disable depth write on green cube
|
||||||
|
// Blue cube will always appear in front
|
||||||
|
await greenMaterialInstance.setDepthWriteEnabled(false);
|
||||||
|
await testHelper.capture(
|
||||||
|
viewer.view, "material_instance_depth_write_disabled");
|
||||||
|
|
||||||
|
// Set priority for greenCube to render last, making it appear in front
|
||||||
|
await viewer.setPriority(greenCube.entity, 7);
|
||||||
|
await testHelper.capture(
|
||||||
|
viewer.view, "material_instance_depth_write_disabled_with_priority");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('set depth func to NEVER', () async {
|
||||||
|
await testHelper.withViewer((viewer) async {
|
||||||
|
final (
|
||||||
|
:blueCube,
|
||||||
|
:blueMaterialInstance,
|
||||||
|
:greenCube,
|
||||||
|
:greenMaterialInstance
|
||||||
|
) = await setup(viewer);
|
||||||
|
|
||||||
|
// Set depth func to NEVER on green cube
|
||||||
|
await greenMaterialInstance.setDepthFunc(SamplerCompareFunction.N);
|
||||||
|
// Green cube is not rendered at all
|
||||||
|
await testHelper.capture(viewer.view, "depth_func_never");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
175
thermion_dart/test/material_stencil_buffer_tests.dart
Normal file
175
thermion_dart/test/material_stencil_buffer_tests.dart
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
import 'package:thermion_dart/thermion_dart.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
import 'helpers.dart';
|
||||||
|
|
||||||
|
Future<
|
||||||
|
({
|
||||||
|
ThermionAsset blueCube,
|
||||||
|
MaterialInstance blueMaterialInstance,
|
||||||
|
ThermionAsset greenCube,
|
||||||
|
MaterialInstance greenMaterialInstance
|
||||||
|
})> setup(ThermionViewer viewer) async {
|
||||||
|
var blueMaterialInstance =
|
||||||
|
await FilamentApp.instance!.createUnlitMaterialInstance();
|
||||||
|
final blueCube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||||
|
materialInstances: [blueMaterialInstance]);
|
||||||
|
await blueMaterialInstance.setParameterFloat4(
|
||||||
|
"baseColorFactor", 0.0, 0.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
// Position blue cube slightly behind/below/right
|
||||||
|
await blueCube.setTransform(Matrix4.translation(Vector3(1.0, -1.0, -1.0)));
|
||||||
|
|
||||||
|
var greenMaterialInstance =
|
||||||
|
await FilamentApp.instance!.createUnlitMaterialInstance();
|
||||||
|
final greenCube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||||
|
materialInstances: [greenMaterialInstance]);
|
||||||
|
await greenMaterialInstance.setParameterFloat4(
|
||||||
|
"baseColorFactor", 0.0, 1.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
blueCube: blueCube,
|
||||||
|
blueMaterialInstance: blueMaterialInstance,
|
||||||
|
greenCube: greenCube,
|
||||||
|
greenMaterialInstance: greenMaterialInstance
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
final testHelper = TestHelper("stencil");
|
||||||
|
|
||||||
|
await testHelper.setup();
|
||||||
|
|
||||||
|
test('enable stencil write', () async {
|
||||||
|
await testHelper.withViewer((viewer) async {
|
||||||
|
final (
|
||||||
|
:blueCube,
|
||||||
|
:blueMaterialInstance,
|
||||||
|
:greenCube,
|
||||||
|
:greenMaterialInstance
|
||||||
|
) = await setup(viewer);
|
||||||
|
|
||||||
|
// force depth to always pass so we're just comparing stencil test
|
||||||
|
await greenMaterialInstance.setDepthFunc(SamplerCompareFunction.A);
|
||||||
|
await blueMaterialInstance.setDepthFunc(SamplerCompareFunction.A);
|
||||||
|
|
||||||
|
await testHelper.capture(
|
||||||
|
viewer.view, "material_instance_depth_pass_stencil_disabled");
|
||||||
|
|
||||||
|
assert(await greenMaterialInstance.isStencilWriteEnabled() == false);
|
||||||
|
assert(await blueMaterialInstance.isStencilWriteEnabled() == false);
|
||||||
|
|
||||||
|
await greenMaterialInstance.setStencilWriteEnabled(true);
|
||||||
|
await blueMaterialInstance.setStencilWriteEnabled(true);
|
||||||
|
|
||||||
|
assert(await greenMaterialInstance.isStencilWriteEnabled() == true);
|
||||||
|
assert(await blueMaterialInstance.isStencilWriteEnabled() == true);
|
||||||
|
|
||||||
|
await viewer.view.setStencilBufferEnabled(true);
|
||||||
|
assert(await viewer.view.isStencilBufferEnabled(), true);
|
||||||
|
|
||||||
|
// just a sanity check, output should be the same as above
|
||||||
|
await testHelper.capture(
|
||||||
|
viewer.view, "material_instance_depth_pass_stencil_enabled");
|
||||||
|
}, postProcessing: true, bg: null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('set stencil compare function to never/always/lt/gt)', () async {
|
||||||
|
await testHelper.withViewer((viewer) async {
|
||||||
|
final (
|
||||||
|
:blueCube,
|
||||||
|
:blueMaterialInstance,
|
||||||
|
:greenCube,
|
||||||
|
:greenMaterialInstance
|
||||||
|
) = await setup(viewer);
|
||||||
|
|
||||||
|
await viewer.view.setStencilBufferEnabled(true);
|
||||||
|
|
||||||
|
// ensure the blue cube renders before the green cube
|
||||||
|
await viewer.setPriority(greenCube.entity, 7);
|
||||||
|
await viewer.setPriority(blueCube.entity, 0);
|
||||||
|
|
||||||
|
for (final mi in [greenMaterialInstance, blueMaterialInstance]) {
|
||||||
|
await mi.setStencilWriteEnabled(true);
|
||||||
|
await mi.setDepthCullingEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set stencil compare function to NEVER
|
||||||
|
for (final mi in [greenMaterialInstance, blueMaterialInstance]) {
|
||||||
|
await mi.setStencilCompareFunction(
|
||||||
|
SamplerCompareFunction.N, StencilFace.FRONT_AND_BACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// should be totally empty
|
||||||
|
await testHelper.capture(viewer.view, "stencil_never");
|
||||||
|
|
||||||
|
// set stencil compare function to ALWAYS
|
||||||
|
for (final mi in [greenMaterialInstance, blueMaterialInstance]) {
|
||||||
|
await mi.setStencilCompareFunction(
|
||||||
|
SamplerCompareFunction.A, StencilFace.FRONT_AND_BACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// should show green cube in front of blue cube
|
||||||
|
await testHelper.capture(viewer.view, "stencil_always");
|
||||||
|
|
||||||
|
// set the blue cube to always pass the stencil test
|
||||||
|
await blueMaterialInstance.setStencilCompareFunction(
|
||||||
|
SamplerCompareFunction.A, StencilFace.FRONT_AND_BACK);
|
||||||
|
// when blue cube passes depth + stencil, replace the default stencil value (0) with 1
|
||||||
|
await blueMaterialInstance.setStencilOpDepthStencilPass(StencilOperation.REPLACE);
|
||||||
|
await blueMaterialInstance.setStencilReferenceValue(1);
|
||||||
|
|
||||||
|
// set the green cube to only pass the stencil test where stencil value is
|
||||||
|
// not equal to 0
|
||||||
|
await greenMaterialInstance.setStencilCompareFunction(
|
||||||
|
SamplerCompareFunction.NE, StencilFace.FRONT_AND_BACK);
|
||||||
|
await greenMaterialInstance.setStencilReferenceValue(0);
|
||||||
|
|
||||||
|
// green cube will only be rendered where it overlaps with blue cube
|
||||||
|
await testHelper.capture(viewer.view, "stencil_ne");
|
||||||
|
|
||||||
|
// set the green cube to only pass the stencil test where stencil value is
|
||||||
|
// equal to 0
|
||||||
|
await greenMaterialInstance.setStencilCompareFunction(
|
||||||
|
SamplerCompareFunction.E, StencilFace.FRONT_AND_BACK);
|
||||||
|
|
||||||
|
// green cube renders where it does not overlap with blue cube (same as if
|
||||||
|
// we had disabled depth writes and rendered the green cube, then the blue
|
||||||
|
// cube)
|
||||||
|
await testHelper.capture(viewer.view, "stencil_eq");
|
||||||
|
|
||||||
|
},
|
||||||
|
bg: null,
|
||||||
|
postProcessing: true,
|
||||||
|
createStencilBuffer: true,
|
||||||
|
createRenderTarget: false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// test('fail stencil not equal', () async {
|
||||||
|
// await testHelper.withViewer((viewer) async {
|
||||||
|
// final (
|
||||||
|
// :blueCube,
|
||||||
|
// :blueMaterialInstance,
|
||||||
|
// :greenCube,
|
||||||
|
// :greenMaterialInstance
|
||||||
|
// ) = await setup(viewer);
|
||||||
|
|
||||||
|
// // this ensures the blue cube is rendered before the green cube
|
||||||
|
// await viewer.setPriority(blueCube.entity, 0);
|
||||||
|
// await viewer.setPriority(greenCube.entity, 1);
|
||||||
|
|
||||||
|
// await blueMaterialInstance.setStencilWriteEnabled(true);
|
||||||
|
// await blueMaterialInstance.setStencilReferenceValue(1);
|
||||||
|
// await blueMaterialInstance
|
||||||
|
// .setStencilCompareFunction(SamplerCompareFunction.A);
|
||||||
|
// await blueMaterialInstance
|
||||||
|
// .setStencilOpDepthStencilPass(StencilOperation.REPLACE);
|
||||||
|
|
||||||
|
// await greenMaterialInstance.setStencilReferenceValue(1);
|
||||||
|
// await greenMaterialInstance
|
||||||
|
// .setStencilCompareFunction(SamplerCompareFunction.E);
|
||||||
|
|
||||||
|
// // green cube is only rendered where it intersects with the blue cube
|
||||||
|
// await testHelper.capture(viewer.view, "fail_stencil_ne");
|
||||||
|
// }, postProcessing: true);
|
||||||
|
// });
|
||||||
|
}
|
||||||
@@ -18,8 +18,8 @@ Future<
|
|||||||
await blueMaterialInstance.setParameterFloat4(
|
await blueMaterialInstance.setParameterFloat4(
|
||||||
"baseColorFactor", 0.0, 0.0, 1.0, 1.0);
|
"baseColorFactor", 0.0, 0.0, 1.0, 1.0);
|
||||||
|
|
||||||
// Position blue cube slightly behind and to the right
|
// Position blue cube slightly behind/below/right
|
||||||
await blueCube.setTransform(Matrix4.translation(Vector3(1.0, 0.0, -1.0)));
|
await blueCube.setTransform(Matrix4.translation(Vector3(1.0, -1.0, -1.0)));
|
||||||
|
|
||||||
var greenMaterialInstance =
|
var greenMaterialInstance =
|
||||||
await FilamentApp.instance!.createUnlitMaterialInstance();
|
await FilamentApp.instance!.createUnlitMaterialInstance();
|
||||||
@@ -36,7 +36,6 @@ Future<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
final testHelper = TestHelper("material");
|
final testHelper = TestHelper("material");
|
||||||
|
|
||||||
@@ -213,114 +212,31 @@ void main() async {
|
|||||||
await viewer.dispose();
|
await viewer.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('disable depth write', () async {
|
test('disable depth write', () async {
|
||||||
await testHelper.withViewer((viewer) async {
|
await testHelper.withViewer((viewer) async {
|
||||||
final (
|
final (
|
||||||
:blueCube,
|
:blueCube,
|
||||||
:blueMaterialInstance,
|
:blueMaterialInstance,
|
||||||
:greenCube,
|
:greenCube,
|
||||||
:greenMaterialInstance
|
:greenMaterialInstance
|
||||||
) = await setup(viewer);
|
) = await setup(viewer);
|
||||||
|
|
||||||
// With depth write enabled on both materials, green cube renders behind the blue cube
|
// With depth write enabled on both materials, green cube renders behind the blue cube
|
||||||
await testHelper.capture(
|
await testHelper.capture(
|
||||||
viewer.view, "material_instance_depth_write_enabled");
|
viewer.view, "material_instance_depth_write_enabled");
|
||||||
|
|
||||||
// Disable depth write on green cube, blue cube will always appear in front (green cube renders behind everything, including the image material, so not it's not visible at all)
|
// Disable depth write on green cube
|
||||||
await greenMaterialInstance.setDepthWriteEnabled(false);
|
// Blue cube will always appear in front
|
||||||
await testHelper.capture(
|
await greenMaterialInstance.setDepthWriteEnabled(false);
|
||||||
viewer.view, "material_instance_depth_write_disabled");
|
await testHelper.capture(
|
||||||
|
viewer.view, "material_instance_depth_write_disabled");
|
||||||
|
|
||||||
// Set priority for greenCube to render last, making it appear in front
|
// Set priority for greenCube to render last, making it appear in front
|
||||||
await viewer.setPriority(greenCube.entity, 7);
|
await viewer.setPriority(greenCube.entity, 7);
|
||||||
await testHelper.capture(viewer.view,
|
await testHelper.capture(
|
||||||
"material_instance_depth_write_disabled_with_priority");
|
viewer.view, "material_instance_depth_write_disabled_with_priority");
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('enable stencil write', () async {
|
|
||||||
await testHelper.withViewer((viewer) async {
|
|
||||||
final (
|
|
||||||
:blueCube,
|
|
||||||
:blueMaterialInstance,
|
|
||||||
:greenCube,
|
|
||||||
:greenMaterialInstance
|
|
||||||
) = await setup(viewer);
|
|
||||||
|
|
||||||
// force depth to always pass so we're just comparing stencil test
|
|
||||||
await greenMaterialInstance.setDepthFunc(SamplerCompareFunction.A);
|
|
||||||
await blueMaterialInstance.setDepthFunc(SamplerCompareFunction.A);
|
|
||||||
|
|
||||||
await testHelper.capture(
|
|
||||||
viewer.view, "material_instance_depth_pass_stencil_disabled");
|
|
||||||
|
|
||||||
assert(await greenMaterialInstance.isStencilWriteEnabled() == false);
|
|
||||||
assert(await blueMaterialInstance.isStencilWriteEnabled() == false);
|
|
||||||
|
|
||||||
await greenMaterialInstance.setStencilWriteEnabled(true);
|
|
||||||
await blueMaterialInstance.setStencilWriteEnabled(true);
|
|
||||||
|
|
||||||
assert(await greenMaterialInstance.isStencilWriteEnabled() == true);
|
|
||||||
assert(await blueMaterialInstance.isStencilWriteEnabled() == true);
|
|
||||||
|
|
||||||
// just a sanity check, no difference from the last
|
|
||||||
await testHelper.capture(
|
|
||||||
viewer.view, "material_instance_depth_pass_stencil_enabled");
|
|
||||||
}, postProcessing: true, bg: null);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('stencil always fail', () async {
|
|
||||||
await testHelper.withViewer((viewer) async {
|
|
||||||
final (
|
|
||||||
:blueCube,
|
|
||||||
:blueMaterialInstance,
|
|
||||||
:greenCube,
|
|
||||||
:greenMaterialInstance
|
|
||||||
) = await setup(viewer);
|
|
||||||
|
|
||||||
// force depth to always pass so we're just comparing stencil test
|
|
||||||
await greenMaterialInstance.setDepthFunc(SamplerCompareFunction.A);
|
|
||||||
await blueMaterialInstance.setDepthFunc(SamplerCompareFunction.A);
|
|
||||||
|
|
||||||
await greenMaterialInstance.setStencilWriteEnabled(true);
|
|
||||||
|
|
||||||
assert(await greenMaterialInstance.isStencilWriteEnabled() == true);
|
|
||||||
|
|
||||||
await greenMaterialInstance
|
|
||||||
.setStencilCompareFunction(SamplerCompareFunction.N);
|
|
||||||
|
|
||||||
// green cube isn't rendered
|
|
||||||
await testHelper.capture(
|
|
||||||
viewer.view, "material_instance_stencil_always_fail");
|
|
||||||
}, postProcessing: true, bg: null);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('fail stencil not equal', () async {
|
|
||||||
await testHelper.withViewer((viewer) async {
|
|
||||||
final (
|
|
||||||
:blueCube,
|
|
||||||
:blueMaterialInstance,
|
|
||||||
:greenCube,
|
|
||||||
:greenMaterialInstance
|
|
||||||
) = await setup(viewer);
|
|
||||||
|
|
||||||
// this ensures the blue cube is rendered before the green cube
|
|
||||||
await viewer.setPriority(blueCube.entity, 0);
|
|
||||||
await viewer.setPriority(greenCube.entity, 1);
|
|
||||||
|
|
||||||
await blueMaterialInstance.setStencilWriteEnabled(true);
|
|
||||||
await blueMaterialInstance.setStencilReferenceValue(1);
|
|
||||||
await blueMaterialInstance
|
|
||||||
.setStencilCompareFunction(SamplerCompareFunction.A);
|
|
||||||
await blueMaterialInstance
|
|
||||||
.setStencilOpDepthStencilPass(StencilOperation.REPLACE);
|
|
||||||
|
|
||||||
await greenMaterialInstance.setStencilReferenceValue(1);
|
|
||||||
await greenMaterialInstance
|
|
||||||
.setStencilCompareFunction(SamplerCompareFunction.E);
|
|
||||||
|
|
||||||
// green cube is only rendered where it intersects with the blue cube
|
|
||||||
await testHelper.capture(viewer.view, "fail_stencil_ne");
|
|
||||||
}, postProcessing: true);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user