Three.js 防止物体以三种方式移出房间

Three.js 防止物体以三种方式移出房间,three.js,Three.js,我在三个js中创建了一个房间,并在其中添加了各种对象。但是 物体正在移出房间。以下是运行我的代码的url: 为了防止物体离开房间或相互碰撞,您必须至少有一种简单的碰撞检测形式。大多数3D引擎(包括three.js)都有用于创建的所有3D对象的轴对齐边界框(或AABB)。在three.js中,要访问边界框,最简单的方法是调用 var BoundingBoxHelper对象=新的三个。BoundingBoxHelper(对象) 如果将其添加到场景中,它将显示为一个线框灰色框,紧紧围绕对象。如果在辅助

我在三个js中创建了一个房间,并在其中添加了各种对象。但是 物体正在移出房间。以下是运行我的代码的url:


为了防止物体离开房间或相互碰撞,您必须至少有一种简单的碰撞检测形式。大多数3D引擎(包括three.js)都有用于创建的所有3D对象的轴对齐边界框(或AABB)。在three.js中,要访问边界框,最简单的方法是调用
var BoundingBoxHelper对象=新的三个。BoundingBoxHelper(对象)
如果将其添加到场景中,它将显示为一个线框灰色框,紧紧围绕对象。如果在辅助对象上调用update(稍后将看到),它将实时更新三维对象的尺寸和移动-非常酷

然后,要对所有这些框执行碰撞检测,请调用
boundingBoxHelperObject.box.intersectsBox(另一个boxhelperobject.box)

碰撞时输出true,不碰撞时输出false。然后执行适当的操作,例如将长方体移回框架以防止其逃出房间或穿透另一个实体对象,或更改两个碰撞对象的颜色,或执行任何您想要的操作

下面是最后一个代码示例,其中包含我在几个月前的最后一篇文章中更正的拾取/拖动代码,以及新的边界框和碰撞测试代码:

    <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html">
<head lang="en">
    <meta charset="UTF-8">
    <title>Room</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r75/three.js"></script>
<script src="http://alexan0308.github.io/threejs/examples/js/loaders/OBJLoader.js"></script>
<script src="http://alexan0308.github.io/threejs/examples/js/loaders/MTLLoader.js"></script>
<script src="http://alexan0308.github.io/threejs/examples/js/loaders/OBJMTLLoader.js"></script>


<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>

