1. 程式人生 > >three.js 帶更新文字的旋轉地球

three.js 帶更新文字的旋轉地球

檢視旋轉地球效果

主要用到幾個知識點

(1)顯示文字是使用了three.js 的精靈(Sprite),精靈的文字方向始終面向相機,文字是在canvas中畫的,精靈的材質就是載入的帶有文字的canvas

	function showText(){
	  const canvas = document.getElementById("canvas");
	  const ctx = canvas.getContext("2d");
	  ctx.canvas.width =256;
	  const x =0;
	  const y=32;
	  ctx.fillStyle = "red";
	  ctx.font = "30px arial";
	  ctx.textAlign = "left";
	  ctx.textBaseline = "middle";
	  ctx.fillText(text,x,y)
	}
	
	var sprite
	function showSprite(){
	  showText()
	  const canvasTexture = new THREE.CanvasTexture(
	    document.querySelector("#canvas")
	  )
	 
	  const spritMaterial = new THREE.SpriteMaterial({
	    map:canvasTexture
	  })
	  sprite = new THREE.Sprite(spritMaterial)
	  sprite.position.set(-280,0,0);
	  //精靈的預設大小很小估計是[1,1,1]
	  sprite.scale.set(0.64*256,0.64*64,1);
	  scene.add(sprite)
	}

(2)文字更新的方法是為canvas的文字重新賦值,並在動畫中移除上次載入的精靈,否則精靈會重疊

scene.remove(sprite)

(3)視窗變化時自適應

	window.addEventListener("resize", onWindowResize, false);
	
	function onWindowResize() {   
	    width = document.getElementById('canvas-frame').clientWidth;
        height = document.getElementById('canvas-frame').clientHeight;
	    camera.aspect = width / height;   
	    camera.updateProjectionMatrix();    
	    renderer.setSize(width, height);
	}

完整程式碼

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>旋轉地球</title>
    <script src="assets/plus/threejs/three.min.js"></script>
    <script src="assets/plus/threejs/js/controls/OrbitControls.js"></script>
    <script src="assets/plus/threejs/js/libs/stats.min.js"></script>
    <style type="text/css">
        body {
            margin: 0px;
        }

        div#canvas-frame {
            border: none;
            cursor: pointer;
            width: 80%;
			margin:0 auto;
            height:100vh;
            background-color: #EEEEEE;
        }

        img {
            width: 0px;
            height: 0px;
            opacity: 0;
        }
    </style>
</head>

<body>
    <canvas id="canvas" width="64" height="64" style="display:none;"></canvas>
    <!-- 存放canvas的容器 -->
    <div id="canvas-frame"></div>
</body>

<script>

    document.addEventListener('DOMContentLoaded', function () {
        threeStart();
    })

	var text = "first text";
	function showText(){
	  const canvas = document.getElementById("canvas");
	  const ctx = canvas.getContext("2d");
	  ctx.canvas.width =256;
	  const x =0;
	  const y=32;
	  ctx.fillStyle = "red";
	  ctx.font = "30px arial";
	  ctx.textAlign = "left";
	  ctx.textBaseline = "middle";
	  ctx.fillText(text,x,y)
	}

    // 渲染器
    var renderer;
	var width, height;
    function initThree() {
        width = document.getElementById('canvas-frame').clientWidth;
        height = document.getElementById('canvas-frame').clientHeight;
        renderer = new THREE.WebGLRenderer({
            antialias: true,
            alpha: true,
            canvas: renderer
        });
        renderer.setSize(width, height);
        document.getElementById('canvas-frame').appendChild(renderer.domElement);
        renderer.setClearColor(0x000000, 1.0);
    }

    // 相機
    var camera;
    function initCamera() {
        // 透視相機 視角越大,看到的場景越大,那麼中間的物體相對於整個場景來說,就越小了
        camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
        camera.position.x = 0;
        camera.position.y = 0;
        camera.position.z = 700;
        //camera.lookAt({ x: 0, y: 0, z: 0 });
    }

    // 場景
    var scene;
    function initScene() {
        scene = new THREE.Scene();
    }

    // 光源
    var light;
    function initLight() {

        // 環境光
        light = new THREE.AmbientLight(0xFFFFFF);
        light.position.set(100, 100, 200);
        scene.add(light);

        // 平行光
        // 位置不同,方向光作用於物體的面也不同,看到的物體各個面的顏色也不一樣
        // light = new THREE.DirectionalLight(0xffffbb, 1);
        // light.position.set(-1, 1, 1);
        // scene.add(light);
    }

    // 地球
    var earthMesh;
    function initEarth() {
        var earthGeo = new THREE.SphereGeometry(200, 100, 100);
        var earthMater = new THREE.MeshPhongMaterial({
            map: new THREE.TextureLoader().load('./assets/earth.jpg'),
            //side: THREE.DoubleSide
        });
        earthMesh = new THREE.Mesh(earthGeo, earthMater);
        scene.add(earthMesh);
    }

    // 雲
    var cloudsMesh;
    function initClouds() {
        var cloudsGeo = new THREE.SphereGeometry(201, 100, 100);
        var cloudsMater = new THREE.MeshPhongMaterial({
            alphaMap: new THREE.TextureLoader().load('./assets/clouds.jpg'),
            transparent: true,
            opacity: 0.2
        });
        cloudsMesh = new THREE.Mesh(cloudsGeo, cloudsMater);
        scene.add(cloudsMesh);
    }

    var controls;
    function threeStart() {
        initThree();
        //initStats();
        initCamera();
        initScene();
        initLight();
        initEarth();
        initClouds();
        // 載入控制器
        controls = new THREE.OrbitControls(camera, renderer.domElement);
		window.addEventListener("resize", onWindowResize, false);
        //renderer.clear();
        animate();
    }
	function onWindowResize() {   
	    width = document.getElementById('canvas-frame').clientWidth;
        height = document.getElementById('canvas-frame').clientHeight;
	    camera.aspect = width / height;   
	    camera.updateProjectionMatrix();    
	    renderer.setSize(width, height);
	}

	var sprite
	function showSprite(){
	  showText()
	  const canvasTexture = new THREE.CanvasTexture(
	    document.querySelector("#canvas")
	  )
	  //canvasTexture.needsUpdate = true; //注意這句不能少
	  const spritMaterial = new THREE.SpriteMaterial({
	    map:canvasTexture
	  })
	  sprite = new THREE.Sprite(spritMaterial)
	  sprite.position.set(-280,0,0);
	  //精靈的預設大小很小估計是[1,1,1]
	  sprite.scale.set(0.64*256,0.64*64,1);
	  scene.add(sprite)
	
	}

    function animate() {
	    text="new text";
		scene.remove(sprite)
		showSprite();
        controls.update();
        //stats.update();
        // 地球自轉
        earthMesh.rotation.y -= 0.002;

        // 漂浮的雲層
        cloudsMesh.rotation.y -= 0.005;
        cloudsMesh.rotation.z += 0.005;

        renderer.render(scene, camera);
        requestAnimationFrame(animate);
    }

</script>
</html>