在 three.js 中加载 .gltf 模型时计算机死机
Computer freezes when loading .gltf model in three.js
我是 运行 一台 Ubuntu 20.10 机器,正在 Firefox 上测试我的网站。使用 npm 作为包管理器,使用 parcel 作为打包器。当我尝试在 three.js 中加载 .gltf 模型时,parcel 没有显示任何错误。当我转到 localhost:1234/ 时,我的笔记本电脑死机了,canvas 是空白的。
index.html
和 index.js
中的目录结构和文件链接是正确的,所以这不是问题。我还使用 parcel-plugin-static-files-copy
来确保静态文件可用。此外,我使用 Blender 生成了 .gltf 文件,并且知道它是有效的 json.
代码:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>chtnnh</title>
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<script src="./js/index.js"></script>
</body>
</html>
index.js
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const loader = new GLTFLoader();
loader.load(
"../static/tvSet.gltf",
(gltf) => {
scene.add(gltf.scene);
},
undefined,
(err) => {
console.error("Could not load asset " + err);
}
);
const light = new THREE.AmbientLight(0xffffff, 1, 500);
light.position.set(100, 0, 250);
scene.add(light);
camera.position.z = 5;
function threeJsResize() {
// ensures scene is responsive
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function animate() {
// renders the scene at the fps of the machine
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
// add event listener for responsive three.js
window.addEventListener("resize", threeJsResize);
style.css
body {
margin: 0;
border: 0;
padding: 0;
}
package.json
{
"name": "x",
"version": "1.0.0",
"description": "x",
"main": "index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"x"
],
"author": "x",
"license": "MIT",
"dependencies": {
"parcel": "^1.12.4",
"three": "^0.125.2"
},
"devDependencies": {
"parcel-plugin-static-files-copy": "^2.5.1"
}
}
编辑:
我也尝试按照各种教程进行操作。这个好像可以,但是不知道为什么。任何帮助将不胜感激
代码:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>chtnnh</title>
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<canvas id="c"></canvas>
<script src="./js/index.js"></script>
</body>
</html>
index.js
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
function main() {
const canvas = document.querySelector("#c");
const renderer = new THREE.WebGLRenderer({ canvas });
const fov = 45;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 100;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 10, 20);
const controls = new OrbitControls(camera, canvas);
controls.target.set(0, 5, 0);
controls.update();
const scene = new THREE.Scene();
scene.background = new THREE.Color("black");
{
const planeSize = 40;
const loader = new THREE.TextureLoader();
const texture = loader.load(
"https://threejsfundamentals.org/threejs/resources/images/checker.png"
);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.magFilter = THREE.NearestFilter;
const repeats = planeSize / 2;
texture.repeat.set(repeats, repeats);
const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
const planeMat = new THREE.MeshPhongMaterial({
map: texture,
side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(planeGeo, planeMat);
mesh.rotation.x = Math.PI * -0.5;
scene.add(mesh);
}
{
const skyColor = 0xb1e1ff; // light blue
const groundColor = 0xb97a20; // brownish orange
const intensity = 1;
const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
scene.add(light);
}
{
const color = 0xffffff;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(5, 10, 2);
scene.add(light);
scene.add(light.target);
}
function frameArea(sizeToFitOnScreen, boxSize, boxCenter, camera) {
const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
const halfFovY = THREE.MathUtils.degToRad(camera.fov * 0.5);
const distance = halfSizeToFitOnScreen / Math.tan(halfFovY);
// compute a unit vector that points in the direction the camera is now
// in the xz plane from the center of the box
const direction = new THREE.Vector3()
.subVectors(camera.position, boxCenter)
.multiply(new THREE.Vector3(1, 0, 1))
.normalize();
// move the camera to a position distance units way from the center
// in whatever direction the camera was from the center already
camera.position.copy(direction.multiplyScalar(distance).add(boxCenter));
// pick some near and far values for the frustum that
// will contain the box.
camera.near = boxSize / 100;
camera.far = boxSize * 100;
camera.updateProjectionMatrix();
// point the camera to look at the center of the box
camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z);
}
{
const gltfLoader = new GLTFLoader();
gltfLoader.load(
"https://threejsfundamentals.org/threejs/resources/models/cartoon_lowpoly_small_city_free_pack/scene.gltf",
(gltf) => {
const root = gltf.scene;
scene.add(root);
// compute the box that contains all the stuff
// from root and below
const box = new THREE.Box3().setFromObject(root);
const boxSize = box.getSize(new THREE.Vector3()).length();
const boxCenter = box.getCenter(new THREE.Vector3());
// set the camera to frame the box
frameArea(boxSize * 0.5, boxSize, boxCenter, camera);
// update the Trackball controls to handle the new size
controls.maxDistance = boxSize * 10;
controls.target.copy(boxCenter);
controls.update();
}
);
}
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
结果证明我在问题中提到的第一个 index.js
没有任何问题。该模型对我的机器来说太高了,因为当我链接一个低多边形模型时,页面加载得很好。
工作代码:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>chtnnh</title>
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<script src="./js/index.js"></script>
</body>
</html>
index.js
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const loader = new GLTFLoader();
loader.load(
"https://threejsfundamentals.org/threejs/resources/models/cartoon_lowpoly_small_city_free_pack/scene.gltf",
(gltf) => {
scene.add(gltf.scene);
},
undefined,
(err) => {
console.error("Could not load asset " + err);
}
);
const light = new THREE.AmbientLight(0xffffff, 1, 500);
light.position.set(100, 0, 250);
scene.add(light);
camera.position.z = 5;
function threeJsResize() {
// ensures scene is responsive
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function animate() {
// renders the scene at the fps of the machine
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
// add event listener for responsive three.js
window.addEventListener("resize", threeJsResize);
我是 运行 一台 Ubuntu 20.10 机器,正在 Firefox 上测试我的网站。使用 npm 作为包管理器,使用 parcel 作为打包器。当我尝试在 three.js 中加载 .gltf 模型时,parcel 没有显示任何错误。当我转到 localhost:1234/ 时,我的笔记本电脑死机了,canvas 是空白的。
index.html
和 index.js
中的目录结构和文件链接是正确的,所以这不是问题。我还使用 parcel-plugin-static-files-copy
来确保静态文件可用。此外,我使用 Blender 生成了 .gltf 文件,并且知道它是有效的 json.
代码: index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>chtnnh</title>
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<script src="./js/index.js"></script>
</body>
</html>
index.js
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const loader = new GLTFLoader();
loader.load(
"../static/tvSet.gltf",
(gltf) => {
scene.add(gltf.scene);
},
undefined,
(err) => {
console.error("Could not load asset " + err);
}
);
const light = new THREE.AmbientLight(0xffffff, 1, 500);
light.position.set(100, 0, 250);
scene.add(light);
camera.position.z = 5;
function threeJsResize() {
// ensures scene is responsive
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function animate() {
// renders the scene at the fps of the machine
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
// add event listener for responsive three.js
window.addEventListener("resize", threeJsResize);
style.css
body {
margin: 0;
border: 0;
padding: 0;
}
package.json
{
"name": "x",
"version": "1.0.0",
"description": "x",
"main": "index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"x"
],
"author": "x",
"license": "MIT",
"dependencies": {
"parcel": "^1.12.4",
"three": "^0.125.2"
},
"devDependencies": {
"parcel-plugin-static-files-copy": "^2.5.1"
}
}
编辑:
我也尝试按照各种教程进行操作。这个好像可以,但是不知道为什么。任何帮助将不胜感激
代码: index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>chtnnh</title>
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<canvas id="c"></canvas>
<script src="./js/index.js"></script>
</body>
</html>
index.js
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
function main() {
const canvas = document.querySelector("#c");
const renderer = new THREE.WebGLRenderer({ canvas });
const fov = 45;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 100;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 10, 20);
const controls = new OrbitControls(camera, canvas);
controls.target.set(0, 5, 0);
controls.update();
const scene = new THREE.Scene();
scene.background = new THREE.Color("black");
{
const planeSize = 40;
const loader = new THREE.TextureLoader();
const texture = loader.load(
"https://threejsfundamentals.org/threejs/resources/images/checker.png"
);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.magFilter = THREE.NearestFilter;
const repeats = planeSize / 2;
texture.repeat.set(repeats, repeats);
const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
const planeMat = new THREE.MeshPhongMaterial({
map: texture,
side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(planeGeo, planeMat);
mesh.rotation.x = Math.PI * -0.5;
scene.add(mesh);
}
{
const skyColor = 0xb1e1ff; // light blue
const groundColor = 0xb97a20; // brownish orange
const intensity = 1;
const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
scene.add(light);
}
{
const color = 0xffffff;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(5, 10, 2);
scene.add(light);
scene.add(light.target);
}
function frameArea(sizeToFitOnScreen, boxSize, boxCenter, camera) {
const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
const halfFovY = THREE.MathUtils.degToRad(camera.fov * 0.5);
const distance = halfSizeToFitOnScreen / Math.tan(halfFovY);
// compute a unit vector that points in the direction the camera is now
// in the xz plane from the center of the box
const direction = new THREE.Vector3()
.subVectors(camera.position, boxCenter)
.multiply(new THREE.Vector3(1, 0, 1))
.normalize();
// move the camera to a position distance units way from the center
// in whatever direction the camera was from the center already
camera.position.copy(direction.multiplyScalar(distance).add(boxCenter));
// pick some near and far values for the frustum that
// will contain the box.
camera.near = boxSize / 100;
camera.far = boxSize * 100;
camera.updateProjectionMatrix();
// point the camera to look at the center of the box
camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z);
}
{
const gltfLoader = new GLTFLoader();
gltfLoader.load(
"https://threejsfundamentals.org/threejs/resources/models/cartoon_lowpoly_small_city_free_pack/scene.gltf",
(gltf) => {
const root = gltf.scene;
scene.add(root);
// compute the box that contains all the stuff
// from root and below
const box = new THREE.Box3().setFromObject(root);
const boxSize = box.getSize(new THREE.Vector3()).length();
const boxCenter = box.getCenter(new THREE.Vector3());
// set the camera to frame the box
frameArea(boxSize * 0.5, boxSize, boxCenter, camera);
// update the Trackball controls to handle the new size
controls.maxDistance = boxSize * 10;
controls.target.copy(boxCenter);
controls.update();
}
);
}
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
结果证明我在问题中提到的第一个 index.js
没有任何问题。该模型对我的机器来说太高了,因为当我链接一个低多边形模型时,页面加载得很好。
工作代码: index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>chtnnh</title>
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<script src="./js/index.js"></script>
</body>
</html>
index.js
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const loader = new GLTFLoader();
loader.load(
"https://threejsfundamentals.org/threejs/resources/models/cartoon_lowpoly_small_city_free_pack/scene.gltf",
(gltf) => {
scene.add(gltf.scene);
},
undefined,
(err) => {
console.error("Could not load asset " + err);
}
);
const light = new THREE.AmbientLight(0xffffff, 1, 500);
light.position.set(100, 0, 250);
scene.add(light);
camera.position.z = 5;
function threeJsResize() {
// ensures scene is responsive
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function animate() {
// renders the scene at the fps of the machine
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
// add event listener for responsive three.js
window.addEventListener("resize", threeJsResize);