threepipe
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

script.ts 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import {
  2. _testFinish,
  3. IObject3D,
  4. LinearToneMapping,
  5. LoadingScreenPlugin,
  6. Mesh,
  7. PerspectiveCamera2,
  8. PlaneGeometry,
  9. PopmotionPlugin,
  10. ProgressivePlugin, shaderReplaceString,
  11. Texture,
  12. ThreeViewer,
  13. ToneMapping,
  14. TonemapPlugin,
  15. UnlitMaterial,
  16. VirtualCamerasPlugin,
  17. ShaderChunk,
  18. } from 'threepipe'
  19. async function init() {
  20. const viewer = new ThreeViewer({
  21. canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
  22. debug: true,
  23. rgbm: true,
  24. msaa: true,
  25. plugins: [new ProgressivePlugin(16), LoadingScreenPlugin],
  26. })
  27. const virtualCameras = viewer.addPluginSync(VirtualCamerasPlugin)
  28. const popmotion = viewer.addPluginSync(PopmotionPlugin)
  29. await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')
  30. await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', {
  31. autoCenter: true,
  32. autoScale: true,
  33. })
  34. const aspect = 2
  35. const plane = new Mesh(
  36. new PlaneGeometry(5 * aspect, 5)
  37. .translate(0, 0, -3),
  38. new UnlitMaterial({
  39. color: '#ffffff',
  40. })
  41. )
  42. plane.castShadow = false
  43. plane.receiveShadow = true
  44. viewer.scene.addObject(plane)
  45. const camera = new PerspectiveCamera2('', viewer.canvas, false, 45, aspect)
  46. camera.position.set(0, 0, 5)
  47. camera.target.set(0, 0.25, 0)
  48. camera.userData.autoLookAtTarget = true
  49. camera.near = 1
  50. camera.far = 10
  51. camera.setDirty()
  52. const vCam = virtualCameras.addCamera(camera)
  53. plane.material.map = vCam.target.texture as Texture
  54. popmotion.animate({
  55. from: 0,
  56. to: 1,
  57. repeat: Infinity,
  58. duration: 6000,
  59. onUpdate: (v)=>{
  60. // Set camera position xz in a circle around the target
  61. const angle = v * Math.PI * 2 + Math.PI / 2
  62. const radius = 5
  63. camera.position.set(Math.cos(angle) * radius, 0, Math.sin(angle) * radius)
  64. camera.setDirty()
  65. viewer.setDirty() // since camera is not in the scene
  66. },
  67. })
  68. // We need to disable tonemapping when rendering the virtual camera, otherwise the tonemapping will be applied multiple times.
  69. let lastTonemapping: ToneMapping = LinearToneMapping
  70. const tonemap = viewer.getPlugin(TonemapPlugin)!
  71. virtualCameras.addEventListener('preRenderCamera', ()=>{
  72. lastTonemapping = tonemap.toneMapping
  73. // Comment this and see what happens to the color in the plane
  74. tonemap.toneMapping = LinearToneMapping
  75. })
  76. virtualCameras.addEventListener('postRenderCamera', ()=>{
  77. tonemap.toneMapping = lastTonemapping
  78. })
  79. // (Extra optional) extension decoding rgbm render target when using rgbm
  80. if (viewer.renderManager.rgbm) {
  81. plane.material.registerMaterialExtensions([{
  82. shaderExtender: (shader, material) => {
  83. if (material.map?.colorSpace !== 'rgbm-16') return
  84. shader.fragmentShader = shaderReplaceString(shader.fragmentShader, '#include <map_fragment>', ShaderChunk.map_fragment)
  85. shader.fragmentShader = shaderReplaceString(shader.fragmentShader, 'texture2D( map, vMapUv )', 'RGBM16ToLinear(texture2D( map, vMapUv ))', {replaceAll: true})
  86. },
  87. computeCacheKey: (material) => material.map?.colorSpace === 'rgbm-16' ? 'rgbm' : '',
  88. }])
  89. }
  90. }
  91. init().finally(_testFinish)