-
Notifications
You must be signed in to change notification settings - Fork 33
Open
Description
Hi @Knightro63
I’m running into a crash when using multiple ThreeJS views with OrbitControls (similar to the MultiViews example).
Platform:
-
Windows (issue occurs)
-
macOS (works fine)
Reproduction steps:
-
I have two ThreeJS widgets (MultiViews1 and MultiViews2), each with its own OrbitControls.
-
When I tap the red divider, I remove MultiViews2 from the widget tree.
-
In MultiViews2.dispose() I call threeJs.dispose().
Problem:
As soon as MultiViews2 is removed and disposed, I get the following error:
[ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: Null check operator used on a null value
#0 EGL.eglMakeCurrent (package:flutter_angle/desktop/lib_egl.dart:412:37)
lib_egl.dart:412
#1 FlutterAngle.activateTexture (package:flutter_angle/desktop/angle.dart:718:16)
angle.dart:718
#2 ThreeJS.render (package:three_js_core/others/three_viewer.dart:243:14)
three_viewer.dart:243
#3 ThreeJS.animate (package:three_js_core/others/three_viewer.dart:232:13)
three_viewer.dart:232
#4 Ticker._tick (package:flutter/src/scheduler/ticker.dart:269:12)
ticker.dart:269
#5 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1438:15)
binding.dart:1438
#6 SchedulerBinding.handleBeginFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:1269:11)
binding.dart:1269
#7 _LinkedHashMapMixin.forEach (dart:_compact_hash:764:13)
#8 SchedulerBinding.handleBeginFrame (package:flutter/src/scheduler/binding.dart:1267:17)
binding.dart:1267
#9 SchedulerBinding._handleBeginFrame (package:flutter/src/scheduler/binding.dart:1183:5)
binding.dart:1183
#10 _invoke1 (dart:ui/hooks.dart:347:13)
hooks.dart:347
#11 PlatformDispatcher._beginFrame (dart:ui/platform_dispatcher.dart:426:5)
platform_dispatcher.dart:426
#12 _beginFrame (dart:ui/hooks.dart:292:31)
After this crash, the OrbitControls of MultiViews1 also stop working.
Code Sample:
import 'dart:async';
import 'package:flutter/material.dart' hide Matrix4;
import 'package:three_js/three_js.dart' as three;
class MultiViews extends StatefulWidget {
const MultiViews({super.key});
@override
createState() => _MyAppState();
}
class _MyAppState extends State<MultiViews> {
List<three.FlutterAngleTexture> textures = [];
ScrollController controller = ScrollController();
bool displayDouble = true;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
const MultiViews1(),
GestureDetector(
onTap: () => setState(() => displayDouble = !displayDouble),
child: Container(height: 10, color: Colors.red)),
if (displayDouble) ...[
const MultiViews2()
]
],
);
;
}
}
class MultiViews1 extends StatefulWidget {
const MultiViews1({super.key});
@override
createState() => _MultiViews1State();
}
class _MultiViews1State extends State<MultiViews1> {
List<int> data = List.filled(60, 0, growable: true);
late three.OrbitControls control;
late three.ThreeJS threeJs;
@override
void initState() {
threeJs = three.ThreeJS(
onSetupComplete: () {
setState(() {});
},
setup: setup,
size: const Size(300, 300),
);
super.initState();
}
@override
void dispose() {
// timer.cancel();
threeJs.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return threeJs.build();
}
Future<void> setup() async {
threeJs.camera =
three.PerspectiveCamera(45, threeJs.width / threeJs.height, 1, 2200);
threeJs.camera.position.setValues(3, 6, 100);
// scene
threeJs.scene = three.Scene();
three.AmbientLight ambientLight = three.AmbientLight(0xffffff, 0.9);
threeJs.scene.add(ambientLight);
three.PointLight pointLight = three.PointLight(0xffffff, 0.8);
pointLight.position.setValues(0, 0, 0);
threeJs.camera.add(pointLight);
threeJs.scene.add(threeJs.camera);
threeJs.camera.lookAt(threeJs.scene.position);
three.BoxGeometry geometry = three.BoxGeometry(20, 20, 20);
three.MeshBasicMaterial material =
three.MeshBasicMaterial.fromMap({"color": 0xff0000});
final object = three.Mesh(geometry, material);
threeJs.scene.add(object);
control = three.OrbitControls(threeJs.camera, threeJs.globalKey);
control.target = object.position;
}
}
class MultiViews2 extends StatefulWidget {
const MultiViews2({super.key});
@override
createState() => _MultiViews2State();
}
class _MultiViews2State extends State<MultiViews2> {
List<int> data = List.filled(60, 0, growable: true);
late three.ThreeJS threeJs;
late three.OrbitControls control;
@override
void initState() {
threeJs = three.ThreeJS(
onSetupComplete: () {
setState(() {});
},
setup: setup,
size: const Size(300, 300),
renderNumber: 1);
super.initState();
}
@override
void dispose() {
threeJs.ticker?.stop();
threeJs.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return threeJs.build();
}
late three.Mesh mesh;
late three.Object3D object;
late three.Texture texture;
three.AnimationMixer? mixer;
Future<void> setup() async {
threeJs.camera =
three.PerspectiveCamera(45, threeJs.width / threeJs.height, 1, 2200);
threeJs.camera.position.setValues(3, 6, 100);
threeJs.scene = three.Scene();
threeJs.scene.background = three.Color(1, 1, 0);
three.AmbientLight ambientLight = three.AmbientLight(0xffffff, 0.9);
threeJs.scene.add(ambientLight);
three.PointLight pointLight = three.PointLight(0xffffff, 0.8);
pointLight.position.setValues(0, 0, 0);
threeJs.camera.add(pointLight);
threeJs.scene.add(threeJs.camera);
threeJs.camera.lookAt(threeJs.scene.position);
three.BoxGeometry geometry = three.BoxGeometry(10, 10, 20);
three.MeshBasicMaterial material = three.MeshBasicMaterial();
object = three.Mesh(geometry, material);
threeJs.scene.add(object);
control = three.OrbitControls(threeJs.camera, threeJs.globalKey);
control.target = object.position;
}
}
Metadata
Metadata
Assignees
Labels
No labels