threejs太阳光与阴影效果实例代码


Posted in Javascript onApril 05, 2022

前言

这篇文章实现智慧城市中模拟太阳光随时间变化产生对应场景效果。为了场景能够更逼真,我们一般会通过对接天气以及阳光等各种环境因素同步到场景中,使得场景能够更贴近现实。比如一些常见的天气系统,下雨、下雪、阴天、雾霾等,我之后会独立一篇文章中提现。这边文章主要介绍一系列灯光,主要是平行光对于太阳的模仿,以及一些材质的问题~

灯光与材质基础篇

常见的灯光:

       - 点光源 (点光源可以理解为一个同时向四面八方散发光线,我们通常用来模拟灯泡,可以产生阴影)

       - 平行光 (平行光可以想象成一个从无限远照射来的光束,通常用来模拟太阳光,可以产生阴影)

       - 聚光灯 (聚光灯字面意思就是类似舞台灯光一样,照射突出特定圆弧形范围,可以产生阴影)

       - 环境光 (一般用于改变整体场景的亮度,也是最常用的光源之一)

这里提一嘴材质:(仅仅列举常用的)

       - 网格基础材质(MeshBasicMaterial,不支持阴影)

       - FBR材质

           - 物理标准材质(MeshStandardMaterial)

           - MeshPhysicalMaterial

           - 以上两者FBR材质相对于高光网格材质效果更好

       - MeshPhongMaterial(高光网格材质,高亮表面、镜面反射)

       - MeshLambertMaterial(网格Lambert材质,暗淡,漫反射)

这里简单做一下介绍,不懂的同学可以具体去了解某个材质

太阳光

添加平行光-----从东至西调整位置-----调整亮度以及颜色-----添加过渡模拟太阳光

接下来介绍本文的重点,如何模拟太阳光照的变化。其实原理非常简单,就是添加平行光,调整场景模型的阴影关系,根据时间实时变化平行光的位置以及光照强度以及颜色即可模拟~

整体调用代码

由于是一个demo,所以注重效果,一切从简实现功能

sun() { //两秒变化一次平行光
  let i=0
  setInterval(()=>{
    this.initSun(i)
    i++
  },2000)
}

简单实现通过定时器以及提前写好对应位置光照的信息。主要是思想,酌情根据自己的需求可以改变~

这里这么写主要是实现效果,真实的应该根据系统时间将太阳光做出调整,包括根据天气原因,换汤不换药,主要还是

手动调整并存储为json通过传入时间以及天气去做出转化~ 

Viewer.prototype.initSun = function (type) {
  let position = {}
  let color = '#ffffff'
  let intensity = 1
  switch (type) {
    case 0:
      position = {
        x: 270,
        y: 150,
        z: 0
      }
      intensity = 5
      break
    case 1:
      position = {
        x: 258,
        y: 170,
        z: 0
      }
      intensity = 7
      color = '#fcffc9'
      break
    case 2:
      position = {
        x: 245,
        y: 180,
        z: 0
      }
      intensity = 10
      color = '#ffe69f'
      break
    case 3:
      position = {
        x: 0,
        y: 100,
        z: 0
      }
      intensity = 15
      color = '#ffe69f'
      break
    case 4:
      position = {
        x: -245,
        y: 180,
        z: 0
      }
      intensity = 10
      color = '#e3894d'
      break
    case 5:
      position = {
        x: -258,
        y: 160,
        z: 0
      }
      intensity = 10
      color = '#ff8400'
      break
    default :
      position = {
        x: -270,
        y: 150,
        z: 0
      }
      intensity = 8
      color = '#ff8400'
      break
  }
  if (this.directionalLight) {
    this.directionalLight.setSun(position,color,intensity)
  } else {
    this.directionalLight = new zhdSun()
    this.directionalLight.renderFn(this.renderFunction)
    this.directionalLight.init({
      position,
      color,
      intensity,
      scene: this.scene,
      currentlayers: this.currentlayers
    })
  }
}

太阳光类

这里主要对太阳光类的拆解与分析,封装的比较粗糙,酌情个人可以优化

import TWEEN from '@tweenjs/tween.js'
import {zhdObject} from './zhdObject'
export class zhdSun extends zhdObject {
  constructor() {
    super()
    this.light = null
  }
}
//由于添加了TWEEN动画库,记得在animate中实时更新TWEEN
TWEEN.update()

初始化

这里做的是向场景中添加平行光,设置其阴影的范围以及距离等属性,因为我这边涉及层级,所以设置了平行光的层级

平行光可谓是所有灯光中阴影调整最麻烦的,想要平行光能够产生对的阴影效果,模型的产生阴影以及接收阴影要调整好,并且平行光的照射范围也要调整好。我效果图中不知大家有没有发现,在正午时刻的时候太阳光照射地面产生了一个长方形的范围阴影,这里是特地录制一个相对不那么完美的版本。

产生原因:平行光范围太小,但是一旦你调整平行光范围过大,由于地面是通过多个瓦片加载的,就会出现条纹状的阴影

如下图

解决方法:调整平行光阴影的bias属性,有助于减少阴影中的伪影

threejs太阳光与阴影效果实例代码

