three.js 製做太陽系統

最近學了three.js,想拿來練練手,喜歡宇宙,因而親手擼代碼來完成這個,爲了更真實,因而查了一些相關資料。
1. 距離太陽由近及遠分別是【水星,金星,地球,火星,木星,土星,天王星,海王星】
2. 他們分別到太陽的距離爲5791, 10820, 14960, 22794, 77833, 142940, 287099, 450400(單位萬公里)
3. 他們的半徑分別爲2440, 6052, 6371, 3397, 71492, 60268, 25559, 24766(公里)
4. 他們的公轉週期分別爲88, 225, 365, 687, 4329, 10767, 30769, 60152(天)
5. 他們的自轉週期分別爲58,243,1, 1, 0.41, 0.42, 0.64, 0.65,
好了除了八大行星都已經調查好了,接下來八大行星都將按照真實比例繪製,(因爲週期相差過大,遂正比於1/2次方)html

1.繪製八大行星

繪製行星很容易,直接看代碼web

shuixing = renderMesh("shuixing", 0); jinxing = renderMesh("jinxing", 1); diqiu = renderMesh("diqiu", 2); huoxing = renderMesh("huoxing", 3); muxing = renderMesh("muxing", 4); tuxing = renderMesh("tuxing", 5); tianwangxing = renderMesh("tianwangxing", 6); haiwangxing = renderMesh("haiwangxing", 7); scene.add(shuixing); scene.add(jinxing); scene.add(diqiu); scene.add(huoxing); scene.add(muxing); scene.add(tuxing); scene.add(tianwangxing); scene.add(haiwangxing); function renderMesh(name, num) { let texture = new THREE.TextureLoader().load("http://www.bettersmile.cn:90/three_code/assets/textures/planets/"+name+".jpg"); let geometry = new THREE.SphereGeometry(radiuses[num] * RADIUS, 50, 50); let material = new THREE.MeshBasicMaterial({map: texture}); let mesh = new THREE.Mesh(geometry, material); mesh.position.x = distances[num] * DISTANCE + SUNRADIUS * RADIUS; return mesh; }

在繪製的同時,咱們還固定了他們的位置哦,canvas

2.繪製小行星帶dom

八大行星都繪製好了,怎麼能少了小行星帶呢?因爲小行星帶都是不規則的石頭,這裏咱們使用上一節的ConvexGeometry()渲染。ide

let asteroidTexture = new THREE.TextureLoader().load("http://www.bettersmile.cn:90/three_code/assets/textures/planets/asteroid.jpg"); asteriods = renderAsteriod(asteroidTexture); scene.add(asteriods); function renderAsteriod(texture) { let asteroid = new THREE.Geometry(); let asteroidMate = new THREE.MeshBasicMaterial(); for(var i=0; i<20000; i++) { let points = []; let rad = Math.pow(Math.random(), 3) * ASTERIODRADIUS; for(var j=0; j<30; j++) { points.push(new THREE.Vector3(Math.random() * RADIUS * rad, Math.random() * RADIUS * rad, Math.random() * RADIUS * rad)) } var asteroidGeom = new THREE.ConvexGeometry(points); var asterMesh = new THREE.Mesh(asteroidGeom, asteroidMate); //2.17-3.64 * 14960 = 32450 - 54450
        let dis = (Math.random() * 22000 + 32450) * DISTANCE + SUNRADIUS * RADIUS; let angle = Math.random() * Math.PI * 2; asterMesh.position.x = dis * Math.sin(angle); asterMesh.position.y = Math.random() * ASTERIODRADIUS * RADIUS * 4 - ASTERIODRADIUS * RADIUS * 2; asterMesh.position.z = dis * Math.cos(angle); asterMesh.updateMatrix(); asteroid.merge(asterMesh.geometry, asterMesh.matrix); } let mesh = new THREE.Mesh(asteroid, new THREE.MeshLambertMaterial({map: texture, emissive: 0x484137})); return mesh; }

