美文网首页
three.js - Environment Map

three.js - Environment Map

作者: 闪电西兰花 | 来源:发表于2024-06-26 17:20 被阅读0次
  • Environment Map
    • as a background
    • as reflection
    • as lighting
  • Set up
<script setup>
  import * as THREE from 'three'
  import {OrbitControls} from 'three/addons/controls/OrbitControls.js'
  import GUI from 'lil-gui'

  /**
   * scene
  */
  const scene = new THREE.Scene()

  /**
   * torus knot
  */
  const torusKnot = new THREE.Mesh(
    new THREE.TorusKnotGeometry(1, 0.4, 100, 16),
    new THREE.MeshBasicMaterial()
  )
  torusKnot.position.y = 4
  scene.add(torusKnot)

  /**
   * camera
  */
  const camera = new THREE.PerspectiveCamera(
    75, 
    window.innerWidth / window.innerHeight, 
    0.1, 
    100)
  camera.position.set(4, 5, 4)
  scene.add(camera)

  /**
   * renderer
  */
  const renderer = new THREE.WebGLRenderer({})
  renderer.setSize(window.innerWidth, window.innerHeight)
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
  document.body.appendChild(renderer.domElement)

  window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()

    renderer.setSize(window.innerWidth, window.innerHeight) 
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))  
  })

  /**
   * control
  */
  const controls = new OrbitControls(camera, renderer.domElement)
  controls.target.y = 3.5
  controls.enableDamping = true

  /**
   * tick
  */
  const tick = () => {
    controls.update()
    renderer.render(scene, camera)
    requestAnimationFrame(tick)
  }
  tick()

  /**
   * gui
  */
  const gui = new GUI()
