博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Three.js 学习笔记 - 给跳一跳小游戏添加光源,阴影
阅读量:6591 次
发布时间:2019-06-24

本文共 7252 字,大约阅读时间需要 24 分钟。

一. 修改物体材质

接着上一篇的项目,在上一篇中物体的材质都是用的MeshBasicMaterial这种材质,这种材质是不受光照的影响的,所以要修改成MeshPhongMaterial这种材质,让它受光照的影响。

在cylinder.js 和 box.js中将MeshBasicMaterial改为MeshPhongMaterial

const material = new THREE.MeshPhongMaterial({    color: 0xffffff})复制代码

这时候就渲染结果就是这个样子:

物体都看不见了,因为没有光

二. 添加环境光

官方文档是这样解释环境光的:

环境光会均匀的照亮场景中的所有物体。环境光不能用来投射阴影,因为它没有方向。

可以理解为从各个方向照向物体的光

在renderer目录下,新建light.js

const light = () => {  return {    ambientLight: new THREE.AmbientLight(0xffffff, 0.8)  }}export default light复制代码

new THREE.AmbientLight第一个参数是光的颜色,第二个参数是光强。

scene.js

import light from './light'const scene = () => {  const sceneInstance = new THREE.Scene()  const axesHelper = new THREE.AxesHelper(100)  const lights = light()  Object.keys(lights).forEach(value => {    sceneInstance.add(lights[value])  })  sceneInstance.add(axesHelper)  return sceneInstance}export default scene复制代码

效果:

现在物体就可以看见了,由于环境光不能投射阴影,所以需要其他的光,下面试下其他光的效果

