首页 > 解决方案 > three.js - 为什么光线投射器无法识别加载的对象?

问题描述

我是 THREE.js 的新手。我想点击鼠标在场景中选择一个加载的 .obj 对象,然后突出显示它(变成半透明),然后移动鼠标,移动的对象跟随鼠标。当我再次单击鼠标时。对象颜色再次变回纯色,并停留在单击的位置。

我编写了以下代码,但光线投射器无法识别我单击了加载的对象,尽管它们已添加到对象数组中。

代码:

<html>
<head includeDefault="true">

  <script src="js/three.js"></script>
  <script src="js/PointerLockControls.js"></script>
  <script src="js/OBJLoader.js"></script>
  <script src="js/MTLLoader.js"></script>
  <script src="js/dat.gui.min.js"></script>
  <script src="js/stats.min.js"></script>
  <script src="js/OrbitControls.js"></script>
  </head>
<body>
    <script>
        var camera, scene, renderer, controls, ambient, cube, wuyun11, tempMateria11;
        var stats = initStats();
        var controlsEnabled=true;
        var step = 0;
        var speed = 10;
        var matArrayA=[];
        var moveForward=false;
        var moveBackward=false;
        var moveLeft=false;
        var moveRight=false;
        var group = new THREE.Group();
        var prevTime=performance.now();
        var velocity=new THREE.Vector3();
        var direction=new THREE.Vector3();
        var color=new THREE.Color();
              var params = {exposure: 1,};
              var Smogs111 = [];
              var SmogGeometry11;
              var SWtrue2 = false;
            var params1 = {
                wather3: function () {
                wather33();
                  },
                }
        var Basic_material = new THREE.MeshStandardMaterial();
        
        //the following variables are for moving objects
        var isSelected=false;
        var objects=[];
        var selectedObject;
        var newPosition;

        init();
        animate();
        function initGui() {
            gui = {
                ambientLight:"#111111",
                directionalLight:"#ffffff",
                intensity:1,
                debug:false,
                time:0,
                pause:false,
                speed:10
            };
            var datGui = new dat.GUI();
            datGui.add(gui,"time",0 ,1440).onChange(function (e) {
              time = e;
            });
            datGui.add(gui,"speed",0 ,100).onChange(function (e) {
              speed = e;
            });
            datGui.add(gui,"pause").onChange(function (e) {
              if(e){
                cancelAnimationFrame(id);
              }
              else{
                requestAnimationFrame(animate);
              }
            });
            datGui.addColor(gui,"ambientLight").onChange(function (e) {
              ambientLight.color = new THREE.Color(e);
            });
            datGui.addColor(gui,"directionalLight").onChange(function (e) {
              directionalLight.color = new THREE.Color(e);
            });
            datGui.add(gui,"intensity",0,5).onChange(function (e) {
              directionalLight.intensity = e;
            });
          }
        function init(){
            var ratio=window.innerWidth/window.innerHeight;
            //camera=new THREE.PerspectiveCamera(60,ratio,0.1,100000);
            var Pos=new THREE.Vector3(0,0,0);
            //camera.position.set(Pos.x,Pos.y,Pos.z);
            var Dir=new THREE.Vector3(0,0,1);
            //camera.lookAt(Dir.x,Dir.y,Dir.z);

            scene=new THREE.Scene();
            scene.fog = new THREE.Fog( scene.background, 3000, 5000 );

            renderer = new THREE.WebGLRenderer({antialias:true});
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setSize( window.innerWidth, window.innerHeight );
            renderer.setClearColor(0x4682B4,1);
            renderer.shadowMapEnabled = true;
            renderer.shadowMapSoft = true;

            document.body.appendChild( renderer.domElement );
            initCamera();
            initGui();
            loadHouse();
            //loadTree();
            loadTrees();
            //loadFountain();
            loadFences();
            //loadChar();
            initLight();
            createFloor();
            createWallMaterail();
            createCubeWall(10, 50, 1000, 0, matArrayA, -500, 25, 0, "Wall");
            createCubeWall(10, 50, 1000, 0, matArrayA, 500, 25, 0, "Wall");
            createCubeWall(10, 50, 1000, 0.5, matArrayA, 0, 25, -500, "Wall");
            createCubeWall(10, 50, 1000, 0.5, matArrayA, 0, 25, 500, "Wall");
            initControls();

            window.addEventListener('resize',onWindowResize,false);

            gui2 = new dat.GUI( { width: 350 } );
            gui2.add( params, 'exposure', 0, 1 );
            gui2.domElement.style = 'position:absolute;top:20px;left:0px;height: 350px';

            var generationFolder111 = gui2.addFolder('Wather');
            generationFolder111.close();
            var genBtn333 = generationFolder111.add(params1, 'wather3');
            genBtn333.name("winter");
        }
        function createFloor(){
            var loader = new THREE.TextureLoader();
            loader.load("img/grass-texture2.jpg",function(texture){
                texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
                texture.repeat.set( 16, 16 );
                var floorGeometry = new THREE.PlaneGeometry(1000, 1000);
                var floorMaterial = new THREE.MeshLambertMaterial( { map: texture } );// side: THREE.DoubleSide
                var floor = new THREE.Mesh(floorGeometry, floorMaterial);
                floor.receiveShadow = true;
                floor.castShadow = true;
                floor.position.y = 0;
                floor.rotation.x = -Math.PI / 2;
                floor.name = "floor";
                scene.add(floor);
            });
        }
        function initStats() {
            var stats = new Stats();

            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';

            document.body.appendChild(stats.domElement);
            return stats;
        }
        function onWindowResize(){
            camera.aspect=window.innerWidth/window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth,window.innerHeight);
        }
        function animate(){
            //requestAnimationFrame(animate);
            id = requestAnimationFrame(animate);
            movnigSun(directionalLight,speed * 0.0002);
            if(controlsEnabled==true){
                var time=performance.now();
                var delta=(time-prevTime)/1000;

                velocity.x-=velocity.x*10.0*delta;
                velocity.z-=velocity.z*10.0*delta;

                direction.z=Number(moveForward)-Number(moveBackward);
                direction.x=Number(moveLeft)-Number(moveRight);
                direction.normalize();

                if(moveForward || moveBackward) velocity.z-=direction.z*400.0*delta;
                if(moveLeft || moveRight) velocity.x-=direction.x*400.0*delta;

                //controls.getObject().translateX(velocity.x*delta);
                //controls.getObject().translateZ(velocity.z*delta);

                prevTime=time;
                stats.update();
            }
            if(cube){
                for (var i = 0; i < cube.material.length; i++) {
                    cube.material[i].color.setRGB(params.exposure,params.exposure,params.exposure);
                }
                //ambientLight.intensity = params.exposure
            }
            renderer.render(scene,camera);
          }
        function ItRains(){
            requestAnimationFrame( ItRains );
            for( var i=0; i<Smogs111.length; i++ ){
                          var ii = i+1;
            if( ii > 3 ){ ii = i/4; }
            if( ii < 10 ){ ii = 10*i; }
            Smogs111[i].position.y -= ii*0.0002;
            Smogs111[i].lookAt(camera.position);
            if( Smogs111[i].position.y < -40 ){
              Smogs111[i].position.y = 140;
            }
          }
        }
        function initCamera() {
            camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
            //camera.shadowCameraVisible = true;
            camera.position.set(0, 800, 1500);
            camera.lookAt(new THREE.Vector3(0, 0, 0));
        }
        function initControls() {
            controls = new THREE.OrbitControls( camera, renderer.domElement );
            controls.enableDamping = true;
            controls.dampingFactor = 0.5;
            controls.minDistance = 100;
            controls.maxDistance = 2000;
            controls.maxPolarAngle = Math.PI/2.2;
            //controls.enablePan = true;
        }
        function wather33(){
          if( SWtrue2 == false ){
                    for( var i=0; i<Smogs111.length; i++ ){
                        Smogs111[i].visible = true;
                    }
                            SWtrue2 = true;
          }else{
                    for( var i=0; i<Smogs111.length; i++ ){
                        Smogs111[i].visible = false;
                    }
                            SWtrue2 = false;
          }
        }
        function loadSkyBox(){
            const geometry=new THREE.CubeGeometry(10000,100,10000);

            const manager = new THREE.LoadingManager();
            const loader = new THREE.TextureLoader(manager);

            const tex1 = loader.load( 'img/sky2.jpg' );
            const tex2 = loader.load( 'img/sky2_new.jpg' );
            var texture = loader.load( 'img/grass-texture4.jpg' );
            const tex3 = loader.load( 'img/sky1.jpg' );

            texture.wrapS=THREE.RepeatWrapping;
            texture.wrapT=THREE.RepeatWrapping;
            texture.repeat.set(128,128);

            manager.onLoad = function() {

                const cubeMaterials= [
                    new THREE.MeshBasicMaterial({map:tex1, side:THREE.DoubleSide}), //left
                    new THREE.MeshBasicMaterial({map:tex1, side:THREE.DoubleSide}), //right
                    new THREE.MeshBasicMaterial({map:tex3, side:THREE.DoubleSide}), //up
                    new THREE.MeshBasicMaterial({map:texture, side:THREE.DoubleSide}), //down
                    new THREE.MeshBasicMaterial({map:tex2, side:THREE.DoubleSide}), //front
                    new THREE.MeshBasicMaterial({map:tex2, side:THREE.DoubleSide})  //back
                ];

                cube=new THREE.Mesh(geometry,cubeMaterials);
                scene.add(cube);

            }

            SmogGeometry11 = new THREE.PlaneBufferGeometry( 5, 5 );
            wuyun11 = new THREE.TextureLoader().load( "img/snowflake1.png" );
            tempMateria11 = new THREE.MeshBasicMaterial({map: wuyun11, transparent: true, opacity: 0.9, blending: THREE.AdditiveBlending, depthWrite: false, side: THREE.DoubleSide })
            for ( var i = 0; i < 200; i++ ) {
              for ( var j = 0; j < 200; j++ ) {
                Smogs11 = new THREE.Mesh( SmogGeometry11, tempMateria11 );
                              Smogs11.position.set( -50 + Math.random()*1080 * Math.sin( i * 0.4 ),70,-50 + Math.random()*1080 * Math.cos( j * 0.25 ));
                                  Smogs11.scale.set(0.1,0.1,0.1);
                                  Smogs11.visible=false;
                            scene.add( Smogs11 );
                              Smogs111.push(Smogs11);
              }
            }
            ItRains();
          }
        function loadHouse(){
            var mtlLoader=new THREE.MTLLoader();
            //mtlLoader.setTexturePath("model/house/");
            //mtlLoader.setPath("model/house/");
            mtlLoader.load(
                "model/house/house_10.mtl", function(materials){
                    materials.preload();
                    materials.materials["grass_ground"].transparent = true;
                      materials.materials["grass_ground"].opacity = 0;
                    materials.materials["roof_01"].color = new THREE.Color(0, 0.5, 1)
                    var objLoader=new THREE.OBJLoader();
                    objLoader.setMaterials(materials);
                    objLoader.load(
                        //resource url
                        "model/house/house_10.obj",
                        //called when resource is loaded
                        function(object){
                          object.traverse( function( child ) {
                            if ( child instanceof THREE.Mesh ) {
                              //child.material = Basic_material;
                              child.castShadow = true;
                              child.receiveShadow = true;
                        }
                      });
                            object.position.y=4;
                            object.position.z=-100;
                            object.scale.set(25,25,25);
                            scene.add(object);
                            objects.push(object);
                        },
                        //called when loading is in progresses
                        function(xhr){
                            console.log((xhr.loaded/xhr.total*100)+'% loaded');
                        },
                        //called when loading has errors
                        function (error){
                            console.log('An error happened'+error);
                        }
                    );
                }
            );
        }
        function loadTrees(){
          createTree(200,25,50);
          createTree(100,25,20);
          createTree(-100,25,30);
          createTree(50,25,100);
          createTree(-100,25,-200);
        }
        function createTree(x,y,z){
          var mtlLoader=new THREE.MTLLoader();
          mtlLoader.load(
              "model/tree1/shu.mtl", function(materials){
                  materials.preload();
                  materials.materials["dashuzhi"].transparent = true;
                  materials.materials["dashuzhi"].alphaTest = 0.7;
                  var objLoader=new THREE.OBJLoader();
                  objLoader.setMaterials(materials);
                  objLoader.load(
                      "model/tree1/shu.obj",
                      function(object){
                        object.traverse( function( child ) {
                            if ( child instanceof THREE.Mesh ) {
                              //child.material = Basic_material;
                              child.castShadow = true;
                              child.receiveShadow = true;
                            }
                          });
                          object.scale.set(0.1,0.1,0.1);
                          object.position.set(x,y,z);
                          scene.add(object);
                          objects.push(object);
                      },
                  );
              }
          );
        }
        function loadFences(){
          //左侧栅栏
          createFence(-300,0,-360,0);
          createFence(-300,0,-270,0);
          createFence(-300,0,-180,0);
          createFence(-300,0,-90,0);
          createFence(-300,0,0,0);
          createFence(-300,0,90,0);
          //右侧栅栏
          createFence(300,0,-360,0);
          createFence(300,0,-270,0);
          createFence(300,0,-180,0);
          createFence(300,0,-90,0);
          createFence(300,0,0,0);
          createFence(300,0,90,0);
          //前面栅栏
          createFence(-311.5,0,206,Math.PI/2);
          createFence(-221.5,0,206,Math.PI/2);
          // createFence(0,0,206,Math.PI/2);
          createFence(100,0,206,Math.PI/2);
          createFence(189.75,0,206,Math.PI/2);
          // createFence(0,0,180,Math.PI/2);

          //后面栅栏
          createFence(-311.5,0,-340,Math.PI/2);
          createFence(-221.5,0,-340,Math.PI/2);
          createFence(100,0,-340,Math.PI/2);
          createFence(189.75,0,-340,Math.PI/2);
        }
        function createFence(positionX,positionY,positionZ,rotationAngle){
            var mtlLoader=new THREE.MTLLoader();
            mtlLoader.load(
              "model/white-fence/Fence_White.mtl",function(materials){
                materials.preload();
                var objLoader=new THREE.OBJLoader();
                objLoader.setMaterials(materials);
                objLoader.load(
                  "model/white-fence/Fence_White.obj",function(object){
                    object.scale.set(1,1,1);
                    object.rotation.y=rotationAngle;
                    object.position.set(positionX,positionY,positionZ);
                    scene.add(object);
                  }
                )
              }
            )
        }
        function loadChar(){
            var mtlLoader=new THREE.MTLLoader();
            //mtlLoader.setTexturePath("model/house/");
            //mtlLoader.setPath("model/house/");
            mtlLoader.load(
                "model/char/Doll_for_fafa.mtl", function(materials){
                    materials.preload();
                    materials.setMaterials('blinn7SG');
                    //materials.materials["grass_ground"].opacity = 0;
                    //materials.materials["grass_ground"].color = new THREE.Color(0x00000, 1.0)
                    var objLoader=new THREE.OBJLoader();
                    objLoader.setMaterials(materials);
                    objLoader.load(
                        //resource url
                        "model/char/Doll_for_fafa.obj",
                        //called when resource is loaded
                        function(object){
                          object.traverse( function( child ) {
                            if ( child instanceof THREE.Mesh ) {
                              //child.material = Basic_material;
                              child.castShadow = true;
                              child.receiveShadow = true;
                        }
                      });
                            object.position.set(0,0,0)
                            object.scale.set(10,10,10);
                            scene.add(object);
                        },
                    );
                }
            );
        }
        function createCubeWall(width, height, depth, angle, material, x, y, z, name){
            var cubeGeometry = new THREE.BoxGeometry(width, height, depth );
            var cube = new THREE.Mesh( cubeGeometry, material );
            cube.castShadow = true;
            cube.receiveShadow = true;
            cube.position.x = x;
            cube.position.y = y;
            cube.position.z = z;
            cube.rotation.y += angle*Math.PI;
            cube.name = name;
            scene.add(cube);
        }
        function createWallMaterail(){
              matArrayA.push(new THREE.MeshPhongMaterial({color: 0xafc0ca}));  //前  0xafc0ca :灰色
              matArrayA.push(new THREE.MeshPhongMaterial({color: 0x9cb2d1}));  //后  0x9cb2d1:淡紫
              matArrayA.push(new THREE.MeshPhongMaterial({color: 0xd6e4ec}));  //上  0xd6e4ec: 偏白色
              matArrayA.push(new THREE.MeshPhongMaterial({color: 0xd6e4ec}));  //下
              matArrayA.push(new THREE.MeshPhongMaterial({color: 0xafc0ca}));  //左   0xafc0ca :灰色
              matArrayA.push(new THREE.MeshPhongMaterial({color: 0xafc0ca}));  //右

        }
        function initLight() {
            directionalLight = new THREE.DirectionalLight( 0xffffff, 0.9 );//模拟远处类似太阳的光源
            var target = new THREE.Object3D();
            target.position.set(0, 0, 0);
            scene.add(target);
            directionalLight.position.set( 500, 500, 0);
            directionalLight.castShadow = true;
            directionalLight.color.setHSL( 0.1, 1, 0.95 );
            directionalLight.shadow.camera.near = 10;
            directionalLight.shadow.camera.far = 1500;
            directionalLight.shadow.camera.left = -500;
            directionalLight.shadow.camera.right = 500;
            directionalLight.shadow.camera.top = 600;
            directionalLight.shadow.camera.bottom = -600;
            directionalLight.shadowCameraVisible = true;
            directionalLight.target = target;
            directionalLight.shadow.mapSize.height = 4096;
            directionalLight.shadow.mapSize.width = 4096;
            scene.add( directionalLight) ;
            var helper = new THREE.CameraHelper(directionalLight.shadow.camera);
            scene.add(helper);
            ambientLight = new THREE.AmbientLight( 0xFFFFFF, 0.1 ); //AmbientLight,影响整个场景的光源
            ambientLight.position.set(0,0,0);
            scene.add( ambientLight );
        }
        function movnigSun(obj,speed){
          step += speed;
          obj.position.x = 750*(Math.cos(step));
          obj.position.y = 750*(Math.sin(step));
          //obj.target.updateMatrixWorld();
        }

        document.addEventListener('mousedown',onDocumentMouseDown);

        function onDocumentMouseDown(e){
            e.preventDefault();

            var vector=new THREE.Vector3((e.clientX/window.innerWidth)*2-1,-(e.clientY/window.innerHeight)*2+1,0.5).unproject(camera);
            var raycaster=new THREE.Raycaster(camera.position,vector.sub(camera.position).normalize());

            var intersects=raycaster.intersectObjects(objects);
            console.log('imtersrcts'+intersects);
            if(intersects.length>0)
            {
                if(isSelected==false)
                {
                    console.log(isSelected);
                    selectedObject=intersects[0].object;
                    selectedObject.material.color=new THREE.Color(0xff0000);
                    
                    console.log(selectedObject);
                    console.log(selectedObject.position);
                    isSelected=true;
                }
                else if(isSelected==true)
                {
                    console.log(selectedObject);
                    console.log(isSelected);
                    selectedObject.material.color=new THREE.Color(0x00ff00);
                    selectedObject.position.set(-10,0,1);
                    isSelected=false;
                }
                
                // selectedObject.position.x-=10;
                //selectedObject.position.set(50,0,0);
                
            }
          }

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

标签: javascriptthree.js

解决方案


我建议在 three.js 中尝试这种更常见的光线投射语法

      var mouse = new THREE.Vector2();
      var raycaster = new THREE.RayCaster();
      mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
      mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
      raycaster.setFromCamera(mouse, camera);

      var intersects = raycaster.intersectObjects(objects);

如果您仍然遇到问题,请确保您的所有网格都可见,因为 three.js 光线投射不会检测到具有 visible=false 的网格


推荐阅读