</script>
Set up.png
  • Model
    • 添加model后向下移动camera就能看见了
    import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
    
    /**
     * loaders
    */
    const gltfLoader = new GLTFLoader()
    ...
    ...
    /**
     * models
    */
    gltfLoader.load(
      '../public/models/environment-map/models/FlightHelmet/glTF/FlightHelmet.gltf',
      (gltf) => {
        // console.log((gltf));
        scene.add(gltf.scene)
      }
    )
    
    model.png
    • the model is too small and it's black, because its materials are MeshStandardMaterial and those need light
    • cube texture environment map, load the textures in this order: positive x, negative x, positive y, negative y, positive z, negative z
    /**
     * loaders
    */
    ...
    const cubeTextureLoader = new THREE.CubeTextureLoader()
    
    /**
     * environment map
    */
    // LDR cube texture
    const environmentMap = cubeTextureLoader.load([
      '../public/models/environment-map/environmentMaps/0/px.png',
      '../public/models/environment-map/environmentMaps/0/nx.png',
      '../public/models/environment-map/environmentMaps/0/py.png',
      '../public/models/environment-map/environmentMaps/0/ny.png',
      '../public/models/environment-map/environmentMaps/0/pz.png',
      '../public/models/environment-map/environmentMaps/0/nz.png'
    ])
    
    scene.background = environmentMap
    
    • move the torus knot to the side and change its material to MeshStandardMaterial
    /**
     * torus knot
    */
    const torusKnot = new THREE.Mesh(
      new THREE.TorusKnotGeometry(1, 0.4, 100, 16),
      new THREE.MeshStandardMaterial({
        roughness: 0.3,
        metalness: 1,
        color: 0xaaaaaa
      })  )
    torusKnot.position.x = -4
    ...
    
    model.png
    • use the environment map to light up the model, 也可以在单个model的material上设置envMap属性,但我们import的model层级结构比较复杂,不方便遍历添加,所以我们使用以下方法
    /**
     * environment map
    */
    // LDR cube texture
    ...
    
    scene.environment = environmentMap // to the hold scene
    scene.background = environmentMap
    
    environment.png
    • control the environment map's intensity, it has to be done on each material, we're going to touch the hole scene using traverse(), this method is available on object3D, we'll do it in a separated function and call it once is loaded
    • we only want to apply the environment map to the Meshes that have a MeshStandardMaterial
    /**
     * update all materials
    */
    const updateAllMaterials = () => {
      scene.traverse(child => {
        // console.log(child) // mesh, group, perspectiveCamera...
    
        // child instanceof THREE.Mesh && child.material instanceof THREE.MeshStandardMaterial
        if(child.isMesh && child.material.isMeshStandardMaterial) {
          // console.log(child);
          child.material.envMapIntensity = 3  // 增强环境贴图的反射强度
        }
      })
    }
    
    /**
     * models
    */
    gltfLoader.load(
      '../public/models/environment-map/models/FlightHelmet/glTF/FlightHelmet.gltf',
      (gltf) => {
        ...
        updateAllMaterials()
      }
    )
    
    envMapIntensity.png
    • control the envMapIntensity by using the Dat.gui
    /**
     * gui
    */
    const gui = new GUI()
    const global = {
      envMapIntensity: 1
    }
    gui
      .add(global, 'envMapIntensity')
      .min(0)
      .max(10)
      .step(0.001)
      .onChange(updateAllMaterials)
    
    /**
     * update all materials
    */
    const updateAllMaterials = () => {
      scene.traverse(child => {
          ...
          child.material.envMapIntensity = global.envMapIntensity // 调整环境贴图的反射强度
        }
      })
    }
    
  • Background blurriness and intensity 模糊度、强度
  scene.backgroundBlurriness = 0
  scene.backgroundIntensity = 1
  gui
    .add(scene, 'backgroundBlurriness')
    .min(0)
    .max(1)
    .step(0.001)
  gui
    .add(scene, 'backgroundIntensity')
    .min(0)
    .max(10)
    .step(0.001)
  • HDRI - Equirectangular Environment Map 等距矩形环境贴图
    • HDR Files: File extension is .hdr, high dynamic range 高动态范围
    • HDRI: color values stored have a much higher range than a traditional image
    • Equirectangular: only one picture containing kind of a 360° view of the surrounding
    • comment the environment map(keep the backgroundBlurriness and backgroundIntensity)
    /**
     * environment map
    */
    // LDR cube texture
    // const environmentMap = cubeTextureLoader.load([
    //   '../public/models/environment-map/environmentMaps/0/px.png',
    //   '../public/models/environment-map/environmentMaps/0/nx.png',
    //   '../public/models/environment-map/environmentMaps/0/py.png',
    //   '../public/models/environment-map/environmentMaps/0/ny.png',
    //   '../public/models/environment-map/environmentMaps/0/pz.png',
    //   '../public/models/environment-map/environmentMaps/0/nz.png'
    // ])
    
    // scene.environment = environmentMap // to the hold scene
    // scene.background = environmentMap
    
    scene.backgroundBlurriness = 0
    scene.backgroundIntensity = 1
    
    • load and use the HDRI, we need to use the RGBELoader, RGBE stands for Red Blue Green Exponent, the exponent means stores the brightness, 使用 RGBELoader 加载的背景看起来要更亮,因为存储在文件中的值更多、范围更大
    import {RGBELoader} from 'three/addons/loaders/RGBELoader.js'
    
    /**
     * loaders
    */
    ...
    const rgbeLoader = new RGBELoader()
    
    /**
     * environment map
    */
    ...
    ...
    // HDR (RGBE) equirectangular
    rgbeLoader.load('../public/models/environment-map/environmentMaps/0/2k.hdr', (environmentMap) => {
      environmentMap.mapping = THREE.EquirectangularReflectionMapping
    
      scene.environment = environmentMap
      scene.background = environmentMap
    })
    
    scene.backgroundBlurriness = 0
    scene.backgroundIntensity = 1
    
    hdr.png
    • 这里我们展示一些通过blender创建的不同类型的HDR背景图所呈现的效果


      image.png
      image.png
  • AI generated environment using NVIDIA Canvas
    • the software is in beta and only works on windows
    • the extension is .exr, our exported file is also an HDR, but EXR can also store layer
    • import the EXRLoader
  ...
  import { EXRLoader } from 'three/addons/loaders/EXRLoader.js';

  /**
   * loaders
  */
  ...
  const exrLoader = new EXRLoader()

  // HDR (RGBE) equirectangular
  // rgbeLoader.load('../public/environment-map/environmentMaps/blender-2k-1.hdr', environmentMap => {
  //   environmentMap.mapping = THREE.EquirectangularReflectionMapping

  //   scene.environment = environmentMap
  //   scene.background = environmentMap
  // })

  // HDR (EXR) equirectangular
  exrLoader.load('../public/environment-map/environmentMaps/nvidia-canvas-4k.exr', environmentMap => {
    environmentMap.mapping = THREE.EquirectangularReflectionMapping

    scene.environment = environmentMap
    scene.background = environmentMap
  })
