three.js实现3D影院的原理的代码分析


Posted in Javascript onDecember 18, 2017

本篇文章我们通过介绍3D影院的视觉原理,并介绍了three.js事件处理过程,全面分析了实现3D影院的基础知识。

1.创建一个3d的空间

可以想象一下我们在房间内,房间是一个立方体,如果你有生活品味,可能会在房间内贴上壁纸,three.js可以很方便的创建一个立方体,并且给它的周围贴上纹理,让照相机在立方体之中,照相机可以360旋转,就模拟了一个真实的场景。

转换为代码:

const path = 'assets/image/'
 const format = '.jpg'
 const urls = [
 `${path}px${format}`, `${path}nx${format}`,
 `${path}py${format}`, `${path}ny${format}`,
 `${path}pz${format}`, `${path}nz${format}`
 ]
 const materials = []
 urls.forEach(url => {
 const textureLoader = new TextureLoader()
 textureLoader.setCrossOrigin(this.crossOrigin)
 const texture = textureLoader.load(url)
 materials.push(new MeshBasicMaterial({
 map: texture,
 overdraw: true,
 side: BackSide
 }))
 })
 const cube = new Mesh(new CubeGeometry(9000, 9000, 9000), new MeshFaceMaterial(materials))
 this.scene.add(cube)

CubeGeometry创建一个超大的立方体 MeshFaceMaterial给立方体贴上文理,由于视角是在立方体内部,所以side:BackSide 2.粒子效果

一个3d模型是由点,线,面组成的,可以遍历模型的每一个点,把每一个点转换为几何模型,并且给它贴上文理,拷贝每一个点的位置,用这些几何模型重新构成一个只有点的模型,这就是粒子效果的基本原理。

this.points = new Group()
 const vertices = []
 let point
 const texture = new TextureLoader().load('assets/image/dot.png')
 geometry.vertices.forEach((o, i) => {
 // 记录每个点的位置
 vertices.push(o.clone())
 const _geometry = new Geometry()
 // 拿到当前点的位置
 const pos = vertices[i]
 _geometry.vertices.push(new Vector3())
 const color = new Color()
 color.r = Math.abs(Math.random() * 10)
 color.g = Math.abs(Math.random() * 10)
 color.b = Math.abs(Math.random() * 10)
 const material = new PointsMaterial({
 color,
 size: Math.random() * 4 + 2,
 map: texture,
 blending: AddEquation,
 depthTest: false,
 transparent: true
 })
 point = new Points(_geometry, material)
 point.position.copy(pos)
 this.points.add(point)
 })
 return this.points

new Group创建一个群,可以说是粒子的集合通过point.position.copy(pos)设置粒子和位置,坐标和模型中对应点的位置相同 3.点击事件的处理

three.js的点击事件需要借助光线投射器(Raycaster),为了方便理解,请先看一张图:

three.js实现3D影院的原理的代码分析

Raycaster发射一个射线,intersectObject监测射线命中的物体

this.raycaster = new Raycaster()
// 把你要监听点击事件的物体用数组储存起来
this.seats.push(seat)

onTouchStart(event) {
 event.preventDefault()
 event.clientX = event.touches[0].clientX;
 event.clientY = event.touches[0].clientY;
 this.onClick(event)
 }

 onClick(event) {
 const mouse = new Vector2()
 mouse.x = ( event.clientX / this.renderer.domElement.clientWidth ) * 2 - 1
 mouse.y = - ( event.clientY / this.renderer.domElement.clientHeight ) * 2 + 1;
 this.raycaster.setFromCamera(mouse, this.camera)
 // 检测命中的座位
 const intersects = this.raycaster.intersectObjects(this.seats)
 if (intersects.length > 0) {
 intersects[0].object.material = new MeshLambertMaterial({
  color: 0xff0000
 })
 }
 }

intersects.length > 0 表示射线命中了某个几何体偷懒只实现了移动端的点击实现,如果想看pc怎么实现,请看thee.js官网

4.着色器的初步使用

着色器分为顶点着色器和片元着色器,用GLSL语言编写,是一种和GPU沟通的的语言,这里只讲如何使用

const vertext = `
 void main()
 {
 gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
 }
 `

const fragment = `
 uniform vec2 resolution;
 uniform float time;

 vec2 rand(vec2 pos)
 {
 return fract( 0.00005 * (pow(pos+2.0, pos.yx + 1.0) * 22222.0));
 }
 vec2 rand2(vec2 pos)
 {
 return rand(rand(pos));
 }

 float softnoise(vec2 pos, float scale)
 {
 vec2 smplpos = pos * scale;
 float c0 = rand2((floor(smplpos) + vec2(0.0, 0.0)) / scale).x;
 float c1 = rand2((floor(smplpos) + vec2(1.0, 0.0)) / scale).x;
 float c2 = rand2((floor(smplpos) + vec2(0.0, 1.0)) / scale).x;
 float c3 = rand2((floor(smplpos) + vec2(1.0, 1.0)) / scale).x;

 vec2 a = fract(smplpos);
 return mix(
 mix(c0, c1, smoothstep(0.0, 1.0, a.x)),
 mix(c2, c3, smoothstep(0.0, 1.0, a.x)),
 smoothstep(0.0, 1.0, a.y));
 }

 void main(void)
 {
 vec2 pos = gl_FragCoord.xy / resolution.y;
 pos.x += time * 0.1;
 float color = 0.0;
 float s = 1.0;
 for(int i = 0; i < 8; i++)
 {
 color += softnoise(pos+vec2(i)*0.02, s * 4.0) / s / 2.0;
 s *= 2.0;
 }
 gl_FragColor = vec4(color);
 }
 `
