Ошибка загрузки> module.exports = require ("three / examples / jsm / loaders / GLTFLoader") в Nextjs - PullRequest
0 голосов
/ 25 января 2020

Я использую react-three-fiber, three и nextjs для отображения некоторых птиц, что является распространенным примером в threejs! Вот мой индексный файл nextjs приложения:

import React, { useRef, useState, useEffect } from 'react';
import * as THREE from 'three';
import { Canvas, useFrame, useLoader } from 'react-three-fiber';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

function Box(props) {
  // This reference will give us direct access to the mesh
  const mesh = useRef();

  // Set up state for the hovered and active state
  const [hovered, setHover] = useState(false);
  const [active, setActive] = useState(false);

  // Rotate mesh every frame, this is outside of React without overhead
  // eslint-disable-next-line no-return-assign,no-multi-assign
  useFrame(() => (mesh.current.rotation.x = mesh.current.rotation.y += 0.01));

  return (
    <mesh
      {...props}
      ref={mesh}
      scale={active ? [1.5, 1.5, 1.5] : [1, 1, 1]}
      onClick={e => setActive(!active)}
      onPointerOver={e => setHover(true)}
      onPointerOut={e => setHover(false)}
    >
      <boxBufferGeometry attach="geometry" args={[1, 1, 1]} />
      <meshStandardMaterial
        attach="material"
        color={hovered ? 'hotpink' : 'orange'}
      />
    </mesh>
  );
}

// This component was auto-generated from GLTF by: https://github.com/react-spring/gltfjsx
function Bird({ speed, factor, url, ...props }) {
  const gltf = useLoader(GLTFLoader, url);
  const group = useRef();
  const [mixer] = useState(() => new THREE.AnimationMixer());
  useEffect(
    () => void mixer.clipAction(gltf.animations[0], group.current).play(),
    [gltf.animations, mixer],
  );
  useFrame((state, delta) => {
    group.current.rotation.y +=
      Math.sin((delta * factor) / 2) * Math.cos((delta * factor) / 2) * 1.5;
    mixer.update(delta * speed);
  });
  return (
    <group ref={group}>
      <scene name="Scene" {...props}>
        <mesh
          name="Object_0"
          morphTargetDictionary={gltf.__$[1].morphTargetDictionary}
          morphTargetInfluences={gltf.__$[1].morphTargetInfluences}
          rotation={[1.5707964611537577, 0, 0]}
        >
          <bufferGeometry attach="geometry" {...gltf.__$[1].geometry} />
          <meshStandardMaterial
            attach="material"
            {...gltf.__$[1].material}
            name="Material_0_COLOR_0"
          />
        </mesh>
      </scene>
    </group>
  );
}

function Birds() {
  return new Array(2).fill().map((_, i) => {
    const x = (15 + Math.random() * 30) * (Math.round(Math.random()) ? -1 : 1);
    const y = -10 + Math.random() * 20;
    const z = -5 + Math.random() * 10;
    const bird = ['stork', 'parrot', 'flamingo'][Math.round(Math.random() * 2)];
    const speed = bird === 'stork' ? 0.5 : bird === 'flamingo' ? 2 : 5;
    const factor =
      bird === 'stork'
        ? 0.5 + Math.random()
        : bird === 'flamingo'
        ? 0.25 + Math.random()
        : 1 + Math.random() - 0.5;
    return (
      <Bird
        key={i}
        position={[x, y, z]}
        rotation={[0, x > 0 ? Math.PI : 0, 0]}
        speed={speed}
        factor={factor}
        url={`/static/glb/${bird}.glb`}
      />
    );
  });
}

const MyComponent = props => {
  return (
    <Canvas>
      <ambientLight />
      <pointLight position={[10, 0, 10]} />
      <Box position={[-1.2, 2, 0]} />
      <Box position={[1.2, 0, 0]} />
      <Box position={[3, -2, 0]} />
      <Birds />
    </Canvas>
  );
};

export default MyComponent;

Мои файлы находятся в папке static/glb/...! Проблема с загрузчиком GLTFLoader . Я пытаюсь продлить метод "react-three-fiber", но не помогает!

Я думаю, может быть, это из-за SSR . Вы так думаете?

1 Ответ

1 голос
/ 14 апреля 2020

Ну, я опоздал примерно на 3 месяца, но я надеюсь, что это разрешит любые сомнения в случае, если кто-нибудь найдет этот вопрос.

Прежде всего вам нужно будет импортировать рендер GLB, ваше приложение не ' В настоящее время я не знаю, какой файл GLB вы пытаетесь визуализировать. Что-то вроде этого должно сделать:

import MyCustomRender from 'src/static/glb/an_awesome_bird.glb'

Затем, каждый раз, когда вы создаете экземпляр компонента птицы, вы сможете передать его как опору, как в

<Bird
    key={i}
    position={[x, y, z]}
    rotation={[0, x > 0 ? Math.PI : 0, 0]}
    speed={speed}
    factor={factor}
    url={MyCustomRender}
/>

Теперь, так как вы используете Next JS, это означает, что вы в настоящее время используете WebPack для комплектации своего приложения.

Дело в том, что WebPack с самого начала не знает, что такое glb или GLTF файл, вы должны сообщить этому маленькому модулю, как вести себя при импорте файла с указанным расширением.

Вы можете сделать это, обновив файл next.config.js следующим образом:

module.exports = withCSS(withSass({
  webpack (config, options) {
    config.module.rules.push({
      test: /\.(glb|gltf)$/,
      use: {
        loader: 'file-loader',
      }
    })
    return config
  }
}))

По сути, это означает, что вы говорите Webpack: «Эй, если вы видите, что я импортирую какие-либо файлы .gltf или .glb, это означает, что я хочу их путь, поэтому дайте мне их URL».

В случае, если вы не Если у вас установлен загрузчик файлов для Webpack, вы всегда можете сделать

npm install file-loader --save-dev

Несколько дней go Я сделал репо, используя точно такой же стек:

https://github.com/franco-roura/react-game

(за исключением того, что я не использовал Next JS, поэтому мой next.config.js на самом деле webpack.config.js)

Надеюсь, это поможет вам устранить любые сомнения!

...