nvidia-canvas.png
  /**
   * loaders
  */
  ...
  const textureLoader = new THREE.TextureLoader()

  // HDR (RGBE) equirectangular
  // rgbeLoader.load('../public/environment-map/environmentMaps/blender-2k-1.hdr', environmentMap => {
  //   environmentMap.mapping = THREE.EquirectangularReflectionMapping

  //   scene.environment = environmentMap
  //   scene.background = environmentMap
  // })

  // HDR (EXR) equirectangular
  // exrLoader.load('../public/environment-map/environmentMaps/nvidia-canvas-4k.exr', environmentMap => {
  //   environmentMap.mapping = THREE.EquirectangularReflectionMapping

  //   scene.environment = environmentMap
  //   scene.background = environmentMap
  // })
  
  // scene.backgroundBlurriness = 0
  // scene.backgroundIntensity = 1

  // LDR equirectangular
  const environmentMap = textureLoader.load('../public/environment-map/environmentMaps/blockadesLabsSkybox/anime_art_style_japan_streets_with_cherry_blossom_.jpg')
  environmentMap.mapping = THREE.EquirectangularReflectionMapping
  environmentMap.colorSpace = THREE.SRGBColorSpace
  scene.environment = environmentMap
  scene.background = environmentMap
BlockadeLabs.png
  • Ground Projected Environment Map
    • when using the environment map as background, the objects look like are flying
    • to use on of the HDR environment maps, only as the environment
  • RealTime EnvironmentMap
    /**
     * real time environment map
    */
    const environmentMap = textureLoader.load('../public/environment-map/environmentMaps/blockadesLabsSkybox/interior_views_cozy_wood_cabin_with_cauldron_and_p.jpg')
    environmentMap.mapping = THREE.EquirectangularReflectionMapping
    environmentMap.colorSpace = THREE.SRGBColorSpace
    
    scene.background = environmentMap
    
    • we're going to create a torus or a donut surrounding the scene and try to make the donut illuminate and reflect on the surface of our objects
    /**
     * holy donut
    */
    const holyDonut = new THREE.Mesh(
      new THREE.TorusGeometry(8, 0.5),
      new THREE.MeshBasicMaterial({color: 'white'})
    )
    holyDonut.position.y = 3.5
    scene.add(holyDonut)
    
    • we're going to render the scene inside our own environment map texture and it's going to be a cube texture
    • 创建立方体纹理:we need to use WebGLCubeRenderTarget, we need to create textures on each frame
    /**
     * cube render target
    */
    const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(
      256,  // 分辨率
      {
        type: THREE.HalfFloatType
      }
    )
    scene.environment = cubeRenderTarget.texture
    
    • we need to use CubeCamera, because we need to render 6 texture for each face
    // cube camera
    const cubeCamera = new THREE.CubeCamera(0.1, 100, cubeRenderTarget) // near, far
    
    /**
     * tick
    */
    const clock = new THREE.Clock()
    const tick = () => {
      const elapsedTime = clock.getElapsedTime()
    
      if(holyDonut) {
        holyDonut.rotation.x = Math.sin(elapsedTime) * 2
        cubeCamera.update(renderer, scene)
      }
    
      controls.update()
      renderer.render(scene, camera)
      requestAnimationFrame(tick)
    }
    tick()
    
    image.png
    • we can make the cube color go beyond the 0 to 1 range
    /**
     * holy donut
    */
    const holyDonut = new THREE.Mesh(
      ...
      new THREE.MeshBasicMaterial({color: new THREE.Color(10, 4, 2)})
    )
    ...
    
    image.png

相关文章

网友评论

      本文标题:three.js - Environment Map

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