反应原生:r3f-native-orbitcontrols:android vs chrome vs firefox 并也用于多个画布?

问题描述 投票:0回答:1

我想渲染几个模型,每个模型都有自己的画布和轨道控件。我通过以下代码完成了这项工作,但我做了两个观察:

  1. 第一次点击模型不会启动旋转,查看 r3f 的源代码,它会尝试检测第一次触摸,并且只将之后的所有内容视为旋转控制。
  2. 当将手指放在我的android显示屏上(我通过expo运行)并离开当前画布时,目标相机位置会以某种方式重置到一个奇怪的位置,我可以通过console.logs在handleCameraChange函数中使其可见。在浏览器(firefox 或 chrome)中测试画布外部的旋转时,不会发生这种情况。 Android 上的这种行为是故意的吗?与 web 和 android 的 DOM 处理方式不同有关吗?

import React, { Suspense, useRef, useMemo, useContext, useCallback, useEffect, useState, lazy } from 'react';
import Chair from './src/components/chair';
import { SafeAreaView, StyleSheet, View } from 'react-native';
import { Canvas } from '@react-three/fiber/native';
import useControls from 'r3f-native-orbitcontrols';
import * as THREE from "three";
import Trigger from './src/components/Trigger';
import Loader from './src/components/Loader';
import { useVisibleStore } from './src/context/MyZustand';
import { Dimensions } from 'react-native';


const Game: React.FC = () => {
  const { width, height } = Dimensions.get('window');
  const isPortrait = height > width;
  const nCubes= useVisibleStore((state) => state.nCubes)
  const [loading, setLoading] = useState<boolean>(false);

  const controlsAndEvents = Array.from({ length: nCubes }, (_, index) => {
    const [OrbitControls, events] = useControls();
    return { OrbitControls, events, index };
  });

return (
      <SafeAreaView style={styles.container}>
        <View style={styles.modelsContainer}>
        {loading && <Loader />}
          <View style={isPortrait ? styles.columnContainer : styles.rowContainer}>
            {controlsAndEvents.map(({ OrbitControls, events, index }) => (
              <View key={index} style={isPortrait ? styles.modelColumn : styles.modelRow}{...events}>
                  <Canvas key={index}>
                    <OrbitControls
                      key={index} 
                      enabled={true}
                      enableZoom={false}
                      enablePan={false}
                      dampingFactor={0.5}
                      enableRotate={true}
                      rotateSpeed={0.5} 
                      // onChange={(event) => handleCameraChange(event, index, letters)} 
                      {...OrbitControls}
                    />
                    <directionalLight position={[1, -1, -1]} intensity={5} args={["yellow", 10]}  />
                    <directionalLight position={[-1, -1, -1]} intensity={7} args={["white", 10]}  />
                    <Suspense fallback={<Trigger setLoading={setLoading} />}>
                      <Chair />
                    </Suspense>
                  </Canvas>
              </View> 
             ))}
          </View>
         </View>
      </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'grey', // Add this line to set the background color to grey
  },
  modelsContainer: {
    flex: 0.9,
  },
   columnContainer: {
    // flexDirection: 'column',
    flex: 1,
  },
  rowContainer: {
    // flexDirection: 'row',
    flex: 1,
  },
  modelColumn: {
    flex: 1,
    justifyContent: 'center',
  },
  modelRow: {
    flex: 1,
    justifyContent: 'center',
  },
});

export default Game;

reactjs react-native orbitcontrols
1个回答
0
投票

当将手指放在我的android显示屏上(我通过expo运行)并离开当前画布时,目标相机位置会以某种方式重置到一个奇怪的位置,我可以通过console.logs在handleCameraChange函数中使其可见。在浏览器(firefox 或 chrome)中测试画布外部的旋转时,不会发生这种情况。 Android 上的这种行为是故意的吗?

我遇到了和你一样的问题,已经解决了。希望同样的方法对您也适用。

我使用公式计算两个位置之间的欧几里德距离。如果距离大于2,我认为位置更新不正确。

const cameraRef = useRef<Camera>();
const lastCameraPositionRef = useRef<Vector3>();

const handleOrbitPositionUpdate = (position?: Vector3) => {
  if (!position) return;

  const lastCameraPosition = lastCameraPositionRef.current;
  if (lastCameraPosition) {
    const { x, y, z } = position;
    const [x0, y0, z0] = lastCameraPosition;

    const camera = cameraRef.current;
    if (camera) {
      // if the distance exceeds 2, assume the new position is incorrect.
      const distance = Math.sqrt((x0 - x) ** 2 + (y0 - y) ** 2 + (z0 - z) ** 2);
      if (distance >= 2) {
        camera.position.set(x0, y0, z0);
        invalidate();
        return;
      }
    }

    if(lastCameraPositionRef.current) {
      lastCameraPositionRef.current = position;    
    }
  }
};


<OrbitControls
  onChange={event =>
    handleOrbitPositionUpdate(event.target.camera?.position)
  }
/>
© www.soinside.com 2019 - 2024. All rights reserved.