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 相关文章推荐
javascript 控制弹出窗口
Apr 10 Javascript
Prototype 学习 工具函数学习($A方法)
Jul 12 Javascript
圣诞节Merry Christmas给博客添加浪漫的下雪效果基于jquery实现
Dec 27 Javascript
js setTimeout()函数介绍及应用以倒计时为例
Dec 12 Javascript
为jquery的ajaxfileupload增加附加参数的方法
Mar 04 Javascript
在JavaScript里防止事件函数高频触发和高频调用的方法
Sep 06 Javascript
jQuery中extend函数的实现原理详解
Feb 03 Javascript
HTML5+Canvas调用手机拍照功能实现图片上传(下)
Apr 21 Javascript
微信小程序form表单组件示例代码
Jul 15 Javascript
浅谈Javascript中的对象和继承
Apr 19 Javascript
.netcore+vue 实现压缩文件下载功能
Sep 24 Javascript
javascript实现下拉菜单效果
Feb 09 Javascript
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
通过JavaScript或PHP检测Android设备的代码
2011/03/09 PHP
php 去除html标记--strip_tags与htmlspecialchars的区别详解
2013/06/26 PHP
PHP根据IP地址获取所在城市具体实现
2013/11/27 PHP
[原创]解决wincache不支持64位PHP5.5/5.6的问题(提供64位wincache下载)
2016/06/22 PHP
php简单随机字符串生成方法示例
2017/04/19 PHP
PHP+mysql防止SQL注入的方法小结
2019/04/27 PHP
修改Laravel自带的认证系统的User类的命名空间的步骤
2019/10/15 PHP
Web 前端设计模式--Dom重构 提高显示性能
2010/10/22 Javascript
js String对象中常用方法小结(字符串操作)
2012/01/27 Javascript
JS根据变量保存方法名并执行方法示例
2014/04/04 Javascript
ECMAScript5中的对象存取器属性:getter和setter介绍
2014/12/08 Javascript
使用Chrome浏览器调试AngularJS应用的方法
2015/06/18 Javascript
jquery实现手风琴效果
2015/11/20 Javascript
js操作数组函数实例小结
2015/12/10 Javascript
vue2.0移动端滑动事件vue-touch的实例代码
2018/11/27 Javascript
微信小程序利用swiper+css实现购物车商品删除功能
2019/03/06 Javascript
[49:27]2018DOTA2亚洲邀请赛 4.4 淘汰赛 TNC vs VG 第一场
2018/04/05 DOTA
[01:16]DOTA2小知识课堂 Ep.03 芒果树无伤肉山
2019/12/05 DOTA
Python 用户登录验证的小例子
2013/03/06 Python
Python函数中定义参数的四种方式
2014/11/30 Python
python使用win32com库播放mp3文件的方法
2015/05/30 Python
python通过百度地图API获取某地址的经纬度详解
2018/01/28 Python
python读取目录下最新的文件夹方法
2018/12/24 Python
python读取Excel表格文件的方法
2019/09/02 Python
python爬虫 猫眼电影和电影天堂数据csv和mysql存储过程解析
2019/09/05 Python
Pycharm pyuic5实现将ui文件转为py文件,让UI界面成功显示
2020/04/08 Python
k-means 聚类算法与Python实现代码
2020/06/01 Python
Python的信号库Blinker用法详解
2020/12/31 Python
解决virtualenv -p python3 venv报错的问题
2021/02/05 Python
道路交通安全实施方案
2014/03/12 职场文书
村干部培训班主持词
2014/03/28 职场文书
领导班子对照检查材料
2014/09/22 职场文书
2014超市双十一活动策划方案
2014/09/29 职场文书
2014年护士工作总结范文
2014/11/11 职场文书
2016年企业先进员工事迹材料
2016/02/25 职场文书
小学生一年级(书信作文)
2019/08/13 职场文书