咱們渲染了20000個小行星,這裏小行星帶距離太陽2.17~3.64個天文單位,一天文單位爲14960萬公里。函數

3.加下來咱們繪製太陽,月球,土星環

繪製太陽,月球和土星環(土星環P了很久),相對容易,太陽設置在原點,月球圍繞地球,土星環圍繞土星,動畫

let taiyangTexture = new THREE.TextureLoader().load("http://www.bettersmile.cn:90/three_code/assets/textures/planets/sun.jpg"); let yueqiuTexture = new THREE.TextureLoader().load("http://www.bettersmile.cn:90/three_code/assets/textures/planets/yueqiu.jpg"); let tuxinghuanTexture = new THREE.TextureLoader().load("http://www.bettersmile.cn:90/three_code/assets/textures/planets/tuxinghuan.png"); let taiyangGeom = new THREE.SphereGeometry(SUNRADIUS * RADIUS, 50, 50); let taiyangMate = new THREE.MeshBasicMaterial({map: taiyangTexture}); let yueqiuGeom = new THREE.SphereGeometry(MOONRADIUS * RADIUS, 50, 50); let yueqiuMate = new THREE.MeshBasicMaterial({map: yueqiuTexture}); tuxinghuan = renderTuxinghuan(tuxinghuanTexture); tuxinghuan.position.copy(tuxing.position); scene.add(tuxinghuan); taiyang = new THREE.Mesh(taiyangGeom, taiyangMate); yueqiu = new THREE.Mesh(yueqiuGeom, yueqiuMate); yueqiu.position.set((distances[2] * DISTANCE + SUNRADIUS * RADIUS) + MOONDISTANCE * DISTANCE, 0, 0); scene.add(taiyang); scene.add(yueqiu); function renderTuxinghuan(texture) { let geom = new THREE.RingGeometry(16, 24, 50, 10, 0, Math.PI * 2); let mate = new THREE.MeshLambertMaterial({emissive: 0xaa8766, transparent:false, opacity: 0.8, map: texture, side: THREE.DoubleSide}); let ring = new THREE.Mesh(geom, mate); ring.rotation.x = - Math.PI / 2; ring.rotation.y = - Math.PI / 12; return ring; } function initCanvas() { let canvas = document.createElement('canvas'); canvas.width = 16; canvas.height = 16; let context = canvas.getContext('2d'); let gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2); gradient.addColorStop(0, 'rgba(244,164,33,1)'); gradient.addColorStop(0.2, 'rgba(244,164,33,1)'); gradient.addColorStop(0.4, 'rgba(244,164,33,.6)'); gradient.addColorStop(1, 'rgba(0,0,0,0)'); context.fillStyle = gradient; context.fillRect(0, 0, canvas.width, canvas.height); return canvas; } function initSunshine() { let centerBallLite = new THREE.Sprite(new THREE.SpriteMaterial({ map: new THREE.CanvasTexture(initCanvas()), blending: THREE.AdditiveBlending })); centerBallLite.scale.x = centerBallLite.scale.y = centerBallLite.scale.z = 250000 * RADIUS; scene.add(centerBallLite); }

這裏咱們的土星環使用了RingGeometry()幾何體,太陽的光暈使用CanvasTexture()ui

4.讓星球動起來

讓全部星星動起來,使用自轉和公轉,這裏須要一點三角函數的功底,this