// 设置物体的质材为着色器质材
 let material = new ShaderMaterial({
 uniforms: uniforms,
 vertexShader: vertext,
 fragmentShader: fragment,
 transparent: true,
 })

5.光晕效果

由于是模拟电影院,我想做一个投影仪,模拟投影仪射出的光线。

// 光晕效果必须设置alpha = true
 const renderer = this.renderer = new WebGLRenderer({alpha: true, antialias: true})

 let textureFlare = new TextureLoader().load('assets/image/lensflare0.png')
 let textureFlare3 = new TextureLoader().load('assets/image/lensflare3.png')
 let flareColor = new Color(0xffffff)
 let lensFlare = new LensFlare(textureFlare, 150, 0.0 , AdditiveBlending, flareColor)
 lensFlare.add(textureFlare3, 60, 0.6, AdditiveBlending);
 lensFlare.add(textureFlare3, 70, 0.7, AdditiveBlending);
 lensFlare.add(textureFlare3, 120, 0.9, AdditiveBlending);
 lensFlare.add(textureFlare3, 70, 1.0, AdditiveBlending);
 lensFlare.position.set(0, 150, -85)

主要的光线还是靠lensflare0.png模拟 textureFlare3设置光晕的范围

Javascript 相关文章推荐
popdiv
Jul 14 Javascript
一个JavaScript继承的实现
Oct 24 Javascript
Prototype Array对象 学习
Jul 19 Javascript
jQuery+jqmodal弹出窗口实现代码分明
Jun 14 Javascript
在页面上用action传递参数到后台出现乱码的解决方法
Dec 31 Javascript
谈谈PHP中相对路径的问题与绝对路径的使用
Aug 16 Javascript
利用JavaScript在网页实现八数码启发式A*算法动画效果
Apr 16 Javascript
react 实现页面代码分割、按需加载的方法
Apr 03 Javascript
解析vue data不可以使用箭头函数问题
Jul 03 Javascript
JavaScript面向对象核心知识与概念归纳整理
May 09 Javascript
小程序Scroll-view上拉滚动刷新数据
Jun 21 Javascript
vue使用vue-quill-editor富文本编辑器且将图片上传到服务器的功能
Jan 13 Vue.js
JS函数节流和函数防抖问题分析
Dec 18 #Javascript
vue 将页面公用的头部组件化的方法
Dec 18 #Javascript
浅谈使用React.setState需要注意的三点
Dec 18 #Javascript
vue 项目如何引入微信sdk接口的方法
Dec 18 #Javascript
微信小程序实现给嵌套template模板传递数据的方式总结
Dec 18 #Javascript
微信小程序实现页面跳转传值以及获取值的方法分析
Dec 18 #Javascript
10个在JavaScript开发中常遇到的BUG
Dec 18 #Javascript
You might like
一段php加密解密的代码
2006/10/09 PHP
PHP读取数据库并按照中文名称进行排序实现代码
2013/01/29 PHP
php cookie中点号(句号)自动转为下划线问题
2014/10/21 PHP
Zend Framework入门知识点小结
2016/03/19 PHP
php实现遍历文件夹的方法汇总
2017/03/02 PHP
为jQuery.Treeview添加右键菜单的实现代码
2010/10/22 Javascript
JavaScript的递归之递归与循环示例介绍
2013/08/05 Javascript
今天是星期几的4种JS代码写法
2013/09/17 Javascript
JavaScript中this关键词的使用技巧、工作原理以及注意事项
2014/05/20 Javascript
jQuery Ajax()方法使用指南
2014/11/19 Javascript
基于JS2Image实现圣诞树代码
2015/12/24 Javascript
基于JavaScript短信验证码如何实现
2016/01/24 Javascript
jquery中live()方法和bind()方法区别分析
2016/06/23 Javascript
微信js-sdk分享功能接口常用逻辑封装示例
2016/10/13 Javascript
JavaScript使用链式方法封装jQuery中CSS()方法示例
2017/04/07 jQuery
JavaScript基础心法 数据类型
2018/03/05 Javascript
微信小程序picker组件关于objectArray数据类型的绑定方法
2019/03/13 Javascript
深入浅析vue中cross-env的使用
2019/09/12 Javascript
vue实现员工信息录入功能
2020/06/11 Javascript
[14:36]2014 DOTA2国际邀请赛中国区预选赛5.21 Orenda VS NE
2014/05/22 DOTA
用Python编写脚本使IE实现代理上网的教程
2015/04/23 Python
Python 比较两个数组的元素的异同方法
2017/08/17 Python
Django与JS交互的示例代码
2017/08/23 Python
python中模块的__all__属性详解
2017/10/26 Python
一百多行python代码实现抢票助手
2018/09/25 Python
为何人工智能(AI)首选Python?读完这篇文章你就知道了(推荐)
2019/04/06 Python
Pycharm 2019 破解激活方法图文详解
2019/10/11 Python
python自动识别文本编码格式代码
2019/12/26 Python
Python爬虫过程解析之多线程获取小米应用商店数据
2020/11/14 Python
凯特·丝蓓英国官网:Kate Spade英国
2016/11/07 全球购物
怎样比较两个类型为String的字符串
2016/08/17 面试题
农行实习自我鉴定
2013/09/22 职场文书
银行行长竞聘演讲稿
2014/04/23 职场文书
车队安全员岗位职责
2015/02/15 职场文书
生日宴会家属答谢词
2015/09/29 职场文书
不想升级Win11?教你彻底锁定老版Windows系统的方法(附下载地址)
2022/09/23 数码科技