Webpack в React не может загрузить 3D-модель с расширением GLTF, показывает 404 не найдено

#reactjs #webpack #three.js #react-three-fiber

#reactjs #webpack #three.js #react-трехволоконный

Вопрос:

Я пытаюсь загрузить 3D-модель с расширением .gltf в React с помощью Typescript. Файлы в папке с 3D-моделью — это файлы .gltf, .png и .bin. Инструментами, используемыми для этой задачи, являются webpack и useGLTFLoader из библиотеки drei. Я пробовал разные инструменты. В основном из three.js библиотека без какого-либо эффекта. Ошибка показывает, что 3D-модель не найдена 404 (показано ниже) и ничего не отображается на месте, где должна быть размещена 3D-модель.

 GET http://localhost:3000/assets/models/Duck/glTF/Duck.gltf 404 (Not Found)
  

Мой компонент для рендеринга 3D-модели показан ниже:

 import React, { Suspense } from 'react';
import { Canvas } from 'react-three-fiber';
import { useGLTFLoader } from 'drei';

const DuckModel = () => {
 const gltf = useGLTFLoader('../../assets/models/Duck/glTF/Duck.gltf', true);
 return <primitive object={gltf.scene} dispose={null} />;
};

export const ThreeDimensionComponent = () => {
 return (
  <>
   <Canvas camera={{ position: [0, 0, 10], fov: 70 }}>
    <Suspense fallback={null}>
     <mesh position={[0, 250, 0]}>
      <DuckModel />
     </mesh>
    </Suspense>
   </Canvas>
  </>
 );
};
  

И ниже я делюсь своей конфигурацией webpack.

 const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

const root = __dirname;

const gsapPath = '/node_modules/gsap/src/uncompressed/';

module.exports = {
 devtool: 'source-map',
 mode: 'development',
 entry: path.join(__dirname, 'src', 'index.tsx'),
 watch: true,
 output: {
  filename: '[name].js',
  path: path.resolve(__dirname, 'dist'),
  sourceMapFilename: '[name].js.map'
 },
 module: {
  rules: [
   {
    test: /.(tsx|ts)$/,
    use: ['babel-loader', 'ts-loader', 'tslint-loader']
   },
   {
    test: /.scss$/,
    use: [
     'style-loader',
     {
      loader: 'css-loader',
      options: {
       sourceMap: true
      }
     },
     {
      loader: 'postcss-loader',
      options: {
       plugins: [require('autoprefixer')()],
       sourceMap: true
      }
     },
     {
      loader: 'sass-loader',
      options: {
       sourceMap: true
      }
     }
    ]
   },
   {
    test: /.(png|jp(e*)g|svg|gif)$/,
    use: [
     {
      loader: 'url-loader',
      options: {
       limit: 8000,
       sourceMap: true
      }
     }
    ]
   },
   {
    test: /.(ttf|eot|woff|woff2)$/,
    use: {
     loader: 'file-loader',
     options: {
      name: 'fonts/[name].[ext]',
      sourceMap: true
     }
    }
   },
   {
    test: /.(glb|gltf)$/,
    use: [
     {
      loader: 'file-loader'
      // options: {
      //  outputPath: 'assets/models'
      // }
     }
    ]
   },
   {
    test: /.(bin)$/,
    use: [
     {
      loader: 'file-loader'
     }
    ]
   }
  ]
 },
 resolve: {
  extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  modules: ['node_modules', path.resolve(__dirname, 'src')],
  alias: {
   TweenLite: 'gsap',
   CSSPlugin: 'gsap',
   Draggable: path.join(root, gsapPath   'utils/Draggable.js'),
   ScrollToPlugin: path.join(root, gsapPath   'plugins/ScrollToPlugin.js')
  }
 },
 devServer: {
  historyApiFallback: true,
  contentBase: './dist',
  inline: true,
  host: 'localhost',
  port: 3000
 },
 plugins: [
  new CleanWebpackPlugin({ verbose: true }),
  new HtmlWebpackPlugin({
   template: path.join(__dirname, 'src', 'index.html')
  }),
  new webpack.ProvidePlugin({
   TweenMax: 'gsap'
  }),
  new CopyWebpackPlugin({
   patterns: [{ from: 'src/assets' }]
  })
 ]
};
  

Мой webpack.config.js файл находится в корневом каталоге проекта. Папка assets находится в папке src. Наконец, файл с кодом реакции находится в src/components/ThreeDimensionComponent/ThreeDimensionComponent.tsx (поэтому путь к нему правильный).

Ответ №1:

Вам нужно либо импортировать модель и использовать URL-адрес, который вы получаете от этого (url-loader), либо поместить его в общую папку. Ваш путь нигде не указывает на связанный вывод.

Еще одна вещь, это @react-three/drei и useGLTF(url).

Комментарии:

