使用Three.js实现太阳系八大行星的自转公转示例代码


Posted in Javascript onApril 09, 2019

一. Three.js框架简介

Three.js是用javascript编写的WebGL第三方库,运用three.js框架写3D程序,就如同在现实生活中观察一个3D场景一样,让人置身其中。介绍three.js必须提到它的三大组件,Scene,Camera,Render。它们是整个框架的基础,有了这三个组件才能将物体渲染到网页上,实现整个场景的搭建。

场景(scene)

顾名思义,就是用来放置所有的元素。

var scene = new THREE.Scene(); //建立场景

相机(camera)

相机,我们要在哪个位置,如何去看这些元素。

相机分为多种,不展开介绍,这里我们使用的是 透视相机。

var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 10000); //设置相机为 角度60度,宽高比,最近端Z轴为1,最远端Z轴为10000

我们可以通过一张来自three.js文档中的图片来了解这些属性

使用Three.js实现太阳系八大行星的自转公转示例代码

渲染器(render)

当把场景中的所有内容准备好后,就可以对场景进行渲染,表示我们怎样来绘制这些元素。

渲染器也分为多种,这里使用的是WebGLRenderer;

var renderer = new THREE.WebGLRenderer();

具体步骤:建立元素->定义相机->搭建场景->将元素和相机放入场景中->渲染场景

具体代码我们会在后面介绍,然后让我们先瞅一眼效果图。

二. 基本初始化

这里直接在CDN上引入three.js

<script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>

注:因为某些行星的大小,转速,距离差距过大,所以进行了一些不平衡调整。

下面将一一分析这些元素是如何放入的。

1.canvas

我们没有把场景直接挂载到body中,而是在body中放置了一个canvas画布,在其上显示。

2.背景

我们没有做3D的旋转背景,而是直接放了一张背景图作为小太阳系的背景。这张背景图是直接在canvas中放置的。

<canvas id="webglcanvas"></canvas>
renderer = new THREE.WebGLRenderer({ //定义渲染器
   alpha: true, //让背景透明,默认是黑色,以显示我们自己的背景图
  });
renderer.setClearAlpha(0);
//css文件
#webglcanvas {
   background: url(./images/bg4.jpg) no-repeat;
   background-size: cover;
  }

但如果只是这样简单的操作是没有用的,因为在添加渲染器后,会默认添加一个背景颜色为黑色。所以要在渲染器中设置它的alpha属性(WebGL渲染器及属性方法),让背景透明,以显示我们自己的背景图

3.定义基本组件

定义场景

scene = new THREE.Scene(), //建立场景

定义照相机位置

camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1,10000); //设置相机为 角度60度,宽高比,最近端Z轴为1,最远端Z轴为10000
  camera.position.z = 2000; //调整相机位置
  camera.position.y = 500;

建立一个组

组可以看作是一些元素的容器,将某些有共同特征的元素放在一个组里。

group = new THREE.Group(), //建立一个组

我会在第三节解释为什么要建立额外16个组。

//下面这些组用来建立每个星球的父元素,以实现 八大行星不同速度的公转与自转
  var group1 = new THREE.Group();
   groupParent1 = new THREE.Group();
   group2 = new THREE.Group();
   groupParent2 = new THREE.Group();
   group3 = new THREE.Group();
   groupParent3 = new THREE.Group();
   group4 = new THREE.Group();
   groupParent4 = new THREE.Group();
   group5 = new THREE.Group();
   groupParent5 = new THREE.Group();
   group6 = new THREE.Group();
   groupParent6 = new THREE.Group();
   group7 = new THREE.Group();
   groupParent7 = new THREE.Group();
   group8 = new THREE.Group();
   groupParent8 = new THREE.Group();

定义渲染器

WebGLRenderer中有一个用来绘制输出的canvas对象,现在获取设置的canvas放入我们渲染器中的canvas对象中

var canvas = document.getElementById('webglcanvas'),
renderer = new THREE.WebGLRenderer({ //定义渲染器
   alpha: true, //让背景透明,默认是黑色 以显示我们自己的背景图
   canvas: canvas, //一个用来绘制输出的Canvas对象
   antialias: true //抗锯齿
  });
renderer.setSize(window.innerWidth, window.innerHeight); //设置渲染器的宽高

4.初始化函数

在这个函数中进行一系列的初始化操作。

