Three.js issue creating meshes outside of loader's load(

Three.js issue creating meshes outside of loader's load() function

本文关键字:load loader of issue js creating meshes outside Three      更新时间:2023-09-26

我很难使用Blender的Three.js插件导出多个纹理,所以我计划通过将部分分离成单独的网格来解决这个问题,但当我在load()函数之外创建网格时,遇到了代码无法工作的意外问题。我在下面提供了一个使用单个模型和单个网格的示例。以下操作很好:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>working</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                font-family: Monospace;
                background-color: #000000;
                margin: 0px;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <script src="js/build/three.min.js"></script>
        <script src="js/loaders/ColladaLoader.js"></script>
        <script src="js/Detector.js"></script>
        <script>
            if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
            var container;
            var camera, scene, renderer, objects;
            var scaleAdj = 100;
            init();
            animate();
            function init() 
            {
                container = document.createElement( 'div' );
                document.body.appendChild( container );
                camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 20000 );
                camera.position.set( 0, 500, 0 );
                scene = new THREE.Scene();
                scene.fog = new THREE.Fog( 0xcce0ff, 10, 10000 );
                var loader = new THREE.JSONLoader();
                loader.load( 'cube.json', function ( geometry, materials ) 
                {
                    var faceMaterial = new THREE.MultiMaterial( materials );
                    for ( var i = 0; i < 250; i ++ ) 
                    {
                        var x = ( ( i % 27 )  - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
                        var z = ( Math.floor( i / 27 ) - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
                        mesh = new THREE.Mesh( geometry, faceMaterial );
                        var s = THREE.Math.randFloat( 0.5, 2 ) * scaleAdj;
                        mesh.scale.set( s, s, s );
                        mesh.position.set( x, scaleAdj, z );
                        mesh.rotation.y = THREE.Math.randFloat( -0.25, 0.25 );
                        mesh.matrixAutoUpdate = false;
                        mesh.updateMatrix();
                        scene.add( mesh );
                    }
                } );
                scene.add( new THREE.AmbientLight( 0xffffff ) );
                // ground
                var textureLoader = new THREE.TextureLoader();
                var groundTexture = textureLoader.load( "texture.jpg" );
                groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
                groundTexture.repeat.set( 40, 40 );
                groundTexture.anisotropy = 16;
                var groundMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, map: groundTexture } );
                var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial );
                mesh.position.y = 0;
                mesh.rotation.x = - Math.PI / 2;
                mesh.receiveShadow = true;
                scene.add( mesh );
                // Renderer
                renderer = new THREE.WebGLRenderer();
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                renderer.setClearColor( scene.fog.color );
                container.appendChild( renderer.domElement );
                // Events
                window.addEventListener( 'resize', onWindowResize, false );
            }

            function onWindowResize( event ) {
                renderer.setSize( window.innerWidth, window.innerHeight );
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
            }
            function animate() {
                requestAnimationFrame( animate );
                render();
            }
            function render() {
                renderer.render( scene, camera );
            }

        </script>
    </body>
</html>

但这并没有(我已经注释了哪些部分包含差异):

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>not working</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                font-family: Monospace;
                background-color: #000000;
                margin: 0px;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <script src="js/build/three.min.js"></script>
        <script src="js/loaders/ColladaLoader.js"></script>
        <script src="js/Detector.js"></script>
        <script>
            if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
            //--------------- difference number 1
            var obj_geometry;
            var obj_material;
            //-----------------------------------
            var container;
            var camera, scene, renderer, objects;
            var scaleAdj = 100;
            init();
            animate();
            function init() 
            {
                container = document.createElement( 'div' );
                document.body.appendChild( container );
                camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 20000 );
                camera.position.set( 0, 500, 0 );
                scene = new THREE.Scene();
                scene.fog = new THREE.Fog( 0xcce0ff, 10, 10000 );

                //-------------------difference number 2--------------------
                var loader = new THREE.JSONLoader();
                loader.load( 'cube.json', function ( geometry, material ) 
                {
                    obj_geometry = geometry;
                    obj_material = material;
                });
                var faceMaterial = new THREE.MultiMaterial( obj_material);
                for ( var i = 0; i < 250; i ++ ) 
                {
                        var x = ( ( i % 27 )  - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
                        var z = ( Math.floor( i / 27 ) - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
                        mesh = new THREE.Mesh( obj_geometry, faceMaterial);
                        var s = THREE.Math.randFloat( 0.5, 2 ) * scaleAdj;
                        mesh.scale.set( s, s, s );
                        mesh.position.set( x, 0, z );
                        mesh.rotation.y = THREE.Math.randFloat( -0.25, 0.25 );
                        mesh.matrixAutoUpdate = false;
                        mesh.updateMatrix();
                        scene.add( mesh );
                }
                //--------------------------------------
                scene.add( new THREE.AmbientLight( 0xffffff ) );
                // ground
                var textureLoader = new THREE.TextureLoader();
                var groundTexture = textureLoader.load(  "texture.jpg" );
                groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
                groundTexture.repeat.set( 40, 40 );
                groundTexture.anisotropy = 16;
                var groundMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, map: groundTexture } );
                var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial );
                mesh.position.y = 0;
                mesh.rotation.x = - Math.PI / 2;
                mesh.receiveShadow = true;
                scene.add( mesh );
                // Renderer
                renderer = new THREE.WebGLRenderer();
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                renderer.setClearColor( scene.fog.color );
                container.appendChild( renderer.domElement );
                // Events
                window.addEventListener( 'resize', onWindowResize, false );
            }

            function onWindowResize( event ) {
                renderer.setSize( window.innerWidth, window.innerHeight );
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
            }
            function animate() {
                requestAnimationFrame( animate );
                render();
            }
            function render() {
                renderer.render( scene, camera );
            }

        </script>
    </body>
