olexale / arkit_flutter_plugin

ARKit Flutter Plugin
MIT License
802 stars 227 forks source link

Rotation and Scaling not working on GLB file. #232

Open Michael-Lyon opened 3 months ago

Michael-Lyon commented 3 months ago

I'm unable to implement Rotation or Pinching and it doesn't show me error. I'm really grateful that you had put this project together it's been awesome. Thank you. I'd appreciate some help or guidance to make this work please.

Here's my code


import 'dart:io';

import 'package:arkit_plugin/arkit_plugin.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
import 'package:path_provider/path_provider.dart';
import 'package:vector_math/vector_math_64.dart' as vector;
import 'package:collection/collection.dart';
import 'dart:math' as math;

class ARGlbManipulationPage extends StatefulWidget {
  final String modelUrl;

  const ARGlbManipulationPage({Key? key, required this.modelUrl})
      : super(key: key);
  @override
  _ARGlbManipulationPageState createState() => _ARGlbManipulationPageState();
}

class _ARGlbManipulationPageState extends State<ARGlbManipulationPage> {
  late ARKitController arkitController;
  ARKitNode? modelNode;
  final Logger logger = Logger();
  @override
  void dispose() {
    arkitController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('Load and Manipulate GLB')),
        body: ARKitSceneView(
          showFeaturePoints: true,
          enableTapRecognizer: true,
          enablePinchRecognizer: true,
          enablePanRecognizer: true,
          enableRotationRecognizer: true,
          planeDetection: ARPlaneDetection.horizontal,
          onARKitViewCreated: onARKitViewCreated,
        ),
      );

  void onARKitViewCreated(ARKitController arkitController) {
    this.arkitController = arkitController;

    // Set up gesture handlers
    this.arkitController.onNodePinch = _onPinchHandler;
    this.arkitController.onNodePan = _onPanHandler;
    this.arkitController.onNodeRotation = _onRotationHandler;

    this.arkitController.onARTap = (ar) {
      final point = ar.firstWhereOrNull(
        (o) => o.type == ARKitHitTestResultType.featurePoint,
      );
      if (point != null) {
        _onARTapHandler(point);
      }
    };
  }

  void _onARTapHandler(ARKitTestResult point) {
    final position = vector.Vector3(
      point.worldTransform.getColumn(3).x,
      point.worldTransform.getColumn(3).y,
      point.worldTransform.getColumn(3).z,
    );

    _loadGLBModel(position);
  }

  Future<void> _loadGLBModel(vector.Vector3 position) async {
    final node = await _getNodeFromNetwork(position);
    arkitController.add(node);
    modelNode = node;
  }

  Future<ARKitGltfNode> _getNodeFromNetwork(vector.Vector3 position) async {
    // Assume this method downloads the GLB file and returns an ARKitGltfNode
    final file = await _downloadFile(widget.modelUrl); // Update with your URL
    if (file.existsSync()) {
      return ARKitGltfNode(
        assetType: AssetType.documents,
        url: file.path.split('/').last,
        scale: vector.Vector3(0.5, 0.5, 0.5),
        position: position,
      );
    }
    throw Exception('Failed to load $file');
  }

  Future<File> _downloadFile(String url) async {
    try {
      final dir = await getApplicationDocumentsDirectory();
      final filePath = '${dir.path}/${url.split("/").last}';
      await Dio().download(url, filePath);
      final file = File(filePath);
      print('Download completed!! path = $filePath');
      return file;
    } catch (e) {
      print('Caught an exception: $e');
      rethrow;
    }
  }

  void _onPinchHandler(List<ARKitNodePinchResult> pinchResults) {
    final pinch = pinchResults.firstWhereOrNull(
      (e) => e.nodeName == modelNode?.name,
    );
    if (pinch != null) {
      logger.d('Pinch detected: ${pinch.scale}'); // Debugging line
      final scale = vector.Vector3.all(pinch.scale);
      logger.d('Setting new scale: $scale'); // Debugging line
      modelNode?.scale = scale;
    } else {
      logger.d('Pinch not applied to the correct node.'); // Debugging line
    }
  }

  void _onPanHandler(List<ARKitNodePanResult> panResults) {
    final pan = panResults.firstWhereOrNull(
      (e) => e.nodeName == modelNode?.name,
    );
    if (pan != null) {
      final old = modelNode?.eulerAngles;
      final newAngleY = pan.translation.x * math.pi / 180;
      modelNode?.eulerAngles =
          vector.Vector3(old?.x ?? 0, newAngleY, old?.z ?? 0);
      logger.d('Pan detected: ${pan.translation}'); // Debugging line
      logger.d(
          'Setting new eulerAngles: ${modelNode?.eulerAngles}'); // Debugging line
    } else {
      logger.d("No pan found");
    }
  }

  void _onRotationHandler(List<ARKitNodeRotationResult> rotationResults) {
    final rotation = rotationResults.firstWhereOrNull(
      (e) => e.nodeName == modelNode?.name,
    );
    if (rotation != null) {
      final eulerAngles = modelNode?.eulerAngles ??
          vector.Vector3.zero() + vector.Vector3.all(rotation.rotation);
      modelNode?.eulerAngles = eulerAngles;
      logger.d('Rotation detected: ${rotation.rotation}'); // Debugging line
      logger.d(
          'Setting new eulerAngles: ${modelNode?.eulerAngles}'); // Debugging line
    } else {
      logger.d("No rotation found");
    }
  }
}
``` @OleksiiShvachenko @mribbons @leeprobert @dokkaebi 
lecanhhiep commented 1 week ago

There is actually a bug in GTLF code, I have issue with onNodeTap event . Have you resolved your above issue ?