function init() {  //用来初始化的函数
   scene.add(group); //把组都添加到场景里

   scene.add(groupParent1);
   scene.add(groupParent2);
   scene.add(groupParent3);
   scene.add(groupParent4);
   scene.add(groupParent5);
   scene.add(groupParent6);
   scene.add(groupParent7);
   scene.add(groupParent8);
   
   var loader = new THREE.TextureLoader();/*材质 纹理加载器*/
   // 太阳
   loader.load('./images/sun1.jpg', function (texture) {  
    var geometry = new THREE.SphereGeometry(250, 20, 20) //球体模型 
    var material = new THREE.MeshBasicMaterial({ map: texture }) //材质 将图片解构成THREE能理解的材质
    var mesh = new THREE.Mesh(geometry, material);  //网孔对象 第一个参数是几何模型(结构),第二参数是材料(外观)
    group.add(mesh);//添加到组里
   })
   // 水星
   loader.load('./images/water.jpg', function (texture) {
    var geometry = new THREE.SphereGeometry(25, 20, 20) //球型 
    var material = new THREE.MeshBasicMaterial({ map: texture }) //材质 将图片解构成THREE能理解的材质
    var mesh = new THREE.Mesh(geometry, material);
    group1.position.x -= 300;
    group1.add(mesh);
    groupParent1.add(group1);
   })
   //其它7颗行星参数因为太长了在这里就不给出了,但参数的设置原理都是一样的
   }

简要解释一下:

var loader = new THREE.TextureLoader();是定义了一个材质纹理加载器。

var geometry = new THREE.SphereGeometry(250, 20, 20);建立一个球体模型,球体半径为250,水平分割面的数量20,垂直分割面的数量20。

var mesh = new THREE.Mesh(geometry, material);网孔对象。

具体作用就是创建一个球体元素,先构建框架,在用行星的平面图将它包裹起来,就形成了一颗行星,再把这颗行星添加到组里,之后再把组添加到场景里。这里就构建单个元素的过程。

那么为什么太阳直接添加到组里,而水星要用两个组层级添加,且给它的位置设偏移呢。我们来到第三节。

三. 自转同时公转

旋转方式:我们要实现旋转功能有三种方式

1.旋转照相机  2.旋转整个场景(Scene)  3.旋转单个元素。

因为我们这里每个行星的自转速度,公转速度都不一样。所以设置整体旋转并不可行,所以要给每个元素设置不同的旋转属性。

旋转机制:这里介绍物体的rotation属性,相对于自身旋转。

例如:

scene.rotation.y += 0.04; //整个场景绕自身的Y轴逆时针旋转

进入正题

使用Three.js实现太阳系八大行星的自转公转示例代码

Scene中的所有元素使用rotation.y属性,默认旋转轴都为这根Y轴,因为它们初始化Y轴就是这根轴。
所以让太阳旋转直接让它的组旋转就行了group.rotation.y += 0.04;

而其它行星需要让它们围绕着太阳转,就要先给它们自身设置一个位置偏移。例如水星:group1.position.x -= 300;  而此时设置group1.rotation.y属性,它就会实现自转。因为它的Y轴位置已经改变了。

使用Three.js实现太阳系八大行星的自转公转示例代码

那么此时要想再实现公转,在这个对象中是找不到默认Y轴这根线的。所以我们给group1再设置了一个“父元素”groupParent1。groupParent1.add(group1);

当我们移动了group1时,groupParent1的位置是没有变的,自然它的Y轴也不会变,又因为groupParent1包含了group1,所以旋转groupParent1时,group1也会绕着初始的默认Y轴旋转。所以设置那么多组,是为了实现每颗行星不同的速度和公转的同时自转。

使用Three.js实现太阳系八大行星的自转公转示例代码

四. 其他实现函数

function render() {
   renderer.render(scene, camera);
   camera.lookAt(scene.position); //让相机盯着场景的位置 场景始终在中间
  }
  //设置公转
  function revolution(){
   groupParent1.rotation.y += 0.15;
   groupParent2.rotation.y += 0.065;
   groupParent3.rotation.y += 0.05;
   groupParent4.rotation.y += 0.03;
   groupParent5.rotation.y += 0.001; 
   groupParent6.rotation.y += 0.02;
   groupParent7.rotation.y += 0.0005;
   groupParent8.rotation.y += 0.003;
  }
  //设置自转
  function selfRotation(){
   group.rotation.y += 0.04;
   group1.rotation.y += 0.02;
   group2.rotation.y -= 0.005;
   group3.rotation.y += 1;
   group4.rotation.y += 1;
   group5.rotation.y += 1.5;
   group6.rotation.y += 1.5;
   group7.rotation.y -= 1.5;
   group8.rotation.y += 1.2;
  }
  function Animation() {
   render();
   selfRotation();
   revolution();
   requestAnimationFrame(Animation); 
  }

