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将相对地址转换为绝对地址示例代码
Jul 19 Javascript
JQuery实现绚丽的横向下拉菜单
Dec 19 Javascript
javascript教程之不完整的继承(js原型链)
Jan 13 Javascript
ECMAScript中函数function类型
Jun 03 Javascript
基于jQuery Ajax实现上传文件
Mar 24 Javascript
vue.js实现表格合并示例代码
Nov 30 Javascript
jQuery中map函数的两种方式
Apr 07 jQuery
基于jQuery实现手风琴菜单、层级菜单、置顶菜单、无缝滚动效果
Jul 20 jQuery
详述 Sublime Text 打开 GBK 格式中文乱码的解决方法
Oct 26 Javascript
使用vue如何构建一个自动建站项目
Feb 05 Javascript
vue.js select下拉框绑定和取值方法
Mar 03 Javascript
vue-cli3自动消除console.log()的调试信息方式
Oct 21 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
php读取文件内容的三种可行方法示例介绍
2014/02/08 PHP
Destoon模板制作简明教程
2014/06/20 PHP
PHP编程之设置apache虚拟目录
2016/07/08 PHP
PHP设计模式之装饰器模式实例详解
2018/02/07 PHP
Laravel实现短信注册的示例代码
2018/05/29 PHP
JSON 学习之JSON in JavaScript详细使用说明
2010/02/23 Javascript
jquery1.4 教程二 ajax方法的改进
2010/02/25 Javascript
Javascript 网页水印(非图片水印)实现代码
2010/03/01 Javascript
js自定义事件代码说明
2011/01/31 Javascript
JavaScript实现按照指定长度为数字前面补零输出的方法
2015/03/19 Javascript
javascript模拟php函数in_array
2015/04/27 Javascript
JavaScript中常见的字符串操作函数及用法汇总
2015/05/04 Javascript
bootstrap的工具提示实例代码
2017/05/17 Javascript
分享Bootstrap简单表格、表单、登录页面
2017/08/04 Javascript
vue实现分页栏效果
2019/06/28 Javascript
vue实现百度语音合成的实例讲解
2019/10/14 Javascript
Object.keys() 和 Object.getOwnPropertyNames() 的区别详解
2020/05/21 Javascript
Vue时间轴 vue-light-timeline的用法说明
2020/10/29 Javascript
[04:41]2014DOTA2国际邀请赛 Liquid顺利突围晋级正赛
2014/07/09 DOTA
python基础之入门必看操作
2017/07/26 Python
python 简单备份文件脚本v1.0的实例
2017/11/06 Python
python递归函数绘制分形树的方法
2018/06/22 Python
对Pycharm创建py文件时自定义头部模板的方法详解
2019/02/12 Python
5款Python程序员高频使用开发工具推荐
2019/04/10 Python
Pytorch 使用 nii数据做输入数据的操作
2020/05/26 Python
如何利用python正则表达式匹配版本信息
2020/12/09 Python
大四自我鉴定范文
2013/10/06 职场文书
初婚未育证明
2014/01/15 职场文书
施工协议书范本
2014/04/22 职场文书
奥巴马连任演讲稿
2014/05/15 职场文书
2015年国庆节广播稿
2015/08/19 职场文书
python实现监听键盘
2021/04/26 Python
Go语言带缓冲的通道实现
2021/04/26 Golang
解决Pytorch dataloader时报错每个tensor维度不一样的问题
2021/05/28 Python
写一个Python脚本下载哔哩哔哩舞蹈区的所有视频
2021/05/31 Python
Android开发手册自定义Switch开关按钮控件
2022/06/10 Java/Android