查看旋轉地球效果javascript
主要用到幾個知識點css
(1)顯示文字是使用了three.js 的精靈(Sprite),精靈的文字方向始終面向相機,文字是在canvas中畫的,精靈的材質就是加載的帶有文字的canvashtml
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的文字從新賦值,並在動畫中移除上次加載的精靈,不然精靈會重疊java
scene.remove(sprite)
也能夠直接修改sprite 的屬性canvas
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 console.log(sprite) controls.update(); //stats.update(); // 地球自轉 earthMesh.rotation.y -= 0.002; renderer.render(scene, camera); requestAnimationFrame(animate); }
(3)窗口變化時自適應app
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); }
完整代碼dom
<!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>