最后再调用一下 init()Animation()函数就OK了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
js与C#进行时间戳转换
Nov 14 Javascript
浅谈javascript 函数表达式和函数声明的区别
Jan 05 Javascript
详解JavaScript异步编程中jQuery的promise对象的作用
May 03 Javascript
JS实现重新加载当前页面
Nov 29 Javascript
jquery操作select取值赋值与设置选中实例
Feb 28 Javascript
JS实现的简单表单验证功能完整实例
Oct 14 Javascript
ES6中Class类的静态方法实例小结
Oct 28 Javascript
webpack构建换肤功能的思路详解
Nov 27 Javascript
vue生命周期实例小结
Aug 15 Javascript
JS实现点星星消除小游戏
Mar 24 Javascript
微信小程序纯文本实现@功能
Apr 08 Javascript
解决vue 使用setTimeout,离开当前路由setTimeout未销毁的问题
Jul 21 Javascript
webpack4实现不同的导出类型
Apr 09 #Javascript
Vue中使用create-keyframe-animation与动画钩子完成复杂动画
Apr 09 #Javascript
基于three.js实现的3D粒子动效实例代码
Apr 09 #Javascript
Koa 中的错误处理解析
Apr 09 #Javascript
简单说说如何使用vue-router插件的方法
Apr 08 #Javascript
利用Bootstrap Multiselect实现下拉框多选功能
Apr 08 #Javascript
纯javascript实现选择框的全选与反选功能
Apr 08 #Javascript
You might like
利用PHP和AJAX创建RSS聚合器的代码
2007/03/13 PHP
cmd下运行php脚本
2008/11/25 PHP
Yii扩展组件编写方法实例分析
2015/06/29 PHP
微信 getAccessToken方法详解及实例
2016/11/23 PHP
dojo 之基础篇
2007/03/24 Javascript
setInterval计时器不准的问题解决方法
2014/05/08 Javascript
jQuery实现Email邮箱地址自动补全功能代码
2015/11/03 Javascript
基于MVC4+EasyUI的Web开发框架形成之旅之界面控件的使用
2015/12/16 Javascript
javascript禁止超链接跳转的方法
2016/02/02 Javascript
详解Node.js如何开发命令行工具
2016/08/14 Javascript
jQuery实现简单的抽奖游戏
2017/05/05 jQuery
微信小程序保存多张图片的实现方法
2019/03/05 Javascript
vue组件之间的数据传递方法详解
2019/04/19 Javascript
如何根据业务封装自己的功能组件
2019/04/19 Javascript
百度小程序之间的页面通信过程详解
2019/07/18 Javascript
手写Vue源码之数据劫持示例详解
2021/01/04 Vue.js
[02:48]DOTA2英雄基础教程 拉席克
2013/12/12 DOTA
[52:15]2014 DOTA2国际邀请赛中国区预选赛5.21 HGT VS LGD-GAMING
2014/05/23 DOTA
python调用cmd复制文件代码分享
2013/12/27 Python
Python框架Flask的基本数据库操作方法分析
2018/07/13 Python
python实现flappy bird小游戏
2018/12/24 Python
Python 生成VOC格式的标签实例
2020/03/10 Python
Python3 hashlib密码散列算法原理详解
2020/03/30 Python
python实现测试工具(二)——简单的ui测试工具
2020/10/19 Python
We Fashion荷兰:一家国际时装公司
2018/04/18 全球购物
Fabletics官网:美国运动服饰品牌,由好莱坞女演员凯特·哈德森创立
2019/10/19 全球购物
值传递还是引用传递
2015/02/08 面试题
军校制空专业毕业生自我鉴定
2013/11/16 职场文书
生物制药专业自我鉴定
2014/02/19 职场文书
学习决心书范文
2014/03/11 职场文书
舞蹈教育学专业自荐信
2014/06/15 职场文书
区长工作作风个人整改措施
2014/10/01 职场文书
乡镇领导班子四风整顿行动工作汇报
2014/10/25 职场文书
2016优秀员工先进事迹材料
2016/02/25 职场文书
六年级语文教学反思
2016/03/03 职场文书
聊聊pytorch测试的时候为何要加上model.eval()
2021/05/23 Python