three.js 带更新文字的旋转地球

2019-04-23 09:47:41 浏览数 (1)

查看旋转地球效果

主要用到几个知识点

(1)显示文字是使用了three.js 的精灵(Sprite),精灵的文字方向始终面向相机,文字是在canvas中画的,精灵的材质就是加载的带有文字的canvas

代码语言:javascript复制
	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)
	}
	
代码语言:javascript复制
	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的文字重新赋值,并在动画中移除上次加载的精灵,否则精灵会重叠

代码语言:javascript复制
scene.remove(sprite)

也可以更新sprite的material属性

代码语言:javascript复制
    function animate() {
	    text="new text";
	    showText()
		  //scene.remove(sprite)
		  const canvasTexture = new THREE.CanvasTexture(
		    	document.querySelector("#canvas")
		   )
		  sprite.material.map = canvasTexture;
		  //sprite.material.map.needsUpdate = true;默认为true
    }

(3)窗口变化时自适应

代码语言:javascript复制
	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);
	}

完整代码

代码语言:javascript复制
<!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>

0 人点赞