1. Я добавил output.publicPath: ‘/’ и добавил options.OutputPath: ‘assets / models’ в оба загрузчика файлов для расширений .gltf и .bin. Модель отображается как [отправленная] в терминале: models / Duck / glTF / Duck.gltf 4,85 КБ [отправлено], но 3D-модель по-прежнему не отображается. Когда я проверил вкладку DevTools sources, там появилась только папка ресурсов «изображения». При необходимости я могу добавить больше кода / информации.

2. Я также изменил на @react-three /drei и использовал glTF(url), как вы советовали.

3. Мне удалось заставить его работать. Опубликованный рабочий пример ниже. Я отметил ваш ответ как правильный, потому что он помог мне решить проблему. Спасибо за помощь.

Ответ №2:

Вот рабочий пример с загруженной 3D-моделью на случай, если она кому-то понадобится. Я отметил ответ от hpalu как правильный, потому что он помог мне решить эту проблему.

Мне нужно было использовать Suspense с резервным вариантом, который не является элементом HTML, а вместо этого является компонентом из react-three-fiber.

Сообщение, которое также помогло мне устранить ошибку:

Вот компонент React:

 import { useGLTF } from '@react-three/drei';
import React, { Suspense } from 'react';
import { Canvas } from 'react-three-fiber';

const DuckModel = () => {
 const gltf = useGLTF('./models/Duck/glTF/Duck.gltf', true);
 return <primitive object={gltf.scene} dispose={null} />;
};

export const ThreeDimensionComponent = () => {
 return (
  <>
   <Canvas camera={{ position: [0, 0, 3], fov: 80 }}>
    <ambientLight intensity={0.3} />
    <Suspense
     fallback={
      <mesh>
       <boxBufferGeometry args={[1, 1, 1]} />
       <meshStandardMaterial />
      </mesh>
     }
    >
     <DuckModel />
    </Suspense>
   </Canvas>
  </>
 );
};
  

И вот конфигурация webpack для этого примера:

 const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

const gsapPath = '/node_modules/gsap/src/uncompressed/';

module.exports = {
 devtool: 'source-map',
 mode: 'development',
 entry: path.join(__dirname, 'src', 'index.tsx'),
 watch: true,
 output: {
  filename: '[name].js',
  path: path.resolve(__dirname, 'dist'),
  sourceMapFilename: '[name].js.map',
  publicPath: '/'
 },
 module: {
  rules: [
   {
    test: /.(tsx|ts)$/,
    use: ['babel-loader', 'ts-loader', 'tslint-loader']
   },
   {
    test: /.scss$/,
    use: [
     'style-loader',
     {
      loader: 'css-loader',
      options: {
       sourceMap: true
      }
     },
     {
      loader: 'postcss-loader',
      options: {
       plugins: [require('autoprefixer')()],
       sourceMap: true
      }
     },
     {
      loader: 'sass-loader',
      options: {
       sourceMap: true
      }
     }
    ]
   },
   {
    test: /.(png|jp(e*)g|svg|gif)$/,
    use: [
     {
      loader: 'url-loader',
      options: {
       limit: 8000,
       sourceMap: true
      }
     }
    ]
   },
   {
    test: /.(ttf|eot|woff|woff2)$/,
    use: {
     loader: 'file-loader',
     options: {
      name: 'fonts/[name].[ext]'
      // sourceMap: true
     }
    }
   },
   {
    test: /.(glb|gltf)$/,
    use: [
     {
      loader: 'file-loader',
      options: {
       outputPath: 'assets/models',
       sourceMap: true
      }
     }
    ]
   },
   {
    test: /.(bin)$/,
    use: [
     {
      loader: 'file-loader',
      options: {
       outputPath: 'assets/models',
       sourceMap: true
      }
     }
    ]
   }
  ]
 },
 resolve: {
  extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  modules: ['node_modules', path.resolve(__dirname, 'src')],
  alias: {
   TweenLite: 'gsap',
   CSSPlugin: 'gsap',
   Draggable: path.join(__dirname, gsapPath   'utils/Draggable.js'),
   ScrollToPlugin: path.join(__dirname, gsapPath   'plugins/ScrollToPlugin.js')
  }
 },
 devServer: {
  historyApiFallback: true,
  contentBase: './dist',
  inline: true,
  host: 'localhost',
  port: 3000
 },
 plugins: [
  new CleanWebpackPlugin({ verbose: true }),
  new HtmlWebpackPlugin({
   template: path.join(__dirname, 'src', 'index.html')
  }),
  new webpack.ProvidePlugin({
   TweenMax: 'gsap'
  }),
  new CopyWebpackPlugin({
   patterns: [{ from: 'src/assets' }]
  })
 ]
};
  

Комментарии:

1. я получаю ./node_modules/three-stdlib/loaders/RGBELoader.js Attempted import error: 'DataUtils' is not exported from 'three'.