【问题标题】:How to use Three.js OutlinePass with React?如何在 React 中使用 Three.js OutlinePass?
【发布时间】:2018-06-28 22:57:16
【问题描述】:

我正在尝试使用 React 服务器端渲染使 Post-processing Outline Thee.js example 工作。我的主要问题是这些行(47 和 280)(来自示例):

<script src="js/postprocessing/OutlinePass.js"></script>

outlinePass = new THREE.OutlinePass( new THREE.Vector2( window.innerWidth, window.innerHeight ), scene, camera );
                composer.addPass( outlinePass );

因为我不确定如何在 React 中包含 OutlinePass。我安装了包 postprocessing (npm profile) 但它没有 OutlinePass。

我还尝试像这样在ComponentDidMountComponentWillMount 中导入脚本:

const script = document.createElement("script");
        script.src = require('!!url-loader!../../../assets/webgl/js/OutlinePass.js');
        script.async = true;
        document.body.appendChild(script);

但它向我显示了错误:Uncaught ReferenceError: THREE is not defined

我也试过(一次一个):

import OutlinePass from '../../../assets/webgl/js/OutlinePass.js';
const OutlinePass = require('../../../assets/webgl/js/OutlinePass.js');
const OutlinePass = require('../../../assets/webgl/js/OutlinePass.js')(THREE);

那也没用。

我的 jsx(部分):

import * as THREE from 'three';
import * as OBJLoader from 'three-obj-loader';

componentWillMount() {
        const width = window.innerWidth;
        const height = window.innerHeight;

        this.setState({
            windowW: width,
            windowH: height
        });

        // LOAD SCRIPTS
        const script = document.createElement("script");
        script.src = require('!!url-loader!../../../assets/webgl/js/OutlinePass.js');
        script.async = true;
        document.body.appendChild(script);
    }

componentDidMount() {
        const { windowH, windowW } = this.state;

        const { THREE } = this;
        const TrackballControls = require('three-trackballcontrols');

        OBJLoader(THREE);


        // WINDOW RESIZE
        // window.addEventListener( 'resize', onWindowResize, false );


        // POST-PROCESSING
        const outlinePass = new THREE.OutlinePass( new THREE.Vector2( window.innerWidth, window.innerHeight ), scene, camera );


        // Code for this not included to clear space
        this.camera = camera;
        this.controls = controls;
        this.scene = scene;
        this.renderer = renderer;

        this.mount.appendChild(this.renderer.domElement);
        this.start();
    }

componentWillUnmount() {
        this.stop();
        this.mount.removeChild(this.renderer.domElement);
    }

    start() {
        if (!this.frameId) {
            this.frameId = requestAnimationFrame(this.animate);
        }
    }

    stop() {
        cancelAnimationFrame(this.frameId);
    }

    animate() {
        this.renderScene();
        this.frameId = window.requestAnimationFrame(this.animate);
        this.controls.update();
    }

    renderScene() {
        this.renderer.render(this.scene, this.camera);
    }