init({position, color, intensity , currentlayers, scene}) {
  const directionalLight = new THREE.DirectionalLight(color, intensity) // 新建一个平行光源,颜色未白色,强度为1
  this.light = directionalLight
  directionalLight.position.set(position.x, position.y, position.z) // 将此平行光源调整到一个合适的位置
  directionalLight.castShadow = true // 将此平行光源产生阴影的属性打开
  // 设置平行光的的阴影属性,即一个长方体的长宽高,在设定值的范围内的物体才会产生阴影
  const d =100 //阴影范围
  directionalLight.shadow.camera.left = -d
  directionalLight.shadow.camera.right = d
  directionalLight.shadow.camera.top = d
  directionalLight.shadow.camera.bottom = -d
  directionalLight.shadow.camera.near = 20
  directionalLight.shadow.camera.far = 8000
  directionalLight.shadow.mapSize.x = 2048 // 定义阴影贴图的宽度和高度,必须为2的整数此幂
  directionalLight.shadow.mapSize.y = 2048 // 较高的值会以计算时间为代价提供更好的阴影质量
  directionalLight.shadow.bias = -0.0005 //解决条纹阴影的出现
  this.setlayers(directionalLight, currentlayers)
  scene.add(directionalLight) // 将此平行光源加入场景中,我们才可以看到这个光源
  return directionalLight
}

设置平行光信息

设置平行光的信息:包括位置、颜色、强度

setSun(position, color, intensity) {
  this.setTweens(this.light.position, position, 2000)
  this.light.color = new THREE.Color( color )
  this.light.intensity = intensity
}

Tween

这里简单介绍TWEEN不懂的可以去看我之前的文章,主要是一个动画库,这里做简单的封装

setTweens(obj, newObj, duration = 1500) {
  var ro = new TWEEN.Tween(obj)
  ro.to(newObj, duration) // 变化后的位置以及动画时间
  ro.easing(TWEEN.Easing.Sinusoidal.InOut)
  ro.onUpdate(function () {
  })
  ro.start()
}

总结

到此这篇关于threejs太阳光与阴影效果的文章就介绍到这了,更多相关threejs太阳光与阴影内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
一个简单的弹性返回顶部JS代码实现介绍
Jun 09 Javascript
如何使Chrome控制台支持多行js模式——意外发现
Jun 13 Javascript
js中的屏蔽的使用示例
Jul 30 Javascript
jQuery遍历Form示例代码
Sep 03 Javascript
关于jquery的多个选择器的使用示例
Oct 18 Javascript
jquery validate添加自定义验证规则(验证邮箱 邮政编码)
Dec 04 Javascript
Jquery1.9.1源码分析系列(六)延时对象应用之jQuery.ready
Nov 24 Javascript
async/await地狱该如何避免详解
May 10 Javascript
Vue2 监听属性改变watch的实例代码
Aug 27 Javascript
在Vue中使用this.$store或者是$route一直报错的解决
Nov 08 Javascript
关于引入vue.js 文件的知识点总结
Jan 28 Javascript
Vue Element UI自定义描述列表组件
May 18 Vue.js
JS实现数组去重的11种方法总结
Apr 04 #Javascript
vue使用wavesurfer.js解决音频可视化播放问题
Apr 04 #Vue.js
JavaScript模拟实现网易云轮播效果
Javascript中Microtask和Macrotask鲜为人知的知识点
vue中div禁止点击事件的实现
Apr 02 #Vue.js
Vue组件更新数据v-model不生效的解决
Apr 02 #Vue.js
Vue+TypeScript中处理computed方式
Apr 02 #Vue.js
You might like
PHP中的按位与和按位或操作示例
2014/01/27 PHP
ThinkPHP调用common/common.php函数提示错误function undefined的解决方法
2014/08/25 PHP
php使用curl打开https网站的方法
2015/06/17 PHP
PHP Web木马扫描器代码分享
2015/09/06 PHP
PHP使用curl模拟post上传及接收文件的方法
2016/03/04 PHP
PHP正则表达式入门教程(推荐)
2016/05/18 PHP
PHP实现登录搜狐广告获取广告联盟数据的方法【附demo源码】
2016/10/14 PHP
php面向对象的用户登录身份验证
2017/06/08 PHP
layui数据表格自定义每页条数limit设置
2019/10/26 PHP
Laravel 修改验证异常的响应格式实例代码详解
2020/05/25 PHP
jQuery 方法大全方便学习参考
2010/02/25 Javascript
js页面滚动时层智能浮动定位实现(jQuery/MooTools)
2011/08/23 Javascript
jQuery toggleClass应用实例(附效果图)
2014/04/06 Javascript
js获取内联样式的方法
2015/01/27 Javascript
JavaScript中Boolean对象的属性解析
2015/10/21 Javascript
jQuery插件之jQuery.Form.js用法实例分析(附demo示例源码)
2016/01/04 Javascript
JavaScript html5 canvas画布中删除一个块区域的方法
2016/01/26 Javascript
jQuery操作cookie
2016/08/08 Javascript
js通过classname来获取元素的方法
2016/11/24 Javascript
垃圾回收器的相关知识点总结
2018/05/13 Javascript
egg.js的基本使用和调用数据库的方法示例
2019/05/18 Javascript
Vuex新手的理解与使用详解
2019/05/31 Javascript
[31:01]2014 DOTA2国际邀请赛中国区预选赛5.21 CNB VS Orenda
2014/05/23 DOTA
在Python的web框架中配置app的教程
2015/04/30 Python
Python中shape计算矩阵的方法示例
2017/04/21 Python
python2.7读取文件夹下所有文件名称及内容的方法
2018/02/24 Python
佳能英国官方网站:Canon UK
2017/08/08 全球购物
Artist Guitars新西兰:乐器在线商店
2017/09/17 全球购物
经理管理专业毕业自荐书范文
2014/02/12 职场文书
村干部培训方案
2014/05/02 职场文书
投标文件签署授权委托书范本
2014/10/12 职场文书
党员批评与自我批评
2014/10/15 职场文书
先进个人评语大全
2015/01/04 职场文书
2015年幼儿园师德师风建设工作总结
2015/10/23 职场文书
使用Djongo模块在Django中使用MongoDB数据库
2021/06/20 Python
Dubbo+zookeeper搭配分布式服务的过程详解
2022/04/03 Java/Android