function allStarsSelfRotate() { taiyang.rotation.y = 1 / Math.sqrt(25) * step1 * SELECYCLE; yueqiu.rotation.y = 1 / Math.sqrt(30) * step1 * SELECYCLE; shuixing.rotation.y = 1 / Math.sqrt(58.65) * step1 * SELECYCLE; jinxing.rotation.y = - 1 / Math.sqrt(243) * step1 * SELECYCLE; diqiu.rotation.y = step1 * SELECYCLE; huoxing.rotation.y = step1 * SELECYCLE; muxing.rotation.y = 1 / Math.sqrt(0.41) * step1 * SELECYCLE; tuxing.rotation.y = 1 / Math.sqrt(0.42) * step1 * SELECYCLE; tianwangxing.rotation.z = 1 / Math.sqrt(0.64) * step1 * SELECYCLE; haiwangxing.rotation.y = 1 / Math.sqrt(0.65) * step1 * SELECYCLE; asteriods.rotation.y = 1 / 50 * step1 * PUBLICCYCLE; step1 ++; } function allStarsPublicRotate() { shuixing.position.set(rotating(0).x,0,rotating(0).z); jinxing.position.set(rotating(1).x,0,rotating(1).z); diqiu.position.set(rotating(2).x,0,rotating(2).z); huoxing.position.set(rotating(3).x,0,rotating(3).z); muxing.position.set(rotating(4).x,0,rotating(4).z); tuxing.position.set(rotating(5).x,0,rotating(5).z); tianwangxing.position.set(rotating(6).x,0,rotating(6).z); haiwangxing.position.set(rotating(7).x,0,rotating(7).z); tuxinghuan.position.copy(tuxing.position); yueqiu.position.set( (distances[2] * DISTANCE + SUNRADIUS * RADIUS) * Math.cos(step2 / Math.sqrt(durations[2]) * PUBLICCYCLE) + (MOONDISTANCE * DISTANCE) * Math.sin(step2 / Math.sqrt(10) * PUBLICCYCLE), 0, - (distances[2] * DISTANCE + SUNRADIUS * RADIUS) * Math.sin(step2 / Math.sqrt(durations[2]) * PUBLICCYCLE) + (MOONDISTANCE * DISTANCE) * Math.cos(step2 / Math.sqrt(10) * PUBLICCYCLE) ); step2 ++; } function rotating(num) { let x = (distances[num] * DISTANCE + SUNRADIUS * RADIUS) * Math.cos(step2 / Math.sqrt(durations[num]) * PUBLICCYCLE); let z = - (distances[num] * DISTANCE + SUNRADIUS * RADIUS) * Math.sin(step2 / Math.sqrt(durations[num]) * PUBLICCYCLE); return {x, z}; }

全是簡單的三角函數,呵呵spa

5.加上星空

星空咱們直接使用PointsMaterial(),咱們隨機3000個點(點太多會很亂)。

function initSprites() { let geom = new THREE.Geometry(); let mate = new THREE.PointsMaterial({ size: 0.2, vertexColors: true, color: 0xffffff, transparent: true, opacity: 0.6 }) for(var i=0; i<3000; i++) { let x = Math.random() * 10000 - 5000; let y = Math.random() * 10000 - 5000; let z = Math.random() * 10000 - 5000; if(x*x+y*y+z*z > 250000) { var vector = new THREE.Vector3(x,y,z); geom.vertices.push(vector); geom.colors.push(new THREE.Color(0xffffff)); } } cloud = new THREE.Points(geom, mate); scene.add(cloud); }

x*x+y*y+z*z > 250000,爲了讓他們處在很遠的地方,咱們過濾掉離中心小於500的星星,因此剩下的應該很少。

6.加上tween動畫和飛行相機

動畫咱們是先給每一個星球一個鏡頭(畢竟球球平等,可是給了地球最好的貼圖),而後俯瞰整個太陽系

