React 中的 Webpack 无法加载带有 GLTF 扩展的 3D 模型,显示 404 not found
Webpack in React can't load the 3D model with a GLTF extension, shows 404 not found
我正在尝试在 React with Typescript 中加载扩展名为 .gltf 的 3D 模型。 3D 模型文件夹中的文件为.gltf、.png 和.bin 文件。用于此任务的工具是 webpack 和 drei 库中的 useGLTFLoader。我尝试过不同的工具。主要来自 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 文件位于项目的根目录中。资产文件夹位于 src 文件夹中。最后,包含 React 代码的文件位于 src/components/ThreeDimensionComponent/ThreeDimensionComponent.tsx(因此它的路径是正确的)。
您要么需要导入模型并使用从中获得的 url (url-loader),要么将其放入 public 文件夹中。您的路径在捆绑输出中无处指向。
还有一点,就是@react-three/drei 和 useGLTF(url).
这是一个加载了 3D 模型的工作示例,以备不时之需。我将 hpalu 的答案标记为正确,因为它帮助我解决了这个问题。
我需要将 Suspense 与不是 HTML 元素但来自 react-three-fiber.
的组件一起使用
也帮我解决了bug的post:
这是 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' }]
})
]
};
我正在尝试在 React with Typescript 中加载扩展名为 .gltf 的 3D 模型。 3D 模型文件夹中的文件为.gltf、.png 和.bin 文件。用于此任务的工具是 webpack 和 drei 库中的 useGLTFLoader。我尝试过不同的工具。主要来自 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 文件位于项目的根目录中。资产文件夹位于 src 文件夹中。最后,包含 React 代码的文件位于 src/components/ThreeDimensionComponent/ThreeDimensionComponent.tsx(因此它的路径是正确的)。
您要么需要导入模型并使用从中获得的 url (url-loader),要么将其放入 public 文件夹中。您的路径在捆绑输出中无处指向。
还有一点,就是@react-three/drei 和 useGLTF(url).
这是一个加载了 3D 模型的工作示例,以备不时之需。我将 hpalu 的答案标记为正确,因为它帮助我解决了这个问题。
我需要将 Suspense 与不是 HTML 元素但来自 react-three-fiber.
的组件一起使用也帮我解决了bug的post:
这是 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' }]
})
]
};