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 相关文章推荐
基于jquery的一个简单的脚本验证插件
Apr 05 Javascript
解析Jquery的LigerUI如何实现文件上传
Jul 09 Javascript
jquery的trigger和triggerHandler的区别示例介绍
Apr 20 Javascript
JavaScript中this关键词的使用技巧、工作原理以及注意事项
May 20 Javascript
浅析javascript中函数声明和函数表达式的区别
Feb 15 Javascript
JavaScript定时器和优化的取消定时器方法
Jul 03 Javascript
图片旋转、鼠标滚轮缩放、镜像、切换图片js代码
Dec 13 Javascript
基于JavaScript实现瀑布流布局(二)
Jan 26 Javascript
JavaScript 是什么意思
Sep 22 Javascript
JavaScript跳出循环的三种方法(break, return, continue)
Jul 30 Javascript
layer 刷新某个页面的实现方法
Sep 05 Javascript
node.js中path路径模块的使用方法实例分析
Feb 13 Javascript
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操作Memcache实例介绍
2013/06/14 PHP
php中json_encode处理gbk与gb2312中文乱码问题的解决方法
2014/07/10 PHP
基于jQuery+HttpHandler实现图片裁剪效果代码(适用于论坛, SNS)
2011/09/02 Javascript
javascript获取作用在元素上面的样式属性代码
2012/09/20 Javascript
JavaScript和jquery获取父级元素、子级元素、兄弟元素的方法
2016/06/05 Javascript
JS中去掉array中重复元素的方法
2017/05/26 Javascript
es6+angular1.X+webpack 实现按路由功能打包项目的示例
2017/08/16 Javascript
React实践之Tree组件的使用方法
2017/09/30 Javascript
node.js基于fs模块对系统文件及目录进行读写操作的方法详解
2017/11/10 Javascript
微信小程序使用modal组件弹出对话框功能示例
2017/11/29 Javascript
全面介绍vue 全家桶和项目实例
2017/12/27 Javascript
配置eslint规范项目代码风格
2019/03/11 Javascript
vue实现文字横向无缝走马灯组件效果的实例代码
2019/04/09 Javascript
如何自动化部署项目?折腾服务器之旅~
2019/04/16 Javascript
详解Vue路由自动注入实践
2019/04/17 Javascript
如何在JavaScript中谨慎使用代码注释
2019/06/21 Javascript
js如何验证密码强度
2020/03/18 Javascript
关于element的表单组件整理笔记
2021/02/05 Javascript
python通过邮件服务器端口发送邮件的方法
2015/04/30 Python
python函数局部变量用法实例分析
2015/08/04 Python
Python登录并获取CSDN博客所有文章列表代码实例
2017/12/28 Python
matplotlib作图添加表格实例代码
2018/01/23 Python
使用Python操作FTP实现上传和下载的方法
2019/04/01 Python
多版本python的pip 升级后, pip2 pip3 与python版本失配解决方法
2019/09/11 Python
Python实现列表索引批量删除的5种方法
2020/11/16 Python
纯CSS3实现给头像加个光芒四射且旋转的背景动画效果
2014/05/07 HTML / CSS
CSS3实现伪类hover离开时平滑过渡效果示例
2017/08/10 HTML / CSS
有关HTML5 Video对象的ontimeupdate事件(Chrome上无效)的问题
2013/07/19 HTML / CSS
Tech21美国/加拿大:英国NO.1防摔保护壳品牌
2018/01/20 全球购物
wedgwood加拿大官网:1759年成立的英国国宝级陶瓷餐具品牌
2018/07/17 全球购物
造型师求职自荐信
2013/09/27 职场文书
高中生操行评语大全
2014/04/25 职场文书
社区个人对照检查材料(群众路线)
2014/09/26 职场文书
MBA推荐信怎么写
2015/03/25 职场文书
物业保洁员管理制度
2015/08/05 职场文书
单位病假条范文
2015/08/17 职场文书