【问题标题】: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?我的 Three.js Group 子项中有五个元素,但我无法访问网格。如何访问 three.js 组中的网格?
【发布时间】:2022-01-19 17:48:30
【问题描述】:

我试图访问这个数组中的元素,但由于某种原因,它说“未定义”并返回长度为 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]);

每 cmets:这里是完整代码:

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 是异步的。这里有人更好地解释了这个概念 - stackoverflow.com/a/23392650/4249232。在您执行 console.log 时,这些元素很可能存在于组中,但在打印时,它们已被删除。向我们展示更多代码,以便人们找出确切的问题
  • @SanilKhurana 感谢您抽出宝贵时间,刚刚添加了完整代码

标签: javascript three.js


【解决方案1】:

您面临的问题是由于异步代码。 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时,将场景分配给全局窗口以便在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],你会看到你的组。

编辑:仅用于调试。

【讨论】:

  • 但是我的异步等待函数不是把它从异步代码变成同步代码吗?
  • @awawawaw 当您调用 loadModels 时,您正在调用异步函数而不使用等待,因此它仍然是异步的。例如,当调用loadModels(blueHouse, blueHouseBaked); 时,该函数调用仍在异步进行,因为它之前没有等待。此外,不应该真正同步加载可能很大的 GLTF 模型。
  • @awawawaw 如果你想以某种方式访问​​网格,一个好的技巧可能是加载非常低分辨率的模型同步,然后加载更高分辨率的异步模型。或者在等待数据加载时显示某种加载功能 - threejs.org/docs/#api/en/loaders/managers/LoadingManager
  • 谢谢,所以当我有const mesh = await gltfLoader.loadAsync(model); 时,我的线路没有任何作用吗?
  • @awawawaw 是的,主要是loadModels 函数是一个异步函数。与你在其中做什么无关,它总是在同步执行完成后执行。这篇文章可能会解释更多 - dev.to/codeprototype/…。另请观看我在回答中提到的与此相关的视频,以更好地理解它
【解决方案2】:

所以我找到了解决方案,但我仍然不知道为什么根本问题仍然存在。如果我把console.log(scene.children[1].children[0]); INSIDE 的勾号它输出:

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;
    }
}

但是,我不明白为什么它在前几个循环中是未定义的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-23
    • 2019-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-08
    相关资源
    最近更新 更多