我的 Three.js 子组中有五个元素,但我无法访问网格。如何访问 three.js 组中的网格?
There are five elements in my Three.js Group children but I can't access the meshes. How to access the meshes in a three.js group?
我试图访问这个数组中的元素,但由于某种原因它说“未定义”并返回长度为 0,但显然长度为 5。上图是这段代码的结果.
console.log(scene.children[1].children);
下面这段代码的结果是0
console.log(scene.children[1].children.length);
下面这段代码的结果是undefined
console.log(scene.children[1].children[0]);
如果对上下文有帮助,这是以前的路径:
console.log(scene);
console.log(scene.children[1]);
根据评论:这里是完整代码:
import "./styles.css";
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import gsap from "gsap";
import blueHouseBaked from "./static/Bluehouse.png";
import blueHouse from "./static/Bluehouse.glb";
import greenHouseBaked from "./static/Greenhouse.png";
import greenHouse from "./static/Greenhouse.glb";
import redHouseBaked from "./static/Redhouse.png";
import redHouse from "./static/Redhouse.glb";
import purpleHouseBaked from "./static/Purplehouse.png";
import purpleHouse from "./static/Purplehouse.glb";
import groundBaked from "./static/Ground.png";
import ground from "./static/Ground.glb";
import "regenerator-runtime/runtime";
const canvas = document.querySelector("canvas.experience");
// Scene
const scene = new THREE.Scene();
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight,
};
window.addEventListener("resize", () => {
// Update sizes
sizes.width = window.innerWidth;
sizes.height = window.innerHeight;
// Update camera
camera.aspect = sizes.width / sizes.height;
camera.updateProjectionMatrix();
// Update renderer
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
/**
* Camera
*/
// Base camera
const camera = new THREE.PerspectiveCamera(
75,
sizes.width / sizes.height,
0.1,
100
);
camera.position.x = 0;
camera.position.y = 17;
camera.position.z = 22;
camera.rotation.x = -Math.PI / 8;
scene.add(camera);
//Controls -------------------
//Three.js vector lerping
let cameraTargetPosition = new THREE.Vector3(0, 17, 22);
window.addEventListener("mousedown", () => {
window.addEventListener("mousemove", updateCamera);
});
window.addEventListener("mouseup", () => {
window.removeEventListener("mousemove", updateCamera);
});
// Controls
function updateCamera(ev) {
ev.preventDefault();
if (ev.movementX > 0) {
cameraTargetPosition.x -= ev.movementX * 0.015;
} else {
cameraTargetPosition.x -= ev.movementX * 0.015;
}
if (ev.movementY > 0) {
cameraTargetPosition.z -= ev.movementY * 0.015;
} else {
cameraTargetPosition.z -= ev.movementY * 0.015;
}
}
/**
* Everything load
*/
let group = new THREE.Group();
async function loadModels(model, texture) {
const gltfLoader = new GLTFLoader();
const textureLoader = new THREE.TextureLoader();
const mesh = await gltfLoader.loadAsync(model);
const bakedTexture = textureLoader.load(texture);
const bakedMaterial = new THREE.MeshBasicMaterial({
map: bakedTexture,
});
bakedTexture.flipY = false;
bakedTexture.encoding = THREE.sRGBEncoding;
mesh.scene.children[0].material = bakedMaterial;
group.add(mesh.scene.children[0]);
}
loadModels(blueHouse, blueHouseBaked);
loadModels(greenHouse, greenHouseBaked);
loadModels(redHouse, redHouseBaked);
loadModels(purpleHouse, purpleHouseBaked);
loadModels(ground, groundBaked);
scene.add(group);
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
});
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
/**
* Animate
*/
const clock = new THREE.Clock();
let lastElapsedTime = 0;
// Ray Casting stuff
let raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
let currentIntersect = null;
window.addEventListener("mousemove", (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
});
console.log(scene.children[1].children[0]);
const tick = () => {
camera.position.lerp(cameraTargetPosition, 0.1);
const elapsedTime = clock.getElapsedTime();
const deltaTime = elapsedTime - lastElapsedTime;
lastElapsedTime = elapsedTime;
// Raycaster stuff
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects([scene.children[1].children]);
if (intersects.length) {
if (!currentIntersect) {
console.log("mouse enter");
}
currentIntersect = intersects[0];
} else {
if (currentIntersect) {
console.log("mouse leave");
}
currentIntersect = null;
}
// Render
renderer.render(scene, camera);
// Call tick again on the next frame
window.requestAnimationFrame(tick);
};
tick();
所以我找到了解决办法,但我仍然不知道为什么根本问题仍然存在。如果我把 console.log(scene.children[1].children[0]);
放在勾号的里面它输出这个:
undefined
mesh
mesh
mesh
所以第一个循环是未定义的。因此,解决方案只是检查它是否未定义,现在我没有收到任何错误并且一切正常:
// Raycaster stuff
raycaster.setFromCamera(mouse, camera);
if (
typeof scene.children[1].children[0] !== "undefined" &&
typeof scene.children[1].children[1] !== "undefined" &&
typeof scene.children[1].children[2] !== "undefined" &&
typeof scene.children[1].children[3] !== "undefined"
) {
const intersects = raycaster.intersectObjects([
scene.children[1].children[0],
scene.children[1].children[1],
scene.children[1].children[2],
scene.children[1].children[3],
]);
if (intersects.length) {
if (!currentIntersect) {
console.log("mouse enter");
}
currentIntersect = intersects[0];
} else {
if (currentIntersect) {
console.log("mouse leave");
}
currentIntersect = null;
}
}
但是,我还是不明白为什么它在前几个循环中是未定义的。
您遇到的问题是由异步代码引起的。 loadModels
函数异步加载模型,这意味着其余代码先完成,然后异步方法完成其所有调用。
这是一个关于事件循环及其工作原理的精彩视频,可以更好地理解为什么会发生这种情况 - https://www.youtube.com/watch?v=8aGhZQkoFbQ。
加载 GLTF 模型也可能需要一些时间,具体取决于它们的大小,因此它们可能需要几毫秒才能在组中可用。
您可以尝试记录每个报价,因此将您的报价方法更改为 -
const tick = () => {
camera.position.lerp(cameraTargetPosition, 0.1);
const elapsedTime = clock.getElapsedTime();
const deltaTime = elapsedTime - lastElapsedTime;
lastElapsedTime = elapsedTime;
// Raycaster stuff
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects([scene.children[1].children]);
if (intersects.length) {
if (!currentIntersect) {
console.log("mouse enter");
}
currentIntersect = intersects[0];
} else {
if (currentIntersect) {
console.log("mouse leave");
}
currentIntersect = null;
}
// Render
renderer.render(scene, camera);
console.log(scene.children[0].children[1])
// Call tick again on the next frame
window.requestAnimationFrame(tick);
};
然而,当我们使用 threejs 时,将场景分配到全局 window 以便于在 chrome 中访问要容易得多。
创建场景后只需在代码中添加以下几行
window.scene = scene
import "./styles.css";
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import gsap from "gsap";
import blueHouseBaked from "./static/Bluehouse.png";
import blueHouse from "./static/Bluehouse.glb";
import greenHouseBaked from "./static/Greenhouse.png";
import greenHouse from "./static/Greenhouse.glb";
import redHouseBaked from "./static/Redhouse.png";
import redHouse from "./static/Redhouse.glb";
import purpleHouseBaked from "./static/Purplehouse.png";
import purpleHouse from "./static/Purplehouse.glb";
import groundBaked from "./static/Ground.png";
import ground from "./static/Ground.glb";
import "regenerator-runtime/runtime";
const canvas = document.querySelector("canvas.experience");
// Scene
const scene = new THREE.Scene();
window.scene = scene
.......
一旦加载了 GLTF 模型,您就可以从 chrome 控制台访问该组,因为现在可以从开发工具访问场景。你可以在那里写场景然后你就可以访问它,或者你可以写scene.children[0].children[1]
然后你会看到你的组。
编辑:这只是为了调试。
我试图访问这个数组中的元素,但由于某种原因它说“未定义”并返回长度为 0,但显然长度为 5。上图是这段代码的结果.
console.log(scene.children[1].children);
下面这段代码的结果是0
console.log(scene.children[1].children.length);
下面这段代码的结果是undefined
console.log(scene.children[1].children[0]);
如果对上下文有帮助,这是以前的路径:
console.log(scene);
console.log(scene.children[1]);
根据评论:这里是完整代码:
import "./styles.css";
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import gsap from "gsap";
import blueHouseBaked from "./static/Bluehouse.png";
import blueHouse from "./static/Bluehouse.glb";
import greenHouseBaked from "./static/Greenhouse.png";
import greenHouse from "./static/Greenhouse.glb";
import redHouseBaked from "./static/Redhouse.png";
import redHouse from "./static/Redhouse.glb";
import purpleHouseBaked from "./static/Purplehouse.png";
import purpleHouse from "./static/Purplehouse.glb";
import groundBaked from "./static/Ground.png";
import ground from "./static/Ground.glb";
import "regenerator-runtime/runtime";
const canvas = document.querySelector("canvas.experience");
// Scene
const scene = new THREE.Scene();
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight,
};
window.addEventListener("resize", () => {
// Update sizes
sizes.width = window.innerWidth;
sizes.height = window.innerHeight;
// Update camera
camera.aspect = sizes.width / sizes.height;
camera.updateProjectionMatrix();
// Update renderer
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
/**
* Camera
*/
// Base camera
const camera = new THREE.PerspectiveCamera(
75,
sizes.width / sizes.height,
0.1,
100
);
camera.position.x = 0;
camera.position.y = 17;
camera.position.z = 22;
camera.rotation.x = -Math.PI / 8;
scene.add(camera);
//Controls -------------------
//Three.js vector lerping
let cameraTargetPosition = new THREE.Vector3(0, 17, 22);
window.addEventListener("mousedown", () => {
window.addEventListener("mousemove", updateCamera);
});
window.addEventListener("mouseup", () => {
window.removeEventListener("mousemove", updateCamera);
});
// Controls
function updateCamera(ev) {
ev.preventDefault();
if (ev.movementX > 0) {
cameraTargetPosition.x -= ev.movementX * 0.015;
} else {
cameraTargetPosition.x -= ev.movementX * 0.015;
}
if (ev.movementY > 0) {
cameraTargetPosition.z -= ev.movementY * 0.015;
} else {
cameraTargetPosition.z -= ev.movementY * 0.015;
}
}
/**
* Everything load
*/
let group = new THREE.Group();
async function loadModels(model, texture) {
const gltfLoader = new GLTFLoader();
const textureLoader = new THREE.TextureLoader();
const mesh = await gltfLoader.loadAsync(model);
const bakedTexture = textureLoader.load(texture);
const bakedMaterial = new THREE.MeshBasicMaterial({
map: bakedTexture,
});
bakedTexture.flipY = false;
bakedTexture.encoding = THREE.sRGBEncoding;
mesh.scene.children[0].material = bakedMaterial;
group.add(mesh.scene.children[0]);
}
loadModels(blueHouse, blueHouseBaked);
loadModels(greenHouse, greenHouseBaked);
loadModels(redHouse, redHouseBaked);
loadModels(purpleHouse, purpleHouseBaked);
loadModels(ground, groundBaked);
scene.add(group);
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
});
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
/**
* Animate
*/
const clock = new THREE.Clock();
let lastElapsedTime = 0;
// Ray Casting stuff
let raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
let currentIntersect = null;
window.addEventListener("mousemove", (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
});
console.log(scene.children[1].children[0]);
const tick = () => {
camera.position.lerp(cameraTargetPosition, 0.1);
const elapsedTime = clock.getElapsedTime();
const deltaTime = elapsedTime - lastElapsedTime;
lastElapsedTime = elapsedTime;
// Raycaster stuff
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects([scene.children[1].children]);
if (intersects.length) {
if (!currentIntersect) {
console.log("mouse enter");
}
currentIntersect = intersects[0];
} else {
if (currentIntersect) {
console.log("mouse leave");
}
currentIntersect = null;
}
// Render
renderer.render(scene, camera);
// Call tick again on the next frame
window.requestAnimationFrame(tick);
};
tick();
所以我找到了解决办法,但我仍然不知道为什么根本问题仍然存在。如果我把 console.log(scene.children[1].children[0]);
放在勾号的里面它输出这个:
undefined
mesh
mesh
mesh
所以第一个循环是未定义的。因此,解决方案只是检查它是否未定义,现在我没有收到任何错误并且一切正常:
// Raycaster stuff
raycaster.setFromCamera(mouse, camera);
if (
typeof scene.children[1].children[0] !== "undefined" &&
typeof scene.children[1].children[1] !== "undefined" &&
typeof scene.children[1].children[2] !== "undefined" &&
typeof scene.children[1].children[3] !== "undefined"
) {
const intersects = raycaster.intersectObjects([
scene.children[1].children[0],
scene.children[1].children[1],
scene.children[1].children[2],
scene.children[1].children[3],
]);
if (intersects.length) {
if (!currentIntersect) {
console.log("mouse enter");
}
currentIntersect = intersects[0];
} else {
if (currentIntersect) {
console.log("mouse leave");
}
currentIntersect = null;
}
}
但是,我还是不明白为什么它在前几个循环中是未定义的。
您遇到的问题是由异步代码引起的。 loadModels
函数异步加载模型,这意味着其余代码先完成,然后异步方法完成其所有调用。
这是一个关于事件循环及其工作原理的精彩视频,可以更好地理解为什么会发生这种情况 - https://www.youtube.com/watch?v=8aGhZQkoFbQ。
加载 GLTF 模型也可能需要一些时间,具体取决于它们的大小,因此它们可能需要几毫秒才能在组中可用。
您可以尝试记录每个报价,因此将您的报价方法更改为 -
const tick = () => {
camera.position.lerp(cameraTargetPosition, 0.1);
const elapsedTime = clock.getElapsedTime();
const deltaTime = elapsedTime - lastElapsedTime;
lastElapsedTime = elapsedTime;
// Raycaster stuff
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects([scene.children[1].children]);
if (intersects.length) {
if (!currentIntersect) {
console.log("mouse enter");
}
currentIntersect = intersects[0];
} else {
if (currentIntersect) {
console.log("mouse leave");
}
currentIntersect = null;
}
// Render
renderer.render(scene, camera);
console.log(scene.children[0].children[1])
// Call tick again on the next frame
window.requestAnimationFrame(tick);
};
然而,当我们使用 threejs 时,将场景分配到全局 window 以便于在 chrome 中访问要容易得多。
创建场景后只需在代码中添加以下几行
window.scene = scene
import "./styles.css";
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import gsap from "gsap";
import blueHouseBaked from "./static/Bluehouse.png";
import blueHouse from "./static/Bluehouse.glb";
import greenHouseBaked from "./static/Greenhouse.png";
import greenHouse from "./static/Greenhouse.glb";
import redHouseBaked from "./static/Redhouse.png";
import redHouse from "./static/Redhouse.glb";
import purpleHouseBaked from "./static/Purplehouse.png";
import purpleHouse from "./static/Purplehouse.glb";
import groundBaked from "./static/Ground.png";
import ground from "./static/Ground.glb";
import "regenerator-runtime/runtime";
const canvas = document.querySelector("canvas.experience");
// Scene
const scene = new THREE.Scene();
window.scene = scene
.......
一旦加载了 GLTF 模型,您就可以从 chrome 控制台访问该组,因为现在可以从开发工具访问场景。你可以在那里写场景然后你就可以访问它,或者你可以写scene.children[0].children[1]
然后你会看到你的组。
编辑:这只是为了调试。