美文网首页
three.js - Shadow

three.js - Shadow

作者: 闪电西兰花 | 来源:发表于2024-01-07 10:09 被阅读0次
    • The dark shadow in the back of the objects are called core shadows, we will going to do drop shadows
    • when you do a render, Three.js will do a render for each light supporting shadows
    • those renders will simulate what the light sees as if it was a camera
    • during these light renders, a MeshDepthMaterial replaces all meshs materials
    • the lights renders are stored as textures and we call those shadow maps
    • 准备一个基础场景,包含一个球、平面


      image.png
    import * as THREE from 'three'
    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
    // 导入gui
    import * as dat from 'dat.gui'
    
    /*
      * scene
    */
    const scene = new THREE.Scene()
    
    /*
      * Objects
    */
    // MeshStandardMaterial
    const material = new THREE.MeshStandardMaterial()
    material.roughness = 0.4
    
    // 球体
    const sphere = new THREE.Mesh(
      new THREE.SphereGeometry(0.5, 32, 32),
      material
    )
    
    // 平面
    const plane = new THREE.Mesh(
      new THREE.PlaneGeometry(5, 5),
      material
    )
    plane.rotation.x = - Math.PI * 0.5
    plane.position.y = - 0.65
    
    scene.add(sphere, plane)
    
    /*
      * size
    */
    const sizes = {
      width: window.innerWidth,
      height: window.innerHeight
    }
    
    window.addEventListener('resize', () => {
      sizes.width = window.innerWidth
      sizes.height = window.innerHeight
    })
    
    /*
      * camera
    */
    const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 1, 1000) 
    camera.position.z = 3
    scene.add(camera) 
    
    /*
      * render
    */
    const renderer = new THREE.WebGLRenderer()
    renderer.setSize(sizes.width, sizes.height)
    renderer.setPixelRatio(Math.min(window.devicePixelRatio))
    renderer.shadowMap.enabled = true
    document.body.appendChild(renderer.domElement)
    
    /*
      * controls
    */
    const controls = new OrbitControls(camera, renderer.domElement)
    controls.enableDamping = true
    
    /*
      *Animations
    */
    const clock = new THREE.Clock()
    const tick = () => {
      let elapsedTime = clock.getElapsedTime()
      controls.update()
      renderer.render(scene, camera)
      window.requestAnimationFrame(tick)
    }
    tick()
    
    • 添加环境光、平行光
    /*
      * Lights
    */
    // AmbientLight
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
    scene.add(ambientLight)
    
    // DirectionalLight
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)
    directionalLight.position.set(2, 2, -1)
    scene.add(directionalLight)
    
    • 灯光阴影的条件:
      1. 材质需要对光照有反应
      2. 设置渲染器开启阴影的计算 renderer.shadowMap.enabled = true
      3. 设置光照投射阴影 directionalLight.castShadow = true
      4. 设置物体投射阴影 sphere.castShadow = true
      5. 设置物体接收阴影 plane.receiveShadow = true(这里是平面接收阴影)
      /**
       * 3. 创建渲染器
      **/
      ...
      ...
      renderer.shadowMap.enabled = true  // 开启场景中的阴影贴图
    
      /*
        * 4. 创建几何体
      */
      ...
      ...
      sphere.castShadow = true  // sphere 投射阴影
      ...
      ...
      plane.receiveShadow = true    // 平面接收阴影
    
    /*
      * Lights
    */
    ...
    ...
    // DirectionalLight
    ...
    directionalLight.castShadow = true
    
    directionalLight.shadow.mapSize.set(1024, 1024) // 阴影贴图分辨率,值为2的幂次方,默认512 * 512
    
    // 观察光源的相机对象,从光的角度来看
    directionalLight.shadow.camera.near = 1 
    directionalLight.shadow.camera.far = 6
    directionalLight.shadow.camera.top = 5
    directionalLight.shadow.camera.bottom = -5
    directionalLight.shadow.camera.left = -5
    directionalLight.shadow.camera.right = 5
    
    directionalLight.shadow.radius = 10 // 阴影边缘模糊度
    
      // SpotLight (与上面的DirectionalLight可对比观察)
      const spotLight = new THREE.SpotLight(0x78ff00, 1, 10, Math.PI * 0.1, 0.25, 1)
      spotLight.position.set(1.5, 1.5, 1.5);
      spotLight.castShadow = true
      spotLight.target = sphere // 聚光灯目标,移动物体时,灯光跟随物体
      spotLight.angle = Math.PI / 6 // 聚光灯角度,一般不超过90°
      spotLight.distance = 5 // 聚光灯光源发出的距离
      spotLight.penumbra = 0.5 // 聚光灯半影衰减,数值越接近1时,灯光边缘越模糊
    
      // 阴影边缘模糊度 
      spotLight.shadow.radius = 20
      
      // 阴影贴图分辨率
      spotLight.shadow.mapSize.set(4096, 4096)
    
    • CamereHelper - 辅助对象
    const directionalLightCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)
    scene.add(directionalLightCameraHelper)
    
    image.png
    • Baking Shadows
      • A good alternative to Three.js shadows is baked shadows, we integrate shadow in textures that we apply on materials, 不是一个实时的阴影,但可以通过创建阴影、修改阴影位置的方式使其跟着物体动起来
      // texture
      const textureLoader = new THREE.TextureLoader()
      const simpleShadow = textureLoader.load(require('../assets/imgs/simpleShadow.jpeg'))
      
      // 阴影,略高于之前创建的plane
      const sphereShadow = new THREE.Mesh(
        new THREE.PlaneGeometry(1.5, 1.5),
        new THREE.MeshBasicMaterial({
          color: 0x000000,
          transparent: true,
          alphaMap: simpleShadow
        })
      )
      sphereShadow.rotation.x = - Math.PI * 0.5
      sphereShadow.position.y = plane.position.y + 0.01 // 略高于plane
      
      /*
        *Animations
      */
      const clock = new THREE.Clock()
      const tick = () => {
        let elapsedTime = clock.getElapsedTime()
      
        // update sphere
        sphere.position.x = Math.cos(elapsedTime) * 1.5
        sphere.position.z = Math.sin(elapsedTime) * 1.5
        sphere.position.y = Math.abs(Math.sin(elapsedTime * 3))
      
        // update sphereSHadow
        sphereSHadow.position.x = sphere.position.x
        sphereSHadow.position.z = sphere.position.z
        sphereSHadow.material.opacity = (1 - Math.abs(sphere.position.y)) * 0.3
      
        controls.update()
        renderer.render(scene, camera)
        window.requestAnimationFrame(tick)
      }
      tick()
      

    相关文章

      网友评论

          本文标题:three.js - Shadow

          本文链接:https://www.haomeiwen.com/subject/giptbdtx.html