<div id="workspace"></div>
<script>
    //define global variables here
    var container, renderer;
    var camera, scene, projector, mouseVector, controls;
    var mouseX, mouseY, draggable;
    var pen, c_mesh, interactiveObj = [], rotateObj = [], groundRaycastObj = [];
    var wallWidth = 1200;
    var wallHeight = 400;
    var chair_model, sofa_model;
    var chair_selected = false;
    var sofa_selected = false;

    var raycaster;
    var mouse = new THREE.Vector2(), INTERSECTED;
    var radius = 100, theta = 0;
    var oldIntersectPoint = new THREE.Vector3();
    var newIntersectPoint = new THREE.Vector3(); 
    var intersectOffset   = new THREE.Vector3();
    var chairOldPosition = new THREE.Vector3();
    var sofaOldPosition = new THREE.Vector3();

    var chair_rotate = false;
    var walls;
    var mesh_box;
    var wallright, wallleft, wallback, wallfront, ceiling, ground;
    var strDownloadMime = "image/octet-stream";
    var chairBox, sofaBox;
    var wallrightBox, wallleftBox, wallbackBox, wallfrontBox;

    init();
    animate();

    function init() {

        container = document.getElementById('workspace'); //document.createElement('div');

        document.body.appendChild(container);

        //camera
        //camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 10, 10000);
       // camera.position.set(0, -wallHeight / 2 + 10, wallWidth);
        //  camera.lookAt(new THREE.Vector3(10, 10, 10));

        //renderer
        renderer = new THREE.WebGLRenderer({preserveDrawingBuffer: true});
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0x889988);
        renderer.shadowMapEnabled = true;
        container.appendChild(renderer.domElement);

        scene = new THREE.Scene();
        raycaster = new THREE.Raycaster();

        var ambient = new THREE.AmbientLight(0xffffff);
        scene.add(ambient);

        camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );

        camera.position.z= wallWidth;
        camera.position.y= wallWidth/2;


        controls = new THREE.OrbitControls( camera, renderer.domElement );
                //controls.addEventListener( 'change', render ); // add this only if there is no animation loop (requestAnimationFrame)
                controls.enableDamping = true;
                controls.dampingFactor = 0.25;
                //controls.enableZoom = false;



        //walls
        walls = new THREE.Object3D();


        var groundGeo_2 = new THREE.PlaneGeometry(wallWidth, wallWidth); //for roof and floor
        var groundGeo = new THREE.PlaneGeometry(wallWidth, wallHeight);

        var wallTextureRight = new THREE.MeshBasicMaterial({
            map: THREE.ImageUtils.loadTexture('textures/walls/rainbow.jpg')
        });
        wallTextureRight.map.needsUpdate = true;

        var wallTextureLeft = new THREE.MeshBasicMaterial({
            map: THREE.ImageUtils.loadTexture('textures/walls/rainbow.jpg')
        });

        var wallTextureFront = new THREE.MeshBasicMaterial({
            map: THREE.ImageUtils.loadTexture('textures/walls/wall4.jpg')
        });

        var wallTextureBack = new THREE.MeshBasicMaterial({
            map: THREE.ImageUtils.loadTexture('textures/walls/wall3.png')
        });

        var floorTexture = new THREE.MeshBasicMaterial({
            map: THREE.ImageUtils.loadTexture('textures/walls/floor.jpg')
        });
        floorTexture.map.needsUpdate = true;

        var ceilTexture = new THREE.MeshBasicMaterial({
            map: THREE.ImageUtils.loadTexture('textures/walls/wall4.jpg')
        });

        ground = new THREE.Mesh(groundGeo_2, floorTexture);
        ground.overdraw = true;
        ground.position.set(0, 0, 0);
        ground.rotation.x = -Math.PI / 2;
        walls.add(ground);
        console.log(ground);

        wallleft = new THREE.Mesh(groundGeo, wallTextureLeft);
        wallleft.overdraw = true;
        wallleft.position.set(-wallWidth / 2, wallHeight / 2, 0);
        wallleft.rotation.y = Math.PI / 2;
        walls.add(wallleft);

        wallleftBox = new THREE.BoundingBoxHelper( wallleft );
        wallleftBox.update(wallleft);
            //wallleftBox.box.min.x -= 0.1;
        //wallleftBox.box.max.x += 0.1;
        //scene.add(wallleftBox);

        wallright = new THREE.Mesh(groundGeo, wallTextureRight);
        wallright.overdraw = true;
        wallright.position.set(wallWidth / 2, wallHeight / 2, 0);
        wallright.rotation.y = -Math.PI / 2;
        walls.add(wallright);

        wallrightBox = new THREE.BoundingBoxHelper( wallright );
        wallrightBox.update(wallright);
            //wallrightBox.box.min.x -= 0.1;
        //wallrightBox.box.max.x += 0.1;
        //scene.add(wallrightBox);

        wallback = new THREE.Mesh(groundGeo, wallTextureBack);
        wallback.overdraw = true;
        wallback.position.set(0, wallHeight / 2, -wallWidth / 2);
        walls.add(wallback);

        wallbackBox = new THREE.BoundingBoxHelper( wallback );
        wallbackBox.update(wallback);
        //scene.add(wallbackBox);

        wallfront = new THREE.Mesh(groundGeo, wallTextureFront);
        wallfront.overdraw = true;
        wallfront.position.set(0, wallHeight / 2, wallWidth / 2);
        wallfront.rotation.y = -Math.PI;
        walls.add(wallfront);

        wallfrontBox = new THREE.BoundingBoxHelper( wallfront );
        wallfrontBox.update(wallfront);
        //scene.add(wallfrontBox);



        ceiling = new THREE.Mesh(groundGeo_2, ceilTexture);
        ceiling.position.set(0, wallHeight, 0);
        ceiling.rotation.x = Math.PI / 2;
        walls.add(ceiling);

        scene.add(walls);

        groundRaycastObj.push(walls);

        //load bed texture
        var bed_texture = new THREE.ImageUtils.loadTexture("textures/cb-rochelle-gray_baked.png");
        var bedMaterial = new THREE.MeshBasicMaterial({
            map: bed_texture,
            side: THREE.DoubleSide
        });

        //load bed
        var loader = new THREE.JSONLoader();
        loader.load('js/sofa.js', function (geometry) {
            sofa_model = new THREE.Mesh(geometry, bedMaterial);
            for (var i = 0; i < sofa_model.children.length; i++) {
                sofa_model.children[i].material = material;
                sofa_model.children[i].userDataParent = sofa_model;
                sofa_model.children[i].name = 'sofa_model';
            }
            sofa_model.position.set(200,0, -200);
            sofa_model.rotation.set(0, 0, 0);
            sofa_model.scale.set(3, 3, 3);
            sofa_model.name = 'sofa_model';
            interactiveObj.push(sofa_model);
            scene.add(sofa_model);

        sofaBox = new THREE.BoundingBoxHelper( sofa_model );

            // comment next line out if you don't want to see the wireframe sofa boxHelper
            scene.add(sofaBox);

        });


         //load chair texture
        var chair_texture = new THREE.ImageUtils.loadTexture("textures/chair.png");
        var chairMaterial = new THREE.MeshBasicMaterial({
            map: chair_texture,
            side: THREE.DoubleSide
        });

        //load chair
        var loader = new THREE.JSONLoader();
        loader.load('js/chair_model.js', function (geometry) {
            chair_model = new THREE.Mesh(geometry, chairMaterial);
            for (var i = 0; i < chair_model.children.length; i++) {
                chair_model.children[i].material = material;
                chair_model.children[i].userDataParent = sofa_model;
                chair_model.children[i].name = 'chair_model';
            }
            chair_model.position.set(-300,0, -200);
            chair_model.rotation.set(0, 0, 0);
            chair_model.scale.set(3, 3, 3);
            chair_model.name = 'chair_model';
            interactiveObj.push(chair_model);
            scene.add(chair_model);

        chairBox = new THREE.BoundingBoxHelper( chair_model );

        // comment next line out if you don't want to see the wireframe chair boxHelper
            scene.add(chairBox);

        });



        //IE, Chrome, Safari, Opera
        document.addEventListener('mousewheel', onDocumentMouseWheel, false);
        //Firefox
        document.addEventListener('DOMMouseScroll', onDocumentMouseWheel, false);
        document.addEventListener('mousemove', onDocumentMouseMove, false);
        document.addEventListener('mousedown', onDocumentMouseDown, false);
        document.addEventListener('mouseup', onDocumentMouseUp, false);
        window.addEventListener('resize', onWindowResize, false);

    }
    function animate() {

        requestAnimationFrame(animate);

        chair_model.rotation.y += 0.02;

    chairBox.update(chair_model);
    sofaBox.update(sofa_model);
    //wallrightBox.update(wallright);
    //wallleftBox.update(wallleft);
    //wallfrontBox.update(wallfront);
    //wallbackBox.update(wallback);



        controls.update();

        // Render the frame
        //Don't render twice, it will slow down your animation!
        //render();
        renderer.render(scene, camera);

    }

    function render() {

        renderer.render(scene, camera);
    }



    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);

        //controls.handleResize();

    }

    function onDocumentMouseDown(event) {
        draggable = true;
        event.preventDefault();

    var testIntersects;
        testIntersects = raycaster.intersectObjects(groundRaycastObj, true);
        if (testIntersects.length > 0)
            oldIntersectPoint.copy(testIntersects[0].point);

        // find intersections
        raycaster.setFromCamera(mouse, camera);
        var intersects = raycaster.intersectObjects(interactiveObj, true);
        if (intersects.length > 0) {
            controls.enabled=false;

            if (intersects[0].object.name == 'chair_model') {
                container.style.cursor = 'pointer';
                chair_selected = true;
            //oldIntersectPoint.copy(chair_model.position);
        chairBox.material.color.set('white');
            } else if (intersects[0].object.name == 'sofa_model') {
                container.style.cursor = 'pointer';
                sofa_selected = true;
            //oldIntersectPoint.copy(sofa_model.position);
        sofaBox.material.color.set('white');
            }
            else {
                chair_selected = false;
                sofa_selected = false;
            }
            draggable = false;
        }

    }

    function onDocumentMouseUp(event) {
        draggable = false;
        chair_selected = false;
        sofa_selected = false;
        chair_rotate = false;
        container.style.cursor = 'auto';
        controls.enabled=true;

    oldIntersectPoint.set(0,0,0);
    newIntersectPoint.set(0,0,0);
        intersectOffset.set(0,0,0);

    chairBox.material.color.set('grey');
    sofaBox.material.color.set('grey');
    }


    function onDocumentMouseMove(event) {

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

        var deltaX = event.clientX - mouseX;
        var deltaY = event.clientY - mouseY;

        var testIntersects;

        raycaster.setFromCamera(mouse, camera);
        var intersects = raycaster.intersectObjects(interactiveObj, true);

        if (intersects.length > 0) {
            container.style.cursor = 'pointer';
            //addRotationLine(intersects[0].object);

        } else {
            container.style.cursor = 'auto';
        }

        if (draggable) {

        } else if (chair_selected == true) {

                testIntersects = raycaster.intersectObjects(groundRaycastObj, true);
                if (testIntersects.length > 0) {

            var okToMove = true;

            chairOldPosition.copy(chair_model.position);

            newIntersectPoint.copy(testIntersects[0].point);

            intersectOffset.copy(newIntersectPoint);
                intersectOffset.sub(oldIntersectPoint);
            //uncomment below if you want more precision mouse movements of objects
            //intersectOffset.multiplyScalar(0.1);
            // store old intersect point for next frame
            oldIntersectPoint.copy(newIntersectPoint);

                        chair_model.position.add(intersectOffset);
            chair_model.updateMatrixWorld(true);
            //chairBox.updateMatrixWorld(true);
            chairBox.update(chair_model);

            // default
            chairBox.material.color.set('white');   

            if( chairBox.box.intersectsBox(sofaBox.box) ) {
                okToMove = false;
                chairBox.material.color.set('red');
            }
            else if( chairBox.box.intersectsBox(wallrightBox.box) ) {
                okToMove = false;
                chairBox.material.color.set('red');
            }
            else if( chairBox.box.intersectsBox(wallleftBox.box) ) {
                okToMove = false;
                chairBox.material.color.set('red');
            }
            else if( chairBox.box.intersectsBox(wallfrontBox.box) ) {
                okToMove = false;
                chairBox.material.color.set('red');
            }
            else if( chairBox.box.intersectsBox(wallbackBox.box) ) {
                okToMove = false;
                chairBox.material.color.set('red');
            }

            // if NOT ok to move and chair is hitting something,
            if ( !okToMove ) {
                // put chair back where it was
                chair_model.position.copy(chairOldPosition);
            }


                }
                // clamp chair position to the ground
                chair_model.position.y = 0;

        } else if (chair_rotate == true) {
            rotate_object(chair_model, event);
        }
        else if (sofa_selected == true) {
            testIntersects = raycaster.intersectObjects(groundRaycastObj, true);
                if (testIntersects.length > 0) {

            var okToMove = true;

            sofaOldPosition.copy(sofa_model.position);

            newIntersectPoint.copy(testIntersects[0].point);

            intersectOffset.copy(newIntersectPoint);
                intersectOffset.sub(oldIntersectPoint);
            //uncomment below if you want more precision mouse movements of objects
            //intersectOffset.multiplyScalar(0.1);
                    oldIntersectPoint.copy(newIntersectPoint);
                        sofa_model.position.add(intersectOffset);

            sofa_model.updateMatrixWorld(true);
            //sofaBox.updateMatrixWorld(true);
            sofaBox.update(sofa_model);

            // default
            sofaBox.material.color.set('white');    

            if( sofaBox.box.intersectsBox(chairBox.box) ) {
                okToMove = false;
                sofaBox.material.color.set('red');
            }
            else if( sofaBox.box.intersectsBox(wallrightBox.box) ) {
                okToMove = false;
                sofaBox.material.color.set('red');
            }
            else if( sofaBox.box.intersectsBox(wallleftBox.box) ) {
                okToMove = false;
                sofaBox.material.color.set('red');
            }
            else if( sofaBox.box.intersectsBox(wallfrontBox.box) ) {
                okToMove = false;
                sofaBox.material.color.set('red');
            }
            else if( sofaBox.box.intersectsBox(wallbackBox.box) ) {
                okToMove = false;
                sofaBox.material.color.set('red');
            }

            // if NOT ok to move and sofa is hitting something,
            if ( !okToMove ) {
                // put sofa back where it was
                sofa_model.position.copy(sofaOldPosition);
            }

                }
                // clamp sofa position to the ground
                sofa_model.position.y = 0;
        }
        mouseX = event.clientX;
        mouseY = event.clientY;
        //render(); // no need to render
    }

    function onDocumentMouseWheel(event) {
        // This is automatically handled for you by orbitControls.js, 
        // but you can't disable zoom on the controls - so don't type controls.enableZoom = false;

        //mouseDelta = (-event.wheelDeltaY || event.detail);
        //camera.position.z += mouseDelta * 1;
        //render(); // no need to render
    }

    function addRotationLine(objModel) {
        var material = new THREE.LineBasicMaterial({
            color: 0x0000ff,
            linewidth: 6
        });
        var geometry = new THREE.Geometry();
        geometry.vertices.push(
                new THREE.Vector3(-10, 500, 0),
                new THREE.Vector3(1000, 500, 0)
        );
        var line = new THREE.Line(geometry, material);
        objModel.add(line);
    }
    function rotate_object(object, event) {
        mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
        mouse.y = -( event.clientY / window.innerHeight ) * 2 + 1;
        var deltaX = event.clientX - mouseX;
        var deltaY = event.clientY - mouseY;

        object.rotation.y += deltaX * 0.02;
        object.rotation.y += deltaY * 0.01;
    }


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