</html>

以下是cube.json文件内容的副本:

{
    "uvs":[[0,0,1,0,1,1,0,1]],
    "faces":[43,0,1,2,3,0,0,1,2,3,0,1,2,3,43,4,7,6,5,0,0,1,2,3,4,5,6,7,43,0,4,5,1,0,0,1,2,3,0,4,7,1,43,1,5,6,2,0,0,1,2,3,1,7,6,2,43,2,6,7,3,0,0,1,2,3,2,6,5,3,43,4,0,3,7,0,0,1,2,3,4,0,3,5],
    "normals":[0.577349,-0.577349,-0.577349,0.577349,-0.577349,0.577349,-0.577349,-0.577349,0.577349,-0.577349,-0.577349,-0.577349,0.577349,0.577349,-0.577349,-0.577349,0.577349,-0.577349,-0.577349,0.577349,0.577349,0.577349,0.577349,0.577349],
    "metadata":{
        "generator":"io_three",
        "type":"Geometry",
        "normals":8,
        "vertices":8,
        "uvs":1,
        "version":3,
        "materials":1,
        "faces":6
    },
    "vertices":[1,-1,-1,1,-1,1,-1,-1,1,-1,-1,-1,1,1,-1,0.999999,1,1,-1,1,1,-1,1,-1],
    "materials":[{
        "DbgName":"Material",
        "colorSpecular":[0.5,0.5,0.5],
        "DbgIndex":0,
        "mapDiffuseWrap":["RepeatWrapping","RepeatWrapping"],
        "mapDiffuse":"texture.jpg",
        "shading":"phong",
        "depthTest":true,
        "opacity":1,
        "transparent":false,
        "colorDiffuse":[0.64,0.64,0.64],
        "mapDiffuseAnisotropy":1,
        "blending":"NormalBlending",
        "depthWrite":true,
        "visible":true,
        "specularCoef":50,
        "mapDiffuseRepeat":[1,1],
        "colorEmissive":[0,0,0],
        "wireframe":false,
        "DbgColor":15658734
    }],
    "name":"CubeGeometry"
}

这是一个可以使用的附加纹理。

对于这里的一些海报来说,这可能只是一个微不足道的问题,如果是的话,提前感谢你让我知道它是什么。如果不是,那么这个答案可能对更多的人有用,感谢你在这方面提供的任何帮助。

您不能异步执行此操作:

var obj_geometry; // === undefined
var myMesh = new THREE.Mesh( obj_geometry ); //because undefined, same as calling new THREE.Mesh();
obj_geometry = geometry;//does nothing, mesh has no idea about this happening
obj_material = material;

当你构造一个网格时,你已经为几何体赋予了undefined,所以我认为它只是在构造函数内调用new Geometry()。此网格是使用空的Geometry创建的,与您的obj_geometry无关。

这里的解决方案是:

var obj_geometry = new THREE.Geometry();
var myMesh = new THREE.Mesh( obj_geometry ); //holds a reference to an empty "proxy"

然后加载