function initTween() { let pos = {x: 41, y: 17, z: -35, lx: 0, ly: 0, lz: 0}; let tween1 = new TWEEN.Tween(pos).to({x: 40.36, y: 0.29, z: 2.642, lx: 40.54, ly: 0, lz: 0}, 20 * ANIMATIONTIME); tween1.easing(TWEEN.Easing.Linear.None); let tween2 = new TWEEN.Tween(pos).to({x: 67.41, y: 0.43, z: -4, lx: 65.7, ly: 0, lz: 0}, 22 * ANIMATIONTIME); tween2.easing(TWEEN.Easing.Linear.None); let tween3 = new TWEEN.Tween(pos).to({x: 84.6, y: 0.91, z: -3.42, lx: 86.4, ly: 0, lz: 0}, 24 * ANIMATIONTIME); tween3.easing(TWEEN.Easing.Linear.None); let tween4 = new TWEEN.Tween(pos).to({x: 127.66, y: 0.26, z: -1.47, lx: 125.56, ly: 0, lz: 0}, 27 * ANIMATIONTIME); tween4.easing(TWEEN.Easing.Linear.None); let tween5 = new TWEEN.Tween(pos).to({x: 177.78, y: 1.64, z: -61.37, lx: 200.84, ly: 0, lz: 0}, 30 * ANIMATIONTIME); tween5.easing(TWEEN.Easing.Linear.None); let tween6 = new TWEEN.Tween(pos).to({x: 359.81, y: 11.44, z: -26.28, lx: 400.76, ly: 0, lz: 0}, 35 * ANIMATIONTIME); tween6.easing(TWEEN.Easing.Linear.None); let tween7 = new TWEEN.Tween(pos).to({x: 703.65, y: 34.43, z: -73.74, lx: 726.29, ly: 0, lz: 0}, 40 * ANIMATIONTIME); tween7.easing(TWEEN.Easing.Linear.None); let tween8 = new TWEEN.Tween(pos).to({x: 1441.76, y: 2.69, z: -26.5, lx: 1447.09, ly: 0, lz: 0}, 50 * ANIMATIONTIME); tween8.easing(TWEEN.Easing.Linear.None); let tween9 = new TWEEN.Tween(pos).to({x: 2262.5, y: 4.43, z: 17.22, lx: 2263.59, ly: 0, lz: 0}, 65 * ANIMATIONTIME); tween9.easing(TWEEN.Easing.Linear.None); let tween10 = new TWEEN.Tween(pos).to({x: -374, y: 452, z: -3.4, lx: 400.76, ly: 0, lz: 0}, 85 * ANIMATIONTIME); tween10.easing(TWEEN.Easing.Linear.None); tween1.chain(tween2); tween2.chain(tween3); tween3.chain(tween4); tween4.chain(tween5); tween5.chain(tween6); tween6.chain(tween7); tween7.chain(tween8); tween8.chain(tween9); tween9.chain(tween10); var onUpdate = function () { var px = this.x; var py = this.y; var pz = this.z; var lx = this.lx; var ly = this.ly; var lz = this.lz; camera.position.set(px, py, pz); camera.lookAt(new THREE.Vector3(lx, ly, lz)) }; tween1.onUpdate(onUpdate); tween2.onUpdate(onUpdate); tween3.onUpdate(onUpdate); tween4.onUpdate(onUpdate); tween5.onUpdate(onUpdate); tween6.onUpdate(onUpdate); tween7.onUpdate(onUpdate); tween8.onUpdate(onUpdate); tween9.onUpdate(onUpdate); tween10.onUpdate(onUpdate); tween1.delay(70 * ANIMATIONTIME); tween2.delay(30 * ANIMATIONTIME); tween3.delay(30 * ANIMATIONTIME); tween4.delay(30 * ANIMATIONTIME); tween5.delay(30 * ANIMATIONTIME); tween6.delay(30 * ANIMATIONTIME); tween7.delay(30 * ANIMATIONTIME); tween8.delay(30 * ANIMATIONTIME); tween9.delay(30 * ANIMATIONTIME); tween10.delay(30 * ANIMATIONTIME); tween1.start(); tween10.onComplete(function () { off = true; }) }

代碼很長不過很好理解...
這樣咱們就完成了一個簡單的太陽系。

 

想看demo的請移步至 郭志強的博客

轉載請註明原文地址 https://www.cnblogs.com/vadim-web/p/12077466.html

原文出處:https://www.cnblogs.com/vadim-web/p/12077466.html

相關文章
相關標籤/搜索