房间
//在这里定义全局变量
var容器,渲染器;
var摄像机、场景、投影仪、鼠标器、控件;
var mouseX,mouseY,可拖动;
var pen,c_mesh,interactiveObj=[],rotateObj=[],groundRaycastObj=[];
var墙宽=1200;
var墙高=400;
var椅子模型、沙发模型;
选择的变量=false;
所选变量=false;
var raycaster;
var mouse=new THREE.Vector2(),相交;
var半径=100,θ=0;
var oldIntersectPoint=new THREE.Vector3();
var newIntersectPoint=new THREE.Vector3();
var intersectOffset=new THREE.Vector3();
var chairOldPosition=new THREE.Vector3();
var sofaolposition=new THREE.Vector3();
var chair_rotate=false;
var墙;
var网格盒;
var墙右、墙左、墙后、墙前、天花板、地面;
var strDownloadMime=“image/octet-stream”;
索法博克斯var chairBox;
var wallrightBox、wallleftBox、wallbackBox、wallfrontBox;
init();
制作动画();
函数init(){
container=document.getElementById('workspace');//document.createElement('div');
文件.正文.附件(容器);
//摄像机
//摄像头=新的三个透视摄像头(60,window.innerWidth/window.innerHeight,10,10000);
//摄像机位置设置(0,-墙高/2+10,墙宽);
//摄像机。观察(新的三个。矢量3(10,10,10));
//渲染器
renderer=new THREE.WebGLRenderer({preserveDrawingBuffer:true});
renderer.setSize(window.innerWidth、window.innerHeight);
renderer.setClearColor(0x889988);
renderer.shadowMapEnabled=true;
container.appendChild(renderer.domeElement);
场景=新的三个。场景();
raycaster=new-THREE.raycaster();
var环境光=新的三个环境光(0xffffff);
场景。添加(环境光);
摄像头=新的三个透视摄像头(60,window.innerWidth/window.innerHeight,11000);
camera.position.z=墙宽;
摄像头位置y=墙宽/2;
控件=新的三个.轨道控件(摄影机、渲染器.doElement);
//controls.addEventListener('change',render);//仅当没有动画循环(requestAnimationFrame)时添加此选项
controls.enableDamping=true;
控制。阻尼系数=0.25;
//controls.enableZoom=false;
//墙
墙=新的三个。Object3D();
var groundGeo_2=新的三个平面几何图形(墙宽、墙宽);//用于屋顶和地板
var groundGeo=新的三个平面几何图形(墙宽、墙高);
var wallTextureRight=新的三网格基本材质({
map:THREE.ImageUtils.loadTexture('textures/walls/rainbow.jpg'))
});
wallTextureRight.map.needsUpdate=true;
var wallTextureLeft=新的三网格基本材质({
map:THREE.ImageUtils.loadTexture('textures/walls/rainbow.jpg'))
});
var wallTextureFront=新的三网格基本材质({
map:THREE.ImageUtils.loadTexture('textures/walls/wall4.jpg'))
});
var wallTextureBack=新的三网格基本材质({
map:THREE.ImageUtils.loadTexture('textures/walls/wall3.png'))
});
var floorTexture=新的三网格基本材质({
map:THREE.ImageUtils.loadTexture('textures/walls/floor.jpg'))
});
floorTexture.map.needsUpdate=true;
var ceilTexture=新的三网格基本材质({
map:THREE.ImageUtils.loadTexture('textures/walls/wall4.jpg'))
});
地面=新的三层网格(地面geo_2,地板结构);
ground.overdraw=真;
地面位置设置(0,0,0);
ground.rotation.x=-Math.PI/2;
墙壁。添加(地面);
控制台。日志(地面);
wallleft=新的三个网格(groundGeo、wallTextureLeft);
wallleft.overdraw=真;
wallleft.position.set(-wallWidth/2,wallHeight/2,0);
wallleft.rotation.y=Math.PI/2;
墙。添加(墙左);
wallleftBox=新的三个.BoundingBoxHelper(wallleft);
更新(wallleft);
//wallleftBox.box.min.x-=0.1;
//wallleftBox.box.max.x+=0.1;
//添加(wallleftBox);
wallright=新的三个网格(groundGeo、wallTextureRight);
wallright.overdraw=真;
wallright.position.set(墙宽/2,墙高/2,0);
墙