loader.load( 'url' , function( geom ) {
  obj_geometry.merge(geom); //"FILL PREVIOUSLY CREATED GEOMETRY WITH DATA"
  obj_geometry.vertsNeedUpdate = true; // there's a few flags like this you need to turn on
}

var myMesh = new THREE.Mesh();
loader.load( 'url', function( geom ) {
   myMesh.geometry = geom; //"PUT THE JUST CREATED GEOMETRY IN THE RIGHT PLACE"
   //myOtherMesh.geometry = geom; //if you have more places where this needs to end up
   //myThirdMesh.geometry = geom; //gets very cumbersome
}

两者都很麻烦,也不太直观:(我真的不喜欢three.js.

的这一部分

感谢pailhead的帮助,指出异步问题,我对代码进行了以下修改,发现它有效。令人惊讶的是,我添加的计数似乎没有超过0,但我认为这是因为这是一个非常接近的结果。

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>asynchronous working</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                font-family: Monospace;
                background-color: #000000;
                margin: 0px;
                overflow: hidden;
            }
        </style>
    </head>
    <body>

        <script src="build/three.min.js"></script>
        <script>
            //--------------- difference number 1
            var obj_geometry;
            var obj_material;
            var loaded = false;
            //-----------------------------------
            var container;
            var camera, scene, renderer, objects;
            var scaleAdj = 100;
            init();
            animate();
            function init() 
            {
                container = document.createElement( 'div' );
                document.body.appendChild( container );
                //-----an info display
                info = document.createElement( 'div' );
                info.id = "info";
                info.style.position = 'absolute';
                info.style.top = '10px';
                info.style.width = '100%';
                info.style.textAlign = 'center';
                container.appendChild(info);
                //-----------------

                camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 20000 );
                camera.position.set( 0, 500, 0 );
                scene = new THREE.Scene();
                scene.fog = new THREE.Fog( 0xcce0ff, 10, 10000 );

                //-------------------difference number 2--------------------
                var loader = new THREE.JSONLoader();
                loader.load( 'cube.json', function ( geometry, material ) 
                {
                    obj_geometry = geometry;
                    obj_material = material;
                    loaded = true;
                });
                var notLoadedCount = 0;
                var processor = setInterval(function()
                {           
                    if(!loaded)
                    {
                        notLoadedCount++;                   
                    }
                    else
                    {
                        var faceMaterial = new THREE.MultiMaterial( obj_material);
                        for ( var i = 0; i < 250; i ++ ) 
                        {
                            var x = ( ( i % 27 )  - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
                            var z = ( Math.floor( i / 27 ) - 13.5 ) * (5 * scaleAdj) + THREE.Math.randFloatSpread( 300 * scaleAdj);
                            mesh = new THREE.Mesh( obj_geometry, faceMaterial);
                            var s = THREE.Math.randFloat( 0.5, 2 ) * scaleAdj;
                            mesh.scale.set( s, s, s );
                            mesh.position.set( x, 0, z );
                            mesh.rotation.y = THREE.Math.randFloat( -0.25, 0.25 );
                            mesh.matrixAutoUpdate = false;
                            mesh.updateMatrix();
                            scene.add( mesh );
                            info.innerHTML= '*not loaded count = ' + notLoadedCount;
                        }
                        clearInterval(processor);
                    }
                }, 100);

                //--------------------------------------
                scene.add( new THREE.AmbientLight( 0xffffff ) );
                // ground
                var textureLoader = new THREE.TextureLoader();
                var groundTexture = textureLoader.load(  "texture.jpg" );
                groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
                groundTexture.repeat.set( 40, 40 );
                groundTexture.anisotropy = 16;
                var groundMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, map: groundTexture } );
                var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial );
                mesh.position.y = 0;
                mesh.rotation.x = - Math.PI / 2;
                mesh.receiveShadow = true;
                scene.add( mesh );
                // Renderer
                renderer = new THREE.WebGLRenderer();
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                renderer.setClearColor( scene.fog.color );
                container.appendChild( renderer.domElement );
                // Events
                window.addEventListener( 'resize', onWindowResize, false );
            }

            function onWindowResize( event ) {
                renderer.setSize( window.innerWidth, window.innerHeight );
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
            }
            function animate() {
                requestAnimationFrame( animate );
                render();
            }
            function render() {
                renderer.render( scene, camera );
            }

        </script>
    </body>
</html>

谢谢你在这方面的帮助,希望它也能帮助其他人。如果有人注意到这项决议有任何问题,请告诉我。谢谢