使用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 相关文章推荐
IE中直接运行显示当前网页中的图片 推荐
Aug 31 Javascript
多浏览器兼容的获取元素和鼠标的位置的js代码
Dec 15 Javascript
深入理解JavaScript系列(14) 作用域链介绍(Scope Chain)
Apr 12 Javascript
JS获取后台Cookies值的小例子
Mar 04 Javascript
DOM基础教程之使用DOM
Jan 19 Javascript
js获得当前系统日期时间的方法
May 06 Javascript
JavaScript实现LI列表数据绑定的方法
Aug 04 Javascript
jQuery版本升级踩坑大全
Jan 12 Javascript
利用ES6实现单例模式及其应用详解
Dec 09 Javascript
jQuery easyui datagird编辑行删除行功能的实现代码
Sep 20 jQuery
vue+高德地图写地图选址组件的方法
May 18 Javascript
js逆向解密之网络爬虫
May 30 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 网页过期时间的控制代码
2009/06/29 PHP
PHP全局变量与超级全局变量区别分析
2016/04/01 PHP
JavaScript URL参数读取改进版
2009/01/16 Javascript
js函数获取html中className所在的内容并去除标签
2013/09/08 Javascript
jquery配合css简单实现返回顶部效果
2013/09/30 Javascript
无刷新预览所选择的图片示例代码
2014/04/02 Javascript
window.open()详解及浏览器兼容性问题示例探讨
2014/05/29 Javascript
js父页面与子页面不同时显示的方法
2014/10/16 Javascript
基于jQuery实现网页进度显示插件
2015/03/04 Javascript
javascript显示上周、上个月日期的处理方法
2016/02/03 Javascript
Android中Okhttp3实现上传多张图片同时传递参数
2017/02/18 Javascript
NodeJS配置HTTPS服务实例分享
2017/02/19 NodeJs
jQuery中clone()函数实现表单中增加和减少输入项
2017/05/13 jQuery
JavaScript截屏功能的实现代码
2017/07/28 Javascript
推荐VSCode 上特别好用的 Vue 插件之vetur
2017/09/14 Javascript
如何利用@angular/cli V6.0直接开发PWA应用详解
2018/05/06 Javascript
vue源码学习之Object.defineProperty对象属性监听
2018/05/30 Javascript
Vue实现底部侧边工具栏的实例代码
2018/09/03 Javascript
jquery无缝图片轮播组件封装
2020/11/25 jQuery
vue路由--网站导航功能详解
2019/03/29 Javascript
ES6知识点整理之数组解构和字符串解构的应用示例
2019/04/17 Javascript
JavaScript算法学习之冒泡排序和选择排序
2019/11/02 Javascript
Vue 中 filter 与 computed 的区别与用法解析
2019/11/21 Javascript
python网络爬虫采集联想词示例
2014/02/11 Python
python字符串连接的N种方式总结
2014/09/17 Python
Python实现将Excel转换成为image的方法
2018/10/23 Python
Keras中的多分类损失函数用法categorical_crossentropy
2020/06/11 Python
用CSS3实现瀑布流布局的示例代码
2017/11/10 HTML / CSS
美国最大的珠宝首饰网上商城:Jewelry.com
2016/07/22 全球购物
物流管理专业大学生自荐信
2013/10/04 职场文书
我的大学生活职业生涯规划
2014/01/02 职场文书
给同学的道歉信
2014/01/16 职场文书
升国旗仪式主持词
2014/03/19 职场文书
医疗纠纷协议书
2014/04/16 职场文书
公司表扬信格式
2015/05/04 职场文书
2019年教师节活动策划方案
2019/09/09 职场文书