add setCameraCulling method to set near/far culling plane and return vector_math:Frustum from planes returned by get_camera_frustum

This commit is contained in:
Nick Fisher
2023-11-09 15:08:34 +08:00
parent 76f723c497
commit f2a458b9ca
11 changed files with 227 additions and 104 deletions

View File

@@ -6,8 +6,12 @@ import 'package:flutter_filament/filament_controller.dart';
class CameraMatrixOverlay extends StatefulWidget {
final FilamentController controller;
final bool showProjectionMatrices;
const CameraMatrixOverlay({super.key, required this.controller});
const CameraMatrixOverlay(
{super.key,
required this.controller,
required this.showProjectionMatrices});
@override
State<StatefulWidget> createState() => _CameraMatrixOverlayState();
@@ -18,21 +22,36 @@ class _CameraMatrixOverlayState extends State<CameraMatrixOverlay> {
String? _cameraPosition;
String? _cameraRotation;
String? _cameraProjectionMatrix;
String? _cameraCullingProjectionMatrix;
void _tick(Timer timer) async {
var cameraPosition = await widget.controller.getCameraPosition();
var cameraRotation = await widget.controller.getCameraRotation();
_cameraPosition =
"${cameraPosition.storage.map((v) => v.toStringAsFixed(2))}";
_cameraRotation =
"${cameraRotation.storage.map((v) => v.toStringAsFixed(2))}";
if (widget.showProjectionMatrices) {
var projMatrix = await widget.controller.getCameraProjectionMatrix();
var cullingMatrix =
await widget.controller.getCameraCullingProjectionMatrix();
_cameraProjectionMatrix =
projMatrix.storage.map((v) => v.toStringAsFixed(2)).join(",");
_cameraCullingProjectionMatrix =
cullingMatrix.storage.map((v) => v.toStringAsFixed(2)).join(",");
}
setState(() {});
}
void _updateTimer() {
_cameraTimer?.cancel();
if (widget.controller.hasViewer.value) {
_cameraTimer =
Timer.periodic(const Duration(milliseconds: 50), (timer) async {
var cameraPosition = await widget.controller.getCameraPosition();
var cameraRotation = await widget.controller.getCameraRotation();
_cameraPosition =
"${cameraPosition.storage.map((v) => v.toStringAsFixed(2))}";
_cameraRotation =
"${cameraRotation.storage.map((v) => v.toStringAsFixed(2))}";
setState(() {});
});
_cameraTimer = Timer.periodic(const Duration(milliseconds: 50), _tick);
}
}
@@ -45,6 +64,12 @@ class _CameraMatrixOverlayState extends State<CameraMatrixOverlay> {
widget.controller.hasViewer.addListener(_updateTimer);
}
@override
void didUpdateWidget(CameraMatrixOverlay oldWidget) {
super.didUpdateWidget(oldWidget);
setState(() {});
}
@override
void dispose() {
super.dispose();
@@ -59,7 +84,20 @@ class _CameraMatrixOverlayState extends State<CameraMatrixOverlay> {
color: Colors.black.withOpacity(0.5),
borderRadius: BorderRadius.circular(29)),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Text("Camera position : $_cameraPosition $_cameraRotation",
style: const TextStyle(color: Colors.white, fontSize: 12)));
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text("Camera position : $_cameraPosition $_cameraRotation",
style: const TextStyle(color: Colors.white, fontSize: 12)),
widget.showProjectionMatrices
? Text("Projection matrix : $_cameraProjectionMatrix",
style: const TextStyle(color: Colors.white, fontSize: 12))
: Container(),
widget.showProjectionMatrices
? Text("Culling matrix : $_cameraCullingProjectionMatrix",
style: const TextStyle(color: Colors.white, fontSize: 12))
: Container(),
]));
}
}

View File

@@ -76,6 +76,7 @@ class ExampleWidgetState extends State<ExampleWidget> {
static FilamentEntity? directionalLight;
static bool loop = false;
static final showProjectionMatrices = ValueNotifier<bool>(false);
late StreamSubscription _listener;
@@ -158,7 +159,11 @@ class ExampleWidgetState extends State<ExampleWidget> {
? Container()
: Padding(
padding: const EdgeInsets.only(top: 40, left: 20, right: 20),
child: CameraMatrixOverlay(controller: _filamentController!),
child: ValueListenableBuilder(
valueListenable: showProjectionMatrices,
builder: (ctx, value, child) => CameraMatrixOverlay(
controller: _filamentController!,
showProjectionMatrices: value)),
),
_filamentController == null
? Container()

View File

@@ -15,8 +15,66 @@ class CameraSubmenu extends StatefulWidget {
}
class _CameraSubmenuState extends State<CameraSubmenu> {
double _near = 0.05;
double _far = 1000.0;
final _menuController = MenuController();
List<Widget> _cameraMenu() {
return [
MenuItemButton(
closeOnActivate: false,
onPressed: () async {
ExampleWidgetState.showProjectionMatrices.value =
!ExampleWidgetState.showProjectionMatrices.value;
print("Set to ${ExampleWidgetState.showProjectionMatrices}");
},
child: Text(
'${ExampleWidgetState.showProjectionMatrices.value ? "Hide" : "Display"} camera projection/culling projection matrices',
style: TextStyle(
fontWeight: ExampleWidgetState.showProjectionMatrices.value
? FontWeight.bold
: FontWeight.normal),
),
),
SubmenuButton(
menuChildren: [1.0, 7.0, 14.0, 28.0, 56.0]
.map((v) => MenuItemButton(
onPressed: () {
widget.controller.setCameraFocalLength(v);
},
child: Text(
v.toStringAsFixed(2),
),
))
.toList(),
child: const Text("Set camera focal length")),
SubmenuButton(
menuChildren: [0.05, 0.1, 1.0, 10.0, 100.0]
.map((v) => MenuItemButton(
onPressed: () {
_near = v;
widget.controller.setCameraCulling(_near, _far);
},
child: Text(
v.toStringAsFixed(2),
),
))
.toList(),
child: const Text("Set near")),
SubmenuButton(
menuChildren: [5.0, 50.0, 500.0, 1000.0, 100000.0]
.map((v) => MenuItemButton(
onPressed: () {
_far = v;
widget.controller.setCameraCulling(_near, _far);
},
child: Text(
v.toStringAsFixed(2),
),
))
.toList(),
child: const Text("Set far")),
MenuItemButton(
onPressed: () async {
widget.controller.setCameraPosition(1.0, 1.0, -1.0);
@@ -80,7 +138,21 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
closeOnActivate: false,
onPressed: () async {
var frustum = await widget.controller.getCameraFrustum();
await showDialog(
var normalString = [
frustum.plane0,
frustum.plane1,
frustum.plane2,
frustum.plane3,
frustum.plane4,
frustum.plane5
]
.map((plane) =>
plane.normal.storage
.map((v) => v.toStringAsFixed(2))
.join(",") +
",${plane.constant}")
.join("\n");
showDialog(
context: context,
builder: (ctx) {
return Center(
@@ -88,8 +160,10 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
height: 300,
width: 300,
color: Colors.white,
child: Text(frustum.toString())));
child:
Text("Frustum plane normals : $normalString ")));
});
_menuController.close();
},
child: const Text("Get frustum")),
SubmenuButton(
@@ -164,6 +238,7 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
@override
Widget build(BuildContext context) {
return SubmenuButton(
controller: _menuController,
menuChildren: _cameraMenu(),
child: const Text("Camera"),
);