1. 程式人生 > >THREE.JS 場景世界座標和平面二維座標互轉

THREE.JS 場景世界座標和平面二維座標互轉

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>場景世界座標轉</title>
    <style type="text/css">
        html, body {
            margin: 0;
            height: 100%;
        }

        canvas {
            display: block;
        }

        .title{
            position: absolute;
            padding: 10px;
            background: rgba(255, 255, 255, 0.5);
            line-height: 1;
            border-radius: 5px;
        }

    </style>
</head>

<body onload="draw();">

<div class="title one">第一個盒子</div>
<div class="title two">第二個盒子</div>
<div class="title three">第三個盒子</div>

</body>

<script src="https://cdn.bootcss.com/three.js/91/three.min.js"></script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="/lib/js/controls/OrbitControls.js"></script>
<script src="/lib/js/libs/stats.min.js"></script>
<script src="https://cdn.bootcss.com/dat-gui/0.7.1/dat.gui.min.js"></script>
<script src="/lib/js/Detector.js"></script>

<script>
    var renderer, camera, scene, gui, light, stats, controls;
    var cube, cube2, cube3;

    function initRender() {
        renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0xeeeeee);
        renderer.shadowMap.enabled = true;
        //告訴渲染器需要陰影效果
        document.body.appendChild(renderer.domElement);
    }

    function initCamera() {
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 0, 15 );
    }

    function initScene() {
        //給場景新增天空盒子紋理
        var cubeTextureLoader = new THREE.CubeTextureLoader();
        cubeTextureLoader.setPath( '/lib/textures/cube/space/' );
        //六張圖片分別是朝前的(posz)、朝後的(negz)、朝上的(posy)、朝下的(negy)、朝右的(posx)和朝左的(negx)。
        var cubeTexture = cubeTextureLoader.load( [
            'right.jpg', 'left.jpg',
            'top.jpg', 'bottom.jpg',
            'front.jpg', 'back.jpg'
        ] );

        scene = new THREE.Scene();

        scene.background = cubeTexture;
    }

    //初始化dat.GUI簡化試驗流程
    function initGui() {
        //宣告一個儲存需求修改的相關資料的物件
        gui = {
        };
        var datGui = new dat.GUI();
        //將設定屬性新增到gui當中,gui.add(物件,屬性,最小值,最大值)
    }

    function initLight() {
        scene.add(new THREE.AmbientLight(0x444444));

        light = new THREE.DirectionalLight(0xffffff);
        light.position.set(0, 20, 20 );

        light.castShadow = true;
        light.shadow.camera.top = 10;
        light.shadow.camera.bottom = -10;
        light.shadow.camera.left = -10;
        light.shadow.camera.right = 10;

        //告訴平行光需要開啟陰影投射
        light.castShadow = true;

        scene.add(light);
    }

    function initModel() {

        //輔助工具
        var helper = new THREE.AxesHelper(50);
        scene.add(helper);

        var material = new THREE.MeshStandardMaterial({color:0x00ffff});

        //新增立方體
        var geometry = new THREE.BoxBufferGeometry( 1, 1, 1 );

        //新增第一個
        cube = new THREE.Mesh(geometry, material);
        scene.add(cube);

        //新增第二個
        cube2 = new THREE.Mesh(geometry, material);
        cube2.position.set(3, 3, -2);
        scene.add(cube2);

        //新增第三個
        cube3 = new THREE.Mesh(geometry, material);
        cube3.position.set(-3, 3, 2);
        scene.add(cube3);

    }

    //初始化效能外掛
    function initStats() {
        stats = new Stats();
        document.body.appendChild(stats.dom);
    }

    function initControls() {

        controls = new THREE.OrbitControls(camera, renderer.domElement);
        //設定控制器的中心點
        //controls.target.set( 0, 5, 0 );
        // 如果使用animate方法時,將此函式刪除
        //controls.addEventListener( 'change', render );
        // 使動畫迴圈使用時阻尼或自轉 意思是否有慣性
        controls.enableDamping = true;
        //動態阻尼係數 就是滑鼠拖拽旋轉靈敏度
        //controls.dampingFactor = 0.25;
        //是否可以縮放
        controls.enableZoom = true;
        //是否自動旋轉
        controls.autoRotate = false;
        controls.autoRotateSpeed = 0.5;
        //設定相機距離原點的最遠距離
        controls.minDistance = 1;
        //設定相機距離原點的最遠距離
        controls.maxDistance = 2000;
        //是否開啟右鍵拖拽
        controls.enablePan = true;
    }

    //每幀額外的運算
    function render() {
        //獲取到視窗的一半高度和一半寬度
        let halfWidth = window.innerWidth / 2;
        let halfHeight = window.innerHeight / 2;

        let vector1 = cube.position.clone().project(camera);
        let vector2 = cube2.position.clone().project(camera);
        let vector3 = cube3.position.clone().project(camera);

        //修改第一個的div的位置
        $(".one").css({
            left:vector1.x * halfWidth + halfWidth,
            top:-vector1.y * halfHeight + halfHeight
        });


        $(".two").css({
            left:vector2.x * halfWidth + halfWidth,
            top:-vector2.y * halfHeight + halfHeight
        });


        $(".three").css({
            left:vector3.x * halfWidth + halfWidth,
            top:-vector3.y * halfHeight + halfHeight
        });

    }

    //視窗變動觸發的函式
    function onWindowResize() {

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

    }

    function animate() {
        //每幀額外的運算
        render();

        //更新效能外掛
        stats.update();

        controls.update();

        renderer.render(scene, camera);

        requestAnimationFrame(animate);
    }

    function draw() {
        //相容性判斷
        if (!Detector.webgl) Detector.addGetWebGLMessage();
        initGui();
        initRender();
        initScene();
        initCamera();
        initLight();
        initModel();
        initControls();
        initStats();

        animate();
        window.onresize = onWindowResize;
    }


</script>
</html>