【问题标题】:How to use onclick in React Threejs for a loaded GLTF object如何在 React Threejs 中使用 onclick 加载 GLTF 对象
【发布时间】:2021-05-08 03:22:12
【问题描述】:

GLTF 文件已加载并且看起来不错,但我想单击它并查看它是否包含任何信息,例如 uuid。下面的代码欺骗了一个错误,当我单击查看器时,说 TypeError: Cannot set property 'x' of undefined。谁能告诉我为什么 this.mouse.x 给我一个错误以及我如何单击加载的 GLTF 对象并从中接收一些信息?我已经添加了下面的代码并复制了下面的错误。希望有人可以在这里帮助我。

TypeError:无法设置未定义的属性“x” HTMLCanvasElement.onClick C:/Users/alikuc/Desktop/codingProjects/IFCtoFSO/server-react/client/src/components/Viewer.js:65 62 |功能点击(事件){ 63 | event.preventDefault(); 64 | 65 | this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1; | ^
| this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; 67 | 68 | this.raycaster.setFromCamera(this.mouse, this.camera);

import React, { Component } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import filePath from '../assets/02.00.04_test8.gltf';

export default class Viewer extends Component {
    componentDidMount() {

        //Add Scene
        this.scene = new THREE.Scene();

        //Add Renderer
        this.renderer = new THREE.WebGLRenderer({ antialias: true });
        this.renderer.setClearColor('#808080');
        this.renderer.shadowMap.enabled = true;
        this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        this.renderer.setPixelRatio(window.devicePixelRatio);
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.mount.appendChild(this.renderer.domElement);

        //Add Camera
        const fov = 60;
        const aspect = window.innerWidth / window.innerHeight;
        const near = 1.0;
        const far = 1000.0;
        this.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
        this.camera.position.set(45, aspect, 1, 1000);

        // //Add Geometry and material
        // const cube = new Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshBasicMaterial({ color: '#0F0' }));

        // // //Add mesh which is also the model
        // this.scene.add(cube);
        
        
        // Load GLTF file
        // Instantiate a loader
        const loader = new GLTFLoader();

        /// Load a glTF resource
        loader.load(
            filePath,
            (gltf) => {
                this.scene.add(gltf.scene);
            },
            (xhr) => {
                console.log((xhr.loaded / xhr.total) * 100 + '% loaded');
            },
            (error) => {
                console.log('An error happened');
                console.log(error);
            }
        );

        //Add raycaster to for interactivity
        this.raycaster = new THREE.Raycaster();
        this.mouse = new THREE.Vector2();

        this.renderer.domElement.addEventListener('click', onClick, false);

        function onClick(event) {
            event.preventDefault();

            this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

            this.raycaster.setFromCamera(this.mouse, this.camera);

            var intersects = this.raycaster.intersectObjects(this.scene.children, true);

            if (intersects.length > 0) {
                console.log('Intersection:', intersects[0]);
            }
        }

        //Settings
        //Add Camera Controls
        const controls = new OrbitControls(this.camera, this.renderer.domElement);
        controls.addEventListener('change', this.render); // use if there is no animation loop
        controls.minDistance = 2;
        controls.maxDistance = 10;
        controls.target.set(0, 0, -0.2);
        controls.update();

        ///Add AMBIENT LIGHT
        let light = new THREE.DirectionalLight(0xffffff, 1.0);
        light.position.set(20, 100, 10);
        light.target.position.set(0, 0, 0);
        light.castShadow = true;
        light.shadow.bias = -0.001;
        light.shadow.mapSize.width = 2048;
        light.shadow.mapSize.height = 2048;
        light.shadow.camera.near = 0.1;
        light.shadow.camera.far = 500.0;
        light.shadow.camera.near = 0.5;
        light.shadow.camera.far = 500.0;
        light.shadow.camera.left = 100;
        light.shadow.camera.right = -100;
        light.shadow.camera.top = 100;
        light.shadow.camera.bottom = -100;
        this.scene.add(light);
        light = new THREE.AmbientLight(0xffffff, 0.7);
        this.scene.add(light);

        //Start animation
        this.start();
    }

    //Unmount when animation has stopped
    componentWillUnmount() {
        this.stop();
        this.mount.removeChild(this.renderer.domElement);
    }

    //Function to start animation
    start = () => {
        //Rotate Models
        if (!this.frameId) {
            this.frameId = requestAnimationFrame(this.animate);
        }
    };

    //Function to stop animation
    stop = () => {
        cancelAnimationFrame(this.frameId);
    };

    //Animate models here
    animate = () => {
        //ReDraw scene with camera and scene object
        //if (this.cubeMesh) this.cubeMesh.rotation.y += 0.01;
        this.renderScene();
        this.frameId = window.requestAnimationFrame(this.animate);
    };

    //Render the scene
    renderScene = () => {
        if (this.renderer) this.renderer.render(this.scene, this.camera);
    };

    render() {
        return (
            <div
                style={{ width: '800px', height: '800px' }}
                ref={(mount) => {
                    this.mount = mount;
                }}
            />
        );
    }
}

【问题讨论】:

  • @Rabbid76 现在好点了吗?或者错误是否需要以更好的方式格式化。只需复制粘贴错误即可。

标签: javascript reactjs three.js onclick gltf


【解决方案1】:

这是因为当您在 onClick 函数中时,this 的范围会发生变化。

尝试通过添加.bind(this)this 添加到该函数的作用域

this.renderer.domElement.addEventListener('click', onClick.bind(this), false);

【讨论】:

  • 谢谢它的工作!您会推荐我使用 this.camera this.scene 等,还是应该将语法更改为 let 或 const?我的意思是 onclick.bind(this) 是我以前从未见过的东西,也许我这样做的方式很不寻常?
  • @Ali91 如果您要在整个Component 中使用这些对象,那么保留this.camera 很重要(因为您需要在renderScene() 中使用它)。如果您只在单个函数中使用它,而不是在Component 生命周期的多个部分中使用它,那么您可以使用letconst。看起来你已经在做正确的事情了。
猜你喜欢
  • 2021-12-08
  • 2020-03-11
  • 2018-03-06
  • 2021-04-16
  • 2021-12-21
  • 2021-11-24
  • 2020-08-20
  • 2021-09-12
  • 1970-01-01
相关资源
最近更新 更多