【问题讨论】:

    标签: javascript node.js reactjs three.js


    【解决方案1】:

    从我看到的你的代码来看,你正在使用 ES6 模块,对于一个重要的模块,模块需要采用正确的格式,换句话说,它需要有一个导出默认值......更多关于 这个http://exploringjs.com/es6/ch_modules.html#sec_basics-of-es6-modules

    您试图将一个不是这种格式的模块添加到您的代码中,这就是您遇到问题的原因,您可以使用 script 标签并使用 window 引用代码

    &lt;script src="js/postprocessing/OutlinePass.js"&gt;&lt;/script&gt;

    然后用 window.THREE.OutlinePass 引用

    【讨论】:

    • 这不是 // LOAD SCRIPTS 部分的作用吗?我把它放在三个变量声明之后,这样它就可以使用它(它定义了 THREE.OutlinePass),但它说 THREE 是未定义的。我不能把它放在 HTML 中,因为我正在做服务器端渲染,如果我把它放在那里,那么脚本总是会加载,我只在渲染这个组件时想要它
    【解决方案2】:

    我做到了!问题是我试图在加载脚本之前使用 THREE.OutlinePass before,所以,我添加了一个按钮来加载触发 loadScene() 的场景:

    componentWillMount() {
            const width = window.innerWidth;
            const height = window.innerHeight;
    
            this.setState({
                windowW: width,
                windowH: height
            });
    
            // LOAD SCRIPTS    
            const scriptOP = document.createElement("script");
            scriptOP.src = require('!!url-loader!../../../assets/webgl/js/OutlinePass.js');
            scriptOP.async = true;
            document.body.appendChild(scriptOP);
        }
    
    componentDidMount() {
            const { windowH, windowW } = this.state;
    
            const { THREE } = window;
            const TrackballControls = require('three-trackballcontrols');
    
            OBJLoader(THREE);
            MTLLoader(THREE);
    
            // CAMERA
            var  camera = new THREE.PerspectiveCamera( 45, windowW / windowH, 1, 10000 );
            camera.position.set( 0, 0, 1 );
            // camera.lookAt(scene.position);
            // camera.up = new THREE.Vector3(0, 0, 1);
    
    
            // CONTROLS
            const controls = new TrackballControls( camera );
            controls.rotateSpeed = 1.0;
            controls.zoomSpeed = 1.2;
            controls.panSpeed = 0.8;
            controls.noZoom = false;
            controls.noPan = false;
            controls.staticMoving = true;
            controls.dynamicDampingFactor = 0.3;
            controls.keys = [ 65, 83, 68 ];
    
    
            // SCENE
            const scene = new THREE.Scene();
            scene.background = new THREE.Color( 0xcccccc );
            scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 );
    
            // RENDERER
            const renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setPixelRatio( window.devicePixelRatio );
            renderer.setSize( windowW, windowH );
            renderer.setClearColor('#000000');
    
            // POST-PROCESSING
            const composer = null; <- this is important
    
            this.camera = camera;
            this.controls = controls;
            this.scene = scene;
            this.composer = composer;
            this.renderer = renderer;
    
            this.mount.appendChild(this.renderer.domElement);
            this.start();
        }
    
    renderScene() {
            this.renderer.autoClear = true;
            this.renderer.setClearColor( 0xfff0f0 );
            this.renderer.setClearAlpha( 0.0 );
            if ( this.composer ) {
                this.composer.render();
            } else {
                this.renderer.render(this.scene, this.camera);
            }
        }
    
    loadScene() {
            const { THREE, innerWidth, innerHeight } = window;
    
            // POST-PROCESSING
            this.composer = new THREE.EffectComposer( this.renderer );
    
            const renderPass = new THREE.RenderPass( this.scene, this.camera );
            this.composer.addPass( renderPass );
    
            const outlinePass = new THREE.OutlinePass( new THREE.Vector2( innerWidth, innerHeight ), this.scene, this.camera);
    
            // LOAD OBJECT
            const onProgress = xhr => {
                console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
            }
    
            const onError = error => {
                console.log("Error! ", error);
            }
    
            const loader = new THREE.OBJLoader();
            loader.load( obj,
                object => {
                    this.scene.add(object);
                    const tempMat = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x050505 } );
                    object.traverse( function( child ) {
                        if ( child instance of THREE.Mesh ) {
                            child.material = tempMat.clone();
    
                            outlinePass.selectedObjects.push( child );
                        }
                    } );
                },
                onProgress,
                onError
            );
    
            const effectFXAA = new THREE.ShaderPass(THREE.FXAAShader);
            effectFXAA.uniforms['resolution'].value.set(1 / innerWidth, 1 / innerHeight );
            effectFXAA.renderToScreen = true;
            this.composer.addPass( effectFXAA );
        }
    

    我希望这对某人有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-23
      • 2021-10-09
      • 2022-12-03
      • 2015-07-02
      • 2020-02-25
      • 2018-09-02
      相关资源
      最近更新 更多