三. 其他类型的光

  • 平行光

    平行光就是从光源处到物体的光线都是平行的,官方文档上说类似太阳光,它是可以产生阴影的。

    light.js

    const light = () => {    const directionalLight = new THREE.DirectionalLight(0xFF8C00)    directionalLight.position.set(10, 30, 20) // 设置光源的位置    return {        ambientLight: new THREE.AmbientLight(0xffffff, 0.5),        directionalLight    }}export default light复制代码

    看下效果:

    因为不加环境光太暗了,所以还是在有环境光的情况下测试,这时候就能看出来物体不同的面受到的光照强度是不同的。

  • 半球光

    并没有从文档上看懂半球光是什么。。先记住一点半球光不能产生阴影,把之前的平行光改成半球光:

    light.js

    const light = () => {    const hemisphereLight = new THREE.HemisphereLight(0x8A2BE2, 0xFFFAFA, 1)    hemisphereLight.position.set(10, 30, 20) // 设置光源的位置    return {        ambientLight: new THREE.AmbientLight(0xffffff, 0.5),        hemisphereLight    }}export default light复制代码

    效果:

    这篇文章给了详细的例子,可以看看。

  • 点光源

    这个好理解,就像蜡烛或者灯泡发出的光线。

    light.js

    const light = () => {    const pointLight = new THREE.PointLight(0x1a94bc, 1, 100)    pointLight.position.set(10, 30, 20) // 设置光源的位置    return {        ambientLight: new THREE.AmbientLight(0xffffff, 0.5),        pointLight    }}export default light复制代码

    看起来和平行光也很像

    但是这个点光源是有一个衰减值的,就是光源离物体越远,光的强度就越低,平行光不会,距离再远也是相同的光强

  • 平面光光源

    这个从名字上就能理解,就是从一个平面发出平行光。

    light.js

    const light = () => {    const pointLight = new THREE.PointLight(0x1a94bc, 1, 100, 100)    pointLight.position.set(10, 30, 20) // 设置光源的位置    return {        ambientLight: new THREE.AmbientLight(0xffffff, 0.5),        pointLight    }}export default light复制代码

    这种光只支持 MeshStandardMaterial 和 MeshPhysicalMaterial 两种材质,所以还得去改一下box.js 和 cylinder.js 中物体的材质

    const material = new THREE.MeshStandardMaterial({  color: 0xffffff})复制代码

    和平行光的效果差不多

  • 聚光灯

    这个在官方文档上有个很好的例子,一看就明白了,这里就不写了。

    看了效果之后决定选择平行光,因为能产生阴影,效果也还可以,最终light.js的代码:

    const light = () => {    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.3)    directionalLight.position.set(10, 30, 20) // 设置光源的位置    return {        ambientLight: new THREE.AmbientLight(0xffffff, 0.8),        directionalLight    }}export default light复制代码

    记得把box.js 和 cylinder.js 中的材质改回来(MeshPhongMaterial)

三. 实现阴影效果

实现阴影效果需要具备以下条件:

  1. 渲染器启用阴影
  2. 可以形成阴影的光源
  3. 能够表现阴影的材质
  4. 物体可以投射阴影
  5. 接受阴影的物体

现在就一步一步实现上面的条件:

  • 渲染器开启阴影

    renderer -> index.js 添加

    init () {    this.instance.shadowMap.enabled = true   // 新增,渲染器启用阴影}复制代码
  • 形成阴影的光源

    上面说过平行光是可以投射阴影的,所以用它就好了。

    ligth.js

    const light = () => {    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.3)    directionalLight.position.set(10, 30, 20) // 设置光源的位置    directionalLight.castShadow = true  // 新增,产生动态阴影        directionalLight.shadow.camera.near = 0.5 // 新增    directionalLight.shadow.camera.far = 500 // 新增    directionalLight.shadow.camera.left = -100 // 新增    directionalLight.shadow.camera.right = 100 // 新增    directionalLight.shadow.camera.top = 100 // 新增    directionalLight.shadow.camera.bottom = -100 // 新增        directionalLight.shadow.mapSize.width = 1024 // 新增    directionalLight.shadow.mapSize.height = 1024 // 新增    return {        ambientLight: new THREE.AmbientLight(0xffffff, 0.8),        directionalLight    }}export default light复制代码
  • 能够表现阴影的材质

    物体使用的是MeshPhongMaterial材质,这个材质是可以产生阴影的,这里就不用改了

  • 物体可以投射阴影

    在cylinder.js 和 box.js 中分别添加如下代码:

    create () {    this.instance.castShadow = true // 新增,让物体可以投射阴影    this.instance.receiveShadow = true // 新增,让物体可以接受阴影}复制代码
  • 接受阴影的物体

    在现实生活中接受阴影的物体最常见的就是地面了,这里也是一样,需要给现在的场景添加一个地面

    新建ground.js

    const ground = () => {    const groundGeometry = new THREE.PlaneGeometry(200, 200)    const groundMaterial = new THREE.MeshStandardMaterial({        color: 0xffffff    })    const instance = new THREE.Mesh(groundGeometry, groundMaterial)    instance.receiveShadow = true    return instance}export default ground复制代码

    现在去看看效果:

    这个效果炸了呀。

    ground变成了墙而不是地面。所以需要旋转一下

    让他沿着x轴转负90度

    instance.rotateX(-Math.PI / 2)复制代码

    效果:

    现在就和x轴在同一平面了,只是有点高,把物体切断了,再往下移一点

    instance.position.y = -5复制代码

    现在的效果是:

  • 添加背景

    由于这样的地面太丑,现在不用MeshStandardMaterial这个材质了,改用ShadowMaterial材质,

    ground.js

    const ground = () => {    const groundGeometry = new THREE.PlaneGeometry(200, 200)    const groundMaterial = new THREE.ShadowMaterial({        color: 0x000000,        opacity: 0.3    })    const instance = new THREE.Mesh(groundGeometry, groundMaterial)    instance.rotateX(-Math.PI / 2)    instance.position.y = -5    instance.receiveShadow = true    return instance}export default ground复制代码

    改完之后现在整个地面又变黑了,暂时不用管,加上背景就好了

    背景应该和相机看到的范围一样大,所以背景的尺寸要用到相机相关的变量size,这里为了方便维护,把这个变量单独存放:

    camera_config.js

    export default {    size: 30}复制代码

    新建background.js

    import cameraConfig from '../../configs/camera_config'const background = () => {    const backgroundGeometry = new THREE.PlaneGeometry(        cameraConfig.size * 2,        window.innerHeight / window.innerWidth * cameraConfig.size * 2    )    const backgroundMaterial = new THREE.MeshBasicMaterial({        color: 0xd7dbe6    })    const instance = new THREE.Mesh(backgroundGeometry, backgroundMaterial)    instance.position.z = -85    return instance}export default background复制代码

    camera.js修改为下面这样

    import cameraConfig from '../../configs/camera_config'  // 新增const camera = () => {    const ratio = window.innerHeight / window.innerWidth    const { size } = cameraConfig  // 改动    // 设置相机可看到范围    const cameraInstance = new THREE.OrthographicCamera(        -size, size, size * ratio, -size * ratio, -100, 85  // 改动    )    cameraInstance.position.set(-10, 10, 10) // 设置相机位置    cameraInstance.up.set(0, 1, 0)    cameraInstance.lookAt(new THREE.Vector3(0, 0, 0)) // 设置相机位置从0, 0, 0望向0, 0, 0    return cameraInstance}export default camera复制代码

    renderer -> index.js

    import camera from './camera'import scene from './scene'import background from '../objects/background'  // 新增class Renderer {    constructor () {        this.camera = null        this.scene = null    }    init () {        this.camera = camera()        this.scene = scene()        const { width, height } = canvas        if (window.devicePixelRatio) {            canvas.height = height * window.devicePixelRatio            canvas.width = width * window.devicePixelRatio        }        this.instance = new THREE.WebGLRenderer({            canvas,            antialias: true        })        this.instance.shadowMap.enabled = true        this.scene.add(this.camera)  // 新增,这一步很重要        this.camera.add(background())  // 新增    }    render () {        this.instance.render(this.scene, this.camera)    }}export default new Renderer()复制代码

    去开发者工具看看效果:

    现在就比较正常了。

    完整代码

接下来就是实现跳一跳中的小人了

转载于:https://juejin.im/post/5d02243ee51d45572c060031

你可能感兴趣的文章
Extjs - Panel组件
查看>>
收集参数及反转过程
查看>>
PPTP××× 数据分流
查看>>
我的友情链接
查看>>
mongodb 索引
查看>>
dhcp服务的讲解和在Linux环境下的搭建
查看>>
PHP fopen和fwrite函数实现创建html页面
查看>>
Citrix 宣布 XenServer 全面开源
查看>>
我的友情链接
查看>>
oracle 如果为空则输出0
查看>>
Mysql聚合函数count(*) 的性能分析
查看>>
[Cordova-IOS]JavaScript与Swift交互
查看>>
Spfa(最短路求解)
查看>>
用一个view来自定义tabbarController,可以实现隐藏
查看>>
使用linux-c编程实现简单的ls命令
查看>>
Q:按F12进行网络安装系统时,一直无法进入,提示加载失败?
查看>>
我的友情链接
查看>>
基于SSH框架、Oracle数据库、easyui的分页显示
查看>>
解决AutoCAD acmgd.dll ARX命令中发现异常
查看>>
[转]passport.js学习笔记
查看>>