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 相关文章推荐
jsPDF生成pdf后在网页展示实例
Jan 16 Javascript
JavaScript中判断整数的多种方法总结
Nov 08 Javascript
快速获取/设置iframe内对象元素的几种js实现方法
May 20 Javascript
jquery.tableSort.js表格排序插件使用方法详解
Aug 12 Javascript
AngularJS实现页面跳转后自动弹出对话框实例代码
Aug 02 Javascript
javascript将url解析为json格式的两种方法
Aug 18 Javascript
快速将Vue项目升级到webpack3的方法步骤
Sep 14 Javascript
Vue2.X 通过AJAX动态更新数据
Jul 17 Javascript
select2 ajax 设置默认值,初始值的方法
Aug 09 Javascript
微信小程序用户位置权限的获取方法(拒绝后提醒)
Nov 15 Javascript
IE11下CKEditor在Bootstrap Modal中下拉问题的解决
Sep 25 Javascript
JavaScript如何实现监听键盘输入和鼠标监点击
Jul 20 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 session
2013/10/28 PHP
php操作xml入门之cdata区段
2015/01/23 PHP
PHP中使用jQuery+Ajax实现分页查询多功能操作(示例讲解)
2017/09/17 PHP
原生JS实现Ajax通过POST方式与PHP进行交互的方法示例
2018/05/12 PHP
jQuery 表格工具集
2010/04/25 Javascript
javascript full screen 全屏显示页面元素的方法
2013/09/27 Javascript
JavaScript的strict模式与with关键字介绍
2014/02/08 Javascript
生成二维码方法汇总
2014/12/26 Javascript
纯Javascript实现ping功能的方法
2015/03/20 Javascript
兼容各大浏览器的JavaScript阻止事件冒泡代码
2015/07/09 Javascript
jQuery DataTables插件自定义Ajax分页实例解析
2020/04/28 Javascript
图解Javascript——作用域、作用域链、闭包
2017/03/21 Javascript
浅谈Angular2 ng-content 指令在组件中嵌入内容
2017/08/18 Javascript
angularJS实现动态添加,删除div方法
2018/02/27 Javascript
JS中call和apply函数用法实例分析
2018/06/20 Javascript
生产制造追溯系统之在线打印功能
2019/06/03 Javascript
关于微信小程序map组件z-index的层级问题分析
2019/07/09 Javascript
vue学习笔记之给组件绑定原生事件操作示例
2020/02/27 Javascript
基于Element封装一个表格组件tableList的使用方法
2020/06/29 Javascript
js实现金山打字通小游戏
2020/07/24 Javascript
vue 实现click同时传入事件对象和自定义参数
2021/01/29 Vue.js
python高阶爬虫实战分析
2018/07/29 Python
python中dict字典的查询键值对 遍历 排序 创建 访问 更新 删除基础操作方法
2018/09/13 Python
numpy.linspace函数具体使用详解
2019/05/27 Python
Python基于模块Paramiko实现SSHv2协议
2020/04/28 Python
css3实现元素环绕中心点布局的方法示例
2019/01/15 HTML / CSS
会计学专业自荐信
2014/06/25 职场文书
驾驶员安全责任书
2014/07/22 职场文书
建筑施工安全责任书
2014/07/24 职场文书
家庭困难证明
2014/10/12 职场文书
党员查摆四风问题思想汇报
2014/10/25 职场文书
2014全年工作总结
2014/11/27 职场文书
美术教师个人工作总结
2015/02/06 职场文书
结婚通知短信大全
2015/04/17 职场文书
教你使用pyinstaller打包Python教程
2021/05/27 Python
吉利入股戴姆勒后smart“长大了”
2022/04/21 数码科技