在三个js中防止物体移动到房间外

  • 本文关键字:移动 房间 js 三个 three.js
  • 更新时间 :
  • 英文 :


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

http://istation-demo.cladev.com/room.html

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

然后,要对所有这些框执行碰撞检测,请调用 boundingBoxHelperObject.box.intersectsBox( anotherBoxHelperObject.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>

希望这对你有用!:)

最新更新