From abd325470fd582cec939f1d690d0972ea8c77514 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Thu, 27 Jul 2023 21:46:10 -0400 Subject: [PATCH 1/5] Update three.js --- three.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/three.js b/three.js index edefdc237..b447ff291 160000 --- a/three.js +++ b/three.js @@ -1 +1 @@ -Subproject commit edefdc237b2528b9668fb873a1c06cb835840303 +Subproject commit b447ff2911cbefcd650df5a18a905e7df882fc78 From f7149ad1545778dc5503f58c5bb5be49d51881db Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Thu, 27 Jul 2023 21:49:14 -0400 Subject: [PATCH 2/5] Update files.json --- examples-testing/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples-testing/index.js b/examples-testing/index.js index fef631a52..839b65f41 100644 --- a/examples-testing/index.js +++ b/examples-testing/index.js @@ -147,6 +147,7 @@ const files = { // 'webgl_materials_cubemap_dynamic', // 'webgl_materials_cubemap_refraction', // 'webgl_materials_cubemap_mipmaps', + // 'webgl_materials_cubemap_render_to_mipmaps', // 'webgl_materials_curvature', // 'webgl_materials_displacementmap', // 'webgl_materials_envmaps', @@ -329,6 +330,7 @@ const files = { // 'webgpu_lights_selective', // 'webgpu_loader_gltf', // 'webgpu_loader_gltf_compressed', + // 'webgpu_loader_gltf_iridescence', // 'webgpu_loader_gltf_sheen', // 'webgpu_materials', // 'webgpu_materials_video', From 8892585c394be7d311b1d40133dba7f14ab6294e Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Thu, 27 Jul 2023 21:50:05 -0400 Subject: [PATCH 3/5] Add examples --- examples-testing/examples/css2d_label.ts | 186 ++++ examples-testing/examples/css3d_molecules.ts | 353 ++++++++ .../examples/css3d_orthographic.ts | 208 +++++ .../examples/css3d_periodictable.ts | 793 ++++++++++++++++++ examples-testing/examples/css3d_sandbox.ts | 180 ++++ examples-testing/examples/css3d_sprites.ts | 157 ++++ examples-testing/examples/css3d_youtube.ts | 79 ++ examples-testing/examples/games_fps.ts | 373 ++++++++ .../examples/misc_animation_groups.ts | 131 +++ .../examples/misc_animation_keys.ts | 135 +++ .../examples/misc_boxselection.ts | 142 ++++ .../examples/misc_controls_arcball.ts | 210 +++++ .../examples/misc_controls_drag.ts | 148 ++++ .../examples/misc_controls_fly.ts | 227 +++++ .../examples/misc_controls_map.ts | 100 +++ .../examples/misc_controls_orbit.ts | 91 ++ .../examples/misc_controls_pointerlock.ts | 247 ++++++ .../examples/misc_controls_trackball.ts | 136 +++ .../examples/misc_controls_transform.ts | 172 ++++ .../examples/misc_exporter_draco.ts | 118 +++ .../examples/misc_exporter_gltf.ts | 493 +++++++++++ .../examples/misc_exporter_obj.ts | 194 +++++ .../examples/misc_exporter_ply.ts | 157 ++++ .../examples/misc_exporter_stl.ts | 130 +++ .../examples/misc_exporter_usdz.ts | 110 +++ examples-testing/examples/misc_lookat.ts | 97 +++ examples-testing/examples/misc_uv_tests.ts | 44 + .../examples/physics_ammo_instancing.ts | 122 +++ .../examples/physics_rapier_instancing.ts | 122 +++ examples-testing/examples/svg_lines.ts | 87 ++ examples-testing/examples/svg_sandbox.ts | 212 +++++ .../examples/webaudio_orientation.ts | 141 ++++ examples-testing/examples/webaudio_sandbox.ts | 228 +++++ examples-testing/examples/webaudio_timing.ts | 158 ++++ .../examples/webaudio_visualizer.ts | 93 ++ ...ebgl2_buffergeometry_attributes_integer.ts | 121 +++ .../webgl2_buffergeometry_attributes_none.ts | 64 ++ .../examples/webgl2_materials_texture3d.ts | 133 +++ ...ebgl2_materials_texture3d_partialupdate.ts | 333 ++++++++ .../examples/webgl2_multiple_rendertargets.ts | 139 +++ .../webgl2_multisampled_renderbuffers.ts | 139 +++ .../webgl2_texture2darray_compressed.ts | 96 +++ examples-testing/examples/webgl2_ubo.ts | 146 ++++ .../examples/webgl2_volume_cloud.ts | 286 +++++++ .../examples/webgl2_volume_instancing.ts | 198 +++++ .../examples/webgl2_volume_perlin.ts | 215 +++++ .../examples/webgl_animation_keyframes.ts | 82 ++ .../examples/webgl_animation_multiple.ts | 104 +++ .../webgl_animation_skinning_morph.ts | 189 +++++ .../examples/webgl_buffergeometry.ts | 182 ++++ ...fergeometry_custom_attributes_particles.ts | 108 +++ .../webgl_buffergeometry_drawrange.ts | 241 ++++++ .../webgl_buffergeometry_glbufferattribute.ts | 145 ++++ .../examples/webgl_buffergeometry_indexed.ts | 142 ++++ .../webgl_buffergeometry_instancing.ts | 148 ++++ ...gl_buffergeometry_instancing_billboards.ts | 98 +++ ...l_buffergeometry_instancing_interleaved.ts | 162 ++++ .../examples/webgl_buffergeometry_lines.ts | 123 +++ .../webgl_buffergeometry_lines_indexed.ts | 186 ++++ .../examples/webgl_buffergeometry_points.ts | 113 +++ ...webgl_buffergeometry_points_interleaved.ts | 127 +++ .../webgl_buffergeometry_rawshader.ts | 102 +++ .../webgl_buffergeometry_selective_draw.ts | 151 ++++ .../examples/webgl_buffergeometry_uint.ts | 182 ++++ examples-testing/examples/webgl_camera.ts | 214 +++++ .../webgl_camera_logarithmicdepthbuffer.ts | 248 ++++++ examples-testing/examples/webgl_clipping.ts | 184 ++++ .../examples/webgl_clipping_advanced.ts | 356 ++++++++ .../examples/webgl_clipping_intersection.ts | 126 +++ .../examples/webgl_clipping_stencil.ts | 260 ++++++ .../examples/webgl_custom_attributes.ts | 102 +++ .../examples/webgl_custom_attributes_lines.ts | 123 +++ .../webgl_custom_attributes_points.ts | 119 +++ .../webgl_custom_attributes_points2.ts | 195 +++++ .../webgl_custom_attributes_points3.ts | 202 +++++ examples-testing/examples/webgl_decals.ts | 238 ++++++ .../examples/webgl_effects_anaglyph.ts | 116 +++ .../examples/webgl_effects_ascii.ts | 87 ++ .../examples/webgl_effects_parallaxbarrier.ts | 116 +++ .../examples/webgl_effects_peppersghost.ts | 87 ++ .../examples/webgl_effects_stereo.ts | 104 +++ .../examples/webgl_framebuffer_texture.ts | 153 ++++ .../examples/webgl_furnace_test.ts | 96 +++ examples-testing/examples/webgl_geometries.ts | 139 +++ .../examples/webgl_geometries_parametric.ts | 126 +++ .../examples/webgl_gpgpu_birds.ts | 319 +++++++ .../examples/webgl_gpgpu_birds_gltf.ts | 421 ++++++++++ .../examples/webgl_gpgpu_protoplanet.ts | 288 +++++++ .../examples/webgl_gpgpu_water.ts | 403 +++++++++ .../examples/webgl_materials_modified.ts | 117 +++ examples-testing/examples/webgl_pmrem_test.ts | 141 ++++ .../examples/webgl_postprocessing.ts | 88 ++ .../examples/webgl_postprocessing_advanced.ts | 306 +++++++ .../webgl_postprocessing_afterimage.ts | 86 ++ .../webgl_postprocessing_backgrounds.ts | 216 +++++ .../webgl_postprocessing_crossfade.ts | 302 +++++++ .../examples/webgl_postprocessing_fxaa.ts | 135 +++ .../examples/webgl_postprocessing_glitch.ts | 99 +++ .../examples/webgl_postprocessing_godrays.ts | 349 ++++++++ .../examples/webgl_postprocessing_masking.ts | 102 +++ .../examples/webgl_postprocessing_outline.ts | 284 +++++++ .../examples/webgl_postprocessing_pixel.ts | 230 +++++ .../webgl_postprocessing_procedural.ts | 81 ++ .../webgl_postprocessing_rgb_halftone.ts | 169 ++++ .../examples/webgl_postprocessing_sao.ts | 142 ++++ .../examples/webgl_postprocessing_smaa.ts | 93 ++ .../examples/webgl_postprocessing_sobel.ts | 113 +++ .../examples/webgl_postprocessing_ssaa.ts | 208 +++++ .../examples/webgl_postprocessing_ssao.ts | 117 +++ .../examples/webgl_postprocessing_ssr.ts | 263 ++++++ .../examples/webgl_postprocessing_taa.ts | 141 ++++ .../webgl_postprocessing_unreal_bloom.ts | 129 +++ ...l_postprocessing_unreal_bloom_selective.ts | 195 +++++ .../examples/webgl_raymarching_reflect.ts | 96 +++ .../examples/webgl_shadowmap_csm.ts | 244 ++++++ .../examples/webgl_shadowmap_pcss.ts | 163 ++++ .../examples/webgl_shadowmap_progressive.ts | 214 +++++ examples-testing/examples/webgl_simple_gi.ts | 175 ++++ examples-testing/examples/webxr_ar_cones.ts | 70 ++ examples-testing/examples/webxr_ar_hittest.ts | 119 +++ .../examples/webxr_ar_lighting.ts | 128 +++ .../examples/webxr_ar_plane_detection.ts | 46 + .../examples/webxr_vr_handinput.ts | 126 +++ .../examples/webxr_vr_panorama.ts | 96 +++ .../examples/webxr_vr_panorama_depth.ts | 94 +++ .../examples/webxr_vr_rollercoaster.ts | 212 +++++ examples-testing/examples/webxr_vr_sandbox.ts | 209 +++++ examples-testing/examples/webxr_vr_video.ts | 96 +++ 128 files changed, 22045 insertions(+) create mode 100644 examples-testing/examples/css2d_label.ts create mode 100644 examples-testing/examples/css3d_molecules.ts create mode 100644 examples-testing/examples/css3d_orthographic.ts create mode 100644 examples-testing/examples/css3d_periodictable.ts create mode 100644 examples-testing/examples/css3d_sandbox.ts create mode 100644 examples-testing/examples/css3d_sprites.ts create mode 100644 examples-testing/examples/css3d_youtube.ts create mode 100644 examples-testing/examples/games_fps.ts create mode 100644 examples-testing/examples/misc_animation_groups.ts create mode 100644 examples-testing/examples/misc_animation_keys.ts create mode 100644 examples-testing/examples/misc_boxselection.ts create mode 100644 examples-testing/examples/misc_controls_arcball.ts create mode 100644 examples-testing/examples/misc_controls_drag.ts create mode 100644 examples-testing/examples/misc_controls_fly.ts create mode 100644 examples-testing/examples/misc_controls_map.ts create mode 100644 examples-testing/examples/misc_controls_orbit.ts create mode 100644 examples-testing/examples/misc_controls_pointerlock.ts create mode 100644 examples-testing/examples/misc_controls_trackball.ts create mode 100644 examples-testing/examples/misc_controls_transform.ts create mode 100644 examples-testing/examples/misc_exporter_draco.ts create mode 100644 examples-testing/examples/misc_exporter_gltf.ts create mode 100644 examples-testing/examples/misc_exporter_obj.ts create mode 100644 examples-testing/examples/misc_exporter_ply.ts create mode 100644 examples-testing/examples/misc_exporter_stl.ts create mode 100644 examples-testing/examples/misc_exporter_usdz.ts create mode 100644 examples-testing/examples/misc_lookat.ts create mode 100644 examples-testing/examples/misc_uv_tests.ts create mode 100644 examples-testing/examples/physics_ammo_instancing.ts create mode 100644 examples-testing/examples/physics_rapier_instancing.ts create mode 100644 examples-testing/examples/svg_lines.ts create mode 100644 examples-testing/examples/svg_sandbox.ts create mode 100644 examples-testing/examples/webaudio_orientation.ts create mode 100644 examples-testing/examples/webaudio_sandbox.ts create mode 100644 examples-testing/examples/webaudio_timing.ts create mode 100644 examples-testing/examples/webaudio_visualizer.ts create mode 100644 examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts create mode 100644 examples-testing/examples/webgl2_buffergeometry_attributes_none.ts create mode 100644 examples-testing/examples/webgl2_materials_texture3d.ts create mode 100644 examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts create mode 100644 examples-testing/examples/webgl2_multiple_rendertargets.ts create mode 100644 examples-testing/examples/webgl2_multisampled_renderbuffers.ts create mode 100644 examples-testing/examples/webgl2_texture2darray_compressed.ts create mode 100644 examples-testing/examples/webgl2_ubo.ts create mode 100644 examples-testing/examples/webgl2_volume_cloud.ts create mode 100644 examples-testing/examples/webgl2_volume_instancing.ts create mode 100644 examples-testing/examples/webgl2_volume_perlin.ts create mode 100644 examples-testing/examples/webgl_animation_keyframes.ts create mode 100644 examples-testing/examples/webgl_animation_multiple.ts create mode 100644 examples-testing/examples/webgl_animation_skinning_morph.ts create mode 100644 examples-testing/examples/webgl_buffergeometry.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_drawrange.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_indexed.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_instancing.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_lines.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_lines_indexed.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_points.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_points_interleaved.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_rawshader.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_selective_draw.ts create mode 100644 examples-testing/examples/webgl_buffergeometry_uint.ts create mode 100644 examples-testing/examples/webgl_camera.ts create mode 100644 examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts create mode 100644 examples-testing/examples/webgl_clipping.ts create mode 100644 examples-testing/examples/webgl_clipping_advanced.ts create mode 100644 examples-testing/examples/webgl_clipping_intersection.ts create mode 100644 examples-testing/examples/webgl_clipping_stencil.ts create mode 100644 examples-testing/examples/webgl_custom_attributes.ts create mode 100644 examples-testing/examples/webgl_custom_attributes_lines.ts create mode 100644 examples-testing/examples/webgl_custom_attributes_points.ts create mode 100644 examples-testing/examples/webgl_custom_attributes_points2.ts create mode 100644 examples-testing/examples/webgl_custom_attributes_points3.ts create mode 100644 examples-testing/examples/webgl_decals.ts create mode 100644 examples-testing/examples/webgl_effects_anaglyph.ts create mode 100644 examples-testing/examples/webgl_effects_ascii.ts create mode 100644 examples-testing/examples/webgl_effects_parallaxbarrier.ts create mode 100644 examples-testing/examples/webgl_effects_peppersghost.ts create mode 100644 examples-testing/examples/webgl_effects_stereo.ts create mode 100644 examples-testing/examples/webgl_framebuffer_texture.ts create mode 100644 examples-testing/examples/webgl_furnace_test.ts create mode 100644 examples-testing/examples/webgl_geometries.ts create mode 100644 examples-testing/examples/webgl_geometries_parametric.ts create mode 100644 examples-testing/examples/webgl_gpgpu_birds.ts create mode 100644 examples-testing/examples/webgl_gpgpu_birds_gltf.ts create mode 100644 examples-testing/examples/webgl_gpgpu_protoplanet.ts create mode 100644 examples-testing/examples/webgl_gpgpu_water.ts create mode 100644 examples-testing/examples/webgl_materials_modified.ts create mode 100644 examples-testing/examples/webgl_pmrem_test.ts create mode 100644 examples-testing/examples/webgl_postprocessing.ts create mode 100644 examples-testing/examples/webgl_postprocessing_advanced.ts create mode 100644 examples-testing/examples/webgl_postprocessing_afterimage.ts create mode 100644 examples-testing/examples/webgl_postprocessing_backgrounds.ts create mode 100644 examples-testing/examples/webgl_postprocessing_crossfade.ts create mode 100644 examples-testing/examples/webgl_postprocessing_fxaa.ts create mode 100644 examples-testing/examples/webgl_postprocessing_glitch.ts create mode 100644 examples-testing/examples/webgl_postprocessing_godrays.ts create mode 100644 examples-testing/examples/webgl_postprocessing_masking.ts create mode 100644 examples-testing/examples/webgl_postprocessing_outline.ts create mode 100644 examples-testing/examples/webgl_postprocessing_pixel.ts create mode 100644 examples-testing/examples/webgl_postprocessing_procedural.ts create mode 100644 examples-testing/examples/webgl_postprocessing_rgb_halftone.ts create mode 100644 examples-testing/examples/webgl_postprocessing_sao.ts create mode 100644 examples-testing/examples/webgl_postprocessing_smaa.ts create mode 100644 examples-testing/examples/webgl_postprocessing_sobel.ts create mode 100644 examples-testing/examples/webgl_postprocessing_ssaa.ts create mode 100644 examples-testing/examples/webgl_postprocessing_ssao.ts create mode 100644 examples-testing/examples/webgl_postprocessing_ssr.ts create mode 100644 examples-testing/examples/webgl_postprocessing_taa.ts create mode 100644 examples-testing/examples/webgl_postprocessing_unreal_bloom.ts create mode 100644 examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts create mode 100644 examples-testing/examples/webgl_raymarching_reflect.ts create mode 100644 examples-testing/examples/webgl_shadowmap_csm.ts create mode 100644 examples-testing/examples/webgl_shadowmap_pcss.ts create mode 100644 examples-testing/examples/webgl_shadowmap_progressive.ts create mode 100644 examples-testing/examples/webgl_simple_gi.ts create mode 100644 examples-testing/examples/webxr_ar_cones.ts create mode 100644 examples-testing/examples/webxr_ar_hittest.ts create mode 100644 examples-testing/examples/webxr_ar_lighting.ts create mode 100644 examples-testing/examples/webxr_ar_plane_detection.ts create mode 100644 examples-testing/examples/webxr_vr_handinput.ts create mode 100644 examples-testing/examples/webxr_vr_panorama.ts create mode 100644 examples-testing/examples/webxr_vr_panorama_depth.ts create mode 100644 examples-testing/examples/webxr_vr_rollercoaster.ts create mode 100644 examples-testing/examples/webxr_vr_sandbox.ts create mode 100644 examples-testing/examples/webxr_vr_video.ts diff --git a/examples-testing/examples/css2d_label.ts b/examples-testing/examples/css2d_label.ts new file mode 100644 index 000000000..48a2d1f05 --- /dev/null +++ b/examples-testing/examples/css2d_label.ts @@ -0,0 +1,186 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let gui; + +let camera, scene, renderer, labelRenderer; + +const layers = { + 'Toggle Name': function () { + camera.layers.toggle(0); + }, + 'Toggle Mass': function () { + camera.layers.toggle(1); + }, + 'Enable All': function () { + camera.layers.enableAll(); + }, + + 'Disable All': function () { + camera.layers.disableAll(); + }, +}; + +const clock = new THREE.Clock(); +const textureLoader = new THREE.TextureLoader(); + +let moon; + +init(); +animate(); + +function init() { + const EARTH_RADIUS = 1; + const MOON_RADIUS = 0.27; + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200); + camera.position.set(10, 5, 20); + camera.layers.enableAll(); + + scene = new THREE.Scene(); + + const dirLight = new THREE.DirectionalLight(0xffffff, 3); + dirLight.position.set(0, 0, 1); + dirLight.layers.enableAll(); + scene.add(dirLight); + + const axesHelper = new THREE.AxesHelper(5); + axesHelper.layers.enableAll(); + scene.add(axesHelper); + + // + + const earthGeometry = new THREE.SphereGeometry(EARTH_RADIUS, 16, 16); + const earthMaterial = new THREE.MeshPhongMaterial({ + specular: 0x333333, + shininess: 5, + map: textureLoader.load('textures/planets/earth_atmos_2048.jpg'), + specularMap: textureLoader.load('textures/planets/earth_specular_2048.jpg'), + normalMap: textureLoader.load('textures/planets/earth_normal_2048.jpg'), + normalScale: new THREE.Vector2(0.85, 0.85), + }); + earthMaterial.map.colorSpace = THREE.SRGBColorSpace; + const earth = new THREE.Mesh(earthGeometry, earthMaterial); + scene.add(earth); + + const moonGeometry = new THREE.SphereGeometry(MOON_RADIUS, 16, 16); + const moonMaterial = new THREE.MeshPhongMaterial({ + shininess: 5, + map: textureLoader.load('textures/planets/moon_1024.jpg'), + }); + moonMaterial.map.colorSpace = THREE.SRGBColorSpace; + moon = new THREE.Mesh(moonGeometry, moonMaterial); + scene.add(moon); + + // + + earth.layers.enableAll(); + moon.layers.enableAll(); + + const earthDiv = document.createElement('div'); + earthDiv.className = 'label'; + earthDiv.textContent = 'Earth'; + earthDiv.style.backgroundColor = 'transparent'; + + const earthLabel = new CSS2DObject(earthDiv); + earthLabel.position.set(1.5 * EARTH_RADIUS, 0, 0); + earthLabel.center.set(0, 1); + earth.add(earthLabel); + earthLabel.layers.set(0); + + const earthMassDiv = document.createElement('div'); + earthMassDiv.className = 'label'; + earthMassDiv.textContent = '5.97237e24 kg'; + earthMassDiv.style.backgroundColor = 'transparent'; + + const earthMassLabel = new CSS2DObject(earthMassDiv); + earthMassLabel.position.set(1.5 * EARTH_RADIUS, 0, 0); + earthMassLabel.center.set(0, 0); + earth.add(earthMassLabel); + earthMassLabel.layers.set(1); + + const moonDiv = document.createElement('div'); + moonDiv.className = 'label'; + moonDiv.textContent = 'Moon'; + moonDiv.style.backgroundColor = 'transparent'; + + const moonLabel = new CSS2DObject(moonDiv); + moonLabel.position.set(1.5 * MOON_RADIUS, 0, 0); + moonLabel.center.set(0, 1); + moon.add(moonLabel); + moonLabel.layers.set(0); + + const moonMassDiv = document.createElement('div'); + moonMassDiv.className = 'label'; + moonMassDiv.textContent = '7.342e22 kg'; + moonMassDiv.style.backgroundColor = 'transparent'; + + const moonMassLabel = new CSS2DObject(moonMassDiv); + moonMassLabel.position.set(1.5 * MOON_RADIUS, 0, 0); + moonMassLabel.center.set(0, 0); + moon.add(moonMassLabel); + moonMassLabel.layers.set(1); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + labelRenderer = new CSS2DRenderer(); + labelRenderer.setSize(window.innerWidth, window.innerHeight); + labelRenderer.domElement.style.position = 'absolute'; + labelRenderer.domElement.style.top = '0px'; + document.body.appendChild(labelRenderer.domElement); + + const controls = new OrbitControls(camera, labelRenderer.domElement); + controls.minDistance = 5; + controls.maxDistance = 100; + + // + + window.addEventListener('resize', onWindowResize); + + initGui(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + labelRenderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + const elapsed = clock.getElapsedTime(); + + moon.position.set(Math.sin(elapsed) * 5, 0, Math.cos(elapsed) * 5); + + renderer.render(scene, camera); + labelRenderer.render(scene, camera); +} + +// + +function initGui() { + gui = new GUI(); + + gui.title('Camera Layers'); + + gui.add(layers, 'Toggle Name'); + gui.add(layers, 'Toggle Mass'); + gui.add(layers, 'Enable All'); + gui.add(layers, 'Disable All'); + + gui.open(); +} diff --git a/examples-testing/examples/css3d_molecules.ts b/examples-testing/examples/css3d_molecules.ts new file mode 100644 index 000000000..538472607 --- /dev/null +++ b/examples-testing/examples/css3d_molecules.ts @@ -0,0 +1,353 @@ +import * as THREE from 'three'; + +import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; +import { PDBLoader } from 'three/addons/loaders/PDBLoader.js'; +import { CSS3DRenderer, CSS3DObject, CSS3DSprite } from 'three/addons/renderers/CSS3DRenderer.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let camera, scene, renderer; +let controls; +let root; + +const objects = []; +const tmpVec1 = new THREE.Vector3(); +const tmpVec2 = new THREE.Vector3(); +const tmpVec3 = new THREE.Vector3(); +const tmpVec4 = new THREE.Vector3(); +const offset = new THREE.Vector3(); + +const VIZ_TYPE = { + Atoms: 0, + Bonds: 1, + 'Atoms + Bonds': 2, +}; + +const MOLECULES = { + Ethanol: 'ethanol.pdb', + Aspirin: 'aspirin.pdb', + Caffeine: 'caffeine.pdb', + Nicotine: 'nicotine.pdb', + LSD: 'lsd.pdb', + Cocaine: 'cocaine.pdb', + Cholesterol: 'cholesterol.pdb', + Lycopene: 'lycopene.pdb', + Glucose: 'glucose.pdb', + 'Aluminium oxide': 'Al2O3.pdb', + Cubane: 'cubane.pdb', + Copper: 'cu.pdb', + Fluorite: 'caf2.pdb', + Salt: 'nacl.pdb', + 'YBCO superconductor': 'ybco.pdb', + Buckyball: 'buckyball.pdb', + // 'Diamond': 'diamond.pdb', + Graphite: 'graphite.pdb', +}; + +const params = { + vizType: 2, + molecule: 'caffeine.pdb', +}; + +const loader = new PDBLoader(); +const colorSpriteMap = {}; +const baseSprite = document.createElement('img'); + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 5000); + camera.position.z = 1000; + + scene = new THREE.Scene(); + + root = new THREE.Object3D(); + scene.add(root); + + // + + renderer = new CSS3DRenderer(); + renderer.setSize(window.innerWidth, window.innerHeight); + document.getElementById('container').appendChild(renderer.domElement); + + // + + controls = new TrackballControls(camera, renderer.domElement); + controls.rotateSpeed = 0.5; + + // + + baseSprite.onload = function () { + loadMolecule(params.molecule); + }; + + baseSprite.src = 'textures/sprites/ball.png'; + + // + + window.addEventListener('resize', onWindowResize); + + // + + const gui = new GUI(); + + gui.add(params, 'vizType', VIZ_TYPE).onChange(changeVizType); + gui.add(params, 'molecule', MOLECULES).onChange(loadMolecule); + gui.open(); +} + +function changeVizType(value) { + if (value === 0) showAtoms(); + else if (value === 1) showBonds(); + else showAtomsBonds(); +} + +// + +function showAtoms() { + for (let i = 0; i < objects.length; i++) { + const object = objects[i]; + + if (object instanceof CSS3DSprite) { + object.element.style.display = ''; + object.visible = true; + } else { + object.element.style.display = 'none'; + object.visible = false; + } + } +} + +function showBonds() { + for (let i = 0; i < objects.length; i++) { + const object = objects[i]; + + if (object instanceof CSS3DSprite) { + object.element.style.display = 'none'; + object.visible = false; + } else { + object.element.style.display = ''; + object.element.style.height = object.userData.bondLengthFull; + object.visible = true; + } + } +} + +function showAtomsBonds() { + for (let i = 0; i < objects.length; i++) { + const object = objects[i]; + + object.element.style.display = ''; + object.visible = true; + + if (!(object instanceof CSS3DSprite)) { + object.element.style.height = object.userData.bondLengthShort; + } + } +} + +// + +function colorify(ctx, width, height, color) { + const r = color.r, + g = color.g, + b = color.b; + + const imageData = ctx.getImageData(0, 0, width, height); + const data = imageData.data; + + for (let i = 0, l = data.length; i < l; i += 4) { + data[i + 0] *= r; + data[i + 1] *= g; + data[i + 2] *= b; + } + + ctx.putImageData(imageData, 0, 0); +} + +function imageToCanvas(image) { + const width = image.width; + const height = image.height; + + const canvas = document.createElement('canvas'); + + canvas.width = width; + canvas.height = height; + + const context = canvas.getContext('2d'); + context.drawImage(image, 0, 0, width, height); + + return canvas; +} + +// + +function loadMolecule(model) { + const url = 'models/pdb/' + model; + + for (let i = 0; i < objects.length; i++) { + const object = objects[i]; + object.parent.remove(object); + } + + objects.length = 0; + + loader.load(url, function (pdb) { + const geometryAtoms = pdb.geometryAtoms; + const geometryBonds = pdb.geometryBonds; + const json = pdb.json; + + geometryAtoms.computeBoundingBox(); + geometryAtoms.boundingBox.getCenter(offset).negate(); + + geometryAtoms.translate(offset.x, offset.y, offset.z); + geometryBonds.translate(offset.x, offset.y, offset.z); + + const positionAtoms = geometryAtoms.getAttribute('position'); + const colorAtoms = geometryAtoms.getAttribute('color'); + + const position = new THREE.Vector3(); + const color = new THREE.Color(); + + for (let i = 0; i < positionAtoms.count; i++) { + position.fromBufferAttribute(positionAtoms, i); + color.fromBufferAttribute(colorAtoms, i); + + const atomJSON = json.atoms[i]; + const element = atomJSON[4]; + + if (!colorSpriteMap[element]) { + const canvas = imageToCanvas(baseSprite); + const context = canvas.getContext('2d'); + + colorify(context, canvas.width, canvas.height, color); + + const dataUrl = canvas.toDataURL(); + + colorSpriteMap[element] = dataUrl; + } + + const colorSprite = colorSpriteMap[element]; + + const atom = document.createElement('img'); + atom.src = colorSprite; + + const object = new CSS3DSprite(atom); + object.position.copy(position); + object.position.multiplyScalar(75); + + object.matrixAutoUpdate = false; + object.updateMatrix(); + + root.add(object); + + objects.push(object); + } + + const positionBonds = geometryBonds.getAttribute('position'); + + const start = new THREE.Vector3(); + const end = new THREE.Vector3(); + + for (let i = 0; i < positionBonds.count; i += 2) { + start.fromBufferAttribute(positionBonds, i); + end.fromBufferAttribute(positionBonds, i + 1); + + start.multiplyScalar(75); + end.multiplyScalar(75); + + tmpVec1.subVectors(end, start); + const bondLength = tmpVec1.length() - 50; + + // + + let bond = document.createElement('div'); + bond.className = 'bond'; + bond.style.height = bondLength + 'px'; + + let object = new CSS3DObject(bond); + object.position.copy(start); + object.position.lerp(end, 0.5); + + object.userData.bondLengthShort = bondLength + 'px'; + object.userData.bondLengthFull = bondLength + 55 + 'px'; + + // + + const axis = tmpVec2.set(0, 1, 0).cross(tmpVec1); + const radians = Math.acos(tmpVec3.set(0, 1, 0).dot(tmpVec4.copy(tmpVec1).normalize())); + + const objMatrix = new THREE.Matrix4().makeRotationAxis(axis.normalize(), radians); + object.matrix.copy(objMatrix); + object.quaternion.setFromRotationMatrix(object.matrix); + + object.matrixAutoUpdate = false; + object.updateMatrix(); + + root.add(object); + + objects.push(object); + + // + + const joint = new THREE.Object3D(); + joint.position.copy(start); + joint.position.lerp(end, 0.5); + + joint.matrix.copy(objMatrix); + joint.quaternion.setFromRotationMatrix(joint.matrix); + + joint.matrixAutoUpdate = false; + joint.updateMatrix(); + + bond = document.createElement('div'); + bond.className = 'bond'; + bond.style.height = bondLength + 'px'; + + object = new CSS3DObject(bond); + object.rotation.y = Math.PI / 2; + + object.matrixAutoUpdate = false; + object.updateMatrix(); + + object.userData.bondLengthShort = bondLength + 'px'; + object.userData.bondLengthFull = bondLength + 55 + 'px'; + + object.userData.joint = joint; + + joint.add(object); + root.add(joint); + + objects.push(object); + } + + //console.log( "CSS3DObjects:", objects.length ); + + changeVizType(params.vizType); + }); +} + +// + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + controls.update(); + + const time = Date.now() * 0.0004; + + root.rotation.x = time; + root.rotation.y = time * 0.7; + + render(); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/css3d_orthographic.ts b/examples-testing/examples/css3d_orthographic.ts new file mode 100644 index 000000000..4aabbed08 --- /dev/null +++ b/examples-testing/examples/css3d_orthographic.ts @@ -0,0 +1,208 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let camera, scene, renderer; + +let scene2, renderer2; + +const frustumSize = 500; + +init(); +animate(); + +function init() { + const aspect = window.innerWidth / window.innerHeight; + camera = new THREE.OrthographicCamera( + (frustumSize * aspect) / -2, + (frustumSize * aspect) / 2, + frustumSize / 2, + frustumSize / -2, + 1, + 1000, + ); + + camera.position.set(-200, 200, 200); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xf0f0f0); + + scene2 = new THREE.Scene(); + + const material = new THREE.MeshBasicMaterial({ + color: 0x000000, + wireframe: true, + wireframeLinewidth: 1, + side: THREE.DoubleSide, + }); + + // left + createPlane( + 100, + 100, + 'chocolate', + new THREE.Vector3(-50, 0, 0), + new THREE.Euler(0, -90 * THREE.MathUtils.DEG2RAD, 0), + ); + // right + createPlane(100, 100, 'saddlebrown', new THREE.Vector3(0, 0, 50), new THREE.Euler(0, 0, 0)); + // top + createPlane( + 100, + 100, + 'yellowgreen', + new THREE.Vector3(0, 50, 0), + new THREE.Euler(-90 * THREE.MathUtils.DEG2RAD, 0, 0), + ); + // bottom + createPlane( + 300, + 300, + 'seagreen', + new THREE.Vector3(0, -50, 0), + new THREE.Euler(-90 * THREE.MathUtils.DEG2RAD, 0, 0), + ); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + renderer2 = new CSS3DRenderer(); + renderer2.setSize(window.innerWidth, window.innerHeight); + renderer2.domElement.style.position = 'absolute'; + renderer2.domElement.style.top = 0; + document.body.appendChild(renderer2.domElement); + + const controls = new OrbitControls(camera, renderer2.domElement); + controls.minZoom = 0.5; + controls.maxZoom = 2; + + function createPlane(width, height, cssColor, pos, rot) { + const element = document.createElement('div'); + element.style.width = width + 'px'; + element.style.height = height + 'px'; + element.style.opacity = 0.75; + element.style.background = cssColor; + + const object = new CSS3DObject(element); + object.position.copy(pos); + object.rotation.copy(rot); + scene2.add(object); + + const geometry = new THREE.PlaneGeometry(width, height); + const mesh = new THREE.Mesh(geometry, material); + mesh.position.copy(object.position); + mesh.rotation.copy(object.rotation); + scene.add(mesh); + } + + window.addEventListener('resize', onWindowResize); + createPanel(); +} + +function onWindowResize() { + const aspect = window.innerWidth / window.innerHeight; + + camera.left = (-frustumSize * aspect) / 2; + camera.right = (frustumSize * aspect) / 2; + camera.top = frustumSize / 2; + camera.bottom = -frustumSize / 2; + + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + renderer2.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + renderer.render(scene, camera); + renderer2.render(scene2, camera); +} + +function createPanel() { + const panel = new GUI(); + const folder1 = panel.addFolder('camera setViewOffset').close(); + + const settings = { + setViewOffset() { + folder1.children[1].enable().setValue(window.innerWidth); + folder1.children[2].enable().setValue(window.innerHeight); + folder1.children[3].enable().setValue(0); + folder1.children[4].enable().setValue(0); + folder1.children[5].enable().setValue(window.innerWidth); + folder1.children[6].enable().setValue(window.innerHeight); + }, + fullWidth: 0, + fullHeight: 0, + offsetX: 0, + offsetY: 0, + width: 0, + height: 0, + clearViewOffset() { + folder1.children[1].setValue(0).disable(); + folder1.children[2].setValue(0).disable(); + folder1.children[3].setValue(0).disable(); + folder1.children[4].setValue(0).disable(); + folder1.children[5].setValue(0).disable(); + folder1.children[6].setValue(0).disable(); + camera.clearViewOffset(); + }, + }; + + folder1.add(settings, 'setViewOffset'); + folder1 + .add(settings, 'fullWidth', window.screen.width / 4, window.screen.width * 2, 1) + .onChange(val => updateCameraViewOffset({ fullWidth: val })) + .disable(); + folder1 + .add(settings, 'fullHeight', window.screen.height / 4, window.screen.height * 2, 1) + .onChange(val => updateCameraViewOffset({ fullHeight: val })) + .disable(); + folder1 + .add(settings, 'offsetX', 0, 256, 1) + .onChange(val => updateCameraViewOffset({ x: val })) + .disable(); + folder1 + .add(settings, 'offsetY', 0, 256, 1) + .onChange(val => updateCameraViewOffset({ y: val })) + .disable(); + folder1 + .add(settings, 'width', window.screen.width / 4, window.screen.width * 2, 1) + .onChange(val => updateCameraViewOffset({ width: val })) + .disable(); + folder1 + .add(settings, 'height', window.screen.height / 4, window.screen.height * 2, 1) + .onChange(val => updateCameraViewOffset({ height: val })) + .disable(); + folder1.add(settings, 'clearViewOffset'); +} + +function updateCameraViewOffset({ fullWidth, fullHeight, x, y, width, height }) { + if (!camera.view) { + camera.setViewOffset( + fullWidth || window.innerWidth, + fullHeight || window.innerHeight, + x || 0, + y || 0, + width || window.innerWidth, + height || window.innerHeight, + ); + } else { + camera.setViewOffset( + fullWidth || camera.view.fullWidth, + fullHeight || camera.view.fullHeight, + x || camera.view.offsetX, + y || camera.view.offsetY, + width || camera.view.width, + height || camera.view.height, + ); + } +} diff --git a/examples-testing/examples/css3d_periodictable.ts b/examples-testing/examples/css3d_periodictable.ts new file mode 100644 index 000000000..e3a33f796 --- /dev/null +++ b/examples-testing/examples/css3d_periodictable.ts @@ -0,0 +1,793 @@ +import * as THREE from 'three'; + +import TWEEN from 'three/addons/libs/tween.module.js'; +import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; +import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js'; + +const table = [ + 'H', + 'Hydrogen', + '1.00794', + 1, + 1, + 'He', + 'Helium', + '4.002602', + 18, + 1, + 'Li', + 'Lithium', + '6.941', + 1, + 2, + 'Be', + 'Beryllium', + '9.012182', + 2, + 2, + 'B', + 'Boron', + '10.811', + 13, + 2, + 'C', + 'Carbon', + '12.0107', + 14, + 2, + 'N', + 'Nitrogen', + '14.0067', + 15, + 2, + 'O', + 'Oxygen', + '15.9994', + 16, + 2, + 'F', + 'Fluorine', + '18.9984032', + 17, + 2, + 'Ne', + 'Neon', + '20.1797', + 18, + 2, + 'Na', + 'Sodium', + '22.98976...', + 1, + 3, + 'Mg', + 'Magnesium', + '24.305', + 2, + 3, + 'Al', + 'Aluminium', + '26.9815386', + 13, + 3, + 'Si', + 'Silicon', + '28.0855', + 14, + 3, + 'P', + 'Phosphorus', + '30.973762', + 15, + 3, + 'S', + 'Sulfur', + '32.065', + 16, + 3, + 'Cl', + 'Chlorine', + '35.453', + 17, + 3, + 'Ar', + 'Argon', + '39.948', + 18, + 3, + 'K', + 'Potassium', + '39.948', + 1, + 4, + 'Ca', + 'Calcium', + '40.078', + 2, + 4, + 'Sc', + 'Scandium', + '44.955912', + 3, + 4, + 'Ti', + 'Titanium', + '47.867', + 4, + 4, + 'V', + 'Vanadium', + '50.9415', + 5, + 4, + 'Cr', + 'Chromium', + '51.9961', + 6, + 4, + 'Mn', + 'Manganese', + '54.938045', + 7, + 4, + 'Fe', + 'Iron', + '55.845', + 8, + 4, + 'Co', + 'Cobalt', + '58.933195', + 9, + 4, + 'Ni', + 'Nickel', + '58.6934', + 10, + 4, + 'Cu', + 'Copper', + '63.546', + 11, + 4, + 'Zn', + 'Zinc', + '65.38', + 12, + 4, + 'Ga', + 'Gallium', + '69.723', + 13, + 4, + 'Ge', + 'Germanium', + '72.63', + 14, + 4, + 'As', + 'Arsenic', + '74.9216', + 15, + 4, + 'Se', + 'Selenium', + '78.96', + 16, + 4, + 'Br', + 'Bromine', + '79.904', + 17, + 4, + 'Kr', + 'Krypton', + '83.798', + 18, + 4, + 'Rb', + 'Rubidium', + '85.4678', + 1, + 5, + 'Sr', + 'Strontium', + '87.62', + 2, + 5, + 'Y', + 'Yttrium', + '88.90585', + 3, + 5, + 'Zr', + 'Zirconium', + '91.224', + 4, + 5, + 'Nb', + 'Niobium', + '92.90628', + 5, + 5, + 'Mo', + 'Molybdenum', + '95.96', + 6, + 5, + 'Tc', + 'Technetium', + '(98)', + 7, + 5, + 'Ru', + 'Ruthenium', + '101.07', + 8, + 5, + 'Rh', + 'Rhodium', + '102.9055', + 9, + 5, + 'Pd', + 'Palladium', + '106.42', + 10, + 5, + 'Ag', + 'Silver', + '107.8682', + 11, + 5, + 'Cd', + 'Cadmium', + '112.411', + 12, + 5, + 'In', + 'Indium', + '114.818', + 13, + 5, + 'Sn', + 'Tin', + '118.71', + 14, + 5, + 'Sb', + 'Antimony', + '121.76', + 15, + 5, + 'Te', + 'Tellurium', + '127.6', + 16, + 5, + 'I', + 'Iodine', + '126.90447', + 17, + 5, + 'Xe', + 'Xenon', + '131.293', + 18, + 5, + 'Cs', + 'Caesium', + '132.9054', + 1, + 6, + 'Ba', + 'Barium', + '132.9054', + 2, + 6, + 'La', + 'Lanthanum', + '138.90547', + 4, + 9, + 'Ce', + 'Cerium', + '140.116', + 5, + 9, + 'Pr', + 'Praseodymium', + '140.90765', + 6, + 9, + 'Nd', + 'Neodymium', + '144.242', + 7, + 9, + 'Pm', + 'Promethium', + '(145)', + 8, + 9, + 'Sm', + 'Samarium', + '150.36', + 9, + 9, + 'Eu', + 'Europium', + '151.964', + 10, + 9, + 'Gd', + 'Gadolinium', + '157.25', + 11, + 9, + 'Tb', + 'Terbium', + '158.92535', + 12, + 9, + 'Dy', + 'Dysprosium', + '162.5', + 13, + 9, + 'Ho', + 'Holmium', + '164.93032', + 14, + 9, + 'Er', + 'Erbium', + '167.259', + 15, + 9, + 'Tm', + 'Thulium', + '168.93421', + 16, + 9, + 'Yb', + 'Ytterbium', + '173.054', + 17, + 9, + 'Lu', + 'Lutetium', + '174.9668', + 18, + 9, + 'Hf', + 'Hafnium', + '178.49', + 4, + 6, + 'Ta', + 'Tantalum', + '180.94788', + 5, + 6, + 'W', + 'Tungsten', + '183.84', + 6, + 6, + 'Re', + 'Rhenium', + '186.207', + 7, + 6, + 'Os', + 'Osmium', + '190.23', + 8, + 6, + 'Ir', + 'Iridium', + '192.217', + 9, + 6, + 'Pt', + 'Platinum', + '195.084', + 10, + 6, + 'Au', + 'Gold', + '196.966569', + 11, + 6, + 'Hg', + 'Mercury', + '200.59', + 12, + 6, + 'Tl', + 'Thallium', + '204.3833', + 13, + 6, + 'Pb', + 'Lead', + '207.2', + 14, + 6, + 'Bi', + 'Bismuth', + '208.9804', + 15, + 6, + 'Po', + 'Polonium', + '(209)', + 16, + 6, + 'At', + 'Astatine', + '(210)', + 17, + 6, + 'Rn', + 'Radon', + '(222)', + 18, + 6, + 'Fr', + 'Francium', + '(223)', + 1, + 7, + 'Ra', + 'Radium', + '(226)', + 2, + 7, + 'Ac', + 'Actinium', + '(227)', + 4, + 10, + 'Th', + 'Thorium', + '232.03806', + 5, + 10, + 'Pa', + 'Protactinium', + '231.0588', + 6, + 10, + 'U', + 'Uranium', + '238.02891', + 7, + 10, + 'Np', + 'Neptunium', + '(237)', + 8, + 10, + 'Pu', + 'Plutonium', + '(244)', + 9, + 10, + 'Am', + 'Americium', + '(243)', + 10, + 10, + 'Cm', + 'Curium', + '(247)', + 11, + 10, + 'Bk', + 'Berkelium', + '(247)', + 12, + 10, + 'Cf', + 'Californium', + '(251)', + 13, + 10, + 'Es', + 'Einstenium', + '(252)', + 14, + 10, + 'Fm', + 'Fermium', + '(257)', + 15, + 10, + 'Md', + 'Mendelevium', + '(258)', + 16, + 10, + 'No', + 'Nobelium', + '(259)', + 17, + 10, + 'Lr', + 'Lawrencium', + '(262)', + 18, + 10, + 'Rf', + 'Rutherfordium', + '(267)', + 4, + 7, + 'Db', + 'Dubnium', + '(268)', + 5, + 7, + 'Sg', + 'Seaborgium', + '(271)', + 6, + 7, + 'Bh', + 'Bohrium', + '(272)', + 7, + 7, + 'Hs', + 'Hassium', + '(270)', + 8, + 7, + 'Mt', + 'Meitnerium', + '(276)', + 9, + 7, + 'Ds', + 'Darmstadium', + '(281)', + 10, + 7, + 'Rg', + 'Roentgenium', + '(280)', + 11, + 7, + 'Cn', + 'Copernicium', + '(285)', + 12, + 7, + 'Nh', + 'Nihonium', + '(286)', + 13, + 7, + 'Fl', + 'Flerovium', + '(289)', + 14, + 7, + 'Mc', + 'Moscovium', + '(290)', + 15, + 7, + 'Lv', + 'Livermorium', + '(293)', + 16, + 7, + 'Ts', + 'Tennessine', + '(294)', + 17, + 7, + 'Og', + 'Oganesson', + '(294)', + 18, + 7, +]; + +let camera, scene, renderer; +let controls; + +const objects = []; +const targets = { table: [], sphere: [], helix: [], grid: [] }; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000); + camera.position.z = 3000; + + scene = new THREE.Scene(); + + // table + + for (let i = 0; i < table.length; i += 5) { + const element = document.createElement('div'); + element.className = 'element'; + element.style.backgroundColor = 'rgba(0,127,127,' + (Math.random() * 0.5 + 0.25) + ')'; + + const number = document.createElement('div'); + number.className = 'number'; + number.textContent = i / 5 + 1; + element.appendChild(number); + + const symbol = document.createElement('div'); + symbol.className = 'symbol'; + symbol.textContent = table[i]; + element.appendChild(symbol); + + const details = document.createElement('div'); + details.className = 'details'; + details.innerHTML = table[i + 1] + '
' + table[i + 2]; + element.appendChild(details); + + const objectCSS = new CSS3DObject(element); + objectCSS.position.x = Math.random() * 4000 - 2000; + objectCSS.position.y = Math.random() * 4000 - 2000; + objectCSS.position.z = Math.random() * 4000 - 2000; + scene.add(objectCSS); + + objects.push(objectCSS); + + // + + const object = new THREE.Object3D(); + object.position.x = table[i + 3] * 140 - 1330; + object.position.y = -(table[i + 4] * 180) + 990; + + targets.table.push(object); + } + + // sphere + + const vector = new THREE.Vector3(); + + for (let i = 0, l = objects.length; i < l; i++) { + const phi = Math.acos(-1 + (2 * i) / l); + const theta = Math.sqrt(l * Math.PI) * phi; + + const object = new THREE.Object3D(); + + object.position.setFromSphericalCoords(800, phi, theta); + + vector.copy(object.position).multiplyScalar(2); + + object.lookAt(vector); + + targets.sphere.push(object); + } + + // helix + + for (let i = 0, l = objects.length; i < l; i++) { + const theta = i * 0.175 + Math.PI; + const y = -(i * 8) + 450; + + const object = new THREE.Object3D(); + + object.position.setFromCylindricalCoords(900, theta, y); + + vector.x = object.position.x * 2; + vector.y = object.position.y; + vector.z = object.position.z * 2; + + object.lookAt(vector); + + targets.helix.push(object); + } + + // grid + + for (let i = 0; i < objects.length; i++) { + const object = new THREE.Object3D(); + + object.position.x = (i % 5) * 400 - 800; + object.position.y = -(Math.floor(i / 5) % 5) * 400 + 800; + object.position.z = Math.floor(i / 25) * 1000 - 2000; + + targets.grid.push(object); + } + + // + + renderer = new CSS3DRenderer(); + renderer.setSize(window.innerWidth, window.innerHeight); + document.getElementById('container').appendChild(renderer.domElement); + + // + + controls = new TrackballControls(camera, renderer.domElement); + controls.minDistance = 500; + controls.maxDistance = 6000; + controls.addEventListener('change', render); + + const buttonTable = document.getElementById('table'); + buttonTable.addEventListener('click', function () { + transform(targets.table, 2000); + }); + + const buttonSphere = document.getElementById('sphere'); + buttonSphere.addEventListener('click', function () { + transform(targets.sphere, 2000); + }); + + const buttonHelix = document.getElementById('helix'); + buttonHelix.addEventListener('click', function () { + transform(targets.helix, 2000); + }); + + const buttonGrid = document.getElementById('grid'); + buttonGrid.addEventListener('click', function () { + transform(targets.grid, 2000); + }); + + transform(targets.table, 2000); + + // + + window.addEventListener('resize', onWindowResize); +} + +function transform(targets, duration) { + TWEEN.removeAll(); + + for (let i = 0; i < objects.length; i++) { + const object = objects[i]; + const target = targets[i]; + + new TWEEN.Tween(object.position) + .to( + { x: target.position.x, y: target.position.y, z: target.position.z }, + Math.random() * duration + duration, + ) + .easing(TWEEN.Easing.Exponential.InOut) + .start(); + + new TWEEN.Tween(object.rotation) + .to( + { x: target.rotation.x, y: target.rotation.y, z: target.rotation.z }, + Math.random() * duration + duration, + ) + .easing(TWEEN.Easing.Exponential.InOut) + .start(); + } + + new TWEEN.Tween(this) + .to({}, duration * 2) + .onUpdate(render) + .start(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + render(); +} + +function animate() { + requestAnimationFrame(animate); + + TWEEN.update(); + + controls.update(); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/css3d_sandbox.ts b/examples-testing/examples/css3d_sandbox.ts new file mode 100644 index 000000000..1088b84b1 --- /dev/null +++ b/examples-testing/examples/css3d_sandbox.ts @@ -0,0 +1,180 @@ +import * as THREE from 'three'; + +import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; +import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let camera, scene, renderer; + +let scene2, renderer2; + +let controls; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.set(200, 200, 200); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xf0f0f0); + + scene2 = new THREE.Scene(); + + const material = new THREE.MeshBasicMaterial({ + color: 0x000000, + wireframe: true, + wireframeLinewidth: 1, + side: THREE.DoubleSide, + }); + + // + + for (let i = 0; i < 10; i++) { + const element = document.createElement('div'); + element.style.width = '100px'; + element.style.height = '100px'; + element.style.opacity = i < 5 ? 0.5 : 1; + element.style.background = new THREE.Color(Math.random() * 0xffffff).getStyle(); + + const object = new CSS3DObject(element); + object.position.x = Math.random() * 200 - 100; + object.position.y = Math.random() * 200 - 100; + object.position.z = Math.random() * 200 - 100; + object.rotation.x = Math.random(); + object.rotation.y = Math.random(); + object.rotation.z = Math.random(); + object.scale.x = Math.random() + 0.5; + object.scale.y = Math.random() + 0.5; + scene2.add(object); + + const geometry = new THREE.PlaneGeometry(100, 100); + const mesh = new THREE.Mesh(geometry, material); + mesh.position.copy(object.position); + mesh.rotation.copy(object.rotation); + mesh.scale.copy(object.scale); + scene.add(mesh); + } + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + renderer2 = new CSS3DRenderer(); + renderer2.setSize(window.innerWidth, window.innerHeight); + renderer2.domElement.style.position = 'absolute'; + renderer2.domElement.style.top = 0; + document.body.appendChild(renderer2.domElement); + + controls = new TrackballControls(camera, renderer2.domElement); + + window.addEventListener('resize', onWindowResize); + createPanel(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + renderer2.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + controls.update(); + + renderer.render(scene, camera); + renderer2.render(scene2, camera); +} + +function createPanel() { + const panel = new GUI(); + const folder1 = panel.addFolder('camera setViewOffset').close(); + + const settings = { + setViewOffset() { + folder1.children[1].enable().setValue(window.innerWidth); + folder1.children[2].enable().setValue(window.innerHeight); + folder1.children[3].enable().setValue(0); + folder1.children[4].enable().setValue(0); + folder1.children[5].enable().setValue(window.innerWidth); + folder1.children[6].enable().setValue(window.innerHeight); + }, + fullWidth: 0, + fullHeight: 0, + offsetX: 0, + offsetY: 0, + width: 0, + height: 0, + clearViewOffset() { + folder1.children[1].setValue(0).disable(); + folder1.children[2].setValue(0).disable(); + folder1.children[3].setValue(0).disable(); + folder1.children[4].setValue(0).disable(); + folder1.children[5].setValue(0).disable(); + folder1.children[6].setValue(0).disable(); + camera.clearViewOffset(); + }, + }; + + folder1.add(settings, 'setViewOffset'); + folder1 + .add(settings, 'fullWidth', window.screen.width / 4, window.screen.width * 2, 1) + .onChange(val => updateCameraViewOffset({ fullWidth: val })) + .disable(); + folder1 + .add(settings, 'fullHeight', window.screen.height / 4, window.screen.height * 2, 1) + .onChange(val => updateCameraViewOffset({ fullHeight: val })) + .disable(); + folder1 + .add(settings, 'offsetX', 0, 256, 1) + .onChange(val => updateCameraViewOffset({ x: val })) + .disable(); + folder1 + .add(settings, 'offsetY', 0, 256, 1) + .onChange(val => updateCameraViewOffset({ y: val })) + .disable(); + folder1 + .add(settings, 'width', window.screen.width / 4, window.screen.width * 2, 1) + .onChange(val => updateCameraViewOffset({ width: val })) + .disable(); + folder1 + .add(settings, 'height', window.screen.height / 4, window.screen.height * 2, 1) + .onChange(val => updateCameraViewOffset({ height: val })) + .disable(); + folder1.add(settings, 'clearViewOffset'); +} + +function updateCameraViewOffset({ fullWidth, fullHeight, x, y, width, height }) { + if (!camera.view) { + camera.setViewOffset( + fullWidth || window.innerWidth, + fullHeight || window.innerHeight, + x || 0, + y || 0, + width || window.innerWidth, + height || window.innerHeight, + ); + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + } else { + camera.setViewOffset( + fullWidth || camera.view.fullWidth, + fullHeight || camera.view.fullHeight, + x || camera.view.offsetX, + y || camera.view.offsetY, + width || camera.view.width, + height || camera.view.height, + ); + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + } +} diff --git a/examples-testing/examples/css3d_sprites.ts b/examples-testing/examples/css3d_sprites.ts new file mode 100644 index 000000000..dfe24e79d --- /dev/null +++ b/examples-testing/examples/css3d_sprites.ts @@ -0,0 +1,157 @@ +import * as THREE from 'three'; + +import TWEEN from 'three/addons/libs/tween.module.js'; +import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; +import { CSS3DRenderer, CSS3DSprite } from 'three/addons/renderers/CSS3DRenderer.js'; + +let camera, scene, renderer; +let controls; + +const particlesTotal = 512; +const positions = []; +const objects = []; +let current = 0; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 5000); + camera.position.set(600, 400, 1500); + camera.lookAt(0, 0, 0); + + scene = new THREE.Scene(); + + const image = document.createElement('img'); + image.addEventListener('load', function () { + for (let i = 0; i < particlesTotal; i++) { + const object = new CSS3DSprite(image.cloneNode()); + (object.position.x = Math.random() * 4000 - 2000), + (object.position.y = Math.random() * 4000 - 2000), + (object.position.z = Math.random() * 4000 - 2000); + scene.add(object); + + objects.push(object); + } + + transition(); + }); + image.src = 'textures/sprite.png'; + + // Plane + + const amountX = 16; + const amountZ = 32; + const separationPlane = 150; + const offsetX = ((amountX - 1) * separationPlane) / 2; + const offsetZ = ((amountZ - 1) * separationPlane) / 2; + + for (let i = 0; i < particlesTotal; i++) { + const x = (i % amountX) * separationPlane; + const z = Math.floor(i / amountX) * separationPlane; + const y = (Math.sin(x * 0.5) + Math.sin(z * 0.5)) * 200; + + positions.push(x - offsetX, y, z - offsetZ); + } + + // Cube + + const amount = 8; + const separationCube = 150; + const offset = ((amount - 1) * separationCube) / 2; + + for (let i = 0; i < particlesTotal; i++) { + const x = (i % amount) * separationCube; + const y = Math.floor((i / amount) % amount) * separationCube; + const z = Math.floor(i / (amount * amount)) * separationCube; + + positions.push(x - offset, y - offset, z - offset); + } + + // Random + + for (let i = 0; i < particlesTotal; i++) { + positions.push(Math.random() * 4000 - 2000, Math.random() * 4000 - 2000, Math.random() * 4000 - 2000); + } + + // Sphere + + const radius = 750; + + for (let i = 0; i < particlesTotal; i++) { + const phi = Math.acos(-1 + (2 * i) / particlesTotal); + const theta = Math.sqrt(particlesTotal * Math.PI) * phi; + + positions.push( + radius * Math.cos(theta) * Math.sin(phi), + radius * Math.sin(theta) * Math.sin(phi), + radius * Math.cos(phi), + ); + } + + // + + renderer = new CSS3DRenderer(); + renderer.setSize(window.innerWidth, window.innerHeight); + document.getElementById('container').appendChild(renderer.domElement); + + // + + controls = new TrackballControls(camera, renderer.domElement); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function transition() { + const offset = current * particlesTotal * 3; + const duration = 2000; + + for (let i = 0, j = offset; i < particlesTotal; i++, j += 3) { + const object = objects[i]; + + new TWEEN.Tween(object.position) + .to( + { + x: positions[j], + y: positions[j + 1], + z: positions[j + 2], + }, + Math.random() * duration + duration, + ) + .easing(TWEEN.Easing.Exponential.InOut) + .start(); + } + + new TWEEN.Tween(this) + .to({}, duration * 3) + .onComplete(transition) + .start(); + + current = (current + 1) % 4; +} + +function animate() { + requestAnimationFrame(animate); + + TWEEN.update(); + controls.update(); + + const time = performance.now(); + + for (let i = 0, l = objects.length; i < l; i++) { + const object = objects[i]; + const scale = Math.sin((Math.floor(object.position.x) + time) * 0.002) * 0.3 + 1; + object.scale.set(scale, scale, scale); + } + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/css3d_youtube.ts b/examples-testing/examples/css3d_youtube.ts new file mode 100644 index 000000000..62652f87f --- /dev/null +++ b/examples-testing/examples/css3d_youtube.ts @@ -0,0 +1,79 @@ +import * as THREE from 'three'; + +import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; +import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js'; + +let camera, scene, renderer; +let controls; + +function Element(id, x, y, z, ry) { + const div = document.createElement('div'); + div.style.width = '480px'; + div.style.height = '360px'; + div.style.backgroundColor = '#000'; + + const iframe = document.createElement('iframe'); + iframe.style.width = '480px'; + iframe.style.height = '360px'; + iframe.style.border = '0px'; + iframe.src = ['https://www.youtube.com/embed/', id, '?rel=0'].join(''); + div.appendChild(iframe); + + const object = new CSS3DObject(div); + object.position.set(x, y, z); + object.rotation.y = ry; + + return object; +} + +init(); +animate(); + +function init() { + const container = document.getElementById('container'); + + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 5000); + camera.position.set(500, 350, 750); + + scene = new THREE.Scene(); + + renderer = new CSS3DRenderer(); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + const group = new THREE.Group(); + group.add(new Element('SJOz3qjfQXU', 0, 0, 240, 0)); + group.add(new Element('Y2-xZ-1HE-Q', 240, 0, 0, Math.PI / 2)); + group.add(new Element('IrydklNpcFI', 0, 0, -240, Math.PI)); + group.add(new Element('9ubytEsCaS0', -240, 0, 0, -Math.PI / 2)); + scene.add(group); + + controls = new TrackballControls(camera, renderer.domElement); + controls.rotateSpeed = 4; + + window.addEventListener('resize', onWindowResize); + + // Block iframe events when dragging camera + + const blocker = document.getElementById('blocker'); + blocker.style.display = 'none'; + + controls.addEventListener('start', function () { + blocker.style.display = ''; + }); + controls.addEventListener('end', function () { + blocker.style.display = 'none'; + }); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + controls.update(); + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/games_fps.ts b/examples-testing/examples/games_fps.ts new file mode 100644 index 000000000..49d31e760 --- /dev/null +++ b/examples-testing/examples/games_fps.ts @@ -0,0 +1,373 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; + +import { Octree } from 'three/addons/math/Octree.js'; +import { OctreeHelper } from 'three/addons/helpers/OctreeHelper.js'; + +import { Capsule } from 'three/addons/math/Capsule.js'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +const clock = new THREE.Clock(); + +const scene = new THREE.Scene(); +scene.background = new THREE.Color(0x88ccee); +scene.fog = new THREE.Fog(0x88ccee, 0, 50); + +const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000); +camera.rotation.order = 'YXZ'; + +const fillLight1 = new THREE.HemisphereLight(0x8dc1de, 0x00668d, 1.5); +fillLight1.position.set(2, 1, 1); +scene.add(fillLight1); + +const directionalLight = new THREE.DirectionalLight(0xffffff, 2.5); +directionalLight.position.set(-5, 25, -1); +directionalLight.castShadow = true; +directionalLight.shadow.camera.near = 0.01; +directionalLight.shadow.camera.far = 500; +directionalLight.shadow.camera.right = 30; +directionalLight.shadow.camera.left = -30; +directionalLight.shadow.camera.top = 30; +directionalLight.shadow.camera.bottom = -30; +directionalLight.shadow.mapSize.width = 1024; +directionalLight.shadow.mapSize.height = 1024; +directionalLight.shadow.radius = 4; +directionalLight.shadow.bias = -0.00006; +scene.add(directionalLight); + +const container = document.getElementById('container'); + +const renderer = new THREE.WebGLRenderer({ antialias: true }); +renderer.setPixelRatio(window.devicePixelRatio); +renderer.setSize(window.innerWidth, window.innerHeight); +renderer.shadowMap.enabled = true; +renderer.shadowMap.type = THREE.VSMShadowMap; +renderer.toneMapping = THREE.ACESFilmicToneMapping; +container.appendChild(renderer.domElement); + +const stats = new Stats(); +stats.domElement.style.position = 'absolute'; +stats.domElement.style.top = '0px'; +container.appendChild(stats.domElement); + +const GRAVITY = 30; + +const NUM_SPHERES = 100; +const SPHERE_RADIUS = 0.2; + +const STEPS_PER_FRAME = 5; + +const sphereGeometry = new THREE.IcosahedronGeometry(SPHERE_RADIUS, 5); +const sphereMaterial = new THREE.MeshLambertMaterial({ color: 0xdede8d }); + +const spheres = []; +let sphereIdx = 0; + +for (let i = 0; i < NUM_SPHERES; i++) { + const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); + sphere.castShadow = true; + sphere.receiveShadow = true; + + scene.add(sphere); + + spheres.push({ + mesh: sphere, + collider: new THREE.Sphere(new THREE.Vector3(0, -100, 0), SPHERE_RADIUS), + velocity: new THREE.Vector3(), + }); +} + +const worldOctree = new Octree(); + +const playerCollider = new Capsule(new THREE.Vector3(0, 0.35, 0), new THREE.Vector3(0, 1, 0), 0.35); + +const playerVelocity = new THREE.Vector3(); +const playerDirection = new THREE.Vector3(); + +let playerOnFloor = false; +let mouseTime = 0; + +const keyStates = {}; + +const vector1 = new THREE.Vector3(); +const vector2 = new THREE.Vector3(); +const vector3 = new THREE.Vector3(); + +document.addEventListener('keydown', event => { + keyStates[event.code] = true; +}); + +document.addEventListener('keyup', event => { + keyStates[event.code] = false; +}); + +container.addEventListener('mousedown', () => { + document.body.requestPointerLock(); + + mouseTime = performance.now(); +}); + +document.addEventListener('mouseup', () => { + if (document.pointerLockElement !== null) throwBall(); +}); + +document.body.addEventListener('mousemove', event => { + if (document.pointerLockElement === document.body) { + camera.rotation.y -= event.movementX / 500; + camera.rotation.x -= event.movementY / 500; + } +}); + +window.addEventListener('resize', onWindowResize); + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function throwBall() { + const sphere = spheres[sphereIdx]; + + camera.getWorldDirection(playerDirection); + + sphere.collider.center.copy(playerCollider.end).addScaledVector(playerDirection, playerCollider.radius * 1.5); + + // throw the ball with more force if we hold the button longer, and if we move forward + + const impulse = 15 + 30 * (1 - Math.exp((mouseTime - performance.now()) * 0.001)); + + sphere.velocity.copy(playerDirection).multiplyScalar(impulse); + sphere.velocity.addScaledVector(playerVelocity, 2); + + sphereIdx = (sphereIdx + 1) % spheres.length; +} + +function playerCollisions() { + const result = worldOctree.capsuleIntersect(playerCollider); + + playerOnFloor = false; + + if (result) { + playerOnFloor = result.normal.y > 0; + + if (!playerOnFloor) { + playerVelocity.addScaledVector(result.normal, -result.normal.dot(playerVelocity)); + } + + playerCollider.translate(result.normal.multiplyScalar(result.depth)); + } +} + +function updatePlayer(deltaTime) { + let damping = Math.exp(-4 * deltaTime) - 1; + + if (!playerOnFloor) { + playerVelocity.y -= GRAVITY * deltaTime; + + // small air resistance + damping *= 0.1; + } + + playerVelocity.addScaledVector(playerVelocity, damping); + + const deltaPosition = playerVelocity.clone().multiplyScalar(deltaTime); + playerCollider.translate(deltaPosition); + + playerCollisions(); + + camera.position.copy(playerCollider.end); +} + +function playerSphereCollision(sphere) { + const center = vector1.addVectors(playerCollider.start, playerCollider.end).multiplyScalar(0.5); + + const sphere_center = sphere.collider.center; + + const r = playerCollider.radius + sphere.collider.radius; + const r2 = r * r; + + // approximation: player = 3 spheres + + for (const point of [playerCollider.start, playerCollider.end, center]) { + const d2 = point.distanceToSquared(sphere_center); + + if (d2 < r2) { + const normal = vector1.subVectors(point, sphere_center).normalize(); + const v1 = vector2.copy(normal).multiplyScalar(normal.dot(playerVelocity)); + const v2 = vector3.copy(normal).multiplyScalar(normal.dot(sphere.velocity)); + + playerVelocity.add(v2).sub(v1); + sphere.velocity.add(v1).sub(v2); + + const d = (r - Math.sqrt(d2)) / 2; + sphere_center.addScaledVector(normal, -d); + } + } +} + +function spheresCollisions() { + for (let i = 0, length = spheres.length; i < length; i++) { + const s1 = spheres[i]; + + for (let j = i + 1; j < length; j++) { + const s2 = spheres[j]; + + const d2 = s1.collider.center.distanceToSquared(s2.collider.center); + const r = s1.collider.radius + s2.collider.radius; + const r2 = r * r; + + if (d2 < r2) { + const normal = vector1.subVectors(s1.collider.center, s2.collider.center).normalize(); + const v1 = vector2.copy(normal).multiplyScalar(normal.dot(s1.velocity)); + const v2 = vector3.copy(normal).multiplyScalar(normal.dot(s2.velocity)); + + s1.velocity.add(v2).sub(v1); + s2.velocity.add(v1).sub(v2); + + const d = (r - Math.sqrt(d2)) / 2; + + s1.collider.center.addScaledVector(normal, d); + s2.collider.center.addScaledVector(normal, -d); + } + } + } +} + +function updateSpheres(deltaTime) { + spheres.forEach(sphere => { + sphere.collider.center.addScaledVector(sphere.velocity, deltaTime); + + const result = worldOctree.sphereIntersect(sphere.collider); + + if (result) { + sphere.velocity.addScaledVector(result.normal, -result.normal.dot(sphere.velocity) * 1.5); + sphere.collider.center.add(result.normal.multiplyScalar(result.depth)); + } else { + sphere.velocity.y -= GRAVITY * deltaTime; + } + + const damping = Math.exp(-1.5 * deltaTime) - 1; + sphere.velocity.addScaledVector(sphere.velocity, damping); + + playerSphereCollision(sphere); + }); + + spheresCollisions(); + + for (const sphere of spheres) { + sphere.mesh.position.copy(sphere.collider.center); + } +} + +function getForwardVector() { + camera.getWorldDirection(playerDirection); + playerDirection.y = 0; + playerDirection.normalize(); + + return playerDirection; +} + +function getSideVector() { + camera.getWorldDirection(playerDirection); + playerDirection.y = 0; + playerDirection.normalize(); + playerDirection.cross(camera.up); + + return playerDirection; +} + +function controls(deltaTime) { + // gives a bit of air control + const speedDelta = deltaTime * (playerOnFloor ? 25 : 8); + + if (keyStates['KeyW']) { + playerVelocity.add(getForwardVector().multiplyScalar(speedDelta)); + } + + if (keyStates['KeyS']) { + playerVelocity.add(getForwardVector().multiplyScalar(-speedDelta)); + } + + if (keyStates['KeyA']) { + playerVelocity.add(getSideVector().multiplyScalar(-speedDelta)); + } + + if (keyStates['KeyD']) { + playerVelocity.add(getSideVector().multiplyScalar(speedDelta)); + } + + if (playerOnFloor) { + if (keyStates['Space']) { + playerVelocity.y = 15; + } + } +} + +const loader = new GLTFLoader().setPath('./models/gltf/'); + +loader.load('collision-world.glb', gltf => { + scene.add(gltf.scene); + + worldOctree.fromGraphNode(gltf.scene); + + gltf.scene.traverse(child => { + if (child.isMesh) { + child.castShadow = true; + child.receiveShadow = true; + + if (child.material.map) { + child.material.map.anisotropy = 4; + } + } + }); + + const helper = new OctreeHelper(worldOctree); + helper.visible = false; + scene.add(helper); + + const gui = new GUI({ width: 200 }); + gui.add({ debug: false }, 'debug').onChange(function (value) { + helper.visible = value; + }); + + animate(); +}); + +function teleportPlayerIfOob() { + if (camera.position.y <= -25) { + playerCollider.start.set(0, 0.35, 0); + playerCollider.end.set(0, 1, 0); + playerCollider.radius = 0.35; + camera.position.copy(playerCollider.end); + camera.rotation.set(0, 0, 0); + } +} + +function animate() { + const deltaTime = Math.min(0.05, clock.getDelta()) / STEPS_PER_FRAME; + + // we look for collisions in substeps to mitigate the risk of + // an object traversing another too quickly for detection. + + for (let i = 0; i < STEPS_PER_FRAME; i++) { + controls(deltaTime); + + updatePlayer(deltaTime); + + updateSpheres(deltaTime); + + teleportPlayerIfOob(); + } + + renderer.render(scene, camera); + + stats.update(); + + requestAnimationFrame(animate); +} diff --git a/examples-testing/examples/misc_animation_groups.ts b/examples-testing/examples/misc_animation_groups.ts new file mode 100644 index 000000000..19d263f4b --- /dev/null +++ b/examples-testing/examples/misc_animation_groups.ts @@ -0,0 +1,131 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let stats, clock; +let scene, camera, renderer, mixer; + +init(); +animate(); + +function init() { + scene = new THREE.Scene(); + + // + + camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.set(50, 50, 100); + camera.lookAt(scene.position); + + // all objects of this animation group share a common animation state + + const animationGroup = new THREE.AnimationObjectGroup(); + + // + + const geometry = new THREE.BoxGeometry(5, 5, 5); + const material = new THREE.MeshBasicMaterial({ transparent: true }); + + // + + for (let i = 0; i < 5; i++) { + for (let j = 0; j < 5; j++) { + const mesh = new THREE.Mesh(geometry, material); + + mesh.position.x = 32 - 16 * i; + mesh.position.y = 0; + mesh.position.z = 32 - 16 * j; + + scene.add(mesh); + animationGroup.add(mesh); + } + } + + // create some keyframe tracks + + const xAxis = new THREE.Vector3(1, 0, 0); + const qInitial = new THREE.Quaternion().setFromAxisAngle(xAxis, 0); + const qFinal = new THREE.Quaternion().setFromAxisAngle(xAxis, Math.PI); + const quaternionKF = new THREE.QuaternionKeyframeTrack( + '.quaternion', + [0, 1, 2], + [ + qInitial.x, + qInitial.y, + qInitial.z, + qInitial.w, + qFinal.x, + qFinal.y, + qFinal.z, + qFinal.w, + qInitial.x, + qInitial.y, + qInitial.z, + qInitial.w, + ], + ); + + const colorKF = new THREE.ColorKeyframeTrack( + '.material.color', + [0, 1, 2], + [1, 0, 0, 0, 1, 0, 0, 0, 1], + THREE.InterpolateDiscrete, + ); + const opacityKF = new THREE.NumberKeyframeTrack('.material.opacity', [0, 1, 2], [1, 0, 1]); + + // create clip + + const clip = new THREE.AnimationClip('default', 3, [quaternionKF, colorKF, opacityKF]); + + // apply the animation group to the mixer as the root object + + mixer = new THREE.AnimationMixer(animationGroup); + + const clipAction = mixer.clipAction(clip); + clipAction.play(); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + // + + stats = new Stats(); + document.body.appendChild(stats.dom); + + // + + clock = new THREE.Clock(); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + render(); +} + +function render() { + const delta = clock.getDelta(); + + if (mixer) { + mixer.update(delta); + } + + renderer.render(scene, camera); + + stats.update(); +} diff --git a/examples-testing/examples/misc_animation_keys.ts b/examples-testing/examples/misc_animation_keys.ts new file mode 100644 index 000000000..4a8089878 --- /dev/null +++ b/examples-testing/examples/misc_animation_keys.ts @@ -0,0 +1,135 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let stats, clock; +let scene, camera, renderer, mixer; + +init(); +animate(); + +function init() { + scene = new THREE.Scene(); + + // + + camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.set(25, 25, 50); + camera.lookAt(scene.position); + + // + + const axesHelper = new THREE.AxesHelper(10); + scene.add(axesHelper); + + // + + const geometry = new THREE.BoxGeometry(5, 5, 5); + const material = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true }); + const mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // create a keyframe track (i.e. a timed sequence of keyframes) for each animated property + // Note: the keyframe track type should correspond to the type of the property being animated + + // POSITION + const positionKF = new THREE.VectorKeyframeTrack('.position', [0, 1, 2], [0, 0, 0, 30, 0, 0, 0, 0, 0]); + + // SCALE + const scaleKF = new THREE.VectorKeyframeTrack('.scale', [0, 1, 2], [1, 1, 1, 2, 2, 2, 1, 1, 1]); + + // ROTATION + // Rotation should be performed using quaternions, using a THREE.QuaternionKeyframeTrack + // Interpolating Euler angles (.rotation property) can be problematic and is currently not supported + + // set up rotation about x axis + const xAxis = new THREE.Vector3(1, 0, 0); + + const qInitial = new THREE.Quaternion().setFromAxisAngle(xAxis, 0); + const qFinal = new THREE.Quaternion().setFromAxisAngle(xAxis, Math.PI); + const quaternionKF = new THREE.QuaternionKeyframeTrack( + '.quaternion', + [0, 1, 2], + [ + qInitial.x, + qInitial.y, + qInitial.z, + qInitial.w, + qFinal.x, + qFinal.y, + qFinal.z, + qFinal.w, + qInitial.x, + qInitial.y, + qInitial.z, + qInitial.w, + ], + ); + + // COLOR + const colorKF = new THREE.ColorKeyframeTrack( + '.material.color', + [0, 1, 2], + [1, 0, 0, 0, 1, 0, 0, 0, 1], + THREE.InterpolateDiscrete, + ); + + // OPACITY + const opacityKF = new THREE.NumberKeyframeTrack('.material.opacity', [0, 1, 2], [1, 0, 1]); + + // create an animation sequence with the tracks + // If a negative time value is passed, the duration will be calculated from the times of the passed tracks array + const clip = new THREE.AnimationClip('Action', 3, [scaleKF, positionKF, quaternionKF, colorKF, opacityKF]); + + // setup the THREE.AnimationMixer + mixer = new THREE.AnimationMixer(mesh); + + // create a ClipAction and set it to play + const clipAction = mixer.clipAction(clip); + clipAction.play(); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + // + + stats = new Stats(); + document.body.appendChild(stats.dom); + + // + + clock = new THREE.Clock(); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + render(); +} + +function render() { + const delta = clock.getDelta(); + + if (mixer) { + mixer.update(delta); + } + + renderer.render(scene, camera); + + stats.update(); +} diff --git a/examples-testing/examples/misc_boxselection.ts b/examples-testing/examples/misc_boxselection.ts new file mode 100644 index 000000000..8766c5592 --- /dev/null +++ b/examples-testing/examples/misc_boxselection.ts @@ -0,0 +1,142 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import { SelectionBox } from 'three/addons/interactive/SelectionBox.js'; +import { SelectionHelper } from 'three/addons/interactive/SelectionHelper.js'; + +let container, stats; +let camera, scene, renderer; + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 500); + camera.position.z = 50; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xf0f0f0); + + scene.add(new THREE.AmbientLight(0xaaaaaa)); + + const light = new THREE.SpotLight(0xffffff, 10000); + light.position.set(0, 25, 50); + light.angle = Math.PI / 5; + + light.castShadow = true; + light.shadow.camera.near = 10; + light.shadow.camera.far = 100; + light.shadow.mapSize.width = 1024; + light.shadow.mapSize.height = 1024; + + scene.add(light); + + const geometry = new THREE.BoxGeometry(); + + for (let i = 0; i < 200; i++) { + const object = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff })); + + object.position.x = Math.random() * 80 - 40; + object.position.y = Math.random() * 45 - 25; + object.position.z = Math.random() * 45 - 25; + + object.rotation.x = Math.random() * 2 * Math.PI; + object.rotation.y = Math.random() * 2 * Math.PI; + object.rotation.z = Math.random() * 2 * Math.PI; + + object.scale.x = Math.random() * 2 + 1; + object.scale.y = Math.random() * 2 + 1; + object.scale.z = Math.random() * 2 + 1; + + object.castShadow = true; + object.receiveShadow = true; + + scene.add(object); + } + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + renderer.shadowMap.type = THREE.PCFShadowMap; + + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + renderer.render(scene, camera); +} + +const selectionBox = new SelectionBox(camera, scene); +const helper = new SelectionHelper(renderer, 'selectBox'); + +document.addEventListener('pointerdown', function (event) { + for (const item of selectionBox.collection) { + item.material.emissive.set(0x000000); + } + + selectionBox.startPoint.set( + (event.clientX / window.innerWidth) * 2 - 1, + -(event.clientY / window.innerHeight) * 2 + 1, + 0.5, + ); +}); + +document.addEventListener('pointermove', function (event) { + if (helper.isDown) { + for (let i = 0; i < selectionBox.collection.length; i++) { + selectionBox.collection[i].material.emissive.set(0x000000); + } + + selectionBox.endPoint.set( + (event.clientX / window.innerWidth) * 2 - 1, + -(event.clientY / window.innerHeight) * 2 + 1, + 0.5, + ); + + const allSelected = selectionBox.select(); + + for (let i = 0; i < allSelected.length; i++) { + allSelected[i].material.emissive.set(0xffffff); + } + } +}); + +document.addEventListener('pointerup', function (event) { + selectionBox.endPoint.set( + (event.clientX / window.innerWidth) * 2 - 1, + -(event.clientY / window.innerHeight) * 2 + 1, + 0.5, + ); + + const allSelected = selectionBox.select(); + + for (let i = 0; i < allSelected.length; i++) { + allSelected[i].material.emissive.set(0xffffff); + } +}); diff --git a/examples-testing/examples/misc_controls_arcball.ts b/examples-testing/examples/misc_controls_arcball.ts new file mode 100644 index 000000000..fbef33189 --- /dev/null +++ b/examples-testing/examples/misc_controls_arcball.ts @@ -0,0 +1,210 @@ +import * as THREE from 'three'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { ArcballControls } from 'three/addons/controls/ArcballControls.js'; + +import { OBJLoader } from 'three/addons/loaders/OBJLoader.js'; +import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'; + +const cameras = ['Orthographic', 'Perspective']; +const cameraType = { type: 'Perspective' }; + +const perspectiveDistance = 2.5; +const orthographicDistance = 120; +let camera, controls, scene, renderer, gui; +let folderOptions, folderAnimations; + +const arcballGui = { + gizmoVisible: true, + + setArcballControls: function () { + controls = new ArcballControls(camera, renderer.domElement, scene); + controls.addEventListener('change', render); + + this.gizmoVisible = true; + + this.populateGui(); + }, + + populateGui: function () { + folderOptions.add(controls, 'enabled').name('Enable controls'); + folderOptions.add(controls, 'enableGrid').name('Enable Grid'); + folderOptions.add(controls, 'enableRotate').name('Enable rotate'); + folderOptions.add(controls, 'enablePan').name('Enable pan'); + folderOptions.add(controls, 'enableZoom').name('Enable zoom'); + folderOptions.add(controls, 'cursorZoom').name('Cursor zoom'); + folderOptions.add(controls, 'adjustNearFar').name('adjust near/far'); + folderOptions.add(controls, 'scaleFactor', 1.1, 10, 0.1).name('Scale factor'); + folderOptions.add(controls, 'minDistance', 0, 50, 0.5).name('Min distance'); + folderOptions.add(controls, 'maxDistance', 0, 50, 0.5).name('Max distance'); + folderOptions.add(controls, 'minZoom', 0, 50, 0.5).name('Min zoom'); + folderOptions.add(controls, 'maxZoom', 0, 50, 0.5).name('Max zoom'); + folderOptions + .add(arcballGui, 'gizmoVisible') + .name('Show gizmos') + .onChange(function () { + controls.setGizmosVisible(arcballGui.gizmoVisible); + }); + folderOptions.add(controls, 'copyState').name('Copy state(ctrl+c)'); + folderOptions.add(controls, 'pasteState').name('Paste state(ctrl+v)'); + folderOptions.add(controls, 'reset').name('Reset'); + folderAnimations.add(controls, 'enableAnimations').name('Enable anim.'); + folderAnimations.add(controls, 'dampingFactor', 0, 100, 1).name('Damping'); + folderAnimations.add(controls, 'wMax', 0, 100, 1).name('Angular spd'); + }, +}; + +init(); + +function init() { + const container = document.createElement('div'); + document.body.appendChild(container); + + renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.toneMapping = THREE.ReinhardToneMapping; + renderer.toneMappingExposure = 3; + renderer.domElement.style.background = 'linear-gradient( 180deg, rgba( 0,0,0,1 ) 0%, rgba( 128,128,255,1 ) 100% )'; + container.appendChild(renderer.domElement); + + // + + scene = new THREE.Scene(); + + camera = makePerspectiveCamera(); + camera.position.set(0, 0, perspectiveDistance); + + const material = new THREE.MeshStandardMaterial(); + + new OBJLoader().setPath('models/obj/cerberus/').load('Cerberus.obj', function (group) { + const textureLoader = new THREE.TextureLoader().setPath('models/obj/cerberus/'); + + material.roughness = 1; + material.metalness = 1; + + const diffuseMap = textureLoader.load('Cerberus_A.jpg', render); + diffuseMap.colorSpace = THREE.SRGBColorSpace; + material.map = diffuseMap; + + material.metalnessMap = material.roughnessMap = textureLoader.load('Cerberus_RM.jpg', render); + material.normalMap = textureLoader.load('Cerberus_N.jpg', render); + + material.map.wrapS = THREE.RepeatWrapping; + material.roughnessMap.wrapS = THREE.RepeatWrapping; + material.metalnessMap.wrapS = THREE.RepeatWrapping; + material.normalMap.wrapS = THREE.RepeatWrapping; + + group.traverse(function (child) { + if (child.isMesh) { + child.material = material; + } + }); + + group.rotation.y = Math.PI / 2; + group.position.x += 0.25; + scene.add(group); + render(); + + new RGBELoader().setPath('textures/equirectangular/').load('venice_sunset_1k.hdr', function (hdrEquirect) { + hdrEquirect.mapping = THREE.EquirectangularReflectionMapping; + + scene.environment = hdrEquirect; + + render(); + }); + + window.addEventListener('keydown', onKeyDown); + window.addEventListener('resize', onWindowResize); + + // + + gui = new GUI(); + gui.add(cameraType, 'type', cameras) + .name('Choose Camera') + .onChange(function () { + setCamera(cameraType.type); + }); + + folderOptions = gui.addFolder('Arcball parameters'); + folderAnimations = folderOptions.addFolder('Animations'); + + arcballGui.setArcballControls(); + + render(); + }); +} + +function makeOrthographicCamera() { + const halfFovV = THREE.MathUtils.DEG2RAD * 45 * 0.5; + const halfFovH = Math.atan((window.innerWidth / window.innerHeight) * Math.tan(halfFovV)); + + const halfW = perspectiveDistance * Math.tan(halfFovH); + const halfH = perspectiveDistance * Math.tan(halfFovV); + const near = 0.01; + const far = 2000; + const newCamera = new THREE.OrthographicCamera(-halfW, halfW, halfH, -halfH, near, far); + return newCamera; +} + +function makePerspectiveCamera() { + const fov = 45; + const aspect = window.innerWidth / window.innerHeight; + const near = 0.01; + const far = 2000; + const newCamera = new THREE.PerspectiveCamera(fov, aspect, near, far); + return newCamera; +} + +function onWindowResize() { + if (camera.type == 'OrthographicCamera') { + const halfFovV = THREE.MathUtils.DEG2RAD * 45 * 0.5; + const halfFovH = Math.atan((window.innerWidth / window.innerHeight) * Math.tan(halfFovV)); + + const halfW = perspectiveDistance * Math.tan(halfFovH); + const halfH = perspectiveDistance * Math.tan(halfFovV); + camera.left = -halfW; + camera.right = halfW; + camera.top = halfH; + camera.bottom = -halfH; + } else if (camera.type == 'PerspectiveCamera') { + camera.aspect = window.innerWidth / window.innerHeight; + } + + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + render(); +} + +function render() { + renderer.render(scene, camera); +} + +function onKeyDown(event) { + if (event.key === 'c') { + if (event.ctrlKey || event.metaKey) { + controls.copyState(); + } + } else if (event.key === 'v') { + if (event.ctrlKey || event.metaKey) { + controls.pasteState(); + } + } +} + +function setCamera(type) { + if (type == 'Orthographic') { + camera = makeOrthographicCamera(); + camera.position.set(0, 0, orthographicDistance); + } else if (type == 'Perspective') { + camera = makePerspectiveCamera(); + camera.position.set(0, 0, perspectiveDistance); + } + + controls.setCamera(camera); + + render(); +} diff --git a/examples-testing/examples/misc_controls_drag.ts b/examples-testing/examples/misc_controls_drag.ts new file mode 100644 index 000000000..5036ab700 --- /dev/null +++ b/examples-testing/examples/misc_controls_drag.ts @@ -0,0 +1,148 @@ +import * as THREE from 'three'; + +import { DragControls } from 'three/addons/controls/DragControls.js'; + +let container; +let camera, scene, renderer; +let controls, group; +let enableSelection = false; + +const objects = []; + +const mouse = new THREE.Vector2(), + raycaster = new THREE.Raycaster(); + +init(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 500); + camera.position.z = 25; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xf0f0f0); + + scene.add(new THREE.AmbientLight(0xaaaaaa)); + + const light = new THREE.SpotLight(0xffffff, 10000); + light.position.set(0, 25, 50); + light.angle = Math.PI / 9; + + light.castShadow = true; + light.shadow.camera.near = 10; + light.shadow.camera.far = 100; + light.shadow.mapSize.width = 1024; + light.shadow.mapSize.height = 1024; + + scene.add(light); + + group = new THREE.Group(); + scene.add(group); + + const geometry = new THREE.BoxGeometry(); + + for (let i = 0; i < 200; i++) { + const object = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff })); + + object.position.x = Math.random() * 30 - 15; + object.position.y = Math.random() * 15 - 7.5; + object.position.z = Math.random() * 20 - 10; + + object.rotation.x = Math.random() * 2 * Math.PI; + object.rotation.y = Math.random() * 2 * Math.PI; + object.rotation.z = Math.random() * 2 * Math.PI; + + object.scale.x = Math.random() * 2 + 1; + object.scale.y = Math.random() * 2 + 1; + object.scale.z = Math.random() * 2 + 1; + + object.castShadow = true; + object.receiveShadow = true; + + scene.add(object); + + objects.push(object); + } + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + renderer.shadowMap.type = THREE.PCFShadowMap; + + container.appendChild(renderer.domElement); + + controls = new DragControls([...objects], camera, renderer.domElement); + controls.addEventListener('drag', render); + + // + + window.addEventListener('resize', onWindowResize); + + document.addEventListener('click', onClick); + window.addEventListener('keydown', onKeyDown); + window.addEventListener('keyup', onKeyUp); + + render(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + render(); +} + +function onKeyDown(event) { + enableSelection = event.keyCode === 16 ? true : false; +} + +function onKeyUp() { + enableSelection = false; +} + +function onClick(event) { + event.preventDefault(); + + if (enableSelection === true) { + const draggableObjects = controls.getObjects(); + draggableObjects.length = 0; + + mouse.x = (event.clientX / window.innerWidth) * 2 - 1; + mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; + + raycaster.setFromCamera(mouse, camera); + + const intersections = raycaster.intersectObjects(objects, true); + + if (intersections.length > 0) { + const object = intersections[0].object; + + if (group.children.includes(object) === true) { + object.material.emissive.set(0x000000); + scene.attach(object); + } else { + object.material.emissive.set(0xaaaaaa); + group.attach(object); + } + + controls.transformGroup = true; + draggableObjects.push(group); + } + + if (group.children.length === 0) { + controls.transformGroup = false; + draggableObjects.push(...objects); + } + } + + render(); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/misc_controls_fly.ts b/examples-testing/examples/misc_controls_fly.ts new file mode 100644 index 000000000..694942d2b --- /dev/null +++ b/examples-testing/examples/misc_controls_fly.ts @@ -0,0 +1,227 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import { FlyControls } from 'three/addons/controls/FlyControls.js'; +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { FilmPass } from 'three/addons/postprocessing/FilmPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; + +const radius = 6371; +const tilt = 0.41; +const rotationSpeed = 0.02; + +const cloudsScale = 1.005; +const moonScale = 0.23; + +const MARGIN = 0; +let SCREEN_HEIGHT = window.innerHeight - MARGIN * 2; +let SCREEN_WIDTH = window.innerWidth; + +let camera, controls, scene, renderer, stats; +let geometry, meshPlanet, meshClouds, meshMoon; +let dirLight; + +let composer; + +const textureLoader = new THREE.TextureLoader(); + +let d, dPlanet, dMoon; +const dMoonVec = new THREE.Vector3(); + +const clock = new THREE.Clock(); + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(25, SCREEN_WIDTH / SCREEN_HEIGHT, 50, 1e7); + camera.position.z = radius * 5; + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2(0x000000, 0.00000025); + + dirLight = new THREE.DirectionalLight(0xffffff, 3); + dirLight.position.set(-1, 0, 1).normalize(); + scene.add(dirLight); + + const materialNormalMap = new THREE.MeshPhongMaterial({ + specular: 0x7c7c7c, + shininess: 15, + map: textureLoader.load('textures/planets/earth_atmos_2048.jpg'), + specularMap: textureLoader.load('textures/planets/earth_specular_2048.jpg'), + normalMap: textureLoader.load('textures/planets/earth_normal_2048.jpg'), + + // y scale is negated to compensate for normal map handedness. + normalScale: new THREE.Vector2(0.85, -0.85), + }); + materialNormalMap.map.colorSpace = THREE.SRGBColorSpace; + + // planet + + geometry = new THREE.SphereGeometry(radius, 100, 50); + + meshPlanet = new THREE.Mesh(geometry, materialNormalMap); + meshPlanet.rotation.y = 0; + meshPlanet.rotation.z = tilt; + scene.add(meshPlanet); + + // clouds + + const materialClouds = new THREE.MeshLambertMaterial({ + map: textureLoader.load('textures/planets/earth_clouds_1024.png'), + transparent: true, + }); + materialClouds.map.colorSpace = THREE.SRGBColorSpace; + + meshClouds = new THREE.Mesh(geometry, materialClouds); + meshClouds.scale.set(cloudsScale, cloudsScale, cloudsScale); + meshClouds.rotation.z = tilt; + scene.add(meshClouds); + + // moon + + const materialMoon = new THREE.MeshPhongMaterial({ + map: textureLoader.load('textures/planets/moon_1024.jpg'), + }); + materialMoon.map.colorSpace = THREE.SRGBColorSpace; + + meshMoon = new THREE.Mesh(geometry, materialMoon); + meshMoon.position.set(radius * 5, 0, 0); + meshMoon.scale.set(moonScale, moonScale, moonScale); + scene.add(meshMoon); + + // stars + + const r = radius, + starsGeometry = [new THREE.BufferGeometry(), new THREE.BufferGeometry()]; + + const vertices1 = []; + const vertices2 = []; + + const vertex = new THREE.Vector3(); + + for (let i = 0; i < 250; i++) { + vertex.x = Math.random() * 2 - 1; + vertex.y = Math.random() * 2 - 1; + vertex.z = Math.random() * 2 - 1; + vertex.multiplyScalar(r); + + vertices1.push(vertex.x, vertex.y, vertex.z); + } + + for (let i = 0; i < 1500; i++) { + vertex.x = Math.random() * 2 - 1; + vertex.y = Math.random() * 2 - 1; + vertex.z = Math.random() * 2 - 1; + vertex.multiplyScalar(r); + + vertices2.push(vertex.x, vertex.y, vertex.z); + } + + starsGeometry[0].setAttribute('position', new THREE.Float32BufferAttribute(vertices1, 3)); + starsGeometry[1].setAttribute('position', new THREE.Float32BufferAttribute(vertices2, 3)); + + const starsMaterials = [ + new THREE.PointsMaterial({ color: 0x9c9c9c, size: 2, sizeAttenuation: false }), + new THREE.PointsMaterial({ color: 0x9c9c9c, size: 1, sizeAttenuation: false }), + new THREE.PointsMaterial({ color: 0x7c7c7c, size: 2, sizeAttenuation: false }), + new THREE.PointsMaterial({ color: 0x838383, size: 1, sizeAttenuation: false }), + new THREE.PointsMaterial({ color: 0x5a5a5a, size: 2, sizeAttenuation: false }), + new THREE.PointsMaterial({ color: 0x5a5a5a, size: 1, sizeAttenuation: false }), + ]; + + for (let i = 10; i < 30; i++) { + const stars = new THREE.Points(starsGeometry[i % 2], starsMaterials[i % 6]); + + stars.rotation.x = Math.random() * 6; + stars.rotation.y = Math.random() * 6; + stars.rotation.z = Math.random() * 6; + stars.scale.setScalar(i * 10); + + stars.matrixAutoUpdate = false; + stars.updateMatrix(); + + scene.add(stars); + } + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); + document.body.appendChild(renderer.domElement); + + // + + controls = new FlyControls(camera, renderer.domElement); + + controls.movementSpeed = 1000; + controls.domElement = renderer.domElement; + controls.rollSpeed = Math.PI / 24; + controls.autoForward = false; + controls.dragToLook = false; + + // + + stats = new Stats(); + document.body.appendChild(stats.dom); + + window.addEventListener('resize', onWindowResize); + + // postprocessing + + const renderModel = new RenderPass(scene, camera); + const effectFilm = new FilmPass(0.35, 0.75, 2048, false); + const outputPass = new OutputPass(); + + composer = new EffectComposer(renderer); + + composer.addPass(renderModel); + composer.addPass(effectFilm); + composer.addPass(outputPass); +} + +function onWindowResize() { + SCREEN_HEIGHT = window.innerHeight; + SCREEN_WIDTH = window.innerWidth; + + camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT; + camera.updateProjectionMatrix(); + + renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); + composer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + // rotate the planet and clouds + + const delta = clock.getDelta(); + + meshPlanet.rotation.y += rotationSpeed * delta; + meshClouds.rotation.y += 1.25 * rotationSpeed * delta; + + // slow down as we approach the surface + + dPlanet = camera.position.length(); + + dMoonVec.subVectors(camera.position, meshMoon.position); + dMoon = dMoonVec.length(); + + if (dMoon < dPlanet) { + d = dMoon - radius * moonScale * 1.01; + } else { + d = dPlanet - radius * 1.01; + } + + controls.movementSpeed = 0.33 * d; + controls.update(delta); + + composer.render(delta); +} diff --git a/examples-testing/examples/misc_controls_map.ts b/examples-testing/examples/misc_controls_map.ts new file mode 100644 index 000000000..d0d62795f --- /dev/null +++ b/examples-testing/examples/misc_controls_map.ts @@ -0,0 +1,100 @@ +import * as THREE from 'three'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { MapControls } from 'three/addons/controls/MapControls.js'; + +let camera, controls, scene, renderer; + +init(); +//render(); // remove when using next line for animation loop (requestAnimationFrame) +animate(); + +function init() { + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xcccccc); + scene.fog = new THREE.FogExp2(0xcccccc, 0.002); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.set(0, 200, -400); + + // controls + + controls = new MapControls(camera, renderer.domElement); + + //controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop) + + controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled + controls.dampingFactor = 0.05; + + controls.screenSpacePanning = false; + + controls.minDistance = 100; + controls.maxDistance = 500; + + controls.maxPolarAngle = Math.PI / 2; + + // world + + const geometry = new THREE.BoxGeometry(); + geometry.translate(0, 0.5, 0); + const material = new THREE.MeshPhongMaterial({ color: 0xeeeeee, flatShading: true }); + + for (let i = 0; i < 500; i++) { + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = Math.random() * 1600 - 800; + mesh.position.y = 0; + mesh.position.z = Math.random() * 1600 - 800; + mesh.scale.x = 20; + mesh.scale.y = Math.random() * 80 + 10; + mesh.scale.z = 20; + mesh.updateMatrix(); + mesh.matrixAutoUpdate = false; + scene.add(mesh); + } + + // lights + + const dirLight1 = new THREE.DirectionalLight(0xffffff, 3); + dirLight1.position.set(1, 1, 1); + scene.add(dirLight1); + + const dirLight2 = new THREE.DirectionalLight(0x002288, 3); + dirLight2.position.set(-1, -1, -1); + scene.add(dirLight2); + + const ambientLight = new THREE.AmbientLight(0x555555); + scene.add(ambientLight); + + // + + window.addEventListener('resize', onWindowResize); + + const gui = new GUI(); + gui.add(controls, 'zoomToCursor'); + gui.add(controls, 'screenSpacePanning'); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + controls.update(); // only required if controls.enableDamping = true, or if controls.autoRotate = true + + render(); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/misc_controls_orbit.ts b/examples-testing/examples/misc_controls_orbit.ts new file mode 100644 index 000000000..fc2938333 --- /dev/null +++ b/examples-testing/examples/misc_controls_orbit.ts @@ -0,0 +1,91 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +let camera, controls, scene, renderer; + +init(); +//render(); // remove when using next line for animation loop (requestAnimationFrame) +animate(); + +function init() { + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xcccccc); + scene.fog = new THREE.FogExp2(0xcccccc, 0.002); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.set(400, 200, 0); + + // controls + + controls = new OrbitControls(camera, renderer.domElement); + controls.listenToKeyEvents(window); // optional + + //controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop) + + controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled + controls.dampingFactor = 0.05; + + controls.screenSpacePanning = false; + + controls.minDistance = 100; + controls.maxDistance = 500; + + controls.maxPolarAngle = Math.PI / 2; + + // world + + const geometry = new THREE.ConeGeometry(10, 30, 4, 1); + const material = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); + + for (let i = 0; i < 500; i++) { + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = Math.random() * 1600 - 800; + mesh.position.y = 0; + mesh.position.z = Math.random() * 1600 - 800; + mesh.updateMatrix(); + mesh.matrixAutoUpdate = false; + scene.add(mesh); + } + + // lights + + const dirLight1 = new THREE.DirectionalLight(0xffffff, 3); + dirLight1.position.set(1, 1, 1); + scene.add(dirLight1); + + const dirLight2 = new THREE.DirectionalLight(0x002288, 3); + dirLight2.position.set(-1, -1, -1); + scene.add(dirLight2); + + const ambientLight = new THREE.AmbientLight(0x555555); + scene.add(ambientLight); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + controls.update(); // only required if controls.enableDamping = true, or if controls.autoRotate = true + + render(); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/misc_controls_pointerlock.ts b/examples-testing/examples/misc_controls_pointerlock.ts new file mode 100644 index 000000000..72ea08f30 --- /dev/null +++ b/examples-testing/examples/misc_controls_pointerlock.ts @@ -0,0 +1,247 @@ +import * as THREE from 'three'; + +import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js'; + +let camera, scene, renderer, controls; + +const objects = []; + +let raycaster; + +let moveForward = false; +let moveBackward = false; +let moveLeft = false; +let moveRight = false; +let canJump = false; + +let prevTime = performance.now(); +const velocity = new THREE.Vector3(); +const direction = new THREE.Vector3(); +const vertex = new THREE.Vector3(); +const color = new THREE.Color(); + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.y = 10; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xffffff); + scene.fog = new THREE.Fog(0xffffff, 0, 750); + + const light = new THREE.HemisphereLight(0xeeeeff, 0x777788, 2.5); + light.position.set(0.5, 1, 0.75); + scene.add(light); + + controls = new PointerLockControls(camera, document.body); + + const blocker = document.getElementById('blocker'); + const instructions = document.getElementById('instructions'); + + instructions.addEventListener('click', function () { + controls.lock(); + }); + + controls.addEventListener('lock', function () { + instructions.style.display = 'none'; + blocker.style.display = 'none'; + }); + + controls.addEventListener('unlock', function () { + blocker.style.display = 'block'; + instructions.style.display = ''; + }); + + scene.add(controls.getObject()); + + const onKeyDown = function (event) { + switch (event.code) { + case 'ArrowUp': + case 'KeyW': + moveForward = true; + break; + + case 'ArrowLeft': + case 'KeyA': + moveLeft = true; + break; + + case 'ArrowDown': + case 'KeyS': + moveBackward = true; + break; + + case 'ArrowRight': + case 'KeyD': + moveRight = true; + break; + + case 'Space': + if (canJump === true) velocity.y += 350; + canJump = false; + break; + } + }; + + const onKeyUp = function (event) { + switch (event.code) { + case 'ArrowUp': + case 'KeyW': + moveForward = false; + break; + + case 'ArrowLeft': + case 'KeyA': + moveLeft = false; + break; + + case 'ArrowDown': + case 'KeyS': + moveBackward = false; + break; + + case 'ArrowRight': + case 'KeyD': + moveRight = false; + break; + } + }; + + document.addEventListener('keydown', onKeyDown); + document.addEventListener('keyup', onKeyUp); + + raycaster = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3(0, -1, 0), 0, 10); + + // floor + + let floorGeometry = new THREE.PlaneGeometry(2000, 2000, 100, 100); + floorGeometry.rotateX(-Math.PI / 2); + + // vertex displacement + + let position = floorGeometry.attributes.position; + + for (let i = 0, l = position.count; i < l; i++) { + vertex.fromBufferAttribute(position, i); + + vertex.x += Math.random() * 20 - 10; + vertex.y += Math.random() * 2; + vertex.z += Math.random() * 20 - 10; + + position.setXYZ(i, vertex.x, vertex.y, vertex.z); + } + + floorGeometry = floorGeometry.toNonIndexed(); // ensure each face has unique vertices + + position = floorGeometry.attributes.position; + const colorsFloor = []; + + for (let i = 0, l = position.count; i < l; i++) { + color.setHSL(Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace); + colorsFloor.push(color.r, color.g, color.b); + } + + floorGeometry.setAttribute('color', new THREE.Float32BufferAttribute(colorsFloor, 3)); + + const floorMaterial = new THREE.MeshBasicMaterial({ vertexColors: true }); + + const floor = new THREE.Mesh(floorGeometry, floorMaterial); + scene.add(floor); + + // objects + + const boxGeometry = new THREE.BoxGeometry(20, 20, 20).toNonIndexed(); + + position = boxGeometry.attributes.position; + const colorsBox = []; + + for (let i = 0, l = position.count; i < l; i++) { + color.setHSL(Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace); + colorsBox.push(color.r, color.g, color.b); + } + + boxGeometry.setAttribute('color', new THREE.Float32BufferAttribute(colorsBox, 3)); + + for (let i = 0; i < 500; i++) { + const boxMaterial = new THREE.MeshPhongMaterial({ specular: 0xffffff, flatShading: true, vertexColors: true }); + boxMaterial.color.setHSL(Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace); + + const box = new THREE.Mesh(boxGeometry, boxMaterial); + box.position.x = Math.floor(Math.random() * 20 - 10) * 20; + box.position.y = Math.floor(Math.random() * 20) * 20 + 10; + box.position.z = Math.floor(Math.random() * 20 - 10) * 20; + + scene.add(box); + objects.push(box); + } + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + const time = performance.now(); + + if (controls.isLocked === true) { + raycaster.ray.origin.copy(controls.getObject().position); + raycaster.ray.origin.y -= 10; + + const intersections = raycaster.intersectObjects(objects, false); + + const onObject = intersections.length > 0; + + const delta = (time - prevTime) / 1000; + + velocity.x -= velocity.x * 10.0 * delta; + velocity.z -= velocity.z * 10.0 * delta; + + velocity.y -= 9.8 * 100.0 * delta; // 100.0 = mass + + direction.z = Number(moveForward) - Number(moveBackward); + direction.x = Number(moveRight) - Number(moveLeft); + direction.normalize(); // this ensures consistent movements in all directions + + if (moveForward || moveBackward) velocity.z -= direction.z * 400.0 * delta; + if (moveLeft || moveRight) velocity.x -= direction.x * 400.0 * delta; + + if (onObject === true) { + velocity.y = Math.max(0, velocity.y); + canJump = true; + } + + controls.moveRight(-velocity.x * delta); + controls.moveForward(-velocity.z * delta); + + controls.getObject().position.y += velocity.y * delta; // new behavior + + if (controls.getObject().position.y < 10) { + velocity.y = 0; + controls.getObject().position.y = 10; + + canJump = true; + } + } + + prevTime = time; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/misc_controls_trackball.ts b/examples-testing/examples/misc_controls_trackball.ts new file mode 100644 index 000000000..88d0541a6 --- /dev/null +++ b/examples-testing/examples/misc_controls_trackball.ts @@ -0,0 +1,136 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; + +let perspectiveCamera, orthographicCamera, controls, scene, renderer, stats; + +const params = { + orthographicCamera: false, +}; + +const frustumSize = 400; + +init(); +animate(); + +function init() { + const aspect = window.innerWidth / window.innerHeight; + + perspectiveCamera = new THREE.PerspectiveCamera(60, aspect, 1, 1000); + perspectiveCamera.position.z = 500; + + orthographicCamera = new THREE.OrthographicCamera( + (frustumSize * aspect) / -2, + (frustumSize * aspect) / 2, + frustumSize / 2, + frustumSize / -2, + 1, + 1000, + ); + orthographicCamera.position.z = 500; + + // world + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xcccccc); + scene.fog = new THREE.FogExp2(0xcccccc, 0.002); + + const geometry = new THREE.ConeGeometry(10, 30, 4, 1); + const material = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); + + for (let i = 0; i < 500; i++) { + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = (Math.random() - 0.5) * 1000; + mesh.position.y = (Math.random() - 0.5) * 1000; + mesh.position.z = (Math.random() - 0.5) * 1000; + mesh.updateMatrix(); + mesh.matrixAutoUpdate = false; + scene.add(mesh); + } + + // lights + + const dirLight1 = new THREE.DirectionalLight(0xffffff, 3); + dirLight1.position.set(1, 1, 1); + scene.add(dirLight1); + + const dirLight2 = new THREE.DirectionalLight(0x002288, 3); + dirLight2.position.set(-1, -1, -1); + scene.add(dirLight2); + + const ambientLight = new THREE.AmbientLight(0x555555); + scene.add(ambientLight); + + // renderer + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + stats = new Stats(); + document.body.appendChild(stats.dom); + + // + + const gui = new GUI(); + gui.add(params, 'orthographicCamera') + .name('use orthographic') + .onChange(function (value) { + controls.dispose(); + + createControls(value ? orthographicCamera : perspectiveCamera); + }); + + // + + window.addEventListener('resize', onWindowResize); + + createControls(perspectiveCamera); +} + +function createControls(camera) { + controls = new TrackballControls(camera, renderer.domElement); + + controls.rotateSpeed = 1.0; + controls.zoomSpeed = 1.2; + controls.panSpeed = 0.8; + + controls.keys = ['KeyA', 'KeyS', 'KeyD']; +} + +function onWindowResize() { + const aspect = window.innerWidth / window.innerHeight; + + perspectiveCamera.aspect = aspect; + perspectiveCamera.updateProjectionMatrix(); + + orthographicCamera.left = (-frustumSize * aspect) / 2; + orthographicCamera.right = (frustumSize * aspect) / 2; + orthographicCamera.top = frustumSize / 2; + orthographicCamera.bottom = -frustumSize / 2; + orthographicCamera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + controls.handleResize(); +} + +function animate() { + requestAnimationFrame(animate); + + controls.update(); + + stats.update(); + + render(); +} + +function render() { + const camera = params.orthographicCamera ? orthographicCamera : perspectiveCamera; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/misc_controls_transform.ts b/examples-testing/examples/misc_controls_transform.ts new file mode 100644 index 000000000..abc4657ac --- /dev/null +++ b/examples-testing/examples/misc_controls_transform.ts @@ -0,0 +1,172 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { TransformControls } from 'three/addons/controls/TransformControls.js'; + +let cameraPersp, cameraOrtho, currentCamera; +let scene, renderer, control, orbit; + +init(); +render(); + +function init() { + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + const aspect = window.innerWidth / window.innerHeight; + + cameraPersp = new THREE.PerspectiveCamera(50, aspect, 0.01, 30000); + cameraOrtho = new THREE.OrthographicCamera(-600 * aspect, 600 * aspect, 600, -600, 0.01, 30000); + currentCamera = cameraPersp; + + currentCamera.position.set(5, 2.5, 5); + + scene = new THREE.Scene(); + scene.add(new THREE.GridHelper(5, 10, 0x888888, 0x444444)); + + const ambientLight = new THREE.AmbientLight(0xffffff); + scene.add(ambientLight); + + const light = new THREE.DirectionalLight(0xffffff, 4); + light.position.set(1, 1, 1); + scene.add(light); + + const texture = new THREE.TextureLoader().load('textures/crate.gif', render); + texture.colorSpace = THREE.SRGBColorSpace; + texture.anisotropy = renderer.capabilities.getMaxAnisotropy(); + + const geometry = new THREE.BoxGeometry(); + const material = new THREE.MeshLambertMaterial({ map: texture }); + + orbit = new OrbitControls(currentCamera, renderer.domElement); + orbit.update(); + orbit.addEventListener('change', render); + + control = new TransformControls(currentCamera, renderer.domElement); + control.addEventListener('change', render); + + control.addEventListener('dragging-changed', function (event) { + orbit.enabled = !event.value; + }); + + const mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + control.attach(mesh); + scene.add(control); + + window.addEventListener('resize', onWindowResize); + + window.addEventListener('keydown', function (event) { + switch (event.keyCode) { + case 81: // Q + control.setSpace(control.space === 'local' ? 'world' : 'local'); + break; + + case 16: // Shift + control.setTranslationSnap(100); + control.setRotationSnap(THREE.MathUtils.degToRad(15)); + control.setScaleSnap(0.25); + break; + + case 87: // W + control.setMode('translate'); + break; + + case 69: // E + control.setMode('rotate'); + break; + + case 82: // R + control.setMode('scale'); + break; + + case 67: // C + const position = currentCamera.position.clone(); + + currentCamera = currentCamera.isPerspectiveCamera ? cameraOrtho : cameraPersp; + currentCamera.position.copy(position); + + orbit.object = currentCamera; + control.camera = currentCamera; + + currentCamera.lookAt(orbit.target.x, orbit.target.y, orbit.target.z); + onWindowResize(); + break; + + case 86: // V + const randomFoV = Math.random() + 0.1; + const randomZoom = Math.random() + 0.1; + + cameraPersp.fov = randomFoV * 160; + cameraOrtho.bottom = -randomFoV * 500; + cameraOrtho.top = randomFoV * 500; + + cameraPersp.zoom = randomZoom * 5; + cameraOrtho.zoom = randomZoom * 5; + onWindowResize(); + break; + + case 187: + case 107: // +, =, num+ + control.setSize(control.size + 0.1); + break; + + case 189: + case 109: // -, _, num- + control.setSize(Math.max(control.size - 0.1, 0.1)); + break; + + case 88: // X + control.showX = !control.showX; + break; + + case 89: // Y + control.showY = !control.showY; + break; + + case 90: // Z + control.showZ = !control.showZ; + break; + + case 32: // Spacebar + control.enabled = !control.enabled; + break; + + case 27: // Esc + control.reset(); + break; + } + }); + + window.addEventListener('keyup', function (event) { + switch (event.keyCode) { + case 16: // Shift + control.setTranslationSnap(null); + control.setRotationSnap(null); + control.setScaleSnap(null); + break; + } + }); +} + +function onWindowResize() { + const aspect = window.innerWidth / window.innerHeight; + + cameraPersp.aspect = aspect; + cameraPersp.updateProjectionMatrix(); + + cameraOrtho.left = cameraOrtho.bottom * aspect; + cameraOrtho.right = cameraOrtho.top * aspect; + cameraOrtho.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + render(); +} + +function render() { + renderer.render(scene, currentCamera); +} diff --git a/examples-testing/examples/misc_exporter_draco.ts b/examples-testing/examples/misc_exporter_draco.ts new file mode 100644 index 000000000..d6a45353f --- /dev/null +++ b/examples-testing/examples/misc_exporter_draco.ts @@ -0,0 +1,118 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { DRACOExporter } from 'three/addons/exporters/DRACOExporter.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let scene, camera, renderer, exporter, mesh; + +const params = { + export: exportFile, +}; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(4, 2, 4); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xa0a0a0); + scene.fog = new THREE.Fog(0xa0a0a0, 4, 20); + + exporter = new DRACOExporter(); + + // + + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 3); + hemiLight.position.set(0, 20, 0); + scene.add(hemiLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff, 3); + directionalLight.position.set(0, 20, 10); + directionalLight.castShadow = true; + directionalLight.shadow.camera.top = 2; + directionalLight.shadow.camera.bottom = -2; + directionalLight.shadow.camera.left = -2; + directionalLight.shadow.camera.right = 2; + scene.add(directionalLight); + + // ground + + const ground = new THREE.Mesh( + new THREE.PlaneGeometry(40, 40), + new THREE.MeshPhongMaterial({ color: 0xbbbbbb, depthWrite: false }), + ); + ground.rotation.x = -Math.PI / 2; + ground.receiveShadow = true; + scene.add(ground); + + const grid = new THREE.GridHelper(40, 20, 0x000000, 0x000000); + grid.material.opacity = 0.2; + grid.material.transparent = true; + scene.add(grid); + + // export mesh + + const geometry = new THREE.TorusKnotGeometry(0.75, 0.2, 200, 30); + const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 }); + mesh = new THREE.Mesh(geometry, material); + mesh.castShadow = true; + mesh.position.y = 1.5; + scene.add(mesh); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + document.body.appendChild(renderer.domElement); + + // + + const controls = new OrbitControls(camera, renderer.domElement); + controls.target.set(0, 1.5, 0); + controls.update(); + + // + + window.addEventListener('resize', onWindowResize); + + const gui = new GUI(); + + gui.add(params, 'export').name('Export DRC'); + gui.open(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + renderer.render(scene, camera); +} + +function exportFile() { + const result = exporter.parse(mesh); + saveArrayBuffer(result, 'file.drc'); +} + +const link = document.createElement('a'); +link.style.display = 'none'; +document.body.appendChild(link); + +function save(blob, filename) { + link.href = URL.createObjectURL(blob); + link.download = filename; + link.click(); +} + +function saveArrayBuffer(buffer, filename) { + save(new Blob([buffer], { type: 'application/octet-stream' }), filename); +} diff --git a/examples-testing/examples/misc_exporter_gltf.ts b/examples-testing/examples/misc_exporter_gltf.ts new file mode 100644 index 000000000..47c871235 --- /dev/null +++ b/examples-testing/examples/misc_exporter_gltf.ts @@ -0,0 +1,493 @@ +import * as THREE from 'three'; + +import { GLTFExporter } from 'three/addons/exporters/GLTFExporter.js'; +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; +import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'; +import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +function exportGLTF(input) { + const gltfExporter = new GLTFExporter(); + + const options = { + trs: params.trs, + onlyVisible: params.onlyVisible, + binary: params.binary, + maxTextureSize: params.maxTextureSize, + }; + gltfExporter.parse( + input, + function (result) { + if (result instanceof ArrayBuffer) { + saveArrayBuffer(result, 'scene.glb'); + } else { + const output = JSON.stringify(result, null, 2); + console.log(output); + saveString(output, 'scene.gltf'); + } + }, + function (error) { + console.log('An error happened during parsing', error); + }, + options, + ); +} + +const link = document.createElement('a'); +link.style.display = 'none'; +document.body.appendChild(link); // Firefox workaround, see #6594 + +function save(blob, filename) { + link.href = URL.createObjectURL(blob); + link.download = filename; + link.click(); + + // URL.revokeObjectURL( url ); breaks Firefox... +} + +function saveString(text, filename) { + save(new Blob([text], { type: 'text/plain' }), filename); +} + +function saveArrayBuffer(buffer, filename) { + save(new Blob([buffer], { type: 'application/octet-stream' }), filename); +} + +let container; + +let camera, object, object2, material, geometry, scene1, scene2, renderer; +let gridHelper, sphere, model, coffeemat; + +const params = { + trs: false, + onlyVisible: true, + binary: false, + maxTextureSize: 4096, + exportScene1: exportScene1, + exportScenes: exportScenes, + exportSphere: exportSphere, + exportModel: exportModel, + exportObjects: exportObjects, + exportSceneObject: exportSceneObject, + exportCompressedObject: exportCompressedObject, +}; + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + // Make linear gradient texture + + const data = new Uint8ClampedArray(100 * 100 * 4); + + for (let y = 0; y < 100; y++) { + for (let x = 0; x < 100; x++) { + const stride = 4 * (100 * y + x); + + data[stride] = Math.round((255 * y) / 99); + data[stride + 1] = Math.round(255 - (255 * y) / 99); + data[stride + 2] = 0; + data[stride + 3] = 255; + } + } + + const gradientTexture = new THREE.DataTexture(data, 100, 100, THREE.RGBAFormat); + gradientTexture.minFilter = THREE.LinearFilter; + gradientTexture.magFilter = THREE.LinearFilter; + gradientTexture.needsUpdate = true; + + scene1 = new THREE.Scene(); + scene1.name = 'Scene1'; + + // --------------------------------------------------------------------- + // Perspective Camera + // --------------------------------------------------------------------- + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000); + camera.position.set(600, 400, 0); + + camera.name = 'PerspectiveCamera'; + scene1.add(camera); + + // --------------------------------------------------------------------- + // Ambient light + // --------------------------------------------------------------------- + const ambientLight = new THREE.AmbientLight(0xcccccc); + ambientLight.name = 'AmbientLight'; + scene1.add(ambientLight); + + // --------------------------------------------------------------------- + // DirectLight + // --------------------------------------------------------------------- + const dirLight = new THREE.DirectionalLight(0xffffff, 3); + dirLight.target.position.set(0, 0, -1); + dirLight.add(dirLight.target); + dirLight.lookAt(-1, -1, 0); + dirLight.name = 'DirectionalLight'; + scene1.add(dirLight); + + // --------------------------------------------------------------------- + // Grid + // --------------------------------------------------------------------- + gridHelper = new THREE.GridHelper(2000, 20, 0xc1c1c1, 0x8d8d8d); + gridHelper.position.y = -50; + gridHelper.name = 'Grid'; + scene1.add(gridHelper); + + // --------------------------------------------------------------------- + // Axes + // --------------------------------------------------------------------- + const axes = new THREE.AxesHelper(500); + axes.name = 'AxesHelper'; + scene1.add(axes); + + // --------------------------------------------------------------------- + // Simple geometry with basic material + // --------------------------------------------------------------------- + // Icosahedron + const mapGrid = new THREE.TextureLoader().load('textures/uv_grid_opengl.jpg'); + mapGrid.wrapS = mapGrid.wrapT = THREE.RepeatWrapping; + mapGrid.colorSpace = THREE.SRGBColorSpace; + material = new THREE.MeshBasicMaterial({ + color: 0xffffff, + map: mapGrid, + }); + + object = new THREE.Mesh(new THREE.IcosahedronGeometry(75, 0), material); + object.position.set(-200, 0, 200); + object.name = 'Icosahedron'; + scene1.add(object); + + // Octahedron + material = new THREE.MeshBasicMaterial({ + color: 0x0000ff, + wireframe: true, + }); + object = new THREE.Mesh(new THREE.OctahedronGeometry(75, 1), material); + object.position.set(0, 0, 200); + object.name = 'Octahedron'; + scene1.add(object); + + // Tetrahedron + material = new THREE.MeshBasicMaterial({ + color: 0xff0000, + transparent: true, + opacity: 0.5, + }); + + object = new THREE.Mesh(new THREE.TetrahedronGeometry(75, 0), material); + object.position.set(200, 0, 200); + object.name = 'Tetrahedron'; + scene1.add(object); + + // --------------------------------------------------------------------- + // Buffered geometry primitives + // --------------------------------------------------------------------- + // Sphere + material = new THREE.MeshStandardMaterial({ + color: 0xffff00, + metalness: 0.5, + roughness: 1.0, + flatShading: true, + }); + material.map = gradientTexture; + sphere = new THREE.Mesh(new THREE.SphereGeometry(70, 10, 10), material); + sphere.position.set(0, 0, 0); + sphere.name = 'Sphere'; + scene1.add(sphere); + + // Cylinder + material = new THREE.MeshStandardMaterial({ + color: 0xff00ff, + flatShading: true, + }); + object = new THREE.Mesh(new THREE.CylinderGeometry(10, 80, 100), material); + object.position.set(200, 0, 0); + object.name = 'Cylinder'; + scene1.add(object); + + // TorusKnot + material = new THREE.MeshStandardMaterial({ + color: 0xff0000, + roughness: 1, + }); + object = new THREE.Mesh(new THREE.TorusKnotGeometry(50, 15, 40, 10), material); + object.position.set(-200, 0, 0); + object.name = 'Cylinder'; + scene1.add(object); + + // --------------------------------------------------------------------- + // Hierarchy + // --------------------------------------------------------------------- + const mapWood = new THREE.TextureLoader().load('textures/hardwood2_diffuse.jpg'); + material = new THREE.MeshStandardMaterial({ map: mapWood, side: THREE.DoubleSide }); + + object = new THREE.Mesh(new THREE.BoxGeometry(40, 100, 100), material); + object.position.set(-200, 0, 400); + object.name = 'Cube'; + scene1.add(object); + + object2 = new THREE.Mesh(new THREE.BoxGeometry(40, 40, 40, 2, 2, 2), material); + object2.position.set(0, 0, 50); + object2.rotation.set(0, 45, 0); + object2.name = 'SubCube'; + object.add(object2); + + // --------------------------------------------------------------------- + // Groups + // --------------------------------------------------------------------- + const group1 = new THREE.Group(); + group1.name = 'Group'; + scene1.add(group1); + + const group2 = new THREE.Group(); + group2.name = 'subGroup'; + group2.position.set(0, 50, 0); + group1.add(group2); + + object2 = new THREE.Mesh(new THREE.BoxGeometry(30, 30, 30), material); + object2.name = 'Cube in group'; + object2.position.set(0, 0, 400); + group2.add(object2); + + // --------------------------------------------------------------------- + // THREE.Line Strip + // --------------------------------------------------------------------- + geometry = new THREE.BufferGeometry(); + let numPoints = 100; + let positions = new Float32Array(numPoints * 3); + + for (let i = 0; i < numPoints; i++) { + positions[i * 3] = i; + positions[i * 3 + 1] = Math.sin(i / 2) * 20; + positions[i * 3 + 2] = 0; + } + + geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); + object = new THREE.Line(geometry, new THREE.LineBasicMaterial({ color: 0xffff00 })); + object.position.set(-50, 0, -200); + scene1.add(object); + + // --------------------------------------------------------------------- + // THREE.Line Loop + // --------------------------------------------------------------------- + geometry = new THREE.BufferGeometry(); + numPoints = 5; + const radius = 70; + positions = new Float32Array(numPoints * 3); + + for (let i = 0; i < numPoints; i++) { + const s = (i * Math.PI * 2) / numPoints; + positions[i * 3] = radius * Math.sin(s); + positions[i * 3 + 1] = radius * Math.cos(s); + positions[i * 3 + 2] = 0; + } + + geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); + object = new THREE.LineLoop(geometry, new THREE.LineBasicMaterial({ color: 0xffff00 })); + object.position.set(0, 0, -200); + + scene1.add(object); + + // --------------------------------------------------------------------- + // THREE.Points + // --------------------------------------------------------------------- + numPoints = 100; + const pointsArray = new Float32Array(numPoints * 3); + for (let i = 0; i < numPoints; i++) { + pointsArray[3 * i] = -50 + Math.random() * 100; + pointsArray[3 * i + 1] = Math.random() * 100; + pointsArray[3 * i + 2] = -50 + Math.random() * 100; + } + + const pointsGeo = new THREE.BufferGeometry(); + pointsGeo.setAttribute('position', new THREE.BufferAttribute(pointsArray, 3)); + + const pointsMaterial = new THREE.PointsMaterial({ color: 0xffff00, size: 5 }); + const pointCloud = new THREE.Points(pointsGeo, pointsMaterial); + pointCloud.name = 'Points'; + pointCloud.position.set(-200, 0, -200); + scene1.add(pointCloud); + + // --------------------------------------------------------------------- + // Ortho camera + // --------------------------------------------------------------------- + const cameraOrtho = new THREE.OrthographicCamera( + window.innerWidth / -2, + window.innerWidth / 2, + window.innerHeight / 2, + window.innerHeight / -2, + 0.1, + 10, + ); + scene1.add(cameraOrtho); + cameraOrtho.name = 'OrthographicCamera'; + + material = new THREE.MeshLambertMaterial({ + color: 0xffff00, + side: THREE.DoubleSide, + }); + + object = new THREE.Mesh(new THREE.CircleGeometry(50, 20, 0, Math.PI * 2), material); + object.position.set(200, 0, -400); + scene1.add(object); + + object = new THREE.Mesh(new THREE.RingGeometry(10, 50, 20, 5, 0, Math.PI * 2), material); + object.position.set(0, 0, -400); + scene1.add(object); + + object = new THREE.Mesh(new THREE.CylinderGeometry(25, 75, 100, 40, 5), material); + object.position.set(-200, 0, -400); + scene1.add(object); + + // + const points = []; + + for (let i = 0; i < 50; i++) { + points.push(new THREE.Vector2(Math.sin(i * 0.2) * Math.sin(i * 0.1) * 15 + 50, (i - 5) * 2)); + } + + object = new THREE.Mesh(new THREE.LatheGeometry(points, 20), material); + object.position.set(200, 0, 400); + scene1.add(object); + + // --------------------------------------------------------------------- + // Big red box hidden just for testing `onlyVisible` option + // --------------------------------------------------------------------- + material = new THREE.MeshBasicMaterial({ + color: 0xff0000, + }); + object = new THREE.Mesh(new THREE.BoxGeometry(200, 200, 200), material); + object.position.set(0, 0, 0); + object.name = 'CubeHidden'; + object.visible = false; + scene1.add(object); + + // --------------------------------------------------------------------- + // Model requiring KHR_mesh_quantization + // --------------------------------------------------------------------- + const loader = new GLTFLoader(); + loader.load('models/gltf/ShaderBall.glb', function (gltf) { + model = gltf.scene; + model.scale.setScalar(50); + model.position.set(200, -40, -200); + scene1.add(model); + }); + + // --------------------------------------------------------------------- + // 2nd THREE.Scene + // --------------------------------------------------------------------- + scene2 = new THREE.Scene(); + object = new THREE.Mesh(new THREE.BoxGeometry(100, 100, 100), material); + object.position.set(0, 0, 0); + object.name = 'Cube2ndScene'; + scene2.name = 'Scene2'; + scene2.add(object); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.toneMapping = THREE.ACESFilmicToneMapping; + renderer.toneMappingExposure = 1; + + container.appendChild(renderer.domElement); + + // + + window.addEventListener('resize', onWindowResize); + + // --------------------------------------------------------------------- + // Exporting compressed textures and meshes (KTX2 / Draco / Meshopt) + // --------------------------------------------------------------------- + const ktx2Loader = new KTX2Loader().setTranscoderPath('jsm/libs/basis/').detectSupport(renderer); + + const gltfLoader = new GLTFLoader().setPath('models/gltf/'); + gltfLoader.setKTX2Loader(ktx2Loader); + gltfLoader.setMeshoptDecoder(MeshoptDecoder); + gltfLoader.load('coffeemat.glb', function (gltf) { + gltf.scene.position.x = 400; + gltf.scene.position.z = -200; + + scene1.add(gltf.scene); + + coffeemat = gltf.scene; + }); + + // + + const gui = new GUI(); + + let h = gui.addFolder('Settings'); + h.add(params, 'trs').name('Use TRS'); + h.add(params, 'onlyVisible').name('Only Visible Objects'); + h.add(params, 'binary').name('Binary (GLB)'); + h.add(params, 'maxTextureSize', 2, 8192).name('Max Texture Size').step(1); + + h = gui.addFolder('Export'); + h.add(params, 'exportScene1').name('Export Scene 1'); + h.add(params, 'exportScenes').name('Export Scene 1 and 2'); + h.add(params, 'exportSphere').name('Export Sphere'); + h.add(params, 'exportModel').name('Export Model'); + h.add(params, 'exportObjects').name('Export Sphere With Grid'); + h.add(params, 'exportSceneObject').name('Export Scene 1 and Object'); + h.add(params, 'exportCompressedObject').name('Export Coffeemat (from compressed data)'); + + gui.open(); +} + +function exportScene1() { + exportGLTF(scene1); +} + +function exportScenes() { + exportGLTF([scene1, scene2]); +} + +function exportSphere() { + exportGLTF(sphere); +} + +function exportModel() { + exportGLTF(model); +} + +function exportObjects() { + exportGLTF([sphere, gridHelper]); +} + +function exportSceneObject() { + exportGLTF([scene1, gridHelper]); +} + +function exportCompressedObject() { + exportGLTF([coffeemat]); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); +} + +function render() { + const timer = Date.now() * 0.0001; + + camera.position.x = Math.cos(timer) * 800; + camera.position.z = Math.sin(timer) * 800; + + camera.lookAt(scene1.position); + renderer.render(scene1, camera); +} diff --git a/examples-testing/examples/misc_exporter_obj.ts b/examples-testing/examples/misc_exporter_obj.ts new file mode 100644 index 000000000..c315294f8 --- /dev/null +++ b/examples-testing/examples/misc_exporter_obj.ts @@ -0,0 +1,194 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { OBJExporter } from 'three/addons/exporters/OBJExporter.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let camera, scene, renderer; + +const params = { + addTriangle: addTriangle, + addCube: addCube, + addCylinder: addCylinder, + addMultiple: addMultiple, + addTransformed: addTransformed, + addPoints: addPoints, + exportToObj: exportToObj, +}; + +init(); +animate(); + +function init() { + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.set(0, 0, 400); + + scene = new THREE.Scene(); + + const ambientLight = new THREE.AmbientLight(0xffffff); + scene.add(ambientLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff, 2.5); + directionalLight.position.set(0, 1, 1); + scene.add(directionalLight); + + const gui = new GUI(); + + let h = gui.addFolder('Geometry Selection'); + h.add(params, 'addTriangle').name('Triangle'); + h.add(params, 'addCube').name('Cube'); + h.add(params, 'addCylinder').name('Cylinder'); + h.add(params, 'addMultiple').name('Multiple objects'); + h.add(params, 'addTransformed').name('Transformed objects'); + h.add(params, 'addPoints').name('Point Cloud'); + + h = gui.addFolder('Export'); + h.add(params, 'exportToObj').name('Export OBJ'); + + gui.open(); + + addGeometry(1); + + window.addEventListener('resize', onWindowResize); + + const controls = new OrbitControls(camera, renderer.domElement); + controls.enablePan = false; +} + +function exportToObj() { + const exporter = new OBJExporter(); + const result = exporter.parse(scene); + saveString(result, 'object.obj'); +} + +function addGeometry(type) { + for (let i = 0; i < scene.children.length; i++) { + const child = scene.children[i]; + + if (child.isMesh || child.isPoints) { + child.geometry.dispose(); + scene.remove(child); + i--; + } + } + + if (type === 1) { + const material = new THREE.MeshLambertMaterial({ color: 0x00cc00 }); + const geometry = generateTriangleGeometry(); + + scene.add(new THREE.Mesh(geometry, material)); + } else if (type === 2) { + const material = new THREE.MeshLambertMaterial({ color: 0x00cc00 }); + const geometry = new THREE.BoxGeometry(100, 100, 100); + scene.add(new THREE.Mesh(geometry, material)); + } else if (type === 3) { + const material = new THREE.MeshLambertMaterial({ color: 0x00cc00 }); + const geometry = new THREE.CylinderGeometry(50, 50, 100, 30, 1); + scene.add(new THREE.Mesh(geometry, material)); + } else if (type === 4 || type === 5) { + const material = new THREE.MeshLambertMaterial({ color: 0x00cc00 }); + const geometry = generateTriangleGeometry(); + + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = -200; + scene.add(mesh); + + const geometry2 = new THREE.BoxGeometry(100, 100, 100); + const mesh2 = new THREE.Mesh(geometry2, material); + scene.add(mesh2); + + const geometry3 = new THREE.CylinderGeometry(50, 50, 100, 30, 1); + const mesh3 = new THREE.Mesh(geometry3, material); + mesh3.position.x = 200; + scene.add(mesh3); + + if (type === 5) { + mesh.rotation.y = Math.PI / 4.0; + mesh2.rotation.y = Math.PI / 4.0; + mesh3.rotation.y = Math.PI / 4.0; + } + } else if (type === 6) { + const points = [0, 0, 0, 100, 0, 0, 100, 100, 0, 0, 100, 0]; + const colors = [0.5, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0.5, 0]; + + const geometry = new THREE.BufferGeometry(); + geometry.setAttribute('position', new THREE.Float32BufferAttribute(points, 3)); + geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); + + const material = new THREE.PointsMaterial({ size: 10, vertexColors: true }); + + const pointCloud = new THREE.Points(geometry, material); + pointCloud.name = 'point cloud'; + scene.add(pointCloud); + } +} + +function addTriangle() { + addGeometry(1); +} + +function addCube() { + addGeometry(2); +} + +function addCylinder() { + addGeometry(3); +} + +function addMultiple() { + addGeometry(4); +} + +function addTransformed() { + addGeometry(5); +} + +function addPoints() { + addGeometry(6); +} + +const link = document.createElement('a'); +link.style.display = 'none'; +document.body.appendChild(link); + +function save(blob, filename) { + link.href = URL.createObjectURL(blob); + link.download = filename; + link.click(); +} + +function saveString(text, filename) { + save(new Blob([text], { type: 'text/plain' }), filename); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + renderer.render(scene, camera); +} + +function generateTriangleGeometry() { + const geometry = new THREE.BufferGeometry(); + const vertices = []; + + vertices.push(-50, -50, 0); + vertices.push(50, -50, 0); + vertices.push(50, 50, 0); + + geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); + geometry.computeVertexNormals(); + + return geometry; +} diff --git a/examples-testing/examples/misc_exporter_ply.ts b/examples-testing/examples/misc_exporter_ply.ts new file mode 100644 index 000000000..997c4f1a0 --- /dev/null +++ b/examples-testing/examples/misc_exporter_ply.ts @@ -0,0 +1,157 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { PLYExporter } from 'three/addons/exporters/PLYExporter.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let scene, camera, renderer, exporter, mesh; + +const params = { + exportASCII: exportASCII, + exportBinaryBigEndian: exportBinaryBigEndian, + exportBinaryLittleEndian: exportBinaryLittleEndian, +}; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(4, 2, 4); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xa0a0a0); + scene.fog = new THREE.Fog(0xa0a0a0, 4, 20); + + exporter = new PLYExporter(); + + // + + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 3); + hemiLight.position.set(0, 20, 0); + scene.add(hemiLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff, 3); + directionalLight.position.set(0, 20, 10); + directionalLight.castShadow = true; + directionalLight.shadow.camera.top = 2; + directionalLight.shadow.camera.bottom = -2; + directionalLight.shadow.camera.left = -2; + directionalLight.shadow.camera.right = 2; + scene.add(directionalLight); + + // ground + + const ground = new THREE.Mesh( + new THREE.PlaneGeometry(40, 40), + new THREE.MeshPhongMaterial({ color: 0xcbcbcb, depthWrite: false }), + ); + ground.rotation.x = -Math.PI / 2; + ground.receiveShadow = true; + scene.add(ground); + + const grid = new THREE.GridHelper(40, 20, 0x000000, 0x000000); + grid.material.opacity = 0.2; + grid.material.transparent = true; + scene.add(grid); + + // export mesh + + const geometry = new THREE.BoxGeometry(); + const material = new THREE.MeshPhongMaterial({ vertexColors: true }); + + // color vertices based on vertex positions + const colors = geometry.getAttribute('position').array.slice(); + for (let i = 0, l = colors.length; i < l; i++) { + if (colors[i] > 0) colors[i] = 0.5; + else colors[i] = 0; + } + + geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3, false)); + + mesh = new THREE.Mesh(geometry, material); + mesh.castShadow = true; + mesh.position.y = 0.5; + scene.add(mesh); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + document.body.appendChild(renderer.domElement); + + // + + const controls = new OrbitControls(camera, renderer.domElement); + controls.target.set(0, 0.5, 0); + controls.update(); + + // + + window.addEventListener('resize', onWindowResize); + + const gui = new GUI(); + + gui.add(params, 'exportASCII').name('Export PLY (ASCII)'); + gui.add(params, 'exportBinaryBigEndian').name('Export PLY (Binary BE)'); + gui.add(params, 'exportBinaryLittleEndian').name('Export PLY (Binary LE)'); + gui.open(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + renderer.render(scene, camera); +} + +function exportASCII() { + exporter.parse(mesh, function (result) { + saveString(result, 'box.ply'); + }); +} + +function exportBinaryBigEndian() { + exporter.parse( + mesh, + function (result) { + saveArrayBuffer(result, 'box.ply'); + }, + { binary: true }, + ); +} + +function exportBinaryLittleEndian() { + exporter.parse( + mesh, + function (result) { + saveArrayBuffer(result, 'box.ply'); + }, + { binary: true, littleEndian: true }, + ); +} + +const link = document.createElement('a'); +link.style.display = 'none'; +document.body.appendChild(link); + +function save(blob, filename) { + link.href = URL.createObjectURL(blob); + link.download = filename; + link.click(); +} + +function saveString(text, filename) { + save(new Blob([text], { type: 'text/plain' }), filename); +} + +function saveArrayBuffer(buffer, filename) { + save(new Blob([buffer], { type: 'application/octet-stream' }), filename); +} diff --git a/examples-testing/examples/misc_exporter_stl.ts b/examples-testing/examples/misc_exporter_stl.ts new file mode 100644 index 000000000..ad6e3f592 --- /dev/null +++ b/examples-testing/examples/misc_exporter_stl.ts @@ -0,0 +1,130 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { STLExporter } from 'three/addons/exporters/STLExporter.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let scene, camera, renderer, exporter, mesh; + +const params = { + exportASCII: exportASCII, + exportBinary: exportBinary, +}; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(4, 2, 4); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xa0a0a0); + scene.fog = new THREE.Fog(0xa0a0a0, 4, 20); + + exporter = new STLExporter(); + + // + + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 3); + hemiLight.position.set(0, 20, 0); + scene.add(hemiLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff, 3); + directionalLight.position.set(0, 20, 10); + directionalLight.castShadow = true; + directionalLight.shadow.camera.top = 2; + directionalLight.shadow.camera.bottom = -2; + directionalLight.shadow.camera.left = -2; + directionalLight.shadow.camera.right = 2; + scene.add(directionalLight); + + // ground + + const ground = new THREE.Mesh( + new THREE.PlaneGeometry(40, 40), + new THREE.MeshPhongMaterial({ color: 0xbbbbbb, depthWrite: false }), + ); + ground.rotation.x = -Math.PI / 2; + ground.receiveShadow = true; + scene.add(ground); + + const grid = new THREE.GridHelper(40, 20, 0x000000, 0x000000); + grid.material.opacity = 0.2; + grid.material.transparent = true; + scene.add(grid); + + // export mesh + + const geometry = new THREE.BoxGeometry(); + const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 }); + + mesh = new THREE.Mesh(geometry, material); + mesh.castShadow = true; + mesh.position.y = 0.5; + scene.add(mesh); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + document.body.appendChild(renderer.domElement); + + // + + const controls = new OrbitControls(camera, renderer.domElement); + controls.target.set(0, 0.5, 0); + controls.update(); + + // + + window.addEventListener('resize', onWindowResize); + + const gui = new GUI(); + + gui.add(params, 'exportASCII').name('Export STL (ASCII)'); + gui.add(params, 'exportBinary').name('Export STL (Binary)'); + gui.open(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + renderer.render(scene, camera); +} + +function exportASCII() { + const result = exporter.parse(mesh); + saveString(result, 'box.stl'); +} + +function exportBinary() { + const result = exporter.parse(mesh, { binary: true }); + saveArrayBuffer(result, 'box.stl'); +} + +const link = document.createElement('a'); +link.style.display = 'none'; +document.body.appendChild(link); + +function save(blob, filename) { + link.href = URL.createObjectURL(blob); + link.download = filename; + link.click(); +} + +function saveString(text, filename) { + save(new Blob([text], { type: 'text/plain' }), filename); +} + +function saveArrayBuffer(buffer, filename) { + save(new Blob([buffer], { type: 'application/octet-stream' }), filename); +} diff --git a/examples-testing/examples/misc_exporter_usdz.ts b/examples-testing/examples/misc_exporter_usdz.ts new file mode 100644 index 000000000..97630ab41 --- /dev/null +++ b/examples-testing/examples/misc_exporter_usdz.ts @@ -0,0 +1,110 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js'; + +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; +import { USDZExporter } from 'three/addons/exporters/USDZExporter.js'; + +let camera, scene, renderer; + +init(); +render(); + +function init() { + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.toneMapping = THREE.ACESFilmicToneMapping; + document.body.appendChild(renderer.domElement); + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.25, 20); + camera.position.set(-2.5, 0.6, 3.0); + + const pmremGenerator = new THREE.PMREMGenerator(renderer); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xf0f0f0); + scene.environment = pmremGenerator.fromScene(new RoomEnvironment(renderer), 0.04).texture; + + const loader = new GLTFLoader().setPath('models/gltf/DamagedHelmet/glTF/'); + loader.load('DamagedHelmet.gltf', async function (gltf) { + scene.add(gltf.scene); + + const shadowMesh = createSpotShadowMesh(); + shadowMesh.position.y = -1.1; + shadowMesh.position.z = -0.25; + shadowMesh.scale.setScalar(2); + scene.add(shadowMesh); + + render(); + + // USDZ + + const exporter = new USDZExporter(); + const arraybuffer = await exporter.parse(gltf.scene); + const blob = new Blob([arraybuffer], { type: 'application/octet-stream' }); + + const link = document.getElementById('link'); + link.href = URL.createObjectURL(blob); + }); + + const controls = new OrbitControls(camera, renderer.domElement); + controls.addEventListener('change', render); // use if there is no animation loop + controls.minDistance = 2; + controls.maxDistance = 10; + controls.target.set(0, -0.15, -0.2); + controls.update(); + + window.addEventListener('resize', onWindowResize); +} + +function createSpotShadowMesh() { + const canvas = document.createElement('canvas'); + canvas.width = 128; + canvas.height = 128; + + const context = canvas.getContext('2d'); + const gradient = context.createRadialGradient( + canvas.width / 2, + canvas.height / 2, + 0, + canvas.width / 2, + canvas.height / 2, + canvas.width / 2, + ); + gradient.addColorStop(0.1, 'rgba(130,130,130,1)'); + gradient.addColorStop(1, 'rgba(255,255,255,1)'); + + context.fillStyle = gradient; + context.fillRect(0, 0, canvas.width, canvas.height); + + const shadowTexture = new THREE.CanvasTexture(canvas); + + const geometry = new THREE.PlaneGeometry(); + const material = new THREE.MeshBasicMaterial({ + map: shadowTexture, + blending: THREE.MultiplyBlending, + toneMapped: false, + }); + + const mesh = new THREE.Mesh(geometry, material); + mesh.rotation.x = -Math.PI / 2; + + return mesh; +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + render(); +} + +// + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/misc_lookat.ts b/examples-testing/examples/misc_lookat.ts new file mode 100644 index 000000000..f6241b9e1 --- /dev/null +++ b/examples-testing/examples/misc_lookat.ts @@ -0,0 +1,97 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let camera, scene, renderer, stats; + +let sphere; + +let mouseX = 0, + mouseY = 0; + +let windowHalfX = window.innerWidth / 2; +let windowHalfY = window.innerHeight / 2; + +document.addEventListener('mousemove', onDocumentMouseMove); + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 15000); + camera.position.z = 3200; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xffffff); + + sphere = new THREE.Mesh(new THREE.SphereGeometry(100, 20, 20), new THREE.MeshNormalMaterial()); + scene.add(sphere); + + const geometry = new THREE.CylinderGeometry(0, 10, 100, 12); + geometry.rotateX(Math.PI / 2); + + const material = new THREE.MeshNormalMaterial(); + + for (let i = 0; i < 1000; i++) { + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = Math.random() * 4000 - 2000; + mesh.position.y = Math.random() * 4000 - 2000; + mesh.position.z = Math.random() * 4000 - 2000; + mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 4 + 2; + scene.add(mesh); + } + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + stats = new Stats(); + document.body.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function onDocumentMouseMove(event) { + mouseX = (event.clientX - windowHalfX) * 10; + mouseY = (event.clientY - windowHalfY) * 10; +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.0005; + + sphere.position.x = Math.sin(time * 0.7) * 2000; + sphere.position.y = Math.cos(time * 0.5) * 2000; + sphere.position.z = Math.cos(time * 0.3) * 2000; + + for (let i = 1, l = scene.children.length; i < l; i++) { + scene.children[i].lookAt(sphere.position); + } + + camera.position.x += (mouseX - camera.position.x) * 0.05; + camera.position.y += (-mouseY - camera.position.y) * 0.05; + camera.lookAt(scene.position); + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/misc_uv_tests.ts b/examples-testing/examples/misc_uv_tests.ts new file mode 100644 index 000000000..4f782d45f --- /dev/null +++ b/examples-testing/examples/misc_uv_tests.ts @@ -0,0 +1,44 @@ +import * as THREE from 'three'; + +import { UVsDebug } from 'three/addons/utils/UVsDebug.js'; + +/* + * This is to help debug UVs problems in geometry, + * as well as allow a new user to visualize what UVs are about. + */ + +function test(name, geometry) { + const d = document.createElement('div'); + + d.innerHTML = '

' + name + '

'; + + d.appendChild(UVsDebug(geometry)); + + document.body.appendChild(d); +} + +const points = []; + +for (let i = 0; i < 10; i++) { + points.push(new THREE.Vector2(Math.sin(i * 0.2) * 15 + 50, (i - 5) * 2)); +} + +// + +test('new THREE.PlaneGeometry( 100, 100, 4, 4 )', new THREE.PlaneGeometry(100, 100, 4, 4)); + +test('new THREE.SphereGeometry( 75, 12, 6 )', new THREE.SphereGeometry(75, 12, 6)); + +test('new THREE.IcosahedronGeometry( 30, 1 )', new THREE.IcosahedronGeometry(30, 1)); + +test('new THREE.OctahedronGeometry( 30, 2 )', new THREE.OctahedronGeometry(30, 2)); + +test('new THREE.CylinderGeometry( 25, 75, 100, 10, 5 )', new THREE.CylinderGeometry(25, 75, 100, 10, 5)); + +test('new THREE.BoxGeometry( 100, 100, 100, 4, 4, 4 )', new THREE.BoxGeometry(100, 100, 100, 4, 4, 4)); + +test('new THREE.LatheGeometry( points, 8 )', new THREE.LatheGeometry(points, 8)); + +test('new THREE.TorusGeometry( 50, 20, 8, 8 )', new THREE.TorusGeometry(50, 20, 8, 8)); + +test('new THREE.TorusKnotGeometry( 50, 10, 12, 6 )', new THREE.TorusKnotGeometry(50, 10, 12, 6)); diff --git a/examples-testing/examples/physics_ammo_instancing.ts b/examples-testing/examples/physics_ammo_instancing.ts new file mode 100644 index 000000000..fdfc815e7 --- /dev/null +++ b/examples-testing/examples/physics_ammo_instancing.ts @@ -0,0 +1,122 @@ +import * as THREE from 'three'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { AmmoPhysics } from 'three/addons/physics/AmmoPhysics.js'; +import Stats from 'three/addons/libs/stats.module.js'; + +let camera, scene, renderer, stats; +let physics, position; + +let boxes, spheres; + +init(); + +async function init() { + physics = await AmmoPhysics(); + position = new THREE.Vector3(); + + // + + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(-1, 1.5, 2); + camera.lookAt(0, 0.5, 0); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x666666); + + const hemiLight = new THREE.HemisphereLight(); + scene.add(hemiLight); + + const dirLight = new THREE.DirectionalLight(0xffffff, 3); + dirLight.position.set(5, 5, 5); + dirLight.castShadow = true; + dirLight.shadow.camera.zoom = 2; + scene.add(dirLight); + + const floor = new THREE.Mesh(new THREE.BoxGeometry(10, 5, 10), new THREE.ShadowMaterial({ color: 0x444444 })); + floor.position.y = -2.5; + floor.receiveShadow = true; + scene.add(floor); + physics.addMesh(floor); + + // + + const material = new THREE.MeshLambertMaterial(); + + const matrix = new THREE.Matrix4(); + const color = new THREE.Color(); + + // Boxes + + const geometryBox = new THREE.BoxGeometry(0.075, 0.075, 0.075); + boxes = new THREE.InstancedMesh(geometryBox, material, 400); + boxes.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // will be updated every frame + boxes.castShadow = true; + boxes.receiveShadow = true; + scene.add(boxes); + + for (let i = 0; i < boxes.count; i++) { + matrix.setPosition(Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5); + boxes.setMatrixAt(i, matrix); + boxes.setColorAt(i, color.setHex(0xffffff * Math.random())); + } + + physics.addMesh(boxes, 1); + + // Spheres + + const geometrySphere = new THREE.IcosahedronGeometry(0.05, 4); + spheres = new THREE.InstancedMesh(geometrySphere, material, 400); + spheres.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // will be updated every frame + spheres.castShadow = true; + spheres.receiveShadow = true; + scene.add(spheres); + + for (let i = 0; i < spheres.count; i++) { + matrix.setPosition(Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5); + spheres.setMatrixAt(i, matrix); + spheres.setColorAt(i, color.setHex(0xffffff * Math.random())); + } + + physics.addMesh(spheres, 1); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + document.body.appendChild(renderer.domElement); + + stats = new Stats(); + document.body.appendChild(stats.dom); + + // + + const controls = new OrbitControls(camera, renderer.domElement); + controls.target.y = 0.5; + controls.update(); + + animate(); + + setInterval(() => { + let index = Math.floor(Math.random() * boxes.count); + + position.set(0, Math.random() + 1, 0); + physics.setMeshPosition(boxes, position, index); + + // + + index = Math.floor(Math.random() * spheres.count); + + position.set(0, Math.random() + 1, 0); + physics.setMeshPosition(spheres, position, index); + }, 1000 / 60); +} + +function animate() { + requestAnimationFrame(animate); + + renderer.render(scene, camera); + + stats.update(); +} diff --git a/examples-testing/examples/physics_rapier_instancing.ts b/examples-testing/examples/physics_rapier_instancing.ts new file mode 100644 index 000000000..42116a6ec --- /dev/null +++ b/examples-testing/examples/physics_rapier_instancing.ts @@ -0,0 +1,122 @@ +import * as THREE from 'three'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { RapierPhysics } from 'three/addons/physics/RapierPhysics.js'; +import Stats from 'three/addons/libs/stats.module.js'; + +let camera, scene, renderer, stats; +let physics, position; + +let boxes, spheres; + +init(); + +async function init() { + physics = await RapierPhysics(); + position = new THREE.Vector3(); + + // + + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(-1, 1.5, 2); + camera.lookAt(0, 0.5, 0); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x666666); + + const hemiLight = new THREE.HemisphereLight(); + scene.add(hemiLight); + + const dirLight = new THREE.DirectionalLight(0xffffff, 3); + dirLight.position.set(5, 5, 5); + dirLight.castShadow = true; + dirLight.shadow.camera.zoom = 2; + scene.add(dirLight); + + const floor = new THREE.Mesh(new THREE.BoxGeometry(10, 5, 10), new THREE.ShadowMaterial({ color: 0x444444 })); + floor.position.y = -2.5; + floor.receiveShadow = true; + scene.add(floor); + physics.addMesh(floor); + + // + + const material = new THREE.MeshLambertMaterial(); + + const matrix = new THREE.Matrix4(); + const color = new THREE.Color(); + + // Boxes + + const geometryBox = new THREE.BoxGeometry(0.075, 0.075, 0.075); + boxes = new THREE.InstancedMesh(geometryBox, material, 400); + boxes.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // will be updated every frame + boxes.castShadow = true; + boxes.receiveShadow = true; + scene.add(boxes); + + for (let i = 0; i < boxes.count; i++) { + matrix.setPosition(Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5); + boxes.setMatrixAt(i, matrix); + boxes.setColorAt(i, color.setHex(0xffffff * Math.random())); + } + + physics.addMesh(boxes, 1); + + // Spheres + + const geometrySphere = new THREE.IcosahedronGeometry(0.05, 4); + spheres = new THREE.InstancedMesh(geometrySphere, material, 400); + spheres.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // will be updated every frame + spheres.castShadow = true; + spheres.receiveShadow = true; + scene.add(spheres); + + for (let i = 0; i < spheres.count; i++) { + matrix.setPosition(Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5); + spheres.setMatrixAt(i, matrix); + spheres.setColorAt(i, color.setHex(0xffffff * Math.random())); + } + + physics.addMesh(spheres, 1); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + document.body.appendChild(renderer.domElement); + + stats = new Stats(); + document.body.appendChild(stats.dom); + + // + + const controls = new OrbitControls(camera, renderer.domElement); + controls.target.y = 0.5; + controls.update(); + + animate(); + + setInterval(() => { + let index = Math.floor(Math.random() * boxes.count); + + position.set(0, Math.random() + 1, 0); + physics.setMeshPosition(boxes, position, index); + + // + + index = Math.floor(Math.random() * spheres.count); + + position.set(0, Math.random() + 1, 0); + physics.setMeshPosition(spheres, position, index); + }, 1000 / 60); +} + +function animate() { + requestAnimationFrame(animate); + + renderer.render(scene, camera); + + stats.update(); +} diff --git a/examples-testing/examples/svg_lines.ts b/examples-testing/examples/svg_lines.ts new file mode 100644 index 000000000..99b74c405 --- /dev/null +++ b/examples-testing/examples/svg_lines.ts @@ -0,0 +1,87 @@ +import * as THREE from 'three'; + +import { SVGRenderer } from 'three/addons/renderers/SVGRenderer.js'; + +THREE.ColorManagement.enabled = false; + +let camera, scene, renderer; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(33, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.z = 10; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0, 0, 0); + + renderer = new SVGRenderer(); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + // + + const vertices = []; + const divisions = 50; + + for (let i = 0; i <= divisions; i++) { + const v = (i / divisions) * (Math.PI * 2); + + const x = Math.sin(v); + const z = Math.cos(v); + + vertices.push(x, 0, z); + } + + const geometry = new THREE.BufferGeometry(); + geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); + + // + + for (let i = 1; i <= 3; i++) { + const material = new THREE.LineBasicMaterial({ + color: Math.random() * 0xffffff, + linewidth: 10, + }); + const line = new THREE.Line(geometry, material); + line.scale.setScalar(i / 3); + scene.add(line); + } + + const material = new THREE.LineDashedMaterial({ + color: 'blue', + linewidth: 1, + dashSize: 10, + gapSize: 10, + }); + const line = new THREE.Line(geometry, material); + line.scale.setScalar(2); + scene.add(line); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + let count = 0; + const time = performance.now() / 1000; + + scene.traverse(function (child) { + child.rotation.x = count + time / 3; + child.rotation.z = count + time / 4; + + count++; + }); + + renderer.render(scene, camera); + requestAnimationFrame(animate); +} diff --git a/examples-testing/examples/svg_sandbox.ts b/examples-testing/examples/svg_sandbox.ts new file mode 100644 index 000000000..e6be8386c --- /dev/null +++ b/examples-testing/examples/svg_sandbox.ts @@ -0,0 +1,212 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import { SVGRenderer, SVGObject } from 'three/addons/renderers/SVGRenderer.js'; + +THREE.ColorManagement.enabled = false; + +let camera, scene, renderer, stats; + +let group; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); + camera.position.z = 500; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xf0f0f0); + + // QRCODE + + const loader = new THREE.BufferGeometryLoader(); + loader.load('models/json/QRCode_buffergeometry.json', function (geometry) { + mesh = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ vertexColors: true })); + mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; + scene.add(mesh); + }); + + // CUBES + + const boxGeometry = new THREE.BoxGeometry(100, 100, 100); + + let mesh = new THREE.Mesh( + boxGeometry, + new THREE.MeshBasicMaterial({ color: 0x0000ff, opacity: 0.5, transparent: true }), + ); + mesh.position.x = 500; + mesh.rotation.x = Math.random(); + mesh.rotation.y = Math.random(); + mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; + scene.add(mesh); + + mesh = new THREE.Mesh(boxGeometry, new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff })); + mesh.position.x = 500; + mesh.position.y = 500; + mesh.rotation.x = Math.random(); + mesh.rotation.y = Math.random(); + mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; + scene.add(mesh); + + // PLANE + + mesh = new THREE.Mesh( + new THREE.PlaneGeometry(100, 100), + new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff, side: THREE.DoubleSide }), + ); + mesh.position.y = -500; + mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; + scene.add(mesh); + + // CYLINDER + + mesh = new THREE.Mesh( + new THREE.CylinderGeometry(20, 100, 200, 10), + new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff }), + ); + mesh.position.x = -500; + mesh.rotation.x = -Math.PI / 2; + mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; + scene.add(mesh); + + // POLYFIELD + + const geometry = new THREE.BufferGeometry(); + const material = new THREE.MeshBasicMaterial({ vertexColors: true, side: THREE.DoubleSide }); + + const v = new THREE.Vector3(); + const v0 = new THREE.Vector3(); + const v1 = new THREE.Vector3(); + const v2 = new THREE.Vector3(); + const color = new THREE.Color(); + + const vertices = []; + const colors = []; + + for (let i = 0; i < 100; i++) { + v.set(Math.random() * 1000 - 500, Math.random() * 1000 - 500, Math.random() * 1000 - 500); + + v0.set(Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50); + + v1.set(Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50); + + v2.set(Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50); + + v0.add(v); + v1.add(v); + v2.add(v); + + color.setHex(Math.random() * 0xffffff); + + // create a single triangle + + vertices.push(v0.x, v0.y, v0.z); + vertices.push(v1.x, v1.y, v1.z); + vertices.push(v2.x, v2.y, v2.z); + + colors.push(color.r, color.g, color.b); + colors.push(color.r, color.g, color.b); + colors.push(color.r, color.g, color.b); + } + + geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); + geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); + + group = new THREE.Mesh(geometry, material); + group.scale.set(2, 2, 2); + scene.add(group); + + // SPRITES + + for (let i = 0; i < 50; i++) { + const material = new THREE.SpriteMaterial({ color: Math.random() * 0xffffff }); + const sprite = new THREE.Sprite(material); + sprite.position.x = Math.random() * 1000 - 500; + sprite.position.y = Math.random() * 1000 - 500; + sprite.position.z = Math.random() * 1000 - 500; + sprite.scale.set(64, 64, 1); + scene.add(sprite); + } + + // CUSTOM + + const node = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); + node.setAttribute('stroke', 'black'); + node.setAttribute('fill', 'red'); + node.setAttribute('r', '40'); + + for (let i = 0; i < 50; i++) { + const object = new SVGObject(node.cloneNode()); + object.position.x = Math.random() * 1000 - 500; + object.position.y = Math.random() * 1000 - 500; + object.position.z = Math.random() * 1000 - 500; + scene.add(object); + } + + // CUSTOM FROM FILE + + const fileLoader = new THREE.FileLoader(); + fileLoader.load('models/svg/hexagon.svg', function (svg) { + const node = document.createElementNS('http://www.w3.org/2000/svg', 'g'); + const parser = new DOMParser(); + const doc = parser.parseFromString(svg, 'image/svg+xml'); + + node.appendChild(doc.documentElement); + + const object = new SVGObject(node); + object.position.x = 500; + scene.add(object); + }); + + // LIGHTS + + const ambient = new THREE.AmbientLight(0x80ffff); + scene.add(ambient); + + const directional = new THREE.DirectionalLight(0xffff00); + directional.position.set(-1, 0.5, 0); + scene.add(directional); + + renderer = new SVGRenderer(); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.setQuality('low'); + document.body.appendChild(renderer.domElement); + + stats = new Stats(); + document.body.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.0002; + + camera.position.x = Math.sin(time) * 500; + camera.position.z = Math.cos(time) * 500; + camera.lookAt(scene.position); + + group.rotation.x += 0.01; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webaudio_orientation.ts b/examples-testing/examples/webaudio_orientation.ts new file mode 100644 index 000000000..d5cff3934 --- /dev/null +++ b/examples-testing/examples/webaudio_orientation.ts @@ -0,0 +1,141 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { PositionalAudioHelper } from 'three/addons/helpers/PositionalAudioHelper.js'; +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; + +let scene, camera, renderer; + +const startButton = document.getElementById('startButton'); +startButton.addEventListener('click', init); + +function init() { + const overlay = document.getElementById('overlay'); + overlay.remove(); + + const container = document.getElementById('container'); + + // + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(3, 2, 3); + + const reflectionCube = new THREE.CubeTextureLoader() + .setPath('textures/cube/SwedishRoyalCastle/') + .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xa0a0a0); + scene.fog = new THREE.Fog(0xa0a0a0, 2, 20); + + // + + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x8d8d8d, 3); + hemiLight.position.set(0, 20, 0); + scene.add(hemiLight); + + const dirLight = new THREE.DirectionalLight(0xffffff, 3); + dirLight.position.set(5, 5, 0); + dirLight.castShadow = true; + dirLight.shadow.camera.top = 1; + dirLight.shadow.camera.bottom = -1; + dirLight.shadow.camera.left = -1; + dirLight.shadow.camera.right = 1; + dirLight.shadow.camera.near = 0.1; + dirLight.shadow.camera.far = 20; + scene.add(dirLight); + + // scene.add( new THREE.CameraHelper( dirLight.shadow.camera ) ); + + // + + const mesh = new THREE.Mesh( + new THREE.PlaneGeometry(50, 50), + new THREE.MeshPhongMaterial({ color: 0xcbcbcb, depthWrite: false }), + ); + mesh.rotation.x = -Math.PI / 2; + mesh.receiveShadow = true; + scene.add(mesh); + + const grid = new THREE.GridHelper(50, 50, 0xc1c1c1, 0xc1c1c1); + scene.add(grid); + + // + + const listener = new THREE.AudioListener(); + camera.add(listener); + + const audioElement = document.getElementById('music'); + audioElement.play(); + + const positionalAudio = new THREE.PositionalAudio(listener); + positionalAudio.setMediaElementSource(audioElement); + positionalAudio.setRefDistance(1); + positionalAudio.setDirectionalCone(180, 230, 0.1); + + const helper = new PositionalAudioHelper(positionalAudio, 0.1); + positionalAudio.add(helper); + + // + + const gltfLoader = new GLTFLoader(); + gltfLoader.load('models/gltf/BoomBox.glb', function (gltf) { + const boomBox = gltf.scene; + boomBox.position.set(0, 0.2, 0); + boomBox.scale.set(20, 20, 20); + + boomBox.traverse(function (object) { + if (object.isMesh) { + object.material.envMap = reflectionCube; + object.geometry.rotateY(-Math.PI); + object.castShadow = true; + } + }); + + boomBox.add(positionalAudio); + scene.add(boomBox); + animate(); + }); + + // sound is damped behind this wall + + const wallGeometry = new THREE.BoxGeometry(2, 1, 0.1); + const wallMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, transparent: true, opacity: 0.5 }); + + const wall = new THREE.Mesh(wallGeometry, wallMaterial); + wall.position.set(0, 0.5, -0.5); + scene.add(wall); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + container.appendChild(renderer.domElement); + + // + + const controls = new OrbitControls(camera, renderer.domElement); + controls.target.set(0, 0.1, 0); + controls.update(); + controls.minDistance = 0.5; + controls.maxDistance = 10; + controls.maxPolarAngle = 0.5 * Math.PI; + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webaudio_sandbox.ts b/examples-testing/examples/webaudio_sandbox.ts new file mode 100644 index 000000000..56bd042a0 --- /dev/null +++ b/examples-testing/examples/webaudio_sandbox.ts @@ -0,0 +1,228 @@ +import * as THREE from 'three'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { FirstPersonControls } from 'three/addons/controls/FirstPersonControls.js'; + +let camera, controls, scene, renderer, light; + +let material1, material2, material3; + +let analyser1, analyser2, analyser3; + +const clock = new THREE.Clock(); + +const startButton = document.getElementById('startButton'); +startButton.addEventListener('click', init); + +function init() { + const overlay = document.getElementById('overlay'); + overlay.remove(); + + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000); + camera.position.set(0, 25, 0); + + const listener = new THREE.AudioListener(); + camera.add(listener); + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2(0x000000, 0.0025); + + light = new THREE.DirectionalLight(0xffffff, 3); + light.position.set(0, 0.5, 1).normalize(); + scene.add(light); + + const sphere = new THREE.SphereGeometry(20, 32, 16); + + material1 = new THREE.MeshPhongMaterial({ color: 0xffaa00, flatShading: true, shininess: 0 }); + material2 = new THREE.MeshPhongMaterial({ color: 0xff2200, flatShading: true, shininess: 0 }); + material3 = new THREE.MeshPhongMaterial({ color: 0x6622aa, flatShading: true, shininess: 0 }); + + // sound spheres + + const mesh1 = new THREE.Mesh(sphere, material1); + mesh1.position.set(-250, 30, 0); + scene.add(mesh1); + + const sound1 = new THREE.PositionalAudio(listener); + const songElement = document.getElementById('song'); + sound1.setMediaElementSource(songElement); + sound1.setRefDistance(20); + songElement.play(); + mesh1.add(sound1); + + // + + const mesh2 = new THREE.Mesh(sphere, material2); + mesh2.position.set(250, 30, 0); + scene.add(mesh2); + + const sound2 = new THREE.PositionalAudio(listener); + const skullbeatzElement = document.getElementById('skullbeatz'); + sound2.setMediaElementSource(skullbeatzElement); + sound2.setRefDistance(20); + skullbeatzElement.play(); + mesh2.add(sound2); + + // + + const mesh3 = new THREE.Mesh(sphere, material3); + mesh3.position.set(0, 30, -250); + scene.add(mesh3); + + const sound3 = new THREE.PositionalAudio(listener); + const oscillator = listener.context.createOscillator(); + oscillator.type = 'sine'; + oscillator.frequency.setValueAtTime(144, sound3.context.currentTime); + oscillator.start(0); + sound3.setNodeSource(oscillator); + sound3.setRefDistance(20); + sound3.setVolume(0.5); + mesh3.add(sound3); + + // analysers + + analyser1 = new THREE.AudioAnalyser(sound1, 32); + analyser2 = new THREE.AudioAnalyser(sound2, 32); + analyser3 = new THREE.AudioAnalyser(sound3, 32); + + // global ambient audio + + const sound4 = new THREE.Audio(listener); + const utopiaElement = document.getElementById('utopia'); + sound4.setMediaElementSource(utopiaElement); + sound4.setVolume(0.5); + utopiaElement.play(); + + // ground + + const helper = new THREE.GridHelper(1000, 10, 0x444444, 0x444444); + helper.position.y = 0.1; + scene.add(helper); + + // + + const SoundControls = function () { + this.master = listener.getMasterVolume(); + this.firstSphere = sound1.getVolume(); + this.secondSphere = sound2.getVolume(); + this.thirdSphere = sound3.getVolume(); + this.Ambient = sound4.getVolume(); + }; + + const GeneratorControls = function () { + this.frequency = oscillator.frequency.value; + this.wavetype = oscillator.type; + }; + + const gui = new GUI(); + const soundControls = new SoundControls(); + const generatorControls = new GeneratorControls(); + const volumeFolder = gui.addFolder('sound volume'); + const generatorFolder = gui.addFolder('sound generator'); + + volumeFolder + .add(soundControls, 'master') + .min(0.0) + .max(1.0) + .step(0.01) + .onChange(function () { + listener.setMasterVolume(soundControls.master); + }); + volumeFolder + .add(soundControls, 'firstSphere') + .min(0.0) + .max(1.0) + .step(0.01) + .onChange(function () { + sound1.setVolume(soundControls.firstSphere); + }); + volumeFolder + .add(soundControls, 'secondSphere') + .min(0.0) + .max(1.0) + .step(0.01) + .onChange(function () { + sound2.setVolume(soundControls.secondSphere); + }); + + volumeFolder + .add(soundControls, 'thirdSphere') + .min(0.0) + .max(1.0) + .step(0.01) + .onChange(function () { + sound3.setVolume(soundControls.thirdSphere); + }); + volumeFolder + .add(soundControls, 'Ambient') + .min(0.0) + .max(1.0) + .step(0.01) + .onChange(function () { + sound4.setVolume(soundControls.Ambient); + }); + volumeFolder.open(); + generatorFolder + .add(generatorControls, 'frequency') + .min(50.0) + .max(5000.0) + .step(1.0) + .onChange(function () { + oscillator.frequency.setValueAtTime(generatorControls.frequency, listener.context.currentTime); + }); + generatorFolder + .add(generatorControls, 'wavetype', ['sine', 'square', 'sawtooth', 'triangle']) + .onChange(function () { + oscillator.type = generatorControls.wavetype; + }); + + generatorFolder.open(); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + // + + controls = new FirstPersonControls(camera, renderer.domElement); + + controls.movementSpeed = 70; + controls.lookSpeed = 0.05; + controls.lookVertical = false; + + // + + window.addEventListener('resize', onWindowResize); + + animate(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + controls.handleResize(); +} + +function animate() { + requestAnimationFrame(animate); + render(); +} + +function render() { + const delta = clock.getDelta(); + + controls.update(delta); + + material1.emissive.b = analyser1.getAverageFrequency() / 256; + material2.emissive.b = analyser2.getAverageFrequency() / 256; + material3.emissive.b = analyser3.getAverageFrequency() / 256; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webaudio_timing.ts b/examples-testing/examples/webaudio_timing.ts new file mode 100644 index 000000000..bab79dd74 --- /dev/null +++ b/examples-testing/examples/webaudio_timing.ts @@ -0,0 +1,158 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +let scene, camera, renderer, clock; + +const objects = []; + +const speed = 2.5; +const height = 3; +const offset = 0.5; + +const startButton = document.getElementById('startButton'); +startButton.addEventListener('click', init); + +function init() { + const overlay = document.getElementById('overlay'); + overlay.remove(); + + const container = document.getElementById('container'); + + scene = new THREE.Scene(); + + clock = new THREE.Clock(); + + // + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(7, 3, 7); + + // lights + + const ambientLight = new THREE.AmbientLight(0xcccccc); + scene.add(ambientLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff, 2.5); + directionalLight.position.set(0, 5, 5); + scene.add(directionalLight); + + const d = 5; + directionalLight.castShadow = true; + directionalLight.shadow.camera.left = -d; + directionalLight.shadow.camera.right = d; + directionalLight.shadow.camera.top = d; + directionalLight.shadow.camera.bottom = -d; + + directionalLight.shadow.camera.near = 1; + directionalLight.shadow.camera.far = 20; + + directionalLight.shadow.mapSize.x = 1024; + directionalLight.shadow.mapSize.y = 1024; + + // audio + + const audioLoader = new THREE.AudioLoader(); + + const listener = new THREE.AudioListener(); + camera.add(listener); + + // floor + + const floorGeometry = new THREE.PlaneGeometry(10, 10); + const floorMaterial = new THREE.MeshLambertMaterial({ color: 0x4676b6 }); + + const floor = new THREE.Mesh(floorGeometry, floorMaterial); + floor.rotation.x = Math.PI * -0.5; + floor.receiveShadow = true; + scene.add(floor); + + // objects + + const count = 5; + const radius = 3; + + const ballGeometry = new THREE.SphereGeometry(0.3, 32, 16); + ballGeometry.translate(0, 0.3, 0); + const ballMaterial = new THREE.MeshLambertMaterial({ color: 0xcccccc }); + + // create objects when audio buffer is loaded + + audioLoader.load('sounds/ping_pong.mp3', function (buffer) { + for (let i = 0; i < count; i++) { + const s = (i / count) * Math.PI * 2; + + const ball = new THREE.Mesh(ballGeometry, ballMaterial); + ball.castShadow = true; + ball.userData.down = false; + + ball.position.x = radius * Math.cos(s); + ball.position.z = radius * Math.sin(s); + + const audio = new THREE.PositionalAudio(listener); + audio.setBuffer(buffer); + ball.add(audio); + + scene.add(ball); + objects.push(ball); + } + + animate(); + }); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + container.appendChild(renderer.domElement); + + // + + const controls = new OrbitControls(camera, renderer.domElement); + controls.minDistance = 1; + controls.maxDistance = 25; + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + render(); +} + +function render() { + const time = clock.getElapsedTime(); + + for (let i = 0; i < objects.length; i++) { + const ball = objects[i]; + + const previousHeight = ball.position.y; + ball.position.y = Math.abs(Math.sin(i * offset + time * speed) * height); + + if (ball.position.y < previousHeight) { + ball.userData.down = true; + } else { + if (ball.userData.down === true) { + // ball changed direction from down to up + + const audio = ball.children[0]; + audio.play(); // play audio with perfect timing when ball hits the surface + ball.userData.down = false; + } + } + } + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webaudio_visualizer.ts b/examples-testing/examples/webaudio_visualizer.ts new file mode 100644 index 000000000..6c4244f82 --- /dev/null +++ b/examples-testing/examples/webaudio_visualizer.ts @@ -0,0 +1,93 @@ +import * as THREE from 'three'; + +let scene, camera, renderer, analyser, uniforms; + +const startButton = document.getElementById('startButton'); +startButton.addEventListener('click', init); + +function init() { + const fftSize = 128; + + // + + const overlay = document.getElementById('overlay'); + overlay.remove(); + + // + + const container = document.getElementById('container'); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + scene = new THREE.Scene(); + + camera = new THREE.Camera(); + + // + + const listener = new THREE.AudioListener(); + + const audio = new THREE.Audio(listener); + const file = './sounds/376737_Skullbeatz___Bad_Cat_Maste.mp3'; + + if (/(iPad|iPhone|iPod)/g.test(navigator.userAgent)) { + const loader = new THREE.AudioLoader(); + loader.load(file, function (buffer) { + audio.setBuffer(buffer); + audio.play(); + }); + } else { + const mediaElement = new Audio(file); + mediaElement.play(); + + audio.setMediaElementSource(mediaElement); + } + + analyser = new THREE.AudioAnalyser(audio, fftSize); + + // + + const format = renderer.capabilities.isWebGL2 ? THREE.RedFormat : THREE.LuminanceFormat; + + uniforms = { + tAudioData: { value: new THREE.DataTexture(analyser.data, fftSize / 2, 1, format) }, + }; + + const material = new THREE.ShaderMaterial({ + uniforms: uniforms, + vertexShader: document.getElementById('vertexShader').textContent, + fragmentShader: document.getElementById('fragmentShader').textContent, + }); + + const geometry = new THREE.PlaneGeometry(1, 1); + + const mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // + + window.addEventListener('resize', onWindowResize); + + animate(); +} + +function onWindowResize() { + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + render(); +} + +function render() { + analyser.getFrequencyData(); + + uniforms.tAudioData.value.needsUpdate = true; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts b/examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts new file mode 100644 index 000000000..848814cd0 --- /dev/null +++ b/examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts @@ -0,0 +1,121 @@ +import * as THREE from 'three'; + +import WebGL from 'three/addons/capabilities/WebGL.js'; + +if (WebGL.isWebGL2Available() === false) { + document.body.appendChild(WebGL.getWebGL2ErrorMessage()); +} + +let camera, scene, renderer, mesh; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500); + camera.position.z = 2500; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x050505); + scene.fog = new THREE.Fog(0x050505, 2000, 3500); + + // geometry + + const triangles = 10000; + + const geometry = new THREE.BufferGeometry(); + + const positions = []; + const uvs = []; + const textureIndices = []; + + const n = 800, + n2 = n / 2; // triangles spread in the cube + const d = 50, + d2 = d / 2; // individual triangle size + + for (let i = 0; i < triangles; i++) { + // positions + + const x = Math.random() * n - n2; + const y = Math.random() * n - n2; + const z = Math.random() * n - n2; + + const ax = x + Math.random() * d - d2; + const ay = y + Math.random() * d - d2; + const az = z + Math.random() * d - d2; + + const bx = x + Math.random() * d - d2; + const by = y + Math.random() * d - d2; + const bz = z + Math.random() * d - d2; + + const cx = x + Math.random() * d - d2; + const cy = y + Math.random() * d - d2; + const cz = z + Math.random() * d - d2; + + positions.push(ax, ay, az); + positions.push(bx, by, bz); + positions.push(cx, cy, cz); + + // uvs + + uvs.push(0, 0); + uvs.push(0.5, 1); + uvs.push(1, 0); + + // texture indices + + const t = i % 3; + textureIndices.push(t, t, t); + } + + geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); + geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2)); + geometry.setAttribute('textureIndex', new THREE.Int16BufferAttribute(textureIndices, 1)); + geometry.attributes.textureIndex.gpuType = THREE.IntType; + + geometry.computeBoundingSphere(); + + // material + + const loader = new THREE.TextureLoader(); + + const map1 = loader.load('textures/crate.gif'); + const map2 = loader.load('textures/floors/FloorsCheckerboard_S_Diffuse.jpg'); + const map3 = loader.load('textures/terrain/grasslight-big.jpg'); + + const material = new THREE.ShaderMaterial({ + uniforms: { + uTextures: { + value: [map1, map2, map3], + }, + }, + vertexShader: document.getElementById('vertexShader').textContent, + fragmentShader: document.getElementById('fragmentShader').textContent, + side: THREE.DoubleSide, + glslVersion: THREE.GLSL3, + }); + + // mesh + + mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // renderer + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); +} + +function animate() { + requestAnimationFrame(animate); + + const time = Date.now() * 0.001; + + mesh.rotation.x = time * 0.25; + mesh.rotation.y = time * 0.5; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl2_buffergeometry_attributes_none.ts b/examples-testing/examples/webgl2_buffergeometry_attributes_none.ts new file mode 100644 index 000000000..a77b973df --- /dev/null +++ b/examples-testing/examples/webgl2_buffergeometry_attributes_none.ts @@ -0,0 +1,64 @@ +import * as THREE from 'three'; + +import WebGL from 'three/addons/capabilities/WebGL.js'; + +if (WebGL.isWebGL2Available() === false) { + document.body.appendChild(WebGL.getWebGL2ErrorMessage()); +} + +let camera, scene, renderer, mesh; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500); + camera.position.z = 4; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x050505); + scene.fog = new THREE.Fog(0x050505, 2000, 3500); + + // geometry + + const triangleCount = 10000; + const vertexCountPerTriangle = 3; + const vertexCount = triangleCount * vertexCountPerTriangle; + + const geometry = new THREE.BufferGeometry(); + geometry.setDrawRange(0, vertexCount); + + // material + + const material = new THREE.RawShaderMaterial({ + uniforms: { + seed: { value: 42 }, + }, + vertexShader: document.getElementById('vertexShader').textContent, + fragmentShader: document.getElementById('fragmentShader').textContent, + side: THREE.DoubleSide, + glslVersion: THREE.GLSL3, + }); + + // mesh + + mesh = new THREE.Mesh(geometry, material); + mesh.frustumCulled = false; + scene.add(mesh); + + // renderer + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); +} + +function animate(time) { + requestAnimationFrame(animate); + + mesh.rotation.x = (time / 1000.0) * 0.25; + mesh.rotation.y = (time / 1000.0) * 0.5; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl2_materials_texture3d.ts b/examples-testing/examples/webgl2_materials_texture3d.ts new file mode 100644 index 000000000..b746daf0b --- /dev/null +++ b/examples-testing/examples/webgl2_materials_texture3d.ts @@ -0,0 +1,133 @@ +import * as THREE from 'three'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { NRRDLoader } from 'three/addons/loaders/NRRDLoader.js'; +import { VolumeRenderShader1 } from 'three/addons/shaders/VolumeShader.js'; +import WebGL from 'three/addons/capabilities/WebGL.js'; + +if (WebGL.isWebGL2Available() === false) { + document.body.appendChild(WebGL.getWebGL2ErrorMessage()); +} + +let renderer, scene, camera, controls, material, volconfig, cmtextures; + +init(); + +function init() { + scene = new THREE.Scene(); + + // Create renderer + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + // Create camera (The volume renderer does not work very well with perspective yet) + const h = 512; // frustum height + const aspect = window.innerWidth / window.innerHeight; + camera = new THREE.OrthographicCamera((-h * aspect) / 2, (h * aspect) / 2, h / 2, -h / 2, 1, 1000); + camera.position.set(-64, -64, 128); + camera.up.set(0, 0, 1); // In our data, z is up + + // Create controls + controls = new OrbitControls(camera, renderer.domElement); + controls.addEventListener('change', render); + controls.target.set(64, 64, 128); + controls.minZoom = 0.5; + controls.maxZoom = 4; + controls.enablePan = false; + controls.update(); + + // scene.add( new AxesHelper( 128 ) ); + + // Lighting is baked into the shader a.t.m. + // let dirLight = new DirectionalLight( 0xffffff ); + + // The gui for interaction + volconfig = { clim1: 0, clim2: 1, renderstyle: 'iso', isothreshold: 0.15, colormap: 'viridis' }; + const gui = new GUI(); + gui.add(volconfig, 'clim1', 0, 1, 0.01).onChange(updateUniforms); + gui.add(volconfig, 'clim2', 0, 1, 0.01).onChange(updateUniforms); + gui.add(volconfig, 'colormap', { gray: 'gray', viridis: 'viridis' }).onChange(updateUniforms); + gui.add(volconfig, 'renderstyle', { mip: 'mip', iso: 'iso' }).onChange(updateUniforms); + gui.add(volconfig, 'isothreshold', 0, 1, 0.01).onChange(updateUniforms); + + // Load the data ... + new NRRDLoader().load('models/nrrd/stent.nrrd', function (volume) { + // Texture to hold the volume. We have scalars, so we put our data in the red channel. + // THREEJS will select R32F (33326) based on the THREE.RedFormat and THREE.FloatType. + // Also see https://www.khronos.org/registry/webgl/specs/latest/2.0/#TEXTURE_TYPES_FORMATS_FROM_DOM_ELEMENTS_TABLE + // TODO: look the dtype up in the volume metadata + const texture = new THREE.Data3DTexture(volume.data, volume.xLength, volume.yLength, volume.zLength); + texture.format = THREE.RedFormat; + texture.type = THREE.FloatType; + texture.minFilter = texture.magFilter = THREE.LinearFilter; + texture.unpackAlignment = 1; + texture.needsUpdate = true; + + // Colormap textures + cmtextures = { + viridis: new THREE.TextureLoader().load('textures/cm_viridis.png', render), + gray: new THREE.TextureLoader().load('textures/cm_gray.png', render), + }; + + // Material + const shader = VolumeRenderShader1; + + const uniforms = THREE.UniformsUtils.clone(shader.uniforms); + + uniforms['u_data'].value = texture; + uniforms['u_size'].value.set(volume.xLength, volume.yLength, volume.zLength); + uniforms['u_clim'].value.set(volconfig.clim1, volconfig.clim2); + uniforms['u_renderstyle'].value = volconfig.renderstyle == 'mip' ? 0 : 1; // 0: MIP, 1: ISO + uniforms['u_renderthreshold'].value = volconfig.isothreshold; // For ISO renderstyle + uniforms['u_cmdata'].value = cmtextures[volconfig.colormap]; + + material = new THREE.ShaderMaterial({ + uniforms: uniforms, + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, + side: THREE.BackSide, // The volume shader uses the backface as its "reference point" + }); + + // THREE.Mesh + const geometry = new THREE.BoxGeometry(volume.xLength, volume.yLength, volume.zLength); + geometry.translate(volume.xLength / 2 - 0.5, volume.yLength / 2 - 0.5, volume.zLength / 2 - 0.5); + + const mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + render(); + }); + + window.addEventListener('resize', onWindowResize); +} + +function updateUniforms() { + material.uniforms['u_clim'].value.set(volconfig.clim1, volconfig.clim2); + material.uniforms['u_renderstyle'].value = volconfig.renderstyle == 'mip' ? 0 : 1; // 0: MIP, 1: ISO + material.uniforms['u_renderthreshold'].value = volconfig.isothreshold; // For ISO renderstyle + material.uniforms['u_cmdata'].value = cmtextures[volconfig.colormap]; + + render(); +} + +function onWindowResize() { + renderer.setSize(window.innerWidth, window.innerHeight); + + const aspect = window.innerWidth / window.innerHeight; + + const frustumHeight = camera.top - camera.bottom; + + camera.left = (-frustumHeight * aspect) / 2; + camera.right = (frustumHeight * aspect) / 2; + + camera.updateProjectionMatrix(); + + render(); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts b/examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts new file mode 100644 index 000000000..026813023 --- /dev/null +++ b/examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts @@ -0,0 +1,333 @@ +import * as THREE from 'three'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { ImprovedNoise } from 'three/addons/math/ImprovedNoise.js'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import WebGL from 'three/addons/capabilities/WebGL.js'; + +if (WebGL.isWebGL2Available() === false) { + document.body.appendChild(WebGL.getWebGL2ErrorMessage()); +} + +const INITIAL_CLOUD_SIZE = 128; + +let renderer, scene, camera; +let mesh; +let prevTime = performance.now(); +let cloudTexture = null; + +init(); +animate(); + +function generateCloudTexture(size, scaleFactor = 1.0) { + const data = new Uint8Array(size * size * size); + const scale = (scaleFactor * 10.0) / size; + + let i = 0; + const perlin = new ImprovedNoise(); + const vector = new THREE.Vector3(); + + for (let z = 0; z < size; z++) { + for (let y = 0; y < size; y++) { + for (let x = 0; x < size; x++) { + const dist = vector + .set(x, y, z) + .subScalar(size / 2) + .divideScalar(size) + .length(); + const fadingFactor = (1.0 - dist) * (1.0 - dist); + data[i] = (128 + 128 * perlin.noise((x * scale) / 1.5, y * scale, (z * scale) / 1.5)) * fadingFactor; + + i++; + } + } + } + + return new THREE.Data3DTexture(data, size, size, size); +} + +function init() { + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(0, 0, 1.5); + + new OrbitControls(camera, renderer.domElement); + + // Sky + + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 32; + + const context = canvas.getContext('2d'); + const gradient = context.createLinearGradient(0, 0, 0, 32); + gradient.addColorStop(0.0, '#014a84'); + gradient.addColorStop(0.5, '#0561a0'); + gradient.addColorStop(1.0, '#437ab6'); + context.fillStyle = gradient; + context.fillRect(0, 0, 1, 32); + + const skyMap = new THREE.CanvasTexture(canvas); + skyMap.colorSpace = THREE.SRGBColorSpace; + + const sky = new THREE.Mesh( + new THREE.SphereGeometry(10), + new THREE.MeshBasicMaterial({ map: skyMap, side: THREE.BackSide }), + ); + scene.add(sky); + + // Texture + + const texture = new THREE.Data3DTexture( + new Uint8Array(INITIAL_CLOUD_SIZE * INITIAL_CLOUD_SIZE * INITIAL_CLOUD_SIZE).fill(0), + INITIAL_CLOUD_SIZE, + INITIAL_CLOUD_SIZE, + INITIAL_CLOUD_SIZE, + ); + texture.format = THREE.RedFormat; + texture.minFilter = THREE.LinearFilter; + texture.magFilter = THREE.LinearFilter; + texture.unpackAlignment = 1; + texture.needsUpdate = true; + + cloudTexture = texture; + + // Material + + const vertexShader = /* glsl */ ` + in vec3 position; + + uniform mat4 modelMatrix; + uniform mat4 modelViewMatrix; + uniform mat4 projectionMatrix; + uniform vec3 cameraPos; + + out vec3 vOrigin; + out vec3 vDirection; + + void main() { + vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); + + vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz; + vDirection = position - vOrigin; + + gl_Position = projectionMatrix * mvPosition; + } + `; + + const fragmentShader = /* glsl */ ` + precision highp float; + precision highp sampler3D; + + uniform mat4 modelViewMatrix; + uniform mat4 projectionMatrix; + + in vec3 vOrigin; + in vec3 vDirection; + + out vec4 color; + + uniform vec3 base; + uniform sampler3D map; + + uniform float threshold; + uniform float range; + uniform float opacity; + uniform float steps; + uniform float frame; + + uint wang_hash(uint seed) + { + seed = (seed ^ 61u) ^ (seed >> 16u); + seed *= 9u; + seed = seed ^ (seed >> 4u); + seed *= 0x27d4eb2du; + seed = seed ^ (seed >> 15u); + return seed; + } + + float randomFloat(inout uint seed) + { + return float(wang_hash(seed)) / 4294967296.; + } + + vec2 hitBox( vec3 orig, vec3 dir ) { + const vec3 box_min = vec3( - 0.5 ); + const vec3 box_max = vec3( 0.5 ); + vec3 inv_dir = 1.0 / dir; + vec3 tmin_tmp = ( box_min - orig ) * inv_dir; + vec3 tmax_tmp = ( box_max - orig ) * inv_dir; + vec3 tmin = min( tmin_tmp, tmax_tmp ); + vec3 tmax = max( tmin_tmp, tmax_tmp ); + float t0 = max( tmin.x, max( tmin.y, tmin.z ) ); + float t1 = min( tmax.x, min( tmax.y, tmax.z ) ); + return vec2( t0, t1 ); + } + + float sample1( vec3 p ) { + return texture( map, p ).r; + } + + float shading( vec3 coord ) { + float step = 0.01; + return sample1( coord + vec3( - step ) ) - sample1( coord + vec3( step ) ); + } + + vec4 linearToSRGB( in vec4 value ) { + return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); + } + + void main(){ + vec3 rayDir = normalize( vDirection ); + vec2 bounds = hitBox( vOrigin, rayDir ); + + if ( bounds.x > bounds.y ) discard; + + bounds.x = max( bounds.x, 0.0 ); + + vec3 p = vOrigin + bounds.x * rayDir; + vec3 inc = 1.0 / abs( rayDir ); + float delta = min( inc.x, min( inc.y, inc.z ) ); + delta /= steps; + + // Jitter + + // Nice little seed from + // https://blog.demofox.org/2020/05/25/casual-shadertoy-path-tracing-1-basic-camera-diffuse-emissive/ + uint seed = uint( gl_FragCoord.x ) * uint( 1973 ) + uint( gl_FragCoord.y ) * uint( 9277 ) + uint( frame ) * uint( 26699 ); + vec3 size = vec3( textureSize( map, 0 ) ); + float randNum = randomFloat( seed ) * 2.0 - 1.0; + p += rayDir * randNum * ( 1.0 / size ); + + // + + vec4 ac = vec4( base, 0.0 ); + + for ( float t = bounds.x; t < bounds.y; t += delta ) { + + float d = sample1( p + 0.5 ); + + d = smoothstep( threshold - range, threshold + range, d ) * opacity; + + float col = shading( p + 0.5 ) * 3.0 + ( ( p.x + p.y ) * 0.25 ) + 0.2; + + ac.rgb += ( 1.0 - ac.a ) * d * col; + + ac.a += ( 1.0 - ac.a ) * d; + + if ( ac.a >= 0.95 ) break; + + p += rayDir * delta; + + } + + color = linearToSRGB( ac ); + + if ( color.a == 0.0 ) discard; + + } + `; + + const geometry = new THREE.BoxGeometry(1, 1, 1); + const material = new THREE.RawShaderMaterial({ + glslVersion: THREE.GLSL3, + uniforms: { + base: { value: new THREE.Color(0x798aa0) }, + map: { value: texture }, + cameraPos: { value: new THREE.Vector3() }, + threshold: { value: 0.25 }, + opacity: { value: 0.25 }, + range: { value: 0.1 }, + steps: { value: 100 }, + frame: { value: 0 }, + }, + vertexShader, + fragmentShader, + side: THREE.BackSide, + transparent: true, + }); + + mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // + + const parameters = { + threshold: 0.25, + opacity: 0.25, + range: 0.1, + steps: 100, + }; + + function update() { + material.uniforms.threshold.value = parameters.threshold; + material.uniforms.opacity.value = parameters.opacity; + material.uniforms.range.value = parameters.range; + material.uniforms.steps.value = parameters.steps; + } + + const gui = new GUI(); + gui.add(parameters, 'threshold', 0, 1, 0.01).onChange(update); + gui.add(parameters, 'opacity', 0, 1, 0.01).onChange(update); + gui.add(parameters, 'range', 0, 1, 0.01).onChange(update); + gui.add(parameters, 'steps', 0, 200, 1).onChange(update); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +let curr = 0; +const countPerRow = 4; +const countPerSlice = countPerRow * countPerRow; +const sliceCount = 4; +const totalCount = sliceCount * countPerSlice; +const margins = 8; + +const perElementPaddedSize = (INITIAL_CLOUD_SIZE - margins) / countPerRow; +const perElementSize = Math.floor((INITIAL_CLOUD_SIZE - 1) / countPerRow); + +function animate() { + requestAnimationFrame(animate); + + const time = performance.now(); + if (time - prevTime > 1500.0 && curr < totalCount) { + const position = new THREE.Vector3( + Math.floor(curr % countPerRow) * perElementSize + margins * 0.5, + Math.floor((curr % countPerSlice) / countPerRow) * perElementSize + margins * 0.5, + Math.floor(curr / countPerSlice) * perElementSize + margins * 0.5, + ).floor(); + + const maxDimension = perElementPaddedSize - 1; + const box = new THREE.Box3( + new THREE.Vector3(0, 0, 0), + new THREE.Vector3(maxDimension, maxDimension, maxDimension), + ); + const scaleFactor = (Math.random() + 0.5) * 0.5; + const source = generateCloudTexture(perElementPaddedSize, scaleFactor); + + renderer.copyTextureToTexture3D(box, position, source, cloudTexture); + + prevTime = time; + + curr++; + } + + mesh.material.uniforms.cameraPos.value.copy(camera.position); + // mesh.rotation.y = - performance.now() / 7500; + + mesh.material.uniforms.frame.value++; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl2_multiple_rendertargets.ts b/examples-testing/examples/webgl2_multiple_rendertargets.ts new file mode 100644 index 000000000..cc1082731 --- /dev/null +++ b/examples-testing/examples/webgl2_multiple_rendertargets.ts @@ -0,0 +1,139 @@ +import * as THREE from 'three'; + +import WebGL from 'three/addons/capabilities/WebGL.js'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let camera, scene, renderer, controls; +let renderTarget; +let postScene, postCamera; + +const parameters = { + samples: 4, + wireframe: false, +}; + +const gui = new GUI(); +gui.add(parameters, 'samples', 0, 4).step(1); +gui.add(parameters, 'wireframe'); +gui.onChange(render); + +init(); + +function init() { + if (WebGL.isWebGL2Available() === false) { + document.body.appendChild(WebGL.getWebGL2ErrorMessage()); + return; + } + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + // Create a multi render target with Float buffers + + renderTarget = new THREE.WebGLMultipleRenderTargets( + window.innerWidth * window.devicePixelRatio, + window.innerHeight * window.devicePixelRatio, + 2, + ); + + for (let i = 0, il = renderTarget.texture.length; i < il; i++) { + renderTarget.texture[i].minFilter = THREE.NearestFilter; + renderTarget.texture[i].magFilter = THREE.NearestFilter; + } + + // Name our G-Buffer attachments for debugging + + renderTarget.texture[0].name = 'diffuse'; + renderTarget.texture[1].name = 'normal'; + + // Scene setup + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x222222); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 50); + camera.position.z = 4; + + const loader = new THREE.TextureLoader(); + + const diffuse = loader.load('textures/hardwood2_diffuse.jpg', render); + diffuse.wrapS = THREE.RepeatWrapping; + diffuse.wrapT = THREE.RepeatWrapping; + diffuse.colorSpace = THREE.SRGBColorSpace; + + scene.add( + new THREE.Mesh( + new THREE.TorusKnotGeometry(1, 0.3, 128, 32), + new THREE.RawShaderMaterial({ + vertexShader: document.querySelector('#gbuffer-vert').textContent.trim(), + fragmentShader: document.querySelector('#gbuffer-frag').textContent.trim(), + uniforms: { + tDiffuse: { value: diffuse }, + repeat: { value: new THREE.Vector2(5, 0.5) }, + }, + glslVersion: THREE.GLSL3, + }), + ), + ); + + // PostProcessing setup + + postScene = new THREE.Scene(); + postCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); + + postScene.add( + new THREE.Mesh( + new THREE.PlaneGeometry(2, 2), + new THREE.RawShaderMaterial({ + vertexShader: document.querySelector('#render-vert').textContent.trim(), + fragmentShader: document.querySelector('#render-frag').textContent.trim(), + uniforms: { + tDiffuse: { value: renderTarget.texture[0] }, + tNormal: { value: renderTarget.texture[1] }, + }, + glslVersion: THREE.GLSL3, + }), + ), + ); + + // Controls + + controls = new OrbitControls(camera, renderer.domElement); + controls.addEventListener('change', render); + //controls.enableZoom = false; + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + const dpr = renderer.getPixelRatio(); + renderTarget.setSize(window.innerWidth * dpr, window.innerHeight * dpr); + + render(); +} + +function render() { + renderTarget.samples = parameters.samples; + + scene.traverse(function (child) { + if (child.material !== undefined) { + child.material.wireframe = parameters.wireframe; + } + }); + + // render scene into target + renderer.setRenderTarget(renderTarget); + renderer.render(scene, camera); + + // render post FX + renderer.setRenderTarget(null); + renderer.render(postScene, postCamera); +} diff --git a/examples-testing/examples/webgl2_multisampled_renderbuffers.ts b/examples-testing/examples/webgl2_multisampled_renderbuffers.ts new file mode 100644 index 000000000..c3197be2a --- /dev/null +++ b/examples-testing/examples/webgl2_multisampled_renderbuffers.ts @@ -0,0 +1,139 @@ +import * as THREE from 'three'; + +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; +import WebGL from 'three/addons/capabilities/WebGL.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let camera, renderer, group, container; + +let composer1, composer2; + +const params = { + animate: true, +}; + +init(); + +function init() { + if (WebGL.isWebGL2Available() === false) { + document.body.appendChild(WebGL.getWebGL2ErrorMessage()); + return; + } + + container = document.getElementById('container'); + + camera = new THREE.PerspectiveCamera(45, container.offsetWidth / container.offsetHeight, 10, 2000); + camera.position.z = 500; + + const scene = new THREE.Scene(); + scene.background = new THREE.Color(0xffffff); + scene.fog = new THREE.Fog(0xcccccc, 100, 1500); + + // + + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x222222, 5); + hemiLight.position.set(1, 1, 1); + scene.add(hemiLight); + + // + + group = new THREE.Group(); + + const geometry = new THREE.SphereGeometry(10, 64, 40); + const material = new THREE.MeshLambertMaterial({ + color: 0xee0808, + polygonOffset: true, + polygonOffsetFactor: 1, // positive value pushes polygon further away + polygonOffsetUnits: 1, + }); + const material2 = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }); + + for (let i = 0; i < 50; i++) { + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = Math.random() * 600 - 300; + mesh.position.y = Math.random() * 600 - 300; + mesh.position.z = Math.random() * 600 - 300; + mesh.rotation.x = Math.random(); + mesh.rotation.z = Math.random(); + mesh.scale.setScalar(Math.random() * 5 + 5); + group.add(mesh); + + const mesh2 = new THREE.Mesh(geometry, material2); + mesh2.position.copy(mesh.position); + mesh2.rotation.copy(mesh.rotation); + mesh2.scale.copy(mesh.scale); + group.add(mesh2); + } + + scene.add(group); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(container.offsetWidth, container.offsetHeight); + renderer.autoClear = false; + container.appendChild(renderer.domElement); + + // + + const size = renderer.getDrawingBufferSize(new THREE.Vector2()); + const renderTarget = new THREE.WebGLRenderTarget(size.width, size.height, { samples: 4 }); + + const renderPass = new RenderPass(scene, camera); + const outputPass = new OutputPass(); + + // + + composer1 = new EffectComposer(renderer); + composer1.addPass(renderPass); + composer1.addPass(outputPass); + + // + + composer2 = new EffectComposer(renderer, renderTarget); + composer2.addPass(renderPass); + composer2.addPass(outputPass); + + // + + const gui = new GUI(); + gui.add(params, 'animate'); + + // + + window.addEventListener('resize', onWindowResize); + + animate(); +} + +function onWindowResize() { + camera.aspect = container.offsetWidth / container.offsetHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(container.offsetWidth, container.offsetHeight); + composer1.setSize(container.offsetWidth, container.offsetHeight); + composer2.setSize(container.offsetWidth, container.offsetHeight); +} + +function animate() { + requestAnimationFrame(animate); + + const halfWidth = container.offsetWidth / 2; + + if (params.animate) { + group.rotation.y += 0.002; + } + + renderer.setScissorTest(true); + + renderer.setScissor(0, 0, halfWidth - 1, container.offsetHeight); + composer1.render(); + + renderer.setScissor(halfWidth, 0, halfWidth, container.offsetHeight); + composer2.render(); + + renderer.setScissorTest(false); +} diff --git a/examples-testing/examples/webgl2_texture2darray_compressed.ts b/examples-testing/examples/webgl2_texture2darray_compressed.ts new file mode 100644 index 000000000..bf86320c0 --- /dev/null +++ b/examples-testing/examples/webgl2_texture2darray_compressed.ts @@ -0,0 +1,96 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'; + +import WebGL from 'three/addons/capabilities/WebGL.js'; + +if (WebGL.isWebGL2Available() === false) { + document.body.appendChild(WebGL.getWebGL2ErrorMessage()); +} + +let camera, scene, mesh, renderer, stats, clock; + +const planeWidth = 50; +const planeHeight = 25; + +let depthStep = 1; + +init(); +animate(); + +function init() { + const container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000); + camera.position.z = 70; + + scene = new THREE.Scene(); + + // + clock = new THREE.Clock(); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + // + + const ktx2Loader = new KTX2Loader(); + ktx2Loader.setTranscoderPath('jsm/libs/basis/'); + ktx2Loader.detectSupport(renderer); + + ktx2Loader.load('textures/spiritedaway.ktx2', function (texturearray) { + const material = new THREE.ShaderMaterial({ + uniforms: { + diffuse: { value: texturearray }, + depth: { value: 55 }, + size: { value: new THREE.Vector2(planeWidth, planeHeight) }, + }, + vertexShader: document.getElementById('vs').textContent.trim(), + fragmentShader: document.getElementById('fs').textContent.trim(), + glslVersion: THREE.GLSL3, + }); + + const geometry = new THREE.PlaneGeometry(planeWidth, planeHeight); + + mesh = new THREE.Mesh(geometry, material); + + scene.add(mesh); + }); + + stats = new Stats(); + container.appendChild(stats.dom); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + if (mesh) { + const delta = clock.getDelta() * 10; + + depthStep += delta; + + const value = depthStep % 5; + + mesh.material.uniforms['depth'].value = value; + } + + render(); + stats.update(); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl2_ubo.ts b/examples-testing/examples/webgl2_ubo.ts new file mode 100644 index 000000000..e296fdced --- /dev/null +++ b/examples-testing/examples/webgl2_ubo.ts @@ -0,0 +1,146 @@ +import * as THREE from 'three'; + +import WebGL from 'three/addons/capabilities/WebGL.js'; + +let camera, scene, renderer, clock; + +init(); +animate(); + +function init() { + if (WebGL.isWebGL2Available() === false) { + document.body.appendChild(WebGL.getWebGL2ErrorMessage()); + return; + } + + const container = document.getElementById('container'); + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(0, 0, 25); + + scene = new THREE.Scene(); + camera.lookAt(scene.position); + + clock = new THREE.Clock(); + + // geometry + + const geometry1 = new THREE.TetrahedronGeometry(); + const geometry2 = new THREE.BoxGeometry(); + + // texture + + const texture = new THREE.TextureLoader().load('textures/crate.gif'); + texture.colorSpace = THREE.SRGBColorSpace; + + // uniforms groups + + // Camera and lighting related data are perfect examples of using UBOs since you have to store these + // data just once. They can be shared across all shader programs. + + const cameraUniformsGroup = new THREE.UniformsGroup(); + cameraUniformsGroup.setName('ViewData'); + cameraUniformsGroup.add(new THREE.Uniform(camera.projectionMatrix)); // projection matrix + cameraUniformsGroup.add(new THREE.Uniform(camera.matrixWorldInverse)); // view matrix + + const lightingUniformsGroup = new THREE.UniformsGroup(); + lightingUniformsGroup.setName('LightingData'); + lightingUniformsGroup.add(new THREE.Uniform(new THREE.Vector3(0, 0, 10))); // light position + lightingUniformsGroup.add(new THREE.Uniform(new THREE.Color(0x7c7c7c))); // ambient color + lightingUniformsGroup.add(new THREE.Uniform(new THREE.Color(0xd5d5d5))); // diffuse color + lightingUniformsGroup.add(new THREE.Uniform(new THREE.Color(0xe7e7e7))); // specular color + lightingUniformsGroup.add(new THREE.Uniform(64)); // shininess + + // materials + + const material1 = new THREE.RawShaderMaterial({ + uniforms: { + modelMatrix: { value: null }, + normalMatrix: { value: null }, + color: { value: null }, + }, + vertexShader: document.getElementById('vertexShader1').textContent, + fragmentShader: document.getElementById('fragmentShader1').textContent, + glslVersion: THREE.GLSL3, + }); + + const material2 = new THREE.RawShaderMaterial({ + uniforms: { + modelMatrix: { value: null }, + diffuseMap: { value: null }, + }, + vertexShader: document.getElementById('vertexShader2').textContent, + fragmentShader: document.getElementById('fragmentShader2').textContent, + glslVersion: THREE.GLSL3, + }); + + // meshes + + for (let i = 0; i < 200; i++) { + let mesh; + + if (i % 2 === 0) { + mesh = new THREE.Mesh(geometry1, material1.clone()); + + mesh.material.uniformsGroups = [cameraUniformsGroup, lightingUniformsGroup]; + mesh.material.uniforms.modelMatrix.value = mesh.matrixWorld; + mesh.material.uniforms.normalMatrix.value = mesh.normalMatrix; + mesh.material.uniforms.color.value = new THREE.Color(0xffffff * Math.random()); + } else { + mesh = new THREE.Mesh(geometry2, material2.clone()); + + mesh.material.uniformsGroups = [cameraUniformsGroup, lightingUniformsGroup]; + mesh.material.uniforms.modelMatrix.value = mesh.matrixWorld; + mesh.material.uniforms.diffuseMap.value = texture; + } + + scene.add(mesh); + + const s = 1 + Math.random() * 0.5; + + mesh.scale.x = s; + mesh.scale.y = s; + mesh.scale.z = s; + + mesh.rotation.x = Math.random() * Math.PI; + mesh.rotation.y = Math.random() * Math.PI; + mesh.rotation.z = Math.random() * Math.PI; + + mesh.position.x = Math.random() * 40 - 20; + mesh.position.y = Math.random() * 40 - 20; + mesh.position.z = Math.random() * 20 - 10; + } + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + window.addEventListener('resize', onWindowResize, false); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + const delta = clock.getDelta(); + + scene.traverse(function (child) { + if (child.isMesh) { + child.rotation.x += delta * 0.5; + child.rotation.y += delta * 0.3; + } + }); + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl2_volume_cloud.ts b/examples-testing/examples/webgl2_volume_cloud.ts new file mode 100644 index 000000000..bc5473299 --- /dev/null +++ b/examples-testing/examples/webgl2_volume_cloud.ts @@ -0,0 +1,286 @@ +import * as THREE from 'three'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { ImprovedNoise } from 'three/addons/math/ImprovedNoise.js'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import WebGL from 'three/addons/capabilities/WebGL.js'; + +if (WebGL.isWebGL2Available() === false) { + document.body.appendChild(WebGL.getWebGL2ErrorMessage()); +} + +let renderer, scene, camera; +let mesh; + +init(); +animate(); + +function init() { + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(0, 0, 1.5); + + new OrbitControls(camera, renderer.domElement); + + // Sky + + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 32; + + const context = canvas.getContext('2d'); + const gradient = context.createLinearGradient(0, 0, 0, 32); + gradient.addColorStop(0.0, '#014a84'); + gradient.addColorStop(0.5, '#0561a0'); + gradient.addColorStop(1.0, '#437ab6'); + context.fillStyle = gradient; + context.fillRect(0, 0, 1, 32); + + const skyMap = new THREE.CanvasTexture(canvas); + skyMap.colorSpace = THREE.SRGBColorSpace; + + const sky = new THREE.Mesh( + new THREE.SphereGeometry(10), + new THREE.MeshBasicMaterial({ map: skyMap, side: THREE.BackSide }), + ); + scene.add(sky); + + // Texture + + const size = 128; + const data = new Uint8Array(size * size * size); + + let i = 0; + const scale = 0.05; + const perlin = new ImprovedNoise(); + const vector = new THREE.Vector3(); + + for (let z = 0; z < size; z++) { + for (let y = 0; y < size; y++) { + for (let x = 0; x < size; x++) { + const d = + 1.0 - + vector + .set(x, y, z) + .subScalar(size / 2) + .divideScalar(size) + .length(); + data[i] = (128 + 128 * perlin.noise((x * scale) / 1.5, y * scale, (z * scale) / 1.5)) * d * d; + i++; + } + } + } + + const texture = new THREE.Data3DTexture(data, size, size, size); + texture.format = THREE.RedFormat; + texture.minFilter = THREE.LinearFilter; + texture.magFilter = THREE.LinearFilter; + texture.unpackAlignment = 1; + texture.needsUpdate = true; + + // Material + + const vertexShader = /* glsl */ ` + in vec3 position; + + uniform mat4 modelMatrix; + uniform mat4 modelViewMatrix; + uniform mat4 projectionMatrix; + uniform vec3 cameraPos; + + out vec3 vOrigin; + out vec3 vDirection; + + void main() { + vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); + + vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz; + vDirection = position - vOrigin; + + gl_Position = projectionMatrix * mvPosition; + } + `; + + const fragmentShader = /* glsl */ ` + precision highp float; + precision highp sampler3D; + + uniform mat4 modelViewMatrix; + uniform mat4 projectionMatrix; + + in vec3 vOrigin; + in vec3 vDirection; + + out vec4 color; + + uniform vec3 base; + uniform sampler3D map; + + uniform float threshold; + uniform float range; + uniform float opacity; + uniform float steps; + uniform float frame; + + uint wang_hash(uint seed) + { + seed = (seed ^ 61u) ^ (seed >> 16u); + seed *= 9u; + seed = seed ^ (seed >> 4u); + seed *= 0x27d4eb2du; + seed = seed ^ (seed >> 15u); + return seed; + } + + float randomFloat(inout uint seed) + { + return float(wang_hash(seed)) / 4294967296.; + } + + vec2 hitBox( vec3 orig, vec3 dir ) { + const vec3 box_min = vec3( - 0.5 ); + const vec3 box_max = vec3( 0.5 ); + vec3 inv_dir = 1.0 / dir; + vec3 tmin_tmp = ( box_min - orig ) * inv_dir; + vec3 tmax_tmp = ( box_max - orig ) * inv_dir; + vec3 tmin = min( tmin_tmp, tmax_tmp ); + vec3 tmax = max( tmin_tmp, tmax_tmp ); + float t0 = max( tmin.x, max( tmin.y, tmin.z ) ); + float t1 = min( tmax.x, min( tmax.y, tmax.z ) ); + return vec2( t0, t1 ); + } + + float sample1( vec3 p ) { + return texture( map, p ).r; + } + + float shading( vec3 coord ) { + float step = 0.01; + return sample1( coord + vec3( - step ) ) - sample1( coord + vec3( step ) ); + } + + vec4 linearToSRGB( in vec4 value ) { + return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); + } + + void main(){ + vec3 rayDir = normalize( vDirection ); + vec2 bounds = hitBox( vOrigin, rayDir ); + + if ( bounds.x > bounds.y ) discard; + + bounds.x = max( bounds.x, 0.0 ); + + vec3 p = vOrigin + bounds.x * rayDir; + vec3 inc = 1.0 / abs( rayDir ); + float delta = min( inc.x, min( inc.y, inc.z ) ); + delta /= steps; + + // Jitter + + // Nice little seed from + // https://blog.demofox.org/2020/05/25/casual-shadertoy-path-tracing-1-basic-camera-diffuse-emissive/ + uint seed = uint( gl_FragCoord.x ) * uint( 1973 ) + uint( gl_FragCoord.y ) * uint( 9277 ) + uint( frame ) * uint( 26699 ); + vec3 size = vec3( textureSize( map, 0 ) ); + float randNum = randomFloat( seed ) * 2.0 - 1.0; + p += rayDir * randNum * ( 1.0 / size ); + + // + + vec4 ac = vec4( base, 0.0 ); + + for ( float t = bounds.x; t < bounds.y; t += delta ) { + + float d = sample1( p + 0.5 ); + + d = smoothstep( threshold - range, threshold + range, d ) * opacity; + + float col = shading( p + 0.5 ) * 3.0 + ( ( p.x + p.y ) * 0.25 ) + 0.2; + + ac.rgb += ( 1.0 - ac.a ) * d * col; + + ac.a += ( 1.0 - ac.a ) * d; + + if ( ac.a >= 0.95 ) break; + + p += rayDir * delta; + + } + + color = linearToSRGB( ac ); + + if ( color.a == 0.0 ) discard; + + } + `; + + const geometry = new THREE.BoxGeometry(1, 1, 1); + const material = new THREE.RawShaderMaterial({ + glslVersion: THREE.GLSL3, + uniforms: { + base: { value: new THREE.Color(0x798aa0) }, + map: { value: texture }, + cameraPos: { value: new THREE.Vector3() }, + threshold: { value: 0.25 }, + opacity: { value: 0.25 }, + range: { value: 0.1 }, + steps: { value: 100 }, + frame: { value: 0 }, + }, + vertexShader, + fragmentShader, + side: THREE.BackSide, + transparent: true, + }); + + mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // + + const parameters = { + threshold: 0.25, + opacity: 0.25, + range: 0.1, + steps: 100, + }; + + function update() { + material.uniforms.threshold.value = parameters.threshold; + material.uniforms.opacity.value = parameters.opacity; + material.uniforms.range.value = parameters.range; + material.uniforms.steps.value = parameters.steps; + } + + const gui = new GUI(); + gui.add(parameters, 'threshold', 0, 1, 0.01).onChange(update); + gui.add(parameters, 'opacity', 0, 1, 0.01).onChange(update); + gui.add(parameters, 'range', 0, 1, 0.01).onChange(update); + gui.add(parameters, 'steps', 0, 200, 1).onChange(update); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + mesh.material.uniforms.cameraPos.value.copy(camera.position); + mesh.rotation.y = -performance.now() / 7500; + + mesh.material.uniforms.frame.value++; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl2_volume_instancing.ts b/examples-testing/examples/webgl2_volume_instancing.ts new file mode 100644 index 000000000..89328698d --- /dev/null +++ b/examples-testing/examples/webgl2_volume_instancing.ts @@ -0,0 +1,198 @@ +import * as THREE from 'three'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { VOXLoader, VOXData3DTexture } from 'three/addons/loaders/VOXLoader.js'; + +import WebGL from 'three/addons/capabilities/WebGL.js'; + +if (WebGL.isWebGL2Available() === false) { + document.body.appendChild(WebGL.getWebGL2ErrorMessage()); +} + +let renderer, scene, camera; +let controls; + +init(); +animate(); + +function init() { + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000); + camera.position.set(0, 0, 4); + + controls = new OrbitControls(camera, renderer.domElement); + controls.autoRotate = true; + controls.autoRotateSpeed = -1.0; + controls.enableDamping = true; + + // Material + + const vertexShader = /* glsl */ ` + in vec3 position; + in mat4 instanceMatrix; + + uniform mat4 modelMatrix; + uniform mat4 modelViewMatrix; + uniform mat4 projectionMatrix; + uniform vec3 cameraPos; + + out vec3 vOrigin; + out vec3 vDirection; + + void main() { + vec4 mvPosition = modelViewMatrix * instanceMatrix * vec4( position, 1.0 ); + + vOrigin = vec3( inverse( instanceMatrix * modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz; + vDirection = position - vOrigin; + + gl_Position = projectionMatrix * mvPosition; + } + `; + + const fragmentShader = /* glsl */ ` + precision highp float; + precision highp sampler3D; + + uniform mat4 modelViewMatrix; + uniform mat4 projectionMatrix; + + in vec3 vOrigin; + in vec3 vDirection; + + out vec4 color; + + uniform sampler3D map; + + uniform float threshold; + uniform float steps; + + vec2 hitBox( vec3 orig, vec3 dir ) { + const vec3 box_min = vec3( - 0.5 ); + const vec3 box_max = vec3( 0.5 ); + vec3 inv_dir = 1.0 / dir; + vec3 tmin_tmp = ( box_min - orig ) * inv_dir; + vec3 tmax_tmp = ( box_max - orig ) * inv_dir; + vec3 tmin = min( tmin_tmp, tmax_tmp ); + vec3 tmax = max( tmin_tmp, tmax_tmp ); + float t0 = max( tmin.x, max( tmin.y, tmin.z ) ); + float t1 = min( tmax.x, min( tmax.y, tmax.z ) ); + return vec2( t0, t1 ); + } + + float sample1( vec3 p ) { + return texture( map, p ).r; + } + + #define epsilon .0001 + + vec3 normal( vec3 coord ) { + if ( coord.x < epsilon ) return vec3( 1.0, 0.0, 0.0 ); + if ( coord.y < epsilon ) return vec3( 0.0, 1.0, 0.0 ); + if ( coord.z < epsilon ) return vec3( 0.0, 0.0, 1.0 ); + if ( coord.x > 1.0 - epsilon ) return vec3( - 1.0, 0.0, 0.0 ); + if ( coord.y > 1.0 - epsilon ) return vec3( 0.0, - 1.0, 0.0 ); + if ( coord.z > 1.0 - epsilon ) return vec3( 0.0, 0.0, - 1.0 ); + + float step = 0.01; + float x = sample1( coord + vec3( - step, 0.0, 0.0 ) ) - sample1( coord + vec3( step, 0.0, 0.0 ) ); + float y = sample1( coord + vec3( 0.0, - step, 0.0 ) ) - sample1( coord + vec3( 0.0, step, 0.0 ) ); + float z = sample1( coord + vec3( 0.0, 0.0, - step ) ) - sample1( coord + vec3( 0.0, 0.0, step ) ); + + return normalize( vec3( x, y, z ) ); + } + + void main(){ + + vec3 rayDir = normalize( vDirection ); + vec2 bounds = hitBox( vOrigin, rayDir ); + + if ( bounds.x > bounds.y ) discard; + + bounds.x = max( bounds.x, 0.0 ); + + vec3 p = vOrigin + bounds.x * rayDir; + vec3 inc = 1.0 / abs( rayDir ); + float delta = min( inc.x, min( inc.y, inc.z ) ); + delta /= 50.0; + + for ( float t = bounds.x; t < bounds.y; t += delta ) { + + float d = sample1( p + 0.5 ); + + if ( d > 0.5 ) { + + color.rgb = p * 2.0; // normal( p + 0.5 ); // * 0.5 + ( p * 1.5 + 0.25 ); + color.a = 1.; + break; + + } + + p += rayDir * delta; + + } + + if ( color.a == 0.0 ) discard; + + } + `; + + const loader = new VOXLoader(); + loader.load('models/vox/menger.vox', function (chunks) { + for (let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; + + const geometry = new THREE.BoxGeometry(1, 1, 1); + const material = new THREE.RawShaderMaterial({ + glslVersion: THREE.GLSL3, + uniforms: { + map: { value: new VOXData3DTexture(chunk) }, + cameraPos: { value: new THREE.Vector3() }, + }, + vertexShader, + fragmentShader, + side: THREE.BackSide, + }); + + const mesh = new THREE.InstancedMesh(geometry, material, 50000); + mesh.onBeforeRender = function () { + this.material.uniforms.cameraPos.value.copy(camera.position); + }; + + const transform = new THREE.Object3D(); + + for (let i = 0; i < mesh.count; i++) { + transform.position.random().subScalar(0.5).multiplyScalar(150); + transform.rotation.x = Math.random() * Math.PI; + transform.rotation.y = Math.random() * Math.PI; + transform.rotation.z = Math.random() * Math.PI; + transform.updateMatrix(); + + mesh.setMatrixAt(i, transform.matrix); + } + + scene.add(mesh); + } + }); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + controls.update(); + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl2_volume_perlin.ts b/examples-testing/examples/webgl2_volume_perlin.ts new file mode 100644 index 000000000..a75328f92 --- /dev/null +++ b/examples-testing/examples/webgl2_volume_perlin.ts @@ -0,0 +1,215 @@ +import * as THREE from 'three'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { ImprovedNoise } from 'three/addons/math/ImprovedNoise.js'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import WebGL from 'three/addons/capabilities/WebGL.js'; + +if (WebGL.isWebGL2Available() === false) { + document.body.appendChild(WebGL.getWebGL2ErrorMessage()); +} + +let renderer, scene, camera; +let mesh; + +init(); +animate(); + +function init() { + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(0, 0, 2); + + new OrbitControls(camera, renderer.domElement); + + // Texture + + const size = 128; + const data = new Uint8Array(size * size * size); + + let i = 0; + const perlin = new ImprovedNoise(); + const vector = new THREE.Vector3(); + + for (let z = 0; z < size; z++) { + for (let y = 0; y < size; y++) { + for (let x = 0; x < size; x++) { + vector.set(x, y, z).divideScalar(size); + + const d = perlin.noise(vector.x * 6.5, vector.y * 6.5, vector.z * 6.5); + + data[i++] = d * 128 + 128; + } + } + } + + const texture = new THREE.Data3DTexture(data, size, size, size); + texture.format = THREE.RedFormat; + texture.minFilter = THREE.LinearFilter; + texture.magFilter = THREE.LinearFilter; + texture.unpackAlignment = 1; + texture.needsUpdate = true; + + // Material + + const vertexShader = /* glsl */ ` + in vec3 position; + + uniform mat4 modelMatrix; + uniform mat4 modelViewMatrix; + uniform mat4 projectionMatrix; + uniform vec3 cameraPos; + + out vec3 vOrigin; + out vec3 vDirection; + + void main() { + vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); + + vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz; + vDirection = position - vOrigin; + + gl_Position = projectionMatrix * mvPosition; + } + `; + + const fragmentShader = /* glsl */ ` + precision highp float; + precision highp sampler3D; + + uniform mat4 modelViewMatrix; + uniform mat4 projectionMatrix; + + in vec3 vOrigin; + in vec3 vDirection; + + out vec4 color; + + uniform sampler3D map; + + uniform float threshold; + uniform float steps; + + vec2 hitBox( vec3 orig, vec3 dir ) { + const vec3 box_min = vec3( - 0.5 ); + const vec3 box_max = vec3( 0.5 ); + vec3 inv_dir = 1.0 / dir; + vec3 tmin_tmp = ( box_min - orig ) * inv_dir; + vec3 tmax_tmp = ( box_max - orig ) * inv_dir; + vec3 tmin = min( tmin_tmp, tmax_tmp ); + vec3 tmax = max( tmin_tmp, tmax_tmp ); + float t0 = max( tmin.x, max( tmin.y, tmin.z ) ); + float t1 = min( tmax.x, min( tmax.y, tmax.z ) ); + return vec2( t0, t1 ); + } + + float sample1( vec3 p ) { + return texture( map, p ).r; + } + + #define epsilon .0001 + + vec3 normal( vec3 coord ) { + if ( coord.x < epsilon ) return vec3( 1.0, 0.0, 0.0 ); + if ( coord.y < epsilon ) return vec3( 0.0, 1.0, 0.0 ); + if ( coord.z < epsilon ) return vec3( 0.0, 0.0, 1.0 ); + if ( coord.x > 1.0 - epsilon ) return vec3( - 1.0, 0.0, 0.0 ); + if ( coord.y > 1.0 - epsilon ) return vec3( 0.0, - 1.0, 0.0 ); + if ( coord.z > 1.0 - epsilon ) return vec3( 0.0, 0.0, - 1.0 ); + + float step = 0.01; + float x = sample1( coord + vec3( - step, 0.0, 0.0 ) ) - sample1( coord + vec3( step, 0.0, 0.0 ) ); + float y = sample1( coord + vec3( 0.0, - step, 0.0 ) ) - sample1( coord + vec3( 0.0, step, 0.0 ) ); + float z = sample1( coord + vec3( 0.0, 0.0, - step ) ) - sample1( coord + vec3( 0.0, 0.0, step ) ); + + return normalize( vec3( x, y, z ) ); + } + + void main(){ + + vec3 rayDir = normalize( vDirection ); + vec2 bounds = hitBox( vOrigin, rayDir ); + + if ( bounds.x > bounds.y ) discard; + + bounds.x = max( bounds.x, 0.0 ); + + vec3 p = vOrigin + bounds.x * rayDir; + vec3 inc = 1.0 / abs( rayDir ); + float delta = min( inc.x, min( inc.y, inc.z ) ); + delta /= steps; + + for ( float t = bounds.x; t < bounds.y; t += delta ) { + + float d = sample1( p + 0.5 ); + + if ( d > threshold ) { + + color.rgb = normal( p + 0.5 ) * 0.5 + ( p * 1.5 + 0.25 ); + color.a = 1.; + break; + + } + + p += rayDir * delta; + + } + + if ( color.a == 0.0 ) discard; + + } + `; + + const geometry = new THREE.BoxGeometry(1, 1, 1); + const material = new THREE.RawShaderMaterial({ + glslVersion: THREE.GLSL3, + uniforms: { + map: { value: texture }, + cameraPos: { value: new THREE.Vector3() }, + threshold: { value: 0.6 }, + steps: { value: 200 }, + }, + vertexShader, + fragmentShader, + side: THREE.BackSide, + }); + + mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // + + const parameters = { threshold: 0.6, steps: 200 }; + + function update() { + material.uniforms.threshold.value = parameters.threshold; + material.uniforms.steps.value = parameters.steps; + } + + const gui = new GUI(); + gui.add(parameters, 'threshold', 0, 1, 0.01).onChange(update); + gui.add(parameters, 'steps', 0, 300, 1).onChange(update); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + mesh.material.uniforms.cameraPos.value.copy(camera.position); + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_animation_keyframes.ts b/examples-testing/examples/webgl_animation_keyframes.ts new file mode 100644 index 000000000..22dd961e4 --- /dev/null +++ b/examples-testing/examples/webgl_animation_keyframes.ts @@ -0,0 +1,82 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js'; + +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; +import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'; + +let mixer; + +const clock = new THREE.Clock(); +const container = document.getElementById('container'); + +const stats = new Stats(); +container.appendChild(stats.dom); + +const renderer = new THREE.WebGLRenderer({ antialias: true }); +renderer.setPixelRatio(window.devicePixelRatio); +renderer.setSize(window.innerWidth, window.innerHeight); +container.appendChild(renderer.domElement); + +const pmremGenerator = new THREE.PMREMGenerator(renderer); + +const scene = new THREE.Scene(); +scene.background = new THREE.Color(0xbfe3dd); +scene.environment = pmremGenerator.fromScene(new RoomEnvironment(renderer), 0.04).texture; + +const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 100); +camera.position.set(5, 2, 8); + +const controls = new OrbitControls(camera, renderer.domElement); +controls.target.set(0, 0.5, 0); +controls.update(); +controls.enablePan = false; +controls.enableDamping = true; + +const dracoLoader = new DRACOLoader(); +dracoLoader.setDecoderPath('jsm/libs/draco/gltf/'); + +const loader = new GLTFLoader(); +loader.setDRACOLoader(dracoLoader); +loader.load( + 'models/gltf/LittlestTokyo.glb', + function (gltf) { + const model = gltf.scene; + model.position.set(1, 1, 0); + model.scale.set(0.01, 0.01, 0.01); + scene.add(model); + + mixer = new THREE.AnimationMixer(model); + mixer.clipAction(gltf.animations[0]).play(); + + animate(); + }, + undefined, + function (e) { + console.error(e); + }, +); + +window.onresize = function () { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +}; + +function animate() { + requestAnimationFrame(animate); + + const delta = clock.getDelta(); + + mixer.update(delta); + + controls.update(); + + stats.update(); + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_animation_multiple.ts b/examples-testing/examples/webgl_animation_multiple.ts new file mode 100644 index 000000000..8f9934099 --- /dev/null +++ b/examples-testing/examples/webgl_animation_multiple.ts @@ -0,0 +1,104 @@ +import * as THREE from 'three'; + +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; +import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.js'; + +let camera, scene, renderer; +let clock; + +const mixers = []; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.set(2, 3, -6); + camera.lookAt(0, 1, 0); + + clock = new THREE.Clock(); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xa0a0a0); + scene.fog = new THREE.Fog(0xa0a0a0, 10, 50); + + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x8d8d8d, 3); + hemiLight.position.set(0, 20, 0); + scene.add(hemiLight); + + const dirLight = new THREE.DirectionalLight(0xffffff, 3); + dirLight.position.set(-3, 10, -10); + dirLight.castShadow = true; + dirLight.shadow.camera.top = 4; + dirLight.shadow.camera.bottom = -4; + dirLight.shadow.camera.left = -4; + dirLight.shadow.camera.right = 4; + dirLight.shadow.camera.near = 0.1; + dirLight.shadow.camera.far = 40; + scene.add(dirLight); + + // scene.add( new THREE.CameraHelper( dirLight.shadow.camera ) ); + + // ground + + const mesh = new THREE.Mesh( + new THREE.PlaneGeometry(200, 200), + new THREE.MeshPhongMaterial({ color: 0xcbcbcb, depthWrite: false }), + ); + mesh.rotation.x = -Math.PI / 2; + mesh.receiveShadow = true; + scene.add(mesh); + + const loader = new GLTFLoader(); + loader.load('models/gltf/Soldier.glb', function (gltf) { + gltf.scene.traverse(function (object) { + if (object.isMesh) object.castShadow = true; + }); + + const model1 = SkeletonUtils.clone(gltf.scene); + const model2 = SkeletonUtils.clone(gltf.scene); + const model3 = SkeletonUtils.clone(gltf.scene); + + const mixer1 = new THREE.AnimationMixer(model1); + const mixer2 = new THREE.AnimationMixer(model2); + const mixer3 = new THREE.AnimationMixer(model3); + + mixer1.clipAction(gltf.animations[0]).play(); // idle + mixer2.clipAction(gltf.animations[1]).play(); // run + mixer3.clipAction(gltf.animations[3]).play(); // walk + + model1.position.x = -2; + model2.position.x = 0; + model3.position.x = 2; + + scene.add(model1, model2, model3); + mixers.push(mixer1, mixer2, mixer3); + + animate(); + }); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + document.body.appendChild(renderer.domElement); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + const delta = clock.getDelta(); + + for (const mixer of mixers) mixer.update(delta); + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_animation_skinning_morph.ts b/examples-testing/examples/webgl_animation_skinning_morph.ts new file mode 100644 index 000000000..6aa1368d4 --- /dev/null +++ b/examples-testing/examples/webgl_animation_skinning_morph.ts @@ -0,0 +1,189 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; + +let container, stats, clock, gui, mixer, actions, activeAction, previousAction; +let camera, scene, renderer, model, face; + +const api = { state: 'Walking' }; + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.25, 100); + camera.position.set(-5, 3, 10); + camera.lookAt(0, 2, 0); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xe0e0e0); + scene.fog = new THREE.Fog(0xe0e0e0, 20, 100); + + clock = new THREE.Clock(); + + // lights + + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x8d8d8d, 3); + hemiLight.position.set(0, 20, 0); + scene.add(hemiLight); + + const dirLight = new THREE.DirectionalLight(0xffffff, 3); + dirLight.position.set(0, 20, 10); + scene.add(dirLight); + + // ground + + const mesh = new THREE.Mesh( + new THREE.PlaneGeometry(2000, 2000), + new THREE.MeshPhongMaterial({ color: 0xcbcbcb, depthWrite: false }), + ); + mesh.rotation.x = -Math.PI / 2; + scene.add(mesh); + + const grid = new THREE.GridHelper(200, 40, 0x000000, 0x000000); + grid.material.opacity = 0.2; + grid.material.transparent = true; + scene.add(grid); + + // model + + const loader = new GLTFLoader(); + loader.load( + 'models/gltf/RobotExpressive/RobotExpressive.glb', + function (gltf) { + model = gltf.scene; + scene.add(model); + + createGUI(model, gltf.animations); + }, + undefined, + function (e) { + console.error(e); + }, + ); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + window.addEventListener('resize', onWindowResize); + + // stats + stats = new Stats(); + container.appendChild(stats.dom); +} + +function createGUI(model, animations) { + const states = ['Idle', 'Walking', 'Running', 'Dance', 'Death', 'Sitting', 'Standing']; + const emotes = ['Jump', 'Yes', 'No', 'Wave', 'Punch', 'ThumbsUp']; + + gui = new GUI(); + + mixer = new THREE.AnimationMixer(model); + + actions = {}; + + for (let i = 0; i < animations.length; i++) { + const clip = animations[i]; + const action = mixer.clipAction(clip); + actions[clip.name] = action; + + if (emotes.indexOf(clip.name) >= 0 || states.indexOf(clip.name) >= 4) { + action.clampWhenFinished = true; + action.loop = THREE.LoopOnce; + } + } + + // states + + const statesFolder = gui.addFolder('States'); + + const clipCtrl = statesFolder.add(api, 'state').options(states); + + clipCtrl.onChange(function () { + fadeToAction(api.state, 0.5); + }); + + statesFolder.open(); + + // emotes + + const emoteFolder = gui.addFolder('Emotes'); + + function createEmoteCallback(name) { + api[name] = function () { + fadeToAction(name, 0.2); + + mixer.addEventListener('finished', restoreState); + }; + + emoteFolder.add(api, name); + } + + function restoreState() { + mixer.removeEventListener('finished', restoreState); + + fadeToAction(api.state, 0.2); + } + + for (let i = 0; i < emotes.length; i++) { + createEmoteCallback(emotes[i]); + } + + emoteFolder.open(); + + // expressions + + face = model.getObjectByName('Head_4'); + + const expressions = Object.keys(face.morphTargetDictionary); + const expressionFolder = gui.addFolder('Expressions'); + + for (let i = 0; i < expressions.length; i++) { + expressionFolder.add(face.morphTargetInfluences, i, 0, 1, 0.01).name(expressions[i]); + } + + activeAction = actions['Walking']; + activeAction.play(); + + expressionFolder.open(); +} + +function fadeToAction(name, duration) { + previousAction = activeAction; + activeAction = actions[name]; + + if (previousAction !== activeAction) { + previousAction.fadeOut(duration); + } + + activeAction.reset().setEffectiveTimeScale(1).setEffectiveWeight(1).fadeIn(duration).play(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + const dt = clock.getDelta(); + + if (mixer) mixer.update(dt); + + requestAnimationFrame(animate); + + renderer.render(scene, camera); + + stats.update(); +} diff --git a/examples-testing/examples/webgl_buffergeometry.ts b/examples-testing/examples/webgl_buffergeometry.ts new file mode 100644 index 000000000..5f9bb39c4 --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry.ts @@ -0,0 +1,182 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let container, stats; + +let camera, scene, renderer; + +let mesh; + +init(); +animate(); + +function init() { + container = document.getElementById('container'); + + // + + camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500); + camera.position.z = 2750; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x050505); + scene.fog = new THREE.Fog(0x050505, 2000, 3500); + + // + + scene.add(new THREE.AmbientLight(0xcccccc)); + + const light1 = new THREE.DirectionalLight(0xffffff, 1.5); + light1.position.set(1, 1, 1); + scene.add(light1); + + const light2 = new THREE.DirectionalLight(0xffffff, 4.5); + light2.position.set(0, -1, 0); + scene.add(light2); + + // + + const triangles = 160000; + + const geometry = new THREE.BufferGeometry(); + + const positions = []; + const normals = []; + const colors = []; + + const color = new THREE.Color(); + + const n = 800, + n2 = n / 2; // triangles spread in the cube + const d = 12, + d2 = d / 2; // individual triangle size + + const pA = new THREE.Vector3(); + const pB = new THREE.Vector3(); + const pC = new THREE.Vector3(); + + const cb = new THREE.Vector3(); + const ab = new THREE.Vector3(); + + for (let i = 0; i < triangles; i++) { + // positions + + const x = Math.random() * n - n2; + const y = Math.random() * n - n2; + const z = Math.random() * n - n2; + + const ax = x + Math.random() * d - d2; + const ay = y + Math.random() * d - d2; + const az = z + Math.random() * d - d2; + + const bx = x + Math.random() * d - d2; + const by = y + Math.random() * d - d2; + const bz = z + Math.random() * d - d2; + + const cx = x + Math.random() * d - d2; + const cy = y + Math.random() * d - d2; + const cz = z + Math.random() * d - d2; + + positions.push(ax, ay, az); + positions.push(bx, by, bz); + positions.push(cx, cy, cz); + + // flat face normals + + pA.set(ax, ay, az); + pB.set(bx, by, bz); + pC.set(cx, cy, cz); + + cb.subVectors(pC, pB); + ab.subVectors(pA, pB); + cb.cross(ab); + + cb.normalize(); + + const nx = cb.x; + const ny = cb.y; + const nz = cb.z; + + normals.push(nx, ny, nz); + normals.push(nx, ny, nz); + normals.push(nx, ny, nz); + + // colors + + const vx = x / n + 0.5; + const vy = y / n + 0.5; + const vz = z / n + 0.5; + + color.setRGB(vx, vy, vz); + + const alpha = Math.random(); + + colors.push(color.r, color.g, color.b, alpha); + colors.push(color.r, color.g, color.b, alpha); + colors.push(color.r, color.g, color.b, alpha); + } + + function disposeArray() { + this.array = null; + } + + geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3).onUpload(disposeArray)); + geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3).onUpload(disposeArray)); + geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 4).onUpload(disposeArray)); + + geometry.computeBoundingSphere(); + + const material = new THREE.MeshPhongMaterial({ + color: 0xd5d5d5, + specular: 0xffffff, + shininess: 250, + side: THREE.DoubleSide, + vertexColors: true, + transparent: true, + }); + + mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + // + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.001; + + mesh.rotation.x = time * 0.25; + mesh.rotation.y = time * 0.5; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts b/examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts new file mode 100644 index 000000000..e9e115dcb --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts @@ -0,0 +1,108 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let renderer, scene, camera, stats; + +let particleSystem, uniforms, geometry; + +const particles = 100000; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000); + camera.position.z = 300; + + scene = new THREE.Scene(); + + uniforms = { + pointTexture: { value: new THREE.TextureLoader().load('textures/sprites/spark1.png') }, + }; + + const shaderMaterial = new THREE.ShaderMaterial({ + uniforms: uniforms, + vertexShader: document.getElementById('vertexshader').textContent, + fragmentShader: document.getElementById('fragmentshader').textContent, + + blending: THREE.AdditiveBlending, + depthTest: false, + transparent: true, + vertexColors: true, + }); + + const radius = 200; + + geometry = new THREE.BufferGeometry(); + + const positions = []; + const colors = []; + const sizes = []; + + const color = new THREE.Color(); + + for (let i = 0; i < particles; i++) { + positions.push((Math.random() * 2 - 1) * radius); + positions.push((Math.random() * 2 - 1) * radius); + positions.push((Math.random() * 2 - 1) * radius); + + color.setHSL(i / particles, 1.0, 0.5); + + colors.push(color.r, color.g, color.b); + + sizes.push(20); + } + + geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); + geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); + geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1).setUsage(THREE.DynamicDrawUsage)); + + particleSystem = new THREE.Points(geometry, shaderMaterial); + + scene.add(particleSystem); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + + const container = document.getElementById('container'); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.005; + + particleSystem.rotation.z = 0.01 * time; + + const sizes = geometry.attributes.size.array; + + for (let i = 0; i < particles; i++) { + sizes[i] = 10 * (1 + Math.sin(0.1 * i + time)); + } + + geometry.attributes.size.needsUpdate = true; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_drawrange.ts b/examples-testing/examples/webgl_buffergeometry_drawrange.ts new file mode 100644 index 000000000..b69868ce4 --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_drawrange.ts @@ -0,0 +1,241 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +let group; +let container, stats; +const particlesData = []; +let camera, scene, renderer; +let positions, colors; +let particles; +let pointCloud; +let particlePositions; +let linesMesh; + +const maxParticleCount = 1000; +let particleCount = 500; +const r = 800; +const rHalf = r / 2; + +const effectController = { + showDots: true, + showLines: true, + minDistance: 150, + limitConnections: false, + maxConnections: 20, + particleCount: 500, +}; + +init(); +animate(); + +function initGUI() { + const gui = new GUI(); + + gui.add(effectController, 'showDots').onChange(function (value) { + pointCloud.visible = value; + }); + gui.add(effectController, 'showLines').onChange(function (value) { + linesMesh.visible = value; + }); + gui.add(effectController, 'minDistance', 10, 300); + gui.add(effectController, 'limitConnections'); + gui.add(effectController, 'maxConnections', 0, 30, 1); + gui.add(effectController, 'particleCount', 0, maxParticleCount, 1).onChange(function (value) { + particleCount = parseInt(value); + particles.setDrawRange(0, particleCount); + }); +} + +function init() { + initGUI(); + + container = document.getElementById('container'); + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 4000); + camera.position.z = 1750; + + const controls = new OrbitControls(camera, container); + controls.minDistance = 1000; + controls.maxDistance = 3000; + + scene = new THREE.Scene(); + + group = new THREE.Group(); + scene.add(group); + + const helper = new THREE.BoxHelper(new THREE.Mesh(new THREE.BoxGeometry(r, r, r))); + helper.material.color.setHex(0x474747); + helper.material.blending = THREE.AdditiveBlending; + helper.material.transparent = true; + group.add(helper); + + const segments = maxParticleCount * maxParticleCount; + + positions = new Float32Array(segments * 3); + colors = new Float32Array(segments * 3); + + const pMaterial = new THREE.PointsMaterial({ + color: 0xffffff, + size: 3, + blending: THREE.AdditiveBlending, + transparent: true, + sizeAttenuation: false, + }); + + particles = new THREE.BufferGeometry(); + particlePositions = new Float32Array(maxParticleCount * 3); + + for (let i = 0; i < maxParticleCount; i++) { + const x = Math.random() * r - r / 2; + const y = Math.random() * r - r / 2; + const z = Math.random() * r - r / 2; + + particlePositions[i * 3] = x; + particlePositions[i * 3 + 1] = y; + particlePositions[i * 3 + 2] = z; + + // add it to the geometry + particlesData.push({ + velocity: new THREE.Vector3(-1 + Math.random() * 2, -1 + Math.random() * 2, -1 + Math.random() * 2), + numConnections: 0, + }); + } + + particles.setDrawRange(0, particleCount); + particles.setAttribute( + 'position', + new THREE.BufferAttribute(particlePositions, 3).setUsage(THREE.DynamicDrawUsage), + ); + + // create the particle system + pointCloud = new THREE.Points(particles, pMaterial); + group.add(pointCloud); + + const geometry = new THREE.BufferGeometry(); + + geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3).setUsage(THREE.DynamicDrawUsage)); + geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3).setUsage(THREE.DynamicDrawUsage)); + + geometry.computeBoundingSphere(); + + geometry.setDrawRange(0, 0); + + const material = new THREE.LineBasicMaterial({ + vertexColors: true, + blending: THREE.AdditiveBlending, + transparent: true, + }); + + linesMesh = new THREE.LineSegments(geometry, material); + group.add(linesMesh); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + + container.appendChild(renderer.domElement); + + // + + stats = new Stats(); + container.appendChild(stats.dom); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + let vertexpos = 0; + let colorpos = 0; + let numConnected = 0; + + for (let i = 0; i < particleCount; i++) particlesData[i].numConnections = 0; + + for (let i = 0; i < particleCount; i++) { + // get the particle + const particleData = particlesData[i]; + + particlePositions[i * 3] += particleData.velocity.x; + particlePositions[i * 3 + 1] += particleData.velocity.y; + particlePositions[i * 3 + 2] += particleData.velocity.z; + + if (particlePositions[i * 3 + 1] < -rHalf || particlePositions[i * 3 + 1] > rHalf) + particleData.velocity.y = -particleData.velocity.y; + + if (particlePositions[i * 3] < -rHalf || particlePositions[i * 3] > rHalf) + particleData.velocity.x = -particleData.velocity.x; + + if (particlePositions[i * 3 + 2] < -rHalf || particlePositions[i * 3 + 2] > rHalf) + particleData.velocity.z = -particleData.velocity.z; + + if (effectController.limitConnections && particleData.numConnections >= effectController.maxConnections) + continue; + + // Check collision + for (let j = i + 1; j < particleCount; j++) { + const particleDataB = particlesData[j]; + if (effectController.limitConnections && particleDataB.numConnections >= effectController.maxConnections) + continue; + + const dx = particlePositions[i * 3] - particlePositions[j * 3]; + const dy = particlePositions[i * 3 + 1] - particlePositions[j * 3 + 1]; + const dz = particlePositions[i * 3 + 2] - particlePositions[j * 3 + 2]; + const dist = Math.sqrt(dx * dx + dy * dy + dz * dz); + + if (dist < effectController.minDistance) { + particleData.numConnections++; + particleDataB.numConnections++; + + const alpha = 1.0 - dist / effectController.minDistance; + + positions[vertexpos++] = particlePositions[i * 3]; + positions[vertexpos++] = particlePositions[i * 3 + 1]; + positions[vertexpos++] = particlePositions[i * 3 + 2]; + + positions[vertexpos++] = particlePositions[j * 3]; + positions[vertexpos++] = particlePositions[j * 3 + 1]; + positions[vertexpos++] = particlePositions[j * 3 + 2]; + + colors[colorpos++] = alpha; + colors[colorpos++] = alpha; + colors[colorpos++] = alpha; + + colors[colorpos++] = alpha; + colors[colorpos++] = alpha; + colors[colorpos++] = alpha; + + numConnected++; + } + } + } + + linesMesh.geometry.setDrawRange(0, numConnected * 2); + linesMesh.geometry.attributes.position.needsUpdate = true; + linesMesh.geometry.attributes.color.needsUpdate = true; + + pointCloud.geometry.attributes.position.needsUpdate = true; + + requestAnimationFrame(animate); + + stats.update(); + render(); +} + +function render() { + const time = Date.now() * 0.001; + + group.rotation.y = time * 0.1; + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts b/examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts new file mode 100644 index 000000000..daf8a0607 --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts @@ -0,0 +1,145 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let container, stats; + +let camera, scene, renderer; + +let points; + +const particles = 300000; +let drawCount = 10000; + +init(); +animate(); + +function init() { + container = document.getElementById('container'); + + // + + renderer = new THREE.WebGLRenderer({ antialias: false }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + + container.appendChild(renderer.domElement); + + // + + camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 5, 3500); + camera.position.z = 2750; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x050505); + scene.fog = new THREE.Fog(0x050505, 2000, 3500); + + // + + const geometry = new THREE.BufferGeometry(); + + const positions = []; + const positions2 = []; + const colors = []; + + const color = new THREE.Color(); + + const n = 1000, + n2 = n / 2; // particles spread in the cube + + for (let i = 0; i < particles; i++) { + // positions + + const x = Math.random() * n - n2; + const y = Math.random() * n - n2; + const z = Math.random() * n - n2; + + positions.push(x, y, z); + positions2.push(z * 0.3, x * 0.3, y * 0.3); + + // colors + + const vx = x / n + 0.5; + const vy = y / n + 0.5; + const vz = z / n + 0.5; + + color.setRGB(vx, vy, vz, THREE.SRGBColorSpace); + + colors.push(color.r, color.g, color.b); + } + + const gl = renderer.getContext(); + + const pos = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, pos); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); + + const pos2 = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, pos2); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions2), gl.STATIC_DRAW); + + const rgb = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, rgb); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); + + const posAttr1 = new THREE.GLBufferAttribute(pos, gl.FLOAT, 3, 4, particles); + const posAttr2 = new THREE.GLBufferAttribute(pos2, gl.FLOAT, 3, 4, particles); + geometry.setAttribute('position', posAttr1); + + setInterval(function () { + const attr = geometry.getAttribute('position'); + + geometry.setAttribute('position', attr === posAttr1 ? posAttr2 : posAttr1); + }, 2000); + + geometry.setAttribute('color', new THREE.GLBufferAttribute(rgb, gl.FLOAT, 3, 4, particles)); + + // + + const material = new THREE.PointsMaterial({ size: 15, vertexColors: true }); + + points = new THREE.Points(geometry, material); + + // Choose one: + // geometry.boundingSphere = ( new THREE.Sphere() ).set( new THREE.Vector3(), Infinity ); + points.frustumCulled = false; + + scene.add(points); + + // + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + drawCount = (Math.max(5000, drawCount) + Math.floor(500 * Math.random())) % particles; + points.geometry.setDrawRange(0, drawCount); + + const time = Date.now() * 0.001; + + points.rotation.x = time * 0.1; + points.rotation.y = time * 0.2; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_indexed.ts b/examples-testing/examples/webgl_buffergeometry_indexed.ts new file mode 100644 index 000000000..1e9f668cc --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_indexed.ts @@ -0,0 +1,142 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let camera, scene, renderer, stats; + +let mesh; + +init(); +animate(); + +function init() { + // + + camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500); + camera.position.z = 64; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x050505); + + // + + const light = new THREE.HemisphereLight(); + light.intensity = 3; + scene.add(light); + + // + + const geometry = new THREE.BufferGeometry(); + + const indices = []; + + const vertices = []; + const normals = []; + const colors = []; + + const size = 20; + const segments = 10; + + const halfSize = size / 2; + const segmentSize = size / segments; + + const _color = new THREE.Color(); + + // generate vertices, normals and color data for a simple grid geometry + + for (let i = 0; i <= segments; i++) { + const y = i * segmentSize - halfSize; + + for (let j = 0; j <= segments; j++) { + const x = j * segmentSize - halfSize; + + vertices.push(x, -y, 0); + normals.push(0, 0, 1); + + const r = x / size + 0.5; + const g = y / size + 0.5; + + _color.setRGB(r, g, 1, THREE.SRGBColorSpace); + + colors.push(_color.r, _color.g, _color.b); + } + } + + // generate indices (data for element array buffer) + + for (let i = 0; i < segments; i++) { + for (let j = 0; j < segments; j++) { + const a = i * (segments + 1) + (j + 1); + const b = i * (segments + 1) + j; + const c = (i + 1) * (segments + 1) + j; + const d = (i + 1) * (segments + 1) + (j + 1); + + // generate two faces (triangles) per iteration + + indices.push(a, b, d); // face one + indices.push(b, c, d); // face two + } + } + + // + + geometry.setIndex(indices); + geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); + geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3)); + geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); + + const material = new THREE.MeshPhongMaterial({ + side: THREE.DoubleSide, + vertexColors: true, + }); + + mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + // + + stats = new Stats(); + document.body.appendChild(stats.dom); + + // + + const gui = new GUI(); + gui.add(material, 'wireframe'); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.001; + + mesh.rotation.x = time * 0.25; + mesh.rotation.y = time * 0.5; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_instancing.ts b/examples-testing/examples/webgl_buffergeometry_instancing.ts new file mode 100644 index 000000000..adff12a8a --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_instancing.ts @@ -0,0 +1,148 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let container, stats; + +let camera, scene, renderer; + +init(); +animate(); + +function init() { + container = document.getElementById('container'); + + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10); + camera.position.z = 2; + + scene = new THREE.Scene(); + + // geometry + + const vector = new THREE.Vector4(); + + const instances = 50000; + + const positions = []; + const offsets = []; + const colors = []; + const orientationsStart = []; + const orientationsEnd = []; + + positions.push(0.025, -0.025, 0); + positions.push(-0.025, 0.025, 0); + positions.push(0, 0, 0.025); + + // instanced attributes + + for (let i = 0; i < instances; i++) { + // offsets + + offsets.push(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5); + + // colors + + colors.push(Math.random(), Math.random(), Math.random(), Math.random()); + + // orientation start + + vector.set(Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1); + vector.normalize(); + + orientationsStart.push(vector.x, vector.y, vector.z, vector.w); + + // orientation end + + vector.set(Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1); + vector.normalize(); + + orientationsEnd.push(vector.x, vector.y, vector.z, vector.w); + } + + const geometry = new THREE.InstancedBufferGeometry(); + geometry.instanceCount = instances; // set so its initalized for dat.GUI, will be set in first draw otherwise + + geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); + + geometry.setAttribute('offset', new THREE.InstancedBufferAttribute(new Float32Array(offsets), 3)); + geometry.setAttribute('color', new THREE.InstancedBufferAttribute(new Float32Array(colors), 4)); + geometry.setAttribute( + 'orientationStart', + new THREE.InstancedBufferAttribute(new Float32Array(orientationsStart), 4), + ); + geometry.setAttribute('orientationEnd', new THREE.InstancedBufferAttribute(new Float32Array(orientationsEnd), 4)); + + // material + + const material = new THREE.RawShaderMaterial({ + uniforms: { + time: { value: 1.0 }, + sineTime: { value: 1.0 }, + }, + vertexShader: document.getElementById('vertexShader').textContent, + fragmentShader: document.getElementById('fragmentShader').textContent, + side: THREE.DoubleSide, + forceSinglePass: true, + transparent: true, + }); + + // + + const mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + if (renderer.capabilities.isWebGL2 === false && renderer.extensions.has('ANGLE_instanced_arrays') === false) { + document.getElementById('notSupported').style.display = ''; + return; + } + + // + + const gui = new GUI({ width: 350 }); + gui.add(geometry, 'instanceCount', 0, instances); + + // + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = performance.now(); + + const object = scene.children[0]; + + object.rotation.y = time * 0.0005; + object.material.uniforms['time'].value = time * 0.005; + object.material.uniforms['sineTime'].value = Math.sin(object.material.uniforms['time'].value * 0.05); + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts b/examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts new file mode 100644 index 000000000..785389c8b --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts @@ -0,0 +1,98 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let container, stats; + +let camera, scene, renderer; +let geometry, material, mesh; + +function init() { + renderer = new THREE.WebGLRenderer(); + + if (renderer.capabilities.isWebGL2 === false && renderer.extensions.has('ANGLE_instanced_arrays') === false) { + document.getElementById('notSupported').style.display = ''; + return false; + } + + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 5000); + camera.position.z = 1400; + + scene = new THREE.Scene(); + + const circleGeometry = new THREE.CircleGeometry(1, 6); + + geometry = new THREE.InstancedBufferGeometry(); + geometry.index = circleGeometry.index; + geometry.attributes = circleGeometry.attributes; + + const particleCount = 75000; + + const translateArray = new Float32Array(particleCount * 3); + + for (let i = 0, i3 = 0, l = particleCount; i < l; i++, i3 += 3) { + translateArray[i3 + 0] = Math.random() * 2 - 1; + translateArray[i3 + 1] = Math.random() * 2 - 1; + translateArray[i3 + 2] = Math.random() * 2 - 1; + } + + geometry.setAttribute('translate', new THREE.InstancedBufferAttribute(translateArray, 3)); + + material = new THREE.RawShaderMaterial({ + uniforms: { + map: { value: new THREE.TextureLoader().load('textures/sprites/circle.png') }, + time: { value: 0.0 }, + }, + vertexShader: document.getElementById('vshader').textContent, + fragmentShader: document.getElementById('fshader').textContent, + depthTest: true, + depthWrite: true, + }); + + mesh = new THREE.Mesh(geometry, material); + mesh.scale.set(500, 500, 500); + scene.add(mesh); + + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + window.addEventListener('resize', onWindowResize); + + return true; +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = performance.now() * 0.0005; + + material.uniforms['time'].value = time; + + mesh.rotation.x = time * 0.2; + mesh.rotation.y = time * 0.4; + + renderer.render(scene, camera); +} + +if (init()) { + animate(); +} diff --git a/examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts b/examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts new file mode 100644 index 000000000..132e1e6df --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts @@ -0,0 +1,162 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let container, stats; +let camera, scene, renderer, mesh; + +const instances = 5000; +let lastTime = 0; + +const moveQ = new THREE.Quaternion(0.5, 0.5, 0.5, 0.0).normalize(); +const tmpQ = new THREE.Quaternion(); +const tmpM = new THREE.Matrix4(); +const currentM = new THREE.Matrix4(); + +init(); +animate(); + +function init() { + container = document.getElementById('container'); + + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1000); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x101010); + + // geometry + + const geometry = new THREE.InstancedBufferGeometry(); + + // per mesh data x,y,z,w,u,v,s,t for 4-element alignment + // only use x,y,z and u,v; but x, y, z, nx, ny, nz, u, v would be a good layout + const vertexBuffer = new THREE.InterleavedBuffer( + new Float32Array([ + // Front + -1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, -1, -1, 1, 0, 0, 1, 0, 0, 1, -1, 1, 0, 1, 1, 0, 0, + // Back + 1, 1, -1, 0, 1, 0, 0, 0, -1, 1, -1, 0, 0, 0, 0, 0, 1, -1, -1, 0, 1, 1, 0, 0, -1, -1, -1, 0, 0, 1, 0, 0, + // Left + -1, 1, -1, 0, 1, 1, 0, 0, -1, 1, 1, 0, 1, 0, 0, 0, -1, -1, -1, 0, 0, 1, 0, 0, -1, -1, 1, 0, 0, 0, 0, 0, + // Right + 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, -1, 0, 1, 1, 0, 0, 1, -1, 1, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 1, 0, 0, + // Top + -1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, -1, 1, -1, 0, 0, 1, 0, 0, 1, 1, -1, 0, 1, 1, 0, 0, + // Bottom + 1, -1, 1, 0, 1, 0, 0, 0, -1, -1, 1, 0, 0, 0, 0, 0, 1, -1, -1, 0, 1, 1, 0, 0, -1, -1, -1, 0, 0, 1, 0, 0, + ]), + 8, + ); + + // Use vertexBuffer, starting at offset 0, 3 items in position attribute + const positions = new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0); + geometry.setAttribute('position', positions); + // Use vertexBuffer, starting at offset 4, 2 items in uv attribute + const uvs = new THREE.InterleavedBufferAttribute(vertexBuffer, 2, 4); + geometry.setAttribute('uv', uvs); + + const indices = new Uint16Array([ + 0, 2, 1, 2, 3, 1, 4, 6, 5, 6, 7, 5, 8, 10, 9, 10, 11, 9, 12, 14, 13, 14, 15, 13, 16, 17, 18, 18, 17, 19, 20, 21, + 22, 22, 21, 23, + ]); + + geometry.setIndex(new THREE.BufferAttribute(indices, 1)); + + // material + + const material = new THREE.MeshBasicMaterial(); + material.map = new THREE.TextureLoader().load('textures/crate.gif'); + material.map.colorSpace = THREE.SRGBColorSpace; + material.map.flipY = false; + + // per instance data + + const matrix = new THREE.Matrix4(); + const offset = new THREE.Vector3(); + const orientation = new THREE.Quaternion(); + const scale = new THREE.Vector3(1, 1, 1); + let x, y, z, w; + + mesh = new THREE.InstancedMesh(geometry, material, instances); + + for (let i = 0; i < instances; i++) { + // offsets + + x = Math.random() * 100 - 50; + y = Math.random() * 100 - 50; + z = Math.random() * 100 - 50; + + offset.set(x, y, z).normalize(); + offset.multiplyScalar(5); // move out at least 5 units from center in current direction + offset.set(x + offset.x, y + offset.y, z + offset.z); + + // orientations + + x = Math.random() * 2 - 1; + y = Math.random() * 2 - 1; + z = Math.random() * 2 - 1; + w = Math.random() * 2 - 1; + + orientation.set(x, y, z, w).normalize(); + + matrix.compose(offset, orientation, scale); + + mesh.setMatrixAt(i, matrix); + } + + scene.add(mesh); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + if (renderer.capabilities.isWebGL2 === false && renderer.extensions.has('ANGLE_instanced_arrays') === false) { + document.getElementById('notSupported').style.display = ''; + return; + } + + stats = new Stats(); + container.appendChild(stats.dom); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = performance.now(); + + mesh.rotation.y = time * 0.00005; + + const delta = (time - lastTime) / 5000; + tmpQ.set(moveQ.x * delta, moveQ.y * delta, moveQ.z * delta, 1).normalize(); + tmpM.makeRotationFromQuaternion(tmpQ); + + for (let i = 0, il = instances; i < il; i++) { + mesh.getMatrixAt(i, currentM); + currentM.multiply(tmpM); + mesh.setMatrixAt(i, currentM); + } + + mesh.instanceMatrix.needsUpdate = true; + mesh.computeBoundingSphere(); + + lastTime = time; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_lines.ts b/examples-testing/examples/webgl_buffergeometry_lines.ts new file mode 100644 index 000000000..c23ea0cdd --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_lines.ts @@ -0,0 +1,123 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let container, stats, clock; + +let camera, scene, renderer; + +let line; + +const segments = 10000; +const r = 800; +let t = 0; + +init(); +animate(); + +function init() { + container = document.getElementById('container'); + + // + + camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 4000); + camera.position.z = 2750; + + scene = new THREE.Scene(); + + clock = new THREE.Clock(); + + const geometry = new THREE.BufferGeometry(); + const material = new THREE.LineBasicMaterial({ vertexColors: true }); + + const positions = []; + const colors = []; + + for (let i = 0; i < segments; i++) { + const x = Math.random() * r - r / 2; + const y = Math.random() * r - r / 2; + const z = Math.random() * r - r / 2; + + // positions + + positions.push(x, y, z); + + // colors + + colors.push(x / r + 0.5); + colors.push(y / r + 0.5); + colors.push(z / r + 0.5); + } + + geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); + geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); + generateMorphTargets(geometry); + + geometry.computeBoundingSphere(); + + line = new THREE.Line(geometry, material); + scene.add(line); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + + container.appendChild(renderer.domElement); + + // + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const delta = clock.getDelta(); + const time = clock.getElapsedTime(); + + line.rotation.x = time * 0.25; + line.rotation.y = time * 0.5; + + t += delta * 0.5; + line.morphTargetInfluences[0] = Math.abs(Math.sin(t)); + + renderer.render(scene, camera); +} + +function generateMorphTargets(geometry) { + const data = []; + + for (let i = 0; i < segments; i++) { + const x = Math.random() * r - r / 2; + const y = Math.random() * r - r / 2; + const z = Math.random() * r - r / 2; + + data.push(x, y, z); + } + + const morphTarget = new THREE.Float32BufferAttribute(data, 3); + morphTarget.name = 'target1'; + + geometry.morphAttributes.position = [morphTarget]; +} diff --git a/examples-testing/examples/webgl_buffergeometry_lines_indexed.ts b/examples-testing/examples/webgl_buffergeometry_lines_indexed.ts new file mode 100644 index 000000000..d81c1736a --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_lines_indexed.ts @@ -0,0 +1,186 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let container, stats; + +let camera, scene, renderer; + +let parent_node; + +init(); +animate(); + +function init() { + container = document.getElementById('container'); + + camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 10000); + camera.position.z = 9000; + + scene = new THREE.Scene(); + + const geometry = new THREE.BufferGeometry(); + const material = new THREE.LineBasicMaterial({ vertexColors: true }); + + const indices = []; + const positions = []; + const colors = []; + + let next_positions_index = 0; + + // + + const iteration_count = 4; + const rangle = (60 * Math.PI) / 180.0; + + function add_vertex(v) { + if (next_positions_index == 0xffff) console.error('Too many points.'); + + positions.push(v.x, v.y, v.z); + colors.push(Math.random() * 0.5 + 0.5, Math.random() * 0.5 + 0.5, 1); + + return next_positions_index++; + } + + // simple Koch curve + + function snowflake_iteration(p0, p4, depth) { + if (--depth < 0) { + const i = next_positions_index - 1; // p0 already there + add_vertex(p4); + indices.push(i, i + 1); + + return; + } + + const v = p4.clone().sub(p0); + const v_tier = v.clone().multiplyScalar(1 / 3); + const p1 = p0.clone().add(v_tier); + + const angle = Math.atan2(v.y, v.x) + rangle; + const length = v_tier.length(); + const p2 = p1.clone(); + p2.x += Math.cos(angle) * length; + p2.y += Math.sin(angle) * length; + + const p3 = p0.clone().add(v_tier).add(v_tier); + + snowflake_iteration(p0, p1, depth); + snowflake_iteration(p1, p2, depth); + snowflake_iteration(p2, p3, depth); + snowflake_iteration(p3, p4, depth); + } + + function snowflake(points, loop, x_offset) { + for (let iteration = 0; iteration != iteration_count; iteration++) { + add_vertex(points[0]); + + for (let p_index = 0, p_count = points.length - 1; p_index != p_count; p_index++) { + snowflake_iteration(points[p_index], points[p_index + 1], iteration); + } + + if (loop) snowflake_iteration(points[points.length - 1], points[0], iteration); + + // translate input curve for next iteration + + for (let p_index = 0, p_count = points.length; p_index != p_count; p_index++) { + points[p_index].x += x_offset; + } + } + } + + let y = 0; + + snowflake([new THREE.Vector3(0, y, 0), new THREE.Vector3(500, y, 0)], false, 600); + + y += 600; + snowflake( + [new THREE.Vector3(0, y, 0), new THREE.Vector3(250, y + 400, 0), new THREE.Vector3(500, y, 0)], + true, + 600, + ); + + y += 600; + snowflake( + [ + new THREE.Vector3(0, y, 0), + new THREE.Vector3(500, y, 0), + new THREE.Vector3(500, y + 500, 0), + new THREE.Vector3(0, y + 500, 0), + ], + true, + 600, + ); + + y += 1000; + snowflake( + [ + new THREE.Vector3(250, y, 0), + new THREE.Vector3(500, y, 0), + new THREE.Vector3(250, y, 0), + new THREE.Vector3(250, y + 250, 0), + new THREE.Vector3(250, y, 0), + new THREE.Vector3(0, y, 0), + new THREE.Vector3(250, y, 0), + new THREE.Vector3(250, y - 250, 0), + new THREE.Vector3(250, y, 0), + ], + false, + 600, + ); + + // + + geometry.setIndex(indices); + geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); + geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); + geometry.computeBoundingSphere(); + + const lineSegments = new THREE.LineSegments(geometry, material); + lineSegments.position.x -= 1200; + lineSegments.position.y -= 1200; + + parent_node = new THREE.Object3D(); + parent_node.add(lineSegments); + + scene.add(parent_node); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + + container.appendChild(renderer.domElement); + + // + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.001; + + parent_node.rotation.z = time * 0.5; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_points.ts b/examples-testing/examples/webgl_buffergeometry_points.ts new file mode 100644 index 000000000..fdfd9575d --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_points.ts @@ -0,0 +1,113 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let container, stats; + +let camera, scene, renderer; + +let points; + +init(); +animate(); + +function init() { + container = document.getElementById('container'); + + // + + camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 5, 3500); + camera.position.z = 2750; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x050505); + scene.fog = new THREE.Fog(0x050505, 2000, 3500); + + // + + const particles = 500000; + + const geometry = new THREE.BufferGeometry(); + + const positions = []; + const colors = []; + + const color = new THREE.Color(); + + const n = 1000, + n2 = n / 2; // particles spread in the cube + + for (let i = 0; i < particles; i++) { + // positions + + const x = Math.random() * n - n2; + const y = Math.random() * n - n2; + const z = Math.random() * n - n2; + + positions.push(x, y, z); + + // colors + + const vx = x / n + 0.5; + const vy = y / n + 0.5; + const vz = z / n + 0.5; + + color.setRGB(vx, vy, vz, THREE.SRGBColorSpace); + + colors.push(color.r, color.g, color.b); + } + + geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); + geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); + + geometry.computeBoundingSphere(); + + // + + const material = new THREE.PointsMaterial({ size: 15, vertexColors: true }); + + points = new THREE.Points(geometry, material); + scene.add(points); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + + container.appendChild(renderer.domElement); + + // + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.001; + + points.rotation.x = time * 0.25; + points.rotation.y = time * 0.5; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_points_interleaved.ts b/examples-testing/examples/webgl_buffergeometry_points_interleaved.ts new file mode 100644 index 000000000..9d1ac41e3 --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_points_interleaved.ts @@ -0,0 +1,127 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let container, stats; + +let camera, scene, renderer; + +let points; + +init(); +animate(); + +function init() { + container = document.getElementById('container'); + + camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 5, 3500); + camera.position.z = 2750; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x050505); + scene.fog = new THREE.Fog(0x050505, 2000, 3500); + + // + + const particles = 500000; + + const geometry = new THREE.BufferGeometry(); + + // create a generic buffer of binary data (a single particle has 16 bytes of data) + + const arrayBuffer = new ArrayBuffer(particles * 16); + + // the following typed arrays share the same buffer + + const interleavedFloat32Buffer = new Float32Array(arrayBuffer); + const interleavedUint8Buffer = new Uint8Array(arrayBuffer); + + // + + const color = new THREE.Color(); + + const n = 1000, + n2 = n / 2; // particles spread in the cube + + for (let i = 0; i < interleavedFloat32Buffer.length; i += 4) { + // position (first 12 bytes) + + const x = Math.random() * n - n2; + const y = Math.random() * n - n2; + const z = Math.random() * n - n2; + + interleavedFloat32Buffer[i + 0] = x; + interleavedFloat32Buffer[i + 1] = y; + interleavedFloat32Buffer[i + 2] = z; + + // color (last 4 bytes) + + const vx = x / n + 0.5; + const vy = y / n + 0.5; + const vz = z / n + 0.5; + + color.setRGB(vx, vy, vz, THREE.SRGBColorSpace); + + const j = (i + 3) * 4; + + interleavedUint8Buffer[j + 0] = color.r * 255; + interleavedUint8Buffer[j + 1] = color.g * 255; + interleavedUint8Buffer[j + 2] = color.b * 255; + interleavedUint8Buffer[j + 3] = 0; // not needed + } + + const interleavedBuffer32 = new THREE.InterleavedBuffer(interleavedFloat32Buffer, 4); + const interleavedBuffer8 = new THREE.InterleavedBuffer(interleavedUint8Buffer, 16); + + geometry.setAttribute('position', new THREE.InterleavedBufferAttribute(interleavedBuffer32, 3, 0, false)); + geometry.setAttribute('color', new THREE.InterleavedBufferAttribute(interleavedBuffer8, 3, 12, true)); + + // + + const material = new THREE.PointsMaterial({ size: 15, vertexColors: true }); + + points = new THREE.Points(geometry, material); + scene.add(points); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + + container.appendChild(renderer.domElement); + + // + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.001; + + points.rotation.x = time * 0.25; + points.rotation.y = time * 0.5; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_rawshader.ts b/examples-testing/examples/webgl_buffergeometry_rawshader.ts new file mode 100644 index 000000000..0d0533951 --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_rawshader.ts @@ -0,0 +1,102 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let container, stats; + +let camera, scene, renderer; + +init(); +animate(); + +function init() { + container = document.getElementById('container'); + + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10); + camera.position.z = 2; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x101010); + + // geometry + // nr of triangles with 3 vertices per triangle + const vertexCount = 200 * 3; + + const geometry = new THREE.BufferGeometry(); + + const positions = []; + const colors = []; + + for (let i = 0; i < vertexCount; i++) { + // adding x,y,z + positions.push(Math.random() - 0.5); + positions.push(Math.random() - 0.5); + positions.push(Math.random() - 0.5); + + // adding r,g,b,a + colors.push(Math.random() * 255); + colors.push(Math.random() * 255); + colors.push(Math.random() * 255); + colors.push(Math.random() * 255); + } + + const positionAttribute = new THREE.Float32BufferAttribute(positions, 3); + const colorAttribute = new THREE.Uint8BufferAttribute(colors, 4); + + colorAttribute.normalized = true; // this will map the buffer values to 0.0f - +1.0f in the shader + + geometry.setAttribute('position', positionAttribute); + geometry.setAttribute('color', colorAttribute); + + // material + + const material = new THREE.RawShaderMaterial({ + uniforms: { + time: { value: 1.0 }, + }, + vertexShader: document.getElementById('vertexShader').textContent, + fragmentShader: document.getElementById('fragmentShader').textContent, + side: THREE.DoubleSide, + transparent: true, + }); + + const mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = performance.now(); + + const object = scene.children[0]; + + object.rotation.y = time * 0.0005; + object.material.uniforms.time.value = time * 0.005; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_selective_draw.ts b/examples-testing/examples/webgl_buffergeometry_selective_draw.ts new file mode 100644 index 000000000..f0752a2b3 --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_selective_draw.ts @@ -0,0 +1,151 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let camera, scene, renderer, stats; +let geometry, mesh; +const numLat = 100; +const numLng = 200; +let numLinesCulled = 0; + +init(); +animate(); + +function init() { + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 10); + camera.position.z = 3.5; + + stats = new Stats(); + document.body.appendChild(stats.dom); + + window.addEventListener('resize', onWindowResize); + + addLines(1.0); + + const hideLinesButton = document.getElementById('hideLines'); + hideLinesButton.addEventListener('click', hideLines); + + const showAllLinesButton = document.getElementById('showAllLines'); + showAllLinesButton.addEventListener('click', showAllLines); +} + +function addLines(radius) { + geometry = new THREE.BufferGeometry(); + const linePositions = new Float32Array(numLat * numLng * 3 * 2); + const lineColors = new Float32Array(numLat * numLng * 3 * 2); + const visible = new Float32Array(numLat * numLng * 2); + + for (let i = 0; i < numLat; ++i) { + for (let j = 0; j < numLng; ++j) { + const lat = (Math.random() * Math.PI) / 50.0 + (i / numLat) * Math.PI; + const lng = (Math.random() * Math.PI) / 50.0 + (j / numLng) * 2 * Math.PI; + + const index = i * numLng + j; + + linePositions[index * 6 + 0] = 0; + linePositions[index * 6 + 1] = 0; + linePositions[index * 6 + 2] = 0; + linePositions[index * 6 + 3] = radius * Math.sin(lat) * Math.cos(lng); + linePositions[index * 6 + 4] = radius * Math.cos(lat); + linePositions[index * 6 + 5] = radius * Math.sin(lat) * Math.sin(lng); + + const color = new THREE.Color(0xffffff); + + color.setHSL(lat / Math.PI, 1.0, 0.2); + lineColors[index * 6 + 0] = color.r; + lineColors[index * 6 + 1] = color.g; + lineColors[index * 6 + 2] = color.b; + + color.setHSL(lat / Math.PI, 1.0, 0.7); + lineColors[index * 6 + 3] = color.r; + lineColors[index * 6 + 4] = color.g; + lineColors[index * 6 + 5] = color.b; + + // non-0 is visible + visible[index * 2 + 0] = 1.0; + visible[index * 2 + 1] = 1.0; + } + } + + geometry.setAttribute('position', new THREE.BufferAttribute(linePositions, 3)); + geometry.setAttribute('vertColor', new THREE.BufferAttribute(lineColors, 3)); + geometry.setAttribute('visible', new THREE.BufferAttribute(visible, 1)); + + geometry.computeBoundingSphere(); + + const shaderMaterial = new THREE.ShaderMaterial({ + vertexShader: document.getElementById('vertexshader').textContent, + fragmentShader: document.getElementById('fragmentshader').textContent, + }); + + mesh = new THREE.LineSegments(geometry, shaderMaterial); + scene.add(mesh); + + updateCount(); +} + +function updateCount() { + const str = + '1 draw call, ' + + numLat * numLng + + ' lines, ' + + numLinesCulled + + ' culled (author)'; + document.getElementById('title').innerHTML = str.replace(/\B(?=(\d{3})+(?!\d))/g, ','); +} + +function hideLines() { + for (let i = 0; i < geometry.attributes.visible.array.length; i += 2) { + if (Math.random() > 0.75) { + if (geometry.attributes.visible.array[i + 0]) { + ++numLinesCulled; + } + + geometry.attributes.visible.array[i + 0] = 0; + geometry.attributes.visible.array[i + 1] = 0; + } + } + + geometry.attributes.visible.needsUpdate = true; + + updateCount(); +} + +function showAllLines() { + numLinesCulled = 0; + + for (let i = 0; i < geometry.attributes.visible.array.length; i += 2) { + geometry.attributes.visible.array[i + 0] = 1; + geometry.attributes.visible.array[i + 1] = 1; + } + + geometry.attributes.visible.needsUpdate = true; + + updateCount(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + const time = Date.now() * 0.001; + + mesh.rotation.x = time * 0.25; + mesh.rotation.y = time * 0.5; + + stats.update(); + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_buffergeometry_uint.ts b/examples-testing/examples/webgl_buffergeometry_uint.ts new file mode 100644 index 000000000..d248a0d15 --- /dev/null +++ b/examples-testing/examples/webgl_buffergeometry_uint.ts @@ -0,0 +1,182 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let container, stats; + +let camera, scene, renderer; + +let mesh; + +init(); +animate(); + +function init() { + container = document.getElementById('container'); + + // + + camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500); + camera.position.z = 2750; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x050505); + scene.fog = new THREE.Fog(0x050505, 2000, 3500); + + // + + scene.add(new THREE.AmbientLight(0xcccccc)); + + const light1 = new THREE.DirectionalLight(0xffffff, 1.5); + light1.position.set(1, 1, 1); + scene.add(light1); + + const light2 = new THREE.DirectionalLight(0xffffff, 4.5); + light2.position.set(0, -1, 0); + scene.add(light2); + + // + + const triangles = 500000; + + const geometry = new THREE.BufferGeometry(); + + const positions = []; + const normals = []; + const colors = []; + + const color = new THREE.Color(); + + const n = 800, + n2 = n / 2; // triangles spread in the cube + const d = 12, + d2 = d / 2; // individual triangle size + + const pA = new THREE.Vector3(); + const pB = new THREE.Vector3(); + const pC = new THREE.Vector3(); + + const cb = new THREE.Vector3(); + const ab = new THREE.Vector3(); + + for (let i = 0; i < triangles; i++) { + // positions + + const x = Math.random() * n - n2; + const y = Math.random() * n - n2; + const z = Math.random() * n - n2; + + const ax = x + Math.random() * d - d2; + const ay = y + Math.random() * d - d2; + const az = z + Math.random() * d - d2; + + const bx = x + Math.random() * d - d2; + const by = y + Math.random() * d - d2; + const bz = z + Math.random() * d - d2; + + const cx = x + Math.random() * d - d2; + const cy = y + Math.random() * d - d2; + const cz = z + Math.random() * d - d2; + + positions.push(ax, ay, az); + positions.push(bx, by, bz); + positions.push(cx, cy, cz); + + // flat face normals + + pA.set(ax, ay, az); + pB.set(bx, by, bz); + pC.set(cx, cy, cz); + + cb.subVectors(pC, pB); + ab.subVectors(pA, pB); + cb.cross(ab); + + cb.normalize(); + + const nx = cb.x; + const ny = cb.y; + const nz = cb.z; + + normals.push(nx * 32767, ny * 32767, nz * 32767); + normals.push(nx * 32767, ny * 32767, nz * 32767); + normals.push(nx * 32767, ny * 32767, nz * 32767); + + // colors + + const vx = x / n + 0.5; + const vy = y / n + 0.5; + const vz = z / n + 0.5; + + color.setRGB(vx, vy, vz); + + colors.push(color.r * 255, color.g * 255, color.b * 255); + colors.push(color.r * 255, color.g * 255, color.b * 255); + colors.push(color.r * 255, color.g * 255, color.b * 255); + } + + const positionAttribute = new THREE.Float32BufferAttribute(positions, 3); + const normalAttribute = new THREE.Int16BufferAttribute(normals, 3); + const colorAttribute = new THREE.Uint8BufferAttribute(colors, 3); + + normalAttribute.normalized = true; // this will map the buffer values to 0.0f - +1.0f in the shader + colorAttribute.normalized = true; + + geometry.setAttribute('position', positionAttribute); + geometry.setAttribute('normal', normalAttribute); + geometry.setAttribute('color', colorAttribute); + + geometry.computeBoundingSphere(); + + const material = new THREE.MeshPhongMaterial({ + color: 0xd5d5d5, + specular: 0xffffff, + shininess: 250, + side: THREE.DoubleSide, + vertexColors: true, + }); + + mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + // + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.001; + + mesh.rotation.x = time * 0.25; + mesh.rotation.y = time * 0.5; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_camera.ts b/examples-testing/examples/webgl_camera.ts new file mode 100644 index 000000000..d8319ec26 --- /dev/null +++ b/examples-testing/examples/webgl_camera.ts @@ -0,0 +1,214 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let SCREEN_WIDTH = window.innerWidth; +let SCREEN_HEIGHT = window.innerHeight; +let aspect = SCREEN_WIDTH / SCREEN_HEIGHT; + +let container, stats; +let camera, scene, renderer, mesh; +let cameraRig, activeCamera, activeHelper; +let cameraPerspective, cameraOrtho; +let cameraPerspectiveHelper, cameraOrthoHelper; +const frustumSize = 600; + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + scene = new THREE.Scene(); + + // + + camera = new THREE.PerspectiveCamera(50, 0.5 * aspect, 1, 10000); + camera.position.z = 2500; + + cameraPerspective = new THREE.PerspectiveCamera(50, 0.5 * aspect, 150, 1000); + + cameraPerspectiveHelper = new THREE.CameraHelper(cameraPerspective); + scene.add(cameraPerspectiveHelper); + + // + cameraOrtho = new THREE.OrthographicCamera( + (0.5 * frustumSize * aspect) / -2, + (0.5 * frustumSize * aspect) / 2, + frustumSize / 2, + frustumSize / -2, + 150, + 1000, + ); + + cameraOrthoHelper = new THREE.CameraHelper(cameraOrtho); + scene.add(cameraOrthoHelper); + + // + + activeCamera = cameraPerspective; + activeHelper = cameraPerspectiveHelper; + + // counteract different front orientation of cameras vs rig + + cameraOrtho.rotation.y = Math.PI; + cameraPerspective.rotation.y = Math.PI; + + cameraRig = new THREE.Group(); + + cameraRig.add(cameraPerspective); + cameraRig.add(cameraOrtho); + + scene.add(cameraRig); + + // + + mesh = new THREE.Mesh( + new THREE.SphereGeometry(100, 16, 8), + new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }), + ); + scene.add(mesh); + + const mesh2 = new THREE.Mesh( + new THREE.SphereGeometry(50, 16, 8), + new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }), + ); + mesh2.position.y = 150; + mesh.add(mesh2); + + const mesh3 = new THREE.Mesh( + new THREE.SphereGeometry(5, 16, 8), + new THREE.MeshBasicMaterial({ color: 0x0000ff, wireframe: true }), + ); + mesh3.position.z = 150; + cameraRig.add(mesh3); + + // + + const geometry = new THREE.BufferGeometry(); + const vertices = []; + + for (let i = 0; i < 10000; i++) { + vertices.push(THREE.MathUtils.randFloatSpread(2000)); // x + vertices.push(THREE.MathUtils.randFloatSpread(2000)); // y + vertices.push(THREE.MathUtils.randFloatSpread(2000)); // z + } + + geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); + + const particles = new THREE.Points(geometry, new THREE.PointsMaterial({ color: 0x888888 })); + scene.add(particles); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); + container.appendChild(renderer.domElement); + + renderer.autoClear = false; + + // + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); + document.addEventListener('keydown', onKeyDown); +} + +// + +function onKeyDown(event) { + switch (event.keyCode) { + case 79 /*O*/: + activeCamera = cameraOrtho; + activeHelper = cameraOrthoHelper; + + break; + + case 80 /*P*/: + activeCamera = cameraPerspective; + activeHelper = cameraPerspectiveHelper; + + break; + } +} + +// + +function onWindowResize() { + SCREEN_WIDTH = window.innerWidth; + SCREEN_HEIGHT = window.innerHeight; + aspect = SCREEN_WIDTH / SCREEN_HEIGHT; + + renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); + + camera.aspect = 0.5 * aspect; + camera.updateProjectionMatrix(); + + cameraPerspective.aspect = 0.5 * aspect; + cameraPerspective.updateProjectionMatrix(); + + cameraOrtho.left = (-0.5 * frustumSize * aspect) / 2; + cameraOrtho.right = (0.5 * frustumSize * aspect) / 2; + cameraOrtho.top = frustumSize / 2; + cameraOrtho.bottom = -frustumSize / 2; + cameraOrtho.updateProjectionMatrix(); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const r = Date.now() * 0.0005; + + mesh.position.x = 700 * Math.cos(r); + mesh.position.z = 700 * Math.sin(r); + mesh.position.y = 700 * Math.sin(r); + + mesh.children[0].position.x = 70 * Math.cos(2 * r); + mesh.children[0].position.z = 70 * Math.sin(r); + + if (activeCamera === cameraPerspective) { + cameraPerspective.fov = 35 + 30 * Math.sin(0.5 * r); + cameraPerspective.far = mesh.position.length(); + cameraPerspective.updateProjectionMatrix(); + + cameraPerspectiveHelper.update(); + cameraPerspectiveHelper.visible = true; + + cameraOrthoHelper.visible = false; + } else { + cameraOrtho.far = mesh.position.length(); + cameraOrtho.updateProjectionMatrix(); + + cameraOrthoHelper.update(); + cameraOrthoHelper.visible = true; + + cameraPerspectiveHelper.visible = false; + } + + cameraRig.lookAt(mesh.position); + + renderer.clear(); + + activeHelper.visible = false; + + renderer.setViewport(0, 0, SCREEN_WIDTH / 2, SCREEN_HEIGHT); + renderer.render(scene, activeCamera); + + activeHelper.visible = true; + + renderer.setViewport(SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2, SCREEN_HEIGHT); + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts b/examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts new file mode 100644 index 000000000..a80cc19e9 --- /dev/null +++ b/examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts @@ -0,0 +1,248 @@ +import * as THREE from 'three'; + +import { FontLoader } from 'three/addons/loaders/FontLoader.js'; +import { TextGeometry } from 'three/addons/geometries/TextGeometry.js'; + +import Stats from 'three/addons/libs/stats.module.js'; + +// 1 micrometer to 100 billion light years in one scene, with 1 unit = 1 meter? preposterous! and yet... +const NEAR = 1e-6, + FAR = 1e27; +let SCREEN_WIDTH = window.innerWidth; +let SCREEN_HEIGHT = window.innerHeight; +let screensplit = 0.25, + screensplit_right = 0; +const mouse = [0.5, 0.5]; +let zoompos = -100, + minzoomspeed = 0.015; +let zoomspeed = minzoomspeed; + +let container, border, stats; +const objects = {}; + +// Generate a number of text labels, from 1µm in size up to 100,000,000 light years +// Try to use some descriptive real-world examples of objects at each scale + +const labeldata = [ + { size: 0.01, scale: 0.0001, label: 'microscopic (1µm)' }, // FIXME - triangulating text fails at this size, so we scale instead + { size: 0.01, scale: 0.1, label: 'minuscule (1mm)' }, + { size: 0.01, scale: 1.0, label: 'tiny (1cm)' }, + { size: 1, scale: 1.0, label: 'child-sized (1m)' }, + { size: 10, scale: 1.0, label: 'tree-sized (10m)' }, + { size: 100, scale: 1.0, label: 'building-sized (100m)' }, + { size: 1000, scale: 1.0, label: 'medium (1km)' }, + { size: 10000, scale: 1.0, label: 'city-sized (10km)' }, + { size: 3400000, scale: 1.0, label: 'moon-sized (3,400 Km)' }, + { size: 12000000, scale: 1.0, label: 'planet-sized (12,000 km)' }, + { size: 1400000000, scale: 1.0, label: 'sun-sized (1,400,000 km)' }, + { size: 7.47e12, scale: 1.0, label: 'solar system-sized (50Au)' }, + { size: 9.4605284e15, scale: 1.0, label: 'gargantuan (1 light year)' }, + { size: 3.08567758e16, scale: 1.0, label: 'ludicrous (1 parsec)' }, + { size: 1e19, scale: 1.0, label: 'mind boggling (1000 light years)' }, +]; + +init(); + +function init() { + container = document.getElementById('container'); + + const loader = new FontLoader(); + loader.load('fonts/helvetiker_regular.typeface.json', function (font) { + const scene = initScene(font); + + // Initialize two copies of the same scene, one with normal z-buffer and one with logarithmic z-buffer + objects.normal = initView(scene, 'normal', false); + objects.logzbuf = initView(scene, 'logzbuf', true); + + animate(); + }); + + stats = new Stats(); + container.appendChild(stats.dom); + + // Resize border allows the user to easily compare effects of logarithmic depth buffer over the whole scene + border = document.getElementById('renderer_border'); + border.addEventListener('pointerdown', onBorderPointerDown); + + window.addEventListener('mousemove', onMouseMove); + window.addEventListener('resize', onWindowResize); + window.addEventListener('wheel', onMouseWheel); +} + +function initView(scene, name, logDepthBuf) { + const framecontainer = document.getElementById('container_' + name); + + const camera = new THREE.PerspectiveCamera(50, (screensplit * SCREEN_WIDTH) / SCREEN_HEIGHT, NEAR, FAR); + scene.add(camera); + + const renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: logDepthBuf }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(SCREEN_WIDTH / 2, SCREEN_HEIGHT); + renderer.domElement.style.position = 'relative'; + renderer.domElement.id = 'renderer_' + name; + framecontainer.appendChild(renderer.domElement); + + return { container: framecontainer, renderer: renderer, scene: scene, camera: camera }; +} + +function initScene(font) { + const scene = new THREE.Scene(); + + scene.add(new THREE.AmbientLight(0x777777)); + + const light = new THREE.DirectionalLight(0xffffff, 3); + light.position.set(100, 100, 100); + scene.add(light); + + const materialargs = { + color: 0xffffff, + specular: 0x050505, + shininess: 50, + emissive: 0x000000, + }; + + const geometry = new THREE.SphereGeometry(0.5, 24, 12); + + for (let i = 0; i < labeldata.length; i++) { + const scale = labeldata[i].scale || 1; + + const labelgeo = new TextGeometry(labeldata[i].label, { + font: font, + size: labeldata[i].size, + height: labeldata[i].size / 2, + }); + + labelgeo.computeBoundingSphere(); + + // center text + labelgeo.translate(-labelgeo.boundingSphere.radius, 0, 0); + + materialargs.color = new THREE.Color().setHSL(Math.random(), 0.5, 0.5); + + const material = new THREE.MeshPhongMaterial(materialargs); + + const group = new THREE.Group(); + group.position.z = -labeldata[i].size * scale; + scene.add(group); + + const textmesh = new THREE.Mesh(labelgeo, material); + textmesh.scale.set(scale, scale, scale); + textmesh.position.z = -labeldata[i].size * scale; + textmesh.position.y = (labeldata[i].size / 4) * scale; + group.add(textmesh); + + const dotmesh = new THREE.Mesh(geometry, material); + dotmesh.position.y = (-labeldata[i].size / 4) * scale; + dotmesh.scale.multiplyScalar(labeldata[i].size * scale); + group.add(dotmesh); + } + + return scene; +} + +function updateRendererSizes() { + // Recalculate size for both renderers when screen size or split location changes + + SCREEN_WIDTH = window.innerWidth; + SCREEN_HEIGHT = window.innerHeight; + + screensplit_right = 1 - screensplit; + + objects.normal.renderer.setSize(screensplit * SCREEN_WIDTH, SCREEN_HEIGHT); + objects.normal.camera.aspect = (screensplit * SCREEN_WIDTH) / SCREEN_HEIGHT; + objects.normal.camera.updateProjectionMatrix(); + objects.normal.camera.setViewOffset(SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, SCREEN_WIDTH * screensplit, SCREEN_HEIGHT); + objects.normal.container.style.width = screensplit * 100 + '%'; + + objects.logzbuf.renderer.setSize(screensplit_right * SCREEN_WIDTH, SCREEN_HEIGHT); + objects.logzbuf.camera.aspect = (screensplit_right * SCREEN_WIDTH) / SCREEN_HEIGHT; + objects.logzbuf.camera.updateProjectionMatrix(); + objects.logzbuf.camera.setViewOffset( + SCREEN_WIDTH, + SCREEN_HEIGHT, + SCREEN_WIDTH * screensplit, + 0, + SCREEN_WIDTH * screensplit_right, + SCREEN_HEIGHT, + ); + objects.logzbuf.container.style.width = screensplit_right * 100 + '%'; + + border.style.left = screensplit * 100 + '%'; +} + +function animate() { + requestAnimationFrame(animate); + render(); +} + +function render() { + // Put some limits on zooming + const minzoom = labeldata[0].size * labeldata[0].scale * 1; + const maxzoom = labeldata[labeldata.length - 1].size * labeldata[labeldata.length - 1].scale * 100; + let damping = Math.abs(zoomspeed) > minzoomspeed ? 0.95 : 1.0; + + // Zoom out faster the further out you go + const zoom = THREE.MathUtils.clamp(Math.pow(Math.E, zoompos), minzoom, maxzoom); + zoompos = Math.log(zoom); + + // Slow down quickly at the zoom limits + if ((zoom == minzoom && zoomspeed < 0) || (zoom == maxzoom && zoomspeed > 0)) { + damping = 0.85; + } + + zoompos += zoomspeed; + zoomspeed *= damping; + + objects.normal.camera.position.x = Math.sin(0.5 * Math.PI * (mouse[0] - 0.5)) * zoom; + objects.normal.camera.position.y = Math.sin(0.25 * Math.PI * (mouse[1] - 0.5)) * zoom; + objects.normal.camera.position.z = Math.cos(0.5 * Math.PI * (mouse[0] - 0.5)) * zoom; + objects.normal.camera.lookAt(objects.normal.scene.position); + + // Clone camera settings across both scenes + objects.logzbuf.camera.position.copy(objects.normal.camera.position); + objects.logzbuf.camera.quaternion.copy(objects.normal.camera.quaternion); + + // Update renderer sizes if the split has changed + if (screensplit_right != 1 - screensplit) { + updateRendererSizes(); + } + + objects.normal.renderer.render(objects.normal.scene, objects.normal.camera); + objects.logzbuf.renderer.render(objects.logzbuf.scene, objects.logzbuf.camera); + + stats.update(); +} + +function onWindowResize() { + updateRendererSizes(); +} + +function onBorderPointerDown() { + // activate draggable window resizing bar + window.addEventListener('pointermove', onBorderPointerMove); + window.addEventListener('pointerup', onBorderPointerUp); +} + +function onBorderPointerMove(ev) { + screensplit = Math.max(0, Math.min(1, ev.clientX / window.innerWidth)); +} + +function onBorderPointerUp() { + window.removeEventListener('pointermove', onBorderPointerMove); + window.removeEventListener('pointerup', onBorderPointerUp); +} + +function onMouseMove(ev) { + mouse[0] = ev.clientX / window.innerWidth; + mouse[1] = ev.clientY / window.innerHeight; +} + +function onMouseWheel(ev) { + const amount = ev.deltaY; + if (amount === 0) return; + const dir = amount / Math.abs(amount); + zoomspeed = dir / 10; + + // Slow down default zoom speed after user starts zooming, to give them more control + minzoomspeed = 0.001; +} diff --git a/examples-testing/examples/webgl_clipping.ts b/examples-testing/examples/webgl_clipping.ts new file mode 100644 index 000000000..f0a18f3ab --- /dev/null +++ b/examples-testing/examples/webgl_clipping.ts @@ -0,0 +1,184 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +let camera, scene, renderer, startTime, object, stats; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(36, window.innerWidth / window.innerHeight, 0.25, 16); + + camera.position.set(0, 1.3, 3); + + scene = new THREE.Scene(); + + // Lights + + scene.add(new THREE.AmbientLight(0xcccccc)); + + const spotLight = new THREE.SpotLight(0xffffff, 60); + spotLight.angle = Math.PI / 5; + spotLight.penumbra = 0.2; + spotLight.position.set(2, 3, 3); + spotLight.castShadow = true; + spotLight.shadow.camera.near = 3; + spotLight.shadow.camera.far = 10; + spotLight.shadow.mapSize.width = 1024; + spotLight.shadow.mapSize.height = 1024; + scene.add(spotLight); + + const dirLight = new THREE.DirectionalLight(0x55505a, 3); + dirLight.position.set(0, 3, 0); + dirLight.castShadow = true; + dirLight.shadow.camera.near = 1; + dirLight.shadow.camera.far = 10; + + dirLight.shadow.camera.right = 1; + dirLight.shadow.camera.left = -1; + dirLight.shadow.camera.top = 1; + dirLight.shadow.camera.bottom = -1; + + dirLight.shadow.mapSize.width = 1024; + dirLight.shadow.mapSize.height = 1024; + scene.add(dirLight); + + // ***** Clipping planes: ***** + + const localPlane = new THREE.Plane(new THREE.Vector3(0, -1, 0), 0.8); + const globalPlane = new THREE.Plane(new THREE.Vector3(-1, 0, 0), 0.1); + + // Geometry + + const material = new THREE.MeshPhongMaterial({ + color: 0x80ee10, + shininess: 100, + side: THREE.DoubleSide, + + // ***** Clipping setup (material): ***** + clippingPlanes: [localPlane], + clipShadows: true, + }); + + const geometry = new THREE.TorusKnotGeometry(0.4, 0.08, 95, 20); + + object = new THREE.Mesh(geometry, material); + object.castShadow = true; + scene.add(object); + + const ground = new THREE.Mesh( + new THREE.PlaneGeometry(9, 9, 1, 1), + new THREE.MeshPhongMaterial({ color: 0xa0adaf, shininess: 150 }), + ); + + ground.rotation.x = -Math.PI / 2; // rotates X/Y to X/Z + ground.receiveShadow = true; + scene.add(ground); + + // Stats + + stats = new Stats(); + document.body.appendChild(stats.dom); + + // Renderer + + renderer = new THREE.WebGLRenderer(); + renderer.shadowMap.enabled = true; + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + window.addEventListener('resize', onWindowResize); + document.body.appendChild(renderer.domElement); + + // ***** Clipping setup (renderer): ***** + const globalPlanes = [globalPlane], + Empty = Object.freeze([]); + renderer.clippingPlanes = Empty; // GUI sets it to globalPlanes + renderer.localClippingEnabled = true; + + // Controls + + const controls = new OrbitControls(camera, renderer.domElement); + controls.target.set(0, 1, 0); + controls.update(); + + // GUI + + const gui = new GUI(), + folderLocal = gui.addFolder('Local Clipping'), + propsLocal = { + get Enabled() { + return renderer.localClippingEnabled; + }, + set Enabled(v) { + renderer.localClippingEnabled = v; + }, + + get Shadows() { + return material.clipShadows; + }, + set Shadows(v) { + material.clipShadows = v; + }, + + get Plane() { + return localPlane.constant; + }, + set Plane(v) { + localPlane.constant = v; + }, + }, + folderGlobal = gui.addFolder('Global Clipping'), + propsGlobal = { + get Enabled() { + return renderer.clippingPlanes !== Empty; + }, + set Enabled(v) { + renderer.clippingPlanes = v ? globalPlanes : Empty; + }, + + get Plane() { + return globalPlane.constant; + }, + set Plane(v) { + globalPlane.constant = v; + }, + }; + + folderLocal.add(propsLocal, 'Enabled'); + folderLocal.add(propsLocal, 'Shadows'); + folderLocal.add(propsLocal, 'Plane', 0.3, 1.25); + + folderGlobal.add(propsGlobal, 'Enabled'); + folderGlobal.add(propsGlobal, 'Plane', -0.4, 3); + + // Start + + startTime = Date.now(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + const currentTime = Date.now(); + const time = (currentTime - startTime) / 1000; + + requestAnimationFrame(animate); + + object.position.y = 0.8; + object.rotation.x = time * 0.5; + object.rotation.y = time * 0.2; + object.scale.setScalar(Math.cos(time) * 0.125 + 0.875); + + stats.begin(); + renderer.render(scene, camera); + stats.end(); +} diff --git a/examples-testing/examples/webgl_clipping_advanced.ts b/examples-testing/examples/webgl_clipping_advanced.ts new file mode 100644 index 000000000..d60532ca2 --- /dev/null +++ b/examples-testing/examples/webgl_clipping_advanced.ts @@ -0,0 +1,356 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +function planesFromMesh(vertices, indices) { + // creates a clipping volume from a convex triangular mesh + // specified by the arrays 'vertices' and 'indices' + + const n = indices.length / 3, + result = new Array(n); + + for (let i = 0, j = 0; i < n; ++i, j += 3) { + const a = vertices[indices[j]], + b = vertices[indices[j + 1]], + c = vertices[indices[j + 2]]; + + result[i] = new THREE.Plane().setFromCoplanarPoints(a, b, c); + } + + return result; +} + +function createPlanes(n) { + // creates an array of n uninitialized plane objects + + const result = new Array(n); + + for (let i = 0; i !== n; ++i) result[i] = new THREE.Plane(); + + return result; +} + +function assignTransformedPlanes(planesOut, planesIn, matrix) { + // sets an array of existing planes to transformed 'planesIn' + + for (let i = 0, n = planesIn.length; i !== n; ++i) planesOut[i].copy(planesIn[i]).applyMatrix4(matrix); +} + +function cylindricalPlanes(n, innerRadius) { + const result = createPlanes(n); + + for (let i = 0; i !== n; ++i) { + const plane = result[i], + angle = (i * Math.PI * 2) / n; + + plane.normal.set(Math.cos(angle), 0, Math.sin(angle)); + + plane.constant = innerRadius; + } + + return result; +} + +const planeToMatrix = (function () { + // creates a matrix that aligns X/Y to a given plane + + // temporaries: + const xAxis = new THREE.Vector3(), + yAxis = new THREE.Vector3(), + trans = new THREE.Vector3(); + + return function planeToMatrix(plane) { + const zAxis = plane.normal, + matrix = new THREE.Matrix4(); + + // Hughes & Moeller '99 + // "Building an Orthonormal Basis from a Unit Vector." + + if (Math.abs(zAxis.x) > Math.abs(zAxis.z)) { + yAxis.set(-zAxis.y, zAxis.x, 0); + } else { + yAxis.set(0, -zAxis.z, zAxis.y); + } + + xAxis.crossVectors(yAxis.normalize(), zAxis); + + plane.coplanarPoint(trans); + return matrix.set( + xAxis.x, + yAxis.x, + zAxis.x, + trans.x, + xAxis.y, + yAxis.y, + zAxis.y, + trans.y, + xAxis.z, + yAxis.z, + zAxis.z, + trans.z, + 0, + 0, + 0, + 1, + ); + }; +})(); + +// A regular tetrahedron for the clipping volume: + +const Vertices = [ + new THREE.Vector3(+1, 0, +Math.SQRT1_2), + new THREE.Vector3(-1, 0, +Math.SQRT1_2), + new THREE.Vector3(0, +1, -Math.SQRT1_2), + new THREE.Vector3(0, -1, -Math.SQRT1_2), + ], + Indices = [0, 1, 2, 0, 2, 3, 0, 3, 1, 1, 3, 2], + Planes = planesFromMesh(Vertices, Indices), + PlaneMatrices = Planes.map(planeToMatrix), + GlobalClippingPlanes = cylindricalPlanes(5, 2.5), + Empty = Object.freeze([]); + +let camera, scene, renderer, startTime, stats, object, clipMaterial, volumeVisualization, globalClippingPlanes; + +function init() { + camera = new THREE.PerspectiveCamera(36, window.innerWidth / window.innerHeight, 0.25, 16); + + camera.position.set(0, 1.5, 3); + + scene = new THREE.Scene(); + + // Lights + + scene.add(new THREE.AmbientLight(0xffffff)); + + const spotLight = new THREE.SpotLight(0xffffff, 60); + spotLight.angle = Math.PI / 5; + spotLight.penumbra = 0.2; + spotLight.position.set(2, 3, 3); + spotLight.castShadow = true; + spotLight.shadow.camera.near = 3; + spotLight.shadow.camera.far = 10; + spotLight.shadow.mapSize.width = 1024; + spotLight.shadow.mapSize.height = 1024; + scene.add(spotLight); + + const dirLight = new THREE.DirectionalLight(0xffffff, 1.5); + dirLight.position.set(0, 2, 0); + dirLight.castShadow = true; + dirLight.shadow.camera.near = 1; + dirLight.shadow.camera.far = 10; + + dirLight.shadow.camera.right = 1; + dirLight.shadow.camera.left = -1; + dirLight.shadow.camera.top = 1; + dirLight.shadow.camera.bottom = -1; + + dirLight.shadow.mapSize.width = 1024; + dirLight.shadow.mapSize.height = 1024; + scene.add(dirLight); + + // Geometry + + clipMaterial = new THREE.MeshPhongMaterial({ + color: 0xee0a10, + shininess: 100, + side: THREE.DoubleSide, + // Clipping setup: + clippingPlanes: createPlanes(Planes.length), + clipShadows: true, + }); + + object = new THREE.Group(); + + const geometry = new THREE.BoxGeometry(0.18, 0.18, 0.18); + + for (let z = -2; z <= 2; ++z) + for (let y = -2; y <= 2; ++y) + for (let x = -2; x <= 2; ++x) { + const mesh = new THREE.Mesh(geometry, clipMaterial); + mesh.position.set(x / 5, y / 5, z / 5); + mesh.castShadow = true; + object.add(mesh); + } + + scene.add(object); + + const planeGeometry = new THREE.PlaneGeometry(3, 3, 1, 1), + color = new THREE.Color(); + + volumeVisualization = new THREE.Group(); + volumeVisualization.visible = false; + + for (let i = 0, n = Planes.length; i !== n; ++i) { + const material = new THREE.MeshBasicMaterial({ + color: color.setHSL(i / n, 0.5, 0.5).getHex(), + side: THREE.DoubleSide, + + opacity: 0.2, + transparent: true, + + // clip to the others to show the volume (wildly + // intersecting transparent planes look bad) + clippingPlanes: clipMaterial.clippingPlanes.filter(function (_, j) { + return j !== i; + }), + + // no need to enable shadow clipping - the plane + // visualization does not cast shadows + }); + + const mesh = new THREE.Mesh(planeGeometry, material); + mesh.matrixAutoUpdate = false; + + volumeVisualization.add(mesh); + } + + scene.add(volumeVisualization); + + const ground = new THREE.Mesh( + planeGeometry, + new THREE.MeshPhongMaterial({ + color: 0xa0adaf, + shininess: 10, + }), + ); + ground.rotation.x = -Math.PI / 2; + ground.scale.multiplyScalar(3); + ground.receiveShadow = true; + scene.add(ground); + + // Renderer + + const container = document.body; + + renderer = new THREE.WebGLRenderer(); + renderer.shadowMap.enabled = true; + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + window.addEventListener('resize', onWindowResize); + container.appendChild(renderer.domElement); + // Clipping setup: + globalClippingPlanes = createPlanes(GlobalClippingPlanes.length); + renderer.clippingPlanes = Empty; + renderer.localClippingEnabled = true; + + // Stats + + stats = new Stats(); + container.appendChild(stats.dom); + + // Controls + + const controls = new OrbitControls(camera, renderer.domElement); + controls.minDistance = 1; + controls.maxDistance = 8; + controls.target.set(0, 1, 0); + controls.update(); + + // GUI + + const gui = new GUI(), + folder = gui.addFolder('Local Clipping'), + props = { + get Enabled() { + return renderer.localClippingEnabled; + }, + set Enabled(v) { + renderer.localClippingEnabled = v; + if (!v) volumeVisualization.visible = false; + }, + + get Shadows() { + return clipMaterial.clipShadows; + }, + set Shadows(v) { + clipMaterial.clipShadows = v; + }, + + get Visualize() { + return volumeVisualization.visible; + }, + set Visualize(v) { + if (renderer.localClippingEnabled) volumeVisualization.visible = v; + }, + }; + + folder.add(props, 'Enabled'); + folder.add(props, 'Shadows'); + folder.add(props, 'Visualize').listen(); + + gui.addFolder('Global Clipping').add( + { + get Enabled() { + return renderer.clippingPlanes !== Empty; + }, + set Enabled(v) { + renderer.clippingPlanes = v ? globalClippingPlanes : Empty; + }, + }, + 'Enabled', + ); + + // Start + + startTime = Date.now(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function setObjectWorldMatrix(object, matrix) { + // set the orientation of an object based on a world matrix + + const parent = object.parent; + scene.updateMatrixWorld(); + object.matrix.copy(parent.matrixWorld).invert(); + object.applyMatrix4(matrix); +} + +const transform = new THREE.Matrix4(), + tmpMatrix = new THREE.Matrix4(); + +function animate() { + const currentTime = Date.now(), + time = (currentTime - startTime) / 1000; + + requestAnimationFrame(animate); + + object.position.y = 1; + object.rotation.x = time * 0.5; + object.rotation.y = time * 0.2; + + object.updateMatrix(); + transform.copy(object.matrix); + + const bouncy = Math.cos(time * 0.5) * 0.5 + 0.7; + transform.multiply(tmpMatrix.makeScale(bouncy, bouncy, bouncy)); + + assignTransformedPlanes(clipMaterial.clippingPlanes, Planes, transform); + + const planeMeshes = volumeVisualization.children; + + for (let i = 0, n = planeMeshes.length; i !== n; ++i) { + tmpMatrix.multiplyMatrices(transform, PlaneMatrices[i]); + setObjectWorldMatrix(planeMeshes[i], tmpMatrix); + } + + transform.makeRotationY(time * 0.1); + + assignTransformedPlanes(globalClippingPlanes, GlobalClippingPlanes, transform); + + stats.begin(); + renderer.render(scene, camera); + stats.end(); +} + +init(); +animate(); diff --git a/examples-testing/examples/webgl_clipping_intersection.ts b/examples-testing/examples/webgl_clipping_intersection.ts new file mode 100644 index 000000000..74022d774 --- /dev/null +++ b/examples-testing/examples/webgl_clipping_intersection.ts @@ -0,0 +1,126 @@ +import * as THREE from 'three'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +let camera, scene, renderer; + +const params = { + clipIntersection: true, + planeConstant: 0, + showHelpers: false, +}; + +const clipPlanes = [ + new THREE.Plane(new THREE.Vector3(1, 0, 0), 0), + new THREE.Plane(new THREE.Vector3(0, -1, 0), 0), + new THREE.Plane(new THREE.Vector3(0, 0, -1), 0), +]; + +init(); +render(); + +function init() { + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.localClippingEnabled = true; + document.body.appendChild(renderer.domElement); + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 200); + + camera.position.set(-1.5, 2.5, 3.0); + + const controls = new OrbitControls(camera, renderer.domElement); + controls.addEventListener('change', render); // use only if there is no animation loop + controls.minDistance = 1; + controls.maxDistance = 10; + controls.enablePan = false; + + const light = new THREE.HemisphereLight(0xffffff, 0x080808, 4.5); + light.position.set(-1.25, 1, 1.25); + scene.add(light); + + // + + const group = new THREE.Group(); + + for (let i = 1; i <= 30; i += 2) { + const geometry = new THREE.SphereGeometry(i / 30, 48, 24); + + const material = new THREE.MeshLambertMaterial({ + color: new THREE.Color().setHSL(Math.random(), 0.5, 0.5, THREE.SRGBColorSpace), + side: THREE.DoubleSide, + clippingPlanes: clipPlanes, + clipIntersection: params.clipIntersection, + }); + + group.add(new THREE.Mesh(geometry, material)); + } + + scene.add(group); + + // helpers + + const helpers = new THREE.Group(); + helpers.add(new THREE.PlaneHelper(clipPlanes[0], 2, 0xff0000)); + helpers.add(new THREE.PlaneHelper(clipPlanes[1], 2, 0x00ff00)); + helpers.add(new THREE.PlaneHelper(clipPlanes[2], 2, 0x0000ff)); + helpers.visible = false; + scene.add(helpers); + + // gui + + const gui = new GUI(); + + gui.add(params, 'clipIntersection') + .name('clip intersection') + .onChange(function (value) { + const children = group.children; + + for (let i = 0; i < children.length; i++) { + children[i].material.clipIntersection = value; + } + + render(); + }); + + gui.add(params, 'planeConstant', -1, 1) + .step(0.01) + .name('plane constant') + .onChange(function (value) { + for (let j = 0; j < clipPlanes.length; j++) { + clipPlanes[j].constant = value; + } + + render(); + }); + + gui.add(params, 'showHelpers') + .name('show helpers') + .onChange(function (value) { + helpers.visible = value; + + render(); + }); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + render(); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_clipping_stencil.ts b/examples-testing/examples/webgl_clipping_stencil.ts new file mode 100644 index 000000000..365087d65 --- /dev/null +++ b/examples-testing/examples/webgl_clipping_stencil.ts @@ -0,0 +1,260 @@ +import * as THREE from 'three'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import Stats from 'three/addons/libs/stats.module.js'; + +let camera, scene, renderer, object, stats; +let planes, planeObjects, planeHelpers; +let clock; + +const params = { + animate: true, + planeX: { + constant: 0, + negated: false, + displayHelper: false, + }, + planeY: { + constant: 0, + negated: false, + displayHelper: false, + }, + planeZ: { + constant: 0, + negated: false, + displayHelper: false, + }, +}; + +init(); +animate(); + +function createPlaneStencilGroup(geometry, plane, renderOrder) { + const group = new THREE.Group(); + const baseMat = new THREE.MeshBasicMaterial(); + baseMat.depthWrite = false; + baseMat.depthTest = false; + baseMat.colorWrite = false; + baseMat.stencilWrite = true; + baseMat.stencilFunc = THREE.AlwaysStencilFunc; + + // back faces + const mat0 = baseMat.clone(); + mat0.side = THREE.BackSide; + mat0.clippingPlanes = [plane]; + mat0.stencilFail = THREE.IncrementWrapStencilOp; + mat0.stencilZFail = THREE.IncrementWrapStencilOp; + mat0.stencilZPass = THREE.IncrementWrapStencilOp; + + const mesh0 = new THREE.Mesh(geometry, mat0); + mesh0.renderOrder = renderOrder; + group.add(mesh0); + + // front faces + const mat1 = baseMat.clone(); + mat1.side = THREE.FrontSide; + mat1.clippingPlanes = [plane]; + mat1.stencilFail = THREE.DecrementWrapStencilOp; + mat1.stencilZFail = THREE.DecrementWrapStencilOp; + mat1.stencilZPass = THREE.DecrementWrapStencilOp; + + const mesh1 = new THREE.Mesh(geometry, mat1); + mesh1.renderOrder = renderOrder; + + group.add(mesh1); + + return group; +} + +function init() { + clock = new THREE.Clock(); + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(36, window.innerWidth / window.innerHeight, 1, 100); + camera.position.set(2, 2, 2); + + scene.add(new THREE.AmbientLight(0xffffff, 1.5)); + + const dirLight = new THREE.DirectionalLight(0xffffff, 3); + dirLight.position.set(5, 10, 7.5); + dirLight.castShadow = true; + dirLight.shadow.camera.right = 2; + dirLight.shadow.camera.left = -2; + dirLight.shadow.camera.top = 2; + dirLight.shadow.camera.bottom = -2; + + dirLight.shadow.mapSize.width = 1024; + dirLight.shadow.mapSize.height = 1024; + scene.add(dirLight); + + planes = [ + new THREE.Plane(new THREE.Vector3(-1, 0, 0), 0), + new THREE.Plane(new THREE.Vector3(0, -1, 0), 0), + new THREE.Plane(new THREE.Vector3(0, 0, -1), 0), + ]; + + planeHelpers = planes.map(p => new THREE.PlaneHelper(p, 2, 0xffffff)); + planeHelpers.forEach(ph => { + ph.visible = false; + scene.add(ph); + }); + + const geometry = new THREE.TorusKnotGeometry(0.4, 0.15, 220, 60); + object = new THREE.Group(); + scene.add(object); + + // Set up clip plane rendering + planeObjects = []; + const planeGeom = new THREE.PlaneGeometry(4, 4); + + for (let i = 0; i < 3; i++) { + const poGroup = new THREE.Group(); + const plane = planes[i]; + const stencilGroup = createPlaneStencilGroup(geometry, plane, i + 1); + + // plane is clipped by the other clipping planes + const planeMat = new THREE.MeshStandardMaterial({ + color: 0xe91e63, + metalness: 0.1, + roughness: 0.75, + clippingPlanes: planes.filter(p => p !== plane), + + stencilWrite: true, + stencilRef: 0, + stencilFunc: THREE.NotEqualStencilFunc, + stencilFail: THREE.ReplaceStencilOp, + stencilZFail: THREE.ReplaceStencilOp, + stencilZPass: THREE.ReplaceStencilOp, + }); + const po = new THREE.Mesh(planeGeom, planeMat); + po.onAfterRender = function (renderer) { + renderer.clearStencil(); + }; + + po.renderOrder = i + 1.1; + + object.add(stencilGroup); + poGroup.add(po); + planeObjects.push(po); + scene.add(poGroup); + } + + const material = new THREE.MeshStandardMaterial({ + color: 0xffc107, + metalness: 0.1, + roughness: 0.75, + clippingPlanes: planes, + clipShadows: true, + shadowSide: THREE.DoubleSide, + }); + + // add the color + const clippedColorFront = new THREE.Mesh(geometry, material); + clippedColorFront.castShadow = true; + clippedColorFront.renderOrder = 6; + object.add(clippedColorFront); + + const ground = new THREE.Mesh( + new THREE.PlaneGeometry(9, 9, 1, 1), + new THREE.ShadowMaterial({ color: 0x000000, opacity: 0.25, side: THREE.DoubleSide }), + ); + + ground.rotation.x = -Math.PI / 2; // rotates X/Y to X/Z + ground.position.y = -1; + ground.receiveShadow = true; + scene.add(ground); + + // Stats + stats = new Stats(); + document.body.appendChild(stats.dom); + + // Renderer + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.shadowMap.enabled = true; + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.setClearColor(0x263238); + window.addEventListener('resize', onWindowResize); + document.body.appendChild(renderer.domElement); + + renderer.localClippingEnabled = true; + + // Controls + const controls = new OrbitControls(camera, renderer.domElement); + controls.minDistance = 2; + controls.maxDistance = 20; + controls.update(); + + // GUI + const gui = new GUI(); + gui.add(params, 'animate'); + + const planeX = gui.addFolder('planeX'); + planeX.add(params.planeX, 'displayHelper').onChange(v => (planeHelpers[0].visible = v)); + planeX + .add(params.planeX, 'constant') + .min(-1) + .max(1) + .onChange(d => (planes[0].constant = d)); + planeX.add(params.planeX, 'negated').onChange(() => { + planes[0].negate(); + params.planeX.constant = planes[0].constant; + }); + planeX.open(); + + const planeY = gui.addFolder('planeY'); + planeY.add(params.planeY, 'displayHelper').onChange(v => (planeHelpers[1].visible = v)); + planeY + .add(params.planeY, 'constant') + .min(-1) + .max(1) + .onChange(d => (planes[1].constant = d)); + planeY.add(params.planeY, 'negated').onChange(() => { + planes[1].negate(); + params.planeY.constant = planes[1].constant; + }); + planeY.open(); + + const planeZ = gui.addFolder('planeZ'); + planeZ.add(params.planeZ, 'displayHelper').onChange(v => (planeHelpers[2].visible = v)); + planeZ + .add(params.planeZ, 'constant') + .min(-1) + .max(1) + .onChange(d => (planes[2].constant = d)); + planeZ.add(params.planeZ, 'negated').onChange(() => { + planes[2].negate(); + params.planeZ.constant = planes[2].constant; + }); + planeZ.open(); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + const delta = clock.getDelta(); + + requestAnimationFrame(animate); + + if (params.animate) { + object.rotation.x += delta * 0.5; + object.rotation.y += delta * 0.2; + } + + for (let i = 0; i < planeObjects.length; i++) { + const plane = planes[i]; + const po = planeObjects[i]; + plane.coplanarPoint(po.position); + po.lookAt(po.position.x - plane.normal.x, po.position.y - plane.normal.y, po.position.z - plane.normal.z); + } + + stats.begin(); + renderer.render(scene, camera); + stats.end(); +} diff --git a/examples-testing/examples/webgl_custom_attributes.ts b/examples-testing/examples/webgl_custom_attributes.ts new file mode 100644 index 000000000..648e097dd --- /dev/null +++ b/examples-testing/examples/webgl_custom_attributes.ts @@ -0,0 +1,102 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let renderer, scene, camera, stats; + +let sphere, uniforms; + +let displacement, noise; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 10000); + camera.position.z = 300; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x050505); + + uniforms = { + amplitude: { value: 1.0 }, + color: { value: new THREE.Color(0xff2200) }, + colorTexture: { value: new THREE.TextureLoader().load('textures/water.jpg') }, + }; + + uniforms['colorTexture'].value.wrapS = uniforms['colorTexture'].value.wrapT = THREE.RepeatWrapping; + + const shaderMaterial = new THREE.ShaderMaterial({ + uniforms: uniforms, + vertexShader: document.getElementById('vertexshader').textContent, + fragmentShader: document.getElementById('fragmentshader').textContent, + }); + + const radius = 50, + segments = 128, + rings = 64; + + const geometry = new THREE.SphereGeometry(radius, segments, rings); + + displacement = new Float32Array(geometry.attributes.position.count); + noise = new Float32Array(geometry.attributes.position.count); + + for (let i = 0; i < displacement.length; i++) { + noise[i] = Math.random() * 5; + } + + geometry.setAttribute('displacement', new THREE.BufferAttribute(displacement, 1)); + + sphere = new THREE.Mesh(geometry, shaderMaterial); + scene.add(sphere); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + + const container = document.getElementById('container'); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.01; + + sphere.rotation.y = sphere.rotation.z = 0.01 * time; + + uniforms['amplitude'].value = 2.5 * Math.sin(sphere.rotation.y * 0.125); + uniforms['color'].value.offsetHSL(0.0005, 0, 0); + + for (let i = 0; i < displacement.length; i++) { + displacement[i] = Math.sin(0.1 * i + time); + + noise[i] += 0.5 * (0.5 - Math.random()); + noise[i] = THREE.MathUtils.clamp(noise[i], -5, 5); + + displacement[i] += noise[i]; + } + + sphere.geometry.attributes.displacement.needsUpdate = true; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_custom_attributes_lines.ts b/examples-testing/examples/webgl_custom_attributes_lines.ts new file mode 100644 index 000000000..29b8a0645 --- /dev/null +++ b/examples-testing/examples/webgl_custom_attributes_lines.ts @@ -0,0 +1,123 @@ +import * as THREE from 'three'; + +import { FontLoader } from 'three/addons/loaders/FontLoader.js'; +import { TextGeometry } from 'three/addons/geometries/TextGeometry.js'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let renderer, scene, camera, stats; + +let line, uniforms; + +const loader = new FontLoader(); +loader.load('fonts/helvetiker_bold.typeface.json', function (font) { + init(font); + animate(); +}); + +function init(font) { + camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 10000); + camera.position.z = 400; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x050505); + + uniforms = { + amplitude: { value: 5.0 }, + opacity: { value: 0.3 }, + color: { value: new THREE.Color(0xffffff) }, + }; + + const shaderMaterial = new THREE.ShaderMaterial({ + uniforms: uniforms, + vertexShader: document.getElementById('vertexshader').textContent, + fragmentShader: document.getElementById('fragmentshader').textContent, + blending: THREE.AdditiveBlending, + depthTest: false, + transparent: true, + }); + + const geometry = new TextGeometry('three.js', { + font: font, + + size: 50, + height: 15, + curveSegments: 10, + + bevelThickness: 5, + bevelSize: 1.5, + bevelEnabled: true, + bevelSegments: 10, + }); + + geometry.center(); + + const count = geometry.attributes.position.count; + + const displacement = new THREE.Float32BufferAttribute(count * 3, 3); + geometry.setAttribute('displacement', displacement); + + const customColor = new THREE.Float32BufferAttribute(count * 3, 3); + geometry.setAttribute('customColor', customColor); + + const color = new THREE.Color(0xffffff); + + for (let i = 0, l = customColor.count; i < l; i++) { + color.setHSL(i / l, 0.5, 0.5); + color.toArray(customColor.array, i * customColor.itemSize); + } + + line = new THREE.Line(geometry, shaderMaterial); + line.rotation.x = 0.2; + scene.add(line); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + + const container = document.getElementById('container'); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.001; + + line.rotation.y = 0.25 * time; + + uniforms.amplitude.value = Math.sin(0.5 * time); + uniforms.color.value.offsetHSL(0.0005, 0, 0); + + const attributes = line.geometry.attributes; + const array = attributes.displacement.array; + + for (let i = 0, l = array.length; i < l; i += 3) { + array[i] += 0.3 * (0.5 - Math.random()); + array[i + 1] += 0.3 * (0.5 - Math.random()); + array[i + 2] += 0.3 * (0.5 - Math.random()); + } + + attributes.displacement.needsUpdate = true; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_custom_attributes_points.ts b/examples-testing/examples/webgl_custom_attributes_points.ts new file mode 100644 index 000000000..f1cfedc09 --- /dev/null +++ b/examples-testing/examples/webgl_custom_attributes_points.ts @@ -0,0 +1,119 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let renderer, scene, camera, stats; + +let sphere; + +const WIDTH = window.innerWidth; +const HEIGHT = window.innerHeight; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(40, WIDTH / HEIGHT, 1, 10000); + camera.position.z = 300; + + scene = new THREE.Scene(); + + const amount = 100000; + const radius = 200; + + const positions = new Float32Array(amount * 3); + const colors = new Float32Array(amount * 3); + const sizes = new Float32Array(amount); + + const vertex = new THREE.Vector3(); + const color = new THREE.Color(0xffffff); + + for (let i = 0; i < amount; i++) { + vertex.x = (Math.random() * 2 - 1) * radius; + vertex.y = (Math.random() * 2 - 1) * radius; + vertex.z = (Math.random() * 2 - 1) * radius; + vertex.toArray(positions, i * 3); + + if (vertex.x < 0) { + color.setHSL(0.5 + 0.1 * (i / amount), 0.7, 0.5); + } else { + color.setHSL(0.0 + 0.1 * (i / amount), 0.9, 0.5); + } + + color.toArray(colors, i * 3); + + sizes[i] = 10; + } + + const geometry = new THREE.BufferGeometry(); + geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); + geometry.setAttribute('customColor', new THREE.BufferAttribute(colors, 3)); + geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1)); + + // + + const material = new THREE.ShaderMaterial({ + uniforms: { + color: { value: new THREE.Color(0xffffff) }, + pointTexture: { value: new THREE.TextureLoader().load('textures/sprites/spark1.png') }, + }, + vertexShader: document.getElementById('vertexshader').textContent, + fragmentShader: document.getElementById('fragmentshader').textContent, + + blending: THREE.AdditiveBlending, + depthTest: false, + transparent: true, + }); + + // + + sphere = new THREE.Points(geometry, material); + scene.add(sphere); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(WIDTH, HEIGHT); + + const container = document.getElementById('container'); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.005; + + sphere.rotation.z = 0.01 * time; + + const geometry = sphere.geometry; + const attributes = geometry.attributes; + + for (let i = 0; i < attributes.size.array.length; i++) { + attributes.size.array[i] = 14 + 13 * Math.sin(0.1 * i + time); + } + + attributes.size.needsUpdate = true; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_custom_attributes_points2.ts b/examples-testing/examples/webgl_custom_attributes_points2.ts new file mode 100644 index 000000000..f744a1eb1 --- /dev/null +++ b/examples-testing/examples/webgl_custom_attributes_points2.ts @@ -0,0 +1,195 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'; + +let renderer, scene, camera, stats; +let sphere, length1; + +const WIDTH = window.innerWidth; +const HEIGHT = window.innerHeight; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(45, WIDTH / HEIGHT, 1, 10000); + camera.position.z = 300; + + scene = new THREE.Scene(); + + const radius = 100, + segments = 68, + rings = 38; + + let sphereGeometry = new THREE.SphereGeometry(radius, segments, rings); + let boxGeometry = new THREE.BoxGeometry(0.8 * radius, 0.8 * radius, 0.8 * radius, 10, 10, 10); + + // if normal and uv attributes are not removed, mergeVertices() can't consolidate identical vertices with different normal/uv data + + sphereGeometry.deleteAttribute('normal'); + sphereGeometry.deleteAttribute('uv'); + + boxGeometry.deleteAttribute('normal'); + boxGeometry.deleteAttribute('uv'); + + sphereGeometry = BufferGeometryUtils.mergeVertices(sphereGeometry); + boxGeometry = BufferGeometryUtils.mergeVertices(boxGeometry); + + const combinedGeometry = BufferGeometryUtils.mergeGeometries([sphereGeometry, boxGeometry]); + const positionAttribute = combinedGeometry.getAttribute('position'); + + const colors = []; + const sizes = []; + + const color = new THREE.Color(); + const vertex = new THREE.Vector3(); + + length1 = sphereGeometry.getAttribute('position').count; + + for (let i = 0, l = positionAttribute.count; i < l; i++) { + vertex.fromBufferAttribute(positionAttribute, i); + + if (i < length1) { + color.setHSL(0.01 + 0.1 * (i / length1), 0.99, (vertex.y + radius) / (4 * radius)); + } else { + color.setHSL(0.6, 0.75, 0.25 + vertex.y / (2 * radius)); + } + + color.toArray(colors, i * 3); + + sizes[i] = i < length1 ? 10 : 40; + } + + const geometry = new THREE.BufferGeometry(); + geometry.setAttribute('position', positionAttribute); + geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1)); + geometry.setAttribute('ca', new THREE.Float32BufferAttribute(colors, 3)); + + // + + const texture = new THREE.TextureLoader().load('textures/sprites/disc.png'); + texture.wrapS = THREE.RepeatWrapping; + texture.wrapT = THREE.RepeatWrapping; + + const material = new THREE.ShaderMaterial({ + uniforms: { + color: { value: new THREE.Color(0xffffff) }, + pointTexture: { value: texture }, + }, + vertexShader: document.getElementById('vertexshader').textContent, + fragmentShader: document.getElementById('fragmentshader').textContent, + transparent: true, + }); + + // + + sphere = new THREE.Points(geometry, material); + scene.add(sphere); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(WIDTH, HEIGHT); + + const container = document.getElementById('container'); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function sortPoints() { + const vector = new THREE.Vector3(); + + // Model View Projection matrix + + const matrix = new THREE.Matrix4(); + matrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); + matrix.multiply(sphere.matrixWorld); + + // + + const geometry = sphere.geometry; + + let index = geometry.getIndex(); + const positions = geometry.getAttribute('position').array; + const length = positions.length / 3; + + if (index === null) { + const array = new Uint16Array(length); + + for (let i = 0; i < length; i++) { + array[i] = i; + } + + index = new THREE.BufferAttribute(array, 1); + + geometry.setIndex(index); + } + + const sortArray = []; + + for (let i = 0; i < length; i++) { + vector.fromArray(positions, i * 3); + vector.applyMatrix4(matrix); + + sortArray.push([vector.z, i]); + } + + function numericalSort(a, b) { + return b[0] - a[0]; + } + + sortArray.sort(numericalSort); + + const indices = index.array; + + for (let i = 0; i < length; i++) { + indices[i] = sortArray[i][1]; + } + + geometry.index.needsUpdate = true; +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.005; + + sphere.rotation.y = 0.02 * time; + sphere.rotation.z = 0.02 * time; + + const geometry = sphere.geometry; + const attributes = geometry.attributes; + + for (let i = 0; i < attributes.size.array.length; i++) { + if (i < length1) { + attributes.size.array[i] = 16 + 12 * Math.sin(0.1 * i + time); + } + } + + attributes.size.needsUpdate = true; + + sortPoints(); + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_custom_attributes_points3.ts b/examples-testing/examples/webgl_custom_attributes_points3.ts new file mode 100644 index 000000000..1ef2f1f82 --- /dev/null +++ b/examples-testing/examples/webgl_custom_attributes_points3.ts @@ -0,0 +1,202 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'; + +let renderer, scene, camera, stats; + +let object; + +let vertices1; + +const WIDTH = window.innerWidth; +const HEIGHT = window.innerHeight; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(40, WIDTH / HEIGHT, 1, 1000); + camera.position.z = 500; + + scene = new THREE.Scene(); + + let radius = 100; + const inner = 0.6 * radius; + const vertex = new THREE.Vector3(); + const vertices = []; + + for (let i = 0; i < 100000; i++) { + vertex.x = Math.random() * 2 - 1; + vertex.y = Math.random() * 2 - 1; + vertex.z = Math.random() * 2 - 1; + vertex.multiplyScalar(radius); + + if ( + vertex.x > inner || + vertex.x < -inner || + vertex.y > inner || + vertex.y < -inner || + vertex.z > inner || + vertex.z < -inner + ) + vertices.push(vertex.x, vertex.y, vertex.z); + } + + vertices1 = vertices.length / 3; + + radius = 200; + + let boxGeometry1 = new THREE.BoxGeometry(radius, 0.1 * radius, 0.1 * radius, 50, 5, 5); + + // if normal and uv attributes are not removed, mergeVertices() can't consolidate indentical vertices with different normal/uv data + + boxGeometry1.deleteAttribute('normal'); + boxGeometry1.deleteAttribute('uv'); + + boxGeometry1 = BufferGeometryUtils.mergeVertices(boxGeometry1); + + const matrix = new THREE.Matrix4(); + const position = new THREE.Vector3(); + const rotation = new THREE.Euler(); + const quaternion = new THREE.Quaternion(); + const scale = new THREE.Vector3(1, 1, 1); + + function addGeo(geo, x, y, z, ry) { + position.set(x, y, z); + rotation.set(0, ry, 0); + + matrix.compose(position, quaternion.setFromEuler(rotation), scale); + + const positionAttribute = geo.getAttribute('position'); + + for (let i = 0, l = positionAttribute.count; i < l; i++) { + vertex.fromBufferAttribute(positionAttribute, i); + vertex.applyMatrix4(matrix); + vertices.push(vertex.x, vertex.y, vertex.z); + } + } + + // side 1 + + addGeo(boxGeometry1, 0, 110, 110, 0); + addGeo(boxGeometry1, 0, 110, -110, 0); + addGeo(boxGeometry1, 0, -110, 110, 0); + addGeo(boxGeometry1, 0, -110, -110, 0); + + // side 2 + + addGeo(boxGeometry1, 110, 110, 0, Math.PI / 2); + addGeo(boxGeometry1, 110, -110, 0, Math.PI / 2); + addGeo(boxGeometry1, -110, 110, 0, Math.PI / 2); + addGeo(boxGeometry1, -110, -110, 0, Math.PI / 2); + + // corner edges + + let boxGeometry2 = new THREE.BoxGeometry(0.1 * radius, radius * 1.2, 0.1 * radius, 5, 60, 5); + + boxGeometry2.deleteAttribute('normal'); + boxGeometry2.deleteAttribute('uv'); + + boxGeometry2 = BufferGeometryUtils.mergeVertices(boxGeometry2); + + addGeo(boxGeometry2, 110, 0, 110, 0); + addGeo(boxGeometry2, 110, 0, -110, 0); + addGeo(boxGeometry2, -110, 0, 110, 0); + addGeo(boxGeometry2, -110, 0, -110, 0); + + const positionAttribute = new THREE.Float32BufferAttribute(vertices, 3); + + const colors = []; + const sizes = []; + + const color = new THREE.Color(); + + for (let i = 0; i < positionAttribute.count; i++) { + if (i < vertices1) { + color.setHSL(0.5 + 0.2 * (i / vertices1), 1, 0.5); + } else { + color.setHSL(0.1, 1, 0.5); + } + + color.toArray(colors, i * 3); + + sizes[i] = i < vertices1 ? 10 : 40; + } + + const geometry = new THREE.BufferGeometry(); + geometry.setAttribute('position', positionAttribute); + geometry.setAttribute('ca', new THREE.Float32BufferAttribute(colors, 3)); + geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1)); + + // + + const texture = new THREE.TextureLoader().load('textures/sprites/ball.png'); + texture.wrapS = THREE.RepeatWrapping; + texture.wrapT = THREE.RepeatWrapping; + + const material = new THREE.ShaderMaterial({ + uniforms: { + amplitude: { value: 1.0 }, + color: { value: new THREE.Color(0xffffff) }, + pointTexture: { value: texture }, + }, + vertexShader: document.getElementById('vertexshader').textContent, + fragmentShader: document.getElementById('fragmentshader').textContent, + }); + + // + + object = new THREE.Points(geometry, material); + scene.add(object); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(WIDTH, HEIGHT); + + const container = document.getElementById('container'); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const time = Date.now() * 0.01; + + object.rotation.y = object.rotation.z = 0.02 * time; + + const geometry = object.geometry; + const attributes = geometry.attributes; + + for (let i = 0; i < attributes.size.array.length; i++) { + if (i < vertices1) { + attributes.size.array[i] = Math.max(0, 26 + 32 * Math.sin(0.1 * i + 0.6 * time)); + } + } + + attributes.size.needsUpdate = true; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_decals.ts b/examples-testing/examples/webgl_decals.ts new file mode 100644 index 000000000..1b3b791c2 --- /dev/null +++ b/examples-testing/examples/webgl_decals.ts @@ -0,0 +1,238 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; +import { DecalGeometry } from 'three/addons/geometries/DecalGeometry.js'; + +const container = document.getElementById('container'); + +let renderer, scene, camera, stats; +let mesh; +let raycaster; +let line; + +const intersection = { + intersects: false, + point: new THREE.Vector3(), + normal: new THREE.Vector3(), +}; +const mouse = new THREE.Vector2(); +const intersects = []; + +const textureLoader = new THREE.TextureLoader(); +const decalDiffuse = textureLoader.load('textures/decal/decal-diffuse.png'); +decalDiffuse.colorSpace = THREE.SRGBColorSpace; +const decalNormal = textureLoader.load('textures/decal/decal-normal.jpg'); + +const decalMaterial = new THREE.MeshPhongMaterial({ + specular: 0x444444, + map: decalDiffuse, + normalMap: decalNormal, + normalScale: new THREE.Vector2(1, 1), + shininess: 30, + transparent: true, + depthTest: true, + depthWrite: false, + polygonOffset: true, + polygonOffsetFactor: -4, + wireframe: false, +}); + +const decals = []; +let mouseHelper; +const position = new THREE.Vector3(); +const orientation = new THREE.Euler(); +const size = new THREE.Vector3(10, 10, 10); + +const params = { + minScale: 10, + maxScale: 20, + rotate: true, + clear: function () { + removeDecals(); + }, +}; + +init(); +animate(); + +function init() { + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.z = 120; + + const controls = new OrbitControls(camera, renderer.domElement); + controls.minDistance = 50; + controls.maxDistance = 200; + + scene.add(new THREE.AmbientLight(0x666666)); + + const dirLight1 = new THREE.DirectionalLight(0xffddcc, 3); + dirLight1.position.set(1, 0.75, 0.5); + scene.add(dirLight1); + + const dirLight2 = new THREE.DirectionalLight(0xccccff, 3); + dirLight2.position.set(-1, 0.75, -0.5); + scene.add(dirLight2); + + const geometry = new THREE.BufferGeometry(); + geometry.setFromPoints([new THREE.Vector3(), new THREE.Vector3()]); + + line = new THREE.Line(geometry, new THREE.LineBasicMaterial()); + scene.add(line); + + loadLeePerrySmith(); + + raycaster = new THREE.Raycaster(); + + mouseHelper = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 10), new THREE.MeshNormalMaterial()); + mouseHelper.visible = false; + scene.add(mouseHelper); + + window.addEventListener('resize', onWindowResize); + + let moved = false; + + controls.addEventListener('change', function () { + moved = true; + }); + + window.addEventListener('pointerdown', function () { + moved = false; + }); + + window.addEventListener('pointerup', function (event) { + if (moved === false) { + checkIntersection(event.clientX, event.clientY); + + if (intersection.intersects) shoot(); + } + }); + + window.addEventListener('pointermove', onPointerMove); + + function onPointerMove(event) { + if (event.isPrimary) { + checkIntersection(event.clientX, event.clientY); + } + } + + function checkIntersection(x, y) { + if (mesh === undefined) return; + + mouse.x = (x / window.innerWidth) * 2 - 1; + mouse.y = -(y / window.innerHeight) * 2 + 1; + + raycaster.setFromCamera(mouse, camera); + raycaster.intersectObject(mesh, false, intersects); + + if (intersects.length > 0) { + const p = intersects[0].point; + mouseHelper.position.copy(p); + intersection.point.copy(p); + + const n = intersects[0].face.normal.clone(); + n.transformDirection(mesh.matrixWorld); + n.multiplyScalar(10); + n.add(intersects[0].point); + + intersection.normal.copy(intersects[0].face.normal); + mouseHelper.lookAt(n); + + const positions = line.geometry.attributes.position; + positions.setXYZ(0, p.x, p.y, p.z); + positions.setXYZ(1, n.x, n.y, n.z); + positions.needsUpdate = true; + + intersection.intersects = true; + + intersects.length = 0; + } else { + intersection.intersects = false; + } + } + + const gui = new GUI(); + + gui.add(params, 'minScale', 1, 30); + gui.add(params, 'maxScale', 1, 30); + gui.add(params, 'rotate'); + gui.add(params, 'clear'); + gui.open(); +} + +function loadLeePerrySmith() { + const map = textureLoader.load('models/gltf/LeePerrySmith/Map-COL.jpg'); + map.colorSpace = THREE.SRGBColorSpace; + const specularMap = textureLoader.load('models/gltf/LeePerrySmith/Map-SPEC.jpg'); + const normalMap = textureLoader.load('models/gltf/LeePerrySmith/Infinite-Level_02_Tangent_SmoothUV.jpg'); + + const loader = new GLTFLoader(); + + loader.load('models/gltf/LeePerrySmith/LeePerrySmith.glb', function (gltf) { + mesh = gltf.scene.children[0]; + mesh.material = new THREE.MeshPhongMaterial({ + specular: 0x111111, + map: map, + specularMap: specularMap, + normalMap: normalMap, + shininess: 25, + }); + + scene.add(mesh); + mesh.scale.set(10, 10, 10); + }); +} + +function shoot() { + position.copy(intersection.point); + orientation.copy(mouseHelper.rotation); + + if (params.rotate) orientation.z = Math.random() * 2 * Math.PI; + + const scale = params.minScale + Math.random() * (params.maxScale - params.minScale); + size.set(scale, scale, scale); + + const material = decalMaterial.clone(); + material.color.setHex(Math.random() * 0xffffff); + + const m = new THREE.Mesh(new DecalGeometry(mesh, position, orientation, size), material); + + decals.push(m); + scene.add(m); +} + +function removeDecals() { + decals.forEach(function (d) { + scene.remove(d); + }); + + decals.length = 0; +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + renderer.render(scene, camera); + + stats.update(); +} diff --git a/examples-testing/examples/webgl_effects_anaglyph.ts b/examples-testing/examples/webgl_effects_anaglyph.ts new file mode 100644 index 000000000..51329638c --- /dev/null +++ b/examples-testing/examples/webgl_effects_anaglyph.ts @@ -0,0 +1,116 @@ +import * as THREE from 'three'; + +import { AnaglyphEffect } from 'three/addons/effects/AnaglyphEffect.js'; + +let container, camera, scene, renderer, effect; + +const spheres = []; + +let mouseX = 0; +let mouseY = 0; + +let windowHalfX = window.innerWidth / 2; +let windowHalfY = window.innerHeight / 2; + +document.addEventListener('mousemove', onDocumentMouseMove); + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 100); + camera.position.z = 3; + + const path = 'textures/cube/pisa/'; + const format = '.png'; + const urls = [ + path + 'px' + format, + path + 'nx' + format, + path + 'py' + format, + path + 'ny' + format, + path + 'pz' + format, + path + 'nz' + format, + ]; + + const textureCube = new THREE.CubeTextureLoader().load(urls); + + scene = new THREE.Scene(); + scene.background = textureCube; + + const geometry = new THREE.SphereGeometry(0.1, 32, 16); + const material = new THREE.MeshBasicMaterial({ color: 0xffffff, envMap: textureCube }); + + for (let i = 0; i < 500; i++) { + const mesh = new THREE.Mesh(geometry, material); + + mesh.position.x = Math.random() * 10 - 5; + mesh.position.y = Math.random() * 10 - 5; + mesh.position.z = Math.random() * 10 - 5; + + mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 3 + 1; + + scene.add(mesh); + + spheres.push(mesh); + } + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + container.appendChild(renderer.domElement); + + const width = window.innerWidth || 2; + const height = window.innerHeight || 2; + + effect = new AnaglyphEffect(renderer); + effect.setSize(width, height); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + effect.setSize(window.innerWidth, window.innerHeight); +} + +function onDocumentMouseMove(event) { + mouseX = (event.clientX - windowHalfX) / 100; + mouseY = (event.clientY - windowHalfY) / 100; +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); +} + +function render() { + const timer = 0.0001 * Date.now(); + + camera.position.x += (mouseX - camera.position.x) * 0.05; + camera.position.y += (-mouseY - camera.position.y) * 0.05; + + camera.lookAt(scene.position); + + for (let i = 0, il = spheres.length; i < il; i++) { + const sphere = spheres[i]; + + sphere.position.x = 5 * Math.cos(timer + i); + sphere.position.y = 5 * Math.sin(timer + i * 1.1); + } + + effect.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_effects_ascii.ts b/examples-testing/examples/webgl_effects_ascii.ts new file mode 100644 index 000000000..60b7de88e --- /dev/null +++ b/examples-testing/examples/webgl_effects_ascii.ts @@ -0,0 +1,87 @@ +import * as THREE from 'three'; + +import { AsciiEffect } from 'three/addons/effects/AsciiEffect.js'; +import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; + +let camera, controls, scene, renderer, effect; + +let sphere, plane; + +const start = Date.now(); + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.y = 150; + camera.position.z = 500; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0, 0, 0); + + const pointLight1 = new THREE.PointLight(0xffffff, 3, 0, 0); + pointLight1.position.set(500, 500, 500); + scene.add(pointLight1); + + const pointLight2 = new THREE.PointLight(0xffffff, 1, 0, 0); + pointLight2.position.set(-500, -500, -500); + scene.add(pointLight2); + + sphere = new THREE.Mesh(new THREE.SphereGeometry(200, 20, 10), new THREE.MeshPhongMaterial({ flatShading: true })); + scene.add(sphere); + + // Plane + + plane = new THREE.Mesh(new THREE.PlaneGeometry(400, 400), new THREE.MeshBasicMaterial({ color: 0xe0e0e0 })); + plane.position.y = -200; + plane.rotation.x = -Math.PI / 2; + scene.add(plane); + + renderer = new THREE.WebGLRenderer(); + renderer.setSize(window.innerWidth, window.innerHeight); + + effect = new AsciiEffect(renderer, ' .:-+*=%@#', { invert: true }); + effect.setSize(window.innerWidth, window.innerHeight); + effect.domElement.style.color = 'white'; + effect.domElement.style.backgroundColor = 'black'; + + // Special case: append effect.domElement, instead of renderer.domElement. + // AsciiEffect creates a custom domElement (a div container) where the ASCII elements are placed. + + document.body.appendChild(effect.domElement); + + controls = new TrackballControls(camera, effect.domElement); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + effect.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); +} + +function render() { + const timer = Date.now() - start; + + sphere.position.y = Math.abs(Math.sin(timer * 0.002)) * 150; + sphere.rotation.x = timer * 0.0003; + sphere.rotation.z = timer * 0.0002; + + controls.update(); + + effect.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_effects_parallaxbarrier.ts b/examples-testing/examples/webgl_effects_parallaxbarrier.ts new file mode 100644 index 000000000..45e74917a --- /dev/null +++ b/examples-testing/examples/webgl_effects_parallaxbarrier.ts @@ -0,0 +1,116 @@ +import * as THREE from 'three'; + +import { ParallaxBarrierEffect } from 'three/addons/effects/ParallaxBarrierEffect.js'; + +let container, camera, scene, renderer, effect; + +const spheres = []; + +let mouseX = 0; +let mouseY = 0; + +let windowHalfX = window.innerWidth / 2; +let windowHalfY = window.innerHeight / 2; + +document.addEventListener('mousemove', onDocumentMouseMove); + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 100); + camera.position.z = 3; + + const path = 'textures/cube/pisa/'; + const format = '.png'; + const urls = [ + path + 'px' + format, + path + 'nx' + format, + path + 'py' + format, + path + 'ny' + format, + path + 'pz' + format, + path + 'nz' + format, + ]; + + const textureCube = new THREE.CubeTextureLoader().load(urls); + + scene = new THREE.Scene(); + scene.background = textureCube; + + const geometry = new THREE.SphereGeometry(0.1, 32, 16); + const material = new THREE.MeshBasicMaterial({ color: 0xffffff, envMap: textureCube }); + + for (let i = 0; i < 500; i++) { + const mesh = new THREE.Mesh(geometry, material); + + mesh.position.x = Math.random() * 10 - 5; + mesh.position.y = Math.random() * 10 - 5; + mesh.position.z = Math.random() * 10 - 5; + + mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 3 + 1; + + scene.add(mesh); + + spheres.push(mesh); + } + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + container.appendChild(renderer.domElement); + + const width = window.innerWidth || 2; + const height = window.innerHeight || 2; + + effect = new ParallaxBarrierEffect(renderer); + effect.setSize(width, height); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + effect.setSize(window.innerWidth, window.innerHeight); +} + +function onDocumentMouseMove(event) { + mouseX = (event.clientX - windowHalfX) / 100; + mouseY = (event.clientY - windowHalfY) / 100; +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); +} + +function render() { + const timer = 0.0001 * Date.now(); + + camera.position.x += (mouseX - camera.position.x) * 0.05; + camera.position.y += (-mouseY - camera.position.y) * 0.05; + + camera.lookAt(scene.position); + + for (let i = 0, il = spheres.length; i < il; i++) { + const sphere = spheres[i]; + + sphere.position.x = 5 * Math.cos(timer + i); + sphere.position.y = 5 * Math.sin(timer + i * 1.1); + } + + effect.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_effects_peppersghost.ts b/examples-testing/examples/webgl_effects_peppersghost.ts new file mode 100644 index 000000000..90cfe01e3 --- /dev/null +++ b/examples-testing/examples/webgl_effects_peppersghost.ts @@ -0,0 +1,87 @@ +import * as THREE from 'three'; + +import { PeppersGhostEffect } from 'three/addons/effects/PeppersGhostEffect.js'; + +let container; + +let camera, scene, renderer, effect; +let group; + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100000); + + scene = new THREE.Scene(); + + group = new THREE.Group(); + scene.add(group); + + // Cube + + const geometry = new THREE.BoxGeometry().toNonIndexed(); // ensure unique vertices for each triangle + + const position = geometry.attributes.position; + const colors = []; + const color = new THREE.Color(); + + // generate for each side of the cube a different color + + for (let i = 0; i < position.count; i += 6) { + color.setHex(Math.random() * 0xffffff); + + // first face + + colors.push(color.r, color.g, color.b); + colors.push(color.r, color.g, color.b); + colors.push(color.r, color.g, color.b); + + // second face + + colors.push(color.r, color.g, color.b); + colors.push(color.r, color.g, color.b); + colors.push(color.r, color.g, color.b); + } + + geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); + + const material = new THREE.MeshBasicMaterial({ vertexColors: true }); + + for (let i = 0; i < 10; i++) { + const cube = new THREE.Mesh(geometry, material); + cube.position.x = Math.random() * 2 - 1; + cube.position.y = Math.random() * 2 - 1; + cube.position.z = Math.random() * 2 - 1; + cube.scale.multiplyScalar(Math.random() + 0.5); + group.add(cube); + } + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + container.appendChild(renderer.domElement); + + effect = new PeppersGhostEffect(renderer); + effect.setSize(window.innerWidth, window.innerHeight); + effect.cameraDistance = 5; + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + effect.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + group.rotation.y += 0.01; + + effect.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_effects_stereo.ts b/examples-testing/examples/webgl_effects_stereo.ts new file mode 100644 index 000000000..4db7184fb --- /dev/null +++ b/examples-testing/examples/webgl_effects_stereo.ts @@ -0,0 +1,104 @@ +import * as THREE from 'three'; + +import { StereoEffect } from 'three/addons/effects/StereoEffect.js'; + +let container, camera, scene, renderer, effect; + +const spheres = []; + +let mouseX = 0, + mouseY = 0; + +let windowHalfX = window.innerWidth / 2; +let windowHalfY = window.innerHeight / 2; + +document.addEventListener('mousemove', onDocumentMouseMove); + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100000); + camera.position.z = 3200; + + scene = new THREE.Scene(); + scene.background = new THREE.CubeTextureLoader() + .setPath('textures/cube/Park3Med/') + .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']); + + const geometry = new THREE.SphereGeometry(100, 32, 16); + + const textureCube = new THREE.CubeTextureLoader() + .setPath('textures/cube/Park3Med/') + .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']); + textureCube.mapping = THREE.CubeRefractionMapping; + + const material = new THREE.MeshBasicMaterial({ color: 0xffffff, envMap: textureCube, refractionRatio: 0.95 }); + + for (let i = 0; i < 500; i++) { + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = Math.random() * 10000 - 5000; + mesh.position.y = Math.random() * 10000 - 5000; + mesh.position.z = Math.random() * 10000 - 5000; + mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 3 + 1; + scene.add(mesh); + + spheres.push(mesh); + } + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + container.appendChild(renderer.domElement); + + effect = new StereoEffect(renderer); + effect.setSize(window.innerWidth, window.innerHeight); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + effect.setSize(window.innerWidth, window.innerHeight); +} + +function onDocumentMouseMove(event) { + mouseX = (event.clientX - windowHalfX) * 10; + mouseY = (event.clientY - windowHalfY) * 10; +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); +} + +function render() { + const timer = 0.0001 * Date.now(); + + camera.position.x += (mouseX - camera.position.x) * 0.05; + camera.position.y += (-mouseY - camera.position.y) * 0.05; + camera.lookAt(scene.position); + + for (let i = 0, il = spheres.length; i < il; i++) { + const sphere = spheres[i]; + + sphere.position.x = 5000 * Math.cos(timer + i); + sphere.position.y = 5000 * Math.sin(timer + i * 1.1); + } + + effect.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_framebuffer_texture.ts b/examples-testing/examples/webgl_framebuffer_texture.ts new file mode 100644 index 000000000..379737fe8 --- /dev/null +++ b/examples-testing/examples/webgl_framebuffer_texture.ts @@ -0,0 +1,153 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import * as GeometryUtils from 'three/addons/utils/GeometryUtils.js'; + +let camera, scene, renderer; +let line, sprite, texture; + +let cameraOrtho, sceneOrtho; + +let offset = 0; + +const dpr = window.devicePixelRatio; + +const textureSize = 128 * dpr; +const vector = new THREE.Vector2(); +const color = new THREE.Color(); + +init(); +animate(); + +function init() { + // + + const width = window.innerWidth; + const height = window.innerHeight; + + camera = new THREE.PerspectiveCamera(70, width / height, 1, 1000); + camera.position.z = 20; + + cameraOrtho = new THREE.OrthographicCamera(-width / 2, width / 2, height / 2, -height / 2, 1, 10); + cameraOrtho.position.z = 10; + + scene = new THREE.Scene(); + sceneOrtho = new THREE.Scene(); + + // + + const points = GeometryUtils.gosper(8); + + const geometry = new THREE.BufferGeometry(); + const positionAttribute = new THREE.Float32BufferAttribute(points, 3); + geometry.setAttribute('position', positionAttribute); + geometry.center(); + + const colorAttribute = new THREE.BufferAttribute(new Float32Array(positionAttribute.array.length), 3); + colorAttribute.setUsage(THREE.DynamicDrawUsage); + geometry.setAttribute('color', colorAttribute); + + const material = new THREE.LineBasicMaterial({ vertexColors: true }); + + line = new THREE.Line(geometry, material); + line.scale.setScalar(0.05); + scene.add(line); + + // + + texture = new THREE.FramebufferTexture(textureSize, textureSize); + + // + + const spriteMaterial = new THREE.SpriteMaterial({ map: texture }); + sprite = new THREE.Sprite(spriteMaterial); + sprite.scale.set(textureSize, textureSize, 1); + sceneOrtho.add(sprite); + + updateSpritePosition(); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.autoClear = false; + document.body.appendChild(renderer.domElement); + + // + + const selection = document.getElementById('selection'); + const controls = new OrbitControls(camera, selection); + controls.enablePan = false; + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + const width = window.innerWidth; + const height = window.innerHeight; + + camera.aspect = width / height; + camera.updateProjectionMatrix(); + + cameraOrtho.left = -width / 2; + cameraOrtho.right = width / 2; + cameraOrtho.top = height / 2; + cameraOrtho.bottom = -height / 2; + cameraOrtho.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + updateSpritePosition(); +} + +function updateSpritePosition() { + const halfWidth = window.innerWidth / 2; + const halfHeight = window.innerHeight / 2; + + const halfImageWidth = textureSize / 2; + const halfImageHeight = textureSize / 2; + + sprite.position.set(-halfWidth + halfImageWidth, halfHeight - halfImageHeight, 1); +} + +function animate() { + requestAnimationFrame(animate); + + const colorAttribute = line.geometry.getAttribute('color'); + updateColors(colorAttribute); + + // scene rendering + + renderer.clear(); + renderer.render(scene, camera); + + // calculate start position for copying data + + vector.x = (window.innerWidth * dpr) / 2 - textureSize / 2; + vector.y = (window.innerHeight * dpr) / 2 - textureSize / 2; + + renderer.copyFramebufferToTexture(vector, texture); + + renderer.clearDepth(); + renderer.render(sceneOrtho, cameraOrtho); +} + +function updateColors(colorAttribute) { + const l = colorAttribute.count; + + for (let i = 0; i < l; i++) { + const h = ((offset + i) % l) / l; + + color.setHSL(h, 1, 0.5); + colorAttribute.setX(i, color.r); + colorAttribute.setY(i, color.g); + colorAttribute.setZ(i, color.b); + } + + colorAttribute.needsUpdate = true; + + offset -= 25; +} diff --git a/examples-testing/examples/webgl_furnace_test.ts b/examples-testing/examples/webgl_furnace_test.ts new file mode 100644 index 000000000..a81954176 --- /dev/null +++ b/examples-testing/examples/webgl_furnace_test.ts @@ -0,0 +1,96 @@ +import * as THREE from 'three'; + +let scene, camera, renderer, radianceMap; + +const COLOR = 0xcccccc; + +function init() { + const width = window.innerWidth; + const height = window.innerHeight; + const aspect = width / height; + + // renderer + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize(width, height); + renderer.setPixelRatio(window.devicePixelRatio); + document.body.appendChild(renderer.domElement); + + window.addEventListener('resize', onWindowResize); + + document.body.addEventListener('mouseover', function () { + scene.traverse(function (child) { + if (child.isMesh) child.material.color.setHex(0xffffff); + }); + + render(); + }); + + document.body.addEventListener('mouseout', function () { + scene.traverse(function (child) { + if (child.isMesh) child.material.color.setHex(0xccccff); // tinted for visibility + }); + + render(); + }); + + // scene + + scene = new THREE.Scene(); + + // camera + camera = new THREE.PerspectiveCamera(40, aspect, 1, 30); + camera.position.set(0, 0, 18); +} + +function createObjects() { + const geometry = new THREE.SphereGeometry(0.4, 32, 16); + + for (let x = 0; x <= 10; x++) { + for (let y = 0; y <= 10; y++) { + const material = new THREE.MeshPhysicalMaterial({ + roughness: x / 10, + metalness: y / 10, + color: 0xffffff, + envMap: radianceMap, + envMapIntensity: 1, + transmission: 0, + ior: 1.5, + }); + + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = x - 5; + mesh.position.y = 5 - y; + scene.add(mesh); + } + } +} + +function createEnvironment() { + const envScene = new THREE.Scene(); + envScene.background = new THREE.Color(COLOR); + + const pmremGenerator = new THREE.PMREMGenerator(renderer); + radianceMap = pmremGenerator.fromScene(envScene).texture; + pmremGenerator.dispose(); + + scene.background = envScene.background; +} + +function onWindowResize() { + const width = window.innerWidth; + const height = window.innerHeight; + + camera.aspect = width / height; + camera.updateProjectionMatrix(); + + renderer.setSize(width, height); + + render(); +} + +function render() { + renderer.render(scene, camera); +} + +Promise.resolve().then(init).then(createEnvironment).then(createObjects).then(render); diff --git a/examples-testing/examples/webgl_geometries.ts b/examples-testing/examples/webgl_geometries.ts new file mode 100644 index 000000000..154164e13 --- /dev/null +++ b/examples-testing/examples/webgl_geometries.ts @@ -0,0 +1,139 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +let camera, scene, renderer, stats; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000); + camera.position.y = 400; + + scene = new THREE.Scene(); + + let object; + + const ambientLight = new THREE.AmbientLight(0xcccccc, 1.5); + scene.add(ambientLight); + + const pointLight = new THREE.PointLight(0xffffff, 2.5, 0, 0); + camera.add(pointLight); + scene.add(camera); + + const map = new THREE.TextureLoader().load('textures/uv_grid_opengl.jpg'); + map.wrapS = map.wrapT = THREE.RepeatWrapping; + map.anisotropy = 16; + map.colorSpace = THREE.SRGBColorSpace; + + const material = new THREE.MeshPhongMaterial({ map: map, side: THREE.DoubleSide }); + + // + + object = new THREE.Mesh(new THREE.SphereGeometry(75, 20, 10), material); + object.position.set(-300, 0, 200); + scene.add(object); + + object = new THREE.Mesh(new THREE.IcosahedronGeometry(75, 1), material); + object.position.set(-100, 0, 200); + scene.add(object); + + object = new THREE.Mesh(new THREE.OctahedronGeometry(75, 2), material); + object.position.set(100, 0, 200); + scene.add(object); + + object = new THREE.Mesh(new THREE.TetrahedronGeometry(75, 0), material); + object.position.set(300, 0, 200); + scene.add(object); + + // + + object = new THREE.Mesh(new THREE.PlaneGeometry(100, 100, 4, 4), material); + object.position.set(-300, 0, 0); + scene.add(object); + + object = new THREE.Mesh(new THREE.BoxGeometry(100, 100, 100, 4, 4, 4), material); + object.position.set(-100, 0, 0); + scene.add(object); + + object = new THREE.Mesh(new THREE.CircleGeometry(50, 20, 0, Math.PI * 2), material); + object.position.set(100, 0, 0); + scene.add(object); + + object = new THREE.Mesh(new THREE.RingGeometry(10, 50, 20, 5, 0, Math.PI * 2), material); + object.position.set(300, 0, 0); + scene.add(object); + + // + + object = new THREE.Mesh(new THREE.CylinderGeometry(25, 75, 100, 40, 5), material); + object.position.set(-300, 0, -200); + scene.add(object); + + const points = []; + + for (let i = 0; i < 50; i++) { + points.push(new THREE.Vector2(Math.sin(i * 0.2) * Math.sin(i * 0.1) * 15 + 50, (i - 5) * 2)); + } + + object = new THREE.Mesh(new THREE.LatheGeometry(points, 20), material); + object.position.set(-100, 0, -200); + scene.add(object); + + object = new THREE.Mesh(new THREE.TorusGeometry(50, 20, 20, 20), material); + object.position.set(100, 0, -200); + scene.add(object); + + object = new THREE.Mesh(new THREE.TorusKnotGeometry(50, 10, 50, 20), material); + object.position.set(300, 0, -200); + scene.add(object); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + stats = new Stats(); + document.body.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const timer = Date.now() * 0.0001; + + camera.position.x = Math.cos(timer) * 800; + camera.position.z = Math.sin(timer) * 800; + + camera.lookAt(scene.position); + + scene.traverse(function (object) { + if (object.isMesh === true) { + object.rotation.x = timer * 5; + object.rotation.y = timer * 2.5; + } + }); + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_geometries_parametric.ts b/examples-testing/examples/webgl_geometries_parametric.ts new file mode 100644 index 000000000..8aa86c345 --- /dev/null +++ b/examples-testing/examples/webgl_geometries_parametric.ts @@ -0,0 +1,126 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import * as Curves from 'three/addons/curves/CurveExtras.js'; +import { ParametricGeometry } from 'three/addons/geometries/ParametricGeometry.js'; +import { ParametricGeometries } from 'three/addons/geometries/ParametricGeometries.js'; + +let camera, scene, renderer, stats; + +init(); +animate(); + +function init() { + const container = document.getElementById('container'); + + camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000); + camera.position.y = 400; + + scene = new THREE.Scene(); + + // + + const ambientLight = new THREE.AmbientLight(0xcccccc, 1.5); + scene.add(ambientLight); + + const pointLight = new THREE.PointLight(0xffffff, 2.5, 0, 0); + camera.add(pointLight); + scene.add(camera); + + // + + const map = new THREE.TextureLoader().load('textures/uv_grid_opengl.jpg'); + map.wrapS = map.wrapT = THREE.RepeatWrapping; + map.anisotropy = 16; + map.colorSpace = THREE.SRGBColorSpace; + + const material = new THREE.MeshPhongMaterial({ map: map, side: THREE.DoubleSide }); + + // + + let geometry, object; + + geometry = new ParametricGeometry(ParametricGeometries.plane(100, 100), 10, 10); + geometry.center(); + object = new THREE.Mesh(geometry, material); + object.position.set(-200, 0, 200); + scene.add(object); + + geometry = new ParametricGeometry(ParametricGeometries.klein, 20, 20); + object = new THREE.Mesh(geometry, material); + object.position.set(0, 0, 200); + object.scale.multiplyScalar(5); + scene.add(object); + + geometry = new ParametricGeometry(ParametricGeometries.mobius, 20, 20); + object = new THREE.Mesh(geometry, material); + object.position.set(200, 0, 200); + object.scale.multiplyScalar(30); + scene.add(object); + + // + + const GrannyKnot = new Curves.GrannyKnot(); + + const torus = new ParametricGeometries.TorusKnotGeometry(50, 10, 50, 20, 2, 3); + const sphere = new ParametricGeometries.SphereGeometry(50, 20, 10); + const tube = new ParametricGeometries.TubeGeometry(GrannyKnot, 100, 3, 8, true); + + object = new THREE.Mesh(torus, material); + object.position.set(-200, 0, -200); + scene.add(object); + + object = new THREE.Mesh(sphere, material); + object.position.set(0, 0, -200); + scene.add(object); + + object = new THREE.Mesh(tube, material); + object.position.set(200, 0, -200); + object.scale.multiplyScalar(2); + scene.add(object); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const timer = Date.now() * 0.0001; + + camera.position.x = Math.cos(timer) * 800; + camera.position.z = Math.sin(timer) * 800; + + camera.lookAt(scene.position); + + scene.traverse(function (object) { + if (object.isMesh === true) { + object.rotation.x = timer * 5; + object.rotation.y = timer * 2.5; + } + }); + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_gpgpu_birds.ts b/examples-testing/examples/webgl_gpgpu_birds.ts new file mode 100644 index 000000000..ecf53eb80 --- /dev/null +++ b/examples-testing/examples/webgl_gpgpu_birds.ts @@ -0,0 +1,319 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { GPUComputationRenderer } from 'three/addons/misc/GPUComputationRenderer.js'; + +/* TEXTURE WIDTH FOR SIMULATION */ +const WIDTH = 32; + +const BIRDS = WIDTH * WIDTH; + +// Custom Geometry - using 3 triangles each. No UVs, no normals currently. +class BirdGeometry extends THREE.BufferGeometry { + constructor() { + super(); + + const trianglesPerBird = 3; + const triangles = BIRDS * trianglesPerBird; + const points = triangles * 3; + + const vertices = new THREE.BufferAttribute(new Float32Array(points * 3), 3); + const birdColors = new THREE.BufferAttribute(new Float32Array(points * 3), 3); + const references = new THREE.BufferAttribute(new Float32Array(points * 2), 2); + const birdVertex = new THREE.BufferAttribute(new Float32Array(points), 1); + + this.setAttribute('position', vertices); + this.setAttribute('birdColor', birdColors); + this.setAttribute('reference', references); + this.setAttribute('birdVertex', birdVertex); + + // this.setAttribute( 'normal', new Float32Array( points * 3 ), 3 ); + + let v = 0; + + function verts_push() { + for (let i = 0; i < arguments.length; i++) { + vertices.array[v++] = arguments[i]; + } + } + + const wingsSpan = 20; + + for (let f = 0; f < BIRDS; f++) { + // Body + + verts_push(0, -0, -20, 0, 4, -20, 0, 0, 30); + + // Wings + + verts_push(0, 0, -15, -wingsSpan, 0, 0, 0, 0, 15); + + verts_push(0, 0, 15, wingsSpan, 0, 0, 0, 0, -15); + } + + for (let v = 0; v < triangles * 3; v++) { + const triangleIndex = ~~(v / 3); + const birdIndex = ~~(triangleIndex / trianglesPerBird); + const x = (birdIndex % WIDTH) / WIDTH; + const y = ~~(birdIndex / WIDTH) / WIDTH; + + const c = new THREE.Color(0x666666 + (~~(v / 9) / BIRDS) * 0x666666); + + birdColors.array[v * 3 + 0] = c.r; + birdColors.array[v * 3 + 1] = c.g; + birdColors.array[v * 3 + 2] = c.b; + + references.array[v * 2] = x; + references.array[v * 2 + 1] = y; + + birdVertex.array[v] = v % 9; + } + + this.scale(0.2, 0.2, 0.2); + } +} + +// + +let container, stats; +let camera, scene, renderer; +let mouseX = 0, + mouseY = 0; + +let windowHalfX = window.innerWidth / 2; +let windowHalfY = window.innerHeight / 2; + +const BOUNDS = 800, + BOUNDS_HALF = BOUNDS / 2; + +let last = performance.now(); + +let gpuCompute; +let velocityVariable; +let positionVariable; +let positionUniforms; +let velocityUniforms; +let birdUniforms; + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 3000); + camera.position.z = 350; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xffffff); + scene.fog = new THREE.Fog(0xffffff, 100, 1000); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + initComputeRenderer(); + + stats = new Stats(); + container.appendChild(stats.dom); + + container.style.touchAction = 'none'; + container.addEventListener('pointermove', onPointerMove); + + // + + window.addEventListener('resize', onWindowResize); + + const gui = new GUI(); + + const effectController = { + separation: 20.0, + alignment: 20.0, + cohesion: 20.0, + freedom: 0.75, + }; + + const valuesChanger = function () { + velocityUniforms['separationDistance'].value = effectController.separation; + velocityUniforms['alignmentDistance'].value = effectController.alignment; + velocityUniforms['cohesionDistance'].value = effectController.cohesion; + velocityUniforms['freedomFactor'].value = effectController.freedom; + }; + + valuesChanger(); + + gui.add(effectController, 'separation', 0.0, 100.0, 1.0).onChange(valuesChanger); + gui.add(effectController, 'alignment', 0.0, 100, 0.001).onChange(valuesChanger); + gui.add(effectController, 'cohesion', 0.0, 100, 0.025).onChange(valuesChanger); + gui.close(); + + initBirds(); +} + +function initComputeRenderer() { + gpuCompute = new GPUComputationRenderer(WIDTH, WIDTH, renderer); + + if (renderer.capabilities.isWebGL2 === false) { + gpuCompute.setDataType(THREE.HalfFloatType); + } + + const dtPosition = gpuCompute.createTexture(); + const dtVelocity = gpuCompute.createTexture(); + fillPositionTexture(dtPosition); + fillVelocityTexture(dtVelocity); + + velocityVariable = gpuCompute.addVariable( + 'textureVelocity', + document.getElementById('fragmentShaderVelocity').textContent, + dtVelocity, + ); + positionVariable = gpuCompute.addVariable( + 'texturePosition', + document.getElementById('fragmentShaderPosition').textContent, + dtPosition, + ); + + gpuCompute.setVariableDependencies(velocityVariable, [positionVariable, velocityVariable]); + gpuCompute.setVariableDependencies(positionVariable, [positionVariable, velocityVariable]); + + positionUniforms = positionVariable.material.uniforms; + velocityUniforms = velocityVariable.material.uniforms; + + positionUniforms['time'] = { value: 0.0 }; + positionUniforms['delta'] = { value: 0.0 }; + velocityUniforms['time'] = { value: 1.0 }; + velocityUniforms['delta'] = { value: 0.0 }; + velocityUniforms['testing'] = { value: 1.0 }; + velocityUniforms['separationDistance'] = { value: 1.0 }; + velocityUniforms['alignmentDistance'] = { value: 1.0 }; + velocityUniforms['cohesionDistance'] = { value: 1.0 }; + velocityUniforms['freedomFactor'] = { value: 1.0 }; + velocityUniforms['predator'] = { value: new THREE.Vector3() }; + velocityVariable.material.defines.BOUNDS = BOUNDS.toFixed(2); + + velocityVariable.wrapS = THREE.RepeatWrapping; + velocityVariable.wrapT = THREE.RepeatWrapping; + positionVariable.wrapS = THREE.RepeatWrapping; + positionVariable.wrapT = THREE.RepeatWrapping; + + const error = gpuCompute.init(); + + if (error !== null) { + console.error(error); + } +} + +function initBirds() { + const geometry = new BirdGeometry(); + + // For Vertex and Fragment + birdUniforms = { + color: { value: new THREE.Color(0xff2200) }, + texturePosition: { value: null }, + textureVelocity: { value: null }, + time: { value: 1.0 }, + delta: { value: 0.0 }, + }; + + // THREE.ShaderMaterial + const material = new THREE.ShaderMaterial({ + uniforms: birdUniforms, + vertexShader: document.getElementById('birdVS').textContent, + fragmentShader: document.getElementById('birdFS').textContent, + side: THREE.DoubleSide, + }); + + const birdMesh = new THREE.Mesh(geometry, material); + birdMesh.rotation.y = Math.PI / 2; + birdMesh.matrixAutoUpdate = false; + birdMesh.updateMatrix(); + + scene.add(birdMesh); +} + +function fillPositionTexture(texture) { + const theArray = texture.image.data; + + for (let k = 0, kl = theArray.length; k < kl; k += 4) { + const x = Math.random() * BOUNDS - BOUNDS_HALF; + const y = Math.random() * BOUNDS - BOUNDS_HALF; + const z = Math.random() * BOUNDS - BOUNDS_HALF; + + theArray[k + 0] = x; + theArray[k + 1] = y; + theArray[k + 2] = z; + theArray[k + 3] = 1; + } +} + +function fillVelocityTexture(texture) { + const theArray = texture.image.data; + + for (let k = 0, kl = theArray.length; k < kl; k += 4) { + const x = Math.random() - 0.5; + const y = Math.random() - 0.5; + const z = Math.random() - 0.5; + + theArray[k + 0] = x * 10; + theArray[k + 1] = y * 10; + theArray[k + 2] = z * 10; + theArray[k + 3] = 1; + } +} + +function onWindowResize() { + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function onPointerMove(event) { + if (event.isPrimary === false) return; + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const now = performance.now(); + let delta = (now - last) / 1000; + + if (delta > 1) delta = 1; // safety cap on large deltas + last = now; + + positionUniforms['time'].value = now; + positionUniforms['delta'].value = delta; + velocityUniforms['time'].value = now; + velocityUniforms['delta'].value = delta; + birdUniforms['time'].value = now; + birdUniforms['delta'].value = delta; + + velocityUniforms['predator'].value.set((0.5 * mouseX) / windowHalfX, (-0.5 * mouseY) / windowHalfY, 0); + + mouseX = 10000; + mouseY = 10000; + + gpuCompute.compute(); + + birdUniforms['texturePosition'].value = gpuCompute.getCurrentRenderTarget(positionVariable).texture; + birdUniforms['textureVelocity'].value = gpuCompute.getCurrentRenderTarget(velocityVariable).texture; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_gpgpu_birds_gltf.ts b/examples-testing/examples/webgl_gpgpu_birds_gltf.ts new file mode 100644 index 000000000..58aee4f15 --- /dev/null +++ b/examples-testing/examples/webgl_gpgpu_birds_gltf.ts @@ -0,0 +1,421 @@ +import * as THREE from 'three'; +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; +import { GPUComputationRenderer } from 'three/addons/misc/GPUComputationRenderer.js'; + +/* TEXTURE WIDTH FOR SIMULATION */ +const WIDTH = 64; +const BIRDS = WIDTH * WIDTH; + +/* BAKE ANIMATION INTO TEXTURE and CREATE GEOMETRY FROM BASE MODEL */ +const BirdGeometry = new THREE.BufferGeometry(); +let textureAnimation, durationAnimation, birdMesh, materialShader, indicesPerBird; + +function nextPowerOf2(n) { + return Math.pow(2, Math.ceil(Math.log(n) / Math.log(2))); +} + +Math.lerp = function (value1, value2, amount) { + amount = Math.max(Math.min(amount, 1), 0); + return value1 + (value2 - value1) * amount; +}; + +const gltfs = ['models/gltf/Parrot.glb', 'models/gltf/Flamingo.glb']; +const colors = [0xccffff, 0xffdeff]; +const sizes = [0.2, 0.1]; +const selectModel = Math.floor(Math.random() * gltfs.length); +new GLTFLoader().load(gltfs[selectModel], function (gltf) { + const animations = gltf.animations; + durationAnimation = Math.round(animations[0].duration * 60); + const birdGeo = gltf.scene.children[0].geometry; + const morphAttributes = birdGeo.morphAttributes.position; + const tHeight = nextPowerOf2(durationAnimation); + const tWidth = nextPowerOf2(birdGeo.getAttribute('position').count); + indicesPerBird = birdGeo.index.count; + const tData = new Float32Array(4 * tWidth * tHeight); + + for (let i = 0; i < tWidth; i++) { + for (let j = 0; j < tHeight; j++) { + const offset = j * tWidth * 4; + + const curMorph = Math.floor((j / durationAnimation) * morphAttributes.length); + const nextMorph = + (Math.floor((j / durationAnimation) * morphAttributes.length) + 1) % morphAttributes.length; + const lerpAmount = ((j / durationAnimation) * morphAttributes.length) % 1; + + if (j < durationAnimation) { + let d0, d1; + + d0 = morphAttributes[curMorph].array[i * 3]; + d1 = morphAttributes[nextMorph].array[i * 3]; + + if (d0 !== undefined && d1 !== undefined) tData[offset + i * 4] = Math.lerp(d0, d1, lerpAmount); + + d0 = morphAttributes[curMorph].array[i * 3 + 1]; + d1 = morphAttributes[nextMorph].array[i * 3 + 1]; + + if (d0 !== undefined && d1 !== undefined) tData[offset + i * 4 + 1] = Math.lerp(d0, d1, lerpAmount); + + d0 = morphAttributes[curMorph].array[i * 3 + 2]; + d1 = morphAttributes[nextMorph].array[i * 3 + 2]; + + if (d0 !== undefined && d1 !== undefined) tData[offset + i * 4 + 2] = Math.lerp(d0, d1, lerpAmount); + + tData[offset + i * 4 + 3] = 1; + } + } + } + + textureAnimation = new THREE.DataTexture(tData, tWidth, tHeight, THREE.RGBAFormat, THREE.FloatType); + textureAnimation.needsUpdate = true; + + const vertices = [], + color = [], + reference = [], + seeds = [], + indices = []; + const totalVertices = birdGeo.getAttribute('position').count * 3 * BIRDS; + for (let i = 0; i < totalVertices; i++) { + const bIndex = i % (birdGeo.getAttribute('position').count * 3); + vertices.push(birdGeo.getAttribute('position').array[bIndex]); + color.push(birdGeo.getAttribute('color').array[bIndex]); + } + + let r = Math.random(); + for (let i = 0; i < birdGeo.getAttribute('position').count * BIRDS; i++) { + const bIndex = i % birdGeo.getAttribute('position').count; + const bird = Math.floor(i / birdGeo.getAttribute('position').count); + if (bIndex == 0) r = Math.random(); + const j = ~~bird; + const x = (j % WIDTH) / WIDTH; + const y = ~~(j / WIDTH) / WIDTH; + reference.push(x, y, bIndex / tWidth, durationAnimation / tHeight); + seeds.push(bird, r, Math.random(), Math.random()); + } + + for (let i = 0; i < birdGeo.index.array.length * BIRDS; i++) { + const offset = Math.floor(i / birdGeo.index.array.length) * birdGeo.getAttribute('position').count; + indices.push(birdGeo.index.array[i % birdGeo.index.array.length] + offset); + } + + BirdGeometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3)); + BirdGeometry.setAttribute('birdColor', new THREE.BufferAttribute(new Float32Array(color), 3)); + BirdGeometry.setAttribute('color', new THREE.BufferAttribute(new Float32Array(color), 3)); + BirdGeometry.setAttribute('reference', new THREE.BufferAttribute(new Float32Array(reference), 4)); + BirdGeometry.setAttribute('seeds', new THREE.BufferAttribute(new Float32Array(seeds), 4)); + + BirdGeometry.setIndex(indices); + + init(); + animate(); +}); + +let container, stats; +let camera, scene, renderer; +let mouseX = 0, + mouseY = 0; + +let windowHalfX = window.innerWidth / 2; +let windowHalfY = window.innerHeight / 2; + +const BOUNDS = 800, + BOUNDS_HALF = BOUNDS / 2; + +let last = performance.now(); + +let gpuCompute; +let velocityVariable; +let positionVariable; +let positionUniforms; +let velocityUniforms; + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 3000); + camera.position.z = 350; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(colors[selectModel]); + scene.fog = new THREE.Fog(colors[selectModel], 100, 1000); + + // LIGHTS + + const hemiLight = new THREE.HemisphereLight(colors[selectModel], 0xffffff, 4.5); + hemiLight.color.setHSL(0.6, 1, 0.6, THREE.SRGBColorSpace); + hemiLight.groundColor.setHSL(0.095, 1, 0.75, THREE.SRGBColorSpace); + hemiLight.position.set(0, 50, 0); + scene.add(hemiLight); + + const dirLight = new THREE.DirectionalLight(0x00ced1, 2.0); + dirLight.color.setHSL(0.1, 1, 0.95, THREE.SRGBColorSpace); + dirLight.position.set(-1, 1.75, 1); + dirLight.position.multiplyScalar(30); + scene.add(dirLight); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + initComputeRenderer(); + + stats = new Stats(); + container.appendChild(stats.dom); + + container.style.touchAction = 'none'; + container.addEventListener('pointermove', onPointerMove); + + window.addEventListener('resize', onWindowResize); + + const gui = new GUI(); + + const effectController = { + separation: 20.0, + alignment: 20.0, + cohesion: 20.0, + freedom: 0.75, + size: sizes[selectModel], + count: Math.floor(BIRDS / 4), + }; + + const valuesChanger = function () { + velocityUniforms['separationDistance'].value = effectController.separation; + velocityUniforms['alignmentDistance'].value = effectController.alignment; + velocityUniforms['cohesionDistance'].value = effectController.cohesion; + velocityUniforms['freedomFactor'].value = effectController.freedom; + if (materialShader) materialShader.uniforms['size'].value = effectController.size; + BirdGeometry.setDrawRange(0, indicesPerBird * effectController.count); + }; + + valuesChanger(); + + gui.add(effectController, 'separation', 0.0, 100.0, 1.0).onChange(valuesChanger); + gui.add(effectController, 'alignment', 0.0, 100, 0.001).onChange(valuesChanger); + gui.add(effectController, 'cohesion', 0.0, 100, 0.025).onChange(valuesChanger); + gui.add(effectController, 'size', 0, 1, 0.01).onChange(valuesChanger); + gui.add(effectController, 'count', 0, BIRDS, 1).onChange(valuesChanger); + gui.close(); + + initBirds(effectController); +} + +function initComputeRenderer() { + gpuCompute = new GPUComputationRenderer(WIDTH, WIDTH, renderer); + + if (renderer.capabilities.isWebGL2 === false) { + gpuCompute.setDataType(THREE.HalfFloatType); + } + + const dtPosition = gpuCompute.createTexture(); + const dtVelocity = gpuCompute.createTexture(); + fillPositionTexture(dtPosition); + fillVelocityTexture(dtVelocity); + + velocityVariable = gpuCompute.addVariable( + 'textureVelocity', + document.getElementById('fragmentShaderVelocity').textContent, + dtVelocity, + ); + positionVariable = gpuCompute.addVariable( + 'texturePosition', + document.getElementById('fragmentShaderPosition').textContent, + dtPosition, + ); + + gpuCompute.setVariableDependencies(velocityVariable, [positionVariable, velocityVariable]); + gpuCompute.setVariableDependencies(positionVariable, [positionVariable, velocityVariable]); + + positionUniforms = positionVariable.material.uniforms; + velocityUniforms = velocityVariable.material.uniforms; + + positionUniforms['time'] = { value: 0.0 }; + positionUniforms['delta'] = { value: 0.0 }; + velocityUniforms['time'] = { value: 1.0 }; + velocityUniforms['delta'] = { value: 0.0 }; + velocityUniforms['testing'] = { value: 1.0 }; + velocityUniforms['separationDistance'] = { value: 1.0 }; + velocityUniforms['alignmentDistance'] = { value: 1.0 }; + velocityUniforms['cohesionDistance'] = { value: 1.0 }; + velocityUniforms['freedomFactor'] = { value: 1.0 }; + velocityUniforms['predator'] = { value: new THREE.Vector3() }; + velocityVariable.material.defines.BOUNDS = BOUNDS.toFixed(2); + + velocityVariable.wrapS = THREE.RepeatWrapping; + velocityVariable.wrapT = THREE.RepeatWrapping; + positionVariable.wrapS = THREE.RepeatWrapping; + positionVariable.wrapT = THREE.RepeatWrapping; + + const error = gpuCompute.init(); + + if (error !== null) { + console.error(error); + } +} + +function initBirds(effectController) { + const geometry = BirdGeometry; + + const m = new THREE.MeshStandardMaterial({ + vertexColors: true, + flatShading: true, + roughness: 1, + metalness: 0, + }); + + m.onBeforeCompile = shader => { + shader.uniforms.texturePosition = { value: null }; + shader.uniforms.textureVelocity = { value: null }; + shader.uniforms.textureAnimation = { value: textureAnimation }; + shader.uniforms.time = { value: 1.0 }; + shader.uniforms.size = { value: effectController.size }; + shader.uniforms.delta = { value: 0.0 }; + + let token = '#define STANDARD'; + + let insert = /* glsl */ ` + attribute vec4 reference; + attribute vec4 seeds; + attribute vec3 birdColor; + uniform sampler2D texturePosition; + uniform sampler2D textureVelocity; + uniform sampler2D textureAnimation; + uniform float size; + uniform float time; + `; + + shader.vertexShader = shader.vertexShader.replace(token, token + insert); + + token = '#include '; + + insert = /* glsl */ ` + vec4 tmpPos = texture2D( texturePosition, reference.xy ); + + vec3 pos = tmpPos.xyz; + vec3 velocity = normalize(texture2D( textureVelocity, reference.xy ).xyz); + vec3 aniPos = texture2D( textureAnimation, vec2( reference.z, mod( time + ( seeds.x ) * ( ( 0.0004 + seeds.y / 10000.0) + normalize( velocity ) / 20000.0 ), reference.w ) ) ).xyz; + vec3 newPosition = position; + + newPosition = mat3( modelMatrix ) * ( newPosition + aniPos ); + newPosition *= size + seeds.y * size * 0.2; + + velocity.z *= -1.; + float xz = length( velocity.xz ); + float xyz = 1.; + float x = sqrt( 1. - velocity.y * velocity.y ); + + float cosry = velocity.x / xz; + float sinry = velocity.z / xz; + + float cosrz = x / xyz; + float sinrz = velocity.y / xyz; + + mat3 maty = mat3( cosry, 0, -sinry, 0 , 1, 0 , sinry, 0, cosry ); + mat3 matz = mat3( cosrz , sinrz, 0, -sinrz, cosrz, 0, 0 , 0 , 1 ); + + newPosition = maty * matz * newPosition; + newPosition += pos; + + vec3 transformed = vec3( newPosition ); + `; + + shader.vertexShader = shader.vertexShader.replace(token, insert); + + materialShader = shader; + }; + + birdMesh = new THREE.Mesh(geometry, m); + birdMesh.rotation.y = Math.PI / 2; + + birdMesh.castShadow = true; + birdMesh.receiveShadow = true; + + scene.add(birdMesh); +} + +function fillPositionTexture(texture) { + const theArray = texture.image.data; + + for (let k = 0, kl = theArray.length; k < kl; k += 4) { + const x = Math.random() * BOUNDS - BOUNDS_HALF; + const y = Math.random() * BOUNDS - BOUNDS_HALF; + const z = Math.random() * BOUNDS - BOUNDS_HALF; + + theArray[k + 0] = x; + theArray[k + 1] = y; + theArray[k + 2] = z; + theArray[k + 3] = 1; + } +} + +function fillVelocityTexture(texture) { + const theArray = texture.image.data; + + for (let k = 0, kl = theArray.length; k < kl; k += 4) { + const x = Math.random() - 0.5; + const y = Math.random() - 0.5; + const z = Math.random() - 0.5; + + theArray[k + 0] = x * 10; + theArray[k + 1] = y * 10; + theArray[k + 2] = z * 10; + theArray[k + 3] = 1; + } +} + +function onWindowResize() { + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function onPointerMove(event) { + if (event.isPrimary === false) return; + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + const now = performance.now(); + let delta = (now - last) / 1000; + + if (delta > 1) delta = 1; // safety cap on large deltas + last = now; + + positionUniforms['time'].value = now; + positionUniforms['delta'].value = delta; + velocityUniforms['time'].value = now; + velocityUniforms['delta'].value = delta; + if (materialShader) materialShader.uniforms['time'].value = now / 1000; + if (materialShader) materialShader.uniforms['delta'].value = delta; + + velocityUniforms['predator'].value.set((0.5 * mouseX) / windowHalfX, (-0.5 * mouseY) / windowHalfY, 0); + + mouseX = 10000; + mouseY = 10000; + + gpuCompute.compute(); + + if (materialShader) + materialShader.uniforms['texturePosition'].value = gpuCompute.getCurrentRenderTarget(positionVariable).texture; + if (materialShader) + materialShader.uniforms['textureVelocity'].value = gpuCompute.getCurrentRenderTarget(velocityVariable).texture; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_gpgpu_protoplanet.ts b/examples-testing/examples/webgl_gpgpu_protoplanet.ts new file mode 100644 index 000000000..b1a7e0287 --- /dev/null +++ b/examples-testing/examples/webgl_gpgpu_protoplanet.ts @@ -0,0 +1,288 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { GPUComputationRenderer } from 'three/addons/misc/GPUComputationRenderer.js'; + +// Texture width for simulation (each texel is a debris particle) +const WIDTH = 64; + +let container, stats; +let camera, scene, renderer, geometry; + +const PARTICLES = WIDTH * WIDTH; + +let gpuCompute; +let velocityVariable; +let positionVariable; +let velocityUniforms; +let particleUniforms; +let effectController; + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 5, 15000); + camera.position.y = 120; + camera.position.z = 400; + + scene = new THREE.Scene(); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + const controls = new OrbitControls(camera, renderer.domElement); + controls.minDistance = 100; + controls.maxDistance = 1000; + + effectController = { + // Can be changed dynamically + gravityConstant: 100.0, + density: 0.45, + + // Must restart simulation + radius: 300, + height: 8, + exponent: 0.4, + maxMass: 15.0, + velocity: 70, + velocityExponent: 0.2, + randVelocity: 0.001, + }; + + initComputeRenderer(); + + stats = new Stats(); + container.appendChild(stats.dom); + + window.addEventListener('resize', onWindowResize); + + initGUI(); + + initProtoplanets(); + + dynamicValuesChanger(); +} + +function initComputeRenderer() { + gpuCompute = new GPUComputationRenderer(WIDTH, WIDTH, renderer); + + if (renderer.capabilities.isWebGL2 === false) { + gpuCompute.setDataType(THREE.HalfFloatType); + } + + const dtPosition = gpuCompute.createTexture(); + const dtVelocity = gpuCompute.createTexture(); + + fillTextures(dtPosition, dtVelocity); + + velocityVariable = gpuCompute.addVariable( + 'textureVelocity', + document.getElementById('computeShaderVelocity').textContent, + dtVelocity, + ); + positionVariable = gpuCompute.addVariable( + 'texturePosition', + document.getElementById('computeShaderPosition').textContent, + dtPosition, + ); + + gpuCompute.setVariableDependencies(velocityVariable, [positionVariable, velocityVariable]); + gpuCompute.setVariableDependencies(positionVariable, [positionVariable, velocityVariable]); + + velocityUniforms = velocityVariable.material.uniforms; + + velocityUniforms['gravityConstant'] = { value: 0.0 }; + velocityUniforms['density'] = { value: 0.0 }; + + const error = gpuCompute.init(); + + if (error !== null) { + console.error(error); + } +} + +function restartSimulation() { + const dtPosition = gpuCompute.createTexture(); + const dtVelocity = gpuCompute.createTexture(); + + fillTextures(dtPosition, dtVelocity); + + gpuCompute.renderTexture(dtPosition, positionVariable.renderTargets[0]); + gpuCompute.renderTexture(dtPosition, positionVariable.renderTargets[1]); + gpuCompute.renderTexture(dtVelocity, velocityVariable.renderTargets[0]); + gpuCompute.renderTexture(dtVelocity, velocityVariable.renderTargets[1]); +} + +function initProtoplanets() { + geometry = new THREE.BufferGeometry(); + + const positions = new Float32Array(PARTICLES * 3); + let p = 0; + + for (let i = 0; i < PARTICLES; i++) { + positions[p++] = (Math.random() * 2 - 1) * effectController.radius; + positions[p++] = 0; //( Math.random() * 2 - 1 ) * effectController.radius; + positions[p++] = (Math.random() * 2 - 1) * effectController.radius; + } + + const uvs = new Float32Array(PARTICLES * 2); + p = 0; + + for (let j = 0; j < WIDTH; j++) { + for (let i = 0; i < WIDTH; i++) { + uvs[p++] = i / (WIDTH - 1); + uvs[p++] = j / (WIDTH - 1); + } + } + + geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); + geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2)); + + particleUniforms = { + texturePosition: { value: null }, + textureVelocity: { value: null }, + cameraConstant: { value: getCameraConstant(camera) }, + density: { value: 0.0 }, + }; + + // THREE.ShaderMaterial + const material = new THREE.ShaderMaterial({ + uniforms: particleUniforms, + vertexShader: document.getElementById('particleVertexShader').textContent, + fragmentShader: document.getElementById('particleFragmentShader').textContent, + }); + + material.extensions.drawBuffers = true; + + const particles = new THREE.Points(geometry, material); + particles.matrixAutoUpdate = false; + particles.updateMatrix(); + + scene.add(particles); +} + +function fillTextures(texturePosition, textureVelocity) { + const posArray = texturePosition.image.data; + const velArray = textureVelocity.image.data; + + const radius = effectController.radius; + const height = effectController.height; + const exponent = effectController.exponent; + const maxMass = (effectController.maxMass * 1024) / PARTICLES; + const maxVel = effectController.velocity; + const velExponent = effectController.velocityExponent; + const randVel = effectController.randVelocity; + + for (let k = 0, kl = posArray.length; k < kl; k += 4) { + // Position + let x, z, rr; + + do { + x = Math.random() * 2 - 1; + z = Math.random() * 2 - 1; + rr = x * x + z * z; + } while (rr > 1); + + rr = Math.sqrt(rr); + + const rExp = radius * Math.pow(rr, exponent); + + // Velocity + const vel = maxVel * Math.pow(rr, velExponent); + + const vx = vel * z + (Math.random() * 2 - 1) * randVel; + const vy = (Math.random() * 2 - 1) * randVel * 0.05; + const vz = -vel * x + (Math.random() * 2 - 1) * randVel; + + x *= rExp; + z *= rExp; + const y = (Math.random() * 2 - 1) * height; + + const mass = Math.random() * maxMass + 1; + + // Fill in texture values + posArray[k + 0] = x; + posArray[k + 1] = y; + posArray[k + 2] = z; + posArray[k + 3] = 1; + + velArray[k + 0] = vx; + velArray[k + 1] = vy; + velArray[k + 2] = vz; + velArray[k + 3] = mass; + } +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + particleUniforms['cameraConstant'].value = getCameraConstant(camera); +} + +function dynamicValuesChanger() { + velocityUniforms['gravityConstant'].value = effectController.gravityConstant; + velocityUniforms['density'].value = effectController.density; + particleUniforms['density'].value = effectController.density; +} + +function initGUI() { + const gui = new GUI({ width: 280 }); + + const folder1 = gui.addFolder('Dynamic parameters'); + + folder1.add(effectController, 'gravityConstant', 0.0, 1000.0, 0.05).onChange(dynamicValuesChanger); + folder1.add(effectController, 'density', 0.0, 10.0, 0.001).onChange(dynamicValuesChanger); + + const folder2 = gui.addFolder('Static parameters'); + + folder2.add(effectController, 'radius', 10.0, 1000.0, 1.0); + folder2.add(effectController, 'height', 0.0, 50.0, 0.01); + folder2.add(effectController, 'exponent', 0.0, 2.0, 0.001); + folder2.add(effectController, 'maxMass', 1.0, 50.0, 0.1); + folder2.add(effectController, 'velocity', 0.0, 150.0, 0.1); + folder2.add(effectController, 'velocityExponent', 0.0, 1.0, 0.01); + folder2.add(effectController, 'randVelocity', 0.0, 50.0, 0.1); + + const buttonRestart = { + restartSimulation: function () { + restartSimulation(); + }, + }; + + folder2.add(buttonRestart, 'restartSimulation'); + + folder1.open(); + folder2.open(); +} + +function getCameraConstant(camera) { + return window.innerHeight / (Math.tan(THREE.MathUtils.DEG2RAD * 0.5 * camera.fov) / camera.zoom); +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + gpuCompute.compute(); + + particleUniforms['texturePosition'].value = gpuCompute.getCurrentRenderTarget(positionVariable).texture; + particleUniforms['textureVelocity'].value = gpuCompute.getCurrentRenderTarget(velocityVariable).texture; + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_gpgpu_water.ts b/examples-testing/examples/webgl_gpgpu_water.ts new file mode 100644 index 000000000..dfc48210e --- /dev/null +++ b/examples-testing/examples/webgl_gpgpu_water.ts @@ -0,0 +1,403 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { GPUComputationRenderer } from 'three/addons/misc/GPUComputationRenderer.js'; +import { SimplexNoise } from 'three/addons/math/SimplexNoise.js'; + +// Texture width for simulation +const WIDTH = 128; + +// Water size in system units +const BOUNDS = 512; +const BOUNDS_HALF = BOUNDS * 0.5; + +let container, stats; +let camera, scene, renderer; +let mouseMoved = false; +const mouseCoords = new THREE.Vector2(); +const raycaster = new THREE.Raycaster(); + +let waterMesh; +let meshRay; +let gpuCompute; +let heightmapVariable; +let waterUniforms; +let smoothShader; +let readWaterLevelShader; +let readWaterLevelRenderTarget; +let readWaterLevelImage; +const waterNormal = new THREE.Vector3(); + +const NUM_SPHERES = 5; +const spheres = []; +let spheresEnabled = true; + +const simplex = new SimplexNoise(); + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 3000); + camera.position.set(0, 200, 350); + camera.lookAt(0, 0, 0); + + scene = new THREE.Scene(); + + const sun = new THREE.DirectionalLight(0xffffff, 3.0); + sun.position.set(300, 400, 175); + scene.add(sun); + + const sun2 = new THREE.DirectionalLight(0x40a040, 2.0); + sun2.position.set(-100, 350, -200); + scene.add(sun2); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + container.style.touchAction = 'none'; + container.addEventListener('pointermove', onPointerMove); + + document.addEventListener('keydown', function (event) { + // W Pressed: Toggle wireframe + if (event.keyCode === 87) { + waterMesh.material.wireframe = !waterMesh.material.wireframe; + waterMesh.material.needsUpdate = true; + } + }); + + window.addEventListener('resize', onWindowResize); + + const gui = new GUI(); + + const effectController = { + mouseSize: 20.0, + viscosity: 0.98, + spheresEnabled: spheresEnabled, + }; + + const valuesChanger = function () { + heightmapVariable.material.uniforms['mouseSize'].value = effectController.mouseSize; + heightmapVariable.material.uniforms['viscosityConstant'].value = effectController.viscosity; + spheresEnabled = effectController.spheresEnabled; + for (let i = 0; i < NUM_SPHERES; i++) { + if (spheres[i]) { + spheres[i].visible = spheresEnabled; + } + } + }; + + gui.add(effectController, 'mouseSize', 1.0, 100.0, 1.0).onChange(valuesChanger); + gui.add(effectController, 'viscosity', 0.9, 0.999, 0.001).onChange(valuesChanger); + gui.add(effectController, 'spheresEnabled', 0, 1, 1).onChange(valuesChanger); + const buttonSmooth = { + smoothWater: function () { + smoothWater(); + }, + }; + gui.add(buttonSmooth, 'smoothWater'); + + initWater(); + + createSpheres(); + + valuesChanger(); +} + +function initWater() { + const materialColor = 0x0040c0; + + const geometry = new THREE.PlaneGeometry(BOUNDS, BOUNDS, WIDTH - 1, WIDTH - 1); + + // material: make a THREE.ShaderMaterial clone of THREE.MeshPhongMaterial, with customized vertex shader + const material = new THREE.ShaderMaterial({ + uniforms: THREE.UniformsUtils.merge([ + THREE.ShaderLib['phong'].uniforms, + { + heightmap: { value: null }, + }, + ]), + vertexShader: document.getElementById('waterVertexShader').textContent, + fragmentShader: THREE.ShaderChunk['meshphong_frag'], + }); + + material.lights = true; + + // Material attributes from THREE.MeshPhongMaterial + // Sets the uniforms with the material values + material.uniforms['diffuse'].value = new THREE.Color(materialColor); + material.uniforms['specular'].value = new THREE.Color(0x111111); + material.uniforms['shininess'].value = Math.max(50, 1e-4); + material.uniforms['opacity'].value = material.opacity; + + // Defines + material.defines.WIDTH = WIDTH.toFixed(1); + material.defines.BOUNDS = BOUNDS.toFixed(1); + + waterUniforms = material.uniforms; + + waterMesh = new THREE.Mesh(geometry, material); + waterMesh.rotation.x = -Math.PI / 2; + waterMesh.matrixAutoUpdate = false; + waterMesh.updateMatrix(); + + scene.add(waterMesh); + + // THREE.Mesh just for mouse raycasting + const geometryRay = new THREE.PlaneGeometry(BOUNDS, BOUNDS, 1, 1); + meshRay = new THREE.Mesh(geometryRay, new THREE.MeshBasicMaterial({ color: 0xffffff, visible: false })); + meshRay.rotation.x = -Math.PI / 2; + meshRay.matrixAutoUpdate = false; + meshRay.updateMatrix(); + scene.add(meshRay); + + // Creates the gpu computation class and sets it up + + gpuCompute = new GPUComputationRenderer(WIDTH, WIDTH, renderer); + + if (renderer.capabilities.isWebGL2 === false) { + gpuCompute.setDataType(THREE.HalfFloatType); + } + + const heightmap0 = gpuCompute.createTexture(); + + fillTexture(heightmap0); + + heightmapVariable = gpuCompute.addVariable( + 'heightmap', + document.getElementById('heightmapFragmentShader').textContent, + heightmap0, + ); + + gpuCompute.setVariableDependencies(heightmapVariable, [heightmapVariable]); + + heightmapVariable.material.uniforms['mousePos'] = { value: new THREE.Vector2(10000, 10000) }; + heightmapVariable.material.uniforms['mouseSize'] = { value: 20.0 }; + heightmapVariable.material.uniforms['viscosityConstant'] = { value: 0.98 }; + heightmapVariable.material.uniforms['heightCompensation'] = { value: 0 }; + heightmapVariable.material.defines.BOUNDS = BOUNDS.toFixed(1); + + const error = gpuCompute.init(); + if (error !== null) { + console.error(error); + } + + // Create compute shader to smooth the water surface and velocity + smoothShader = gpuCompute.createShaderMaterial(document.getElementById('smoothFragmentShader').textContent, { + smoothTexture: { value: null }, + }); + + // Create compute shader to read water level + readWaterLevelShader = gpuCompute.createShaderMaterial( + document.getElementById('readWaterLevelFragmentShader').textContent, + { + point1: { value: new THREE.Vector2() }, + levelTexture: { value: null }, + }, + ); + readWaterLevelShader.defines.WIDTH = WIDTH.toFixed(1); + readWaterLevelShader.defines.BOUNDS = BOUNDS.toFixed(1); + + // Create a 4x1 pixel image and a render target (Uint8, 4 channels, 1 byte per channel) to read water height and orientation + readWaterLevelImage = new Uint8Array(4 * 1 * 4); + + readWaterLevelRenderTarget = new THREE.WebGLRenderTarget(4, 1, { + wrapS: THREE.ClampToEdgeWrapping, + wrapT: THREE.ClampToEdgeWrapping, + minFilter: THREE.NearestFilter, + magFilter: THREE.NearestFilter, + format: THREE.RGBAFormat, + type: THREE.UnsignedByteType, + depthBuffer: false, + }); +} + +function fillTexture(texture) { + const waterMaxHeight = 10; + + function noise(x, y) { + let multR = waterMaxHeight; + let mult = 0.025; + let r = 0; + for (let i = 0; i < 15; i++) { + r += multR * simplex.noise(x * mult, y * mult); + multR *= 0.53 + 0.025 * i; + mult *= 1.25; + } + + return r; + } + + const pixels = texture.image.data; + + let p = 0; + for (let j = 0; j < WIDTH; j++) { + for (let i = 0; i < WIDTH; i++) { + const x = (i * 128) / WIDTH; + const y = (j * 128) / WIDTH; + + pixels[p + 0] = noise(x, y); + pixels[p + 1] = pixels[p + 0]; + pixels[p + 2] = 0; + pixels[p + 3] = 1; + + p += 4; + } + } +} + +function smoothWater() { + const currentRenderTarget = gpuCompute.getCurrentRenderTarget(heightmapVariable); + const alternateRenderTarget = gpuCompute.getAlternateRenderTarget(heightmapVariable); + + for (let i = 0; i < 10; i++) { + smoothShader.uniforms['smoothTexture'].value = currentRenderTarget.texture; + gpuCompute.doRenderTarget(smoothShader, alternateRenderTarget); + + smoothShader.uniforms['smoothTexture'].value = alternateRenderTarget.texture; + gpuCompute.doRenderTarget(smoothShader, currentRenderTarget); + } +} + +function createSpheres() { + const sphereTemplate = new THREE.Mesh( + new THREE.SphereGeometry(4, 24, 12), + new THREE.MeshPhongMaterial({ color: 0xffff00 }), + ); + + for (let i = 0; i < NUM_SPHERES; i++) { + let sphere = sphereTemplate; + if (i < NUM_SPHERES - 1) { + sphere = sphereTemplate.clone(); + } + + sphere.position.x = (Math.random() - 0.5) * BOUNDS * 0.7; + sphere.position.z = (Math.random() - 0.5) * BOUNDS * 0.7; + + sphere.userData.velocity = new THREE.Vector3(); + + scene.add(sphere); + + spheres[i] = sphere; + } +} + +function sphereDynamics() { + const currentRenderTarget = gpuCompute.getCurrentRenderTarget(heightmapVariable); + + readWaterLevelShader.uniforms['levelTexture'].value = currentRenderTarget.texture; + + for (let i = 0; i < NUM_SPHERES; i++) { + const sphere = spheres[i]; + + if (sphere) { + // Read water level and orientation + const u = (0.5 * sphere.position.x) / BOUNDS_HALF + 0.5; + const v = 1 - ((0.5 * sphere.position.z) / BOUNDS_HALF + 0.5); + readWaterLevelShader.uniforms['point1'].value.set(u, v); + gpuCompute.doRenderTarget(readWaterLevelShader, readWaterLevelRenderTarget); + + renderer.readRenderTargetPixels(readWaterLevelRenderTarget, 0, 0, 4, 1, readWaterLevelImage); + const pixels = new Float32Array(readWaterLevelImage.buffer); + + // Get orientation + waterNormal.set(pixels[1], 0, -pixels[2]); + + const pos = sphere.position; + + // Set height + pos.y = pixels[0]; + + // Move sphere + waterNormal.multiplyScalar(0.1); + sphere.userData.velocity.add(waterNormal); + sphere.userData.velocity.multiplyScalar(0.998); + pos.add(sphere.userData.velocity); + + if (pos.x < -BOUNDS_HALF) { + pos.x = -BOUNDS_HALF + 0.001; + sphere.userData.velocity.x *= -0.3; + } else if (pos.x > BOUNDS_HALF) { + pos.x = BOUNDS_HALF - 0.001; + sphere.userData.velocity.x *= -0.3; + } + + if (pos.z < -BOUNDS_HALF) { + pos.z = -BOUNDS_HALF + 0.001; + sphere.userData.velocity.z *= -0.3; + } else if (pos.z > BOUNDS_HALF) { + pos.z = BOUNDS_HALF - 0.001; + sphere.userData.velocity.z *= -0.3; + } + } + } +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function setMouseCoords(x, y) { + mouseCoords.set((x / renderer.domElement.clientWidth) * 2 - 1, -(y / renderer.domElement.clientHeight) * 2 + 1); + mouseMoved = true; +} + +function onPointerMove(event) { + if (event.isPrimary === false) return; + + setMouseCoords(event.clientX, event.clientY); +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function render() { + // Set uniforms: mouse interaction + const uniforms = heightmapVariable.material.uniforms; + if (mouseMoved) { + raycaster.setFromCamera(mouseCoords, camera); + + const intersects = raycaster.intersectObject(meshRay); + + if (intersects.length > 0) { + const point = intersects[0].point; + uniforms['mousePos'].value.set(point.x, point.z); + } else { + uniforms['mousePos'].value.set(10000, 10000); + } + + mouseMoved = false; + } else { + uniforms['mousePos'].value.set(10000, 10000); + } + + // Do the gpu computation + gpuCompute.compute(); + + if (spheresEnabled) { + sphereDynamics(); + } + + // Get compute output in custom uniform + waterUniforms['heightmap'].value = gpuCompute.getCurrentRenderTarget(heightmapVariable).texture; + + // Render + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_materials_modified.ts b/examples-testing/examples/webgl_materials_modified.ts new file mode 100644 index 000000000..3708f65b7 --- /dev/null +++ b/examples-testing/examples/webgl_materials_modified.ts @@ -0,0 +1,117 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; + +let camera, scene, renderer, stats; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.z = 20; + + scene = new THREE.Scene(); + + const loader = new GLTFLoader(); + loader.load('models/gltf/LeePerrySmith/LeePerrySmith.glb', function (gltf) { + const geometry = gltf.scene.children[0].geometry; + + let mesh = new THREE.Mesh(geometry, buildTwistMaterial(2.0)); + mesh.position.x = -3.5; + mesh.position.y = -0.5; + scene.add(mesh); + + mesh = new THREE.Mesh(geometry, buildTwistMaterial(-2.0)); + mesh.position.x = 3.5; + mesh.position.y = -0.5; + scene.add(mesh); + }); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + const controls = new OrbitControls(camera, renderer.domElement); + controls.minDistance = 10; + controls.maxDistance = 50; + + // + + stats = new Stats(); + document.body.appendChild(stats.dom); + + // EVENTS + + window.addEventListener('resize', onWindowResize); +} + +function buildTwistMaterial(amount) { + const material = new THREE.MeshNormalMaterial(); + material.onBeforeCompile = function (shader) { + shader.uniforms.time = { value: 0 }; + + shader.vertexShader = 'uniform float time;\n' + shader.vertexShader; + shader.vertexShader = shader.vertexShader.replace( + '#include ', + [ + `float theta = sin( time + position.y ) / ${amount.toFixed(1)};`, + 'float c = cos( theta );', + 'float s = sin( theta );', + 'mat3 m = mat3( c, 0, s, 0, 1, 0, -s, 0, c );', + 'vec3 transformed = vec3( position ) * m;', + 'vNormal = vNormal * m;', + ].join('\n'), + ); + + material.userData.shader = shader; + }; + + // Make sure WebGLRenderer doesnt reuse a single program + + material.customProgramCacheKey = function () { + return amount.toFixed(1); + }; + + return material; +} + +// + +function onWindowResize() { + const width = window.innerWidth; + const height = window.innerHeight; + + camera.aspect = width / height; + camera.updateProjectionMatrix(); + + renderer.setSize(width, height); +} + +// + +function animate() { + requestAnimationFrame(animate); + + render(); + + stats.update(); +} + +function render() { + scene.traverse(function (child) { + if (child.isMesh) { + const shader = child.material.userData.shader; + + if (shader) { + shader.uniforms.time.value = performance.now() / 1000; + } + } + }); + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webgl_pmrem_test.ts b/examples-testing/examples/webgl_pmrem_test.ts new file mode 100644 index 000000000..b33e4e2f1 --- /dev/null +++ b/examples-testing/examples/webgl_pmrem_test.ts @@ -0,0 +1,141 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let scene, camera, controls, renderer; + +function init() { + const width = window.innerWidth; + const height = window.innerHeight; + const aspect = width / height; + + // renderer + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(width, height); + + // tonemapping + renderer.toneMapping = THREE.ACESFilmicToneMapping; + renderer.toneMappingExposure = 1; + + document.body.appendChild(renderer.domElement); + + window.addEventListener('resize', onWindowResize); + + // scene + + scene = new THREE.Scene(); + + // camera + + camera = new THREE.PerspectiveCamera(40, aspect, 1, 30); + updateCamera(); + camera.position.set(0, 0, 16); + + // controls + + controls = new OrbitControls(camera, renderer.domElement); + controls.addEventListener('change', render); // use if there is no animation loop + controls.minDistance = 4; + controls.maxDistance = 20; + + // light + + const directionalLight = new THREE.DirectionalLight(0xffffff, 0); // set intensity to 0 to start + const x = 597; + const y = 213; + const theta = ((x + 0.5) * Math.PI) / 512; + const phi = ((y + 0.5) * Math.PI) / 512; + + directionalLight.position.setFromSphericalCoords(100, -phi, Math.PI / 2 - theta); + + scene.add(directionalLight); + // scene.add( new THREE.DirectionalLightHelper( directionalLight ) ); + + // The spot1Lux HDR environment map is expressed in nits (lux / sr). The directional light has units of lux, + // so to match a 1 lux light, we set a single pixel with a value equal to 1 divided by the solid + // angle of the pixel in steradians. This image is 1024 x 512, + // so the value is 1 / ( sin( phi ) * ( pi / 512 ) ^ 2 ) = 27,490 nits. + + const gui = new GUI(); + gui.add({ enabled: true }, 'enabled') + .name('PMREM') + .onChange(value => { + directionalLight.intensity = value ? 0 : 1; + + scene.traverse(function (child) { + if (child.isMesh) { + child.material.envMapIntensity = 1 - directionalLight.intensity; + } + }); + + render(); + }); +} + +function createObjects() { + let radianceMap = null; + new RGBELoader() + // .setDataType( THREE.FloatType ) + .setPath('textures/equirectangular/') + .load('spot1Lux.hdr', function (texture) { + radianceMap = pmremGenerator.fromEquirectangular(texture).texture; + pmremGenerator.dispose(); + + scene.background = radianceMap; + + const geometry = new THREE.SphereGeometry(0.4, 32, 32); + + for (let x = 0; x <= 10; x++) { + for (let y = 0; y <= 2; y++) { + const material = new THREE.MeshPhysicalMaterial({ + roughness: x / 10, + metalness: y < 1 ? 1 : 0, + color: y < 2 ? 0xffffff : 0x000000, + envMap: radianceMap, + envMapIntensity: 1, + }); + + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = x - 5; + mesh.position.y = 1 - y; + scene.add(mesh); + } + } + + render(); + }); + + const pmremGenerator = new THREE.PMREMGenerator(renderer); + pmremGenerator.compileEquirectangularShader(); +} + +function onWindowResize() { + const width = window.innerWidth; + const height = window.innerHeight; + + camera.aspect = width / height; + updateCamera(); + + renderer.setSize(width, height); + + render(); +} + +function updateCamera() { + const horizontalFoV = 40; + const verticalFoV = + (2 * Math.atan(Math.tan(((horizontalFoV / 2) * Math.PI) / 180) / camera.aspect) * 180) / Math.PI; + camera.fov = verticalFoV; + camera.updateProjectionMatrix(); +} + +function render() { + renderer.render(scene, camera); +} + +Promise.resolve().then(init).then(createObjects).then(render); diff --git a/examples-testing/examples/webgl_postprocessing.ts b/examples-testing/examples/webgl_postprocessing.ts new file mode 100644 index 000000000..944115ba1 --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing.ts @@ -0,0 +1,88 @@ +import * as THREE from 'three'; + +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; + +import { RGBShiftShader } from 'three/addons/shaders/RGBShiftShader.js'; +import { DotScreenShader } from 'three/addons/shaders/DotScreenShader.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; + +let camera, renderer, composer; +let object; + +init(); +animate(); + +function init() { + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + // + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.z = 400; + + const scene = new THREE.Scene(); + scene.fog = new THREE.Fog(0x000000, 1, 1000); + + object = new THREE.Object3D(); + scene.add(object); + + const geometry = new THREE.SphereGeometry(1, 4, 4); + const material = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); + + for (let i = 0; i < 100; i++) { + const mesh = new THREE.Mesh(geometry, material); + mesh.position.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize(); + mesh.position.multiplyScalar(Math.random() * 400); + mesh.rotation.set(Math.random() * 2, Math.random() * 2, Math.random() * 2); + mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 50; + object.add(mesh); + } + + scene.add(new THREE.AmbientLight(0xcccccc)); + + const light = new THREE.DirectionalLight(0xffffff, 3); + light.position.set(1, 1, 1); + scene.add(light); + + // postprocessing + + composer = new EffectComposer(renderer); + composer.addPass(new RenderPass(scene, camera)); + + const effect1 = new ShaderPass(DotScreenShader); + effect1.uniforms['scale'].value = 4; + composer.addPass(effect1); + + const effect2 = new ShaderPass(RGBShiftShader); + effect2.uniforms['amount'].value = 0.0015; + composer.addPass(effect2); + + const effect3 = new OutputPass(); + composer.addPass(effect3); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + composer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + object.rotation.x += 0.005; + object.rotation.y += 0.01; + + composer.render(); +} diff --git a/examples-testing/examples/webgl_postprocessing_advanced.ts b/examples-testing/examples/webgl_postprocessing_advanced.ts new file mode 100644 index 000000000..bf49da5eb --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_advanced.ts @@ -0,0 +1,306 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; +import { BloomPass } from 'three/addons/postprocessing/BloomPass.js'; +import { FilmPass } from 'three/addons/postprocessing/FilmPass.js'; +import { DotScreenPass } from 'three/addons/postprocessing/DotScreenPass.js'; +import { MaskPass, ClearMaskPass } from 'three/addons/postprocessing/MaskPass.js'; +import { TexturePass } from 'three/addons/postprocessing/TexturePass.js'; + +import { BleachBypassShader } from 'three/addons/shaders/BleachBypassShader.js'; +import { ColorifyShader } from 'three/addons/shaders/ColorifyShader.js'; +import { HorizontalBlurShader } from 'three/addons/shaders/HorizontalBlurShader.js'; +import { VerticalBlurShader } from 'three/addons/shaders/VerticalBlurShader.js'; +import { SepiaShader } from 'three/addons/shaders/SepiaShader.js'; +import { VignetteShader } from 'three/addons/shaders/VignetteShader.js'; +import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.js'; + +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; + +let container, stats; + +let composerScene, composer1, composer2, composer3, composer4; + +let cameraOrtho, cameraPerspective, sceneModel, sceneBG, renderer, mesh, directionalLight; + +const width = window.innerWidth || 2; +const height = window.innerHeight || 2; + +let halfWidth = width / 2; +let halfHeight = height / 2; + +let quadBG, quadMask, renderScene; + +const delta = 0.01; + +init(); +animate(); + +function init() { + container = document.getElementById('container'); + + // + + cameraOrtho = new THREE.OrthographicCamera(-halfWidth, halfWidth, halfHeight, -halfHeight, -10000, 10000); + cameraOrtho.position.z = 100; + + cameraPerspective = new THREE.PerspectiveCamera(50, width / height, 1, 10000); + cameraPerspective.position.z = 900; + + // + + sceneModel = new THREE.Scene(); + sceneBG = new THREE.Scene(); + + // + + directionalLight = new THREE.DirectionalLight(0xffffff, 3); + directionalLight.position.set(0, -0.1, 1).normalize(); + sceneModel.add(directionalLight); + + const loader = new GLTFLoader(); + loader.load('models/gltf/LeePerrySmith/LeePerrySmith.glb', function (gltf) { + createMesh(gltf.scene.children[0].geometry, sceneModel, 100); + }); + + // + + const diffuseMap = new THREE.TextureLoader().load('textures/cube/SwedishRoyalCastle/pz.jpg'); + diffuseMap.colorSpace = THREE.SRGBColorSpace; + + const materialColor = new THREE.MeshBasicMaterial({ + map: diffuseMap, + depthTest: false, + }); + + quadBG = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), materialColor); + quadBG.position.z = -500; + quadBG.scale.set(width, height, 1); + sceneBG.add(quadBG); + + // + + const sceneMask = new THREE.Scene(); + + quadMask = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), new THREE.MeshBasicMaterial({ color: 0xffaa00 })); + quadMask.position.z = -300; + quadMask.scale.set(width / 2, height / 2, 1); + sceneMask.add(quadMask); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(width, height); + renderer.autoClear = false; + + // + + container.appendChild(renderer.domElement); + + // + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + const shaderBleach = BleachBypassShader; + const shaderSepia = SepiaShader; + const shaderVignette = VignetteShader; + + const effectBleach = new ShaderPass(shaderBleach); + const effectSepia = new ShaderPass(shaderSepia); + const effectVignette = new ShaderPass(shaderVignette); + const gammaCorrection = new ShaderPass(GammaCorrectionShader); + + effectBleach.uniforms['opacity'].value = 0.95; + + effectSepia.uniforms['amount'].value = 0.9; + + effectVignette.uniforms['offset'].value = 0.95; + effectVignette.uniforms['darkness'].value = 1.6; + + const effectBloom = new BloomPass(0.5); + const effectFilm = new FilmPass(0.35, 0.025, 648, false); + const effectFilmBW = new FilmPass(0.35, 0.5, 2048, true); + const effectDotScreen = new DotScreenPass(new THREE.Vector2(0, 0), 0.5, 0.8); + + const effectHBlur = new ShaderPass(HorizontalBlurShader); + const effectVBlur = new ShaderPass(VerticalBlurShader); + effectHBlur.uniforms['h'].value = 2 / (width / 2); + effectVBlur.uniforms['v'].value = 2 / (height / 2); + + const effectColorify1 = new ShaderPass(ColorifyShader); + const effectColorify2 = new ShaderPass(ColorifyShader); + effectColorify1.uniforms['color'] = new THREE.Uniform(new THREE.Color(1, 0.8, 0.8)); + effectColorify2.uniforms['color'] = new THREE.Uniform(new THREE.Color(1, 0.75, 0.5)); + + const clearMask = new ClearMaskPass(); + const renderMask = new MaskPass(sceneModel, cameraPerspective); + const renderMaskInverse = new MaskPass(sceneModel, cameraPerspective); + + renderMaskInverse.inverse = true; + + // + + const rtParameters = { + stencilBuffer: true, + }; + + const rtWidth = width / 2; + const rtHeight = height / 2; + + // + + const renderBackground = new RenderPass(sceneBG, cameraOrtho); + const renderModel = new RenderPass(sceneModel, cameraPerspective); + + renderModel.clear = false; + + composerScene = new EffectComposer(renderer, new THREE.WebGLRenderTarget(rtWidth * 2, rtHeight * 2, rtParameters)); + + composerScene.addPass(renderBackground); + composerScene.addPass(renderModel); + composerScene.addPass(renderMaskInverse); + composerScene.addPass(effectHBlur); + composerScene.addPass(effectVBlur); + composerScene.addPass(clearMask); + + // + + renderScene = new TexturePass(composerScene.renderTarget2.texture); + + // + + composer1 = new EffectComposer(renderer, new THREE.WebGLRenderTarget(rtWidth, rtHeight, rtParameters)); + + composer1.addPass(renderScene); + composer1.addPass(gammaCorrection); + composer1.addPass(effectFilmBW); + composer1.addPass(effectVignette); + + // + + composer2 = new EffectComposer(renderer, new THREE.WebGLRenderTarget(rtWidth, rtHeight, rtParameters)); + + composer2.addPass(renderScene); + composer2.addPass(gammaCorrection); + composer2.addPass(effectDotScreen); + composer2.addPass(renderMask); + composer2.addPass(effectColorify1); + composer2.addPass(clearMask); + composer2.addPass(renderMaskInverse); + composer2.addPass(effectColorify2); + composer2.addPass(clearMask); + composer2.addPass(effectVignette); + + // + + composer3 = new EffectComposer(renderer, new THREE.WebGLRenderTarget(rtWidth, rtHeight, rtParameters)); + + composer3.addPass(renderScene); + composer3.addPass(gammaCorrection); + composer3.addPass(effectSepia); + composer3.addPass(effectFilm); + composer3.addPass(effectVignette); + + // + + composer4 = new EffectComposer(renderer, new THREE.WebGLRenderTarget(rtWidth, rtHeight, rtParameters)); + + composer4.addPass(renderScene); + composer4.addPass(gammaCorrection); + composer4.addPass(effectBloom); + composer4.addPass(effectFilm); + composer4.addPass(effectBleach); + composer4.addPass(effectVignette); + + renderScene.uniforms['tDiffuse'].value = composerScene.renderTarget2.texture; + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + halfWidth = window.innerWidth / 2; + halfHeight = window.innerHeight / 2; + + cameraPerspective.aspect = window.innerWidth / window.innerHeight; + cameraPerspective.updateProjectionMatrix(); + + cameraOrtho.left = -halfWidth; + cameraOrtho.right = halfWidth; + cameraOrtho.top = halfHeight; + cameraOrtho.bottom = -halfHeight; + + cameraOrtho.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + + composerScene.setSize(halfWidth * 2, halfHeight * 2); + + composer1.setSize(halfWidth, halfHeight); + composer2.setSize(halfWidth, halfHeight); + composer3.setSize(halfWidth, halfHeight); + composer4.setSize(halfWidth, halfHeight); + + renderScene.uniforms['tDiffuse'].value = composerScene.renderTarget2.texture; + + quadBG.scale.set(window.innerWidth, window.innerHeight, 1); + quadMask.scale.set(window.innerWidth / 2, window.innerHeight / 2, 1); +} + +function createMesh(geometry, scene, scale) { + const diffuseMap = new THREE.TextureLoader().load('models/gltf/LeePerrySmith/Map-COL.jpg'); + diffuseMap.colorSpace = THREE.SRGBColorSpace; + + const mat2 = new THREE.MeshPhongMaterial({ + color: 0xcbcbcb, + specular: 0x080808, + shininess: 20, + map: diffuseMap, + normalMap: new THREE.TextureLoader().load('models/gltf/LeePerrySmith/Infinite-Level_02_Tangent_SmoothUV.jpg'), + normalScale: new THREE.Vector2(0.75, 0.75), + }); + + mesh = new THREE.Mesh(geometry, mat2); + mesh.position.set(0, -50, 0); + mesh.scale.set(scale, scale, scale); + + scene.add(mesh); +} + +// + +function animate() { + requestAnimationFrame(animate); + + stats.begin(); + render(); + stats.end(); +} + +function render() { + const time = Date.now() * 0.0004; + + if (mesh) mesh.rotation.y = -time; + + renderer.setViewport(0, 0, halfWidth, halfHeight); + composerScene.render(delta); + + renderer.setViewport(0, 0, halfWidth, halfHeight); + composer1.render(delta); + + renderer.setViewport(halfWidth, 0, halfWidth, halfHeight); + composer2.render(delta); + + renderer.setViewport(0, halfHeight, halfWidth, halfHeight); + composer3.render(delta); + + renderer.setViewport(halfWidth, halfHeight, halfWidth, halfHeight); + composer4.render(delta); +} diff --git a/examples-testing/examples/webgl_postprocessing_afterimage.ts b/examples-testing/examples/webgl_postprocessing_afterimage.ts new file mode 100644 index 000000000..2477c5002 --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_afterimage.ts @@ -0,0 +1,86 @@ +import * as THREE from 'three'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { AfterimagePass } from 'three/addons/postprocessing/AfterimagePass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; + +let camera, scene, renderer, composer; +let mesh; + +let afterimagePass; + +const params = { + enable: true, +}; + +init(); +createGUI(); +animate(); + +function init() { + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.z = 400; + + scene = new THREE.Scene(); + scene.fog = new THREE.Fog(0x000000, 1, 1000); + + const geometry = new THREE.BoxGeometry(150, 150, 150, 2, 2, 2); + const material = new THREE.MeshNormalMaterial(); + mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // postprocessing + + composer = new EffectComposer(renderer); + composer.addPass(new RenderPass(scene, camera)); + + afterimagePass = new AfterimagePass(); + composer.addPass(afterimagePass); + + const outputPass = new OutputPass(); + composer.addPass(outputPass); + + window.addEventListener('resize', onWindowResize); + + if (typeof TESTING !== 'undefined') { + for (let i = 0; i < 45; i++) { + render(); + } + } +} + +function createGUI() { + const gui = new GUI({ title: 'Damp setting' }); + gui.add(afterimagePass.uniforms['damp'], 'value', 0, 1).step(0.001); + gui.add(params, 'enable'); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + composer.setSize(window.innerWidth, window.innerHeight); +} + +function render() { + mesh.rotation.x += 0.005; + mesh.rotation.y += 0.01; + + afterimagePass.enabled = params.enable; + + composer.render(); +} + +function animate() { + requestAnimationFrame(animate); + render(); +} diff --git a/examples-testing/examples/webgl_postprocessing_backgrounds.ts b/examples-testing/examples/webgl_postprocessing_backgrounds.ts new file mode 100644 index 000000000..0bfb65506 --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_backgrounds.ts @@ -0,0 +1,216 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { TexturePass } from 'three/addons/postprocessing/TexturePass.js'; +import { CubeTexturePass } from 'three/addons/postprocessing/CubeTexturePass.js'; +import { ClearPass } from 'three/addons/postprocessing/ClearPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +let scene, renderer, composer; +let clearPass, texturePass, renderPass; +let cameraP, cubeTexturePassP; +let gui, stats; + +const params = { + clearPass: true, + clearColor: 'white', + clearAlpha: 1.0, + + texturePass: true, + texturePassOpacity: 1.0, + + cubeTexturePass: true, + cubeTexturePassOpacity: 1.0, + + renderPass: true, +}; + +init(); +animate(); + +clearGui(); + +function clearGui() { + if (gui) gui.destroy(); + + gui = new GUI(); + + gui.add(params, 'clearPass'); + gui.add(params, 'clearColor', ['black', 'white', 'blue', 'green', 'red']); + gui.add(params, 'clearAlpha', 0, 1); + + gui.add(params, 'texturePass'); + gui.add(params, 'texturePassOpacity', 0, 1); + + gui.add(params, 'cubeTexturePass'); + gui.add(params, 'cubeTexturePassOpacity', 0, 1); + + gui.add(params, 'renderPass'); + + gui.open(); +} + +function init() { + const container = document.getElementById('container'); + + const width = window.innerWidth || 1; + const height = window.innerHeight || 1; + const aspect = width / height; + const devicePixelRatio = window.devicePixelRatio || 1; + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(devicePixelRatio); + renderer.setSize(width, height); + document.body.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + cameraP = new THREE.PerspectiveCamera(65, aspect, 1, 10); + cameraP.position.z = 7; + + scene = new THREE.Scene(); + + const group = new THREE.Group(); + scene.add(group); + + const light = new THREE.PointLight(0xefffef, 500); + light.position.z = 10; + light.position.y = -10; + light.position.x = -10; + scene.add(light); + + const light2 = new THREE.PointLight(0xffefef, 500); + light2.position.z = 10; + light2.position.x = -10; + light2.position.y = 10; + scene.add(light2); + + const light3 = new THREE.PointLight(0xefefff, 500); + light3.position.z = 10; + light3.position.x = 10; + light3.position.y = -10; + scene.add(light3); + + const geometry = new THREE.SphereGeometry(1, 48, 24); + + const material = new THREE.MeshStandardMaterial(); + material.roughness = 0.5 * Math.random() + 0.25; + material.metalness = 0; + material.color.setHSL(Math.random(), 1.0, 0.3); + + const mesh = new THREE.Mesh(geometry, material); + group.add(mesh); + + // postprocessing + + const genCubeUrls = function (prefix, postfix) { + return [ + prefix + 'px' + postfix, + prefix + 'nx' + postfix, + prefix + 'py' + postfix, + prefix + 'ny' + postfix, + prefix + 'pz' + postfix, + prefix + 'nz' + postfix, + ]; + }; + + composer = new EffectComposer(renderer); + + clearPass = new ClearPass(params.clearColor, params.clearAlpha); + composer.addPass(clearPass); + + texturePass = new TexturePass(); + composer.addPass(texturePass); + + const textureLoader = new THREE.TextureLoader(); + textureLoader.load('textures/hardwood2_diffuse.jpg', function (map) { + map.colorSpace = THREE.SRGBColorSpace; + texturePass.map = map; + }); + + cubeTexturePassP = null; + + const ldrUrls = genCubeUrls('textures/cube/pisa/', '.png'); + new THREE.CubeTextureLoader().load(ldrUrls, function (ldrCubeMap) { + cubeTexturePassP = new CubeTexturePass(cameraP, ldrCubeMap); + composer.insertPass(cubeTexturePassP, 2); + }); + + renderPass = new RenderPass(scene, cameraP); + renderPass.clear = false; + composer.addPass(renderPass); + + const outputPass = new OutputPass(); + composer.addPass(outputPass); + + const controls = new OrbitControls(cameraP, renderer.domElement); + controls.enableZoom = false; + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + const width = window.innerWidth; + const height = window.innerHeight; + const aspect = width / height; + + cameraP.aspect = aspect; + cameraP.updateProjectionMatrix(); + + renderer.setSize(width, height); + composer.setSize(width, height); +} + +function animate() { + requestAnimationFrame(animate); + + stats.begin(); + + cameraP.updateMatrixWorld(true); + + let newColor = clearPass.clearColor; + + switch (params.clearColor) { + case 'blue': + newColor = 0x0000ff; + break; + case 'red': + newColor = 0xff0000; + break; + case 'green': + newColor = 0x00ff00; + break; + case 'white': + newColor = 0xffffff; + break; + case 'black': + newColor = 0x000000; + break; + } + + clearPass.enabled = params.clearPass; + clearPass.clearColor = newColor; + clearPass.clearAlpha = params.clearAlpha; + + texturePass.enabled = params.texturePass; + texturePass.opacity = params.texturePassOpacity; + + if (cubeTexturePassP !== null) { + cubeTexturePassP.enabled = params.cubeTexturePass; + cubeTexturePassP.opacity = params.cubeTexturePassOpacity; + } + + renderPass.enabled = params.renderPass; + + composer.render(); + + stats.end(); +} diff --git a/examples-testing/examples/webgl_postprocessing_crossfade.ts b/examples-testing/examples/webgl_postprocessing_crossfade.ts new file mode 100644 index 000000000..d3203e35b --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_crossfade.ts @@ -0,0 +1,302 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import TWEEN from 'three/addons/libs/tween.module.js'; + +let container, stats; +let renderer; +let transition; + +const transitionParams = { + useTexture: true, + transition: 0, + texture: 5, + cycle: true, + animate: true, + threshold: 0.3, +}; + +const clock = new THREE.Clock(); + +init(); +animate(); + +function init() { + initGUI(); + + container = document.getElementById('container'); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + const geometryA = new THREE.BoxGeometry(2, 2, 2); + const geometryB = new THREE.IcosahedronGeometry(1, 1); + const sceneA = new FXScene(geometryA, new THREE.Vector3(0, -0.4, 0), 0xffffff); + const sceneB = new FXScene(geometryB, new THREE.Vector3(0, 0.2, 0.1), 0x000000); + + transition = new Transition(sceneA, sceneB); +} + +function animate() { + requestAnimationFrame(animate); + + render(); + stats.update(); +} + +function initGUI() { + const gui = new GUI(); + + gui.add(transitionParams, 'animate'); + gui.add(transitionParams, 'transition', 0, 1, 0.01).listen(); + + gui.add(transitionParams, 'useTexture').onChange(function (value) { + transition.useTexture(value); + }); + + gui.add(transitionParams, 'texture', { Perlin: 0, Squares: 1, Cells: 2, Distort: 3, Gradient: 4, Radial: 5 }) + .onChange(function (value) { + transition.setTexture(value); + }) + .listen(); + + gui.add(transitionParams, 'cycle'); + + gui.add(transitionParams, 'threshold', 0, 1, 0.01).onChange(function (value) { + transition.setTextureThreshold(value); + }); +} + +function render() { + transition.render(clock.getDelta()); +} + +function generateInstancedMesh(geometry, material, count) { + const mesh = new THREE.InstancedMesh(geometry, material, count); + + const dummy = new THREE.Object3D(); + const color = new THREE.Color(); + + for (let i = 0; i < count; i++) { + dummy.position.x = Math.random() * 100 - 50; + dummy.position.y = Math.random() * 60 - 30; + dummy.position.z = Math.random() * 80 - 40; + + dummy.rotation.x = Math.random() * 2 * Math.PI; + dummy.rotation.y = Math.random() * 2 * Math.PI; + dummy.rotation.z = Math.random() * 2 * Math.PI; + + dummy.scale.x = Math.random() * 2 + 1; + + if (geometry.type === 'BoxGeometry') { + dummy.scale.y = Math.random() * 2 + 1; + dummy.scale.z = Math.random() * 2 + 1; + } else { + dummy.scale.y = dummy.scale.x; + dummy.scale.z = dummy.scale.x; + } + + dummy.updateMatrix(); + + mesh.setMatrixAt(i, dummy.matrix); + mesh.setColorAt(i, color.setScalar(0.1 + 0.9 * Math.random())); + } + + return mesh; +} + +function FXScene(geometry, rotationSpeed, clearColor) { + this.clearColor = clearColor; + + const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.z = 20; + + // Setup scene + const scene = new THREE.Scene(); + scene.add(new THREE.AmbientLight(0xaaaaaa, 3)); + + const light = new THREE.DirectionalLight(0xffffff, 3); + light.position.set(0, 1, 4); + scene.add(light); + + this.rotationSpeed = rotationSpeed; + + const color = geometry.type === 'BoxGeometry' ? 0x0000ff : 0xff0000; + const material = new THREE.MeshPhongMaterial({ color: color, flatShading: true }); + const mesh = generateInstancedMesh(geometry, material, 500); + scene.add(mesh); + + this.fbo = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, { type: THREE.HalfFloatType }); + + this.render = function (delta, rtt) { + mesh.rotation.x += delta * this.rotationSpeed.x; + mesh.rotation.y += delta * this.rotationSpeed.y; + mesh.rotation.z += delta * this.rotationSpeed.z; + + renderer.setClearColor(this.clearColor); + + if (rtt) { + renderer.setRenderTarget(this.fbo); + renderer.clear(); + renderer.render(scene, camera); + } else { + renderer.setRenderTarget(null); + renderer.render(scene, camera); + } + }; +} + +function Transition(sceneA, sceneB) { + const scene = new THREE.Scene(); + + const width = window.innerWidth; + const height = window.innerHeight; + + const camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, -10, 10); + + const textures = []; + + const loader = new THREE.TextureLoader(); + + for (let i = 0; i < 6; i++) { + textures[i] = loader.load('textures/transition/transition' + (i + 1) + '.png'); + } + + const material = new THREE.ShaderMaterial({ + uniforms: { + tDiffuse1: { + value: null, + }, + tDiffuse2: { + value: null, + }, + mixRatio: { + value: 0.0, + }, + threshold: { + value: 0.1, + }, + useTexture: { + value: 1, + }, + tMixTexture: { + value: textures[0], + }, + }, + vertexShader: [ + 'varying vec2 vUv;', + + 'void main() {', + + 'vUv = vec2( uv.x, uv.y );', + 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', + + '}', + ].join('\n'), + fragmentShader: [ + 'uniform float mixRatio;', + + 'uniform sampler2D tDiffuse1;', + 'uniform sampler2D tDiffuse2;', + 'uniform sampler2D tMixTexture;', + + 'uniform int useTexture;', + 'uniform float threshold;', + + 'varying vec2 vUv;', + + 'void main() {', + + ' vec4 texel1 = texture2D( tDiffuse1, vUv );', + ' vec4 texel2 = texture2D( tDiffuse2, vUv );', + + ' if (useTexture==1) {', + + ' vec4 transitionTexel = texture2D( tMixTexture, vUv );', + ' float r = mixRatio * (1.0 + threshold * 2.0) - threshold;', + ' float mixf=clamp((transitionTexel.r - r)*(1.0/threshold), 0.0, 1.0);', + + ' gl_FragColor = mix( texel1, texel2, mixf );', + + ' } else {', + + ' gl_FragColor = mix( texel2, texel1, mixRatio );', + + ' }', + + ' #include ', + ' #include ', + + '}', + ].join('\n'), + }); + + const geometry = new THREE.PlaneGeometry(window.innerWidth, window.innerHeight); + const mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + material.uniforms.tDiffuse1.value = sceneA.fbo.texture; + material.uniforms.tDiffuse2.value = sceneB.fbo.texture; + + new TWEEN.Tween(transitionParams).to({ transition: 1 }, 1500).repeat(Infinity).delay(2000).yoyo(true).start(); + + this.needsTextureChange = false; + + this.setTextureThreshold = function (value) { + material.uniforms.threshold.value = value; + }; + + this.useTexture = function (value) { + material.uniforms.useTexture.value = value ? 1 : 0; + }; + + this.setTexture = function (i) { + material.uniforms.tMixTexture.value = textures[i]; + }; + + this.render = function (delta) { + // Transition animation + if (transitionParams.animate) { + TWEEN.update(); + + // Change the current alpha texture after each transition + if (transitionParams.cycle) { + if (transitionParams.transition == 0 || transitionParams.transition == 1) { + if (this.needsTextureChange) { + transitionParams.texture = (transitionParams.texture + 1) % textures.length; + material.uniforms.tMixTexture.value = textures[transitionParams.texture]; + this.needsTextureChange = false; + } + } else { + this.needsTextureChange = true; + } + } else { + this.needsTextureChange = true; + } + } + + material.uniforms.mixRatio.value = transitionParams.transition; + + // Prevent render both scenes when it's not necessary + if (transitionParams.transition == 0) { + sceneB.render(delta, false); + } else if (transitionParams.transition == 1) { + sceneA.render(delta, false); + } else { + // When 0 0) { + const selectedObject = intersects[0].object; + addSelectedObject(selectedObject); + outlinePass.selectedObjects = selectedObjects; + } else { + // outlinePass.selectedObjects = []; + } + } +} + +function onWindowResize() { + const width = window.innerWidth; + const height = window.innerHeight; + + camera.aspect = width / height; + camera.updateProjectionMatrix(); + + renderer.setSize(width, height); + composer.setSize(width, height); + + effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + stats.begin(); + + const timer = performance.now(); + + if (params.rotate) { + group.rotation.y = timer * 0.0001; + } + + controls.update(); + + composer.render(); + + stats.end(); +} diff --git a/examples-testing/examples/webgl_postprocessing_pixel.ts b/examples-testing/examples/webgl_postprocessing_pixel.ts new file mode 100644 index 000000000..fa763090a --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_pixel.ts @@ -0,0 +1,230 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPixelatedPass } from 'three/addons/postprocessing/RenderPixelatedPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let camera, scene, renderer, composer, crystalMesh, clock; +let gui, params; + +init(); +animate(); + +function init() { + const aspectRatio = window.innerWidth / window.innerHeight; + + camera = new THREE.OrthographicCamera(-aspectRatio, aspectRatio, 1, -1, 0.1, 10); + camera.position.y = 2 * Math.tan(Math.PI / 6); + camera.position.z = 2; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x151729); + + clock = new THREE.Clock(); + + renderer = new THREE.WebGLRenderer(); + renderer.shadowMap.enabled = true; + //renderer.setPixelRatio( window.devicePixelRatio ); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + composer = new EffectComposer(renderer); + const renderPixelatedPass = new RenderPixelatedPass(6, scene, camera); + composer.addPass(renderPixelatedPass); + + const outputPass = new OutputPass(); + composer.addPass(outputPass); + + window.addEventListener('resize', onWindowResize); + + const controls = new OrbitControls(camera, renderer.domElement); + controls.maxZoom = 2; + + // gui + + gui = new GUI(); + params = { pixelSize: 6, normalEdgeStrength: 0.3, depthEdgeStrength: 0.4, pixelAlignedPanning: true }; + gui.add(params, 'pixelSize') + .min(1) + .max(16) + .step(1) + .onChange(() => { + renderPixelatedPass.setPixelSize(params.pixelSize); + }); + gui.add(renderPixelatedPass, 'normalEdgeStrength').min(0).max(2).step(0.05); + gui.add(renderPixelatedPass, 'depthEdgeStrength').min(0).max(1).step(0.05); + gui.add(params, 'pixelAlignedPanning'); + + // textures + + const loader = new THREE.TextureLoader(); + const texChecker = pixelTexture(loader.load('textures/checker.png')); + const texChecker2 = pixelTexture(loader.load('textures/checker.png')); + texChecker.repeat.set(3, 3); + texChecker2.repeat.set(1.5, 1.5); + + // meshes + + const boxMaterial = new THREE.MeshPhongMaterial({ map: texChecker2 }); + + function addBox(boxSideLength, x, z, rotation) { + const mesh = new THREE.Mesh(new THREE.BoxGeometry(boxSideLength, boxSideLength, boxSideLength), boxMaterial); + mesh.castShadow = true; + mesh.receiveShadow = true; + mesh.rotation.y = rotation; + mesh.position.y = boxSideLength / 2; + mesh.position.set(x, boxSideLength / 2 + 0.0001, z); + scene.add(mesh); + return mesh; + } + + addBox(0.4, 0, 0, Math.PI / 4); + addBox(0.5, -0.5, -0.5, Math.PI / 4); + + const planeSideLength = 2; + const planeMesh = new THREE.Mesh( + new THREE.PlaneGeometry(planeSideLength, planeSideLength), + new THREE.MeshPhongMaterial({ map: texChecker }), + ); + planeMesh.receiveShadow = true; + planeMesh.rotation.x = -Math.PI / 2; + scene.add(planeMesh); + + const radius = 0.2; + const geometry = new THREE.IcosahedronGeometry(radius); + crystalMesh = new THREE.Mesh( + geometry, + new THREE.MeshPhongMaterial({ + color: 0x68b7e9, + emissive: 0x4f7e8b, + shininess: 10, + specular: 0xffffff, + }), + ); + crystalMesh.receiveShadow = true; + crystalMesh.castShadow = true; + scene.add(crystalMesh); + + // lights + + scene.add(new THREE.AmbientLight(0x757f8e, 3)); + + const directionalLight = new THREE.DirectionalLight(0xfffecd, 1.5); + directionalLight.position.set(100, 100, 100); + directionalLight.castShadow = true; + directionalLight.shadow.mapSize.set(2048, 2048); + scene.add(directionalLight); + + const spotLight = new THREE.SpotLight(0xffc100, 10, 10, Math.PI / 16, 0.02, 2); + spotLight.position.set(2, 2, 0); + const target = spotLight.target; + scene.add(target); + target.position.set(0, 0, 0); + spotLight.castShadow = true; + scene.add(spotLight); +} + +function onWindowResize() { + const aspectRatio = window.innerWidth / window.innerHeight; + camera.left = -aspectRatio; + camera.right = aspectRatio; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + composer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + const t = clock.getElapsedTime(); + + crystalMesh.material.emissiveIntensity = Math.sin(t * 3) * 0.5 + 0.5; + crystalMesh.position.y = 0.7 + Math.sin(t * 2) * 0.05; + crystalMesh.rotation.y = stopGoEased(t, 2, 4) * 2 * Math.PI; + + const rendererSize = renderer.getSize(new THREE.Vector2()); + const aspectRatio = rendererSize.x / rendererSize.y; + if (params['pixelAlignedPanning']) { + pixelAlignFrustum( + camera, + aspectRatio, + Math.floor(rendererSize.x / params['pixelSize']), + Math.floor(rendererSize.y / params['pixelSize']), + ); + } else if (camera.left != -aspectRatio || camera.top != 1.0) { + // Reset the Camera Frustum if it has been modified + camera.left = -aspectRatio; + camera.right = aspectRatio; + camera.top = 1.0; + camera.bottom = -1.0; + camera.updateProjectionMatrix(); + } + + composer.render(); +} + +// Helper functions + +function pixelTexture(texture) { + texture.minFilter = THREE.NearestFilter; + texture.magFilter = THREE.NearestFilter; + texture.generateMipmaps = false; + texture.wrapS = THREE.RepeatWrapping; + texture.wrapT = THREE.RepeatWrapping; + texture.colorSpace = THREE.SRGBColorSpace; + return texture; +} + +function easeInOutCubic(x) { + return x ** 2 * 3 - x ** 3 * 2; +} + +function linearStep(x, edge0, edge1) { + const w = edge1 - edge0; + const m = 1 / w; + const y0 = -m * edge0; + return THREE.MathUtils.clamp(y0 + m * x, 0, 1); +} + +function stopGoEased(x, downtime, period) { + const cycle = (x / period) | 0; + const tween = x - cycle * period; + const linStep = easeInOutCubic(linearStep(tween, downtime, period)); + return cycle + linStep; +} + +function pixelAlignFrustum(camera, aspectRatio, pixelsPerScreenWidth, pixelsPerScreenHeight) { + // 0. Get Pixel Grid Units + const worldScreenWidth = (camera.right - camera.left) / camera.zoom; + const worldScreenHeight = (camera.top - camera.bottom) / camera.zoom; + const pixelWidth = worldScreenWidth / pixelsPerScreenWidth; + const pixelHeight = worldScreenHeight / pixelsPerScreenHeight; + + // 1. Project the current camera position along its local rotation bases + const camPos = new THREE.Vector3(); + camera.getWorldPosition(camPos); + const camRot = new THREE.Quaternion(); + camera.getWorldQuaternion(camRot); + const camRight = new THREE.Vector3(1.0, 0.0, 0.0).applyQuaternion(camRot); + const camUp = new THREE.Vector3(0.0, 1.0, 0.0).applyQuaternion(camRot); + const camPosRight = camPos.dot(camRight); + const camPosUp = camPos.dot(camUp); + + // 2. Find how far along its position is along these bases in pixel units + const camPosRightPx = camPosRight / pixelWidth; + const camPosUpPx = camPosUp / pixelHeight; + + // 3. Find the fractional pixel units and convert to world units + const fractX = camPosRightPx - Math.round(camPosRightPx); + const fractY = camPosUpPx - Math.round(camPosUpPx); + + // 4. Add fractional world units to the left/right top/bottom to align with the pixel grid + camera.left = -aspectRatio - fractX * pixelWidth; + camera.right = aspectRatio - fractX * pixelWidth; + camera.top = 1.0 - fractY * pixelHeight; + camera.bottom = -1.0 - fractY * pixelHeight; + camera.updateProjectionMatrix(); +} diff --git a/examples-testing/examples/webgl_postprocessing_procedural.ts b/examples-testing/examples/webgl_postprocessing_procedural.ts new file mode 100644 index 000000000..860b1c4d7 --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_procedural.ts @@ -0,0 +1,81 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +let postCamera, postScene, renderer; +let postMaterial, noiseRandom1DMaterial, noiseRandom2DMaterial, noiseRandom3DMaterial, postQuad; +let stats; + +const params = { procedure: 'noiseRandom3D' }; + +init(); +animate(); +initGui(); + +// Init gui +function initGui() { + const gui = new GUI(); + gui.add(params, 'procedure', ['noiseRandom1D', 'noiseRandom2D', 'noiseRandom3D']); +} + +function init() { + const container = document.getElementById('container'); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + // Setup post processing stage + postCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); + noiseRandom1DMaterial = new THREE.ShaderMaterial({ + vertexShader: document.querySelector('#procedural-vert').textContent.trim(), + fragmentShader: document.querySelector('#noiseRandom1D-frag').textContent.trim(), + }); + noiseRandom2DMaterial = new THREE.ShaderMaterial({ + vertexShader: document.querySelector('#procedural-vert').textContent.trim(), + fragmentShader: document.querySelector('#noiseRandom2D-frag').textContent.trim(), + }); + noiseRandom3DMaterial = new THREE.ShaderMaterial({ + vertexShader: document.querySelector('#procedural-vert').textContent.trim(), + fragmentShader: document.querySelector('#noiseRandom3D-frag').textContent.trim(), + }); + postMaterial = noiseRandom3DMaterial; + const postPlane = new THREE.PlaneGeometry(2, 2); + postQuad = new THREE.Mesh(postPlane, postMaterial); + postScene = new THREE.Scene(); + postScene.add(postQuad); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + switch (params.procedure) { + case 'noiseRandom1D': + postMaterial = noiseRandom1DMaterial; + break; + case 'noiseRandom2D': + postMaterial = noiseRandom2DMaterial; + break; + case 'noiseRandom3D': + postMaterial = noiseRandom3DMaterial; + break; + } + + postQuad.material = postMaterial; + + // render post FX + renderer.render(postScene, postCamera); + + stats.update(); +} diff --git a/examples-testing/examples/webgl_postprocessing_rgb_halftone.ts b/examples-testing/examples/webgl_postprocessing_rgb_halftone.ts new file mode 100644 index 000000000..e81303e9f --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_rgb_halftone.ts @@ -0,0 +1,169 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { HalftonePass } from 'three/addons/postprocessing/HalftonePass.js'; + +let renderer, clock, camera, stats; + +const rotationSpeed = Math.PI / 64; + +let composer, group; + +init(); +animate(); + +function init() { + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + + clock = new THREE.Clock(); + + camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.z = 12; + + stats = new Stats(); + + document.body.appendChild(renderer.domElement); + document.body.appendChild(stats.dom); + + // camera controls + const controls = new OrbitControls(camera, renderer.domElement); + controls.target.set(0, 0, 0); + controls.update(); + + // scene + + const scene = new THREE.Scene(); + scene.background = new THREE.Color(0x444444); + + group = new THREE.Group(); + const floor = new THREE.Mesh(new THREE.BoxGeometry(100, 1, 100), new THREE.MeshPhongMaterial({})); + floor.position.y = -10; + const light = new THREE.PointLight(0xffffff, 250); + light.position.y = 2; + group.add(floor, light); + scene.add(group); + + const mat = new THREE.ShaderMaterial({ + uniforms: {}, + + vertexShader: [ + 'varying vec2 vUV;', + 'varying vec3 vNormal;', + + 'void main() {', + + 'vUV = uv;', + 'vNormal = vec3( normal );', + 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', + + '}', + ].join('\n'), + + fragmentShader: [ + 'varying vec2 vUV;', + 'varying vec3 vNormal;', + + 'void main() {', + + 'vec4 c = vec4( abs( vNormal ) + vec3( vUV, 0.0 ), 0.0 );', + 'gl_FragColor = c;', + + '}', + ].join('\n'), + }); + + for (let i = 0; i < 50; ++i) { + // fill scene with coloured cubes + const mesh = new THREE.Mesh(new THREE.BoxGeometry(2, 2, 2), mat); + mesh.position.set(Math.random() * 16 - 8, Math.random() * 16 - 8, Math.random() * 16 - 8); + mesh.rotation.set(Math.random() * Math.PI * 2, Math.random() * Math.PI * 2, Math.random() * Math.PI * 2); + group.add(mesh); + } + + // post-processing + + composer = new EffectComposer(renderer); + const renderPass = new RenderPass(scene, camera); + const params = { + shape: 1, + radius: 4, + rotateR: Math.PI / 12, + rotateB: (Math.PI / 12) * 2, + rotateG: (Math.PI / 12) * 3, + scatter: 0, + blending: 1, + blendingMode: 1, + greyscale: false, + disable: false, + }; + const halftonePass = new HalftonePass(window.innerWidth, window.innerHeight, params); + composer.addPass(renderPass); + composer.addPass(halftonePass); + + window.onresize = function () { + // resize composer + renderer.setSize(window.innerWidth, window.innerHeight); + composer.setSize(window.innerWidth, window.innerHeight); + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + }; + + // GUI + + const controller = { + radius: halftonePass.uniforms['radius'].value, + rotateR: halftonePass.uniforms['rotateR'].value / (Math.PI / 180), + rotateG: halftonePass.uniforms['rotateG'].value / (Math.PI / 180), + rotateB: halftonePass.uniforms['rotateB'].value / (Math.PI / 180), + scatter: halftonePass.uniforms['scatter'].value, + shape: halftonePass.uniforms['shape'].value, + greyscale: halftonePass.uniforms['greyscale'].value, + blending: halftonePass.uniforms['blending'].value, + blendingMode: halftonePass.uniforms['blendingMode'].value, + disable: halftonePass.uniforms['disable'].value, + }; + + function onGUIChange() { + // update uniforms + halftonePass.uniforms['radius'].value = controller.radius; + halftonePass.uniforms['rotateR'].value = controller.rotateR * (Math.PI / 180); + halftonePass.uniforms['rotateG'].value = controller.rotateG * (Math.PI / 180); + halftonePass.uniforms['rotateB'].value = controller.rotateB * (Math.PI / 180); + halftonePass.uniforms['scatter'].value = controller.scatter; + halftonePass.uniforms['shape'].value = controller.shape; + halftonePass.uniforms['greyscale'].value = controller.greyscale; + halftonePass.uniforms['blending'].value = controller.blending; + halftonePass.uniforms['blendingMode'].value = controller.blendingMode; + halftonePass.uniforms['disable'].value = controller.disable; + } + + const gui = new GUI(); + gui.add(controller, 'shape', { Dot: 1, Ellipse: 2, Line: 3, Square: 4 }).onChange(onGUIChange); + gui.add(controller, 'radius', 1, 25).onChange(onGUIChange); + gui.add(controller, 'rotateR', 0, 90).onChange(onGUIChange); + gui.add(controller, 'rotateG', 0, 90).onChange(onGUIChange); + gui.add(controller, 'rotateB', 0, 90).onChange(onGUIChange); + gui.add(controller, 'scatter', 0, 1, 0.01).onChange(onGUIChange); + gui.add(controller, 'greyscale').onChange(onGUIChange); + gui.add(controller, 'blending', 0, 1, 0.01).onChange(onGUIChange); + gui.add(controller, 'blendingMode', { Linear: 1, Multiply: 2, Add: 3, Lighter: 4, Darker: 5 }).onChange( + onGUIChange, + ); + gui.add(controller, 'disable').onChange(onGUIChange); +} + +function animate() { + requestAnimationFrame(animate); + + const delta = clock.getDelta(); + stats.update(); + group.rotation.y += delta * rotationSpeed; + composer.render(delta); +} diff --git a/examples-testing/examples/webgl_postprocessing_sao.ts b/examples-testing/examples/webgl_postprocessing_sao.ts new file mode 100644 index 000000000..f8ae1e4f9 --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_sao.ts @@ -0,0 +1,142 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { SAOPass } from 'three/addons/postprocessing/SAOPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; + +let container, stats; +let camera, scene, renderer; +let composer, renderPass, saoPass; +let group; + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + const width = window.innerWidth || 1; + const height = window.innerHeight || 1; + const devicePixelRatio = window.devicePixelRatio || 1; + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setClearColor(0x000000); + renderer.setPixelRatio(devicePixelRatio); + renderer.setSize(width, height); + document.body.appendChild(renderer.domElement); + + camera = new THREE.PerspectiveCamera(65, width / height, 3, 10); + camera.position.z = 7; + + scene = new THREE.Scene(); + + group = new THREE.Object3D(); + scene.add(group); + + const light = new THREE.PointLight(0xefffef, 500); + light.position.z = 10; + light.position.y = -10; + light.position.x = -10; + scene.add(light); + + const light2 = new THREE.PointLight(0xffefef, 500); + light2.position.z = 10; + light2.position.x = -10; + light2.position.y = 10; + scene.add(light2); + + const light3 = new THREE.PointLight(0xefefff, 500); + light3.position.z = 10; + light3.position.x = 10; + light3.position.y = -10; + scene.add(light3); + + const light4 = new THREE.AmbientLight(0xffffff, 0.2); + scene.add(light4); + + const geometry = new THREE.SphereGeometry(3, 48, 24); + + for (let i = 0; i < 120; i++) { + const material = new THREE.MeshStandardMaterial(); + material.roughness = 0.5 * Math.random() + 0.25; + material.metalness = 0; + material.color.setHSL(Math.random(), 1.0, 0.3); + + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = Math.random() * 4 - 2; + mesh.position.y = Math.random() * 4 - 2; + mesh.position.z = Math.random() * 4 - 2; + mesh.rotation.x = Math.random(); + mesh.rotation.y = Math.random(); + mesh.rotation.z = Math.random(); + + mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 0.2 + 0.05; + group.add(mesh); + } + + stats = new Stats(); + container.appendChild(stats.dom); + + composer = new EffectComposer(renderer); + renderPass = new RenderPass(scene, camera); + composer.addPass(renderPass); + saoPass = new SAOPass(scene, camera, false, true); + composer.addPass(saoPass); + const outputPass = new OutputPass(); + composer.addPass(outputPass); + + // Init gui + const gui = new GUI(); + gui.add(saoPass.params, 'output', { + Beauty: SAOPass.OUTPUT.Beauty, + 'Beauty+SAO': SAOPass.OUTPUT.Default, + SAO: SAOPass.OUTPUT.SAO, + Depth: SAOPass.OUTPUT.Depth, + Normal: SAOPass.OUTPUT.Normal, + }).onChange(function (value) { + saoPass.params.output = parseInt(value); + }); + gui.add(saoPass.params, 'saoBias', -1, 1); + gui.add(saoPass.params, 'saoIntensity', 0, 1); + gui.add(saoPass.params, 'saoScale', 0, 10); + gui.add(saoPass.params, 'saoKernelRadius', 1, 100); + gui.add(saoPass.params, 'saoMinResolution', 0, 1); + gui.add(saoPass.params, 'saoBlur'); + gui.add(saoPass.params, 'saoBlurRadius', 0, 200); + gui.add(saoPass.params, 'saoBlurStdDev', 0.5, 150); + gui.add(saoPass.params, 'saoBlurDepthCutoff', 0.0, 0.1); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + const width = window.innerWidth || 1; + const height = window.innerHeight || 1; + + camera.aspect = width / height; + camera.updateProjectionMatrix(); + renderer.setSize(width, height); + + composer.setSize(width, height); +} + +function animate() { + requestAnimationFrame(animate); + + stats.begin(); + render(); + stats.end(); +} + +function render() { + const timer = performance.now(); + group.rotation.x = timer * 0.0002; + group.rotation.y = timer * 0.0001; + + composer.render(); +} diff --git a/examples-testing/examples/webgl_postprocessing_smaa.ts b/examples-testing/examples/webgl_postprocessing_smaa.ts new file mode 100644 index 000000000..5eea466e3 --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_smaa.ts @@ -0,0 +1,93 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { SMAAPass } from 'three/addons/postprocessing/SMAAPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; + +let camera, scene, renderer, composer, stats; + +init(); +animate(); + +function init() { + const container = document.getElementById('container'); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.z = 300; + + scene = new THREE.Scene(); + + const geometry = new THREE.BoxGeometry(120, 120, 120); + const material1 = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }); + + const mesh1 = new THREE.Mesh(geometry, material1); + mesh1.position.x = -100; + scene.add(mesh1); + + const texture = new THREE.TextureLoader().load('textures/brick_diffuse.jpg'); + texture.anisotropy = 4; + texture.colorSpace = THREE.SRGBColorSpace; + + const material2 = new THREE.MeshBasicMaterial({ map: texture }); + + const mesh2 = new THREE.Mesh(geometry, material2); + mesh2.position.x = 100; + scene.add(mesh2); + + // postprocessing + + composer = new EffectComposer(renderer); + composer.addPass(new RenderPass(scene, camera)); + + const pass = new SMAAPass( + window.innerWidth * renderer.getPixelRatio(), + window.innerHeight * renderer.getPixelRatio(), + ); + composer.addPass(pass); + + const outputPass = new OutputPass(); + composer.addPass(outputPass); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + const width = window.innerWidth; + const height = window.innerHeight; + + camera.aspect = width / height; + camera.updateProjectionMatrix(); + + renderer.setSize(width, height); + composer.setSize(width, height); +} + +function animate() { + requestAnimationFrame(animate); + + stats.begin(); + + for (let i = 0; i < scene.children.length; i++) { + const child = scene.children[i]; + + child.rotation.x += 0.005; + child.rotation.y += 0.01; + } + + composer.render(); + + stats.end(); +} diff --git a/examples-testing/examples/webgl_postprocessing_sobel.ts b/examples-testing/examples/webgl_postprocessing_sobel.ts new file mode 100644 index 000000000..32663120a --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_sobel.ts @@ -0,0 +1,113 @@ +import * as THREE from 'three'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; + +import { LuminosityShader } from 'three/addons/shaders/LuminosityShader.js'; +import { SobelOperatorShader } from 'three/addons/shaders/SobelOperatorShader.js'; + +let camera, scene, renderer, composer; + +let effectSobel; + +const params = { + enable: true, +}; + +init(); +animate(); + +function init() { + // + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.set(0, 1, 3); + camera.lookAt(scene.position); + + // + + const geometry = new THREE.TorusKnotGeometry(1, 0.3, 256, 32); + const material = new THREE.MeshPhongMaterial({ color: 0xffff00 }); + + const mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // + + const ambientLight = new THREE.AmbientLight(0xe7e7e7); + scene.add(ambientLight); + + const pointLight = new THREE.PointLight(0xffffff, 20); + camera.add(pointLight); + scene.add(camera); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + // postprocessing + + composer = new EffectComposer(renderer); + const renderPass = new RenderPass(scene, camera); + composer.addPass(renderPass); + + // color to grayscale conversion + + const effectGrayScale = new ShaderPass(LuminosityShader); + composer.addPass(effectGrayScale); + + // you might want to use a gaussian blur filter before + // the next pass to improve the result of the Sobel operator + + // Sobel operator + + effectSobel = new ShaderPass(SobelOperatorShader); + effectSobel.uniforms['resolution'].value.x = window.innerWidth * window.devicePixelRatio; + effectSobel.uniforms['resolution'].value.y = window.innerHeight * window.devicePixelRatio; + composer.addPass(effectSobel); + + const controls = new OrbitControls(camera, renderer.domElement); + controls.enableZoom = false; + + // + + const gui = new GUI(); + + gui.add(params, 'enable'); + gui.open(); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + composer.setSize(window.innerWidth, window.innerHeight); + + effectSobel.uniforms['resolution'].value.x = window.innerWidth * window.devicePixelRatio; + effectSobel.uniforms['resolution'].value.y = window.innerHeight * window.devicePixelRatio; +} + +function animate() { + requestAnimationFrame(animate); + + if (params.enable === true) { + composer.render(); + } else { + renderer.render(scene, camera); + } +} diff --git a/examples-testing/examples/webgl_postprocessing_ssaa.ts b/examples-testing/examples/webgl_postprocessing_ssaa.ts new file mode 100644 index 000000000..bca3b4632 --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_ssaa.ts @@ -0,0 +1,208 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { SSAARenderPass } from 'three/addons/postprocessing/SSAARenderPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; + +let scene, renderer, composer; +let cameraP, ssaaRenderPassP; +let cameraO, ssaaRenderPassO; +let gui, stats; + +const params = { + sampleLevel: 4, + unbiased: true, + camera: 'perspective', + clearColor: 'black', + clearAlpha: 1.0, + viewOffsetX: 0, + autoRotate: true, +}; + +init(); +animate(); + +clearGui(); + +function clearGui() { + if (gui) gui.destroy(); + + gui = new GUI(); + + gui.add(params, 'unbiased'); + gui.add(params, 'sampleLevel', { + 'Level 0: 1 Sample': 0, + 'Level 1: 2 Samples': 1, + 'Level 2: 4 Samples': 2, + 'Level 3: 8 Samples': 3, + 'Level 4: 16 Samples': 4, + 'Level 5: 32 Samples': 5, + }); + gui.add(params, 'camera', ['perspective', 'orthographic']); + gui.add(params, 'clearColor', ['black', 'white', 'blue', 'green', 'red']); + gui.add(params, 'clearAlpha', 0, 1); + gui.add(params, 'viewOffsetX', -100, 100); + gui.add(params, 'autoRotate'); + + gui.open(); +} + +function init() { + const container = document.getElementById('container'); + + const width = window.innerWidth || 1; + const height = window.innerHeight || 1; + const aspect = width / height; + const devicePixelRatio = window.devicePixelRatio || 1; + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(devicePixelRatio); + renderer.setSize(width, height); + document.body.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + cameraP = new THREE.PerspectiveCamera(65, aspect, 3, 10); + cameraP.position.z = 7; + cameraP.setViewOffset(width, height, params.viewOffsetX, 0, width, height); + + cameraO = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 3, 10); + cameraO.position.z = 7; + + const fov = THREE.MathUtils.degToRad(cameraP.fov); + const hyperfocus = (cameraP.near + cameraP.far) / 2; + const _height = 2 * Math.tan(fov / 2) * hyperfocus; + cameraO.zoom = height / _height; + + scene = new THREE.Scene(); + + const group = new THREE.Group(); + scene.add(group); + + const light = new THREE.PointLight(0xefffef, 500); + light.position.z = 10; + light.position.y = -10; + light.position.x = -10; + scene.add(light); + + const light2 = new THREE.PointLight(0xffefef, 500); + light2.position.z = 10; + light2.position.x = -10; + light2.position.y = 10; + scene.add(light2); + + const light3 = new THREE.PointLight(0xefefff, 500); + light3.position.z = 10; + light3.position.x = 10; + light3.position.y = -10; + scene.add(light3); + + const light4 = new THREE.AmbientLight(0xffffff, 0.2); + scene.add(light4); + + const geometry = new THREE.SphereGeometry(3, 48, 24); + + for (let i = 0; i < 120; i++) { + const material = new THREE.MeshStandardMaterial(); + material.roughness = 0.5 * Math.random() + 0.25; + material.metalness = 0; + material.color.setHSL(Math.random(), 1.0, 0.3); + + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = Math.random() * 4 - 2; + mesh.position.y = Math.random() * 4 - 2; + mesh.position.z = Math.random() * 4 - 2; + mesh.rotation.x = Math.random(); + mesh.rotation.y = Math.random(); + mesh.rotation.z = Math.random(); + + mesh.scale.setScalar(Math.random() * 0.2 + 0.05); + group.add(mesh); + } + + // postprocessing + + composer = new EffectComposer(renderer); + composer.setPixelRatio(1); // ensure pixel ratio is always 1 for performance reasons + ssaaRenderPassP = new SSAARenderPass(scene, cameraP); + composer.addPass(ssaaRenderPassP); + ssaaRenderPassO = new SSAARenderPass(scene, cameraO); + composer.addPass(ssaaRenderPassO); + const outputPass = new OutputPass(); + composer.addPass(outputPass); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + const width = window.innerWidth; + const height = window.innerHeight; + const aspect = width / height; + + cameraP.aspect = aspect; + cameraP.setViewOffset(width, height, params.viewOffsetX, 0, width, height); + cameraO.updateProjectionMatrix(); + + cameraO.left = -height * aspect; + cameraO.right = height * aspect; + cameraO.top = height; + cameraO.bottom = -height; + cameraO.updateProjectionMatrix(); + + renderer.setSize(width, height); + composer.setSize(width, height); +} + +function animate() { + requestAnimationFrame(animate); + + stats.begin(); + + if (params.autoRotate) { + for (let i = 0; i < scene.children.length; i++) { + const child = scene.children[i]; + + child.rotation.x += 0.005; + child.rotation.y += 0.01; + } + } + + let newColor = ssaaRenderPassP.clearColor; + + switch (params.clearColor) { + case 'blue': + newColor = 0x0000ff; + break; + case 'red': + newColor = 0xff0000; + break; + case 'green': + newColor = 0x00ff00; + break; + case 'white': + newColor = 0xffffff; + break; + case 'black': + newColor = 0x000000; + break; + } + + ssaaRenderPassP.clearColor = ssaaRenderPassO.clearColor = newColor; + ssaaRenderPassP.clearAlpha = ssaaRenderPassO.clearAlpha = params.clearAlpha; + + ssaaRenderPassP.sampleLevel = ssaaRenderPassO.sampleLevel = params.sampleLevel; + ssaaRenderPassP.unbiased = ssaaRenderPassO.unbiased = params.unbiased; + + ssaaRenderPassP.enabled = params.camera === 'perspective'; + ssaaRenderPassO.enabled = params.camera === 'orthographic'; + + cameraP.view.offsetX = params.viewOffsetX; + + composer.render(); + + stats.end(); +} diff --git a/examples-testing/examples/webgl_postprocessing_ssao.ts b/examples-testing/examples/webgl_postprocessing_ssao.ts new file mode 100644 index 000000000..0f7f8e4ff --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_ssao.ts @@ -0,0 +1,117 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { SSAOPass } from 'three/addons/postprocessing/SSAOPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; + +let container, stats; +let camera, scene, renderer; +let composer; +let group; + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + renderer = new THREE.WebGLRenderer(); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 100, 700); + camera.position.z = 500; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xaaaaaa); + + scene.add(new THREE.DirectionalLight(0xffffff, 4)); + scene.add(new THREE.AmbientLight(0xffffff)); + + group = new THREE.Group(); + scene.add(group); + + const geometry = new THREE.BoxGeometry(10, 10, 10); + + for (let i = 0; i < 100; i++) { + const material = new THREE.MeshLambertMaterial({ + color: Math.random() * 0xffffff, + }); + + const mesh = new THREE.Mesh(geometry, material); + mesh.position.x = Math.random() * 400 - 200; + mesh.position.y = Math.random() * 400 - 200; + mesh.position.z = Math.random() * 400 - 200; + mesh.rotation.x = Math.random(); + mesh.rotation.y = Math.random(); + mesh.rotation.z = Math.random(); + + mesh.scale.setScalar(Math.random() * 10 + 2); + group.add(mesh); + } + + stats = new Stats(); + container.appendChild(stats.dom); + + const width = window.innerWidth; + const height = window.innerHeight; + + composer = new EffectComposer(renderer); + + const ssaoPass = new SSAOPass(scene, camera, width, height); + ssaoPass.kernelRadius = 16; + composer.addPass(ssaoPass); + + const outputPass = new OutputPass(); + composer.addPass(outputPass); + + // Init gui + const gui = new GUI(); + + gui.add(ssaoPass, 'output', { + Default: SSAOPass.OUTPUT.Default, + 'SSAO Only': SSAOPass.OUTPUT.SSAO, + 'SSAO Only + Blur': SSAOPass.OUTPUT.Blur, + Beauty: SSAOPass.OUTPUT.Beauty, + Depth: SSAOPass.OUTPUT.Depth, + Normal: SSAOPass.OUTPUT.Normal, + }).onChange(function (value) { + ssaoPass.output = parseInt(value); + }); + gui.add(ssaoPass, 'kernelRadius').min(0).max(32); + gui.add(ssaoPass, 'minDistance').min(0.001).max(0.02); + gui.add(ssaoPass, 'maxDistance').min(0.01).max(0.3); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + const width = window.innerWidth; + const height = window.innerHeight; + + camera.aspect = width / height; + camera.updateProjectionMatrix(); + + renderer.setSize(width, height); + composer.setSize(width, height); +} + +function animate() { + requestAnimationFrame(animate); + + stats.begin(); + render(); + stats.end(); +} + +function render() { + const timer = performance.now(); + group.rotation.x = timer * 0.0002; + group.rotation.y = timer * 0.0001; + + composer.render(); +} diff --git a/examples-testing/examples/webgl_postprocessing_ssr.ts b/examples-testing/examples/webgl_postprocessing_ssr.ts new file mode 100644 index 000000000..5fb1e0140 --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_ssr.ts @@ -0,0 +1,263 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { SSRPass } from 'three/addons/postprocessing/SSRPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; +import { ReflectorForSSRPass } from 'three/addons/objects/ReflectorForSSRPass.js'; + +import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'; + +const params = { + enableSSR: true, + autoRotate: true, + otherMeshes: true, + groundReflector: true, +}; +let composer; +let ssrPass; +let gui; +let stats; +let controls; +let camera, scene, renderer; +const otherMeshes = []; +let groundReflector; +const selects = []; + +const container = document.querySelector('#container'); + +// Configure and create Draco decoder. +const dracoLoader = new DRACOLoader(); +dracoLoader.setDecoderPath('jsm/libs/draco/'); +dracoLoader.setDecoderConfig({ type: 'js' }); + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 15); + camera.position.set(0.13271600513224902, 0.3489546826045913, 0.43921296427927076); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x443333); + scene.fog = new THREE.Fog(0x443333, 1, 4); + + // Ground + const plane = new THREE.Mesh(new THREE.PlaneGeometry(8, 8), new THREE.MeshPhongMaterial({ color: 0xcbcbcb })); + plane.rotation.x = -Math.PI / 2; + plane.position.y = -0.0001; + // plane.receiveShadow = true; + scene.add(plane); + + // Lights + const hemiLight = new THREE.HemisphereLight(0x8d7c7c, 0x494966, 3); + scene.add(hemiLight); + + const spotLight = new THREE.SpotLight(); + spotLight.intensity = 8; + spotLight.angle = Math.PI / 16; + spotLight.penumbra = 0.5; + // spotLight.castShadow = true; + spotLight.position.set(-1, 1, 1); + scene.add(spotLight); + + dracoLoader.load('models/draco/bunny.drc', function (geometry) { + geometry.computeVertexNormals(); + + const material = new THREE.MeshStandardMaterial({ color: 0xa5a5a5 }); + const mesh = new THREE.Mesh(geometry, material); + mesh.position.y = -0.0365; + scene.add(mesh); + selects.push(mesh); + + // Release decoder resources. + dracoLoader.dispose(); + }); + + let geometry, material, mesh; + + geometry = new THREE.BoxGeometry(0.05, 0.05, 0.05); + material = new THREE.MeshStandardMaterial({ color: 'green' }); + mesh = new THREE.Mesh(geometry, material); + mesh.position.set(-0.12, 0.025, 0.015); + scene.add(mesh); + otherMeshes.push(mesh); + selects.push(mesh); + + geometry = new THREE.IcosahedronGeometry(0.025, 4); + material = new THREE.MeshStandardMaterial({ color: 'cyan' }); + mesh = new THREE.Mesh(geometry, material); + mesh.position.set(-0.05, 0.025, 0.08); + scene.add(mesh); + otherMeshes.push(mesh); + selects.push(mesh); + + geometry = new THREE.ConeGeometry(0.025, 0.05, 64); + material = new THREE.MeshStandardMaterial({ color: 'yellow' }); + mesh = new THREE.Mesh(geometry, material); + mesh.position.set(-0.05, 0.025, -0.055); + scene.add(mesh); + otherMeshes.push(mesh); + selects.push(mesh); + + geometry = new THREE.PlaneGeometry(1, 1); + groundReflector = new ReflectorForSSRPass(geometry, { + clipBias: 0.0003, + textureWidth: window.innerWidth, + textureHeight: window.innerHeight, + color: 0x888888, + useDepthTexture: true, + }); + groundReflector.material.depthWrite = false; + groundReflector.rotation.x = -Math.PI / 2; + groundReflector.visible = false; + scene.add(groundReflector); + + // renderer + renderer = new THREE.WebGLRenderer({ antialias: false }); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + // + + controls = new OrbitControls(camera, renderer.domElement); + controls.enableDamping = true; + controls.target.set(0, 0.0635, 0); + controls.update(); + controls.enabled = !params.autoRotate; + + // STATS + + stats = new Stats(); + container.appendChild(stats.dom); + + window.addEventListener('resize', onWindowResize); + + // composer + + composer = new EffectComposer(renderer); + ssrPass = new SSRPass({ + renderer, + scene, + camera, + width: innerWidth, + height: innerHeight, + groundReflector: params.groundReflector ? groundReflector : null, + selects: params.groundReflector ? selects : null, + }); + + composer.addPass(ssrPass); + composer.addPass(new OutputPass()); + + // GUI + + gui = new GUI({ width: 260 }); + gui.add(params, 'enableSSR').name('Enable SSR'); + gui.add(params, 'groundReflector').onChange(() => { + if (params.groundReflector) { + (ssrPass.groundReflector = groundReflector), (ssrPass.selects = selects); + } else { + (ssrPass.groundReflector = null), (ssrPass.selects = null); + } + }); + ssrPass.thickness = 0.018; + gui.add(ssrPass, 'thickness').min(0).max(0.1).step(0.0001); + ssrPass.infiniteThick = false; + gui.add(ssrPass, 'infiniteThick'); + gui.add(params, 'autoRotate').onChange(() => { + controls.enabled = !params.autoRotate; + }); + + const folder = gui.addFolder('more settings'); + folder.add(ssrPass, 'fresnel').onChange(() => { + groundReflector.fresnel = ssrPass.fresnel; + }); + folder.add(ssrPass, 'distanceAttenuation').onChange(() => { + groundReflector.distanceAttenuation = ssrPass.distanceAttenuation; + }); + ssrPass.maxDistance = 0.1; + groundReflector.maxDistance = ssrPass.maxDistance; + folder + .add(ssrPass, 'maxDistance') + .min(0) + .max(0.5) + .step(0.001) + .onChange(() => { + groundReflector.maxDistance = ssrPass.maxDistance; + }); + folder.add(params, 'otherMeshes').onChange(() => { + if (params.otherMeshes) { + otherMeshes.forEach(mesh => (mesh.visible = true)); + } else { + otherMeshes.forEach(mesh => (mesh.visible = false)); + } + }); + folder.add(ssrPass, 'bouncing'); + folder + .add(ssrPass, 'output', { + Default: SSRPass.OUTPUT.Default, + 'SSR Only': SSRPass.OUTPUT.SSR, + Beauty: SSRPass.OUTPUT.Beauty, + Depth: SSRPass.OUTPUT.Depth, + Normal: SSRPass.OUTPUT.Normal, + Metalness: SSRPass.OUTPUT.Metalness, + }) + .onChange(function (value) { + ssrPass.output = parseInt(value); + }); + ssrPass.opacity = 1; + groundReflector.opacity = ssrPass.opacity; + folder + .add(ssrPass, 'opacity') + .min(0) + .max(1) + .onChange(() => { + groundReflector.opacity = ssrPass.opacity; + }); + folder.add(ssrPass, 'blur'); + // folder.open() + // gui.close() +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); + composer.setSize(window.innerWidth, window.innerHeight); + groundReflector.getRenderTarget().setSize(window.innerWidth, window.innerHeight); + groundReflector.resolution.set(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + stats.begin(); + render(); + stats.end(); +} + +function render() { + if (params.autoRotate) { + const timer = Date.now() * 0.0003; + + camera.position.x = Math.sin(timer) * 0.5; + camera.position.y = 0.2135; + camera.position.z = Math.cos(timer) * 0.5; + camera.lookAt(0, 0.0635, 0); + } else { + controls.update(); + } + + if (params.enableSSR) { + // TODO: groundReflector has full ground info, need use it to solve reflection gaps problem on objects when camera near ground. + // TODO: the normal and depth info where groundReflector reflected need to be changed. + composer.render(); + } else { + renderer.render(scene, camera); + } +} diff --git a/examples-testing/examples/webgl_postprocessing_taa.ts b/examples-testing/examples/webgl_postprocessing_taa.ts new file mode 100644 index 000000000..b2a12b531 --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_taa.ts @@ -0,0 +1,141 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { TAARenderPass } from 'three/addons/postprocessing/TAARenderPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; + +let camera, scene, renderer, composer, taaRenderPass, renderPass; +let gui, stats; +let index = 0; + +const param = { TAAEnabled: '1', TAASampleLevel: 0 }; + +init(); +animate(); + +clearGui(); + +function clearGui() { + if (gui) gui.destroy(); + + gui = new GUI(); + + gui.add(param, 'TAAEnabled', { + Disabled: '0', + Enabled: '1', + }).onFinishChange(function () { + if (taaRenderPass) { + taaRenderPass.enabled = param.TAAEnabled === '1'; + renderPass.enabled = param.TAAEnabled !== '1'; + } + }); + + gui.add(param, 'TAASampleLevel', { + 'Level 0: 1 Sample': 0, + 'Level 1: 2 Samples': 1, + 'Level 2: 4 Samples': 2, + 'Level 3: 8 Samples': 3, + 'Level 4: 16 Samples': 4, + 'Level 5: 32 Samples': 5, + }).onFinishChange(function () { + if (taaRenderPass) { + taaRenderPass.sampleLevel = param.TAASampleLevel; + } + }); + + gui.open(); +} + +function init() { + const container = document.getElementById('container'); + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.z = 300; + + scene = new THREE.Scene(); + + const geometry = new THREE.BoxGeometry(120, 120, 120); + const material1 = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }); + + const mesh1 = new THREE.Mesh(geometry, material1); + mesh1.position.x = -100; + scene.add(mesh1); + + const texture = new THREE.TextureLoader().load('textures/brick_diffuse.jpg'); + texture.minFilter = THREE.NearestFilter; + texture.magFilter = THREE.NearestFilter; + texture.anisotropy = 1; + texture.generateMipmaps = false; + texture.colorSpace = THREE.SRGBColorSpace; + + const material2 = new THREE.MeshBasicMaterial({ map: texture }); + + const mesh2 = new THREE.Mesh(geometry, material2); + mesh2.position.x = 100; + scene.add(mesh2); + + // postprocessing + + composer = new EffectComposer(renderer); + + taaRenderPass = new TAARenderPass(scene, camera); + taaRenderPass.unbiased = false; + composer.addPass(taaRenderPass); + + renderPass = new RenderPass(scene, camera); + renderPass.enabled = false; + composer.addPass(renderPass); + + const outputPass = new OutputPass(); + composer.addPass(outputPass); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + const width = window.innerWidth; + const height = window.innerHeight; + + camera.aspect = width / height; + camera.updateProjectionMatrix(); + + renderer.setSize(width, height); + composer.setSize(width, height); +} + +function animate() { + requestAnimationFrame(animate); + + index++; + + if (Math.round(index / 200) % 2 === 0) { + for (let i = 0; i < scene.children.length; i++) { + const child = scene.children[i]; + + child.rotation.x += 0.005; + child.rotation.y += 0.01; + } + + if (taaRenderPass) taaRenderPass.accumulate = false; + } else { + if (taaRenderPass) taaRenderPass.accumulate = true; + } + + composer.render(); + + stats.update(); +} diff --git a/examples-testing/examples/webgl_postprocessing_unreal_bloom.ts b/examples-testing/examples/webgl_postprocessing_unreal_bloom.ts new file mode 100644 index 000000000..886f77fdd --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_unreal_bloom.ts @@ -0,0 +1,129 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; + +let camera, stats; +let composer, renderer, mixer, clock; + +const params = { + threshold: 0, + strength: 1, + radius: 0, + exposure: 1, +}; + +init(); + +function init() { + const container = document.getElementById('container'); + + stats = new Stats(); + container.appendChild(stats.dom); + + clock = new THREE.Clock(); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.toneMapping = THREE.ReinhardToneMapping; + container.appendChild(renderer.domElement); + + const scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 100); + camera.position.set(-5, 2.5, -3.5); + scene.add(camera); + + const controls = new OrbitControls(camera, renderer.domElement); + controls.maxPolarAngle = Math.PI * 0.5; + controls.minDistance = 3; + controls.maxDistance = 8; + + scene.add(new THREE.AmbientLight(0xcccccc)); + + const pointLight = new THREE.PointLight(0xffffff, 100); + camera.add(pointLight); + + const renderScene = new RenderPass(scene, camera); + + const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85); + bloomPass.threshold = params.threshold; + bloomPass.strength = params.strength; + bloomPass.radius = params.radius; + + const outputPass = new OutputPass(); + + composer = new EffectComposer(renderer); + composer.addPass(renderScene); + composer.addPass(bloomPass); + composer.addPass(outputPass); + + new GLTFLoader().load('models/gltf/PrimaryIonDrive.glb', function (gltf) { + const model = gltf.scene; + + scene.add(model); + + mixer = new THREE.AnimationMixer(model); + const clip = gltf.animations[0]; + mixer.clipAction(clip.optimize()).play(); + + animate(); + }); + + const gui = new GUI(); + + const bloomFolder = gui.addFolder('bloom'); + + bloomFolder.add(params, 'threshold', 0.0, 1.0).onChange(function (value) { + bloomPass.threshold = Number(value); + }); + + bloomFolder.add(params, 'strength', 0.0, 3.0).onChange(function (value) { + bloomPass.strength = Number(value); + }); + + gui.add(params, 'radius', 0.0, 1.0) + .step(0.01) + .onChange(function (value) { + bloomPass.radius = Number(value); + }); + + const toneMappingFolder = gui.addFolder('tone mapping'); + + toneMappingFolder.add(params, 'exposure', 0.1, 2).onChange(function (value) { + renderer.toneMappingExposure = Math.pow(value, 4.0); + }); + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + const width = window.innerWidth; + const height = window.innerHeight; + + camera.aspect = width / height; + camera.updateProjectionMatrix(); + + renderer.setSize(width, height); + composer.setSize(width, height); +} + +function animate() { + requestAnimationFrame(animate); + + const delta = clock.getDelta(); + + mixer.update(delta); + + stats.update(); + + composer.render(); +} diff --git a/examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts b/examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts new file mode 100644 index 000000000..d633806ee --- /dev/null +++ b/examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts @@ -0,0 +1,195 @@ +import * as THREE from 'three'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; +import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js'; +import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; + +const BLOOM_SCENE = 1; + +const bloomLayer = new THREE.Layers(); +bloomLayer.set(BLOOM_SCENE); + +const params = { + threshold: 0, + strength: 1, + radius: 0.5, + exposure: 1, +}; + +const darkMaterial = new THREE.MeshBasicMaterial({ color: 'black' }); +const materials = {}; + +const renderer = new THREE.WebGLRenderer({ antialias: true }); +renderer.setPixelRatio(window.devicePixelRatio); +renderer.setSize(window.innerWidth, window.innerHeight); +renderer.toneMapping = THREE.ReinhardToneMapping; +document.body.appendChild(renderer.domElement); + +const scene = new THREE.Scene(); + +const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 200); +camera.position.set(0, 0, 20); +camera.lookAt(0, 0, 0); + +const controls = new OrbitControls(camera, renderer.domElement); +controls.maxPolarAngle = Math.PI * 0.5; +controls.minDistance = 1; +controls.maxDistance = 100; +controls.addEventListener('change', render); + +const renderScene = new RenderPass(scene, camera); + +const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85); +bloomPass.threshold = params.threshold; +bloomPass.strength = params.strength; +bloomPass.radius = params.radius; + +const bloomComposer = new EffectComposer(renderer); +bloomComposer.renderToScreen = false; +bloomComposer.addPass(renderScene); +bloomComposer.addPass(bloomPass); + +const mixPass = new ShaderPass( + new THREE.ShaderMaterial({ + uniforms: { + baseTexture: { value: null }, + bloomTexture: { value: bloomComposer.renderTarget2.texture }, + }, + vertexShader: document.getElementById('vertexshader').textContent, + fragmentShader: document.getElementById('fragmentshader').textContent, + defines: {}, + }), + 'baseTexture', +); +mixPass.needsSwap = true; + +const outputPass = new OutputPass(); + +const finalComposer = new EffectComposer(renderer); +finalComposer.addPass(renderScene); +finalComposer.addPass(mixPass); +finalComposer.addPass(outputPass); + +const raycaster = new THREE.Raycaster(); + +const mouse = new THREE.Vector2(); + +window.addEventListener('pointerdown', onPointerDown); + +const gui = new GUI(); + +const bloomFolder = gui.addFolder('bloom'); + +bloomFolder.add(params, 'threshold', 0.0, 1.0).onChange(function (value) { + bloomPass.threshold = Number(value); + render(); +}); + +bloomFolder.add(params, 'strength', 0.0, 3).onChange(function (value) { + bloomPass.strength = Number(value); + render(); +}); + +bloomFolder + .add(params, 'radius', 0.0, 1.0) + .step(0.01) + .onChange(function (value) { + bloomPass.radius = Number(value); + render(); + }); + +const toneMappingFolder = gui.addFolder('tone mapping'); + +toneMappingFolder.add(params, 'exposure', 0.1, 2).onChange(function (value) { + renderer.toneMappingExposure = Math.pow(value, 4.0); + render(); +}); + +setupScene(); + +function onPointerDown(event) { + mouse.x = (event.clientX / window.innerWidth) * 2 - 1; + mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; + + raycaster.setFromCamera(mouse, camera); + const intersects = raycaster.intersectObjects(scene.children, false); + if (intersects.length > 0) { + const object = intersects[0].object; + object.layers.toggle(BLOOM_SCENE); + render(); + } +} + +window.onresize = function () { + const width = window.innerWidth; + const height = window.innerHeight; + + camera.aspect = width / height; + camera.updateProjectionMatrix(); + + renderer.setSize(width, height); + + bloomComposer.setSize(width, height); + finalComposer.setSize(width, height); + + render(); +}; + +function setupScene() { + scene.traverse(disposeMaterial); + scene.children.length = 0; + + const geometry = new THREE.IcosahedronGeometry(1, 15); + + for (let i = 0; i < 50; i++) { + const color = new THREE.Color(); + color.setHSL(Math.random(), 0.7, Math.random() * 0.2 + 0.05); + + const material = new THREE.MeshBasicMaterial({ color: color }); + const sphere = new THREE.Mesh(geometry, material); + sphere.position.x = Math.random() * 10 - 5; + sphere.position.y = Math.random() * 10 - 5; + sphere.position.z = Math.random() * 10 - 5; + sphere.position.normalize().multiplyScalar(Math.random() * 4.0 + 2.0); + sphere.scale.setScalar(Math.random() * Math.random() + 0.5); + scene.add(sphere); + + if (Math.random() < 0.25) sphere.layers.enable(BLOOM_SCENE); + } + + render(); +} + +function disposeMaterial(obj) { + if (obj.material) { + obj.material.dispose(); + } +} + +function render() { + scene.traverse(darkenNonBloomed); + bloomComposer.render(); + scene.traverse(restoreMaterial); + + // render the entire scene, then render bloom scene on top + finalComposer.render(); +} + +function darkenNonBloomed(obj) { + if (obj.isMesh && bloomLayer.test(obj.layers) === false) { + materials[obj.uuid] = obj.material; + obj.material = darkMaterial; + } +} + +function restoreMaterial(obj) { + if (materials[obj.uuid]) { + obj.material = materials[obj.uuid]; + delete materials[obj.uuid]; + } +} diff --git a/examples-testing/examples/webgl_raymarching_reflect.ts b/examples-testing/examples/webgl_raymarching_reflect.ts new file mode 100644 index 000000000..96f9a81d0 --- /dev/null +++ b/examples-testing/examples/webgl_raymarching_reflect.ts @@ -0,0 +1,96 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +let dolly, camera, scene, renderer; +let geometry, material, mesh; +let stats, clock; + +const canvas = document.querySelector('#canvas'); + +const config = { + saveImage: function () { + renderer.render(scene, camera); + window.open(canvas.toDataURL()); + }, + resolution: '512', +}; + +init(); +render(); + +function init() { + renderer = new THREE.WebGLRenderer({ canvas: canvas }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(parseInt(config.resolution), parseInt(config.resolution)); + + window.addEventListener('resize', onWindowResize); + + // THREE.Scene + scene = new THREE.Scene(); + + dolly = new THREE.Group(); + scene.add(dolly); + + clock = new THREE.Clock(); + + camera = new THREE.PerspectiveCamera(60, canvas.width / canvas.height, 1, 2000); + camera.position.z = 4; + dolly.add(camera); + + geometry = new THREE.PlaneGeometry(2.0, 2.0); + material = new THREE.RawShaderMaterial({ + uniforms: { + resolution: { value: new THREE.Vector2(canvas.width, canvas.height) }, + cameraWorldMatrix: { value: camera.matrixWorld }, + cameraProjectionMatrixInverse: { value: camera.projectionMatrixInverse.clone() }, + }, + vertexShader: document.getElementById('vertex_shader').textContent, + fragmentShader: document.getElementById('fragment_shader').textContent, + }); + mesh = new THREE.Mesh(geometry, material); + mesh.frustumCulled = false; + scene.add(mesh); + + // Controls + const controls = new OrbitControls(camera, canvas); + controls.enableZoom = false; + + // GUI + const gui = new GUI(); + gui.add(config, 'saveImage').name('Save Image'); + gui.add(config, 'resolution', ['256', '512', '800', 'full']).name('Resolution').onChange(onWindowResize); + + stats = new Stats(); + document.body.appendChild(stats.dom); +} + +function onWindowResize() { + if (config.resolution === 'full') { + renderer.setSize(window.innerWidth, window.innerHeight); + } else { + renderer.setSize(parseInt(config.resolution), parseInt(config.resolution)); + } + + camera.aspect = canvas.width / canvas.height; + camera.updateProjectionMatrix(); + + material.uniforms.resolution.value.set(canvas.width, canvas.height); + material.uniforms.cameraProjectionMatrixInverse.value.copy(camera.projectionMatrixInverse); +} + +function render() { + stats.begin(); + + const elapsedTime = clock.getElapsedTime(); + + dolly.position.z = -elapsedTime; + + renderer.render(scene, camera); + + stats.end(); + requestAnimationFrame(render); +} diff --git a/examples-testing/examples/webgl_shadowmap_csm.ts b/examples-testing/examples/webgl_shadowmap_csm.ts new file mode 100644 index 000000000..f9df4abf5 --- /dev/null +++ b/examples-testing/examples/webgl_shadowmap_csm.ts @@ -0,0 +1,244 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import { CSM } from 'three/addons/csm/CSM.js'; +import { CSMHelper } from 'three/addons/csm/CSMHelper.js'; + +let renderer, scene, camera, orthoCamera, controls, csm, csmHelper; + +const params = { + orthographic: false, + fade: false, + far: 1000, + mode: 'practical', + lightX: -1, + lightY: -1, + lightZ: -1, + margin: 100, + lightFar: 5000, + lightNear: 1, + autoUpdateHelper: true, + updateHelper: function () { + csmHelper.update(); + }, +}; + +init(); +animate(); + +function updateOrthoCamera() { + const size = controls.target.distanceTo(camera.position); + const aspect = camera.aspect; + + orthoCamera.left = (size * aspect) / -2; + orthoCamera.right = (size * aspect) / 2; + + orthoCamera.top = size / 2; + orthoCamera.bottom = size / -2; + orthoCamera.position.copy(camera.position); + orthoCamera.rotation.copy(camera.rotation); + orthoCamera.updateProjectionMatrix(); +} + +function init() { + scene = new THREE.Scene(); + scene.background = new THREE.Color('#454e61'); + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 5000); + orthoCamera = new THREE.OrthographicCamera(); + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + renderer.shadowMap.enabled = true; + renderer.shadowMap.type = THREE.PCFSoftShadowMap; + + controls = new OrbitControls(camera, renderer.domElement); + controls.maxPolarAngle = Math.PI / 2; + camera.position.set(60, 60, 0); + controls.target = new THREE.Vector3(-100, 10, 0); + controls.update(); + + const ambientLight = new THREE.AmbientLight(0xffffff, 1.5); + scene.add(ambientLight); + + const additionalDirectionalLight = new THREE.DirectionalLight(0x000020, 1.5); + additionalDirectionalLight.position + .set(params.lightX, params.lightY, params.lightZ) + .normalize() + .multiplyScalar(-200); + scene.add(additionalDirectionalLight); + + csm = new CSM({ + maxFar: params.far, + cascades: 4, + mode: params.mode, + parent: scene, + shadowMapSize: 1024, + lightDirection: new THREE.Vector3(params.lightX, params.lightY, params.lightZ).normalize(), + camera: camera, + }); + + csmHelper = new CSMHelper(csm); + csmHelper.visible = false; + scene.add(csmHelper); + + const floorMaterial = new THREE.MeshPhongMaterial({ color: '#252a34' }); + csm.setupMaterial(floorMaterial); + + const floor = new THREE.Mesh(new THREE.PlaneGeometry(10000, 10000, 8, 8), floorMaterial); + floor.rotation.x = -Math.PI / 2; + floor.castShadow = true; + floor.receiveShadow = true; + scene.add(floor); + + const material1 = new THREE.MeshPhongMaterial({ color: '#08d9d6' }); + csm.setupMaterial(material1); + + const material2 = new THREE.MeshPhongMaterial({ color: '#ff2e63' }); + csm.setupMaterial(material2); + + const geometry = new THREE.BoxGeometry(10, 10, 10); + + for (let i = 0; i < 40; i++) { + const cube1 = new THREE.Mesh(geometry, i % 2 === 0 ? material1 : material2); + cube1.castShadow = true; + cube1.receiveShadow = true; + scene.add(cube1); + cube1.position.set(-i * 25, 20, 30); + cube1.scale.y = Math.random() * 2 + 6; + + const cube2 = new THREE.Mesh(geometry, i % 2 === 0 ? material2 : material1); + cube2.castShadow = true; + cube2.receiveShadow = true; + scene.add(cube2); + cube2.position.set(-i * 25, 20, -30); + cube2.scale.y = Math.random() * 2 + 6; + } + + const gui = new GUI(); + + gui.add(params, 'orthographic').onChange(function (value) { + csm.camera = value ? orthoCamera : camera; + csm.updateFrustums(); + }); + + gui.add(params, 'fade').onChange(function (value) { + csm.fade = value; + csm.updateFrustums(); + }); + + gui.add(params, 'far', 1, 5000) + .step(1) + .name('shadow far') + .onChange(function (value) { + csm.maxFar = value; + csm.updateFrustums(); + }); + + gui.add(params, 'mode', ['uniform', 'logarithmic', 'practical']) + .name('frustum split mode') + .onChange(function (value) { + csm.mode = value; + csm.updateFrustums(); + }); + + gui.add(params, 'lightX', -1, 1) + .name('light direction x') + .onChange(function (value) { + csm.lightDirection.x = value; + }); + + gui.add(params, 'lightY', -1, 1) + .name('light direction y') + .onChange(function (value) { + csm.lightDirection.y = value; + }); + + gui.add(params, 'lightZ', -1, 1) + .name('light direction z') + .onChange(function (value) { + csm.lightDirection.z = value; + }); + + gui.add(params, 'margin', 0, 200) + .name('light margin') + .onChange(function (value) { + csm.lightMargin = value; + }); + + gui.add(params, 'lightNear', 1, 10000) + .name('light near') + .onChange(function (value) { + for (let i = 0; i < csm.lights.length; i++) { + csm.lights[i].shadow.camera.near = value; + csm.lights[i].shadow.camera.updateProjectionMatrix(); + } + }); + + gui.add(params, 'lightFar', 1, 10000) + .name('light far') + .onChange(function (value) { + for (let i = 0; i < csm.lights.length; i++) { + csm.lights[i].shadow.camera.far = value; + csm.lights[i].shadow.camera.updateProjectionMatrix(); + } + }); + + const helperFolder = gui.addFolder('helper'); + + helperFolder.add(csmHelper, 'visible'); + + helperFolder.add(csmHelper, 'displayFrustum').onChange(function () { + csmHelper.updateVisibility(); + }); + + helperFolder.add(csmHelper, 'displayPlanes').onChange(function () { + csmHelper.updateVisibility(); + }); + + helperFolder.add(csmHelper, 'displayShadowBounds').onChange(function () { + csmHelper.updateVisibility(); + }); + + helperFolder.add(params, 'autoUpdateHelper').name('auto update'); + + helperFolder.add(params, 'updateHelper').name('update'); + + helperFolder.open(); + + window.addEventListener('resize', function () { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + updateOrthoCamera(); + csm.updateFrustums(); + + renderer.setSize(window.innerWidth, window.innerHeight); + }); +} + +function animate() { + requestAnimationFrame(animate); + + camera.updateMatrixWorld(); + csm.update(); + controls.update(); + + if (params.orthographic) { + updateOrthoCamera(); + csm.updateFrustums(); + + if (params.autoUpdateHelper) { + csmHelper.update(); + } + + renderer.render(scene, orthoCamera); + } else { + if (params.autoUpdateHelper) { + csmHelper.update(); + } + + renderer.render(scene, camera); + } +} diff --git a/examples-testing/examples/webgl_shadowmap_pcss.ts b/examples-testing/examples/webgl_shadowmap_pcss.ts new file mode 100644 index 000000000..91ba36072 --- /dev/null +++ b/examples-testing/examples/webgl_shadowmap_pcss.ts @@ -0,0 +1,163 @@ +import * as THREE from 'three'; + +import Stats from 'three/addons/libs/stats.module.js'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +let stats; +let camera, scene, renderer; + +let group; + +init(); +animate(); + +function init() { + const container = document.createElement('div'); + document.body.appendChild(container); + + // scene + + scene = new THREE.Scene(); + scene.fog = new THREE.Fog(0xcce0ff, 5, 100); + + // camera + + camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 10000); + + // We use this particular camera position in order to expose a bug that can sometimes happen presumably + // due to lack of precision when interpolating values over really large triangles. + // It reproduced on at least NVIDIA GTX 1080 and GTX 1050 Ti GPUs when the ground plane was not + // subdivided into segments. + camera.position.x = 7; + camera.position.y = 13; + camera.position.z = 7; + + scene.add(camera); + + // lights + + scene.add(new THREE.AmbientLight(0xaaaaaa, 3)); + + const light = new THREE.DirectionalLight(0xf0f6ff, 4.5); + light.position.set(2, 8, 4); + + light.castShadow = true; + light.shadow.mapSize.width = 1024; + light.shadow.mapSize.height = 1024; + light.shadow.camera.far = 20; + + scene.add(light); + + // scene.add( new DirectionalLightHelper( light ) ); + scene.add(new THREE.CameraHelper(light.shadow.camera)); + + // group + + group = new THREE.Group(); + scene.add(group); + + const geometry = new THREE.SphereGeometry(0.3, 20, 20); + + for (let i = 0; i < 20; i++) { + const material = new THREE.MeshPhongMaterial({ color: Math.random() * 0xffffff }); + + const sphere = new THREE.Mesh(geometry, material); + sphere.position.x = Math.random() - 0.5; + sphere.position.z = Math.random() - 0.5; + sphere.position.normalize(); + sphere.position.multiplyScalar(Math.random() * 2 + 1); + sphere.castShadow = true; + sphere.receiveShadow = true; + sphere.userData.phase = Math.random() * Math.PI; + group.add(sphere); + } + + // ground + + const groundMaterial = new THREE.MeshPhongMaterial({ color: 0x898989 }); + + const ground = new THREE.Mesh(new THREE.PlaneGeometry(20000, 20000, 8, 8), groundMaterial); + ground.rotation.x = -Math.PI / 2; + ground.receiveShadow = true; + scene.add(ground); + + // column + + const column = new THREE.Mesh(new THREE.BoxGeometry(1, 4, 1), groundMaterial); + column.position.y = 2; + column.castShadow = true; + column.receiveShadow = true; + scene.add(column); + + // overwrite shadowmap code + + let shader = THREE.ShaderChunk.shadowmap_pars_fragment; + + shader = shader.replace( + '#ifdef USE_SHADOWMAP', + '#ifdef USE_SHADOWMAP' + document.getElementById('PCSS').textContent, + ); + + shader = shader.replace( + '#if defined( SHADOWMAP_TYPE_PCF )', + document.getElementById('PCSSGetShadow').textContent + '#if defined( SHADOWMAP_TYPE_PCF )', + ); + + THREE.ShaderChunk.shadowmap_pars_fragment = shader; + + // renderer + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.setClearColor(scene.fog.color); + + container.appendChild(renderer.domElement); + + renderer.shadowMap.enabled = true; + + // controls + const controls = new OrbitControls(camera, renderer.domElement); + controls.maxPolarAngle = Math.PI * 0.5; + controls.minDistance = 10; + controls.maxDistance = 75; + controls.target.set(0, 2.5, 0); + controls.update(); + + // performance monitor + + stats = new Stats(); + container.appendChild(stats.dom); + + // + + window.addEventListener('resize', onWindowResize); +} + +// + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + const time = performance.now() / 1000; + + group.traverse(function (child) { + if ('phase' in child.userData) { + child.position.y = Math.abs(Math.sin(time + child.userData.phase)) * 4 + 0.3; + } + }); + + renderer.render(scene, camera); + + stats.update(); + + requestAnimationFrame(animate); +} diff --git a/examples-testing/examples/webgl_shadowmap_progressive.ts b/examples-testing/examples/webgl_shadowmap_progressive.ts new file mode 100644 index 000000000..eaf6e325c --- /dev/null +++ b/examples-testing/examples/webgl_shadowmap_progressive.ts @@ -0,0 +1,214 @@ +import * as THREE from 'three'; +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { TransformControls } from 'three/addons/controls/TransformControls.js'; +import { ProgressiveLightMap } from 'three/addons/misc/ProgressiveLightMap.js'; + +// ShadowMap + LightMap Res and Number of Directional Lights +const shadowMapRes = 512, + lightMapRes = 1024, + lightCount = 8; +let camera, + scene, + renderer, + controls, + control, + control2, + object = new THREE.Mesh(), + lightOrigin = null, + progressiveSurfacemap; +const dirLights = [], + lightmapObjects = []; +const params = { + Enable: true, + 'Blur Edges': true, + 'Blend Window': 200, + 'Light Radius': 50, + 'Ambient Weight': 0.5, + 'Debug Lightmap': false, +}; +init(); +createGUI(); +animate(); + +function init() { + // renderer + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + document.body.appendChild(renderer.domElement); + + // camera + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); + camera.position.set(0, 100, 200); + camera.name = 'Camera'; + + // scene + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x949494); + scene.fog = new THREE.Fog(0x949494, 1000, 3000); + + // progressive lightmap + progressiveSurfacemap = new ProgressiveLightMap(renderer, lightMapRes); + + // directional lighting "origin" + lightOrigin = new THREE.Group(); + lightOrigin.position.set(60, 150, 100); + scene.add(lightOrigin); + + // transform gizmo + control = new TransformControls(camera, renderer.domElement); + control.addEventListener('dragging-changed', event => { + controls.enabled = !event.value; + }); + control.attach(lightOrigin); + scene.add(control); + + // create 8 directional lights to speed up the convergence + for (let l = 0; l < lightCount; l++) { + const dirLight = new THREE.DirectionalLight(0xffffff, 1.0 / lightCount); + dirLight.name = 'Dir. Light ' + l; + dirLight.position.set(200, 200, 200); + dirLight.castShadow = true; + dirLight.shadow.camera.near = 100; + dirLight.shadow.camera.far = 5000; + dirLight.shadow.camera.right = 150; + dirLight.shadow.camera.left = -150; + dirLight.shadow.camera.top = 150; + dirLight.shadow.camera.bottom = -150; + dirLight.shadow.mapSize.width = shadowMapRes; + dirLight.shadow.mapSize.height = shadowMapRes; + lightmapObjects.push(dirLight); + dirLights.push(dirLight); + } + + // ground + const groundMesh = new THREE.Mesh( + new THREE.PlaneGeometry(600, 600), + new THREE.MeshPhongMaterial({ color: 0xffffff, depthWrite: true }), + ); + groundMesh.position.y = -0.1; + groundMesh.rotation.x = -Math.PI / 2; + groundMesh.name = 'Ground Mesh'; + lightmapObjects.push(groundMesh); + scene.add(groundMesh); + + // model + function loadModel() { + object.traverse(function (child) { + if (child.isMesh) { + child.name = 'Loaded Mesh'; + child.castShadow = true; + child.receiveShadow = true; + child.material = new THREE.MeshPhongMaterial(); + + // This adds the model to the lightmap + lightmapObjects.push(child); + progressiveSurfacemap.addObjectsToLightMap(lightmapObjects); + } else { + child.layers.disableAll(); // Disable Rendering for this + } + }); + scene.add(object); + object.scale.set(2, 2, 2); + object.position.set(0, -16, 0); + control2 = new TransformControls(camera, renderer.domElement); + control2.addEventListener('dragging-changed', event => { + controls.enabled = !event.value; + }); + control2.attach(object); + scene.add(control2); + const lightTarget = new THREE.Group(); + lightTarget.position.set(0, 20, 0); + for (let l = 0; l < dirLights.length; l++) { + dirLights[l].target = lightTarget; + } + + object.add(lightTarget); + + if (typeof TESTING !== 'undefined') { + for (let i = 0; i < 300; i++) { + render(); + } + } + } + + const manager = new THREE.LoadingManager(loadModel); + const loader = new GLTFLoader(manager); + loader.load('models/gltf/ShadowmappableMesh.glb', function (obj) { + object = obj.scene.children[0]; + }); + + // controls + controls = new OrbitControls(camera, renderer.domElement); + controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled + controls.dampingFactor = 0.05; + controls.screenSpacePanning = true; + controls.minDistance = 100; + controls.maxDistance = 500; + controls.maxPolarAngle = Math.PI / 1.5; + controls.target.set(0, 100, 0); + window.addEventListener('resize', onWindowResize); +} + +function createGUI() { + const gui = new GUI({ title: 'Accumulation Settings' }); + gui.add(params, 'Enable'); + gui.add(params, 'Blur Edges'); + gui.add(params, 'Blend Window', 1, 500).step(1); + gui.add(params, 'Light Radius', 0, 200).step(10); + gui.add(params, 'Ambient Weight', 0, 1).step(0.1); + gui.add(params, 'Debug Lightmap'); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function render() { + // Update the inertia on the orbit controls + controls.update(); + + // Accumulate Surface Maps + if (params['Enable']) { + progressiveSurfacemap.update(camera, params['Blend Window'], params['Blur Edges']); + + if (!progressiveSurfacemap.firstUpdate) { + progressiveSurfacemap.showDebugLightmap(params['Debug Lightmap']); + } + } + + // Manually Update the Directional Lights + for (let l = 0; l < dirLights.length; l++) { + // Sometimes they will be sampled from the target direction + // Sometimes they will be uniformly sampled from the upper hemisphere + if (Math.random() > params['Ambient Weight']) { + dirLights[l].position.set( + lightOrigin.position.x + Math.random() * params['Light Radius'], + lightOrigin.position.y + Math.random() * params['Light Radius'], + lightOrigin.position.z + Math.random() * params['Light Radius'], + ); + } else { + // Uniform Hemispherical Surface Distribution for Ambient Occlusion + const lambda = Math.acos(2 * Math.random() - 1) - 3.14159 / 2.0; + const phi = 2 * 3.14159 * Math.random(); + dirLights[l].position.set( + Math.cos(lambda) * Math.cos(phi) * 300 + object.position.x, + Math.abs(Math.cos(lambda) * Math.sin(phi) * 300) + object.position.y + 20, + Math.sin(lambda) * 300 + object.position.z, + ); + } + } + + // Render Scene + renderer.render(scene, camera); +} + +function animate() { + requestAnimationFrame(animate); + render(); +} diff --git a/examples-testing/examples/webgl_simple_gi.ts b/examples-testing/examples/webgl_simple_gi.ts new file mode 100644 index 000000000..cd5d567d9 --- /dev/null +++ b/examples-testing/examples/webgl_simple_gi.ts @@ -0,0 +1,175 @@ +import * as THREE from 'three'; + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +class GIMesh extends THREE.Mesh { + copy(source) { + super.copy(source); + + this.geometry = source.geometry.clone(); + + return this; + } +} + +// + +const SimpleGI = function (renderer, scene) { + const SIZE = 32, + SIZE2 = SIZE * SIZE; + + const camera = new THREE.PerspectiveCamera(90, 1, 0.01, 100); + + scene.updateMatrixWorld(true); + + let clone = scene.clone(); + clone.matrixWorldAutoUpdate = false; + + const rt = new THREE.WebGLRenderTarget(SIZE, SIZE); + + const normalMatrix = new THREE.Matrix3(); + + const position = new THREE.Vector3(); + const normal = new THREE.Vector3(); + + let bounces = 0; + let currentVertex = 0; + + const color = new Float32Array(3); + const buffer = new Uint8Array(SIZE2 * 4); + + function compute() { + if (bounces === 3) return; + + const object = scene.children[0]; // torusKnot + const geometry = object.geometry; + + const attributes = geometry.attributes; + const positions = attributes.position.array; + const normals = attributes.normal.array; + + if (attributes.color === undefined) { + const colors = new Float32Array(positions.length); + geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3).setUsage(THREE.DynamicDrawUsage)); + } + + const colors = attributes.color.array; + + const startVertex = currentVertex; + const totalVertex = positions.length / 3; + + for (let i = 0; i < 32; i++) { + if (currentVertex >= totalVertex) break; + + position.fromArray(positions, currentVertex * 3); + position.applyMatrix4(object.matrixWorld); + + normal.fromArray(normals, currentVertex * 3); + normal.applyMatrix3(normalMatrix.getNormalMatrix(object.matrixWorld)).normalize(); + + camera.position.copy(position); + camera.lookAt(position.add(normal)); + + renderer.setRenderTarget(rt); + renderer.render(clone, camera); + + renderer.readRenderTargetPixels(rt, 0, 0, SIZE, SIZE, buffer); + + color[0] = 0; + color[1] = 0; + color[2] = 0; + + for (let k = 0, kl = buffer.length; k < kl; k += 4) { + color[0] += buffer[k + 0]; + color[1] += buffer[k + 1]; + color[2] += buffer[k + 2]; + } + + colors[currentVertex * 3 + 0] = color[0] / (SIZE2 * 255); + colors[currentVertex * 3 + 1] = color[1] / (SIZE2 * 255); + colors[currentVertex * 3 + 2] = color[2] / (SIZE2 * 255); + + currentVertex++; + } + + attributes.color.updateRange.offset = startVertex * 3; + attributes.color.updateRange.count = (currentVertex - startVertex) * 3; + attributes.color.needsUpdate = true; + + if (currentVertex >= totalVertex) { + clone = scene.clone(); + clone.matrixWorldAutoUpdate = false; + + bounces++; + currentVertex = 0; + } + + requestAnimationFrame(compute); + } + + requestAnimationFrame(compute); +}; + +// + +let camera, scene, renderer; + +init(); +animate(); + +function init() { + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 100); + camera.position.z = 4; + + scene = new THREE.Scene(); + + // torus knot + + const torusGeometry = new THREE.TorusKnotGeometry(0.75, 0.3, 128, 32, 1); + const material = new THREE.MeshBasicMaterial({ vertexColors: true }); + + const torusKnot = new GIMesh(torusGeometry, material); + scene.add(torusKnot); + + // room + + const materials = []; + + for (let i = 0; i < 8; i++) { + materials.push(new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff, side: THREE.BackSide })); + } + + const boxGeometry = new THREE.BoxGeometry(3, 3, 3); + + const box = new THREE.Mesh(boxGeometry, materials); + scene.add(box); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(renderer.domElement); + + new SimpleGI(renderer, scene); + + const controls = new OrbitControls(camera, renderer.domElement); + controls.minDistance = 1; + controls.maxDistance = 10; + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + requestAnimationFrame(animate); + + renderer.setRenderTarget(null); + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webxr_ar_cones.ts b/examples-testing/examples/webxr_ar_cones.ts new file mode 100644 index 000000000..996e41f27 --- /dev/null +++ b/examples-testing/examples/webxr_ar_cones.ts @@ -0,0 +1,70 @@ +import * as THREE from 'three'; +import { ARButton } from 'three/addons/webxr/ARButton.js'; + +let camera, scene, renderer; +let controller; + +init(); +animate(); + +function init() { + const container = document.createElement('div'); + document.body.appendChild(container); + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20); + + const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 3); + light.position.set(0.5, 1, 0.25); + scene.add(light); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.xr.enabled = true; + container.appendChild(renderer.domElement); + + // + + document.body.appendChild(ARButton.createButton(renderer)); + + // + + const geometry = new THREE.CylinderGeometry(0, 0.05, 0.2, 32).rotateX(Math.PI / 2); + + function onSelect() { + const material = new THREE.MeshPhongMaterial({ color: 0xffffff * Math.random() }); + const mesh = new THREE.Mesh(geometry, material); + mesh.position.set(0, 0, -0.3).applyMatrix4(controller.matrixWorld); + mesh.quaternion.setFromRotationMatrix(controller.matrixWorld); + scene.add(mesh); + } + + controller = renderer.xr.getController(0); + controller.addEventListener('select', onSelect); + scene.add(controller); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + renderer.setAnimationLoop(render); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webxr_ar_hittest.ts b/examples-testing/examples/webxr_ar_hittest.ts new file mode 100644 index 000000000..5540c90da --- /dev/null +++ b/examples-testing/examples/webxr_ar_hittest.ts @@ -0,0 +1,119 @@ +import * as THREE from 'three'; +import { ARButton } from 'three/addons/webxr/ARButton.js'; + +let container; +let camera, scene, renderer; +let controller; + +let reticle; + +let hitTestSource = null; +let hitTestSourceRequested = false; + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20); + + const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 3); + light.position.set(0.5, 1, 0.25); + scene.add(light); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.xr.enabled = true; + container.appendChild(renderer.domElement); + + // + + document.body.appendChild(ARButton.createButton(renderer, { requiredFeatures: ['hit-test'] })); + + // + + const geometry = new THREE.CylinderGeometry(0.1, 0.1, 0.2, 32).translate(0, 0.1, 0); + + function onSelect() { + if (reticle.visible) { + const material = new THREE.MeshPhongMaterial({ color: 0xffffff * Math.random() }); + const mesh = new THREE.Mesh(geometry, material); + reticle.matrix.decompose(mesh.position, mesh.quaternion, mesh.scale); + mesh.scale.y = Math.random() * 2 + 1; + scene.add(mesh); + } + } + + controller = renderer.xr.getController(0); + controller.addEventListener('select', onSelect); + scene.add(controller); + + reticle = new THREE.Mesh( + new THREE.RingGeometry(0.15, 0.2, 32).rotateX(-Math.PI / 2), + new THREE.MeshBasicMaterial(), + ); + reticle.matrixAutoUpdate = false; + reticle.visible = false; + scene.add(reticle); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + renderer.setAnimationLoop(render); +} + +function render(timestamp, frame) { + if (frame) { + const referenceSpace = renderer.xr.getReferenceSpace(); + const session = renderer.xr.getSession(); + + if (hitTestSourceRequested === false) { + session.requestReferenceSpace('viewer').then(function (referenceSpace) { + session.requestHitTestSource({ space: referenceSpace }).then(function (source) { + hitTestSource = source; + }); + }); + + session.addEventListener('end', function () { + hitTestSourceRequested = false; + hitTestSource = null; + }); + + hitTestSourceRequested = true; + } + + if (hitTestSource) { + const hitTestResults = frame.getHitTestResults(hitTestSource); + + if (hitTestResults.length) { + const hit = hitTestResults[0]; + + reticle.visible = true; + reticle.matrix.fromArray(hit.getPose(referenceSpace).transform.matrix); + } else { + reticle.visible = false; + } + } + } + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webxr_ar_lighting.ts b/examples-testing/examples/webxr_ar_lighting.ts new file mode 100644 index 000000000..1a9c4de21 --- /dev/null +++ b/examples-testing/examples/webxr_ar_lighting.ts @@ -0,0 +1,128 @@ +import * as THREE from 'three'; +import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'; +import { ARButton } from 'three/addons/webxr/ARButton.js'; +import { XREstimatedLight } from 'three/addons/webxr/XREstimatedLight.js'; + +let camera, scene, renderer; +let controller; +let defaultEnvironment; + +init(); +animate(); + +function init() { + const container = document.createElement('div'); + document.body.appendChild(container); + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20); + + const defaultLight = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1); + defaultLight.position.set(0.5, 1, 0.25); + scene.add(defaultLight); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.xr.enabled = true; + container.appendChild(renderer.domElement); + + // Don't add the XREstimatedLight to the scene initially. + // It doesn't have any estimated lighting values until an AR session starts. + + const xrLight = new XREstimatedLight(renderer); + + xrLight.addEventListener('estimationstart', () => { + // Swap the default light out for the estimated one one we start getting some estimated values. + scene.add(xrLight); + scene.remove(defaultLight); + + // The estimated lighting also provides an environment cubemap, which we can apply here. + if (xrLight.environment) { + scene.environment = xrLight.environment; + } + }); + + xrLight.addEventListener('estimationend', () => { + // Swap the lights back when we stop receiving estimated values. + scene.add(defaultLight); + scene.remove(xrLight); + + // Revert back to the default environment. + scene.environment = defaultEnvironment; + }); + + // + + new RGBELoader().setPath('textures/equirectangular/').load('royal_esplanade_1k.hdr', function (texture) { + texture.mapping = THREE.EquirectangularReflectionMapping; + + defaultEnvironment = texture; + + scene.environment = defaultEnvironment; + }); + + // + + // In order for lighting estimation to work, 'light-estimation' must be included as either an optional or required feature. + document.body.appendChild(ARButton.createButton(renderer, { optionalFeatures: ['light-estimation'] })); + + // + + const ballGeometry = new THREE.SphereGeometry(0.175, 32, 32); + const ballGroup = new THREE.Group(); + ballGroup.position.z = -2; + + const rows = 3; + const cols = 3; + + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + const ballMaterial = new THREE.MeshStandardMaterial({ + color: 0xdddddd, + roughness: i / rows, + metalness: j / cols, + }); + const ballMesh = new THREE.Mesh(ballGeometry, ballMaterial); + ballMesh.position.set((i + 0.5 - rows * 0.5) * 0.4, (j + 0.5 - cols * 0.5) * 0.4, 0); + ballGroup.add(ballMesh); + } + } + + scene.add(ballGroup); + + // + + function onSelect() { + ballGroup.position.set(0, 0, -2).applyMatrix4(controller.matrixWorld); + ballGroup.quaternion.setFromRotationMatrix(controller.matrixWorld); + } + + controller = renderer.xr.getController(0); + controller.addEventListener('select', onSelect); + scene.add(controller); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +function animate() { + renderer.setAnimationLoop(render); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webxr_ar_plane_detection.ts b/examples-testing/examples/webxr_ar_plane_detection.ts new file mode 100644 index 000000000..0826cc3a6 --- /dev/null +++ b/examples-testing/examples/webxr_ar_plane_detection.ts @@ -0,0 +1,46 @@ +import * as THREE from 'three'; +import { ARButton } from 'three/addons/webxr/ARButton.js'; +import { XRPlanes } from 'three/addons/webxr/XRPlanes.js'; + +// + +const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); +renderer.setPixelRatio(window.devicePixelRatio); +renderer.setSize(window.innerWidth, window.innerHeight); +renderer.setAnimationLoop(render); +renderer.xr.enabled = true; +document.body.appendChild(renderer.domElement); + +document.body.appendChild( + ARButton.createButton(renderer, { + requiredFeatures: ['plane-detection'], + }), +); + +window.addEventListener('resize', onWindowResize); + +// + +const scene = new THREE.Scene(); + +const planes = new XRPlanes(renderer); +scene.add(planes); + +const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20); + +const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 3); +light.position.set(0.5, 1, 0.25); +scene.add(light); + +// + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webxr_vr_handinput.ts b/examples-testing/examples/webxr_vr_handinput.ts new file mode 100644 index 000000000..a896103ad --- /dev/null +++ b/examples-testing/examples/webxr_vr_handinput.ts @@ -0,0 +1,126 @@ +import * as THREE from 'three'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { VRButton } from 'three/addons/webxr/VRButton.js'; +import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js'; +import { XRHandModelFactory } from 'three/addons/webxr/XRHandModelFactory.js'; + +let container; +let camera, scene, renderer; +let hand1, hand2; +let controller1, controller2; +let controllerGrip1, controllerGrip2; + +let controls; + +init(); +animate(); + +function init() { + container = document.createElement('div'); + document.body.appendChild(container); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x444444); + + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 10); + camera.position.set(0, 1.6, 3); + + controls = new OrbitControls(camera, container); + controls.target.set(0, 1.6, 0); + controls.update(); + + const floorGeometry = new THREE.PlaneGeometry(4, 4); + const floorMaterial = new THREE.MeshStandardMaterial({ color: 0x666666 }); + const floor = new THREE.Mesh(floorGeometry, floorMaterial); + floor.rotation.x = -Math.PI / 2; + floor.receiveShadow = true; + scene.add(floor); + + scene.add(new THREE.HemisphereLight(0xbcbcbc, 0xa5a5a5, 3)); + + const light = new THREE.DirectionalLight(0xffffff, 3); + light.position.set(0, 6, 0); + light.castShadow = true; + light.shadow.camera.top = 2; + light.shadow.camera.bottom = -2; + light.shadow.camera.right = 2; + light.shadow.camera.left = -2; + light.shadow.mapSize.set(4096, 4096); + scene.add(light); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; + renderer.xr.enabled = true; + + container.appendChild(renderer.domElement); + + document.body.appendChild(VRButton.createButton(renderer)); + + // controllers + + controller1 = renderer.xr.getController(0); + scene.add(controller1); + + controller2 = renderer.xr.getController(1); + scene.add(controller2); + + const controllerModelFactory = new XRControllerModelFactory(); + const handModelFactory = new XRHandModelFactory(); + + // Hand 1 + controllerGrip1 = renderer.xr.getControllerGrip(0); + controllerGrip1.add(controllerModelFactory.createControllerModel(controllerGrip1)); + scene.add(controllerGrip1); + + hand1 = renderer.xr.getHand(0); + hand1.add(handModelFactory.createHandModel(hand1)); + + scene.add(hand1); + + // Hand 2 + controllerGrip2 = renderer.xr.getControllerGrip(1); + controllerGrip2.add(controllerModelFactory.createControllerModel(controllerGrip2)); + scene.add(controllerGrip2); + + hand2 = renderer.xr.getHand(1); + hand2.add(handModelFactory.createHandModel(hand2)); + scene.add(hand2); + + // + + const geometry = new THREE.BufferGeometry().setFromPoints([ + new THREE.Vector3(0, 0, 0), + new THREE.Vector3(0, 0, -1), + ]); + + const line = new THREE.Line(geometry); + line.name = 'line'; + line.scale.z = 5; + + controller1.add(line.clone()); + controller2.add(line.clone()); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} +// + +function animate() { + renderer.setAnimationLoop(render); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webxr_vr_panorama.ts b/examples-testing/examples/webxr_vr_panorama.ts new file mode 100644 index 000000000..fdd23aaa6 --- /dev/null +++ b/examples-testing/examples/webxr_vr_panorama.ts @@ -0,0 +1,96 @@ +import * as THREE from 'three'; +import { VRButton } from 'three/addons/webxr/VRButton.js'; + +let camera; +let renderer; +let scene; + +init(); +animate(); + +function init() { + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.xr.enabled = true; + renderer.xr.setReferenceSpaceType('local'); + document.body.appendChild(renderer.domElement); + + document.body.appendChild(VRButton.createButton(renderer)); + + // + + scene = new THREE.Scene(); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); + camera.layers.enable(1); + + const geometry = new THREE.BoxGeometry(100, 100, 100); + geometry.scale(1, 1, -1); + + const textures = getTexturesFromAtlasFile('textures/cube/sun_temple_stripe_stereo.jpg', 12); + + const materials = []; + + for (let i = 0; i < 6; i++) { + materials.push(new THREE.MeshBasicMaterial({ map: textures[i] })); + } + + const skyBox = new THREE.Mesh(geometry, materials); + skyBox.layers.set(1); + scene.add(skyBox); + + const materialsR = []; + + for (let i = 6; i < 12; i++) { + materialsR.push(new THREE.MeshBasicMaterial({ map: textures[i] })); + } + + const skyBoxR = new THREE.Mesh(geometry, materialsR); + skyBoxR.layers.set(2); + scene.add(skyBoxR); + + window.addEventListener('resize', onWindowResize); +} + +function getTexturesFromAtlasFile(atlasImgUrl, tilesNum) { + const textures = []; + + for (let i = 0; i < tilesNum; i++) { + textures[i] = new THREE.Texture(); + } + + const loader = new THREE.ImageLoader(); + loader.load(atlasImgUrl, function (imageObj) { + let canvas, context; + const tileWidth = imageObj.height; + + for (let i = 0; i < textures.length; i++) { + canvas = document.createElement('canvas'); + context = canvas.getContext('2d'); + canvas.height = tileWidth; + canvas.width = tileWidth; + context.drawImage(imageObj, tileWidth * i, 0, tileWidth, tileWidth, 0, 0, tileWidth, tileWidth); + textures[i].colorSpace = THREE.SRGBColorSpace; + textures[i].image = canvas; + textures[i].needsUpdate = true; + } + }); + + return textures; +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + renderer.setAnimationLoop(render); +} + +function render() { + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webxr_vr_panorama_depth.ts b/examples-testing/examples/webxr_vr_panorama_depth.ts new file mode 100644 index 000000000..a09b73344 --- /dev/null +++ b/examples-testing/examples/webxr_vr_panorama_depth.ts @@ -0,0 +1,94 @@ +import * as THREE from 'three'; +import { VRButton } from 'three/addons/webxr/VRButton.js'; + +let camera, scene, renderer, sphere, clock; + +init(); +animate(); + +function init() { + const container = document.getElementById('container'); + + clock = new THREE.Clock(); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x101010); + + const light = new THREE.AmbientLight(0xffffff, 3); + scene.add(light); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 2000); + scene.add(camera); + + // Create the panoramic sphere geometery + const panoSphereGeo = new THREE.SphereGeometry(6, 256, 256); + + // Create the panoramic sphere material + const panoSphereMat = new THREE.MeshStandardMaterial({ + side: THREE.BackSide, + displacementScale: -4.0, + }); + + // Create the panoramic sphere mesh + sphere = new THREE.Mesh(panoSphereGeo, panoSphereMat); + + // Load and assign the texture and depth map + const manager = new THREE.LoadingManager(); + const loader = new THREE.TextureLoader(manager); + + loader.load('./textures/kandao3.jpg', function (texture) { + texture.colorSpace = THREE.SRGBColorSpace; + texture.minFilter = THREE.NearestFilter; + texture.generateMipmaps = false; + sphere.material.map = texture; + }); + + loader.load('./textures/kandao3_depthmap.jpg', function (depth) { + depth.minFilter = THREE.NearestFilter; + depth.generateMipmaps = false; + sphere.material.displacementMap = depth; + }); + + // On load complete add the panoramic sphere to the scene + manager.onLoad = function () { + scene.add(sphere); + }; + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.xr.enabled = true; + renderer.xr.setReferenceSpaceType('local'); + container.appendChild(renderer.domElement); + + document.body.appendChild(VRButton.createButton(renderer)); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + renderer.setAnimationLoop(render); +} + +function render() { + // If we are not presenting move the camera a little so the effect is visible + + if (renderer.xr.isPresenting === false) { + const time = clock.getElapsedTime(); + + sphere.rotation.y += 0.001; + sphere.position.x = Math.sin(time) * 0.2; + sphere.position.z = Math.cos(time) * 0.2; + } + + renderer.render(scene, camera); +} diff --git a/examples-testing/examples/webxr_vr_rollercoaster.ts b/examples-testing/examples/webxr_vr_rollercoaster.ts new file mode 100644 index 000000000..b65965267 --- /dev/null +++ b/examples-testing/examples/webxr_vr_rollercoaster.ts @@ -0,0 +1,212 @@ +import * as THREE from 'three'; + +import { + RollerCoasterGeometry, + RollerCoasterShadowGeometry, + RollerCoasterLiftersGeometry, + TreesGeometry, + SkyGeometry, +} from 'three/addons/misc/RollerCoaster.js'; +import { VRButton } from 'three/addons/webxr/VRButton.js'; + +let mesh, material, geometry; + +const renderer = new THREE.WebGLRenderer({ antialias: true }); +renderer.setPixelRatio(window.devicePixelRatio); +renderer.setSize(window.innerWidth, window.innerHeight); +renderer.xr.enabled = true; +renderer.xr.setReferenceSpaceType('local'); +document.body.appendChild(renderer.domElement); + +document.body.appendChild(VRButton.createButton(renderer)); + +// + +const scene = new THREE.Scene(); +scene.background = new THREE.Color(0xf0f0ff); + +const light = new THREE.HemisphereLight(0xfff0f0, 0x60606, 3); +light.position.set(1, 1, 1); +scene.add(light); + +const train = new THREE.Object3D(); +scene.add(train); + +const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 500); +train.add(camera); + +// environment + +geometry = new THREE.PlaneGeometry(500, 500, 15, 15); +geometry.rotateX(-Math.PI / 2); + +const positions = geometry.attributes.position.array; +const vertex = new THREE.Vector3(); + +for (let i = 0; i < positions.length; i += 3) { + vertex.fromArray(positions, i); + + vertex.x += Math.random() * 10 - 5; + vertex.z += Math.random() * 10 - 5; + + const distance = vertex.distanceTo(scene.position) / 5 - 25; + vertex.y = Math.random() * Math.max(0, distance); + + vertex.toArray(positions, i); +} + +geometry.computeVertexNormals(); + +material = new THREE.MeshLambertMaterial({ + color: 0x407000, +}); + +mesh = new THREE.Mesh(geometry, material); +scene.add(mesh); + +geometry = new TreesGeometry(mesh); +material = new THREE.MeshBasicMaterial({ + side: THREE.DoubleSide, + vertexColors: true, +}); +mesh = new THREE.Mesh(geometry, material); +scene.add(mesh); + +geometry = new SkyGeometry(); +material = new THREE.MeshBasicMaterial({ color: 0xffffff }); +mesh = new THREE.Mesh(geometry, material); +scene.add(mesh); + +// + +const PI2 = Math.PI * 2; + +const curve = (function () { + const vector = new THREE.Vector3(); + const vector2 = new THREE.Vector3(); + + return { + getPointAt: function (t) { + t = t * PI2; + + const x = Math.sin(t * 3) * Math.cos(t * 4) * 50; + const y = Math.sin(t * 10) * 2 + Math.cos(t * 17) * 2 + 5; + const z = Math.sin(t) * Math.sin(t * 4) * 50; + + return vector.set(x, y, z).multiplyScalar(2); + }, + + getTangentAt: function (t) { + const delta = 0.0001; + const t1 = Math.max(0, t - delta); + const t2 = Math.min(1, t + delta); + + return vector2.copy(this.getPointAt(t2)).sub(this.getPointAt(t1)).normalize(); + }, + }; +})(); + +geometry = new RollerCoasterGeometry(curve, 1500); +material = new THREE.MeshPhongMaterial({ + vertexColors: true, +}); +mesh = new THREE.Mesh(geometry, material); +scene.add(mesh); + +geometry = new RollerCoasterLiftersGeometry(curve, 100); +material = new THREE.MeshPhongMaterial(); +mesh = new THREE.Mesh(geometry, material); +mesh.position.y = 0.1; +scene.add(mesh); + +geometry = new RollerCoasterShadowGeometry(curve, 500); +material = new THREE.MeshBasicMaterial({ + color: 0x305000, + depthWrite: false, + transparent: true, +}); +mesh = new THREE.Mesh(geometry, material); +mesh.position.y = 0.1; +scene.add(mesh); + +const funfairs = []; + +// + +geometry = new THREE.CylinderGeometry(10, 10, 5, 15); +material = new THREE.MeshLambertMaterial({ + color: 0xff8080, +}); +mesh = new THREE.Mesh(geometry, material); +mesh.position.set(-80, 10, -70); +mesh.rotation.x = Math.PI / 2; +scene.add(mesh); + +funfairs.push(mesh); + +geometry = new THREE.CylinderGeometry(5, 6, 4, 10); +material = new THREE.MeshLambertMaterial({ + color: 0x8080ff, +}); +mesh = new THREE.Mesh(geometry, material); +mesh.position.set(50, 2, 30); +scene.add(mesh); + +funfairs.push(mesh); + +// + +window.addEventListener('resize', onWindowResize); + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +// + +const position = new THREE.Vector3(); +const tangent = new THREE.Vector3(); + +const lookAt = new THREE.Vector3(); + +let velocity = 0; +let progress = 0; + +let prevTime = performance.now(); + +function render() { + const time = performance.now(); + const delta = time - prevTime; + + for (let i = 0; i < funfairs.length; i++) { + funfairs[i].rotation.y = time * 0.0004; + } + + // + + progress += velocity; + progress = progress % 1; + + position.copy(curve.getPointAt(progress)); + position.y += 0.3; + + train.position.copy(position); + + tangent.copy(curve.getTangentAt(progress)); + + velocity -= tangent.y * 0.0000001 * delta; + velocity = Math.max(0.00004, Math.min(0.0002, velocity)); + + train.lookAt(lookAt.copy(position).sub(tangent)); + + // + + renderer.render(scene, camera); + + prevTime = time; +} + +renderer.setAnimationLoop(render); diff --git a/examples-testing/examples/webxr_vr_sandbox.ts b/examples-testing/examples/webxr_vr_sandbox.ts new file mode 100644 index 000000000..aa80cf762 --- /dev/null +++ b/examples-testing/examples/webxr_vr_sandbox.ts @@ -0,0 +1,209 @@ +import * as THREE from 'three'; + +import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'; +import { Lensflare, LensflareElement } from 'three/addons/objects/Lensflare.js'; +import { Reflector } from 'three/addons/objects/Reflector.js'; +import { VRButton } from 'three/addons/webxr/VRButton.js'; + +import { HTMLMesh } from 'three/addons/interactive/HTMLMesh.js'; +import { InteractiveGroup } from 'three/addons/interactive/InteractiveGroup.js'; +import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js'; + +import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; +import Stats from 'three/addons/libs/stats.module.js'; + +let camera, scene, renderer; +let reflector; +let stats, statsMesh; + +const parameters = { + radius: 0.6, + tube: 0.2, + tubularSegments: 150, + radialSegments: 20, + p: 2, + q: 3, + thickness: 0.5, +}; + +init(); +animate(); + +function init() { + scene = new THREE.Scene(); + + new RGBELoader().setPath('textures/equirectangular/').load('moonless_golf_1k.hdr', function (texture) { + texture.mapping = THREE.EquirectangularReflectionMapping; + + scene.background = texture; + scene.environment = texture; + }); + + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 10); + camera.position.set(0, 1.6, 1.5); + + // + + const torusGeometry = new THREE.TorusKnotGeometry(...Object.values(parameters)); + const torusMaterial = new THREE.MeshPhysicalMaterial({ + transmission: 1.0, + roughness: 0, + metalness: 0.25, + thickness: 0.5, + side: THREE.DoubleSide, + }); + const torus = new THREE.Mesh(torusGeometry, torusMaterial); + torus.name = 'torus'; + torus.position.y = 1.5; + torus.position.z = -2; + scene.add(torus); + + const cylinderGeometry = new THREE.CylinderGeometry(1, 1, 0.1, 50); + const cylinderMaterial = new THREE.MeshStandardMaterial(); + const cylinder = new THREE.Mesh(cylinderGeometry, cylinderMaterial); + cylinder.position.z = -2; + scene.add(cylinder); + + // lensflare + const loader = new THREE.TextureLoader(); + const texture0 = loader.load('textures/lensflare/lensflare0.png'); + const texture3 = loader.load('textures/lensflare/lensflare3.png'); + + const lensflare = new Lensflare(); + lensflare.position.set(0, 5, -5); + lensflare.addElement(new LensflareElement(texture0, 700, 0)); + lensflare.addElement(new LensflareElement(texture3, 60, 0.6)); + lensflare.addElement(new LensflareElement(texture3, 70, 0.7)); + lensflare.addElement(new LensflareElement(texture3, 120, 0.9)); + lensflare.addElement(new LensflareElement(texture3, 70, 1)); + scene.add(lensflare); + + // + + reflector = new Reflector(new THREE.PlaneGeometry(2, 2), { + textureWidth: window.innerWidth * window.devicePixelRatio, + textureHeight: window.innerHeight * window.devicePixelRatio, + }); + reflector.position.x = 1; + reflector.position.y = 1.5; + reflector.position.z = -3; + reflector.rotation.y = -Math.PI / 4; + // TOFIX: Reflector breaks transmission + // scene.add( reflector ); + + const frameGeometry = new THREE.BoxGeometry(2.1, 2.1, 0.1); + const frameMaterial = new THREE.MeshPhongMaterial(); + const frame = new THREE.Mesh(frameGeometry, frameMaterial); + frame.position.z = -0.07; + reflector.add(frame); + + // + + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.autoClear = false; + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.xr.enabled = true; + renderer.toneMapping = THREE.ACESFilmicToneMapping; + renderer.toneMappingExposure = 1; + document.body.appendChild(renderer.domElement); + + document.body.appendChild(VRButton.createButton(renderer)); + + window.addEventListener('resize', onWindowResize); + + // + + const geometry = new THREE.BufferGeometry(); + geometry.setFromPoints([new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, -5)]); + + const controller1 = renderer.xr.getController(0); + controller1.add(new THREE.Line(geometry)); + scene.add(controller1); + + const controller2 = renderer.xr.getController(1); + controller2.add(new THREE.Line(geometry)); + scene.add(controller2); + + // + + const controllerModelFactory = new XRControllerModelFactory(); + + const controllerGrip1 = renderer.xr.getControllerGrip(0); + controllerGrip1.add(controllerModelFactory.createControllerModel(controllerGrip1)); + scene.add(controllerGrip1); + + const controllerGrip2 = renderer.xr.getControllerGrip(1); + controllerGrip2.add(controllerModelFactory.createControllerModel(controllerGrip2)); + scene.add(controllerGrip2); + + // GUI + + function onChange() { + torus.geometry.dispose(); + torus.geometry = new THREE.TorusKnotGeometry(...Object.values(parameters)); + } + + function onThicknessChange() { + torus.material.thickness = parameters.thickness; + } + + const gui = new GUI({ width: 300 }); + gui.add(parameters, 'radius', 0.0, 1.0).onChange(onChange); + gui.add(parameters, 'tube', 0.0, 1.0).onChange(onChange); + gui.add(parameters, 'tubularSegments', 10, 150, 1).onChange(onChange); + gui.add(parameters, 'radialSegments', 2, 20, 1).onChange(onChange); + gui.add(parameters, 'p', 1, 10, 1).onChange(onChange); + gui.add(parameters, 'q', 0, 10, 1).onChange(onChange); + gui.add(parameters, 'thickness', 0, 1).onChange(onThicknessChange); + gui.domElement.style.visibility = 'hidden'; + + const group = new InteractiveGroup(renderer, camera); + scene.add(group); + + const mesh = new HTMLMesh(gui.domElement); + mesh.position.x = -0.75; + mesh.position.y = 1.5; + mesh.position.z = -0.5; + mesh.rotation.y = Math.PI / 4; + mesh.scale.setScalar(2); + group.add(mesh); + + // Add stats.js + stats = new Stats(); + stats.dom.style.width = '80px'; + stats.dom.style.height = '48px'; + document.body.appendChild(stats.dom); + + statsMesh = new HTMLMesh(stats.dom); + statsMesh.position.x = -0.75; + statsMesh.position.y = 2; + statsMesh.position.z = -0.6; + statsMesh.rotation.y = Math.PI / 4; + statsMesh.scale.setScalar(2.5); + group.add(statsMesh); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + renderer.setAnimationLoop(render); +} + +function render() { + const time = performance.now() * 0.0002; + const torus = scene.getObjectByName('torus'); + torus.rotation.x = time * 0.4; + torus.rotation.y = time; + + renderer.render(scene, camera); + stats.update(); + + // Canvas elements doesn't trigger DOM updates, so we have to update the texture + statsMesh.material.map.update(); +} diff --git a/examples-testing/examples/webxr_vr_video.ts b/examples-testing/examples/webxr_vr_video.ts new file mode 100644 index 000000000..2baded481 --- /dev/null +++ b/examples-testing/examples/webxr_vr_video.ts @@ -0,0 +1,96 @@ +import * as THREE from 'three'; +import { VRButton } from 'three/addons/webxr/VRButton.js'; + +let camera, scene, renderer; + +init(); +animate(); + +function init() { + const container = document.getElementById('container'); + container.addEventListener('click', function () { + video.play(); + }); + + camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 2000); + camera.layers.enable(1); // render left view when no stereo available + + // video + + const video = document.getElementById('video'); + video.play(); + + const texture = new THREE.VideoTexture(video); + texture.colorSpace = THREE.SRGBColorSpace; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0x101010); + + // left + + const geometry1 = new THREE.SphereGeometry(500, 60, 40); + // invert the geometry on the x-axis so that all of the faces point inward + geometry1.scale(-1, 1, 1); + + const uvs1 = geometry1.attributes.uv.array; + + for (let i = 0; i < uvs1.length; i += 2) { + uvs1[i] *= 0.5; + } + + const material1 = new THREE.MeshBasicMaterial({ map: texture }); + + const mesh1 = new THREE.Mesh(geometry1, material1); + mesh1.rotation.y = -Math.PI / 2; + mesh1.layers.set(1); // display in left eye only + scene.add(mesh1); + + // right + + const geometry2 = new THREE.SphereGeometry(500, 60, 40); + geometry2.scale(-1, 1, 1); + + const uvs2 = geometry2.attributes.uv.array; + + for (let i = 0; i < uvs2.length; i += 2) { + uvs2[i] *= 0.5; + uvs2[i] += 0.5; + } + + const material2 = new THREE.MeshBasicMaterial({ map: texture }); + + const mesh2 = new THREE.Mesh(geometry2, material2); + mesh2.rotation.y = -Math.PI / 2; + mesh2.layers.set(2); // display in right eye only + scene.add(mesh2); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.xr.enabled = true; + renderer.xr.setReferenceSpaceType('local'); + container.appendChild(renderer.domElement); + + document.body.appendChild(VRButton.createButton(renderer)); + + // + + window.addEventListener('resize', onWindowResize); +} + +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() { + renderer.setAnimationLoop(render); +} + +function render() { + renderer.render(scene, camera); +} From 1b714d462839a992c4d6687d6163e128c15d9439 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Thu, 27 Jul 2023 22:12:47 -0400 Subject: [PATCH 4/5] Update patch --- examples-testing/changes.patch | 720 ++++++++++++++------------------- 1 file changed, 296 insertions(+), 424 deletions(-) diff --git a/examples-testing/changes.patch b/examples-testing/changes.patch index f713a4433..2db1a5162 100644 --- a/examples-testing/changes.patch +++ b/examples-testing/changes.patch @@ -1,5 +1,5 @@ diff --git a/examples-testing/examples/css2d_label.ts b/examples-testing/examples/css2d_label.ts -index 24c45ad..1eb439f 100644 +index 48a2d1f..e726021 100644 --- a/examples-testing/examples/css2d_label.ts +++ b/examples-testing/examples/css2d_label.ts @@ -7,7 +7,7 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; @@ -155,7 +155,7 @@ index 5384726..f08bb34 100644 const atom = document.createElement('img'); atom.src = colorSprite; diff --git a/examples-testing/examples/css3d_orthographic.ts b/examples-testing/examples/css3d_orthographic.ts -index 39bcf17..c6d998b 100644 +index 4aabbed..5488635 100644 --- a/examples-testing/examples/css3d_orthographic.ts +++ b/examples-testing/examples/css3d_orthographic.ts @@ -3,10 +3,11 @@ import * as THREE from 'three'; @@ -172,7 +172,7 @@ index 39bcf17..c6d998b 100644 const frustumSize = 500; -@@ -76,18 +77,18 @@ function init() { +@@ -75,18 +76,18 @@ function init() { renderer2 = new CSS3DRenderer(); renderer2.setSize(window.innerWidth, window.innerHeight); renderer2.domElement.style.position = 'absolute'; @@ -194,7 +194,7 @@ index 39bcf17..c6d998b 100644 element.style.background = cssColor; const object = new CSS3DObject(element); -@@ -134,12 +135,12 @@ function createPanel() { +@@ -133,12 +134,12 @@ function createPanel() { const settings = { setViewOffset() { @@ -213,7 +213,7 @@ index 39bcf17..c6d998b 100644 }, fullWidth: 0, fullHeight: 0, -@@ -148,12 +149,12 @@ function createPanel() { +@@ -147,12 +148,12 @@ function createPanel() { width: 0, height: 0, clearViewOffset() { @@ -232,7 +232,7 @@ index 39bcf17..c6d998b 100644 camera.clearViewOffset(); }, }; -@@ -161,32 +162,46 @@ function createPanel() { +@@ -160,32 +161,46 @@ function createPanel() { folder1.add(settings, 'setViewOffset'); folder1 .add(settings, 'fullWidth', window.screen.width / 4, window.screen.width * 2, 1) @@ -392,7 +392,7 @@ index e3a33f7..516df46 100644 .onUpdate(render) .start(); diff --git a/examples-testing/examples/css3d_sandbox.ts b/examples-testing/examples/css3d_sandbox.ts -index 6b9efbb..8d241c1 100644 +index 1088b84..b910c1f 100644 --- a/examples-testing/examples/css3d_sandbox.ts +++ b/examples-testing/examples/css3d_sandbox.ts @@ -2,13 +2,13 @@ import * as THREE from 'three'; @@ -422,7 +422,7 @@ index 6b9efbb..8d241c1 100644 element.style.background = new THREE.Color(Math.random() * 0xffffff).getStyle(); const object = new CSS3DObject(element); -@@ -68,7 +68,7 @@ function init() { +@@ -67,7 +67,7 @@ function init() { renderer2 = new CSS3DRenderer(); renderer2.setSize(window.innerWidth, window.innerHeight); renderer2.domElement.style.position = 'absolute'; @@ -431,7 +431,7 @@ index 6b9efbb..8d241c1 100644 document.body.appendChild(renderer2.domElement); controls = new TrackballControls(camera, renderer2.domElement); -@@ -102,12 +102,12 @@ function createPanel() { +@@ -101,12 +101,12 @@ function createPanel() { const settings = { setViewOffset() { @@ -450,7 +450,7 @@ index 6b9efbb..8d241c1 100644 }, fullWidth: 0, fullHeight: 0, -@@ -116,12 +116,12 @@ function createPanel() { +@@ -115,12 +115,12 @@ function createPanel() { width: 0, height: 0, clearViewOffset() { @@ -469,7 +469,7 @@ index 6b9efbb..8d241c1 100644 camera.clearViewOffset(); }, }; -@@ -129,32 +129,46 @@ function createPanel() { +@@ -128,32 +128,46 @@ function createPanel() { folder1.add(settings, 'setViewOffset'); folder1 .add(settings, 'fullWidth', window.screen.width / 4, window.screen.width * 2, 1) @@ -623,7 +623,7 @@ index 62652f8..3dcc2f1 100644 controls.addEventListener('start', function () { diff --git a/examples-testing/examples/games_fps.ts b/examples-testing/examples/games_fps.ts -index a37faaa..9b1e817 100644 +index 49d31e7..8398b56 100644 --- a/examples-testing/examples/games_fps.ts +++ b/examples-testing/examples/games_fps.ts @@ -39,7 +39,7 @@ directionalLight.shadow.radius = 4; @@ -635,7 +635,7 @@ index a37faaa..9b1e817 100644 const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setPixelRatio(window.devicePixelRatio); -@@ -51,9 +51,9 @@ renderer.useLegacyLights = false; +@@ -50,9 +50,9 @@ renderer.toneMapping = THREE.ACESFilmicToneMapping; container.appendChild(renderer.domElement); const stats = new Stats(); @@ -648,7 +648,7 @@ index a37faaa..9b1e817 100644 const GRAVITY = 30; -@@ -65,7 +65,13 @@ const STEPS_PER_FRAME = 5; +@@ -64,7 +64,13 @@ const STEPS_PER_FRAME = 5; const sphereGeometry = new THREE.IcosahedronGeometry(SPHERE_RADIUS, 5); const sphereMaterial = new THREE.MeshLambertMaterial({ color: 0xdede8d }); @@ -663,7 +663,7 @@ index a37faaa..9b1e817 100644 let sphereIdx = 0; for (let i = 0; i < NUM_SPHERES; i++) { -@@ -92,7 +98,7 @@ const playerDirection = new THREE.Vector3(); +@@ -91,7 +97,7 @@ const playerDirection = new THREE.Vector3(); let playerOnFloor = false; let mouseTime = 0; @@ -672,7 +672,7 @@ index a37faaa..9b1e817 100644 const vector1 = new THREE.Vector3(); const vector2 = new THREE.Vector3(); -@@ -165,7 +171,7 @@ function playerCollisions() { +@@ -164,7 +170,7 @@ function playerCollisions() { } } @@ -681,7 +681,7 @@ index a37faaa..9b1e817 100644 let damping = Math.exp(-4 * deltaTime) - 1; if (!playerOnFloor) { -@@ -185,7 +191,7 @@ function updatePlayer(deltaTime) { +@@ -184,7 +190,7 @@ function updatePlayer(deltaTime) { camera.position.copy(playerCollider.end); } @@ -690,7 +690,7 @@ index a37faaa..9b1e817 100644 const center = vector1.addVectors(playerCollider.start, playerCollider.end).multiplyScalar(0.5); const sphere_center = sphere.collider.center; -@@ -240,7 +246,7 @@ function spheresCollisions() { +@@ -239,7 +245,7 @@ function spheresCollisions() { } } @@ -699,7 +699,7 @@ index a37faaa..9b1e817 100644 spheres.forEach(sphere => { sphere.collider.center.addScaledVector(sphere.velocity, deltaTime); -@@ -283,7 +289,7 @@ function getSideVector() { +@@ -282,7 +288,7 @@ function getSideVector() { return playerDirection; } @@ -708,7 +708,7 @@ index a37faaa..9b1e817 100644 // gives a bit of air control const speedDelta = deltaTime * (playerOnFloor ? 25 : 8); -@@ -318,12 +324,12 @@ loader.load('collision-world.glb', gltf => { +@@ -317,12 +323,12 @@ loader.load('collision-world.glb', gltf => { worldOctree.fromGraphNode(gltf.scene); gltf.scene.traverse(child => { @@ -724,7 +724,7 @@ index a37faaa..9b1e817 100644 } } }); -@@ -333,7 +339,7 @@ loader.load('collision-world.glb', gltf => { +@@ -332,7 +338,7 @@ loader.load('collision-world.glb', gltf => { scene.add(helper); const gui = new GUI({ width: 200 }); @@ -734,7 +734,7 @@ index a37faaa..9b1e817 100644 }); diff --git a/examples-testing/examples/misc_animation_groups.ts b/examples-testing/examples/misc_animation_groups.ts -index e882045..17c6a3a 100644 +index 19d263f..f8d0bed 100644 --- a/examples-testing/examples/misc_animation_groups.ts +++ b/examples-testing/examples/misc_animation_groups.ts @@ -2,8 +2,8 @@ import * as THREE from 'three'; @@ -749,7 +749,7 @@ index e882045..17c6a3a 100644 init(); animate(); diff --git a/examples-testing/examples/misc_animation_keys.ts b/examples-testing/examples/misc_animation_keys.ts -index 0c678e2..f0313a0 100644 +index 4a80898..d2613d0 100644 --- a/examples-testing/examples/misc_animation_keys.ts +++ b/examples-testing/examples/misc_animation_keys.ts @@ -2,8 +2,8 @@ import * as THREE from 'three'; @@ -776,7 +776,7 @@ index 0c678e2..f0313a0 100644 scene.add(mesh); diff --git a/examples-testing/examples/misc_boxselection.ts b/examples-testing/examples/misc_boxselection.ts -index 2e2ac51..fc58453 100644 +index 8766c55..f70f4fc 100644 --- a/examples-testing/examples/misc_boxselection.ts +++ b/examples-testing/examples/misc_boxselection.ts @@ -5,8 +5,8 @@ import Stats from 'three/addons/libs/stats.module.js'; @@ -790,7 +790,7 @@ index 2e2ac51..fc58453 100644 init(); animate(); -@@ -93,12 +93,12 @@ function render() { +@@ -92,12 +92,12 @@ function render() { renderer.render(scene, camera); } @@ -806,7 +806,7 @@ index 2e2ac51..fc58453 100644 } selectionBox.startPoint.set( -@@ -111,7 +111,7 @@ document.addEventListener('pointerdown', function (event) { +@@ -110,7 +110,7 @@ document.addEventListener('pointerdown', function (event) { document.addEventListener('pointermove', function (event) { if (helper.isDown) { for (let i = 0; i < selectionBox.collection.length; i++) { @@ -815,7 +815,7 @@ index 2e2ac51..fc58453 100644 } selectionBox.endPoint.set( -@@ -123,7 +123,7 @@ document.addEventListener('pointermove', function (event) { +@@ -122,7 +122,7 @@ document.addEventListener('pointermove', function (event) { const allSelected = selectionBox.select(); for (let i = 0; i < allSelected.length; i++) { @@ -824,7 +824,7 @@ index 2e2ac51..fc58453 100644 } } }); -@@ -138,6 +138,6 @@ document.addEventListener('pointerup', function (event) { +@@ -137,6 +137,6 @@ document.addEventListener('pointerup', function (event) { const allSelected = selectionBox.select(); for (let i = 0; i < allSelected.length; i++) { @@ -833,7 +833,7 @@ index 2e2ac51..fc58453 100644 } }); diff --git a/examples-testing/examples/misc_controls_arcball.ts b/examples-testing/examples/misc_controls_arcball.ts -index 923d07b..d8e4db0 100644 +index fbef331..be69ca7 100644 --- a/examples-testing/examples/misc_controls_arcball.ts +++ b/examples-testing/examples/misc_controls_arcball.ts @@ -12,8 +12,12 @@ const cameraType = { type: 'Perspective' }; @@ -851,7 +851,7 @@ index 923d07b..d8e4db0 100644 const arcballGui = { gizmoVisible: true, -@@ -98,8 +102,8 @@ function init() { +@@ -97,8 +101,8 @@ function init() { material.normalMap.wrapS = THREE.RepeatWrapping; group.traverse(function (child) { @@ -862,7 +862,7 @@ index 923d07b..d8e4db0 100644 } }); -@@ -165,12 +169,12 @@ function onWindowResize() { +@@ -164,12 +168,12 @@ function onWindowResize() { const halfW = perspectiveDistance * Math.tan(halfFovH); const halfH = perspectiveDistance * Math.tan(halfFovV); @@ -880,7 +880,7 @@ index 923d07b..d8e4db0 100644 } camera.updateProjectionMatrix(); -@@ -184,7 +188,7 @@ function render() { +@@ -183,7 +187,7 @@ function render() { renderer.render(scene, camera); } @@ -889,7 +889,7 @@ index 923d07b..d8e4db0 100644 if (event.key === 'c') { if (event.ctrlKey || event.metaKey) { controls.copyState(); -@@ -196,7 +200,7 @@ function onKeyDown(event) { +@@ -195,7 +199,7 @@ function onKeyDown(event) { } } @@ -899,7 +899,7 @@ index 923d07b..d8e4db0 100644 camera = makeOrthographicCamera(); camera.position.set(0, 0, orthographicDistance); diff --git a/examples-testing/examples/misc_controls_drag.ts b/examples-testing/examples/misc_controls_drag.ts -index 131fa6b..555fb1e 100644 +index 5036ab7..8522f7d 100644 --- a/examples-testing/examples/misc_controls_drag.ts +++ b/examples-testing/examples/misc_controls_drag.ts @@ -2,12 +2,12 @@ import * as THREE from 'three'; @@ -919,7 +919,7 @@ index 131fa6b..555fb1e 100644 const mouse = new THREE.Vector2(), raycaster = new THREE.Raycaster(); -@@ -98,7 +98,7 @@ function onWindowResize() { +@@ -97,7 +97,7 @@ function onWindowResize() { render(); } @@ -928,7 +928,7 @@ index 131fa6b..555fb1e 100644 enableSelection = event.keyCode === 16 ? true : false; } -@@ -106,7 +106,7 @@ function onKeyUp() { +@@ -105,7 +105,7 @@ function onKeyUp() { enableSelection = false; } @@ -937,7 +937,7 @@ index 131fa6b..555fb1e 100644 event.preventDefault(); if (enableSelection === true) { -@@ -124,10 +124,10 @@ function onClick(event) { +@@ -123,10 +123,10 @@ function onClick(event) { const object = intersections[0].object; if (group.children.includes(object) === true) { @@ -951,7 +951,7 @@ index 131fa6b..555fb1e 100644 } diff --git a/examples-testing/examples/misc_controls_fly.ts b/examples-testing/examples/misc_controls_fly.ts -index dd48a63..b13530a 100644 +index 694942d..4275504 100644 --- a/examples-testing/examples/misc_controls_fly.ts +++ b/examples-testing/examples/misc_controls_fly.ts @@ -19,11 +19,15 @@ const MARGIN = 0; @@ -1002,7 +1002,7 @@ index dd48a63..b13530a 100644 meshMoon = new THREE.Mesh(geometry, materialMoon); meshMoon.position.set(radius * 5, 0, 0); diff --git a/examples-testing/examples/misc_controls_map.ts b/examples-testing/examples/misc_controls_map.ts -index 943098e..c41b797 100644 +index d0d6279..7ed0ea4 100644 --- a/examples-testing/examples/misc_controls_map.ts +++ b/examples-testing/examples/misc_controls_map.ts @@ -4,7 +4,7 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; @@ -1015,7 +1015,7 @@ index 943098e..c41b797 100644 init(); //render(); // remove when using next line for animation loop (requestAnimationFrame) diff --git a/examples-testing/examples/misc_controls_orbit.ts b/examples-testing/examples/misc_controls_orbit.ts -index a6dd046..610447c 100644 +index fc29383..9f4a806 100644 --- a/examples-testing/examples/misc_controls_orbit.ts +++ b/examples-testing/examples/misc_controls_orbit.ts @@ -2,7 +2,7 @@ import * as THREE from 'three'; @@ -1028,7 +1028,7 @@ index a6dd046..610447c 100644 init(); //render(); // remove when using next line for animation loop (requestAnimationFrame) diff --git a/examples-testing/examples/misc_controls_pointerlock.ts b/examples-testing/examples/misc_controls_pointerlock.ts -index 9c3138f..c075d08 100644 +index 72ea08f..cf0142d 100644 --- a/examples-testing/examples/misc_controls_pointerlock.ts +++ b/examples-testing/examples/misc_controls_pointerlock.ts @@ -2,11 +2,11 @@ import * as THREE from 'three'; @@ -1098,7 +1098,7 @@ index 9c3138f..c075d08 100644 const box = new THREE.Mesh(boxGeometry, boxMaterial); diff --git a/examples-testing/examples/misc_controls_trackball.ts b/examples-testing/examples/misc_controls_trackball.ts -index 2e398e6..fb903c8 100644 +index 88d0541..94f66ac 100644 --- a/examples-testing/examples/misc_controls_trackball.ts +++ b/examples-testing/examples/misc_controls_trackball.ts @@ -5,7 +5,12 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; @@ -1115,7 +1115,7 @@ index 2e398e6..fb903c8 100644 const params = { orthographicCamera: false, -@@ -80,7 +85,7 @@ function init() { +@@ -79,7 +84,7 @@ function init() { const gui = new GUI(); gui.add(params, 'orthographicCamera') .name('use orthographic') @@ -1124,7 +1124,7 @@ index 2e398e6..fb903c8 100644 controls.dispose(); createControls(value ? orthographicCamera : perspectiveCamera); -@@ -93,7 +98,7 @@ function init() { +@@ -92,7 +97,7 @@ function init() { createControls(perspectiveCamera); } @@ -1134,7 +1134,7 @@ index 2e398e6..fb903c8 100644 controls.rotateSpeed = 1.0; diff --git a/examples-testing/examples/misc_controls_transform.ts b/examples-testing/examples/misc_controls_transform.ts -index 596e8bc..e49ef59 100644 +index abc4657..4254e08 100644 --- a/examples-testing/examples/misc_controls_transform.ts +++ b/examples-testing/examples/misc_controls_transform.ts @@ -3,8 +3,8 @@ import * as THREE from 'three'; @@ -1148,7 +1148,7 @@ index 596e8bc..e49ef59 100644 init(); render(); -@@ -87,7 +87,9 @@ function init() { +@@ -86,7 +86,9 @@ function init() { case 67: // C const position = currentCamera.position.clone(); @@ -1160,7 +1160,7 @@ index 596e8bc..e49ef59 100644 orbit.object = currentCamera; diff --git a/examples-testing/examples/misc_exporter_draco.ts b/examples-testing/examples/misc_exporter_draco.ts -index 4fb3cdb..6b0e1be 100644 +index d6a4535..63dab8d 100644 --- a/examples-testing/examples/misc_exporter_draco.ts +++ b/examples-testing/examples/misc_exporter_draco.ts @@ -4,7 +4,11 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; @@ -1176,7 +1176,7 @@ index 4fb3cdb..6b0e1be 100644 const params = { export: exportFile, -@@ -108,12 +112,12 @@ const link = document.createElement('a'); +@@ -107,12 +111,12 @@ const link = document.createElement('a'); link.style.display = 'none'; document.body.appendChild(link); @@ -1192,7 +1192,7 @@ index 4fb3cdb..6b0e1be 100644 save(new Blob([buffer], { type: 'application/octet-stream' }), filename); } diff --git a/examples-testing/examples/misc_exporter_gltf.ts b/examples-testing/examples/misc_exporter_gltf.ts -index f7d5624..bc5c478 100644 +index 47c8712..7c7ff78 100644 --- a/examples-testing/examples/misc_exporter_gltf.ts +++ b/examples-testing/examples/misc_exporter_gltf.ts @@ -6,7 +6,7 @@ import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'; @@ -1246,7 +1246,7 @@ index f7d5624..bc5c478 100644 const params = { trs: false, diff --git a/examples-testing/examples/misc_exporter_obj.ts b/examples-testing/examples/misc_exporter_obj.ts -index 2361ae4..522d4f0 100644 +index c315294..384af61 100644 --- a/examples-testing/examples/misc_exporter_obj.ts +++ b/examples-testing/examples/misc_exporter_obj.ts @@ -4,7 +4,7 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; @@ -1258,7 +1258,7 @@ index 2361ae4..522d4f0 100644 const params = { addTriangle: addTriangle, -@@ -67,12 +67,12 @@ function exportToObj() { +@@ -66,12 +66,12 @@ function exportToObj() { saveString(result, 'object.obj'); } @@ -1274,7 +1274,7 @@ index 2361ae4..522d4f0 100644 scene.remove(child); i--; } -@@ -157,13 +157,13 @@ const link = document.createElement('a'); +@@ -156,13 +156,13 @@ const link = document.createElement('a'); link.style.display = 'none'; document.body.appendChild(link); @@ -1291,7 +1291,7 @@ index 2361ae4..522d4f0 100644 } diff --git a/examples-testing/examples/misc_exporter_ply.ts b/examples-testing/examples/misc_exporter_ply.ts -index bb381fa..7ab5278 100644 +index 997c4f1..b860682 100644 --- a/examples-testing/examples/misc_exporter_ply.ts +++ b/examples-testing/examples/misc_exporter_ply.ts @@ -4,7 +4,11 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; @@ -1307,7 +1307,7 @@ index bb381fa..7ab5278 100644 const params = { exportASCII: exportASCII, -@@ -143,16 +147,16 @@ const link = document.createElement('a'); +@@ -142,16 +146,16 @@ const link = document.createElement('a'); link.style.display = 'none'; document.body.appendChild(link); @@ -1328,7 +1328,7 @@ index bb381fa..7ab5278 100644 save(new Blob([buffer], { type: 'application/octet-stream' }), filename); } diff --git a/examples-testing/examples/misc_exporter_stl.ts b/examples-testing/examples/misc_exporter_stl.ts -index 373aaab..4f1e683 100644 +index ad6e3f5..3eec71e 100644 --- a/examples-testing/examples/misc_exporter_stl.ts +++ b/examples-testing/examples/misc_exporter_stl.ts @@ -4,7 +4,11 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; @@ -1344,7 +1344,7 @@ index 373aaab..4f1e683 100644 const params = { exportASCII: exportASCII, -@@ -116,16 +120,16 @@ const link = document.createElement('a'); +@@ -115,16 +119,16 @@ const link = document.createElement('a'); link.style.display = 'none'; document.body.appendChild(link); @@ -1365,7 +1365,7 @@ index 373aaab..4f1e683 100644 save(new Blob([buffer], { type: 'application/octet-stream' }), filename); } diff --git a/examples-testing/examples/misc_exporter_usdz.ts b/examples-testing/examples/misc_exporter_usdz.ts -index e4853b3..0303273 100644 +index 97630ab..1cbb2e6 100644 --- a/examples-testing/examples/misc_exporter_usdz.ts +++ b/examples-testing/examples/misc_exporter_usdz.ts @@ -6,7 +6,7 @@ import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js'; @@ -1377,7 +1377,7 @@ index e4853b3..0303273 100644 init(); render(); -@@ -46,7 +46,7 @@ function init() { +@@ -45,7 +45,7 @@ function init() { const arraybuffer = await exporter.parse(gltf.scene); const blob = new Blob([arraybuffer], { type: 'application/octet-stream' }); @@ -1386,7 +1386,7 @@ index e4853b3..0303273 100644 link.href = URL.createObjectURL(blob); }); -@@ -65,7 +65,7 @@ function createSpotShadowMesh() { +@@ -64,7 +64,7 @@ function createSpotShadowMesh() { canvas.width = 128; canvas.height = 128; @@ -1396,7 +1396,7 @@ index e4853b3..0303273 100644 canvas.width / 2, canvas.height / 2, diff --git a/examples-testing/examples/misc_lookat.ts b/examples-testing/examples/misc_lookat.ts -index 44d3006..4a34f9a 100644 +index f6241b9..93e8340 100644 --- a/examples-testing/examples/misc_lookat.ts +++ b/examples-testing/examples/misc_lookat.ts @@ -2,9 +2,9 @@ import * as THREE from 'three'; @@ -1411,7 +1411,7 @@ index 44d3006..4a34f9a 100644 let mouseX = 0, mouseY = 0; -@@ -65,7 +65,7 @@ function onWindowResize() { +@@ -64,7 +64,7 @@ function onWindowResize() { renderer.setSize(window.innerWidth, window.innerHeight); } @@ -1434,7 +1434,7 @@ index 4f782d4..0759cfc 100644 d.innerHTML = '

' + name + '

'; diff --git a/examples-testing/examples/physics_ammo_instancing.ts b/examples-testing/examples/physics_ammo_instancing.ts -index 9a4e034..e02ae14 100644 +index fdfc815..1eede4e 100644 --- a/examples-testing/examples/physics_ammo_instancing.ts +++ b/examples-testing/examples/physics_ammo_instancing.ts @@ -1,12 +1,12 @@ @@ -1455,7 +1455,7 @@ index 9a4e034..e02ae14 100644 init(); diff --git a/examples-testing/examples/physics_rapier_instancing.ts b/examples-testing/examples/physics_rapier_instancing.ts -index aa612a9..59244c0 100644 +index 42116a6..1e9811b 100644 --- a/examples-testing/examples/physics_rapier_instancing.ts +++ b/examples-testing/examples/physics_rapier_instancing.ts @@ -1,12 +1,12 @@ @@ -1574,7 +1574,7 @@ index e6be838..faea9a7 100644 node.appendChild(doc.documentElement); diff --git a/examples-testing/examples/webaudio_orientation.ts b/examples-testing/examples/webaudio_orientation.ts -index 5a15d35..20a0dfd 100644 +index d5cff39..06315a2 100644 --- a/examples-testing/examples/webaudio_orientation.ts +++ b/examples-testing/examples/webaudio_orientation.ts @@ -4,16 +4,16 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; @@ -1636,7 +1636,7 @@ index 5a15d35..20a0dfd 100644 const wall = new THREE.Mesh(wallGeometry, wallMaterial); wall.position.set(0, 0.5, -0.5); diff --git a/examples-testing/examples/webaudio_sandbox.ts b/examples-testing/examples/webaudio_sandbox.ts -index 1fe2921..bd250db 100644 +index 56bd042..b200423 100644 --- a/examples-testing/examples/webaudio_sandbox.ts +++ b/examples-testing/examples/webaudio_sandbox.ts @@ -4,19 +4,23 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; @@ -1739,16 +1739,8 @@ index 1fe2921..bd250db 100644 const gui = new GUI(); const soundControls = new SoundControls(); -@@ -193,7 +210,6 @@ function init() { - - controls.movementSpeed = 70; - controls.lookSpeed = 0.05; -- controls.noFly = true; - controls.lookVertical = false; - - // diff --git a/examples-testing/examples/webaudio_timing.ts b/examples-testing/examples/webaudio_timing.ts -index 39259ae..3852550 100644 +index bab79dd..2d6c621 100644 --- a/examples-testing/examples/webaudio_timing.ts +++ b/examples-testing/examples/webaudio_timing.ts @@ -2,22 +2,22 @@ import * as THREE from 'three'; @@ -1779,7 +1771,7 @@ index 39259ae..3852550 100644 scene = new THREE.Scene(); -@@ -148,7 +148,7 @@ function render() { +@@ -147,7 +147,7 @@ function render() { if (ball.userData.down === true) { // ball changed direction from down to up @@ -1789,7 +1781,7 @@ index 39259ae..3852550 100644 ball.userData.down = false; } diff --git a/examples-testing/examples/webaudio_visualizer.ts b/examples-testing/examples/webaudio_visualizer.ts -index ecbcda0..ff46509 100644 +index 6c4244f..857d8f1 100644 --- a/examples-testing/examples/webaudio_visualizer.ts +++ b/examples-testing/examples/webaudio_visualizer.ts @@ -1,8 +1,13 @@ @@ -1823,7 +1815,7 @@ index ecbcda0..ff46509 100644 renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setPixelRatio(window.devicePixelRatio); -@@ -59,8 +64,8 @@ function init() { +@@ -58,8 +63,8 @@ function init() { const material = new THREE.ShaderMaterial({ uniforms: uniforms, @@ -1834,7 +1826,7 @@ index ecbcda0..ff46509 100644 }); const geometry = new THREE.PlaneGeometry(1, 1); -@@ -88,7 +93,7 @@ function animate() { +@@ -87,7 +92,7 @@ function animate() { function render() { analyser.getFrequencyData(); @@ -1844,7 +1836,7 @@ index ecbcda0..ff46509 100644 renderer.render(scene, camera); } diff --git a/examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts b/examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts -index 9a22568..c98f35d 100644 +index 848814c..ca05c89 100644 --- a/examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts +++ b/examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts @@ -6,7 +6,7 @@ if (WebGL.isWebGL2Available() === false) { @@ -1877,7 +1869,7 @@ index 9a22568..c98f35d 100644 glslVersion: THREE.GLSL3, }); diff --git a/examples-testing/examples/webgl2_buffergeometry_attributes_none.ts b/examples-testing/examples/webgl2_buffergeometry_attributes_none.ts -index 75bea7b..27151c7 100644 +index a77b973..d24a458 100644 --- a/examples-testing/examples/webgl2_buffergeometry_attributes_none.ts +++ b/examples-testing/examples/webgl2_buffergeometry_attributes_none.ts @@ -6,7 +6,7 @@ if (WebGL.isWebGL2Available() === false) { @@ -1900,7 +1892,7 @@ index 75bea7b..27151c7 100644 side: THREE.DoubleSide, glslVersion: THREE.GLSL3, }); -@@ -55,11 +55,11 @@ function init() { +@@ -54,11 +54,11 @@ function init() { document.body.appendChild(renderer.domElement); } @@ -1916,7 +1908,7 @@ index 75bea7b..27151c7 100644 renderer.render(scene, camera); } diff --git a/examples-testing/examples/webgl2_materials_texture3d.ts b/examples-testing/examples/webgl2_materials_texture3d.ts -index be5c068..53f823c 100644 +index b746daf..581c97a 100644 --- a/examples-testing/examples/webgl2_materials_texture3d.ts +++ b/examples-testing/examples/webgl2_materials_texture3d.ts @@ -10,7 +10,15 @@ if (WebGL.isWebGL2Available() === false) { @@ -1936,7 +1928,7 @@ index be5c068..53f823c 100644 init(); -@@ -106,7 +114,7 @@ function init() { +@@ -105,7 +113,7 @@ function init() { } function updateUniforms() { @@ -1946,7 +1938,7 @@ index be5c068..53f823c 100644 material.uniforms['u_renderthreshold'].value = volconfig.isothreshold; // For ISO renderstyle material.uniforms['u_cmdata'].value = cmtextures[volconfig.colormap]; diff --git a/examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts b/examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts -index d0c8b1a..9d00f29 100644 +index 0268130..0e78ed5 100644 --- a/examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts +++ b/examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts @@ -11,15 +11,15 @@ if (WebGL.isWebGL2Available() === false) { @@ -1969,7 +1961,7 @@ index d0c8b1a..9d00f29 100644 const data = new Uint8Array(size * size * size); const scale = (scaleFactor * 10.0) / size; -@@ -66,7 +66,7 @@ function init() { +@@ -65,7 +65,7 @@ function init() { canvas.width = 1; canvas.height = 32; @@ -1978,7 +1970,7 @@ index d0c8b1a..9d00f29 100644 const gradient = context.createLinearGradient(0, 0, 0, 32); gradient.addColorStop(0.0, '#014a84'); gradient.addColorStop(0.5, '#0561a0'); -@@ -318,17 +318,17 @@ function animate() { +@@ -317,17 +317,17 @@ function animate() { const scaleFactor = (Math.random() + 0.5) * 0.5; const source = generateCloudTexture(perElementPaddedSize, scaleFactor); @@ -2000,7 +1992,7 @@ index d0c8b1a..9d00f29 100644 renderer.render(scene, camera); } diff --git a/examples-testing/examples/webgl2_multiple_rendertargets.ts b/examples-testing/examples/webgl2_multiple_rendertargets.ts -index 1d85f79..a94cbe8 100644 +index cc10827..217ec13 100644 --- a/examples-testing/examples/webgl2_multiple_rendertargets.ts +++ b/examples-testing/examples/webgl2_multiple_rendertargets.ts @@ -4,9 +4,9 @@ import WebGL from 'three/addons/capabilities/WebGL.js'; @@ -2016,7 +2008,7 @@ index 1d85f79..a94cbe8 100644 const parameters = { samples: 4, -@@ -69,8 +69,8 @@ function init() { +@@ -68,8 +68,8 @@ function init() { new THREE.Mesh( new THREE.TorusKnotGeometry(1, 0.3, 128, 32), new THREE.RawShaderMaterial({ @@ -2027,7 +2019,7 @@ index 1d85f79..a94cbe8 100644 uniforms: { tDiffuse: { value: diffuse }, repeat: { value: new THREE.Vector2(5, 0.5) }, -@@ -89,8 +89,8 @@ function init() { +@@ -88,8 +88,8 @@ function init() { new THREE.Mesh( new THREE.PlaneGeometry(2, 2), new THREE.RawShaderMaterial({ @@ -2038,7 +2030,7 @@ index 1d85f79..a94cbe8 100644 uniforms: { tDiffuse: { value: renderTarget.texture[0] }, tNormal: { value: renderTarget.texture[1] }, -@@ -125,8 +125,8 @@ function render() { +@@ -124,8 +124,8 @@ function render() { renderTarget.samples = parameters.samples; scene.traverse(function (child) { @@ -2050,7 +2042,7 @@ index 1d85f79..a94cbe8 100644 }); diff --git a/examples-testing/examples/webgl2_multisampled_renderbuffers.ts b/examples-testing/examples/webgl2_multisampled_renderbuffers.ts -index 1a20251..72c23b6 100644 +index c3197be..e795c79 100644 --- a/examples-testing/examples/webgl2_multisampled_renderbuffers.ts +++ b/examples-testing/examples/webgl2_multisampled_renderbuffers.ts @@ -6,9 +6,9 @@ import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; @@ -2075,7 +2067,7 @@ index 1a20251..72c23b6 100644 camera = new THREE.PerspectiveCamera(45, container.offsetWidth / container.offsetHeight, 10, 2000); camera.position.z = 500; diff --git a/examples-testing/examples/webgl2_texture2darray_compressed.ts b/examples-testing/examples/webgl2_texture2darray_compressed.ts -index a75fb5a..575fbd7 100644 +index bf86320..5294a1f 100644 --- a/examples-testing/examples/webgl2_texture2darray_compressed.ts +++ b/examples-testing/examples/webgl2_texture2darray_compressed.ts @@ -9,7 +9,12 @@ if (WebGL.isWebGL2Available() === false) { @@ -2092,7 +2084,7 @@ index a75fb5a..575fbd7 100644 const planeWidth = 50; const planeHeight = 25; -@@ -50,8 +55,8 @@ function init() { +@@ -49,8 +54,8 @@ function init() { depth: { value: 55 }, size: { value: new THREE.Vector2(planeWidth, planeHeight) }, }, @@ -2104,7 +2096,7 @@ index a75fb5a..575fbd7 100644 }); diff --git a/examples-testing/examples/webgl2_ubo.ts b/examples-testing/examples/webgl2_ubo.ts -index f4f8c07..2163795 100644 +index e296fdc..527b9a7 100644 --- a/examples-testing/examples/webgl2_ubo.ts +++ b/examples-testing/examples/webgl2_ubo.ts @@ -2,7 +2,7 @@ import * as THREE from 'three'; @@ -2147,7 +2139,7 @@ index f4f8c07..2163795 100644 glslVersion: THREE.GLSL3, }); -@@ -137,7 +137,7 @@ function animate() { +@@ -136,7 +136,7 @@ function animate() { const delta = clock.getDelta(); scene.traverse(function (child) { @@ -2157,7 +2149,7 @@ index f4f8c07..2163795 100644 child.rotation.y += delta * 0.3; } diff --git a/examples-testing/examples/webgl2_volume_cloud.ts b/examples-testing/examples/webgl2_volume_cloud.ts -index 217ab94..c60b77c 100644 +index bc54732..7fe4043 100644 --- a/examples-testing/examples/webgl2_volume_cloud.ts +++ b/examples-testing/examples/webgl2_volume_cloud.ts @@ -9,8 +9,8 @@ if (WebGL.isWebGL2Available() === false) { @@ -2171,7 +2163,7 @@ index 217ab94..c60b77c 100644 init(); animate(); -@@ -35,7 +35,7 @@ function init() { +@@ -34,7 +34,7 @@ function init() { canvas.width = 1; canvas.height = 32; @@ -2180,7 +2172,7 @@ index 217ab94..c60b77c 100644 const gradient = context.createLinearGradient(0, 0, 0, 32); gradient.addColorStop(0.0, '#014a84'); gradient.addColorStop(0.5, '#0561a0'); -@@ -278,10 +278,10 @@ function onWindowResize() { +@@ -277,10 +277,10 @@ function onWindowResize() { function animate() { requestAnimationFrame(animate); @@ -2194,7 +2186,7 @@ index 217ab94..c60b77c 100644 renderer.render(scene, camera); } diff --git a/examples-testing/examples/webgl2_volume_instancing.ts b/examples-testing/examples/webgl2_volume_instancing.ts -index fe795d5..cb10b1d 100644 +index 8932869..db8d5b3 100644 --- a/examples-testing/examples/webgl2_volume_instancing.ts +++ b/examples-testing/examples/webgl2_volume_instancing.ts @@ -8,8 +8,8 @@ if (WebGL.isWebGL2Available() === false) { @@ -2208,7 +2200,7 @@ index fe795d5..cb10b1d 100644 init(); animate(); -@@ -161,7 +161,7 @@ function init() { +@@ -160,7 +160,7 @@ function init() { const mesh = new THREE.InstancedMesh(geometry, material, 50000); mesh.onBeforeRender = function () { @@ -2218,7 +2210,7 @@ index fe795d5..cb10b1d 100644 const transform = new THREE.Object3D(); diff --git a/examples-testing/examples/webgl2_volume_perlin.ts b/examples-testing/examples/webgl2_volume_perlin.ts -index 75ccf8d..35d06e4 100644 +index a75328f..35a0321 100644 --- a/examples-testing/examples/webgl2_volume_perlin.ts +++ b/examples-testing/examples/webgl2_volume_perlin.ts @@ -9,8 +9,8 @@ if (WebGL.isWebGL2Available() === false) { @@ -2232,7 +2224,7 @@ index 75ccf8d..35d06e4 100644 init(); animate(); -@@ -210,7 +210,7 @@ function onWindowResize() { +@@ -209,7 +209,7 @@ function onWindowResize() { function animate() { requestAnimationFrame(animate); @@ -2242,7 +2234,7 @@ index 75ccf8d..35d06e4 100644 renderer.render(scene, camera); } diff --git a/examples-testing/examples/webgl_animation_keyframes.ts b/examples-testing/examples/webgl_animation_keyframes.ts -index 263eef7..9603bea 100644 +index 22dd961..fbe392b 100644 --- a/examples-testing/examples/webgl_animation_keyframes.ts +++ b/examples-testing/examples/webgl_animation_keyframes.ts @@ -8,10 +8,10 @@ import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js'; @@ -2259,7 +2251,7 @@ index 263eef7..9603bea 100644 const stats = new Stats(); container.appendChild(stats.dom); diff --git a/examples-testing/examples/webgl_animation_multiple.ts b/examples-testing/examples/webgl_animation_multiple.ts -index 16c58cf..5ccaf47 100644 +index 8f99340..4f3fafa 100644 --- a/examples-testing/examples/webgl_animation_multiple.ts +++ b/examples-testing/examples/webgl_animation_multiple.ts @@ -3,10 +3,10 @@ import * as THREE from 'three'; @@ -2286,7 +2278,7 @@ index 16c58cf..5ccaf47 100644 const model1 = SkeletonUtils.clone(gltf.scene); diff --git a/examples-testing/examples/webgl_animation_skinning_morph.ts b/examples-testing/examples/webgl_animation_skinning_morph.ts -index 03ba9ea..5b47c51 100644 +index 6aa1368..6c5c199 100644 --- a/examples-testing/examples/webgl_animation_skinning_morph.ts +++ b/examples-testing/examples/webgl_animation_skinning_morph.ts @@ -5,10 +5,29 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; @@ -2323,7 +2315,7 @@ index 03ba9ea..5b47c51 100644 init(); animate(); -@@ -81,9 +100,9 @@ function init() { +@@ -80,9 +99,9 @@ function init() { container.appendChild(stats.dom); } @@ -2335,7 +2327,7 @@ index 03ba9ea..5b47c51 100644 gui = new GUI(); -@@ -96,7 +115,7 @@ function createGUI(model, animations) { +@@ -95,7 +114,7 @@ function createGUI(model, animations) { const action = mixer.clipAction(clip); actions[clip.name] = action; @@ -2344,7 +2336,7 @@ index 03ba9ea..5b47c51 100644 action.clampWhenFinished = true; action.loop = THREE.LoopOnce; } -@@ -118,7 +137,7 @@ function createGUI(model, animations) { +@@ -117,7 +136,7 @@ function createGUI(model, animations) { const emoteFolder = gui.addFolder('Emotes'); @@ -2353,7 +2345,7 @@ index 03ba9ea..5b47c51 100644 api[name] = function () { fadeToAction(name, 0.2); -@@ -142,13 +161,13 @@ function createGUI(model, animations) { +@@ -141,13 +160,13 @@ function createGUI(model, animations) { // expressions @@ -2370,7 +2362,7 @@ index 03ba9ea..5b47c51 100644 } activeAction = actions['Walking']; -@@ -157,7 +176,7 @@ function createGUI(model, animations) { +@@ -156,7 +175,7 @@ function createGUI(model, animations) { expressionFolder.open(); } @@ -2380,7 +2372,7 @@ index 03ba9ea..5b47c51 100644 activeAction = actions[name]; diff --git a/examples-testing/examples/webgl_buffergeometry.ts b/examples-testing/examples/webgl_buffergeometry.ts -index 42a9c31..ad80640 100644 +index 5f9bb39..03d2644 100644 --- a/examples-testing/examples/webgl_buffergeometry.ts +++ b/examples-testing/examples/webgl_buffergeometry.ts @@ -2,17 +2,17 @@ import * as THREE from 'three'; @@ -2417,7 +2409,7 @@ index 42a9c31..ad80640 100644 geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3).onUpload(disposeArray)); diff --git a/examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts b/examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts -index 94c862c..653cf2b 100644 +index e9e115d..65b7563 100644 --- a/examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts +++ b/examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts @@ -2,9 +2,11 @@ import * as THREE from 'three'; @@ -2445,9 +2437,9 @@ index 94c862c..653cf2b 100644 blending: THREE.AdditiveBlending, depthTest: false, -@@ -67,7 +69,7 @@ function init() { +@@ -66,7 +68,7 @@ function init() { + renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); - renderer.useLegacyLights = false; - const container = document.getElementById('container'); + const container = document.getElementById('container')!; @@ -2455,7 +2447,7 @@ index 94c862c..653cf2b 100644 stats = new Stats(); diff --git a/examples-testing/examples/webgl_buffergeometry_drawrange.ts b/examples-testing/examples/webgl_buffergeometry_drawrange.ts -index 58e4dd1..915d687 100644 +index b69868c..4c79b56 100644 --- a/examples-testing/examples/webgl_buffergeometry_drawrange.ts +++ b/examples-testing/examples/webgl_buffergeometry_drawrange.ts @@ -5,15 +5,15 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; @@ -2513,7 +2505,7 @@ index 58e4dd1..915d687 100644 camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 4000); camera.position.z = 1750; diff --git a/examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts b/examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts -index f62c733..06f84e6 100644 +index daf8a06..0624ea0 100644 --- a/examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts +++ b/examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts @@ -2,11 +2,11 @@ import * as THREE from 'three'; @@ -2540,7 +2532,7 @@ index f62c733..06f84e6 100644 // -@@ -37,7 +37,7 @@ function init() { +@@ -36,7 +36,7 @@ function init() { // @@ -2549,7 +2541,7 @@ index f62c733..06f84e6 100644 const positions = []; const positions2 = []; -@@ -71,15 +71,15 @@ function init() { +@@ -70,15 +70,15 @@ function init() { const gl = renderer.getContext(); @@ -2569,7 +2561,7 @@ index f62c733..06f84e6 100644 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); diff --git a/examples-testing/examples/webgl_buffergeometry_indexed.ts b/examples-testing/examples/webgl_buffergeometry_indexed.ts -index 769a3c9..707146a 100644 +index 1e9f668..ec64598 100644 --- a/examples-testing/examples/webgl_buffergeometry_indexed.ts +++ b/examples-testing/examples/webgl_buffergeometry_indexed.ts @@ -3,9 +3,9 @@ import * as THREE from 'three'; @@ -2585,7 +2577,7 @@ index 769a3c9..707146a 100644 init(); animate(); diff --git a/examples-testing/examples/webgl_buffergeometry_instancing.ts b/examples-testing/examples/webgl_buffergeometry_instancing.ts -index 936d4c4..12d1546 100644 +index adff12a..fb9267f 100644 --- a/examples-testing/examples/webgl_buffergeometry_instancing.ts +++ b/examples-testing/examples/webgl_buffergeometry_instancing.ts @@ -3,15 +3,15 @@ import * as THREE from 'three'; @@ -2618,7 +2610,7 @@ index 936d4c4..12d1546 100644 side: THREE.DoubleSide, forceSinglePass: true, transparent: true, -@@ -101,7 +101,7 @@ function init() { +@@ -100,7 +100,7 @@ function init() { container.appendChild(renderer.domElement); if (renderer.capabilities.isWebGL2 === false && renderer.extensions.has('ANGLE_instanced_arrays') === false) { @@ -2627,7 +2619,7 @@ index 936d4c4..12d1546 100644 return; } -@@ -139,7 +139,7 @@ function animate() { +@@ -138,7 +138,7 @@ function animate() { function render() { const time = performance.now(); @@ -2637,7 +2629,7 @@ index 936d4c4..12d1546 100644 object.rotation.y = time * 0.0005; object.material.uniforms['time'].value = time * 0.005; diff --git a/examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts b/examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts -index 92f0e4d..7478c75 100644 +index 785389c..64b3ee1 100644 --- a/examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts +++ b/examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts @@ -2,16 +2,16 @@ import * as THREE from 'three'; @@ -2673,7 +2665,7 @@ index 92f0e4d..7478c75 100644 depthWrite: true, }); diff --git a/examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts b/examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts -index 0b409ce..f934b06 100644 +index 132e1e6..77ce657 100644 --- a/examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts +++ b/examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts @@ -2,8 +2,8 @@ import * as THREE from 'three'; @@ -2696,7 +2688,7 @@ index 0b409ce..f934b06 100644 camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1000); -@@ -113,7 +113,7 @@ function init() { +@@ -112,7 +112,7 @@ function init() { container.appendChild(renderer.domElement); if (renderer.capabilities.isWebGL2 === false && renderer.extensions.has('ANGLE_instanced_arrays') === false) { @@ -2706,7 +2698,7 @@ index 0b409ce..f934b06 100644 } diff --git a/examples-testing/examples/webgl_buffergeometry_lines.ts b/examples-testing/examples/webgl_buffergeometry_lines.ts -index 507d899..a4d4bbc 100644 +index c23ea0c..705d08f 100644 --- a/examples-testing/examples/webgl_buffergeometry_lines.ts +++ b/examples-testing/examples/webgl_buffergeometry_lines.ts @@ -2,11 +2,11 @@ import * as THREE from 'three'; @@ -2733,7 +2725,7 @@ index 507d899..a4d4bbc 100644 // -@@ -101,12 +101,12 @@ function render() { +@@ -100,12 +100,12 @@ function render() { line.rotation.y = time * 0.5; t += delta * 0.5; @@ -2749,7 +2741,7 @@ index 507d899..a4d4bbc 100644 for (let i = 0; i < segments; i++) { diff --git a/examples-testing/examples/webgl_buffergeometry_lines_indexed.ts b/examples-testing/examples/webgl_buffergeometry_lines_indexed.ts -index e0a25ee..bb61a36 100644 +index d81c173..209454f 100644 --- a/examples-testing/examples/webgl_buffergeometry_lines_indexed.ts +++ b/examples-testing/examples/webgl_buffergeometry_lines_indexed.ts @@ -2,17 +2,17 @@ import * as THREE from 'three'; @@ -2815,7 +2807,7 @@ index e0a25ee..bb61a36 100644 add_vertex(points[0]); diff --git a/examples-testing/examples/webgl_buffergeometry_points.ts b/examples-testing/examples/webgl_buffergeometry_points.ts -index 07d6273..c3110bb 100644 +index fdfd957..b05a609 100644 --- a/examples-testing/examples/webgl_buffergeometry_points.ts +++ b/examples-testing/examples/webgl_buffergeometry_points.ts @@ -2,17 +2,17 @@ import * as THREE from 'three'; @@ -2841,7 +2833,7 @@ index 07d6273..c3110bb 100644 // diff --git a/examples-testing/examples/webgl_buffergeometry_points_interleaved.ts b/examples-testing/examples/webgl_buffergeometry_points_interleaved.ts -index 7c29a13..f5c781e 100644 +index 9d1ac41..e26b9a1 100644 --- a/examples-testing/examples/webgl_buffergeometry_points_interleaved.ts +++ b/examples-testing/examples/webgl_buffergeometry_points_interleaved.ts @@ -2,17 +2,17 @@ import * as THREE from 'three'; @@ -2867,7 +2859,7 @@ index 7c29a13..f5c781e 100644 camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 5, 3500); camera.position.z = 2750; diff --git a/examples-testing/examples/webgl_buffergeometry_rawshader.ts b/examples-testing/examples/webgl_buffergeometry_rawshader.ts -index 6623468..c35a1da 100644 +index 0d05339..cd5fe8c 100644 --- a/examples-testing/examples/webgl_buffergeometry_rawshader.ts +++ b/examples-testing/examples/webgl_buffergeometry_rawshader.ts @@ -2,15 +2,15 @@ import * as THREE from 'three'; @@ -2900,7 +2892,7 @@ index 6623468..c35a1da 100644 side: THREE.DoubleSide, transparent: true, }); -@@ -94,7 +94,7 @@ function animate() { +@@ -93,7 +93,7 @@ function animate() { function render() { const time = performance.now(); @@ -2910,7 +2902,7 @@ index 6623468..c35a1da 100644 object.rotation.y = time * 0.0005; object.material.uniforms.time.value = time * 0.005; diff --git a/examples-testing/examples/webgl_buffergeometry_selective_draw.ts b/examples-testing/examples/webgl_buffergeometry_selective_draw.ts -index 2157752..5aebaef 100644 +index f0752a2..8e8a44f 100644 --- a/examples-testing/examples/webgl_buffergeometry_selective_draw.ts +++ b/examples-testing/examples/webgl_buffergeometry_selective_draw.ts @@ -2,8 +2,8 @@ import * as THREE from 'three'; @@ -2924,7 +2916,7 @@ index 2157752..5aebaef 100644 const numLat = 100; const numLng = 200; let numLinesCulled = 0; -@@ -30,14 +30,14 @@ function init() { +@@ -29,14 +29,14 @@ function init() { addLines(1.0); @@ -2942,7 +2934,7 @@ index 2157752..5aebaef 100644 geometry = new THREE.BufferGeometry(); const linePositions = new Float32Array(numLat * numLng * 3 * 2); const lineColors = new Float32Array(numLat * numLng * 3 * 2); -@@ -82,8 +82,8 @@ function addLines(radius) { +@@ -81,8 +81,8 @@ function addLines(radius) { geometry.computeBoundingSphere(); const shaderMaterial = new THREE.ShaderMaterial({ @@ -2953,7 +2945,7 @@ index 2157752..5aebaef 100644 }); mesh = new THREE.LineSegments(geometry, shaderMaterial); -@@ -99,7 +99,7 @@ function updateCount() { +@@ -98,7 +98,7 @@ function updateCount() { ' lines, ' + numLinesCulled + ' culled (author)'; @@ -2963,7 +2955,7 @@ index 2157752..5aebaef 100644 function hideLines() { diff --git a/examples-testing/examples/webgl_buffergeometry_uint.ts b/examples-testing/examples/webgl_buffergeometry_uint.ts -index c1dcfc0..736b9c6 100644 +index d248a0d..16a111b 100644 --- a/examples-testing/examples/webgl_buffergeometry_uint.ts +++ b/examples-testing/examples/webgl_buffergeometry_uint.ts @@ -2,17 +2,17 @@ import * as THREE from 'three'; @@ -2989,7 +2981,7 @@ index c1dcfc0..736b9c6 100644 // diff --git a/examples-testing/examples/webgl_camera.ts b/examples-testing/examples/webgl_camera.ts -index 47a2b53..14a6dd3 100644 +index d8319ec..8f8b515 100644 --- a/examples-testing/examples/webgl_camera.ts +++ b/examples-testing/examples/webgl_camera.ts @@ -6,11 +6,11 @@ let SCREEN_WIDTH = window.innerWidth; @@ -3009,7 +3001,7 @@ index 47a2b53..14a6dd3 100644 const frustumSize = 600; init(); -@@ -123,7 +123,7 @@ function init() { +@@ -122,7 +122,7 @@ function init() { // @@ -3019,7 +3011,7 @@ index 47a2b53..14a6dd3 100644 case 79 /*O*/: activeCamera = cameraOrtho; diff --git a/examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts b/examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts -index 2f1de25..9fa4a8e 100644 +index a80cc19..4d1f2c8 100644 --- a/examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts +++ b/examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts @@ -1,6 +1,6 @@ @@ -3078,7 +3070,7 @@ index 2f1de25..9fa4a8e 100644 const camera = new THREE.PerspectiveCamera(50, (screensplit * SCREEN_WIDTH) / SCREEN_HEIGHT, NEAR, FAR); scene.add(camera); -@@ -86,7 +94,7 @@ function initView(scene, name, logDepthBuf) { +@@ -85,7 +93,7 @@ function initView(scene, name, logDepthBuf) { return { container: framecontainer, renderer: renderer, scene: scene, camera: camera }; } @@ -3087,7 +3079,7 @@ index 2f1de25..9fa4a8e 100644 const scene = new THREE.Scene(); scene.add(new THREE.AmbientLight(0x777777)); -@@ -95,7 +103,7 @@ function initScene(font) { +@@ -94,7 +102,7 @@ function initScene(font) { light.position.set(100, 100, 100); scene.add(light); @@ -3096,7 +3088,7 @@ index 2f1de25..9fa4a8e 100644 color: 0xffffff, specular: 0x050505, shininess: 50, -@@ -116,7 +124,7 @@ function initScene(font) { +@@ -115,7 +123,7 @@ function initScene(font) { labelgeo.computeBoundingSphere(); // center text @@ -3105,7 +3097,7 @@ index 2f1de25..9fa4a8e 100644 materialargs.color = new THREE.Color().setHSL(Math.random(), 0.5, 0.5); -@@ -149,16 +157,16 @@ function updateRendererSizes() { +@@ -148,16 +156,16 @@ function updateRendererSizes() { screensplit_right = 1 - screensplit; @@ -3131,7 +3123,7 @@ index 2f1de25..9fa4a8e 100644 SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH * screensplit, -@@ -166,7 +174,7 @@ function updateRendererSizes() { +@@ -165,7 +173,7 @@ function updateRendererSizes() { SCREEN_WIDTH * screensplit_right, SCREEN_HEIGHT, ); @@ -3140,7 +3132,7 @@ index 2f1de25..9fa4a8e 100644 border.style.left = screensplit * 100 + '%'; } -@@ -194,22 +202,22 @@ function render() { +@@ -193,22 +201,22 @@ function render() { zoompos += zoomspeed; zoomspeed *= damping; @@ -3171,7 +3163,7 @@ index 2f1de25..9fa4a8e 100644 stats.update(); } -@@ -224,7 +232,7 @@ function onBorderPointerDown() { +@@ -223,7 +231,7 @@ function onBorderPointerDown() { window.addEventListener('pointerup', onBorderPointerUp); } @@ -3180,7 +3172,7 @@ index 2f1de25..9fa4a8e 100644 screensplit = Math.max(0, Math.min(1, ev.clientX / window.innerWidth)); } -@@ -233,12 +241,12 @@ function onBorderPointerUp() { +@@ -232,12 +240,12 @@ function onBorderPointerUp() { window.removeEventListener('pointerup', onBorderPointerUp); } @@ -3196,7 +3188,7 @@ index 2f1de25..9fa4a8e 100644 if (amount === 0) return; const dir = amount / Math.abs(amount); diff --git a/examples-testing/examples/webgl_clipping.ts b/examples-testing/examples/webgl_clipping.ts -index 3d3d7a5..590b344 100644 +index f0a18f3..754f7ce 100644 --- a/examples-testing/examples/webgl_clipping.ts +++ b/examples-testing/examples/webgl_clipping.ts @@ -5,7 +5,12 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; @@ -3214,7 +3206,7 @@ index 3d3d7a5..590b344 100644 init(); animate(); diff --git a/examples-testing/examples/webgl_clipping_advanced.ts b/examples-testing/examples/webgl_clipping_advanced.ts -index 5c48039..01528be 100644 +index d60532c..ccc98e6 100644 --- a/examples-testing/examples/webgl_clipping_advanced.ts +++ b/examples-testing/examples/webgl_clipping_advanced.ts @@ -5,7 +5,7 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; @@ -3280,7 +3272,7 @@ index 5c48039..01528be 100644 function init() { camera = new THREE.PerspectiveCamera(36, window.innerWidth / window.innerHeight, 0.25, 16); -@@ -307,12 +315,12 @@ function onWindowResize() { +@@ -306,12 +314,12 @@ function onWindowResize() { renderer.setSize(window.innerWidth, window.innerHeight); } @@ -3296,7 +3288,7 @@ index 5c48039..01528be 100644 } diff --git a/examples-testing/examples/webgl_clipping_intersection.ts b/examples-testing/examples/webgl_clipping_intersection.ts -index 494ef56..212e6db 100644 +index 74022d7..d2906ce 100644 --- a/examples-testing/examples/webgl_clipping_intersection.ts +++ b/examples-testing/examples/webgl_clipping_intersection.ts @@ -4,7 +4,7 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; @@ -3308,7 +3300,7 @@ index 494ef56..212e6db 100644 const params = { clipIntersection: true, -@@ -79,11 +79,11 @@ function init() { +@@ -78,11 +78,11 @@ function init() { gui.add(params, 'clipIntersection') .name('clip intersection') @@ -3322,7 +3314,7 @@ index 494ef56..212e6db 100644 } render(); -@@ -92,7 +92,7 @@ function init() { +@@ -91,7 +91,7 @@ function init() { gui.add(params, 'planeConstant', -1, 1) .step(0.01) .name('plane constant') @@ -3331,7 +3323,7 @@ index 494ef56..212e6db 100644 for (let j = 0; j < clipPlanes.length; j++) { clipPlanes[j].constant = value; } -@@ -102,7 +102,7 @@ function init() { +@@ -101,7 +101,7 @@ function init() { gui.add(params, 'showHelpers') .name('show helpers') @@ -3341,7 +3333,7 @@ index 494ef56..212e6db 100644 render(); diff --git a/examples-testing/examples/webgl_clipping_stencil.ts b/examples-testing/examples/webgl_clipping_stencil.ts -index 47c7115..8b7a23e 100644 +index 365087d..cb3b747 100644 --- a/examples-testing/examples/webgl_clipping_stencil.ts +++ b/examples-testing/examples/webgl_clipping_stencil.ts @@ -3,9 +3,13 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; @@ -3370,7 +3362,7 @@ index 47c7115..8b7a23e 100644 const group = new THREE.Group(); const baseMat = new THREE.MeshBasicMaterial(); baseMat.depthWrite = false; -@@ -192,12 +196,12 @@ function init() { +@@ -191,12 +195,12 @@ function init() { gui.add(params, 'animate'); const planeX = gui.addFolder('planeX'); @@ -3385,7 +3377,7 @@ index 47c7115..8b7a23e 100644 planeX.add(params.planeX, 'negated').onChange(() => { planes[0].negate(); params.planeX.constant = planes[0].constant; -@@ -205,12 +209,12 @@ function init() { +@@ -204,12 +208,12 @@ function init() { planeX.open(); const planeY = gui.addFolder('planeY'); @@ -3400,7 +3392,7 @@ index 47c7115..8b7a23e 100644 planeY.add(params.planeY, 'negated').onChange(() => { planes[1].negate(); params.planeY.constant = planes[1].constant; -@@ -218,12 +222,12 @@ function init() { +@@ -217,12 +221,12 @@ function init() { planeY.open(); const planeZ = gui.addFolder('planeZ'); @@ -3416,7 +3408,7 @@ index 47c7115..8b7a23e 100644 planes[2].negate(); params.planeZ.constant = planes[2].constant; diff --git a/examples-testing/examples/webgl_custom_attributes.ts b/examples-testing/examples/webgl_custom_attributes.ts -index a74bda8..cec7cd9 100644 +index 648e097..98d024c 100644 --- a/examples-testing/examples/webgl_custom_attributes.ts +++ b/examples-testing/examples/webgl_custom_attributes.ts @@ -2,11 +2,16 @@ import * as THREE from 'three'; @@ -3450,9 +3442,9 @@ index a74bda8..cec7cd9 100644 }); const radius = 50, -@@ -55,7 +60,7 @@ function init() { +@@ -54,7 +59,7 @@ function init() { + renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); - renderer.useLegacyLights = false; - const container = document.getElementById('container'); + const container = document.getElementById('container')!; @@ -3460,7 +3452,7 @@ index a74bda8..cec7cd9 100644 stats = new Stats(); diff --git a/examples-testing/examples/webgl_custom_attributes_lines.ts b/examples-testing/examples/webgl_custom_attributes_lines.ts -index dfc997f..8e172cc 100644 +index 29b8a06..9217e11 100644 --- a/examples-testing/examples/webgl_custom_attributes_lines.ts +++ b/examples-testing/examples/webgl_custom_attributes_lines.ts @@ -1,13 +1,18 @@ @@ -3505,9 +3497,9 @@ index dfc997f..8e172cc 100644 blending: THREE.AdditiveBlending, depthTest: false, transparent: true, -@@ -76,7 +81,7 @@ function init(font) { +@@ -75,7 +80,7 @@ function init(font) { + renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); - renderer.useLegacyLights = false; - const container = document.getElementById('container'); + const container = document.getElementById('container')!; @@ -3515,7 +3507,7 @@ index dfc997f..8e172cc 100644 stats = new Stats(); diff --git a/examples-testing/examples/webgl_custom_attributes_points.ts b/examples-testing/examples/webgl_custom_attributes_points.ts -index 6be7af6..e65e35e 100644 +index f1cfedc..a6ec206 100644 --- a/examples-testing/examples/webgl_custom_attributes_points.ts +++ b/examples-testing/examples/webgl_custom_attributes_points.ts @@ -2,9 +2,9 @@ import * as THREE from 'three'; @@ -3541,9 +3533,9 @@ index 6be7af6..e65e35e 100644 blending: THREE.AdditiveBlending, depthTest: false, -@@ -77,7 +77,7 @@ function init() { +@@ -76,7 +76,7 @@ function init() { + renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(WIDTH, HEIGHT); - renderer.useLegacyLights = false; - const container = document.getElementById('container'); + const container = document.getElementById('container')!; @@ -3551,7 +3543,7 @@ index 6be7af6..e65e35e 100644 stats = new Stats(); diff --git a/examples-testing/examples/webgl_custom_attributes_points2.ts b/examples-testing/examples/webgl_custom_attributes_points2.ts -index 724f12e..b9b614a 100644 +index f744a1e..d3b5cc2 100644 --- a/examples-testing/examples/webgl_custom_attributes_points2.ts +++ b/examples-testing/examples/webgl_custom_attributes_points2.ts @@ -4,8 +4,8 @@ import Stats from 'three/addons/libs/stats.module.js'; @@ -3598,16 +3590,16 @@ index 724f12e..b9b614a 100644 transparent: true, }); -@@ -95,7 +95,7 @@ function init() { +@@ -94,7 +94,7 @@ function init() { + renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(WIDTH, HEIGHT); - renderer.useLegacyLights = false; - const container = document.getElementById('container'); + const container = document.getElementById('container')!; container.appendChild(renderer.domElement); stats = new Stats(); -@@ -151,7 +151,7 @@ function sortPoints() { +@@ -150,7 +150,7 @@ function sortPoints() { sortArray.push([vector.z, i]); } @@ -3616,7 +3608,7 @@ index 724f12e..b9b614a 100644 return b[0] - a[0]; } -@@ -163,7 +163,7 @@ function sortPoints() { +@@ -162,7 +162,7 @@ function sortPoints() { indices[i] = sortArray[i][1]; } @@ -3626,7 +3618,7 @@ index 724f12e..b9b614a 100644 function animate() { diff --git a/examples-testing/examples/webgl_custom_attributes_points3.ts b/examples-testing/examples/webgl_custom_attributes_points3.ts -index f7022dd..baf629d 100644 +index 1ef2f1f..fc34046 100644 --- a/examples-testing/examples/webgl_custom_attributes_points3.ts +++ b/examples-testing/examples/webgl_custom_attributes_points3.ts @@ -4,11 +4,11 @@ import Stats from 'three/addons/libs/stats.module.js'; @@ -3693,9 +3685,9 @@ index f7022dd..baf629d 100644 }); // -@@ -158,7 +158,7 @@ function init() { +@@ -157,7 +157,7 @@ function init() { + renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(WIDTH, HEIGHT); - renderer.useLegacyLights = false; - const container = document.getElementById('container'); + const container = document.getElementById('container')!; @@ -3703,7 +3695,7 @@ index f7022dd..baf629d 100644 stats = new Stats(); diff --git a/examples-testing/examples/webgl_decals.ts b/examples-testing/examples/webgl_decals.ts -index 8e6df57..4f99335 100644 +index 1b3b791..ddf54a2 100644 --- a/examples-testing/examples/webgl_decals.ts +++ b/examples-testing/examples/webgl_decals.ts @@ -7,12 +7,12 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; @@ -3744,7 +3736,7 @@ index 8e6df57..4f99335 100644 const position = new THREE.Vector3(); const orientation = new THREE.Euler(); const size = new THREE.Vector3(10, 10, 10); -@@ -124,13 +124,13 @@ function init() { +@@ -123,13 +123,13 @@ function init() { window.addEventListener('pointermove', onPointerMove); @@ -3760,7 +3752,7 @@ index 8e6df57..4f99335 100644 if (mesh === undefined) return; mouse.x = (x / window.innerWidth) * 2 - 1; -@@ -144,12 +144,12 @@ function init() { +@@ -143,12 +143,12 @@ function init() { mouseHelper.position.copy(p); intersection.point.copy(p); @@ -3775,7 +3767,7 @@ index 8e6df57..4f99335 100644 mouseHelper.lookAt(n); const positions = line.geometry.attributes.position; -@@ -183,7 +183,7 @@ function loadLeePerrySmith() { +@@ -182,7 +182,7 @@ function loadLeePerrySmith() { const loader = new GLTFLoader(); loader.load('models/gltf/LeePerrySmith/LeePerrySmith.glb', function (gltf) { @@ -3785,7 +3777,7 @@ index 8e6df57..4f99335 100644 specular: 0x111111, map: map, diff --git a/examples-testing/examples/webgl_effects_anaglyph.ts b/examples-testing/examples/webgl_effects_anaglyph.ts -index 4d6f829..ccea1a9 100644 +index 5132963..af1bb7f 100644 --- a/examples-testing/examples/webgl_effects_anaglyph.ts +++ b/examples-testing/examples/webgl_effects_anaglyph.ts @@ -2,9 +2,13 @@ import * as THREE from 'three'; @@ -3804,16 +3796,7 @@ index 4d6f829..ccea1a9 100644 let mouseX = 0; let mouseY = 0; -@@ -23,7 +27,7 @@ function init() { - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 100); - camera.position.z = 3; -- camera.focalLength = 3; -+ camera.setFocalLength(3); - - const path = 'textures/cube/pisa/'; - const format = '.png'; -@@ -86,7 +90,7 @@ function onWindowResize() { +@@ -84,7 +88,7 @@ function onWindowResize() { effect.setSize(window.innerWidth, window.innerHeight); } @@ -3823,7 +3806,7 @@ index 4d6f829..ccea1a9 100644 mouseY = (event.clientY - windowHalfY) / 100; } diff --git a/examples-testing/examples/webgl_effects_ascii.ts b/examples-testing/examples/webgl_effects_ascii.ts -index ecb7136..cfca2ff 100644 +index 60b7de8..6e546c4 100644 --- a/examples-testing/examples/webgl_effects_ascii.ts +++ b/examples-testing/examples/webgl_effects_ascii.ts @@ -3,9 +3,13 @@ import * as THREE from 'three'; @@ -3843,7 +3826,7 @@ index ecb7136..cfca2ff 100644 const start = Date.now(); diff --git a/examples-testing/examples/webgl_effects_parallaxbarrier.ts b/examples-testing/examples/webgl_effects_parallaxbarrier.ts -index 3a5c8ca..f6872d9 100644 +index 45e7491..f6ed13c 100644 --- a/examples-testing/examples/webgl_effects_parallaxbarrier.ts +++ b/examples-testing/examples/webgl_effects_parallaxbarrier.ts @@ -2,9 +2,13 @@ import * as THREE from 'three'; @@ -3862,16 +3845,7 @@ index 3a5c8ca..f6872d9 100644 let mouseX = 0; let mouseY = 0; -@@ -23,7 +27,7 @@ function init() { - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 100); - camera.position.z = 3; -- camera.focalLength = 3; -+ camera.setFocalLength(3); - - const path = 'textures/cube/pisa/'; - const format = '.png'; -@@ -86,7 +90,7 @@ function onWindowResize() { +@@ -84,7 +88,7 @@ function onWindowResize() { effect.setSize(window.innerWidth, window.innerHeight); } @@ -3881,7 +3855,7 @@ index 3a5c8ca..f6872d9 100644 mouseY = (event.clientY - windowHalfY) / 100; } diff --git a/examples-testing/examples/webgl_effects_peppersghost.ts b/examples-testing/examples/webgl_effects_peppersghost.ts -index 411d9d8..ecec99b 100644 +index 90cfe01..314b24c 100644 --- a/examples-testing/examples/webgl_effects_peppersghost.ts +++ b/examples-testing/examples/webgl_effects_peppersghost.ts @@ -2,10 +2,10 @@ import * as THREE from 'three'; @@ -3899,7 +3873,7 @@ index 411d9d8..ecec99b 100644 init(); animate(); diff --git a/examples-testing/examples/webgl_effects_stereo.ts b/examples-testing/examples/webgl_effects_stereo.ts -index 3f68985..8f40d2a 100644 +index 4db7184..a5457e3 100644 --- a/examples-testing/examples/webgl_effects_stereo.ts +++ b/examples-testing/examples/webgl_effects_stereo.ts @@ -2,9 +2,13 @@ import * as THREE from 'three'; @@ -3918,7 +3892,7 @@ index 3f68985..8f40d2a 100644 let mouseX = 0, mouseY = 0; -@@ -74,7 +78,7 @@ function onWindowResize() { +@@ -73,7 +77,7 @@ function onWindowResize() { effect.setSize(window.innerWidth, window.innerHeight); } @@ -3928,7 +3902,7 @@ index 3f68985..8f40d2a 100644 mouseY = (event.clientY - windowHalfY) * 10; } diff --git a/examples-testing/examples/webgl_framebuffer_texture.ts b/examples-testing/examples/webgl_framebuffer_texture.ts -index e992ef1..3eaf545 100644 +index 379737f..5f4095f 100644 --- a/examples-testing/examples/webgl_framebuffer_texture.ts +++ b/examples-testing/examples/webgl_framebuffer_texture.ts @@ -3,10 +3,10 @@ import * as THREE from 'three'; @@ -3945,7 +3919,7 @@ index e992ef1..3eaf545 100644 let offset = 0; -@@ -77,7 +77,7 @@ function init() { +@@ -76,7 +76,7 @@ function init() { // @@ -3954,7 +3928,7 @@ index e992ef1..3eaf545 100644 const controls = new OrbitControls(camera, selection); controls.enablePan = false; -@@ -136,7 +136,7 @@ function animate() { +@@ -135,7 +135,7 @@ function animate() { renderer.render(sceneOrtho, cameraOrtho); } @@ -3964,7 +3938,7 @@ index e992ef1..3eaf545 100644 for (let i = 0; i < l; i++) { diff --git a/examples-testing/examples/webgl_furnace_test.ts b/examples-testing/examples/webgl_furnace_test.ts -index f746f2e..143dc67 100644 +index a819541..46230b4 100644 --- a/examples-testing/examples/webgl_furnace_test.ts +++ b/examples-testing/examples/webgl_furnace_test.ts @@ -1,6 +1,6 @@ @@ -3975,7 +3949,7 @@ index f746f2e..143dc67 100644 const COLOR = 0xcccccc; -@@ -21,7 +21,8 @@ function init() { +@@ -20,7 +20,8 @@ function init() { document.body.addEventListener('mouseover', function () { scene.traverse(function (child) { @@ -3985,7 +3959,7 @@ index f746f2e..143dc67 100644 }); render(); -@@ -29,7 +30,8 @@ function init() { +@@ -28,7 +29,8 @@ function init() { document.body.addEventListener('mouseout', function () { scene.traverse(function (child) { @@ -3996,7 +3970,7 @@ index f746f2e..143dc67 100644 render(); diff --git a/examples-testing/examples/webgl_geometries.ts b/examples-testing/examples/webgl_geometries.ts -index c8963d2..13a6cdc 100644 +index 154164e..ab4961b 100644 --- a/examples-testing/examples/webgl_geometries.ts +++ b/examples-testing/examples/webgl_geometries.ts @@ -2,7 +2,7 @@ import * as THREE from 'three'; @@ -4008,7 +3982,7 @@ index c8963d2..13a6cdc 100644 init(); animate(); -@@ -130,7 +130,7 @@ function render() { +@@ -129,7 +129,7 @@ function render() { camera.lookAt(scene.position); scene.traverse(function (object) { @@ -4018,7 +3992,7 @@ index c8963d2..13a6cdc 100644 object.rotation.y = timer * 2.5; } diff --git a/examples-testing/examples/webgl_geometries_parametric.ts b/examples-testing/examples/webgl_geometries_parametric.ts -index 492f72b..7e2d646 100644 +index 8aa86c3..ea8662c 100644 --- a/examples-testing/examples/webgl_geometries_parametric.ts +++ b/examples-testing/examples/webgl_geometries_parametric.ts @@ -6,13 +6,13 @@ import * as Curves from 'three/addons/curves/CurveExtras.js'; @@ -4037,7 +4011,7 @@ index 492f72b..7e2d646 100644 camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000); camera.position.y = 400; -@@ -117,7 +117,7 @@ function render() { +@@ -116,7 +116,7 @@ function render() { camera.lookAt(scene.position); scene.traverse(function (object) { @@ -4047,7 +4021,7 @@ index 492f72b..7e2d646 100644 object.rotation.y = timer * 2.5; } diff --git a/examples-testing/examples/webgl_gpgpu_birds.ts b/examples-testing/examples/webgl_gpgpu_birds.ts -index 8fe7ab1..0010fda 100644 +index ecf53eb..4f865bd 100644 --- a/examples-testing/examples/webgl_gpgpu_birds.ts +++ b/examples-testing/examples/webgl_gpgpu_birds.ts @@ -3,7 +3,7 @@ import * as THREE from 'three'; @@ -4102,7 +4076,7 @@ index 8fe7ab1..0010fda 100644 init(); animate(); -@@ -169,12 +169,12 @@ function initComputeRenderer() { +@@ -168,12 +168,12 @@ function initComputeRenderer() { velocityVariable = gpuCompute.addVariable( 'textureVelocity', @@ -4117,7 +4091,7 @@ index 8fe7ab1..0010fda 100644 dtPosition, ); -@@ -223,8 +223,8 @@ function initBirds() { +@@ -222,8 +222,8 @@ function initBirds() { // THREE.ShaderMaterial const material = new THREE.ShaderMaterial({ uniforms: birdUniforms, @@ -4128,7 +4102,7 @@ index 8fe7ab1..0010fda 100644 side: THREE.DoubleSide, }); -@@ -236,7 +236,7 @@ function initBirds() { +@@ -235,7 +235,7 @@ function initBirds() { scene.add(birdMesh); } @@ -4137,7 +4111,7 @@ index 8fe7ab1..0010fda 100644 const theArray = texture.image.data; for (let k = 0, kl = theArray.length; k < kl; k += 4) { -@@ -251,7 +251,7 @@ function fillPositionTexture(texture) { +@@ -250,7 +250,7 @@ function fillPositionTexture(texture) { } } @@ -4146,7 +4120,7 @@ index 8fe7ab1..0010fda 100644 const theArray = texture.image.data; for (let k = 0, kl = theArray.length; k < kl; k += 4) { -@@ -276,7 +276,7 @@ function onWindowResize() { +@@ -275,7 +275,7 @@ function onWindowResize() { renderer.setSize(window.innerWidth, window.innerHeight); } @@ -4156,7 +4130,7 @@ index 8fe7ab1..0010fda 100644 mouseX = event.clientX - windowHalfX; diff --git a/examples-testing/examples/webgl_gpgpu_birds_gltf.ts b/examples-testing/examples/webgl_gpgpu_birds_gltf.ts -index 574c3d4..ab889b5 100644 +index 58aee4f..dfec2ec 100644 --- a/examples-testing/examples/webgl_gpgpu_birds_gltf.ts +++ b/examples-testing/examples/webgl_gpgpu_birds_gltf.ts @@ -2,7 +2,7 @@ import * as THREE from 'three'; @@ -4278,7 +4252,7 @@ index 574c3d4..ab889b5 100644 function init() { container = document.createElement('div'); -@@ -217,12 +230,12 @@ function initComputeRenderer() { +@@ -216,12 +229,12 @@ function initComputeRenderer() { velocityVariable = gpuCompute.addVariable( 'textureVelocity', @@ -4293,7 +4267,7 @@ index 574c3d4..ab889b5 100644 dtPosition, ); -@@ -256,7 +269,7 @@ function initComputeRenderer() { +@@ -255,7 +268,7 @@ function initComputeRenderer() { } } @@ -4302,7 +4276,7 @@ index 574c3d4..ab889b5 100644 const geometry = BirdGeometry; const m = new THREE.MeshStandardMaterial({ -@@ -336,7 +349,7 @@ function initBirds(effectController) { +@@ -335,7 +348,7 @@ function initBirds(effectController) { scene.add(birdMesh); } @@ -4311,7 +4285,7 @@ index 574c3d4..ab889b5 100644 const theArray = texture.image.data; for (let k = 0, kl = theArray.length; k < kl; k += 4) { -@@ -351,7 +364,7 @@ function fillPositionTexture(texture) { +@@ -350,7 +363,7 @@ function fillPositionTexture(texture) { } } @@ -4320,7 +4294,7 @@ index 574c3d4..ab889b5 100644 const theArray = texture.image.data; for (let k = 0, kl = theArray.length; k < kl; k += 4) { -@@ -376,7 +389,7 @@ function onWindowResize() { +@@ -375,7 +388,7 @@ function onWindowResize() { renderer.setSize(window.innerWidth, window.innerHeight); } @@ -4330,7 +4304,7 @@ index 574c3d4..ab889b5 100644 mouseX = event.clientX - windowHalfX; diff --git a/examples-testing/examples/webgl_gpgpu_protoplanet.ts b/examples-testing/examples/webgl_gpgpu_protoplanet.ts -index 7906b0b..1543994 100644 +index b1a7e02..35fb039 100644 --- a/examples-testing/examples/webgl_gpgpu_protoplanet.ts +++ b/examples-testing/examples/webgl_gpgpu_protoplanet.ts @@ -4,22 +4,32 @@ import Stats from 'three/addons/libs/stats.module.js'; @@ -4375,7 +4349,7 @@ index 7906b0b..1543994 100644 init(); animate(); -@@ -87,12 +97,12 @@ function initComputeRenderer() { +@@ -86,12 +96,12 @@ function initComputeRenderer() { velocityVariable = gpuCompute.addVariable( 'textureVelocity', @@ -4390,7 +4364,7 @@ index 7906b0b..1543994 100644 dtPosition, ); -@@ -158,8 +168,8 @@ function initProtoplanets() { +@@ -157,8 +167,8 @@ function initProtoplanets() { // THREE.ShaderMaterial const material = new THREE.ShaderMaterial({ uniforms: particleUniforms, @@ -4401,7 +4375,7 @@ index 7906b0b..1543994 100644 }); material.extensions.drawBuffers = true; -@@ -171,7 +181,7 @@ function initProtoplanets() { +@@ -170,7 +180,7 @@ function initProtoplanets() { scene.add(particles); } @@ -4410,7 +4384,7 @@ index 7906b0b..1543994 100644 const posArray = texturePosition.image.data; const velArray = textureVelocity.image.data; -@@ -268,7 +278,7 @@ function initGUI() { +@@ -267,7 +277,7 @@ function initGUI() { folder2.open(); } @@ -4420,7 +4394,7 @@ index 7906b0b..1543994 100644 } diff --git a/examples-testing/examples/webgl_gpgpu_water.ts b/examples-testing/examples/webgl_gpgpu_water.ts -index eebb24f..eb4fa94 100644 +index dfc4821..36bd4ec 100644 --- a/examples-testing/examples/webgl_gpgpu_water.ts +++ b/examples-testing/examples/webgl_gpgpu_water.ts @@ -3,7 +3,7 @@ import * as THREE from 'three'; @@ -4470,7 +4444,7 @@ index eebb24f..eb4fa94 100644 let spheresEnabled = true; const simplex = new SimplexNoise(); -@@ -128,21 +128,17 @@ function initWater() { +@@ -127,7 +127,7 @@ function initWater() { heightmap: { value: null }, }, ]), @@ -4479,24 +4453,7 @@ index eebb24f..eb4fa94 100644 fragmentShader: THREE.ShaderChunk['meshphong_frag'], }); - material.lights = true; - - // Material attributes from THREE.MeshPhongMaterial -- material.color = new THREE.Color(materialColor); -- material.specular = new THREE.Color(0x111111); -- material.shininess = 50; -- - // Sets the uniforms with the material values -- material.uniforms['diffuse'].value = material.color; -- material.uniforms['specular'].value = material.specular; -- material.uniforms['shininess'].value = Math.max(material.shininess, 1e-4); -+ material.uniforms['diffuse'].value = new THREE.Color(materialColor); -+ material.uniforms['specular'].value = new THREE.Color(0x111111); -+ material.uniforms['shininess'].value = Math.max(50, 1e-4); - material.uniforms['opacity'].value = material.opacity; - - // Defines -@@ -180,7 +176,7 @@ function initWater() { +@@ -175,7 +175,7 @@ function initWater() { heightmapVariable = gpuCompute.addVariable( 'heightmap', @@ -4505,7 +4462,7 @@ index eebb24f..eb4fa94 100644 heightmap0, ); -@@ -198,13 +194,13 @@ function initWater() { +@@ -193,13 +193,13 @@ function initWater() { } // Create compute shader to smooth the water surface and velocity @@ -4521,7 +4478,7 @@ index eebb24f..eb4fa94 100644 { point1: { value: new THREE.Vector2() }, levelTexture: { value: null }, -@@ -227,10 +223,10 @@ function initWater() { +@@ -222,10 +222,10 @@ function initWater() { }); } @@ -4534,7 +4491,7 @@ index eebb24f..eb4fa94 100644 let multR = waterMaxHeight; let mult = 0.025; let r = 0; -@@ -355,12 +351,12 @@ function onWindowResize() { +@@ -350,12 +350,12 @@ function onWindowResize() { renderer.setSize(window.innerWidth, window.innerHeight); } @@ -4550,7 +4507,7 @@ index eebb24f..eb4fa94 100644 setMouseCoords(event.clientX, event.clientY); diff --git a/examples-testing/examples/webgl_materials_modified.ts b/examples-testing/examples/webgl_materials_modified.ts -index 48e4781..b717d93 100644 +index 3708f65..4c1f793 100644 --- a/examples-testing/examples/webgl_materials_modified.ts +++ b/examples-testing/examples/webgl_materials_modified.ts @@ -5,7 +5,7 @@ import Stats from 'three/addons/libs/stats.module.js'; @@ -4571,7 +4528,7 @@ index 48e4781..b717d93 100644 let mesh = new THREE.Mesh(geometry, buildTwistMaterial(2.0)); mesh.position.x = -3.5; -@@ -51,7 +51,7 @@ function init() { +@@ -50,7 +50,7 @@ function init() { window.addEventListener('resize', onWindowResize); } @@ -4580,16 +4537,7 @@ index 48e4781..b717d93 100644 const material = new THREE.MeshNormalMaterial(); material.onBeforeCompile = function (shader) { shader.uniforms.time = { value: 0 }; -@@ -75,7 +75,7 @@ function buildTwistMaterial(amount) { - // Make sure WebGLRenderer doesnt reuse a single program - - material.customProgramCacheKey = function () { -- return amount; -+ return amount.toFixed(1); - }; - - return material; -@@ -105,8 +105,8 @@ function animate() { +@@ -104,8 +104,8 @@ function animate() { function render() { scene.traverse(function (child) { @@ -4601,7 +4549,7 @@ index 48e4781..b717d93 100644 if (shader) { shader.uniforms.time.value = performance.now() / 1000; diff --git a/examples-testing/examples/webgl_pmrem_test.ts b/examples-testing/examples/webgl_pmrem_test.ts -index c2a8058..c3fbbfc 100644 +index b33e4e2..4bbe5d1 100644 --- a/examples-testing/examples/webgl_pmrem_test.ts +++ b/examples-testing/examples/webgl_pmrem_test.ts @@ -5,7 +5,7 @@ import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'; @@ -4613,7 +4561,7 @@ index c2a8058..c3fbbfc 100644 function init() { const width = window.innerWidth; -@@ -65,12 +65,13 @@ function init() { +@@ -64,12 +64,13 @@ function init() { const gui = new GUI(); gui.add({ enabled: true }, 'enabled') .name('PMREM') @@ -4631,7 +4579,7 @@ index c2a8058..c3fbbfc 100644 }); diff --git a/examples-testing/examples/webgl_postprocessing.ts b/examples-testing/examples/webgl_postprocessing.ts -index e7fb488..6979525 100644 +index 944115b..d0afc09 100644 --- a/examples-testing/examples/webgl_postprocessing.ts +++ b/examples-testing/examples/webgl_postprocessing.ts @@ -8,8 +8,8 @@ import { RGBShiftShader } from 'three/addons/shaders/RGBShiftShader.js'; @@ -4646,7 +4594,7 @@ index e7fb488..6979525 100644 init(); animate(); diff --git a/examples-testing/examples/webgl_postprocessing_advanced.ts b/examples-testing/examples/webgl_postprocessing_advanced.ts -index 2a33a3d..76eb02b 100644 +index bf49da5..fde1efb 100644 --- a/examples-testing/examples/webgl_postprocessing_advanced.ts +++ b/examples-testing/examples/webgl_postprocessing_advanced.ts @@ -21,11 +21,21 @@ import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShade @@ -4703,7 +4651,7 @@ index 2a33a3d..76eb02b 100644 }); // -@@ -255,7 +265,7 @@ function onWindowResize() { +@@ -254,7 +264,7 @@ function onWindowResize() { quadMask.scale.set(window.innerWidth / 2, window.innerHeight / 2, 1); } @@ -4713,7 +4661,7 @@ index 2a33a3d..76eb02b 100644 diffuseMap.colorSpace = THREE.SRGBColorSpace; diff --git a/examples-testing/examples/webgl_postprocessing_afterimage.ts b/examples-testing/examples/webgl_postprocessing_afterimage.ts -index a45e6bc..5a1d2d2 100644 +index 2477c50..160e1a9 100644 --- a/examples-testing/examples/webgl_postprocessing_afterimage.ts +++ b/examples-testing/examples/webgl_postprocessing_afterimage.ts @@ -7,10 +7,10 @@ import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; @@ -4730,7 +4678,7 @@ index a45e6bc..5a1d2d2 100644 const params = { enable: true, -@@ -51,7 +51,7 @@ function init() { +@@ -50,7 +50,7 @@ function init() { window.addEventListener('resize', onWindowResize); @@ -4739,17 +4687,8 @@ index a45e6bc..5a1d2d2 100644 for (let i = 0; i < 45; i++) { render(); } -@@ -59,7 +59,7 @@ function init() { - } - - function createGUI() { -- const gui = new GUI({ name: 'Damp setting' }); -+ const gui = new GUI({ title: 'Damp setting' }); - gui.add(afterimagePass.uniforms['damp'], 'value', 0, 1).step(0.001); - gui.add(params, 'enable'); - } diff --git a/examples-testing/examples/webgl_postprocessing_backgrounds.ts b/examples-testing/examples/webgl_postprocessing_backgrounds.ts -index 156e52d..39ee5fc 100644 +index 0bfb655..89c4a5c 100644 --- a/examples-testing/examples/webgl_postprocessing_backgrounds.ts +++ b/examples-testing/examples/webgl_postprocessing_backgrounds.ts @@ -11,10 +11,10 @@ import { ClearPass } from 'three/addons/postprocessing/ClearPass.js'; @@ -4776,7 +4715,7 @@ index 156e52d..39ee5fc 100644 const width = window.innerWidth || 1; const height = window.innerHeight || 1; -@@ -112,7 +112,7 @@ function init() { +@@ -111,7 +111,7 @@ function init() { // postprocessing @@ -4786,7 +4725,7 @@ index 156e52d..39ee5fc 100644 prefix + 'px' + postfix, prefix + 'nx' + postfix, diff --git a/examples-testing/examples/webgl_postprocessing_crossfade.ts b/examples-testing/examples/webgl_postprocessing_crossfade.ts -index 1780757..5eb3b01 100644 +index d3203e3..02cec7a 100644 --- a/examples-testing/examples/webgl_postprocessing_crossfade.ts +++ b/examples-testing/examples/webgl_postprocessing_crossfade.ts @@ -4,9 +4,9 @@ import Stats from 'three/addons/libs/stats.module.js'; @@ -4811,7 +4750,7 @@ index 1780757..5eb3b01 100644 renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setPixelRatio(window.devicePixelRatio); -@@ -57,19 +57,19 @@ function initGUI() { +@@ -56,19 +56,19 @@ function initGUI() { gui.add(transitionParams, 'animate'); gui.add(transitionParams, 'transition', 0, 1, 0.01).listen(); @@ -4834,7 +4773,7 @@ index 1780757..5eb3b01 100644 transition.setTextureThreshold(value); }); } -@@ -78,7 +78,7 @@ function render() { +@@ -77,7 +77,7 @@ function render() { transition.render(clock.getDelta()); } @@ -4843,7 +4782,7 @@ index 1780757..5eb3b01 100644 const mesh = new THREE.InstancedMesh(geometry, material, count); const dummy = new THREE.Object3D(); -@@ -112,192 +112,207 @@ function generateInstancedMesh(geometry, material, count) { +@@ -111,192 +111,207 @@ function generateInstancedMesh(geometry, material, count) { return mesh; } @@ -5188,7 +5127,7 @@ index 1780757..5eb3b01 100644 + } } diff --git a/examples-testing/examples/webgl_postprocessing_fxaa.ts b/examples-testing/examples/webgl_postprocessing_fxaa.ts -index 328afe4..2ca67c6 100644 +index 24270de..4012110 100644 --- a/examples-testing/examples/webgl_postprocessing_fxaa.ts +++ b/examples-testing/examples/webgl_postprocessing_fxaa.ts @@ -6,15 +6,20 @@ import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; @@ -5216,7 +5155,7 @@ index 328afe4..2ca67c6 100644 camera = new THREE.PerspectiveCamera(45, container.offsetWidth / container.offsetHeight, 1, 2000); camera.position.z = 500; diff --git a/examples-testing/examples/webgl_postprocessing_glitch.ts b/examples-testing/examples/webgl_postprocessing_glitch.ts -index e668385..0b6509c 100644 +index 343f2b1..9c6d3f5 100644 --- a/examples-testing/examples/webgl_postprocessing_glitch.ts +++ b/examples-testing/examples/webgl_postprocessing_glitch.ts @@ -5,14 +5,14 @@ import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; @@ -5248,7 +5187,7 @@ index e668385..0b6509c 100644 glitchPass.goWild = wildGlitch.checked; } -@@ -76,7 +76,7 @@ function init() { +@@ -75,7 +75,7 @@ function init() { window.addEventListener('resize', onWindowResize); @@ -5258,7 +5197,7 @@ index e668385..0b6509c 100644 updateOptions(); diff --git a/examples-testing/examples/webgl_postprocessing_godrays.ts b/examples-testing/examples/webgl_postprocessing_godrays.ts -index cd451e7..aa70f31 100644 +index 47e89f6..4329bfe 100644 --- a/examples-testing/examples/webgl_postprocessing_godrays.ts +++ b/examples-testing/examples/webgl_postprocessing_godrays.ts @@ -11,16 +11,37 @@ import { @@ -5303,15 +5242,7 @@ index cd451e7..aa70f31 100644 const orbitRadius = 200; -@@ -54,7 +75,6 @@ function init() { - - const loader = new OBJLoader(); - loader.load('models/obj/tree.obj', function (object) { -- object.material = materialScene; - object.position.set(0, -150, -150); - object.scale.multiplyScalar(400); - scene.add(object); -@@ -106,17 +126,17 @@ function onWindowResize() { +@@ -102,17 +123,17 @@ function onWindowResize() { camera.updateProjectionMatrix(); renderer.setSize(renderTargetWidth, renderTargetHeight); @@ -5335,7 +5266,7 @@ index cd451e7..aa70f31 100644 postprocessing.scene = new THREE.Scene(); postprocessing.camera = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5, -10000, 10000); -@@ -187,10 +207,10 @@ function initPostprocessing(renderTargetWidth, renderTargetHeight) { +@@ -183,10 +204,10 @@ function initPostprocessing(renderTargetWidth, renderTargetHeight) { fragmentShader: godraysFakeSunShader.fragmentShader, }); @@ -5349,15 +5280,7 @@ index cd451e7..aa70f31 100644 postprocessing.quad = new THREE.Mesh(new THREE.PlaneGeometry(1.0, 1.0), postprocessing.materialGodraysGenerate); postprocessing.quad.position.z = -9900; -@@ -198,26 +218,26 @@ function initPostprocessing(renderTargetWidth, renderTargetHeight) { - } - - function animate() { -- requestAnimationFrame(animate, renderer.domElement); -+ requestAnimationFrame(animate); - - stats.begin(); - render(); +@@ -201,19 +222,19 @@ function animate() { stats.end(); } @@ -5384,7 +5307,7 @@ index cd451e7..aa70f31 100644 } function render() { -@@ -245,14 +265,14 @@ function render() { +@@ -241,14 +262,14 @@ function render() { // Give it to the god-ray and sun shaders @@ -5402,7 +5325,7 @@ index cd451e7..aa70f31 100644 renderer.clear(true, true, false); // Sun render. Runs a shader that gives a brightness based on the screen -@@ -268,11 +288,11 @@ function render() { +@@ -264,11 +285,11 @@ function render() { renderer.setScissor(screenSpacePosition.x - sunsqW / 2, screenSpacePosition.y - sunsqH / 2, sunsqW, sunsqH); renderer.setScissorTest(true); @@ -5418,7 +5341,7 @@ index cd451e7..aa70f31 100644 renderer.setScissorTest(false); -@@ -281,23 +301,23 @@ function render() { +@@ -277,23 +298,23 @@ function render() { // Colors scene.overrideMaterial = null; @@ -5448,7 +5371,7 @@ index cd451e7..aa70f31 100644 // -- Render god-rays -- -@@ -316,35 +336,35 @@ function render() { +@@ -312,35 +333,35 @@ function render() { // pass 1 - render into first ping-pong target filterGodRays( @@ -5496,7 +5419,7 @@ index cd451e7..aa70f31 100644 renderer.setRenderTarget(null); renderer.clear(); diff --git a/examples-testing/examples/webgl_postprocessing_masking.ts b/examples-testing/examples/webgl_postprocessing_masking.ts -index 53cda30..f061d6e 100644 +index 3650bfe..88a3d81 100644 --- a/examples-testing/examples/webgl_postprocessing_masking.ts +++ b/examples-testing/examples/webgl_postprocessing_masking.ts @@ -6,8 +6,8 @@ import { ClearPass } from 'three/addons/postprocessing/ClearPass.js'; @@ -5511,7 +5434,7 @@ index 53cda30..f061d6e 100644 init(); animate(); diff --git a/examples-testing/examples/webgl_postprocessing_outline.ts b/examples-testing/examples/webgl_postprocessing_outline.ts -index 4930155..e041a19 100644 +index 60d8b01..9d624be 100644 --- a/examples-testing/examples/webgl_postprocessing_outline.ts +++ b/examples-testing/examples/webgl_postprocessing_outline.ts @@ -12,11 +12,11 @@ import { OutlinePass } from 'three/addons/postprocessing/OutlinePass.js'; @@ -5586,7 +5509,7 @@ index 4930155..e041a19 100644 outlinePass.hiddenEdgeColor.set(value); }); -@@ -224,7 +229,7 @@ function init() { +@@ -223,7 +228,7 @@ function init() { renderer.domElement.style.touchAction = 'none'; renderer.domElement.addEventListener('pointermove', onPointerMove); @@ -5595,7 +5518,7 @@ index 4930155..e041a19 100644 if (event.isPrimary === false) return; mouse.x = (event.clientX / window.innerWidth) * 2 - 1; -@@ -233,7 +238,7 @@ function init() { +@@ -232,7 +237,7 @@ function init() { checkIntersection(); } @@ -5605,7 +5528,7 @@ index 4930155..e041a19 100644 selectedObjects.push(object); } diff --git a/examples-testing/examples/webgl_postprocessing_pixel.ts b/examples-testing/examples/webgl_postprocessing_pixel.ts -index c3bcfe4..b9ee62c 100644 +index fa76309..e6096a1 100644 --- a/examples-testing/examples/webgl_postprocessing_pixel.ts +++ b/examples-testing/examples/webgl_postprocessing_pixel.ts @@ -6,8 +6,14 @@ import { RenderPixelatedPass } from 'three/addons/postprocessing/RenderPixelated @@ -5625,7 +5548,7 @@ index c3bcfe4..b9ee62c 100644 init(); animate(); -@@ -70,7 +76,7 @@ function init() { +@@ -69,7 +75,7 @@ function init() { const boxMaterial = new THREE.MeshPhongMaterial({ map: texChecker2 }); @@ -5634,7 +5557,7 @@ index c3bcfe4..b9ee62c 100644 const mesh = new THREE.Mesh(new THREE.BoxGeometry(boxSideLength, boxSideLength, boxSideLength), boxMaterial); mesh.castShadow = true; mesh.receiveShadow = true; -@@ -169,7 +175,7 @@ function animate() { +@@ -168,7 +174,7 @@ function animate() { // Helper functions @@ -5643,7 +5566,7 @@ index c3bcfe4..b9ee62c 100644 texture.minFilter = THREE.NearestFilter; texture.magFilter = THREE.NearestFilter; texture.generateMipmaps = false; -@@ -179,25 +185,30 @@ function pixelTexture(texture) { +@@ -178,25 +184,30 @@ function pixelTexture(texture) { return texture; } @@ -5679,7 +5602,7 @@ index c3bcfe4..b9ee62c 100644 const worldScreenWidth = (camera.right - camera.left) / camera.zoom; const worldScreenHeight = (camera.top - camera.bottom) / camera.zoom; diff --git a/examples-testing/examples/webgl_postprocessing_procedural.ts b/examples-testing/examples/webgl_postprocessing_procedural.ts -index 0a05229..1ec8cb9 100644 +index 860b1c4..e38910e 100644 --- a/examples-testing/examples/webgl_postprocessing_procedural.ts +++ b/examples-testing/examples/webgl_postprocessing_procedural.ts @@ -3,9 +3,13 @@ import * as THREE from 'three'; @@ -5708,7 +5631,7 @@ index 0a05229..1ec8cb9 100644 renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio(window.devicePixelRatio); -@@ -34,16 +38,16 @@ function init() { +@@ -33,16 +37,16 @@ function init() { // Setup post processing stage postCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); noiseRandom1DMaterial = new THREE.ShaderMaterial({ @@ -5731,23 +5654,8 @@ index 0a05229..1ec8cb9 100644 }); postMaterial = noiseRandom3DMaterial; const postPlane = new THREE.PlaneGeometry(2, 2); -@@ -55,13 +59,7 @@ function init() { - } - - function onWindowResize() { -- const width = window.innerWidth; -- const height = window.innerHeight; -- -- postCamera.aspect = width / height; -- postCamera.updateProjectionMatrix(); -- -- renderer.setSize(width, height); -+ renderer.setSize(window.innerWidth, window.innerHeight); - } - - function animate() { diff --git a/examples-testing/examples/webgl_postprocessing_rgb_halftone.ts b/examples-testing/examples/webgl_postprocessing_rgb_halftone.ts -index cb97a5a..1c15b62 100644 +index e81303e..7d062b7 100644 --- a/examples-testing/examples/webgl_postprocessing_rgb_halftone.ts +++ b/examples-testing/examples/webgl_postprocessing_rgb_halftone.ts @@ -8,11 +8,11 @@ import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; @@ -5765,7 +5673,7 @@ index cb97a5a..1c15b62 100644 init(); animate(); diff --git a/examples-testing/examples/webgl_postprocessing_sao.ts b/examples-testing/examples/webgl_postprocessing_sao.ts -index 6f09ad6..34daf12 100644 +index f8ae1e4..3638258 100644 --- a/examples-testing/examples/webgl_postprocessing_sao.ts +++ b/examples-testing/examples/webgl_postprocessing_sao.ts @@ -8,10 +8,10 @@ import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; @@ -5783,7 +5691,7 @@ index 6f09ad6..34daf12 100644 init(); animate(); -@@ -99,7 +99,7 @@ function init() { +@@ -98,7 +98,7 @@ function init() { SAO: SAOPass.OUTPUT.SAO, Depth: SAOPass.OUTPUT.Depth, Normal: SAOPass.OUTPUT.Normal, @@ -5793,7 +5701,7 @@ index 6f09ad6..34daf12 100644 }); gui.add(saoPass.params, 'saoBias', -1, 1); diff --git a/examples-testing/examples/webgl_postprocessing_smaa.ts b/examples-testing/examples/webgl_postprocessing_smaa.ts -index 36d014d..c4aff5c 100644 +index 5eea466..011e6f4 100644 --- a/examples-testing/examples/webgl_postprocessing_smaa.ts +++ b/examples-testing/examples/webgl_postprocessing_smaa.ts @@ -7,13 +7,17 @@ import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; @@ -5817,7 +5725,7 @@ index 36d014d..c4aff5c 100644 renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio(window.devicePixelRatio); diff --git a/examples-testing/examples/webgl_postprocessing_sobel.ts b/examples-testing/examples/webgl_postprocessing_sobel.ts -index a561fb7..997974b 100644 +index 3266312..4712f25 100644 --- a/examples-testing/examples/webgl_postprocessing_sobel.ts +++ b/examples-testing/examples/webgl_postprocessing_sobel.ts @@ -11,9 +11,9 @@ import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; @@ -5833,7 +5741,7 @@ index a561fb7..997974b 100644 const params = { enable: true, diff --git a/examples-testing/examples/webgl_postprocessing_ssaa.ts b/examples-testing/examples/webgl_postprocessing_ssaa.ts -index f3028fa..9cf7166 100644 +index bca3b46..0aa0074 100644 --- a/examples-testing/examples/webgl_postprocessing_ssaa.ts +++ b/examples-testing/examples/webgl_postprocessing_ssaa.ts @@ -7,10 +7,10 @@ import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; @@ -5860,16 +5768,7 @@ index f3028fa..9cf7166 100644 const width = window.innerWidth || 1; const height = window.innerHeight || 1; -@@ -145,7 +145,7 @@ function onWindowResize() { - const aspect = width / height; - - cameraP.aspect = aspect; -- cameraP.setViewOffset(width, height, params.viewOffset, 0, width, height); -+ cameraP.setViewOffset(width, height, params.viewOffsetX, 0, width, height); - cameraO.updateProjectionMatrix(); - - cameraO.left = -height * aspect; -@@ -201,7 +201,7 @@ function animate() { +@@ -200,7 +200,7 @@ function animate() { ssaaRenderPassP.enabled = params.camera === 'perspective'; ssaaRenderPassO.enabled = params.camera === 'orthographic'; @@ -5879,7 +5778,7 @@ index f3028fa..9cf7166 100644 composer.render(); diff --git a/examples-testing/examples/webgl_postprocessing_ssao.ts b/examples-testing/examples/webgl_postprocessing_ssao.ts -index 4c03241..07013bf 100644 +index 0f7f8e4..6638518 100644 --- a/examples-testing/examples/webgl_postprocessing_ssao.ts +++ b/examples-testing/examples/webgl_postprocessing_ssao.ts @@ -7,10 +7,10 @@ import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; @@ -5897,7 +5796,7 @@ index 4c03241..07013bf 100644 init(); animate(); -@@ -80,7 +80,7 @@ function init() { +@@ -79,7 +79,7 @@ function init() { Beauty: SSAOPass.OUTPUT.Beauty, Depth: SSAOPass.OUTPUT.Depth, Normal: SSAOPass.OUTPUT.Normal, @@ -5907,7 +5806,7 @@ index 4c03241..07013bf 100644 }); gui.add(ssaoPass, 'kernelRadius').min(0).max(32); diff --git a/examples-testing/examples/webgl_postprocessing_ssr.ts b/examples-testing/examples/webgl_postprocessing_ssr.ts -index 5a2c6a9..046203f 100644 +index 5fb1e01..257941b 100644 --- a/examples-testing/examples/webgl_postprocessing_ssr.ts +++ b/examples-testing/examples/webgl_postprocessing_ssr.ts @@ -18,17 +18,17 @@ const params = { @@ -5948,7 +5847,7 @@ index 5a2c6a9..046203f 100644 geometry = new THREE.BoxGeometry(0.05, 0.05, 0.05); material = new THREE.MeshStandardMaterial({ color: 'green' }); -@@ -207,7 +207,7 @@ function init() { +@@ -206,7 +206,7 @@ function init() { Normal: SSRPass.OUTPUT.Normal, Metalness: SSRPass.OUTPUT.Metalness, }) @@ -5958,7 +5857,7 @@ index 5a2c6a9..046203f 100644 }); ssrPass.opacity = 1; diff --git a/examples-testing/examples/webgl_postprocessing_taa.ts b/examples-testing/examples/webgl_postprocessing_taa.ts -index b4d2b37..be57963 100644 +index b2a12b5..b1efc76 100644 --- a/examples-testing/examples/webgl_postprocessing_taa.ts +++ b/examples-testing/examples/webgl_postprocessing_taa.ts @@ -8,8 +8,13 @@ import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; @@ -5987,7 +5886,7 @@ index b4d2b37..be57963 100644 renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio(window.devicePixelRatio); diff --git a/examples-testing/examples/webgl_postprocessing_unreal_bloom.ts b/examples-testing/examples/webgl_postprocessing_unreal_bloom.ts -index 1317f0f..fd7c58b 100644 +index 886f77f..70ac7b8 100644 --- a/examples-testing/examples/webgl_postprocessing_unreal_bloom.ts +++ b/examples-testing/examples/webgl_postprocessing_unreal_bloom.ts @@ -10,8 +10,8 @@ import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; @@ -6035,11 +5934,11 @@ index 1317f0f..fd7c58b 100644 - toneMappingFolder.add(params, 'exposure', 0.1, 2).onChange(function (value) { + toneMappingFolder.add(params, 'exposure', 0.1, 2).onChange(function (value: number) { - outputPass.toneMappingExposure = Math.pow(value, 4.0); + renderer.toneMappingExposure = Math.pow(value, 4.0); }); diff --git a/examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts b/examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts -index 9c2e530..c0e796b 100644 +index d633806..cd11498 100644 --- a/examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts +++ b/examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts @@ -22,7 +22,7 @@ const params = { @@ -6091,7 +5990,7 @@ index 9c2e530..c0e796b 100644 -toneMappingFolder.add(params, 'exposure', 0.1, 2).onChange(function (value) { +toneMappingFolder.add(params, 'exposure', 0.1, 2).onChange(function (value: number) { - outputPass.toneMappingExposure = Math.pow(value, 4.0); + renderer.toneMappingExposure = Math.pow(value, 4.0); render(); }); @@ -6139,7 +6038,7 @@ index 9c2e530..c0e796b 100644 } } diff --git a/examples-testing/examples/webgl_raymarching_reflect.ts b/examples-testing/examples/webgl_raymarching_reflect.ts -index b19db24..53d07f6 100644 +index 96f9a81..43bd75d 100644 --- a/examples-testing/examples/webgl_raymarching_reflect.ts +++ b/examples-testing/examples/webgl_raymarching_reflect.ts @@ -5,11 +5,11 @@ import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; @@ -6158,16 +6057,7 @@ index b19db24..53d07f6 100644 const config = { saveImage: function () { -@@ -25,7 +25,7 @@ render(); - function init() { - renderer = new THREE.WebGLRenderer({ canvas: canvas }); - renderer.setPixelRatio(window.devicePixelRatio); -- renderer.setSize(config.resolution, config.resolution); -+ renderer.setSize(parseInt(config.resolution), parseInt(config.resolution)); - renderer.useLegacyLights = false; - - window.addEventListener('resize', onWindowResize); -@@ -49,8 +49,8 @@ function init() { +@@ -48,8 +48,8 @@ function init() { cameraWorldMatrix: { value: camera.matrixWorld }, cameraProjectionMatrixInverse: { value: camera.projectionMatrixInverse.clone() }, }, @@ -6178,17 +6068,8 @@ index b19db24..53d07f6 100644 }); mesh = new THREE.Mesh(geometry, material); mesh.frustumCulled = false; -@@ -73,7 +73,7 @@ function onWindowResize() { - if (config.resolution === 'full') { - renderer.setSize(window.innerWidth, window.innerHeight); - } else { -- renderer.setSize(config.resolution, config.resolution); -+ renderer.setSize(parseInt(config.resolution), parseInt(config.resolution)); - } - - camera.aspect = canvas.width / canvas.height; diff --git a/examples-testing/examples/webgl_shadowmap_csm.ts b/examples-testing/examples/webgl_shadowmap_csm.ts -index 1776942..3d405af 100644 +index f9df4ab..21ce7ad 100644 --- a/examples-testing/examples/webgl_shadowmap_csm.ts +++ b/examples-testing/examples/webgl_shadowmap_csm.ts @@ -2,16 +2,22 @@ import * as THREE from 'three'; @@ -6217,7 +6098,7 @@ index 1776942..3d405af 100644 lightX: -1, lightY: -1, lightZ: -1, -@@ -119,12 +125,12 @@ function init() { +@@ -118,12 +124,12 @@ function init() { const gui = new GUI(); @@ -6232,7 +6113,7 @@ index 1776942..3d405af 100644 csm.fade = value; csm.updateFrustums(); }); -@@ -132,45 +138,45 @@ function init() { +@@ -131,45 +137,45 @@ function init() { gui.add(params, 'far', 1, 5000) .step(1) .name('shadow far') @@ -6285,7 +6166,7 @@ index 1776942..3d405af 100644 for (let i = 0; i < csm.lights.length; i++) { csm.lights[i].shadow.camera.near = value; csm.lights[i].shadow.camera.updateProjectionMatrix(); -@@ -179,7 +185,7 @@ function init() { +@@ -178,7 +184,7 @@ function init() { gui.add(params, 'lightFar', 1, 10000) .name('light far') @@ -6295,7 +6176,7 @@ index 1776942..3d405af 100644 csm.lights[i].shadow.camera.far = value; csm.lights[i].shadow.camera.updateProjectionMatrix(); diff --git a/examples-testing/examples/webgl_shadowmap_pcss.ts b/examples-testing/examples/webgl_shadowmap_pcss.ts -index ca1ce0d..25ea881 100644 +index 91ba360..230059a 100644 --- a/examples-testing/examples/webgl_shadowmap_pcss.ts +++ b/examples-testing/examples/webgl_shadowmap_pcss.ts @@ -4,10 +4,10 @@ import Stats from 'three/addons/libs/stats.module.js'; @@ -6328,7 +6209,7 @@ index ca1ce0d..25ea881 100644 THREE.ShaderChunk.shadowmap_pars_fragment = shader; diff --git a/examples-testing/examples/webgl_shadowmap_progressive.ts b/examples-testing/examples/webgl_shadowmap_progressive.ts -index 6bac312..ce14ee0 100644 +index eaf6e32..d3592c8 100644 --- a/examples-testing/examples/webgl_shadowmap_progressive.ts +++ b/examples-testing/examples/webgl_shadowmap_progressive.ts @@ -9,17 +9,17 @@ import { ProgressiveLightMap } from 'three/addons/misc/ProgressiveLightMap.js'; @@ -6360,7 +6241,7 @@ index 6bac312..ce14ee0 100644 const params = { Enable: true, 'Blur Edges': true, -@@ -99,11 +99,11 @@ function init() { +@@ -98,11 +98,11 @@ function init() { // model function loadModel() { object.traverse(function (child) { @@ -6374,7 +6255,7 @@ index 6bac312..ce14ee0 100644 // This adds the model to the lightmap lightmapObjects.push(child); -@@ -129,7 +129,7 @@ function init() { +@@ -128,7 +128,7 @@ function init() { object.add(lightTarget); @@ -6383,16 +6264,7 @@ index 6bac312..ce14ee0 100644 for (let i = 0; i < 300; i++) { render(); } -@@ -155,7 +155,7 @@ function init() { - } - - function createGUI() { -- const gui = new GUI({ name: 'Accumulation Settings' }); -+ const gui = new GUI({ title: 'Accumulation Settings' }); - gui.add(params, 'Enable'); - gui.add(params, 'Blur Edges'); - gui.add(params, 'Blend Window', 1, 500).step(1); -@@ -189,9 +189,9 @@ function render() { +@@ -188,9 +188,9 @@ function render() { // Sometimes they will be uniformly sampled from the upper hemisphere if (Math.random() > params['Ambient Weight']) { dirLights[l].position.set( @@ -6406,7 +6278,7 @@ index 6bac312..ce14ee0 100644 } else { // Uniform Hemispherical Surface Distribution for Ambient Occlusion diff --git a/examples-testing/examples/webgl_simple_gi.ts b/examples-testing/examples/webgl_simple_gi.ts -index 11522c1..c96df96 100644 +index cd5d567..12c30ec 100644 --- a/examples-testing/examples/webgl_simple_gi.ts +++ b/examples-testing/examples/webgl_simple_gi.ts @@ -3,7 +3,7 @@ import * as THREE from 'three'; @@ -6592,7 +6464,7 @@ index 11522c1..c96df96 100644 init(); animate(); diff --git a/examples-testing/examples/webxr_ar_cones.ts b/examples-testing/examples/webxr_ar_cones.ts -index c2357f8..eab4381 100644 +index 996e41f..03af8ca 100644 --- a/examples-testing/examples/webxr_ar_cones.ts +++ b/examples-testing/examples/webxr_ar_cones.ts @@ -1,8 +1,8 @@ @@ -6607,7 +6479,7 @@ index c2357f8..eab4381 100644 init(); animate(); diff --git a/examples-testing/examples/webxr_ar_hittest.ts b/examples-testing/examples/webxr_ar_hittest.ts -index b6feada..ba190ee 100644 +index 5540c90..0cd8a4f 100644 --- a/examples-testing/examples/webxr_ar_hittest.ts +++ b/examples-testing/examples/webxr_ar_hittest.ts @@ -1,13 +1,13 @@ @@ -6629,7 +6501,7 @@ index b6feada..ba190ee 100644 let hitTestSourceRequested = false; init(); -@@ -82,14 +82,14 @@ function animate() { +@@ -81,14 +81,14 @@ function animate() { renderer.setAnimationLoop(render); } @@ -6647,7 +6519,7 @@ index b6feada..ba190ee 100644 hitTestSource = source; }); }); -@@ -109,7 +109,7 @@ function render(timestamp, frame) { +@@ -108,7 +108,7 @@ function render(timestamp, frame) { const hit = hitTestResults[0]; reticle.visible = true; @@ -6657,7 +6529,7 @@ index b6feada..ba190ee 100644 reticle.visible = false; } diff --git a/examples-testing/examples/webxr_ar_lighting.ts b/examples-testing/examples/webxr_ar_lighting.ts -index 81aa8e0..6c4fc65 100644 +index 1a9c4de..53cb684 100644 --- a/examples-testing/examples/webxr_ar_lighting.ts +++ b/examples-testing/examples/webxr_ar_lighting.ts @@ -3,9 +3,9 @@ import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'; @@ -6674,7 +6546,7 @@ index 81aa8e0..6c4fc65 100644 init(); animate(); diff --git a/examples-testing/examples/webxr_vr_handinput.ts b/examples-testing/examples/webxr_vr_handinput.ts -index 86f70ce..44a61ca 100644 +index a896103..797674f 100644 --- a/examples-testing/examples/webxr_vr_handinput.ts +++ b/examples-testing/examples/webxr_vr_handinput.ts @@ -4,13 +4,13 @@ import { VRButton } from 'three/addons/webxr/VRButton.js'; @@ -6698,7 +6570,7 @@ index 86f70ce..44a61ca 100644 init(); animate(); diff --git a/examples-testing/examples/webxr_vr_panorama.ts b/examples-testing/examples/webxr_vr_panorama.ts -index 1aeba88..4612ebe 100644 +index fdd23aa..bd103ef 100644 --- a/examples-testing/examples/webxr_vr_panorama.ts +++ b/examples-testing/examples/webxr_vr_panorama.ts @@ -1,9 +1,9 @@ @@ -6714,7 +6586,7 @@ index 1aeba88..4612ebe 100644 init(); animate(); -@@ -54,8 +54,8 @@ function init() { +@@ -53,8 +53,8 @@ function init() { window.addEventListener('resize', onWindowResize); } @@ -6725,7 +6597,7 @@ index 1aeba88..4612ebe 100644 for (let i = 0; i < tilesNum; i++) { textures[i] = new THREE.Texture(); -@@ -68,7 +68,7 @@ function getTexturesFromAtlasFile(atlasImgUrl, tilesNum) { +@@ -67,7 +67,7 @@ function getTexturesFromAtlasFile(atlasImgUrl, tilesNum) { for (let i = 0; i < textures.length; i++) { canvas = document.createElement('canvas'); @@ -6735,7 +6607,7 @@ index 1aeba88..4612ebe 100644 canvas.width = tileWidth; context.drawImage(imageObj, tileWidth * i, 0, tileWidth, tileWidth, 0, 0, tileWidth, tileWidth); diff --git a/examples-testing/examples/webxr_vr_panorama_depth.ts b/examples-testing/examples/webxr_vr_panorama_depth.ts -index cad78ad..9d632af 100644 +index a09b733..292719d 100644 --- a/examples-testing/examples/webxr_vr_panorama_depth.ts +++ b/examples-testing/examples/webxr_vr_panorama_depth.ts @@ -1,13 +1,17 @@ @@ -6759,7 +6631,7 @@ index cad78ad..9d632af 100644 clock = new THREE.Clock(); diff --git a/examples-testing/examples/webxr_vr_rollercoaster.ts b/examples-testing/examples/webxr_vr_rollercoaster.ts -index 66f8f89..2e12898 100644 +index b659652..a10b469 100644 --- a/examples-testing/examples/webxr_vr_rollercoaster.ts +++ b/examples-testing/examples/webxr_vr_rollercoaster.ts @@ -9,7 +9,7 @@ import { @@ -6771,7 +6643,7 @@ index 66f8f89..2e12898 100644 const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setPixelRatio(window.devicePixelRatio); -@@ -87,7 +87,7 @@ const curve = (function () { +@@ -86,7 +86,7 @@ const curve = (function () { const vector2 = new THREE.Vector3(); return { @@ -6780,7 +6652,7 @@ index 66f8f89..2e12898 100644 t = t * PI2; const x = Math.sin(t * 3) * Math.cos(t * 4) * 50; -@@ -97,7 +97,7 @@ const curve = (function () { +@@ -96,7 +96,7 @@ const curve = (function () { return vector.set(x, y, z).multiplyScalar(2); }, @@ -6789,7 +6661,7 @@ index 66f8f89..2e12898 100644 const delta = 0.0001; const t1 = Math.max(0, t - delta); const t2 = Math.min(1, t + delta); -@@ -130,7 +130,7 @@ mesh = new THREE.Mesh(geometry, material); +@@ -129,7 +129,7 @@ mesh = new THREE.Mesh(geometry, material); mesh.position.y = 0.1; scene.add(mesh); @@ -6799,7 +6671,7 @@ index 66f8f89..2e12898 100644 // diff --git a/examples-testing/examples/webxr_vr_sandbox.ts b/examples-testing/examples/webxr_vr_sandbox.ts -index 408df61..bcee51e 100644 +index aa80cf7..e929206 100644 --- a/examples-testing/examples/webxr_vr_sandbox.ts +++ b/examples-testing/examples/webxr_vr_sandbox.ts @@ -12,9 +12,9 @@ import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFa @@ -6815,7 +6687,7 @@ index 408df61..bcee51e 100644 const parameters = { radius: 0.6, -@@ -198,7 +198,7 @@ function animate() { +@@ -197,7 +197,7 @@ function animate() { function render() { const time = performance.now() * 0.0002; @@ -6824,7 +6696,7 @@ index 408df61..bcee51e 100644 torus.rotation.x = time * 0.4; torus.rotation.y = time; -@@ -206,5 +206,9 @@ function render() { +@@ -205,5 +205,9 @@ function render() { stats.update(); // Canvas elements doesn't trigger DOM updates, so we have to update the texture @@ -6836,7 +6708,7 @@ index 408df61..bcee51e 100644 + update(): void; } diff --git a/examples-testing/examples/webxr_vr_video.ts b/examples-testing/examples/webxr_vr_video.ts -index 53769e1..44628a6 100644 +index 2baded4..9c3f5e7 100644 --- a/examples-testing/examples/webxr_vr_video.ts +++ b/examples-testing/examples/webxr_vr_video.ts @@ -1,13 +1,13 @@ From 987edc440b2c0a4e41ce78cffebf718a56c1306e Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Thu, 27 Jul 2023 22:13:01 -0400 Subject: [PATCH 5/5] Delete examples --- examples-testing/examples/css2d_label.ts | 186 ---- examples-testing/examples/css3d_molecules.ts | 353 -------- .../examples/css3d_orthographic.ts | 208 ----- .../examples/css3d_periodictable.ts | 793 ------------------ examples-testing/examples/css3d_sandbox.ts | 180 ---- examples-testing/examples/css3d_sprites.ts | 157 ---- examples-testing/examples/css3d_youtube.ts | 79 -- examples-testing/examples/games_fps.ts | 373 -------- .../examples/misc_animation_groups.ts | 131 --- .../examples/misc_animation_keys.ts | 135 --- .../examples/misc_boxselection.ts | 142 ---- .../examples/misc_controls_arcball.ts | 210 ----- .../examples/misc_controls_drag.ts | 148 ---- .../examples/misc_controls_fly.ts | 227 ----- .../examples/misc_controls_map.ts | 100 --- .../examples/misc_controls_orbit.ts | 91 -- .../examples/misc_controls_pointerlock.ts | 247 ------ .../examples/misc_controls_trackball.ts | 136 --- .../examples/misc_controls_transform.ts | 172 ---- .../examples/misc_exporter_draco.ts | 118 --- .../examples/misc_exporter_gltf.ts | 493 ----------- .../examples/misc_exporter_obj.ts | 194 ----- .../examples/misc_exporter_ply.ts | 157 ---- .../examples/misc_exporter_stl.ts | 130 --- .../examples/misc_exporter_usdz.ts | 110 --- examples-testing/examples/misc_lookat.ts | 97 --- examples-testing/examples/misc_uv_tests.ts | 44 - .../examples/physics_ammo_instancing.ts | 122 --- .../examples/physics_rapier_instancing.ts | 122 --- examples-testing/examples/svg_lines.ts | 87 -- examples-testing/examples/svg_sandbox.ts | 212 ----- .../examples/webaudio_orientation.ts | 141 ---- examples-testing/examples/webaudio_sandbox.ts | 228 ----- examples-testing/examples/webaudio_timing.ts | 158 ---- .../examples/webaudio_visualizer.ts | 93 -- ...ebgl2_buffergeometry_attributes_integer.ts | 121 --- .../webgl2_buffergeometry_attributes_none.ts | 64 -- .../examples/webgl2_materials_texture3d.ts | 133 --- ...ebgl2_materials_texture3d_partialupdate.ts | 333 -------- .../examples/webgl2_multiple_rendertargets.ts | 139 --- .../webgl2_multisampled_renderbuffers.ts | 139 --- .../webgl2_texture2darray_compressed.ts | 96 --- examples-testing/examples/webgl2_ubo.ts | 146 ---- .../examples/webgl2_volume_cloud.ts | 286 ------- .../examples/webgl2_volume_instancing.ts | 198 ----- .../examples/webgl2_volume_perlin.ts | 215 ----- .../examples/webgl_animation_keyframes.ts | 82 -- .../examples/webgl_animation_multiple.ts | 104 --- .../webgl_animation_skinning_morph.ts | 189 ----- .../examples/webgl_buffergeometry.ts | 182 ---- ...fergeometry_custom_attributes_particles.ts | 108 --- .../webgl_buffergeometry_drawrange.ts | 241 ------ .../webgl_buffergeometry_glbufferattribute.ts | 145 ---- .../examples/webgl_buffergeometry_indexed.ts | 142 ---- .../webgl_buffergeometry_instancing.ts | 148 ---- ...gl_buffergeometry_instancing_billboards.ts | 98 --- ...l_buffergeometry_instancing_interleaved.ts | 162 ---- .../examples/webgl_buffergeometry_lines.ts | 123 --- .../webgl_buffergeometry_lines_indexed.ts | 186 ---- .../examples/webgl_buffergeometry_points.ts | 113 --- ...webgl_buffergeometry_points_interleaved.ts | 127 --- .../webgl_buffergeometry_rawshader.ts | 102 --- .../webgl_buffergeometry_selective_draw.ts | 151 ---- .../examples/webgl_buffergeometry_uint.ts | 182 ---- examples-testing/examples/webgl_camera.ts | 214 ----- .../webgl_camera_logarithmicdepthbuffer.ts | 248 ------ examples-testing/examples/webgl_clipping.ts | 184 ---- .../examples/webgl_clipping_advanced.ts | 356 -------- .../examples/webgl_clipping_intersection.ts | 126 --- .../examples/webgl_clipping_stencil.ts | 260 ------ .../examples/webgl_custom_attributes.ts | 102 --- .../examples/webgl_custom_attributes_lines.ts | 123 --- .../webgl_custom_attributes_points.ts | 119 --- .../webgl_custom_attributes_points2.ts | 195 ----- .../webgl_custom_attributes_points3.ts | 202 ----- examples-testing/examples/webgl_decals.ts | 238 ------ .../examples/webgl_effects_anaglyph.ts | 116 --- .../examples/webgl_effects_ascii.ts | 87 -- .../examples/webgl_effects_parallaxbarrier.ts | 116 --- .../examples/webgl_effects_peppersghost.ts | 87 -- .../examples/webgl_effects_stereo.ts | 104 --- .../examples/webgl_framebuffer_texture.ts | 153 ---- .../examples/webgl_furnace_test.ts | 96 --- examples-testing/examples/webgl_geometries.ts | 139 --- .../examples/webgl_geometries_parametric.ts | 126 --- .../examples/webgl_gpgpu_birds.ts | 319 ------- .../examples/webgl_gpgpu_birds_gltf.ts | 421 ---------- .../examples/webgl_gpgpu_protoplanet.ts | 288 ------- .../examples/webgl_gpgpu_water.ts | 403 --------- .../examples/webgl_materials_modified.ts | 117 --- examples-testing/examples/webgl_pmrem_test.ts | 141 ---- .../examples/webgl_postprocessing.ts | 88 -- .../examples/webgl_postprocessing_advanced.ts | 306 ------- .../webgl_postprocessing_afterimage.ts | 86 -- .../webgl_postprocessing_backgrounds.ts | 216 ----- .../webgl_postprocessing_crossfade.ts | 302 ------- .../examples/webgl_postprocessing_fxaa.ts | 135 --- .../examples/webgl_postprocessing_glitch.ts | 99 --- .../examples/webgl_postprocessing_godrays.ts | 349 -------- .../examples/webgl_postprocessing_masking.ts | 102 --- .../examples/webgl_postprocessing_outline.ts | 284 ------- .../examples/webgl_postprocessing_pixel.ts | 230 ----- .../webgl_postprocessing_procedural.ts | 81 -- .../webgl_postprocessing_rgb_halftone.ts | 169 ---- .../examples/webgl_postprocessing_sao.ts | 142 ---- .../examples/webgl_postprocessing_smaa.ts | 93 -- .../examples/webgl_postprocessing_sobel.ts | 113 --- .../examples/webgl_postprocessing_ssaa.ts | 208 ----- .../examples/webgl_postprocessing_ssao.ts | 117 --- .../examples/webgl_postprocessing_ssr.ts | 263 ------ .../examples/webgl_postprocessing_taa.ts | 141 ---- .../webgl_postprocessing_unreal_bloom.ts | 129 --- ...l_postprocessing_unreal_bloom_selective.ts | 195 ----- .../examples/webgl_raymarching_reflect.ts | 96 --- .../examples/webgl_shadowmap_csm.ts | 244 ------ .../examples/webgl_shadowmap_pcss.ts | 163 ---- .../examples/webgl_shadowmap_progressive.ts | 214 ----- examples-testing/examples/webgl_simple_gi.ts | 175 ---- examples-testing/examples/webxr_ar_cones.ts | 70 -- examples-testing/examples/webxr_ar_hittest.ts | 119 --- .../examples/webxr_ar_lighting.ts | 128 --- .../examples/webxr_ar_plane_detection.ts | 46 - .../examples/webxr_vr_handinput.ts | 126 --- .../examples/webxr_vr_panorama.ts | 96 --- .../examples/webxr_vr_panorama_depth.ts | 94 --- .../examples/webxr_vr_rollercoaster.ts | 212 ----- examples-testing/examples/webxr_vr_sandbox.ts | 209 ----- examples-testing/examples/webxr_vr_video.ts | 96 --- 128 files changed, 22045 deletions(-) delete mode 100644 examples-testing/examples/css2d_label.ts delete mode 100644 examples-testing/examples/css3d_molecules.ts delete mode 100644 examples-testing/examples/css3d_orthographic.ts delete mode 100644 examples-testing/examples/css3d_periodictable.ts delete mode 100644 examples-testing/examples/css3d_sandbox.ts delete mode 100644 examples-testing/examples/css3d_sprites.ts delete mode 100644 examples-testing/examples/css3d_youtube.ts delete mode 100644 examples-testing/examples/games_fps.ts delete mode 100644 examples-testing/examples/misc_animation_groups.ts delete mode 100644 examples-testing/examples/misc_animation_keys.ts delete mode 100644 examples-testing/examples/misc_boxselection.ts delete mode 100644 examples-testing/examples/misc_controls_arcball.ts delete mode 100644 examples-testing/examples/misc_controls_drag.ts delete mode 100644 examples-testing/examples/misc_controls_fly.ts delete mode 100644 examples-testing/examples/misc_controls_map.ts delete mode 100644 examples-testing/examples/misc_controls_orbit.ts delete mode 100644 examples-testing/examples/misc_controls_pointerlock.ts delete mode 100644 examples-testing/examples/misc_controls_trackball.ts delete mode 100644 examples-testing/examples/misc_controls_transform.ts delete mode 100644 examples-testing/examples/misc_exporter_draco.ts delete mode 100644 examples-testing/examples/misc_exporter_gltf.ts delete mode 100644 examples-testing/examples/misc_exporter_obj.ts delete mode 100644 examples-testing/examples/misc_exporter_ply.ts delete mode 100644 examples-testing/examples/misc_exporter_stl.ts delete mode 100644 examples-testing/examples/misc_exporter_usdz.ts delete mode 100644 examples-testing/examples/misc_lookat.ts delete mode 100644 examples-testing/examples/misc_uv_tests.ts delete mode 100644 examples-testing/examples/physics_ammo_instancing.ts delete mode 100644 examples-testing/examples/physics_rapier_instancing.ts delete mode 100644 examples-testing/examples/svg_lines.ts delete mode 100644 examples-testing/examples/svg_sandbox.ts delete mode 100644 examples-testing/examples/webaudio_orientation.ts delete mode 100644 examples-testing/examples/webaudio_sandbox.ts delete mode 100644 examples-testing/examples/webaudio_timing.ts delete mode 100644 examples-testing/examples/webaudio_visualizer.ts delete mode 100644 examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts delete mode 100644 examples-testing/examples/webgl2_buffergeometry_attributes_none.ts delete mode 100644 examples-testing/examples/webgl2_materials_texture3d.ts delete mode 100644 examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts delete mode 100644 examples-testing/examples/webgl2_multiple_rendertargets.ts delete mode 100644 examples-testing/examples/webgl2_multisampled_renderbuffers.ts delete mode 100644 examples-testing/examples/webgl2_texture2darray_compressed.ts delete mode 100644 examples-testing/examples/webgl2_ubo.ts delete mode 100644 examples-testing/examples/webgl2_volume_cloud.ts delete mode 100644 examples-testing/examples/webgl2_volume_instancing.ts delete mode 100644 examples-testing/examples/webgl2_volume_perlin.ts delete mode 100644 examples-testing/examples/webgl_animation_keyframes.ts delete mode 100644 examples-testing/examples/webgl_animation_multiple.ts delete mode 100644 examples-testing/examples/webgl_animation_skinning_morph.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_drawrange.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_indexed.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_instancing.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_lines.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_lines_indexed.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_points.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_points_interleaved.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_rawshader.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_selective_draw.ts delete mode 100644 examples-testing/examples/webgl_buffergeometry_uint.ts delete mode 100644 examples-testing/examples/webgl_camera.ts delete mode 100644 examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts delete mode 100644 examples-testing/examples/webgl_clipping.ts delete mode 100644 examples-testing/examples/webgl_clipping_advanced.ts delete mode 100644 examples-testing/examples/webgl_clipping_intersection.ts delete mode 100644 examples-testing/examples/webgl_clipping_stencil.ts delete mode 100644 examples-testing/examples/webgl_custom_attributes.ts delete mode 100644 examples-testing/examples/webgl_custom_attributes_lines.ts delete mode 100644 examples-testing/examples/webgl_custom_attributes_points.ts delete mode 100644 examples-testing/examples/webgl_custom_attributes_points2.ts delete mode 100644 examples-testing/examples/webgl_custom_attributes_points3.ts delete mode 100644 examples-testing/examples/webgl_decals.ts delete mode 100644 examples-testing/examples/webgl_effects_anaglyph.ts delete mode 100644 examples-testing/examples/webgl_effects_ascii.ts delete mode 100644 examples-testing/examples/webgl_effects_parallaxbarrier.ts delete mode 100644 examples-testing/examples/webgl_effects_peppersghost.ts delete mode 100644 examples-testing/examples/webgl_effects_stereo.ts delete mode 100644 examples-testing/examples/webgl_framebuffer_texture.ts delete mode 100644 examples-testing/examples/webgl_furnace_test.ts delete mode 100644 examples-testing/examples/webgl_geometries.ts delete mode 100644 examples-testing/examples/webgl_geometries_parametric.ts delete mode 100644 examples-testing/examples/webgl_gpgpu_birds.ts delete mode 100644 examples-testing/examples/webgl_gpgpu_birds_gltf.ts delete mode 100644 examples-testing/examples/webgl_gpgpu_protoplanet.ts delete mode 100644 examples-testing/examples/webgl_gpgpu_water.ts delete mode 100644 examples-testing/examples/webgl_materials_modified.ts delete mode 100644 examples-testing/examples/webgl_pmrem_test.ts delete mode 100644 examples-testing/examples/webgl_postprocessing.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_advanced.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_afterimage.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_backgrounds.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_crossfade.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_fxaa.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_glitch.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_godrays.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_masking.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_outline.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_pixel.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_procedural.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_rgb_halftone.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_sao.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_smaa.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_sobel.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_ssaa.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_ssao.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_ssr.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_taa.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_unreal_bloom.ts delete mode 100644 examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts delete mode 100644 examples-testing/examples/webgl_raymarching_reflect.ts delete mode 100644 examples-testing/examples/webgl_shadowmap_csm.ts delete mode 100644 examples-testing/examples/webgl_shadowmap_pcss.ts delete mode 100644 examples-testing/examples/webgl_shadowmap_progressive.ts delete mode 100644 examples-testing/examples/webgl_simple_gi.ts delete mode 100644 examples-testing/examples/webxr_ar_cones.ts delete mode 100644 examples-testing/examples/webxr_ar_hittest.ts delete mode 100644 examples-testing/examples/webxr_ar_lighting.ts delete mode 100644 examples-testing/examples/webxr_ar_plane_detection.ts delete mode 100644 examples-testing/examples/webxr_vr_handinput.ts delete mode 100644 examples-testing/examples/webxr_vr_panorama.ts delete mode 100644 examples-testing/examples/webxr_vr_panorama_depth.ts delete mode 100644 examples-testing/examples/webxr_vr_rollercoaster.ts delete mode 100644 examples-testing/examples/webxr_vr_sandbox.ts delete mode 100644 examples-testing/examples/webxr_vr_video.ts diff --git a/examples-testing/examples/css2d_label.ts b/examples-testing/examples/css2d_label.ts deleted file mode 100644 index 48a2d1f05..000000000 --- a/examples-testing/examples/css2d_label.ts +++ /dev/null @@ -1,186 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let gui; - -let camera, scene, renderer, labelRenderer; - -const layers = { - 'Toggle Name': function () { - camera.layers.toggle(0); - }, - 'Toggle Mass': function () { - camera.layers.toggle(1); - }, - 'Enable All': function () { - camera.layers.enableAll(); - }, - - 'Disable All': function () { - camera.layers.disableAll(); - }, -}; - -const clock = new THREE.Clock(); -const textureLoader = new THREE.TextureLoader(); - -let moon; - -init(); -animate(); - -function init() { - const EARTH_RADIUS = 1; - const MOON_RADIUS = 0.27; - - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200); - camera.position.set(10, 5, 20); - camera.layers.enableAll(); - - scene = new THREE.Scene(); - - const dirLight = new THREE.DirectionalLight(0xffffff, 3); - dirLight.position.set(0, 0, 1); - dirLight.layers.enableAll(); - scene.add(dirLight); - - const axesHelper = new THREE.AxesHelper(5); - axesHelper.layers.enableAll(); - scene.add(axesHelper); - - // - - const earthGeometry = new THREE.SphereGeometry(EARTH_RADIUS, 16, 16); - const earthMaterial = new THREE.MeshPhongMaterial({ - specular: 0x333333, - shininess: 5, - map: textureLoader.load('textures/planets/earth_atmos_2048.jpg'), - specularMap: textureLoader.load('textures/planets/earth_specular_2048.jpg'), - normalMap: textureLoader.load('textures/planets/earth_normal_2048.jpg'), - normalScale: new THREE.Vector2(0.85, 0.85), - }); - earthMaterial.map.colorSpace = THREE.SRGBColorSpace; - const earth = new THREE.Mesh(earthGeometry, earthMaterial); - scene.add(earth); - - const moonGeometry = new THREE.SphereGeometry(MOON_RADIUS, 16, 16); - const moonMaterial = new THREE.MeshPhongMaterial({ - shininess: 5, - map: textureLoader.load('textures/planets/moon_1024.jpg'), - }); - moonMaterial.map.colorSpace = THREE.SRGBColorSpace; - moon = new THREE.Mesh(moonGeometry, moonMaterial); - scene.add(moon); - - // - - earth.layers.enableAll(); - moon.layers.enableAll(); - - const earthDiv = document.createElement('div'); - earthDiv.className = 'label'; - earthDiv.textContent = 'Earth'; - earthDiv.style.backgroundColor = 'transparent'; - - const earthLabel = new CSS2DObject(earthDiv); - earthLabel.position.set(1.5 * EARTH_RADIUS, 0, 0); - earthLabel.center.set(0, 1); - earth.add(earthLabel); - earthLabel.layers.set(0); - - const earthMassDiv = document.createElement('div'); - earthMassDiv.className = 'label'; - earthMassDiv.textContent = '5.97237e24 kg'; - earthMassDiv.style.backgroundColor = 'transparent'; - - const earthMassLabel = new CSS2DObject(earthMassDiv); - earthMassLabel.position.set(1.5 * EARTH_RADIUS, 0, 0); - earthMassLabel.center.set(0, 0); - earth.add(earthMassLabel); - earthMassLabel.layers.set(1); - - const moonDiv = document.createElement('div'); - moonDiv.className = 'label'; - moonDiv.textContent = 'Moon'; - moonDiv.style.backgroundColor = 'transparent'; - - const moonLabel = new CSS2DObject(moonDiv); - moonLabel.position.set(1.5 * MOON_RADIUS, 0, 0); - moonLabel.center.set(0, 1); - moon.add(moonLabel); - moonLabel.layers.set(0); - - const moonMassDiv = document.createElement('div'); - moonMassDiv.className = 'label'; - moonMassDiv.textContent = '7.342e22 kg'; - moonMassDiv.style.backgroundColor = 'transparent'; - - const moonMassLabel = new CSS2DObject(moonMassDiv); - moonMassLabel.position.set(1.5 * MOON_RADIUS, 0, 0); - moonMassLabel.center.set(0, 0); - moon.add(moonMassLabel); - moonMassLabel.layers.set(1); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - labelRenderer = new CSS2DRenderer(); - labelRenderer.setSize(window.innerWidth, window.innerHeight); - labelRenderer.domElement.style.position = 'absolute'; - labelRenderer.domElement.style.top = '0px'; - document.body.appendChild(labelRenderer.domElement); - - const controls = new OrbitControls(camera, labelRenderer.domElement); - controls.minDistance = 5; - controls.maxDistance = 100; - - // - - window.addEventListener('resize', onWindowResize); - - initGui(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - labelRenderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - const elapsed = clock.getElapsedTime(); - - moon.position.set(Math.sin(elapsed) * 5, 0, Math.cos(elapsed) * 5); - - renderer.render(scene, camera); - labelRenderer.render(scene, camera); -} - -// - -function initGui() { - gui = new GUI(); - - gui.title('Camera Layers'); - - gui.add(layers, 'Toggle Name'); - gui.add(layers, 'Toggle Mass'); - gui.add(layers, 'Enable All'); - gui.add(layers, 'Disable All'); - - gui.open(); -} diff --git a/examples-testing/examples/css3d_molecules.ts b/examples-testing/examples/css3d_molecules.ts deleted file mode 100644 index 538472607..000000000 --- a/examples-testing/examples/css3d_molecules.ts +++ /dev/null @@ -1,353 +0,0 @@ -import * as THREE from 'three'; - -import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; -import { PDBLoader } from 'three/addons/loaders/PDBLoader.js'; -import { CSS3DRenderer, CSS3DObject, CSS3DSprite } from 'three/addons/renderers/CSS3DRenderer.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let camera, scene, renderer; -let controls; -let root; - -const objects = []; -const tmpVec1 = new THREE.Vector3(); -const tmpVec2 = new THREE.Vector3(); -const tmpVec3 = new THREE.Vector3(); -const tmpVec4 = new THREE.Vector3(); -const offset = new THREE.Vector3(); - -const VIZ_TYPE = { - Atoms: 0, - Bonds: 1, - 'Atoms + Bonds': 2, -}; - -const MOLECULES = { - Ethanol: 'ethanol.pdb', - Aspirin: 'aspirin.pdb', - Caffeine: 'caffeine.pdb', - Nicotine: 'nicotine.pdb', - LSD: 'lsd.pdb', - Cocaine: 'cocaine.pdb', - Cholesterol: 'cholesterol.pdb', - Lycopene: 'lycopene.pdb', - Glucose: 'glucose.pdb', - 'Aluminium oxide': 'Al2O3.pdb', - Cubane: 'cubane.pdb', - Copper: 'cu.pdb', - Fluorite: 'caf2.pdb', - Salt: 'nacl.pdb', - 'YBCO superconductor': 'ybco.pdb', - Buckyball: 'buckyball.pdb', - // 'Diamond': 'diamond.pdb', - Graphite: 'graphite.pdb', -}; - -const params = { - vizType: 2, - molecule: 'caffeine.pdb', -}; - -const loader = new PDBLoader(); -const colorSpriteMap = {}; -const baseSprite = document.createElement('img'); - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 5000); - camera.position.z = 1000; - - scene = new THREE.Scene(); - - root = new THREE.Object3D(); - scene.add(root); - - // - - renderer = new CSS3DRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - document.getElementById('container').appendChild(renderer.domElement); - - // - - controls = new TrackballControls(camera, renderer.domElement); - controls.rotateSpeed = 0.5; - - // - - baseSprite.onload = function () { - loadMolecule(params.molecule); - }; - - baseSprite.src = 'textures/sprites/ball.png'; - - // - - window.addEventListener('resize', onWindowResize); - - // - - const gui = new GUI(); - - gui.add(params, 'vizType', VIZ_TYPE).onChange(changeVizType); - gui.add(params, 'molecule', MOLECULES).onChange(loadMolecule); - gui.open(); -} - -function changeVizType(value) { - if (value === 0) showAtoms(); - else if (value === 1) showBonds(); - else showAtomsBonds(); -} - -// - -function showAtoms() { - for (let i = 0; i < objects.length; i++) { - const object = objects[i]; - - if (object instanceof CSS3DSprite) { - object.element.style.display = ''; - object.visible = true; - } else { - object.element.style.display = 'none'; - object.visible = false; - } - } -} - -function showBonds() { - for (let i = 0; i < objects.length; i++) { - const object = objects[i]; - - if (object instanceof CSS3DSprite) { - object.element.style.display = 'none'; - object.visible = false; - } else { - object.element.style.display = ''; - object.element.style.height = object.userData.bondLengthFull; - object.visible = true; - } - } -} - -function showAtomsBonds() { - for (let i = 0; i < objects.length; i++) { - const object = objects[i]; - - object.element.style.display = ''; - object.visible = true; - - if (!(object instanceof CSS3DSprite)) { - object.element.style.height = object.userData.bondLengthShort; - } - } -} - -// - -function colorify(ctx, width, height, color) { - const r = color.r, - g = color.g, - b = color.b; - - const imageData = ctx.getImageData(0, 0, width, height); - const data = imageData.data; - - for (let i = 0, l = data.length; i < l; i += 4) { - data[i + 0] *= r; - data[i + 1] *= g; - data[i + 2] *= b; - } - - ctx.putImageData(imageData, 0, 0); -} - -function imageToCanvas(image) { - const width = image.width; - const height = image.height; - - const canvas = document.createElement('canvas'); - - canvas.width = width; - canvas.height = height; - - const context = canvas.getContext('2d'); - context.drawImage(image, 0, 0, width, height); - - return canvas; -} - -// - -function loadMolecule(model) { - const url = 'models/pdb/' + model; - - for (let i = 0; i < objects.length; i++) { - const object = objects[i]; - object.parent.remove(object); - } - - objects.length = 0; - - loader.load(url, function (pdb) { - const geometryAtoms = pdb.geometryAtoms; - const geometryBonds = pdb.geometryBonds; - const json = pdb.json; - - geometryAtoms.computeBoundingBox(); - geometryAtoms.boundingBox.getCenter(offset).negate(); - - geometryAtoms.translate(offset.x, offset.y, offset.z); - geometryBonds.translate(offset.x, offset.y, offset.z); - - const positionAtoms = geometryAtoms.getAttribute('position'); - const colorAtoms = geometryAtoms.getAttribute('color'); - - const position = new THREE.Vector3(); - const color = new THREE.Color(); - - for (let i = 0; i < positionAtoms.count; i++) { - position.fromBufferAttribute(positionAtoms, i); - color.fromBufferAttribute(colorAtoms, i); - - const atomJSON = json.atoms[i]; - const element = atomJSON[4]; - - if (!colorSpriteMap[element]) { - const canvas = imageToCanvas(baseSprite); - const context = canvas.getContext('2d'); - - colorify(context, canvas.width, canvas.height, color); - - const dataUrl = canvas.toDataURL(); - - colorSpriteMap[element] = dataUrl; - } - - const colorSprite = colorSpriteMap[element]; - - const atom = document.createElement('img'); - atom.src = colorSprite; - - const object = new CSS3DSprite(atom); - object.position.copy(position); - object.position.multiplyScalar(75); - - object.matrixAutoUpdate = false; - object.updateMatrix(); - - root.add(object); - - objects.push(object); - } - - const positionBonds = geometryBonds.getAttribute('position'); - - const start = new THREE.Vector3(); - const end = new THREE.Vector3(); - - for (let i = 0; i < positionBonds.count; i += 2) { - start.fromBufferAttribute(positionBonds, i); - end.fromBufferAttribute(positionBonds, i + 1); - - start.multiplyScalar(75); - end.multiplyScalar(75); - - tmpVec1.subVectors(end, start); - const bondLength = tmpVec1.length() - 50; - - // - - let bond = document.createElement('div'); - bond.className = 'bond'; - bond.style.height = bondLength + 'px'; - - let object = new CSS3DObject(bond); - object.position.copy(start); - object.position.lerp(end, 0.5); - - object.userData.bondLengthShort = bondLength + 'px'; - object.userData.bondLengthFull = bondLength + 55 + 'px'; - - // - - const axis = tmpVec2.set(0, 1, 0).cross(tmpVec1); - const radians = Math.acos(tmpVec3.set(0, 1, 0).dot(tmpVec4.copy(tmpVec1).normalize())); - - const objMatrix = new THREE.Matrix4().makeRotationAxis(axis.normalize(), radians); - object.matrix.copy(objMatrix); - object.quaternion.setFromRotationMatrix(object.matrix); - - object.matrixAutoUpdate = false; - object.updateMatrix(); - - root.add(object); - - objects.push(object); - - // - - const joint = new THREE.Object3D(); - joint.position.copy(start); - joint.position.lerp(end, 0.5); - - joint.matrix.copy(objMatrix); - joint.quaternion.setFromRotationMatrix(joint.matrix); - - joint.matrixAutoUpdate = false; - joint.updateMatrix(); - - bond = document.createElement('div'); - bond.className = 'bond'; - bond.style.height = bondLength + 'px'; - - object = new CSS3DObject(bond); - object.rotation.y = Math.PI / 2; - - object.matrixAutoUpdate = false; - object.updateMatrix(); - - object.userData.bondLengthShort = bondLength + 'px'; - object.userData.bondLengthFull = bondLength + 55 + 'px'; - - object.userData.joint = joint; - - joint.add(object); - root.add(joint); - - objects.push(object); - } - - //console.log( "CSS3DObjects:", objects.length ); - - changeVizType(params.vizType); - }); -} - -// - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - controls.update(); - - const time = Date.now() * 0.0004; - - root.rotation.x = time; - root.rotation.y = time * 0.7; - - render(); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/css3d_orthographic.ts b/examples-testing/examples/css3d_orthographic.ts deleted file mode 100644 index 4aabbed08..000000000 --- a/examples-testing/examples/css3d_orthographic.ts +++ /dev/null @@ -1,208 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let camera, scene, renderer; - -let scene2, renderer2; - -const frustumSize = 500; - -init(); -animate(); - -function init() { - const aspect = window.innerWidth / window.innerHeight; - camera = new THREE.OrthographicCamera( - (frustumSize * aspect) / -2, - (frustumSize * aspect) / 2, - frustumSize / 2, - frustumSize / -2, - 1, - 1000, - ); - - camera.position.set(-200, 200, 200); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xf0f0f0); - - scene2 = new THREE.Scene(); - - const material = new THREE.MeshBasicMaterial({ - color: 0x000000, - wireframe: true, - wireframeLinewidth: 1, - side: THREE.DoubleSide, - }); - - // left - createPlane( - 100, - 100, - 'chocolate', - new THREE.Vector3(-50, 0, 0), - new THREE.Euler(0, -90 * THREE.MathUtils.DEG2RAD, 0), - ); - // right - createPlane(100, 100, 'saddlebrown', new THREE.Vector3(0, 0, 50), new THREE.Euler(0, 0, 0)); - // top - createPlane( - 100, - 100, - 'yellowgreen', - new THREE.Vector3(0, 50, 0), - new THREE.Euler(-90 * THREE.MathUtils.DEG2RAD, 0, 0), - ); - // bottom - createPlane( - 300, - 300, - 'seagreen', - new THREE.Vector3(0, -50, 0), - new THREE.Euler(-90 * THREE.MathUtils.DEG2RAD, 0, 0), - ); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - renderer2 = new CSS3DRenderer(); - renderer2.setSize(window.innerWidth, window.innerHeight); - renderer2.domElement.style.position = 'absolute'; - renderer2.domElement.style.top = 0; - document.body.appendChild(renderer2.domElement); - - const controls = new OrbitControls(camera, renderer2.domElement); - controls.minZoom = 0.5; - controls.maxZoom = 2; - - function createPlane(width, height, cssColor, pos, rot) { - const element = document.createElement('div'); - element.style.width = width + 'px'; - element.style.height = height + 'px'; - element.style.opacity = 0.75; - element.style.background = cssColor; - - const object = new CSS3DObject(element); - object.position.copy(pos); - object.rotation.copy(rot); - scene2.add(object); - - const geometry = new THREE.PlaneGeometry(width, height); - const mesh = new THREE.Mesh(geometry, material); - mesh.position.copy(object.position); - mesh.rotation.copy(object.rotation); - scene.add(mesh); - } - - window.addEventListener('resize', onWindowResize); - createPanel(); -} - -function onWindowResize() { - const aspect = window.innerWidth / window.innerHeight; - - camera.left = (-frustumSize * aspect) / 2; - camera.right = (frustumSize * aspect) / 2; - camera.top = frustumSize / 2; - camera.bottom = -frustumSize / 2; - - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - renderer2.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - renderer.render(scene, camera); - renderer2.render(scene2, camera); -} - -function createPanel() { - const panel = new GUI(); - const folder1 = panel.addFolder('camera setViewOffset').close(); - - const settings = { - setViewOffset() { - folder1.children[1].enable().setValue(window.innerWidth); - folder1.children[2].enable().setValue(window.innerHeight); - folder1.children[3].enable().setValue(0); - folder1.children[4].enable().setValue(0); - folder1.children[5].enable().setValue(window.innerWidth); - folder1.children[6].enable().setValue(window.innerHeight); - }, - fullWidth: 0, - fullHeight: 0, - offsetX: 0, - offsetY: 0, - width: 0, - height: 0, - clearViewOffset() { - folder1.children[1].setValue(0).disable(); - folder1.children[2].setValue(0).disable(); - folder1.children[3].setValue(0).disable(); - folder1.children[4].setValue(0).disable(); - folder1.children[5].setValue(0).disable(); - folder1.children[6].setValue(0).disable(); - camera.clearViewOffset(); - }, - }; - - folder1.add(settings, 'setViewOffset'); - folder1 - .add(settings, 'fullWidth', window.screen.width / 4, window.screen.width * 2, 1) - .onChange(val => updateCameraViewOffset({ fullWidth: val })) - .disable(); - folder1 - .add(settings, 'fullHeight', window.screen.height / 4, window.screen.height * 2, 1) - .onChange(val => updateCameraViewOffset({ fullHeight: val })) - .disable(); - folder1 - .add(settings, 'offsetX', 0, 256, 1) - .onChange(val => updateCameraViewOffset({ x: val })) - .disable(); - folder1 - .add(settings, 'offsetY', 0, 256, 1) - .onChange(val => updateCameraViewOffset({ y: val })) - .disable(); - folder1 - .add(settings, 'width', window.screen.width / 4, window.screen.width * 2, 1) - .onChange(val => updateCameraViewOffset({ width: val })) - .disable(); - folder1 - .add(settings, 'height', window.screen.height / 4, window.screen.height * 2, 1) - .onChange(val => updateCameraViewOffset({ height: val })) - .disable(); - folder1.add(settings, 'clearViewOffset'); -} - -function updateCameraViewOffset({ fullWidth, fullHeight, x, y, width, height }) { - if (!camera.view) { - camera.setViewOffset( - fullWidth || window.innerWidth, - fullHeight || window.innerHeight, - x || 0, - y || 0, - width || window.innerWidth, - height || window.innerHeight, - ); - } else { - camera.setViewOffset( - fullWidth || camera.view.fullWidth, - fullHeight || camera.view.fullHeight, - x || camera.view.offsetX, - y || camera.view.offsetY, - width || camera.view.width, - height || camera.view.height, - ); - } -} diff --git a/examples-testing/examples/css3d_periodictable.ts b/examples-testing/examples/css3d_periodictable.ts deleted file mode 100644 index e3a33f796..000000000 --- a/examples-testing/examples/css3d_periodictable.ts +++ /dev/null @@ -1,793 +0,0 @@ -import * as THREE from 'three'; - -import TWEEN from 'three/addons/libs/tween.module.js'; -import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; -import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js'; - -const table = [ - 'H', - 'Hydrogen', - '1.00794', - 1, - 1, - 'He', - 'Helium', - '4.002602', - 18, - 1, - 'Li', - 'Lithium', - '6.941', - 1, - 2, - 'Be', - 'Beryllium', - '9.012182', - 2, - 2, - 'B', - 'Boron', - '10.811', - 13, - 2, - 'C', - 'Carbon', - '12.0107', - 14, - 2, - 'N', - 'Nitrogen', - '14.0067', - 15, - 2, - 'O', - 'Oxygen', - '15.9994', - 16, - 2, - 'F', - 'Fluorine', - '18.9984032', - 17, - 2, - 'Ne', - 'Neon', - '20.1797', - 18, - 2, - 'Na', - 'Sodium', - '22.98976...', - 1, - 3, - 'Mg', - 'Magnesium', - '24.305', - 2, - 3, - 'Al', - 'Aluminium', - '26.9815386', - 13, - 3, - 'Si', - 'Silicon', - '28.0855', - 14, - 3, - 'P', - 'Phosphorus', - '30.973762', - 15, - 3, - 'S', - 'Sulfur', - '32.065', - 16, - 3, - 'Cl', - 'Chlorine', - '35.453', - 17, - 3, - 'Ar', - 'Argon', - '39.948', - 18, - 3, - 'K', - 'Potassium', - '39.948', - 1, - 4, - 'Ca', - 'Calcium', - '40.078', - 2, - 4, - 'Sc', - 'Scandium', - '44.955912', - 3, - 4, - 'Ti', - 'Titanium', - '47.867', - 4, - 4, - 'V', - 'Vanadium', - '50.9415', - 5, - 4, - 'Cr', - 'Chromium', - '51.9961', - 6, - 4, - 'Mn', - 'Manganese', - '54.938045', - 7, - 4, - 'Fe', - 'Iron', - '55.845', - 8, - 4, - 'Co', - 'Cobalt', - '58.933195', - 9, - 4, - 'Ni', - 'Nickel', - '58.6934', - 10, - 4, - 'Cu', - 'Copper', - '63.546', - 11, - 4, - 'Zn', - 'Zinc', - '65.38', - 12, - 4, - 'Ga', - 'Gallium', - '69.723', - 13, - 4, - 'Ge', - 'Germanium', - '72.63', - 14, - 4, - 'As', - 'Arsenic', - '74.9216', - 15, - 4, - 'Se', - 'Selenium', - '78.96', - 16, - 4, - 'Br', - 'Bromine', - '79.904', - 17, - 4, - 'Kr', - 'Krypton', - '83.798', - 18, - 4, - 'Rb', - 'Rubidium', - '85.4678', - 1, - 5, - 'Sr', - 'Strontium', - '87.62', - 2, - 5, - 'Y', - 'Yttrium', - '88.90585', - 3, - 5, - 'Zr', - 'Zirconium', - '91.224', - 4, - 5, - 'Nb', - 'Niobium', - '92.90628', - 5, - 5, - 'Mo', - 'Molybdenum', - '95.96', - 6, - 5, - 'Tc', - 'Technetium', - '(98)', - 7, - 5, - 'Ru', - 'Ruthenium', - '101.07', - 8, - 5, - 'Rh', - 'Rhodium', - '102.9055', - 9, - 5, - 'Pd', - 'Palladium', - '106.42', - 10, - 5, - 'Ag', - 'Silver', - '107.8682', - 11, - 5, - 'Cd', - 'Cadmium', - '112.411', - 12, - 5, - 'In', - 'Indium', - '114.818', - 13, - 5, - 'Sn', - 'Tin', - '118.71', - 14, - 5, - 'Sb', - 'Antimony', - '121.76', - 15, - 5, - 'Te', - 'Tellurium', - '127.6', - 16, - 5, - 'I', - 'Iodine', - '126.90447', - 17, - 5, - 'Xe', - 'Xenon', - '131.293', - 18, - 5, - 'Cs', - 'Caesium', - '132.9054', - 1, - 6, - 'Ba', - 'Barium', - '132.9054', - 2, - 6, - 'La', - 'Lanthanum', - '138.90547', - 4, - 9, - 'Ce', - 'Cerium', - '140.116', - 5, - 9, - 'Pr', - 'Praseodymium', - '140.90765', - 6, - 9, - 'Nd', - 'Neodymium', - '144.242', - 7, - 9, - 'Pm', - 'Promethium', - '(145)', - 8, - 9, - 'Sm', - 'Samarium', - '150.36', - 9, - 9, - 'Eu', - 'Europium', - '151.964', - 10, - 9, - 'Gd', - 'Gadolinium', - '157.25', - 11, - 9, - 'Tb', - 'Terbium', - '158.92535', - 12, - 9, - 'Dy', - 'Dysprosium', - '162.5', - 13, - 9, - 'Ho', - 'Holmium', - '164.93032', - 14, - 9, - 'Er', - 'Erbium', - '167.259', - 15, - 9, - 'Tm', - 'Thulium', - '168.93421', - 16, - 9, - 'Yb', - 'Ytterbium', - '173.054', - 17, - 9, - 'Lu', - 'Lutetium', - '174.9668', - 18, - 9, - 'Hf', - 'Hafnium', - '178.49', - 4, - 6, - 'Ta', - 'Tantalum', - '180.94788', - 5, - 6, - 'W', - 'Tungsten', - '183.84', - 6, - 6, - 'Re', - 'Rhenium', - '186.207', - 7, - 6, - 'Os', - 'Osmium', - '190.23', - 8, - 6, - 'Ir', - 'Iridium', - '192.217', - 9, - 6, - 'Pt', - 'Platinum', - '195.084', - 10, - 6, - 'Au', - 'Gold', - '196.966569', - 11, - 6, - 'Hg', - 'Mercury', - '200.59', - 12, - 6, - 'Tl', - 'Thallium', - '204.3833', - 13, - 6, - 'Pb', - 'Lead', - '207.2', - 14, - 6, - 'Bi', - 'Bismuth', - '208.9804', - 15, - 6, - 'Po', - 'Polonium', - '(209)', - 16, - 6, - 'At', - 'Astatine', - '(210)', - 17, - 6, - 'Rn', - 'Radon', - '(222)', - 18, - 6, - 'Fr', - 'Francium', - '(223)', - 1, - 7, - 'Ra', - 'Radium', - '(226)', - 2, - 7, - 'Ac', - 'Actinium', - '(227)', - 4, - 10, - 'Th', - 'Thorium', - '232.03806', - 5, - 10, - 'Pa', - 'Protactinium', - '231.0588', - 6, - 10, - 'U', - 'Uranium', - '238.02891', - 7, - 10, - 'Np', - 'Neptunium', - '(237)', - 8, - 10, - 'Pu', - 'Plutonium', - '(244)', - 9, - 10, - 'Am', - 'Americium', - '(243)', - 10, - 10, - 'Cm', - 'Curium', - '(247)', - 11, - 10, - 'Bk', - 'Berkelium', - '(247)', - 12, - 10, - 'Cf', - 'Californium', - '(251)', - 13, - 10, - 'Es', - 'Einstenium', - '(252)', - 14, - 10, - 'Fm', - 'Fermium', - '(257)', - 15, - 10, - 'Md', - 'Mendelevium', - '(258)', - 16, - 10, - 'No', - 'Nobelium', - '(259)', - 17, - 10, - 'Lr', - 'Lawrencium', - '(262)', - 18, - 10, - 'Rf', - 'Rutherfordium', - '(267)', - 4, - 7, - 'Db', - 'Dubnium', - '(268)', - 5, - 7, - 'Sg', - 'Seaborgium', - '(271)', - 6, - 7, - 'Bh', - 'Bohrium', - '(272)', - 7, - 7, - 'Hs', - 'Hassium', - '(270)', - 8, - 7, - 'Mt', - 'Meitnerium', - '(276)', - 9, - 7, - 'Ds', - 'Darmstadium', - '(281)', - 10, - 7, - 'Rg', - 'Roentgenium', - '(280)', - 11, - 7, - 'Cn', - 'Copernicium', - '(285)', - 12, - 7, - 'Nh', - 'Nihonium', - '(286)', - 13, - 7, - 'Fl', - 'Flerovium', - '(289)', - 14, - 7, - 'Mc', - 'Moscovium', - '(290)', - 15, - 7, - 'Lv', - 'Livermorium', - '(293)', - 16, - 7, - 'Ts', - 'Tennessine', - '(294)', - 17, - 7, - 'Og', - 'Oganesson', - '(294)', - 18, - 7, -]; - -let camera, scene, renderer; -let controls; - -const objects = []; -const targets = { table: [], sphere: [], helix: [], grid: [] }; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000); - camera.position.z = 3000; - - scene = new THREE.Scene(); - - // table - - for (let i = 0; i < table.length; i += 5) { - const element = document.createElement('div'); - element.className = 'element'; - element.style.backgroundColor = 'rgba(0,127,127,' + (Math.random() * 0.5 + 0.25) + ')'; - - const number = document.createElement('div'); - number.className = 'number'; - number.textContent = i / 5 + 1; - element.appendChild(number); - - const symbol = document.createElement('div'); - symbol.className = 'symbol'; - symbol.textContent = table[i]; - element.appendChild(symbol); - - const details = document.createElement('div'); - details.className = 'details'; - details.innerHTML = table[i + 1] + '
' + table[i + 2]; - element.appendChild(details); - - const objectCSS = new CSS3DObject(element); - objectCSS.position.x = Math.random() * 4000 - 2000; - objectCSS.position.y = Math.random() * 4000 - 2000; - objectCSS.position.z = Math.random() * 4000 - 2000; - scene.add(objectCSS); - - objects.push(objectCSS); - - // - - const object = new THREE.Object3D(); - object.position.x = table[i + 3] * 140 - 1330; - object.position.y = -(table[i + 4] * 180) + 990; - - targets.table.push(object); - } - - // sphere - - const vector = new THREE.Vector3(); - - for (let i = 0, l = objects.length; i < l; i++) { - const phi = Math.acos(-1 + (2 * i) / l); - const theta = Math.sqrt(l * Math.PI) * phi; - - const object = new THREE.Object3D(); - - object.position.setFromSphericalCoords(800, phi, theta); - - vector.copy(object.position).multiplyScalar(2); - - object.lookAt(vector); - - targets.sphere.push(object); - } - - // helix - - for (let i = 0, l = objects.length; i < l; i++) { - const theta = i * 0.175 + Math.PI; - const y = -(i * 8) + 450; - - const object = new THREE.Object3D(); - - object.position.setFromCylindricalCoords(900, theta, y); - - vector.x = object.position.x * 2; - vector.y = object.position.y; - vector.z = object.position.z * 2; - - object.lookAt(vector); - - targets.helix.push(object); - } - - // grid - - for (let i = 0; i < objects.length; i++) { - const object = new THREE.Object3D(); - - object.position.x = (i % 5) * 400 - 800; - object.position.y = -(Math.floor(i / 5) % 5) * 400 + 800; - object.position.z = Math.floor(i / 25) * 1000 - 2000; - - targets.grid.push(object); - } - - // - - renderer = new CSS3DRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - document.getElementById('container').appendChild(renderer.domElement); - - // - - controls = new TrackballControls(camera, renderer.domElement); - controls.minDistance = 500; - controls.maxDistance = 6000; - controls.addEventListener('change', render); - - const buttonTable = document.getElementById('table'); - buttonTable.addEventListener('click', function () { - transform(targets.table, 2000); - }); - - const buttonSphere = document.getElementById('sphere'); - buttonSphere.addEventListener('click', function () { - transform(targets.sphere, 2000); - }); - - const buttonHelix = document.getElementById('helix'); - buttonHelix.addEventListener('click', function () { - transform(targets.helix, 2000); - }); - - const buttonGrid = document.getElementById('grid'); - buttonGrid.addEventListener('click', function () { - transform(targets.grid, 2000); - }); - - transform(targets.table, 2000); - - // - - window.addEventListener('resize', onWindowResize); -} - -function transform(targets, duration) { - TWEEN.removeAll(); - - for (let i = 0; i < objects.length; i++) { - const object = objects[i]; - const target = targets[i]; - - new TWEEN.Tween(object.position) - .to( - { x: target.position.x, y: target.position.y, z: target.position.z }, - Math.random() * duration + duration, - ) - .easing(TWEEN.Easing.Exponential.InOut) - .start(); - - new TWEEN.Tween(object.rotation) - .to( - { x: target.rotation.x, y: target.rotation.y, z: target.rotation.z }, - Math.random() * duration + duration, - ) - .easing(TWEEN.Easing.Exponential.InOut) - .start(); - } - - new TWEEN.Tween(this) - .to({}, duration * 2) - .onUpdate(render) - .start(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - render(); -} - -function animate() { - requestAnimationFrame(animate); - - TWEEN.update(); - - controls.update(); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/css3d_sandbox.ts b/examples-testing/examples/css3d_sandbox.ts deleted file mode 100644 index 1088b84b1..000000000 --- a/examples-testing/examples/css3d_sandbox.ts +++ /dev/null @@ -1,180 +0,0 @@ -import * as THREE from 'three'; - -import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; -import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let camera, scene, renderer; - -let scene2, renderer2; - -let controls; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.set(200, 200, 200); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xf0f0f0); - - scene2 = new THREE.Scene(); - - const material = new THREE.MeshBasicMaterial({ - color: 0x000000, - wireframe: true, - wireframeLinewidth: 1, - side: THREE.DoubleSide, - }); - - // - - for (let i = 0; i < 10; i++) { - const element = document.createElement('div'); - element.style.width = '100px'; - element.style.height = '100px'; - element.style.opacity = i < 5 ? 0.5 : 1; - element.style.background = new THREE.Color(Math.random() * 0xffffff).getStyle(); - - const object = new CSS3DObject(element); - object.position.x = Math.random() * 200 - 100; - object.position.y = Math.random() * 200 - 100; - object.position.z = Math.random() * 200 - 100; - object.rotation.x = Math.random(); - object.rotation.y = Math.random(); - object.rotation.z = Math.random(); - object.scale.x = Math.random() + 0.5; - object.scale.y = Math.random() + 0.5; - scene2.add(object); - - const geometry = new THREE.PlaneGeometry(100, 100); - const mesh = new THREE.Mesh(geometry, material); - mesh.position.copy(object.position); - mesh.rotation.copy(object.rotation); - mesh.scale.copy(object.scale); - scene.add(mesh); - } - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - renderer2 = new CSS3DRenderer(); - renderer2.setSize(window.innerWidth, window.innerHeight); - renderer2.domElement.style.position = 'absolute'; - renderer2.domElement.style.top = 0; - document.body.appendChild(renderer2.domElement); - - controls = new TrackballControls(camera, renderer2.domElement); - - window.addEventListener('resize', onWindowResize); - createPanel(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - renderer2.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - controls.update(); - - renderer.render(scene, camera); - renderer2.render(scene2, camera); -} - -function createPanel() { - const panel = new GUI(); - const folder1 = panel.addFolder('camera setViewOffset').close(); - - const settings = { - setViewOffset() { - folder1.children[1].enable().setValue(window.innerWidth); - folder1.children[2].enable().setValue(window.innerHeight); - folder1.children[3].enable().setValue(0); - folder1.children[4].enable().setValue(0); - folder1.children[5].enable().setValue(window.innerWidth); - folder1.children[6].enable().setValue(window.innerHeight); - }, - fullWidth: 0, - fullHeight: 0, - offsetX: 0, - offsetY: 0, - width: 0, - height: 0, - clearViewOffset() { - folder1.children[1].setValue(0).disable(); - folder1.children[2].setValue(0).disable(); - folder1.children[3].setValue(0).disable(); - folder1.children[4].setValue(0).disable(); - folder1.children[5].setValue(0).disable(); - folder1.children[6].setValue(0).disable(); - camera.clearViewOffset(); - }, - }; - - folder1.add(settings, 'setViewOffset'); - folder1 - .add(settings, 'fullWidth', window.screen.width / 4, window.screen.width * 2, 1) - .onChange(val => updateCameraViewOffset({ fullWidth: val })) - .disable(); - folder1 - .add(settings, 'fullHeight', window.screen.height / 4, window.screen.height * 2, 1) - .onChange(val => updateCameraViewOffset({ fullHeight: val })) - .disable(); - folder1 - .add(settings, 'offsetX', 0, 256, 1) - .onChange(val => updateCameraViewOffset({ x: val })) - .disable(); - folder1 - .add(settings, 'offsetY', 0, 256, 1) - .onChange(val => updateCameraViewOffset({ y: val })) - .disable(); - folder1 - .add(settings, 'width', window.screen.width / 4, window.screen.width * 2, 1) - .onChange(val => updateCameraViewOffset({ width: val })) - .disable(); - folder1 - .add(settings, 'height', window.screen.height / 4, window.screen.height * 2, 1) - .onChange(val => updateCameraViewOffset({ height: val })) - .disable(); - folder1.add(settings, 'clearViewOffset'); -} - -function updateCameraViewOffset({ fullWidth, fullHeight, x, y, width, height }) { - if (!camera.view) { - camera.setViewOffset( - fullWidth || window.innerWidth, - fullHeight || window.innerHeight, - x || 0, - y || 0, - width || window.innerWidth, - height || window.innerHeight, - ); - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - } else { - camera.setViewOffset( - fullWidth || camera.view.fullWidth, - fullHeight || camera.view.fullHeight, - x || camera.view.offsetX, - y || camera.view.offsetY, - width || camera.view.width, - height || camera.view.height, - ); - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - } -} diff --git a/examples-testing/examples/css3d_sprites.ts b/examples-testing/examples/css3d_sprites.ts deleted file mode 100644 index dfe24e79d..000000000 --- a/examples-testing/examples/css3d_sprites.ts +++ /dev/null @@ -1,157 +0,0 @@ -import * as THREE from 'three'; - -import TWEEN from 'three/addons/libs/tween.module.js'; -import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; -import { CSS3DRenderer, CSS3DSprite } from 'three/addons/renderers/CSS3DRenderer.js'; - -let camera, scene, renderer; -let controls; - -const particlesTotal = 512; -const positions = []; -const objects = []; -let current = 0; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 5000); - camera.position.set(600, 400, 1500); - camera.lookAt(0, 0, 0); - - scene = new THREE.Scene(); - - const image = document.createElement('img'); - image.addEventListener('load', function () { - for (let i = 0; i < particlesTotal; i++) { - const object = new CSS3DSprite(image.cloneNode()); - (object.position.x = Math.random() * 4000 - 2000), - (object.position.y = Math.random() * 4000 - 2000), - (object.position.z = Math.random() * 4000 - 2000); - scene.add(object); - - objects.push(object); - } - - transition(); - }); - image.src = 'textures/sprite.png'; - - // Plane - - const amountX = 16; - const amountZ = 32; - const separationPlane = 150; - const offsetX = ((amountX - 1) * separationPlane) / 2; - const offsetZ = ((amountZ - 1) * separationPlane) / 2; - - for (let i = 0; i < particlesTotal; i++) { - const x = (i % amountX) * separationPlane; - const z = Math.floor(i / amountX) * separationPlane; - const y = (Math.sin(x * 0.5) + Math.sin(z * 0.5)) * 200; - - positions.push(x - offsetX, y, z - offsetZ); - } - - // Cube - - const amount = 8; - const separationCube = 150; - const offset = ((amount - 1) * separationCube) / 2; - - for (let i = 0; i < particlesTotal; i++) { - const x = (i % amount) * separationCube; - const y = Math.floor((i / amount) % amount) * separationCube; - const z = Math.floor(i / (amount * amount)) * separationCube; - - positions.push(x - offset, y - offset, z - offset); - } - - // Random - - for (let i = 0; i < particlesTotal; i++) { - positions.push(Math.random() * 4000 - 2000, Math.random() * 4000 - 2000, Math.random() * 4000 - 2000); - } - - // Sphere - - const radius = 750; - - for (let i = 0; i < particlesTotal; i++) { - const phi = Math.acos(-1 + (2 * i) / particlesTotal); - const theta = Math.sqrt(particlesTotal * Math.PI) * phi; - - positions.push( - radius * Math.cos(theta) * Math.sin(phi), - radius * Math.sin(theta) * Math.sin(phi), - radius * Math.cos(phi), - ); - } - - // - - renderer = new CSS3DRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - document.getElementById('container').appendChild(renderer.domElement); - - // - - controls = new TrackballControls(camera, renderer.domElement); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function transition() { - const offset = current * particlesTotal * 3; - const duration = 2000; - - for (let i = 0, j = offset; i < particlesTotal; i++, j += 3) { - const object = objects[i]; - - new TWEEN.Tween(object.position) - .to( - { - x: positions[j], - y: positions[j + 1], - z: positions[j + 2], - }, - Math.random() * duration + duration, - ) - .easing(TWEEN.Easing.Exponential.InOut) - .start(); - } - - new TWEEN.Tween(this) - .to({}, duration * 3) - .onComplete(transition) - .start(); - - current = (current + 1) % 4; -} - -function animate() { - requestAnimationFrame(animate); - - TWEEN.update(); - controls.update(); - - const time = performance.now(); - - for (let i = 0, l = objects.length; i < l; i++) { - const object = objects[i]; - const scale = Math.sin((Math.floor(object.position.x) + time) * 0.002) * 0.3 + 1; - object.scale.set(scale, scale, scale); - } - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/css3d_youtube.ts b/examples-testing/examples/css3d_youtube.ts deleted file mode 100644 index 62652f87f..000000000 --- a/examples-testing/examples/css3d_youtube.ts +++ /dev/null @@ -1,79 +0,0 @@ -import * as THREE from 'three'; - -import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; -import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js'; - -let camera, scene, renderer; -let controls; - -function Element(id, x, y, z, ry) { - const div = document.createElement('div'); - div.style.width = '480px'; - div.style.height = '360px'; - div.style.backgroundColor = '#000'; - - const iframe = document.createElement('iframe'); - iframe.style.width = '480px'; - iframe.style.height = '360px'; - iframe.style.border = '0px'; - iframe.src = ['https://www.youtube.com/embed/', id, '?rel=0'].join(''); - div.appendChild(iframe); - - const object = new CSS3DObject(div); - object.position.set(x, y, z); - object.rotation.y = ry; - - return object; -} - -init(); -animate(); - -function init() { - const container = document.getElementById('container'); - - camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 5000); - camera.position.set(500, 350, 750); - - scene = new THREE.Scene(); - - renderer = new CSS3DRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - const group = new THREE.Group(); - group.add(new Element('SJOz3qjfQXU', 0, 0, 240, 0)); - group.add(new Element('Y2-xZ-1HE-Q', 240, 0, 0, Math.PI / 2)); - group.add(new Element('IrydklNpcFI', 0, 0, -240, Math.PI)); - group.add(new Element('9ubytEsCaS0', -240, 0, 0, -Math.PI / 2)); - scene.add(group); - - controls = new TrackballControls(camera, renderer.domElement); - controls.rotateSpeed = 4; - - window.addEventListener('resize', onWindowResize); - - // Block iframe events when dragging camera - - const blocker = document.getElementById('blocker'); - blocker.style.display = 'none'; - - controls.addEventListener('start', function () { - blocker.style.display = ''; - }); - controls.addEventListener('end', function () { - blocker.style.display = 'none'; - }); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - controls.update(); - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/games_fps.ts b/examples-testing/examples/games_fps.ts deleted file mode 100644 index 49d31e760..000000000 --- a/examples-testing/examples/games_fps.ts +++ /dev/null @@ -1,373 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; - -import { Octree } from 'three/addons/math/Octree.js'; -import { OctreeHelper } from 'three/addons/helpers/OctreeHelper.js'; - -import { Capsule } from 'three/addons/math/Capsule.js'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -const clock = new THREE.Clock(); - -const scene = new THREE.Scene(); -scene.background = new THREE.Color(0x88ccee); -scene.fog = new THREE.Fog(0x88ccee, 0, 50); - -const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000); -camera.rotation.order = 'YXZ'; - -const fillLight1 = new THREE.HemisphereLight(0x8dc1de, 0x00668d, 1.5); -fillLight1.position.set(2, 1, 1); -scene.add(fillLight1); - -const directionalLight = new THREE.DirectionalLight(0xffffff, 2.5); -directionalLight.position.set(-5, 25, -1); -directionalLight.castShadow = true; -directionalLight.shadow.camera.near = 0.01; -directionalLight.shadow.camera.far = 500; -directionalLight.shadow.camera.right = 30; -directionalLight.shadow.camera.left = -30; -directionalLight.shadow.camera.top = 30; -directionalLight.shadow.camera.bottom = -30; -directionalLight.shadow.mapSize.width = 1024; -directionalLight.shadow.mapSize.height = 1024; -directionalLight.shadow.radius = 4; -directionalLight.shadow.bias = -0.00006; -scene.add(directionalLight); - -const container = document.getElementById('container'); - -const renderer = new THREE.WebGLRenderer({ antialias: true }); -renderer.setPixelRatio(window.devicePixelRatio); -renderer.setSize(window.innerWidth, window.innerHeight); -renderer.shadowMap.enabled = true; -renderer.shadowMap.type = THREE.VSMShadowMap; -renderer.toneMapping = THREE.ACESFilmicToneMapping; -container.appendChild(renderer.domElement); - -const stats = new Stats(); -stats.domElement.style.position = 'absolute'; -stats.domElement.style.top = '0px'; -container.appendChild(stats.domElement); - -const GRAVITY = 30; - -const NUM_SPHERES = 100; -const SPHERE_RADIUS = 0.2; - -const STEPS_PER_FRAME = 5; - -const sphereGeometry = new THREE.IcosahedronGeometry(SPHERE_RADIUS, 5); -const sphereMaterial = new THREE.MeshLambertMaterial({ color: 0xdede8d }); - -const spheres = []; -let sphereIdx = 0; - -for (let i = 0; i < NUM_SPHERES; i++) { - const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); - sphere.castShadow = true; - sphere.receiveShadow = true; - - scene.add(sphere); - - spheres.push({ - mesh: sphere, - collider: new THREE.Sphere(new THREE.Vector3(0, -100, 0), SPHERE_RADIUS), - velocity: new THREE.Vector3(), - }); -} - -const worldOctree = new Octree(); - -const playerCollider = new Capsule(new THREE.Vector3(0, 0.35, 0), new THREE.Vector3(0, 1, 0), 0.35); - -const playerVelocity = new THREE.Vector3(); -const playerDirection = new THREE.Vector3(); - -let playerOnFloor = false; -let mouseTime = 0; - -const keyStates = {}; - -const vector1 = new THREE.Vector3(); -const vector2 = new THREE.Vector3(); -const vector3 = new THREE.Vector3(); - -document.addEventListener('keydown', event => { - keyStates[event.code] = true; -}); - -document.addEventListener('keyup', event => { - keyStates[event.code] = false; -}); - -container.addEventListener('mousedown', () => { - document.body.requestPointerLock(); - - mouseTime = performance.now(); -}); - -document.addEventListener('mouseup', () => { - if (document.pointerLockElement !== null) throwBall(); -}); - -document.body.addEventListener('mousemove', event => { - if (document.pointerLockElement === document.body) { - camera.rotation.y -= event.movementX / 500; - camera.rotation.x -= event.movementY / 500; - } -}); - -window.addEventListener('resize', onWindowResize); - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function throwBall() { - const sphere = spheres[sphereIdx]; - - camera.getWorldDirection(playerDirection); - - sphere.collider.center.copy(playerCollider.end).addScaledVector(playerDirection, playerCollider.radius * 1.5); - - // throw the ball with more force if we hold the button longer, and if we move forward - - const impulse = 15 + 30 * (1 - Math.exp((mouseTime - performance.now()) * 0.001)); - - sphere.velocity.copy(playerDirection).multiplyScalar(impulse); - sphere.velocity.addScaledVector(playerVelocity, 2); - - sphereIdx = (sphereIdx + 1) % spheres.length; -} - -function playerCollisions() { - const result = worldOctree.capsuleIntersect(playerCollider); - - playerOnFloor = false; - - if (result) { - playerOnFloor = result.normal.y > 0; - - if (!playerOnFloor) { - playerVelocity.addScaledVector(result.normal, -result.normal.dot(playerVelocity)); - } - - playerCollider.translate(result.normal.multiplyScalar(result.depth)); - } -} - -function updatePlayer(deltaTime) { - let damping = Math.exp(-4 * deltaTime) - 1; - - if (!playerOnFloor) { - playerVelocity.y -= GRAVITY * deltaTime; - - // small air resistance - damping *= 0.1; - } - - playerVelocity.addScaledVector(playerVelocity, damping); - - const deltaPosition = playerVelocity.clone().multiplyScalar(deltaTime); - playerCollider.translate(deltaPosition); - - playerCollisions(); - - camera.position.copy(playerCollider.end); -} - -function playerSphereCollision(sphere) { - const center = vector1.addVectors(playerCollider.start, playerCollider.end).multiplyScalar(0.5); - - const sphere_center = sphere.collider.center; - - const r = playerCollider.radius + sphere.collider.radius; - const r2 = r * r; - - // approximation: player = 3 spheres - - for (const point of [playerCollider.start, playerCollider.end, center]) { - const d2 = point.distanceToSquared(sphere_center); - - if (d2 < r2) { - const normal = vector1.subVectors(point, sphere_center).normalize(); - const v1 = vector2.copy(normal).multiplyScalar(normal.dot(playerVelocity)); - const v2 = vector3.copy(normal).multiplyScalar(normal.dot(sphere.velocity)); - - playerVelocity.add(v2).sub(v1); - sphere.velocity.add(v1).sub(v2); - - const d = (r - Math.sqrt(d2)) / 2; - sphere_center.addScaledVector(normal, -d); - } - } -} - -function spheresCollisions() { - for (let i = 0, length = spheres.length; i < length; i++) { - const s1 = spheres[i]; - - for (let j = i + 1; j < length; j++) { - const s2 = spheres[j]; - - const d2 = s1.collider.center.distanceToSquared(s2.collider.center); - const r = s1.collider.radius + s2.collider.radius; - const r2 = r * r; - - if (d2 < r2) { - const normal = vector1.subVectors(s1.collider.center, s2.collider.center).normalize(); - const v1 = vector2.copy(normal).multiplyScalar(normal.dot(s1.velocity)); - const v2 = vector3.copy(normal).multiplyScalar(normal.dot(s2.velocity)); - - s1.velocity.add(v2).sub(v1); - s2.velocity.add(v1).sub(v2); - - const d = (r - Math.sqrt(d2)) / 2; - - s1.collider.center.addScaledVector(normal, d); - s2.collider.center.addScaledVector(normal, -d); - } - } - } -} - -function updateSpheres(deltaTime) { - spheres.forEach(sphere => { - sphere.collider.center.addScaledVector(sphere.velocity, deltaTime); - - const result = worldOctree.sphereIntersect(sphere.collider); - - if (result) { - sphere.velocity.addScaledVector(result.normal, -result.normal.dot(sphere.velocity) * 1.5); - sphere.collider.center.add(result.normal.multiplyScalar(result.depth)); - } else { - sphere.velocity.y -= GRAVITY * deltaTime; - } - - const damping = Math.exp(-1.5 * deltaTime) - 1; - sphere.velocity.addScaledVector(sphere.velocity, damping); - - playerSphereCollision(sphere); - }); - - spheresCollisions(); - - for (const sphere of spheres) { - sphere.mesh.position.copy(sphere.collider.center); - } -} - -function getForwardVector() { - camera.getWorldDirection(playerDirection); - playerDirection.y = 0; - playerDirection.normalize(); - - return playerDirection; -} - -function getSideVector() { - camera.getWorldDirection(playerDirection); - playerDirection.y = 0; - playerDirection.normalize(); - playerDirection.cross(camera.up); - - return playerDirection; -} - -function controls(deltaTime) { - // gives a bit of air control - const speedDelta = deltaTime * (playerOnFloor ? 25 : 8); - - if (keyStates['KeyW']) { - playerVelocity.add(getForwardVector().multiplyScalar(speedDelta)); - } - - if (keyStates['KeyS']) { - playerVelocity.add(getForwardVector().multiplyScalar(-speedDelta)); - } - - if (keyStates['KeyA']) { - playerVelocity.add(getSideVector().multiplyScalar(-speedDelta)); - } - - if (keyStates['KeyD']) { - playerVelocity.add(getSideVector().multiplyScalar(speedDelta)); - } - - if (playerOnFloor) { - if (keyStates['Space']) { - playerVelocity.y = 15; - } - } -} - -const loader = new GLTFLoader().setPath('./models/gltf/'); - -loader.load('collision-world.glb', gltf => { - scene.add(gltf.scene); - - worldOctree.fromGraphNode(gltf.scene); - - gltf.scene.traverse(child => { - if (child.isMesh) { - child.castShadow = true; - child.receiveShadow = true; - - if (child.material.map) { - child.material.map.anisotropy = 4; - } - } - }); - - const helper = new OctreeHelper(worldOctree); - helper.visible = false; - scene.add(helper); - - const gui = new GUI({ width: 200 }); - gui.add({ debug: false }, 'debug').onChange(function (value) { - helper.visible = value; - }); - - animate(); -}); - -function teleportPlayerIfOob() { - if (camera.position.y <= -25) { - playerCollider.start.set(0, 0.35, 0); - playerCollider.end.set(0, 1, 0); - playerCollider.radius = 0.35; - camera.position.copy(playerCollider.end); - camera.rotation.set(0, 0, 0); - } -} - -function animate() { - const deltaTime = Math.min(0.05, clock.getDelta()) / STEPS_PER_FRAME; - - // we look for collisions in substeps to mitigate the risk of - // an object traversing another too quickly for detection. - - for (let i = 0; i < STEPS_PER_FRAME; i++) { - controls(deltaTime); - - updatePlayer(deltaTime); - - updateSpheres(deltaTime); - - teleportPlayerIfOob(); - } - - renderer.render(scene, camera); - - stats.update(); - - requestAnimationFrame(animate); -} diff --git a/examples-testing/examples/misc_animation_groups.ts b/examples-testing/examples/misc_animation_groups.ts deleted file mode 100644 index 19d263f4b..000000000 --- a/examples-testing/examples/misc_animation_groups.ts +++ /dev/null @@ -1,131 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let stats, clock; -let scene, camera, renderer, mixer; - -init(); -animate(); - -function init() { - scene = new THREE.Scene(); - - // - - camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.set(50, 50, 100); - camera.lookAt(scene.position); - - // all objects of this animation group share a common animation state - - const animationGroup = new THREE.AnimationObjectGroup(); - - // - - const geometry = new THREE.BoxGeometry(5, 5, 5); - const material = new THREE.MeshBasicMaterial({ transparent: true }); - - // - - for (let i = 0; i < 5; i++) { - for (let j = 0; j < 5; j++) { - const mesh = new THREE.Mesh(geometry, material); - - mesh.position.x = 32 - 16 * i; - mesh.position.y = 0; - mesh.position.z = 32 - 16 * j; - - scene.add(mesh); - animationGroup.add(mesh); - } - } - - // create some keyframe tracks - - const xAxis = new THREE.Vector3(1, 0, 0); - const qInitial = new THREE.Quaternion().setFromAxisAngle(xAxis, 0); - const qFinal = new THREE.Quaternion().setFromAxisAngle(xAxis, Math.PI); - const quaternionKF = new THREE.QuaternionKeyframeTrack( - '.quaternion', - [0, 1, 2], - [ - qInitial.x, - qInitial.y, - qInitial.z, - qInitial.w, - qFinal.x, - qFinal.y, - qFinal.z, - qFinal.w, - qInitial.x, - qInitial.y, - qInitial.z, - qInitial.w, - ], - ); - - const colorKF = new THREE.ColorKeyframeTrack( - '.material.color', - [0, 1, 2], - [1, 0, 0, 0, 1, 0, 0, 0, 1], - THREE.InterpolateDiscrete, - ); - const opacityKF = new THREE.NumberKeyframeTrack('.material.opacity', [0, 1, 2], [1, 0, 1]); - - // create clip - - const clip = new THREE.AnimationClip('default', 3, [quaternionKF, colorKF, opacityKF]); - - // apply the animation group to the mixer as the root object - - mixer = new THREE.AnimationMixer(animationGroup); - - const clipAction = mixer.clipAction(clip); - clipAction.play(); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - // - - stats = new Stats(); - document.body.appendChild(stats.dom); - - // - - clock = new THREE.Clock(); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - render(); -} - -function render() { - const delta = clock.getDelta(); - - if (mixer) { - mixer.update(delta); - } - - renderer.render(scene, camera); - - stats.update(); -} diff --git a/examples-testing/examples/misc_animation_keys.ts b/examples-testing/examples/misc_animation_keys.ts deleted file mode 100644 index 4a8089878..000000000 --- a/examples-testing/examples/misc_animation_keys.ts +++ /dev/null @@ -1,135 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let stats, clock; -let scene, camera, renderer, mixer; - -init(); -animate(); - -function init() { - scene = new THREE.Scene(); - - // - - camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.set(25, 25, 50); - camera.lookAt(scene.position); - - // - - const axesHelper = new THREE.AxesHelper(10); - scene.add(axesHelper); - - // - - const geometry = new THREE.BoxGeometry(5, 5, 5); - const material = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true }); - const mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // create a keyframe track (i.e. a timed sequence of keyframes) for each animated property - // Note: the keyframe track type should correspond to the type of the property being animated - - // POSITION - const positionKF = new THREE.VectorKeyframeTrack('.position', [0, 1, 2], [0, 0, 0, 30, 0, 0, 0, 0, 0]); - - // SCALE - const scaleKF = new THREE.VectorKeyframeTrack('.scale', [0, 1, 2], [1, 1, 1, 2, 2, 2, 1, 1, 1]); - - // ROTATION - // Rotation should be performed using quaternions, using a THREE.QuaternionKeyframeTrack - // Interpolating Euler angles (.rotation property) can be problematic and is currently not supported - - // set up rotation about x axis - const xAxis = new THREE.Vector3(1, 0, 0); - - const qInitial = new THREE.Quaternion().setFromAxisAngle(xAxis, 0); - const qFinal = new THREE.Quaternion().setFromAxisAngle(xAxis, Math.PI); - const quaternionKF = new THREE.QuaternionKeyframeTrack( - '.quaternion', - [0, 1, 2], - [ - qInitial.x, - qInitial.y, - qInitial.z, - qInitial.w, - qFinal.x, - qFinal.y, - qFinal.z, - qFinal.w, - qInitial.x, - qInitial.y, - qInitial.z, - qInitial.w, - ], - ); - - // COLOR - const colorKF = new THREE.ColorKeyframeTrack( - '.material.color', - [0, 1, 2], - [1, 0, 0, 0, 1, 0, 0, 0, 1], - THREE.InterpolateDiscrete, - ); - - // OPACITY - const opacityKF = new THREE.NumberKeyframeTrack('.material.opacity', [0, 1, 2], [1, 0, 1]); - - // create an animation sequence with the tracks - // If a negative time value is passed, the duration will be calculated from the times of the passed tracks array - const clip = new THREE.AnimationClip('Action', 3, [scaleKF, positionKF, quaternionKF, colorKF, opacityKF]); - - // setup the THREE.AnimationMixer - mixer = new THREE.AnimationMixer(mesh); - - // create a ClipAction and set it to play - const clipAction = mixer.clipAction(clip); - clipAction.play(); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - // - - stats = new Stats(); - document.body.appendChild(stats.dom); - - // - - clock = new THREE.Clock(); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - render(); -} - -function render() { - const delta = clock.getDelta(); - - if (mixer) { - mixer.update(delta); - } - - renderer.render(scene, camera); - - stats.update(); -} diff --git a/examples-testing/examples/misc_boxselection.ts b/examples-testing/examples/misc_boxselection.ts deleted file mode 100644 index 8766c5592..000000000 --- a/examples-testing/examples/misc_boxselection.ts +++ /dev/null @@ -1,142 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import { SelectionBox } from 'three/addons/interactive/SelectionBox.js'; -import { SelectionHelper } from 'three/addons/interactive/SelectionHelper.js'; - -let container, stats; -let camera, scene, renderer; - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 500); - camera.position.z = 50; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xf0f0f0); - - scene.add(new THREE.AmbientLight(0xaaaaaa)); - - const light = new THREE.SpotLight(0xffffff, 10000); - light.position.set(0, 25, 50); - light.angle = Math.PI / 5; - - light.castShadow = true; - light.shadow.camera.near = 10; - light.shadow.camera.far = 100; - light.shadow.mapSize.width = 1024; - light.shadow.mapSize.height = 1024; - - scene.add(light); - - const geometry = new THREE.BoxGeometry(); - - for (let i = 0; i < 200; i++) { - const object = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff })); - - object.position.x = Math.random() * 80 - 40; - object.position.y = Math.random() * 45 - 25; - object.position.z = Math.random() * 45 - 25; - - object.rotation.x = Math.random() * 2 * Math.PI; - object.rotation.y = Math.random() * 2 * Math.PI; - object.rotation.z = Math.random() * 2 * Math.PI; - - object.scale.x = Math.random() * 2 + 1; - object.scale.y = Math.random() * 2 + 1; - object.scale.z = Math.random() * 2 + 1; - - object.castShadow = true; - object.receiveShadow = true; - - scene.add(object); - } - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - renderer.shadowMap.type = THREE.PCFShadowMap; - - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - renderer.render(scene, camera); -} - -const selectionBox = new SelectionBox(camera, scene); -const helper = new SelectionHelper(renderer, 'selectBox'); - -document.addEventListener('pointerdown', function (event) { - for (const item of selectionBox.collection) { - item.material.emissive.set(0x000000); - } - - selectionBox.startPoint.set( - (event.clientX / window.innerWidth) * 2 - 1, - -(event.clientY / window.innerHeight) * 2 + 1, - 0.5, - ); -}); - -document.addEventListener('pointermove', function (event) { - if (helper.isDown) { - for (let i = 0; i < selectionBox.collection.length; i++) { - selectionBox.collection[i].material.emissive.set(0x000000); - } - - selectionBox.endPoint.set( - (event.clientX / window.innerWidth) * 2 - 1, - -(event.clientY / window.innerHeight) * 2 + 1, - 0.5, - ); - - const allSelected = selectionBox.select(); - - for (let i = 0; i < allSelected.length; i++) { - allSelected[i].material.emissive.set(0xffffff); - } - } -}); - -document.addEventListener('pointerup', function (event) { - selectionBox.endPoint.set( - (event.clientX / window.innerWidth) * 2 - 1, - -(event.clientY / window.innerHeight) * 2 + 1, - 0.5, - ); - - const allSelected = selectionBox.select(); - - for (let i = 0; i < allSelected.length; i++) { - allSelected[i].material.emissive.set(0xffffff); - } -}); diff --git a/examples-testing/examples/misc_controls_arcball.ts b/examples-testing/examples/misc_controls_arcball.ts deleted file mode 100644 index fbef33189..000000000 --- a/examples-testing/examples/misc_controls_arcball.ts +++ /dev/null @@ -1,210 +0,0 @@ -import * as THREE from 'three'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { ArcballControls } from 'three/addons/controls/ArcballControls.js'; - -import { OBJLoader } from 'three/addons/loaders/OBJLoader.js'; -import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'; - -const cameras = ['Orthographic', 'Perspective']; -const cameraType = { type: 'Perspective' }; - -const perspectiveDistance = 2.5; -const orthographicDistance = 120; -let camera, controls, scene, renderer, gui; -let folderOptions, folderAnimations; - -const arcballGui = { - gizmoVisible: true, - - setArcballControls: function () { - controls = new ArcballControls(camera, renderer.domElement, scene); - controls.addEventListener('change', render); - - this.gizmoVisible = true; - - this.populateGui(); - }, - - populateGui: function () { - folderOptions.add(controls, 'enabled').name('Enable controls'); - folderOptions.add(controls, 'enableGrid').name('Enable Grid'); - folderOptions.add(controls, 'enableRotate').name('Enable rotate'); - folderOptions.add(controls, 'enablePan').name('Enable pan'); - folderOptions.add(controls, 'enableZoom').name('Enable zoom'); - folderOptions.add(controls, 'cursorZoom').name('Cursor zoom'); - folderOptions.add(controls, 'adjustNearFar').name('adjust near/far'); - folderOptions.add(controls, 'scaleFactor', 1.1, 10, 0.1).name('Scale factor'); - folderOptions.add(controls, 'minDistance', 0, 50, 0.5).name('Min distance'); - folderOptions.add(controls, 'maxDistance', 0, 50, 0.5).name('Max distance'); - folderOptions.add(controls, 'minZoom', 0, 50, 0.5).name('Min zoom'); - folderOptions.add(controls, 'maxZoom', 0, 50, 0.5).name('Max zoom'); - folderOptions - .add(arcballGui, 'gizmoVisible') - .name('Show gizmos') - .onChange(function () { - controls.setGizmosVisible(arcballGui.gizmoVisible); - }); - folderOptions.add(controls, 'copyState').name('Copy state(ctrl+c)'); - folderOptions.add(controls, 'pasteState').name('Paste state(ctrl+v)'); - folderOptions.add(controls, 'reset').name('Reset'); - folderAnimations.add(controls, 'enableAnimations').name('Enable anim.'); - folderAnimations.add(controls, 'dampingFactor', 0, 100, 1).name('Damping'); - folderAnimations.add(controls, 'wMax', 0, 100, 1).name('Angular spd'); - }, -}; - -init(); - -function init() { - const container = document.createElement('div'); - document.body.appendChild(container); - - renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.toneMapping = THREE.ReinhardToneMapping; - renderer.toneMappingExposure = 3; - renderer.domElement.style.background = 'linear-gradient( 180deg, rgba( 0,0,0,1 ) 0%, rgba( 128,128,255,1 ) 100% )'; - container.appendChild(renderer.domElement); - - // - - scene = new THREE.Scene(); - - camera = makePerspectiveCamera(); - camera.position.set(0, 0, perspectiveDistance); - - const material = new THREE.MeshStandardMaterial(); - - new OBJLoader().setPath('models/obj/cerberus/').load('Cerberus.obj', function (group) { - const textureLoader = new THREE.TextureLoader().setPath('models/obj/cerberus/'); - - material.roughness = 1; - material.metalness = 1; - - const diffuseMap = textureLoader.load('Cerberus_A.jpg', render); - diffuseMap.colorSpace = THREE.SRGBColorSpace; - material.map = diffuseMap; - - material.metalnessMap = material.roughnessMap = textureLoader.load('Cerberus_RM.jpg', render); - material.normalMap = textureLoader.load('Cerberus_N.jpg', render); - - material.map.wrapS = THREE.RepeatWrapping; - material.roughnessMap.wrapS = THREE.RepeatWrapping; - material.metalnessMap.wrapS = THREE.RepeatWrapping; - material.normalMap.wrapS = THREE.RepeatWrapping; - - group.traverse(function (child) { - if (child.isMesh) { - child.material = material; - } - }); - - group.rotation.y = Math.PI / 2; - group.position.x += 0.25; - scene.add(group); - render(); - - new RGBELoader().setPath('textures/equirectangular/').load('venice_sunset_1k.hdr', function (hdrEquirect) { - hdrEquirect.mapping = THREE.EquirectangularReflectionMapping; - - scene.environment = hdrEquirect; - - render(); - }); - - window.addEventListener('keydown', onKeyDown); - window.addEventListener('resize', onWindowResize); - - // - - gui = new GUI(); - gui.add(cameraType, 'type', cameras) - .name('Choose Camera') - .onChange(function () { - setCamera(cameraType.type); - }); - - folderOptions = gui.addFolder('Arcball parameters'); - folderAnimations = folderOptions.addFolder('Animations'); - - arcballGui.setArcballControls(); - - render(); - }); -} - -function makeOrthographicCamera() { - const halfFovV = THREE.MathUtils.DEG2RAD * 45 * 0.5; - const halfFovH = Math.atan((window.innerWidth / window.innerHeight) * Math.tan(halfFovV)); - - const halfW = perspectiveDistance * Math.tan(halfFovH); - const halfH = perspectiveDistance * Math.tan(halfFovV); - const near = 0.01; - const far = 2000; - const newCamera = new THREE.OrthographicCamera(-halfW, halfW, halfH, -halfH, near, far); - return newCamera; -} - -function makePerspectiveCamera() { - const fov = 45; - const aspect = window.innerWidth / window.innerHeight; - const near = 0.01; - const far = 2000; - const newCamera = new THREE.PerspectiveCamera(fov, aspect, near, far); - return newCamera; -} - -function onWindowResize() { - if (camera.type == 'OrthographicCamera') { - const halfFovV = THREE.MathUtils.DEG2RAD * 45 * 0.5; - const halfFovH = Math.atan((window.innerWidth / window.innerHeight) * Math.tan(halfFovV)); - - const halfW = perspectiveDistance * Math.tan(halfFovH); - const halfH = perspectiveDistance * Math.tan(halfFovV); - camera.left = -halfW; - camera.right = halfW; - camera.top = halfH; - camera.bottom = -halfH; - } else if (camera.type == 'PerspectiveCamera') { - camera.aspect = window.innerWidth / window.innerHeight; - } - - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - render(); -} - -function render() { - renderer.render(scene, camera); -} - -function onKeyDown(event) { - if (event.key === 'c') { - if (event.ctrlKey || event.metaKey) { - controls.copyState(); - } - } else if (event.key === 'v') { - if (event.ctrlKey || event.metaKey) { - controls.pasteState(); - } - } -} - -function setCamera(type) { - if (type == 'Orthographic') { - camera = makeOrthographicCamera(); - camera.position.set(0, 0, orthographicDistance); - } else if (type == 'Perspective') { - camera = makePerspectiveCamera(); - camera.position.set(0, 0, perspectiveDistance); - } - - controls.setCamera(camera); - - render(); -} diff --git a/examples-testing/examples/misc_controls_drag.ts b/examples-testing/examples/misc_controls_drag.ts deleted file mode 100644 index 5036ab700..000000000 --- a/examples-testing/examples/misc_controls_drag.ts +++ /dev/null @@ -1,148 +0,0 @@ -import * as THREE from 'three'; - -import { DragControls } from 'three/addons/controls/DragControls.js'; - -let container; -let camera, scene, renderer; -let controls, group; -let enableSelection = false; - -const objects = []; - -const mouse = new THREE.Vector2(), - raycaster = new THREE.Raycaster(); - -init(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 500); - camera.position.z = 25; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xf0f0f0); - - scene.add(new THREE.AmbientLight(0xaaaaaa)); - - const light = new THREE.SpotLight(0xffffff, 10000); - light.position.set(0, 25, 50); - light.angle = Math.PI / 9; - - light.castShadow = true; - light.shadow.camera.near = 10; - light.shadow.camera.far = 100; - light.shadow.mapSize.width = 1024; - light.shadow.mapSize.height = 1024; - - scene.add(light); - - group = new THREE.Group(); - scene.add(group); - - const geometry = new THREE.BoxGeometry(); - - for (let i = 0; i < 200; i++) { - const object = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff })); - - object.position.x = Math.random() * 30 - 15; - object.position.y = Math.random() * 15 - 7.5; - object.position.z = Math.random() * 20 - 10; - - object.rotation.x = Math.random() * 2 * Math.PI; - object.rotation.y = Math.random() * 2 * Math.PI; - object.rotation.z = Math.random() * 2 * Math.PI; - - object.scale.x = Math.random() * 2 + 1; - object.scale.y = Math.random() * 2 + 1; - object.scale.z = Math.random() * 2 + 1; - - object.castShadow = true; - object.receiveShadow = true; - - scene.add(object); - - objects.push(object); - } - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - renderer.shadowMap.type = THREE.PCFShadowMap; - - container.appendChild(renderer.domElement); - - controls = new DragControls([...objects], camera, renderer.domElement); - controls.addEventListener('drag', render); - - // - - window.addEventListener('resize', onWindowResize); - - document.addEventListener('click', onClick); - window.addEventListener('keydown', onKeyDown); - window.addEventListener('keyup', onKeyUp); - - render(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - render(); -} - -function onKeyDown(event) { - enableSelection = event.keyCode === 16 ? true : false; -} - -function onKeyUp() { - enableSelection = false; -} - -function onClick(event) { - event.preventDefault(); - - if (enableSelection === true) { - const draggableObjects = controls.getObjects(); - draggableObjects.length = 0; - - mouse.x = (event.clientX / window.innerWidth) * 2 - 1; - mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; - - raycaster.setFromCamera(mouse, camera); - - const intersections = raycaster.intersectObjects(objects, true); - - if (intersections.length > 0) { - const object = intersections[0].object; - - if (group.children.includes(object) === true) { - object.material.emissive.set(0x000000); - scene.attach(object); - } else { - object.material.emissive.set(0xaaaaaa); - group.attach(object); - } - - controls.transformGroup = true; - draggableObjects.push(group); - } - - if (group.children.length === 0) { - controls.transformGroup = false; - draggableObjects.push(...objects); - } - } - - render(); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/misc_controls_fly.ts b/examples-testing/examples/misc_controls_fly.ts deleted file mode 100644 index 694942d2b..000000000 --- a/examples-testing/examples/misc_controls_fly.ts +++ /dev/null @@ -1,227 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import { FlyControls } from 'three/addons/controls/FlyControls.js'; -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { FilmPass } from 'three/addons/postprocessing/FilmPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; - -const radius = 6371; -const tilt = 0.41; -const rotationSpeed = 0.02; - -const cloudsScale = 1.005; -const moonScale = 0.23; - -const MARGIN = 0; -let SCREEN_HEIGHT = window.innerHeight - MARGIN * 2; -let SCREEN_WIDTH = window.innerWidth; - -let camera, controls, scene, renderer, stats; -let geometry, meshPlanet, meshClouds, meshMoon; -let dirLight; - -let composer; - -const textureLoader = new THREE.TextureLoader(); - -let d, dPlanet, dMoon; -const dMoonVec = new THREE.Vector3(); - -const clock = new THREE.Clock(); - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(25, SCREEN_WIDTH / SCREEN_HEIGHT, 50, 1e7); - camera.position.z = radius * 5; - - scene = new THREE.Scene(); - scene.fog = new THREE.FogExp2(0x000000, 0.00000025); - - dirLight = new THREE.DirectionalLight(0xffffff, 3); - dirLight.position.set(-1, 0, 1).normalize(); - scene.add(dirLight); - - const materialNormalMap = new THREE.MeshPhongMaterial({ - specular: 0x7c7c7c, - shininess: 15, - map: textureLoader.load('textures/planets/earth_atmos_2048.jpg'), - specularMap: textureLoader.load('textures/planets/earth_specular_2048.jpg'), - normalMap: textureLoader.load('textures/planets/earth_normal_2048.jpg'), - - // y scale is negated to compensate for normal map handedness. - normalScale: new THREE.Vector2(0.85, -0.85), - }); - materialNormalMap.map.colorSpace = THREE.SRGBColorSpace; - - // planet - - geometry = new THREE.SphereGeometry(radius, 100, 50); - - meshPlanet = new THREE.Mesh(geometry, materialNormalMap); - meshPlanet.rotation.y = 0; - meshPlanet.rotation.z = tilt; - scene.add(meshPlanet); - - // clouds - - const materialClouds = new THREE.MeshLambertMaterial({ - map: textureLoader.load('textures/planets/earth_clouds_1024.png'), - transparent: true, - }); - materialClouds.map.colorSpace = THREE.SRGBColorSpace; - - meshClouds = new THREE.Mesh(geometry, materialClouds); - meshClouds.scale.set(cloudsScale, cloudsScale, cloudsScale); - meshClouds.rotation.z = tilt; - scene.add(meshClouds); - - // moon - - const materialMoon = new THREE.MeshPhongMaterial({ - map: textureLoader.load('textures/planets/moon_1024.jpg'), - }); - materialMoon.map.colorSpace = THREE.SRGBColorSpace; - - meshMoon = new THREE.Mesh(geometry, materialMoon); - meshMoon.position.set(radius * 5, 0, 0); - meshMoon.scale.set(moonScale, moonScale, moonScale); - scene.add(meshMoon); - - // stars - - const r = radius, - starsGeometry = [new THREE.BufferGeometry(), new THREE.BufferGeometry()]; - - const vertices1 = []; - const vertices2 = []; - - const vertex = new THREE.Vector3(); - - for (let i = 0; i < 250; i++) { - vertex.x = Math.random() * 2 - 1; - vertex.y = Math.random() * 2 - 1; - vertex.z = Math.random() * 2 - 1; - vertex.multiplyScalar(r); - - vertices1.push(vertex.x, vertex.y, vertex.z); - } - - for (let i = 0; i < 1500; i++) { - vertex.x = Math.random() * 2 - 1; - vertex.y = Math.random() * 2 - 1; - vertex.z = Math.random() * 2 - 1; - vertex.multiplyScalar(r); - - vertices2.push(vertex.x, vertex.y, vertex.z); - } - - starsGeometry[0].setAttribute('position', new THREE.Float32BufferAttribute(vertices1, 3)); - starsGeometry[1].setAttribute('position', new THREE.Float32BufferAttribute(vertices2, 3)); - - const starsMaterials = [ - new THREE.PointsMaterial({ color: 0x9c9c9c, size: 2, sizeAttenuation: false }), - new THREE.PointsMaterial({ color: 0x9c9c9c, size: 1, sizeAttenuation: false }), - new THREE.PointsMaterial({ color: 0x7c7c7c, size: 2, sizeAttenuation: false }), - new THREE.PointsMaterial({ color: 0x838383, size: 1, sizeAttenuation: false }), - new THREE.PointsMaterial({ color: 0x5a5a5a, size: 2, sizeAttenuation: false }), - new THREE.PointsMaterial({ color: 0x5a5a5a, size: 1, sizeAttenuation: false }), - ]; - - for (let i = 10; i < 30; i++) { - const stars = new THREE.Points(starsGeometry[i % 2], starsMaterials[i % 6]); - - stars.rotation.x = Math.random() * 6; - stars.rotation.y = Math.random() * 6; - stars.rotation.z = Math.random() * 6; - stars.scale.setScalar(i * 10); - - stars.matrixAutoUpdate = false; - stars.updateMatrix(); - - scene.add(stars); - } - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); - document.body.appendChild(renderer.domElement); - - // - - controls = new FlyControls(camera, renderer.domElement); - - controls.movementSpeed = 1000; - controls.domElement = renderer.domElement; - controls.rollSpeed = Math.PI / 24; - controls.autoForward = false; - controls.dragToLook = false; - - // - - stats = new Stats(); - document.body.appendChild(stats.dom); - - window.addEventListener('resize', onWindowResize); - - // postprocessing - - const renderModel = new RenderPass(scene, camera); - const effectFilm = new FilmPass(0.35, 0.75, 2048, false); - const outputPass = new OutputPass(); - - composer = new EffectComposer(renderer); - - composer.addPass(renderModel); - composer.addPass(effectFilm); - composer.addPass(outputPass); -} - -function onWindowResize() { - SCREEN_HEIGHT = window.innerHeight; - SCREEN_WIDTH = window.innerWidth; - - camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT; - camera.updateProjectionMatrix(); - - renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); - composer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - // rotate the planet and clouds - - const delta = clock.getDelta(); - - meshPlanet.rotation.y += rotationSpeed * delta; - meshClouds.rotation.y += 1.25 * rotationSpeed * delta; - - // slow down as we approach the surface - - dPlanet = camera.position.length(); - - dMoonVec.subVectors(camera.position, meshMoon.position); - dMoon = dMoonVec.length(); - - if (dMoon < dPlanet) { - d = dMoon - radius * moonScale * 1.01; - } else { - d = dPlanet - radius * 1.01; - } - - controls.movementSpeed = 0.33 * d; - controls.update(delta); - - composer.render(delta); -} diff --git a/examples-testing/examples/misc_controls_map.ts b/examples-testing/examples/misc_controls_map.ts deleted file mode 100644 index d0d62795f..000000000 --- a/examples-testing/examples/misc_controls_map.ts +++ /dev/null @@ -1,100 +0,0 @@ -import * as THREE from 'three'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { MapControls } from 'three/addons/controls/MapControls.js'; - -let camera, controls, scene, renderer; - -init(); -//render(); // remove when using next line for animation loop (requestAnimationFrame) -animate(); - -function init() { - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xcccccc); - scene.fog = new THREE.FogExp2(0xcccccc, 0.002); - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.set(0, 200, -400); - - // controls - - controls = new MapControls(camera, renderer.domElement); - - //controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop) - - controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled - controls.dampingFactor = 0.05; - - controls.screenSpacePanning = false; - - controls.minDistance = 100; - controls.maxDistance = 500; - - controls.maxPolarAngle = Math.PI / 2; - - // world - - const geometry = new THREE.BoxGeometry(); - geometry.translate(0, 0.5, 0); - const material = new THREE.MeshPhongMaterial({ color: 0xeeeeee, flatShading: true }); - - for (let i = 0; i < 500; i++) { - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = Math.random() * 1600 - 800; - mesh.position.y = 0; - mesh.position.z = Math.random() * 1600 - 800; - mesh.scale.x = 20; - mesh.scale.y = Math.random() * 80 + 10; - mesh.scale.z = 20; - mesh.updateMatrix(); - mesh.matrixAutoUpdate = false; - scene.add(mesh); - } - - // lights - - const dirLight1 = new THREE.DirectionalLight(0xffffff, 3); - dirLight1.position.set(1, 1, 1); - scene.add(dirLight1); - - const dirLight2 = new THREE.DirectionalLight(0x002288, 3); - dirLight2.position.set(-1, -1, -1); - scene.add(dirLight2); - - const ambientLight = new THREE.AmbientLight(0x555555); - scene.add(ambientLight); - - // - - window.addEventListener('resize', onWindowResize); - - const gui = new GUI(); - gui.add(controls, 'zoomToCursor'); - gui.add(controls, 'screenSpacePanning'); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - controls.update(); // only required if controls.enableDamping = true, or if controls.autoRotate = true - - render(); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/misc_controls_orbit.ts b/examples-testing/examples/misc_controls_orbit.ts deleted file mode 100644 index fc2938333..000000000 --- a/examples-testing/examples/misc_controls_orbit.ts +++ /dev/null @@ -1,91 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -let camera, controls, scene, renderer; - -init(); -//render(); // remove when using next line for animation loop (requestAnimationFrame) -animate(); - -function init() { - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xcccccc); - scene.fog = new THREE.FogExp2(0xcccccc, 0.002); - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.set(400, 200, 0); - - // controls - - controls = new OrbitControls(camera, renderer.domElement); - controls.listenToKeyEvents(window); // optional - - //controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop) - - controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled - controls.dampingFactor = 0.05; - - controls.screenSpacePanning = false; - - controls.minDistance = 100; - controls.maxDistance = 500; - - controls.maxPolarAngle = Math.PI / 2; - - // world - - const geometry = new THREE.ConeGeometry(10, 30, 4, 1); - const material = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); - - for (let i = 0; i < 500; i++) { - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = Math.random() * 1600 - 800; - mesh.position.y = 0; - mesh.position.z = Math.random() * 1600 - 800; - mesh.updateMatrix(); - mesh.matrixAutoUpdate = false; - scene.add(mesh); - } - - // lights - - const dirLight1 = new THREE.DirectionalLight(0xffffff, 3); - dirLight1.position.set(1, 1, 1); - scene.add(dirLight1); - - const dirLight2 = new THREE.DirectionalLight(0x002288, 3); - dirLight2.position.set(-1, -1, -1); - scene.add(dirLight2); - - const ambientLight = new THREE.AmbientLight(0x555555); - scene.add(ambientLight); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - controls.update(); // only required if controls.enableDamping = true, or if controls.autoRotate = true - - render(); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/misc_controls_pointerlock.ts b/examples-testing/examples/misc_controls_pointerlock.ts deleted file mode 100644 index 72ea08f30..000000000 --- a/examples-testing/examples/misc_controls_pointerlock.ts +++ /dev/null @@ -1,247 +0,0 @@ -import * as THREE from 'three'; - -import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js'; - -let camera, scene, renderer, controls; - -const objects = []; - -let raycaster; - -let moveForward = false; -let moveBackward = false; -let moveLeft = false; -let moveRight = false; -let canJump = false; - -let prevTime = performance.now(); -const velocity = new THREE.Vector3(); -const direction = new THREE.Vector3(); -const vertex = new THREE.Vector3(); -const color = new THREE.Color(); - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.y = 10; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xffffff); - scene.fog = new THREE.Fog(0xffffff, 0, 750); - - const light = new THREE.HemisphereLight(0xeeeeff, 0x777788, 2.5); - light.position.set(0.5, 1, 0.75); - scene.add(light); - - controls = new PointerLockControls(camera, document.body); - - const blocker = document.getElementById('blocker'); - const instructions = document.getElementById('instructions'); - - instructions.addEventListener('click', function () { - controls.lock(); - }); - - controls.addEventListener('lock', function () { - instructions.style.display = 'none'; - blocker.style.display = 'none'; - }); - - controls.addEventListener('unlock', function () { - blocker.style.display = 'block'; - instructions.style.display = ''; - }); - - scene.add(controls.getObject()); - - const onKeyDown = function (event) { - switch (event.code) { - case 'ArrowUp': - case 'KeyW': - moveForward = true; - break; - - case 'ArrowLeft': - case 'KeyA': - moveLeft = true; - break; - - case 'ArrowDown': - case 'KeyS': - moveBackward = true; - break; - - case 'ArrowRight': - case 'KeyD': - moveRight = true; - break; - - case 'Space': - if (canJump === true) velocity.y += 350; - canJump = false; - break; - } - }; - - const onKeyUp = function (event) { - switch (event.code) { - case 'ArrowUp': - case 'KeyW': - moveForward = false; - break; - - case 'ArrowLeft': - case 'KeyA': - moveLeft = false; - break; - - case 'ArrowDown': - case 'KeyS': - moveBackward = false; - break; - - case 'ArrowRight': - case 'KeyD': - moveRight = false; - break; - } - }; - - document.addEventListener('keydown', onKeyDown); - document.addEventListener('keyup', onKeyUp); - - raycaster = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3(0, -1, 0), 0, 10); - - // floor - - let floorGeometry = new THREE.PlaneGeometry(2000, 2000, 100, 100); - floorGeometry.rotateX(-Math.PI / 2); - - // vertex displacement - - let position = floorGeometry.attributes.position; - - for (let i = 0, l = position.count; i < l; i++) { - vertex.fromBufferAttribute(position, i); - - vertex.x += Math.random() * 20 - 10; - vertex.y += Math.random() * 2; - vertex.z += Math.random() * 20 - 10; - - position.setXYZ(i, vertex.x, vertex.y, vertex.z); - } - - floorGeometry = floorGeometry.toNonIndexed(); // ensure each face has unique vertices - - position = floorGeometry.attributes.position; - const colorsFloor = []; - - for (let i = 0, l = position.count; i < l; i++) { - color.setHSL(Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace); - colorsFloor.push(color.r, color.g, color.b); - } - - floorGeometry.setAttribute('color', new THREE.Float32BufferAttribute(colorsFloor, 3)); - - const floorMaterial = new THREE.MeshBasicMaterial({ vertexColors: true }); - - const floor = new THREE.Mesh(floorGeometry, floorMaterial); - scene.add(floor); - - // objects - - const boxGeometry = new THREE.BoxGeometry(20, 20, 20).toNonIndexed(); - - position = boxGeometry.attributes.position; - const colorsBox = []; - - for (let i = 0, l = position.count; i < l; i++) { - color.setHSL(Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace); - colorsBox.push(color.r, color.g, color.b); - } - - boxGeometry.setAttribute('color', new THREE.Float32BufferAttribute(colorsBox, 3)); - - for (let i = 0; i < 500; i++) { - const boxMaterial = new THREE.MeshPhongMaterial({ specular: 0xffffff, flatShading: true, vertexColors: true }); - boxMaterial.color.setHSL(Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75, THREE.SRGBColorSpace); - - const box = new THREE.Mesh(boxGeometry, boxMaterial); - box.position.x = Math.floor(Math.random() * 20 - 10) * 20; - box.position.y = Math.floor(Math.random() * 20) * 20 + 10; - box.position.z = Math.floor(Math.random() * 20 - 10) * 20; - - scene.add(box); - objects.push(box); - } - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - const time = performance.now(); - - if (controls.isLocked === true) { - raycaster.ray.origin.copy(controls.getObject().position); - raycaster.ray.origin.y -= 10; - - const intersections = raycaster.intersectObjects(objects, false); - - const onObject = intersections.length > 0; - - const delta = (time - prevTime) / 1000; - - velocity.x -= velocity.x * 10.0 * delta; - velocity.z -= velocity.z * 10.0 * delta; - - velocity.y -= 9.8 * 100.0 * delta; // 100.0 = mass - - direction.z = Number(moveForward) - Number(moveBackward); - direction.x = Number(moveRight) - Number(moveLeft); - direction.normalize(); // this ensures consistent movements in all directions - - if (moveForward || moveBackward) velocity.z -= direction.z * 400.0 * delta; - if (moveLeft || moveRight) velocity.x -= direction.x * 400.0 * delta; - - if (onObject === true) { - velocity.y = Math.max(0, velocity.y); - canJump = true; - } - - controls.moveRight(-velocity.x * delta); - controls.moveForward(-velocity.z * delta); - - controls.getObject().position.y += velocity.y * delta; // new behavior - - if (controls.getObject().position.y < 10) { - velocity.y = 0; - controls.getObject().position.y = 10; - - canJump = true; - } - } - - prevTime = time; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/misc_controls_trackball.ts b/examples-testing/examples/misc_controls_trackball.ts deleted file mode 100644 index 88d0541a6..000000000 --- a/examples-testing/examples/misc_controls_trackball.ts +++ /dev/null @@ -1,136 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; - -let perspectiveCamera, orthographicCamera, controls, scene, renderer, stats; - -const params = { - orthographicCamera: false, -}; - -const frustumSize = 400; - -init(); -animate(); - -function init() { - const aspect = window.innerWidth / window.innerHeight; - - perspectiveCamera = new THREE.PerspectiveCamera(60, aspect, 1, 1000); - perspectiveCamera.position.z = 500; - - orthographicCamera = new THREE.OrthographicCamera( - (frustumSize * aspect) / -2, - (frustumSize * aspect) / 2, - frustumSize / 2, - frustumSize / -2, - 1, - 1000, - ); - orthographicCamera.position.z = 500; - - // world - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xcccccc); - scene.fog = new THREE.FogExp2(0xcccccc, 0.002); - - const geometry = new THREE.ConeGeometry(10, 30, 4, 1); - const material = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); - - for (let i = 0; i < 500; i++) { - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = (Math.random() - 0.5) * 1000; - mesh.position.y = (Math.random() - 0.5) * 1000; - mesh.position.z = (Math.random() - 0.5) * 1000; - mesh.updateMatrix(); - mesh.matrixAutoUpdate = false; - scene.add(mesh); - } - - // lights - - const dirLight1 = new THREE.DirectionalLight(0xffffff, 3); - dirLight1.position.set(1, 1, 1); - scene.add(dirLight1); - - const dirLight2 = new THREE.DirectionalLight(0x002288, 3); - dirLight2.position.set(-1, -1, -1); - scene.add(dirLight2); - - const ambientLight = new THREE.AmbientLight(0x555555); - scene.add(ambientLight); - - // renderer - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - stats = new Stats(); - document.body.appendChild(stats.dom); - - // - - const gui = new GUI(); - gui.add(params, 'orthographicCamera') - .name('use orthographic') - .onChange(function (value) { - controls.dispose(); - - createControls(value ? orthographicCamera : perspectiveCamera); - }); - - // - - window.addEventListener('resize', onWindowResize); - - createControls(perspectiveCamera); -} - -function createControls(camera) { - controls = new TrackballControls(camera, renderer.domElement); - - controls.rotateSpeed = 1.0; - controls.zoomSpeed = 1.2; - controls.panSpeed = 0.8; - - controls.keys = ['KeyA', 'KeyS', 'KeyD']; -} - -function onWindowResize() { - const aspect = window.innerWidth / window.innerHeight; - - perspectiveCamera.aspect = aspect; - perspectiveCamera.updateProjectionMatrix(); - - orthographicCamera.left = (-frustumSize * aspect) / 2; - orthographicCamera.right = (frustumSize * aspect) / 2; - orthographicCamera.top = frustumSize / 2; - orthographicCamera.bottom = -frustumSize / 2; - orthographicCamera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - controls.handleResize(); -} - -function animate() { - requestAnimationFrame(animate); - - controls.update(); - - stats.update(); - - render(); -} - -function render() { - const camera = params.orthographicCamera ? orthographicCamera : perspectiveCamera; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/misc_controls_transform.ts b/examples-testing/examples/misc_controls_transform.ts deleted file mode 100644 index abc4657ac..000000000 --- a/examples-testing/examples/misc_controls_transform.ts +++ /dev/null @@ -1,172 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { TransformControls } from 'three/addons/controls/TransformControls.js'; - -let cameraPersp, cameraOrtho, currentCamera; -let scene, renderer, control, orbit; - -init(); -render(); - -function init() { - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - const aspect = window.innerWidth / window.innerHeight; - - cameraPersp = new THREE.PerspectiveCamera(50, aspect, 0.01, 30000); - cameraOrtho = new THREE.OrthographicCamera(-600 * aspect, 600 * aspect, 600, -600, 0.01, 30000); - currentCamera = cameraPersp; - - currentCamera.position.set(5, 2.5, 5); - - scene = new THREE.Scene(); - scene.add(new THREE.GridHelper(5, 10, 0x888888, 0x444444)); - - const ambientLight = new THREE.AmbientLight(0xffffff); - scene.add(ambientLight); - - const light = new THREE.DirectionalLight(0xffffff, 4); - light.position.set(1, 1, 1); - scene.add(light); - - const texture = new THREE.TextureLoader().load('textures/crate.gif', render); - texture.colorSpace = THREE.SRGBColorSpace; - texture.anisotropy = renderer.capabilities.getMaxAnisotropy(); - - const geometry = new THREE.BoxGeometry(); - const material = new THREE.MeshLambertMaterial({ map: texture }); - - orbit = new OrbitControls(currentCamera, renderer.domElement); - orbit.update(); - orbit.addEventListener('change', render); - - control = new TransformControls(currentCamera, renderer.domElement); - control.addEventListener('change', render); - - control.addEventListener('dragging-changed', function (event) { - orbit.enabled = !event.value; - }); - - const mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - control.attach(mesh); - scene.add(control); - - window.addEventListener('resize', onWindowResize); - - window.addEventListener('keydown', function (event) { - switch (event.keyCode) { - case 81: // Q - control.setSpace(control.space === 'local' ? 'world' : 'local'); - break; - - case 16: // Shift - control.setTranslationSnap(100); - control.setRotationSnap(THREE.MathUtils.degToRad(15)); - control.setScaleSnap(0.25); - break; - - case 87: // W - control.setMode('translate'); - break; - - case 69: // E - control.setMode('rotate'); - break; - - case 82: // R - control.setMode('scale'); - break; - - case 67: // C - const position = currentCamera.position.clone(); - - currentCamera = currentCamera.isPerspectiveCamera ? cameraOrtho : cameraPersp; - currentCamera.position.copy(position); - - orbit.object = currentCamera; - control.camera = currentCamera; - - currentCamera.lookAt(orbit.target.x, orbit.target.y, orbit.target.z); - onWindowResize(); - break; - - case 86: // V - const randomFoV = Math.random() + 0.1; - const randomZoom = Math.random() + 0.1; - - cameraPersp.fov = randomFoV * 160; - cameraOrtho.bottom = -randomFoV * 500; - cameraOrtho.top = randomFoV * 500; - - cameraPersp.zoom = randomZoom * 5; - cameraOrtho.zoom = randomZoom * 5; - onWindowResize(); - break; - - case 187: - case 107: // +, =, num+ - control.setSize(control.size + 0.1); - break; - - case 189: - case 109: // -, _, num- - control.setSize(Math.max(control.size - 0.1, 0.1)); - break; - - case 88: // X - control.showX = !control.showX; - break; - - case 89: // Y - control.showY = !control.showY; - break; - - case 90: // Z - control.showZ = !control.showZ; - break; - - case 32: // Spacebar - control.enabled = !control.enabled; - break; - - case 27: // Esc - control.reset(); - break; - } - }); - - window.addEventListener('keyup', function (event) { - switch (event.keyCode) { - case 16: // Shift - control.setTranslationSnap(null); - control.setRotationSnap(null); - control.setScaleSnap(null); - break; - } - }); -} - -function onWindowResize() { - const aspect = window.innerWidth / window.innerHeight; - - cameraPersp.aspect = aspect; - cameraPersp.updateProjectionMatrix(); - - cameraOrtho.left = cameraOrtho.bottom * aspect; - cameraOrtho.right = cameraOrtho.top * aspect; - cameraOrtho.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - render(); -} - -function render() { - renderer.render(scene, currentCamera); -} diff --git a/examples-testing/examples/misc_exporter_draco.ts b/examples-testing/examples/misc_exporter_draco.ts deleted file mode 100644 index d6a45353f..000000000 --- a/examples-testing/examples/misc_exporter_draco.ts +++ /dev/null @@ -1,118 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { DRACOExporter } from 'three/addons/exporters/DRACOExporter.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let scene, camera, renderer, exporter, mesh; - -const params = { - export: exportFile, -}; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(4, 2, 4); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xa0a0a0); - scene.fog = new THREE.Fog(0xa0a0a0, 4, 20); - - exporter = new DRACOExporter(); - - // - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 3); - hemiLight.position.set(0, 20, 0); - scene.add(hemiLight); - - const directionalLight = new THREE.DirectionalLight(0xffffff, 3); - directionalLight.position.set(0, 20, 10); - directionalLight.castShadow = true; - directionalLight.shadow.camera.top = 2; - directionalLight.shadow.camera.bottom = -2; - directionalLight.shadow.camera.left = -2; - directionalLight.shadow.camera.right = 2; - scene.add(directionalLight); - - // ground - - const ground = new THREE.Mesh( - new THREE.PlaneGeometry(40, 40), - new THREE.MeshPhongMaterial({ color: 0xbbbbbb, depthWrite: false }), - ); - ground.rotation.x = -Math.PI / 2; - ground.receiveShadow = true; - scene.add(ground); - - const grid = new THREE.GridHelper(40, 20, 0x000000, 0x000000); - grid.material.opacity = 0.2; - grid.material.transparent = true; - scene.add(grid); - - // export mesh - - const geometry = new THREE.TorusKnotGeometry(0.75, 0.2, 200, 30); - const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 }); - mesh = new THREE.Mesh(geometry, material); - mesh.castShadow = true; - mesh.position.y = 1.5; - scene.add(mesh); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - document.body.appendChild(renderer.domElement); - - // - - const controls = new OrbitControls(camera, renderer.domElement); - controls.target.set(0, 1.5, 0); - controls.update(); - - // - - window.addEventListener('resize', onWindowResize); - - const gui = new GUI(); - - gui.add(params, 'export').name('Export DRC'); - gui.open(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - renderer.render(scene, camera); -} - -function exportFile() { - const result = exporter.parse(mesh); - saveArrayBuffer(result, 'file.drc'); -} - -const link = document.createElement('a'); -link.style.display = 'none'; -document.body.appendChild(link); - -function save(blob, filename) { - link.href = URL.createObjectURL(blob); - link.download = filename; - link.click(); -} - -function saveArrayBuffer(buffer, filename) { - save(new Blob([buffer], { type: 'application/octet-stream' }), filename); -} diff --git a/examples-testing/examples/misc_exporter_gltf.ts b/examples-testing/examples/misc_exporter_gltf.ts deleted file mode 100644 index 47c871235..000000000 --- a/examples-testing/examples/misc_exporter_gltf.ts +++ /dev/null @@ -1,493 +0,0 @@ -import * as THREE from 'three'; - -import { GLTFExporter } from 'three/addons/exporters/GLTFExporter.js'; -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; -import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'; -import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -function exportGLTF(input) { - const gltfExporter = new GLTFExporter(); - - const options = { - trs: params.trs, - onlyVisible: params.onlyVisible, - binary: params.binary, - maxTextureSize: params.maxTextureSize, - }; - gltfExporter.parse( - input, - function (result) { - if (result instanceof ArrayBuffer) { - saveArrayBuffer(result, 'scene.glb'); - } else { - const output = JSON.stringify(result, null, 2); - console.log(output); - saveString(output, 'scene.gltf'); - } - }, - function (error) { - console.log('An error happened during parsing', error); - }, - options, - ); -} - -const link = document.createElement('a'); -link.style.display = 'none'; -document.body.appendChild(link); // Firefox workaround, see #6594 - -function save(blob, filename) { - link.href = URL.createObjectURL(blob); - link.download = filename; - link.click(); - - // URL.revokeObjectURL( url ); breaks Firefox... -} - -function saveString(text, filename) { - save(new Blob([text], { type: 'text/plain' }), filename); -} - -function saveArrayBuffer(buffer, filename) { - save(new Blob([buffer], { type: 'application/octet-stream' }), filename); -} - -let container; - -let camera, object, object2, material, geometry, scene1, scene2, renderer; -let gridHelper, sphere, model, coffeemat; - -const params = { - trs: false, - onlyVisible: true, - binary: false, - maxTextureSize: 4096, - exportScene1: exportScene1, - exportScenes: exportScenes, - exportSphere: exportSphere, - exportModel: exportModel, - exportObjects: exportObjects, - exportSceneObject: exportSceneObject, - exportCompressedObject: exportCompressedObject, -}; - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - // Make linear gradient texture - - const data = new Uint8ClampedArray(100 * 100 * 4); - - for (let y = 0; y < 100; y++) { - for (let x = 0; x < 100; x++) { - const stride = 4 * (100 * y + x); - - data[stride] = Math.round((255 * y) / 99); - data[stride + 1] = Math.round(255 - (255 * y) / 99); - data[stride + 2] = 0; - data[stride + 3] = 255; - } - } - - const gradientTexture = new THREE.DataTexture(data, 100, 100, THREE.RGBAFormat); - gradientTexture.minFilter = THREE.LinearFilter; - gradientTexture.magFilter = THREE.LinearFilter; - gradientTexture.needsUpdate = true; - - scene1 = new THREE.Scene(); - scene1.name = 'Scene1'; - - // --------------------------------------------------------------------- - // Perspective Camera - // --------------------------------------------------------------------- - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000); - camera.position.set(600, 400, 0); - - camera.name = 'PerspectiveCamera'; - scene1.add(camera); - - // --------------------------------------------------------------------- - // Ambient light - // --------------------------------------------------------------------- - const ambientLight = new THREE.AmbientLight(0xcccccc); - ambientLight.name = 'AmbientLight'; - scene1.add(ambientLight); - - // --------------------------------------------------------------------- - // DirectLight - // --------------------------------------------------------------------- - const dirLight = new THREE.DirectionalLight(0xffffff, 3); - dirLight.target.position.set(0, 0, -1); - dirLight.add(dirLight.target); - dirLight.lookAt(-1, -1, 0); - dirLight.name = 'DirectionalLight'; - scene1.add(dirLight); - - // --------------------------------------------------------------------- - // Grid - // --------------------------------------------------------------------- - gridHelper = new THREE.GridHelper(2000, 20, 0xc1c1c1, 0x8d8d8d); - gridHelper.position.y = -50; - gridHelper.name = 'Grid'; - scene1.add(gridHelper); - - // --------------------------------------------------------------------- - // Axes - // --------------------------------------------------------------------- - const axes = new THREE.AxesHelper(500); - axes.name = 'AxesHelper'; - scene1.add(axes); - - // --------------------------------------------------------------------- - // Simple geometry with basic material - // --------------------------------------------------------------------- - // Icosahedron - const mapGrid = new THREE.TextureLoader().load('textures/uv_grid_opengl.jpg'); - mapGrid.wrapS = mapGrid.wrapT = THREE.RepeatWrapping; - mapGrid.colorSpace = THREE.SRGBColorSpace; - material = new THREE.MeshBasicMaterial({ - color: 0xffffff, - map: mapGrid, - }); - - object = new THREE.Mesh(new THREE.IcosahedronGeometry(75, 0), material); - object.position.set(-200, 0, 200); - object.name = 'Icosahedron'; - scene1.add(object); - - // Octahedron - material = new THREE.MeshBasicMaterial({ - color: 0x0000ff, - wireframe: true, - }); - object = new THREE.Mesh(new THREE.OctahedronGeometry(75, 1), material); - object.position.set(0, 0, 200); - object.name = 'Octahedron'; - scene1.add(object); - - // Tetrahedron - material = new THREE.MeshBasicMaterial({ - color: 0xff0000, - transparent: true, - opacity: 0.5, - }); - - object = new THREE.Mesh(new THREE.TetrahedronGeometry(75, 0), material); - object.position.set(200, 0, 200); - object.name = 'Tetrahedron'; - scene1.add(object); - - // --------------------------------------------------------------------- - // Buffered geometry primitives - // --------------------------------------------------------------------- - // Sphere - material = new THREE.MeshStandardMaterial({ - color: 0xffff00, - metalness: 0.5, - roughness: 1.0, - flatShading: true, - }); - material.map = gradientTexture; - sphere = new THREE.Mesh(new THREE.SphereGeometry(70, 10, 10), material); - sphere.position.set(0, 0, 0); - sphere.name = 'Sphere'; - scene1.add(sphere); - - // Cylinder - material = new THREE.MeshStandardMaterial({ - color: 0xff00ff, - flatShading: true, - }); - object = new THREE.Mesh(new THREE.CylinderGeometry(10, 80, 100), material); - object.position.set(200, 0, 0); - object.name = 'Cylinder'; - scene1.add(object); - - // TorusKnot - material = new THREE.MeshStandardMaterial({ - color: 0xff0000, - roughness: 1, - }); - object = new THREE.Mesh(new THREE.TorusKnotGeometry(50, 15, 40, 10), material); - object.position.set(-200, 0, 0); - object.name = 'Cylinder'; - scene1.add(object); - - // --------------------------------------------------------------------- - // Hierarchy - // --------------------------------------------------------------------- - const mapWood = new THREE.TextureLoader().load('textures/hardwood2_diffuse.jpg'); - material = new THREE.MeshStandardMaterial({ map: mapWood, side: THREE.DoubleSide }); - - object = new THREE.Mesh(new THREE.BoxGeometry(40, 100, 100), material); - object.position.set(-200, 0, 400); - object.name = 'Cube'; - scene1.add(object); - - object2 = new THREE.Mesh(new THREE.BoxGeometry(40, 40, 40, 2, 2, 2), material); - object2.position.set(0, 0, 50); - object2.rotation.set(0, 45, 0); - object2.name = 'SubCube'; - object.add(object2); - - // --------------------------------------------------------------------- - // Groups - // --------------------------------------------------------------------- - const group1 = new THREE.Group(); - group1.name = 'Group'; - scene1.add(group1); - - const group2 = new THREE.Group(); - group2.name = 'subGroup'; - group2.position.set(0, 50, 0); - group1.add(group2); - - object2 = new THREE.Mesh(new THREE.BoxGeometry(30, 30, 30), material); - object2.name = 'Cube in group'; - object2.position.set(0, 0, 400); - group2.add(object2); - - // --------------------------------------------------------------------- - // THREE.Line Strip - // --------------------------------------------------------------------- - geometry = new THREE.BufferGeometry(); - let numPoints = 100; - let positions = new Float32Array(numPoints * 3); - - for (let i = 0; i < numPoints; i++) { - positions[i * 3] = i; - positions[i * 3 + 1] = Math.sin(i / 2) * 20; - positions[i * 3 + 2] = 0; - } - - geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); - object = new THREE.Line(geometry, new THREE.LineBasicMaterial({ color: 0xffff00 })); - object.position.set(-50, 0, -200); - scene1.add(object); - - // --------------------------------------------------------------------- - // THREE.Line Loop - // --------------------------------------------------------------------- - geometry = new THREE.BufferGeometry(); - numPoints = 5; - const radius = 70; - positions = new Float32Array(numPoints * 3); - - for (let i = 0; i < numPoints; i++) { - const s = (i * Math.PI * 2) / numPoints; - positions[i * 3] = radius * Math.sin(s); - positions[i * 3 + 1] = radius * Math.cos(s); - positions[i * 3 + 2] = 0; - } - - geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); - object = new THREE.LineLoop(geometry, new THREE.LineBasicMaterial({ color: 0xffff00 })); - object.position.set(0, 0, -200); - - scene1.add(object); - - // --------------------------------------------------------------------- - // THREE.Points - // --------------------------------------------------------------------- - numPoints = 100; - const pointsArray = new Float32Array(numPoints * 3); - for (let i = 0; i < numPoints; i++) { - pointsArray[3 * i] = -50 + Math.random() * 100; - pointsArray[3 * i + 1] = Math.random() * 100; - pointsArray[3 * i + 2] = -50 + Math.random() * 100; - } - - const pointsGeo = new THREE.BufferGeometry(); - pointsGeo.setAttribute('position', new THREE.BufferAttribute(pointsArray, 3)); - - const pointsMaterial = new THREE.PointsMaterial({ color: 0xffff00, size: 5 }); - const pointCloud = new THREE.Points(pointsGeo, pointsMaterial); - pointCloud.name = 'Points'; - pointCloud.position.set(-200, 0, -200); - scene1.add(pointCloud); - - // --------------------------------------------------------------------- - // Ortho camera - // --------------------------------------------------------------------- - const cameraOrtho = new THREE.OrthographicCamera( - window.innerWidth / -2, - window.innerWidth / 2, - window.innerHeight / 2, - window.innerHeight / -2, - 0.1, - 10, - ); - scene1.add(cameraOrtho); - cameraOrtho.name = 'OrthographicCamera'; - - material = new THREE.MeshLambertMaterial({ - color: 0xffff00, - side: THREE.DoubleSide, - }); - - object = new THREE.Mesh(new THREE.CircleGeometry(50, 20, 0, Math.PI * 2), material); - object.position.set(200, 0, -400); - scene1.add(object); - - object = new THREE.Mesh(new THREE.RingGeometry(10, 50, 20, 5, 0, Math.PI * 2), material); - object.position.set(0, 0, -400); - scene1.add(object); - - object = new THREE.Mesh(new THREE.CylinderGeometry(25, 75, 100, 40, 5), material); - object.position.set(-200, 0, -400); - scene1.add(object); - - // - const points = []; - - for (let i = 0; i < 50; i++) { - points.push(new THREE.Vector2(Math.sin(i * 0.2) * Math.sin(i * 0.1) * 15 + 50, (i - 5) * 2)); - } - - object = new THREE.Mesh(new THREE.LatheGeometry(points, 20), material); - object.position.set(200, 0, 400); - scene1.add(object); - - // --------------------------------------------------------------------- - // Big red box hidden just for testing `onlyVisible` option - // --------------------------------------------------------------------- - material = new THREE.MeshBasicMaterial({ - color: 0xff0000, - }); - object = new THREE.Mesh(new THREE.BoxGeometry(200, 200, 200), material); - object.position.set(0, 0, 0); - object.name = 'CubeHidden'; - object.visible = false; - scene1.add(object); - - // --------------------------------------------------------------------- - // Model requiring KHR_mesh_quantization - // --------------------------------------------------------------------- - const loader = new GLTFLoader(); - loader.load('models/gltf/ShaderBall.glb', function (gltf) { - model = gltf.scene; - model.scale.setScalar(50); - model.position.set(200, -40, -200); - scene1.add(model); - }); - - // --------------------------------------------------------------------- - // 2nd THREE.Scene - // --------------------------------------------------------------------- - scene2 = new THREE.Scene(); - object = new THREE.Mesh(new THREE.BoxGeometry(100, 100, 100), material); - object.position.set(0, 0, 0); - object.name = 'Cube2ndScene'; - scene2.name = 'Scene2'; - scene2.add(object); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.toneMapping = THREE.ACESFilmicToneMapping; - renderer.toneMappingExposure = 1; - - container.appendChild(renderer.domElement); - - // - - window.addEventListener('resize', onWindowResize); - - // --------------------------------------------------------------------- - // Exporting compressed textures and meshes (KTX2 / Draco / Meshopt) - // --------------------------------------------------------------------- - const ktx2Loader = new KTX2Loader().setTranscoderPath('jsm/libs/basis/').detectSupport(renderer); - - const gltfLoader = new GLTFLoader().setPath('models/gltf/'); - gltfLoader.setKTX2Loader(ktx2Loader); - gltfLoader.setMeshoptDecoder(MeshoptDecoder); - gltfLoader.load('coffeemat.glb', function (gltf) { - gltf.scene.position.x = 400; - gltf.scene.position.z = -200; - - scene1.add(gltf.scene); - - coffeemat = gltf.scene; - }); - - // - - const gui = new GUI(); - - let h = gui.addFolder('Settings'); - h.add(params, 'trs').name('Use TRS'); - h.add(params, 'onlyVisible').name('Only Visible Objects'); - h.add(params, 'binary').name('Binary (GLB)'); - h.add(params, 'maxTextureSize', 2, 8192).name('Max Texture Size').step(1); - - h = gui.addFolder('Export'); - h.add(params, 'exportScene1').name('Export Scene 1'); - h.add(params, 'exportScenes').name('Export Scene 1 and 2'); - h.add(params, 'exportSphere').name('Export Sphere'); - h.add(params, 'exportModel').name('Export Model'); - h.add(params, 'exportObjects').name('Export Sphere With Grid'); - h.add(params, 'exportSceneObject').name('Export Scene 1 and Object'); - h.add(params, 'exportCompressedObject').name('Export Coffeemat (from compressed data)'); - - gui.open(); -} - -function exportScene1() { - exportGLTF(scene1); -} - -function exportScenes() { - exportGLTF([scene1, scene2]); -} - -function exportSphere() { - exportGLTF(sphere); -} - -function exportModel() { - exportGLTF(model); -} - -function exportObjects() { - exportGLTF([sphere, gridHelper]); -} - -function exportSceneObject() { - exportGLTF([scene1, gridHelper]); -} - -function exportCompressedObject() { - exportGLTF([coffeemat]); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); -} - -function render() { - const timer = Date.now() * 0.0001; - - camera.position.x = Math.cos(timer) * 800; - camera.position.z = Math.sin(timer) * 800; - - camera.lookAt(scene1.position); - renderer.render(scene1, camera); -} diff --git a/examples-testing/examples/misc_exporter_obj.ts b/examples-testing/examples/misc_exporter_obj.ts deleted file mode 100644 index c315294f8..000000000 --- a/examples-testing/examples/misc_exporter_obj.ts +++ /dev/null @@ -1,194 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { OBJExporter } from 'three/addons/exporters/OBJExporter.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let camera, scene, renderer; - -const params = { - addTriangle: addTriangle, - addCube: addCube, - addCylinder: addCylinder, - addMultiple: addMultiple, - addTransformed: addTransformed, - addPoints: addPoints, - exportToObj: exportToObj, -}; - -init(); -animate(); - -function init() { - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.set(0, 0, 400); - - scene = new THREE.Scene(); - - const ambientLight = new THREE.AmbientLight(0xffffff); - scene.add(ambientLight); - - const directionalLight = new THREE.DirectionalLight(0xffffff, 2.5); - directionalLight.position.set(0, 1, 1); - scene.add(directionalLight); - - const gui = new GUI(); - - let h = gui.addFolder('Geometry Selection'); - h.add(params, 'addTriangle').name('Triangle'); - h.add(params, 'addCube').name('Cube'); - h.add(params, 'addCylinder').name('Cylinder'); - h.add(params, 'addMultiple').name('Multiple objects'); - h.add(params, 'addTransformed').name('Transformed objects'); - h.add(params, 'addPoints').name('Point Cloud'); - - h = gui.addFolder('Export'); - h.add(params, 'exportToObj').name('Export OBJ'); - - gui.open(); - - addGeometry(1); - - window.addEventListener('resize', onWindowResize); - - const controls = new OrbitControls(camera, renderer.domElement); - controls.enablePan = false; -} - -function exportToObj() { - const exporter = new OBJExporter(); - const result = exporter.parse(scene); - saveString(result, 'object.obj'); -} - -function addGeometry(type) { - for (let i = 0; i < scene.children.length; i++) { - const child = scene.children[i]; - - if (child.isMesh || child.isPoints) { - child.geometry.dispose(); - scene.remove(child); - i--; - } - } - - if (type === 1) { - const material = new THREE.MeshLambertMaterial({ color: 0x00cc00 }); - const geometry = generateTriangleGeometry(); - - scene.add(new THREE.Mesh(geometry, material)); - } else if (type === 2) { - const material = new THREE.MeshLambertMaterial({ color: 0x00cc00 }); - const geometry = new THREE.BoxGeometry(100, 100, 100); - scene.add(new THREE.Mesh(geometry, material)); - } else if (type === 3) { - const material = new THREE.MeshLambertMaterial({ color: 0x00cc00 }); - const geometry = new THREE.CylinderGeometry(50, 50, 100, 30, 1); - scene.add(new THREE.Mesh(geometry, material)); - } else if (type === 4 || type === 5) { - const material = new THREE.MeshLambertMaterial({ color: 0x00cc00 }); - const geometry = generateTriangleGeometry(); - - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = -200; - scene.add(mesh); - - const geometry2 = new THREE.BoxGeometry(100, 100, 100); - const mesh2 = new THREE.Mesh(geometry2, material); - scene.add(mesh2); - - const geometry3 = new THREE.CylinderGeometry(50, 50, 100, 30, 1); - const mesh3 = new THREE.Mesh(geometry3, material); - mesh3.position.x = 200; - scene.add(mesh3); - - if (type === 5) { - mesh.rotation.y = Math.PI / 4.0; - mesh2.rotation.y = Math.PI / 4.0; - mesh3.rotation.y = Math.PI / 4.0; - } - } else if (type === 6) { - const points = [0, 0, 0, 100, 0, 0, 100, 100, 0, 0, 100, 0]; - const colors = [0.5, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0.5, 0]; - - const geometry = new THREE.BufferGeometry(); - geometry.setAttribute('position', new THREE.Float32BufferAttribute(points, 3)); - geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); - - const material = new THREE.PointsMaterial({ size: 10, vertexColors: true }); - - const pointCloud = new THREE.Points(geometry, material); - pointCloud.name = 'point cloud'; - scene.add(pointCloud); - } -} - -function addTriangle() { - addGeometry(1); -} - -function addCube() { - addGeometry(2); -} - -function addCylinder() { - addGeometry(3); -} - -function addMultiple() { - addGeometry(4); -} - -function addTransformed() { - addGeometry(5); -} - -function addPoints() { - addGeometry(6); -} - -const link = document.createElement('a'); -link.style.display = 'none'; -document.body.appendChild(link); - -function save(blob, filename) { - link.href = URL.createObjectURL(blob); - link.download = filename; - link.click(); -} - -function saveString(text, filename) { - save(new Blob([text], { type: 'text/plain' }), filename); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - renderer.render(scene, camera); -} - -function generateTriangleGeometry() { - const geometry = new THREE.BufferGeometry(); - const vertices = []; - - vertices.push(-50, -50, 0); - vertices.push(50, -50, 0); - vertices.push(50, 50, 0); - - geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); - geometry.computeVertexNormals(); - - return geometry; -} diff --git a/examples-testing/examples/misc_exporter_ply.ts b/examples-testing/examples/misc_exporter_ply.ts deleted file mode 100644 index 997c4f1a0..000000000 --- a/examples-testing/examples/misc_exporter_ply.ts +++ /dev/null @@ -1,157 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { PLYExporter } from 'three/addons/exporters/PLYExporter.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let scene, camera, renderer, exporter, mesh; - -const params = { - exportASCII: exportASCII, - exportBinaryBigEndian: exportBinaryBigEndian, - exportBinaryLittleEndian: exportBinaryLittleEndian, -}; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(4, 2, 4); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xa0a0a0); - scene.fog = new THREE.Fog(0xa0a0a0, 4, 20); - - exporter = new PLYExporter(); - - // - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 3); - hemiLight.position.set(0, 20, 0); - scene.add(hemiLight); - - const directionalLight = new THREE.DirectionalLight(0xffffff, 3); - directionalLight.position.set(0, 20, 10); - directionalLight.castShadow = true; - directionalLight.shadow.camera.top = 2; - directionalLight.shadow.camera.bottom = -2; - directionalLight.shadow.camera.left = -2; - directionalLight.shadow.camera.right = 2; - scene.add(directionalLight); - - // ground - - const ground = new THREE.Mesh( - new THREE.PlaneGeometry(40, 40), - new THREE.MeshPhongMaterial({ color: 0xcbcbcb, depthWrite: false }), - ); - ground.rotation.x = -Math.PI / 2; - ground.receiveShadow = true; - scene.add(ground); - - const grid = new THREE.GridHelper(40, 20, 0x000000, 0x000000); - grid.material.opacity = 0.2; - grid.material.transparent = true; - scene.add(grid); - - // export mesh - - const geometry = new THREE.BoxGeometry(); - const material = new THREE.MeshPhongMaterial({ vertexColors: true }); - - // color vertices based on vertex positions - const colors = geometry.getAttribute('position').array.slice(); - for (let i = 0, l = colors.length; i < l; i++) { - if (colors[i] > 0) colors[i] = 0.5; - else colors[i] = 0; - } - - geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3, false)); - - mesh = new THREE.Mesh(geometry, material); - mesh.castShadow = true; - mesh.position.y = 0.5; - scene.add(mesh); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - document.body.appendChild(renderer.domElement); - - // - - const controls = new OrbitControls(camera, renderer.domElement); - controls.target.set(0, 0.5, 0); - controls.update(); - - // - - window.addEventListener('resize', onWindowResize); - - const gui = new GUI(); - - gui.add(params, 'exportASCII').name('Export PLY (ASCII)'); - gui.add(params, 'exportBinaryBigEndian').name('Export PLY (Binary BE)'); - gui.add(params, 'exportBinaryLittleEndian').name('Export PLY (Binary LE)'); - gui.open(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - renderer.render(scene, camera); -} - -function exportASCII() { - exporter.parse(mesh, function (result) { - saveString(result, 'box.ply'); - }); -} - -function exportBinaryBigEndian() { - exporter.parse( - mesh, - function (result) { - saveArrayBuffer(result, 'box.ply'); - }, - { binary: true }, - ); -} - -function exportBinaryLittleEndian() { - exporter.parse( - mesh, - function (result) { - saveArrayBuffer(result, 'box.ply'); - }, - { binary: true, littleEndian: true }, - ); -} - -const link = document.createElement('a'); -link.style.display = 'none'; -document.body.appendChild(link); - -function save(blob, filename) { - link.href = URL.createObjectURL(blob); - link.download = filename; - link.click(); -} - -function saveString(text, filename) { - save(new Blob([text], { type: 'text/plain' }), filename); -} - -function saveArrayBuffer(buffer, filename) { - save(new Blob([buffer], { type: 'application/octet-stream' }), filename); -} diff --git a/examples-testing/examples/misc_exporter_stl.ts b/examples-testing/examples/misc_exporter_stl.ts deleted file mode 100644 index ad6e3f592..000000000 --- a/examples-testing/examples/misc_exporter_stl.ts +++ /dev/null @@ -1,130 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { STLExporter } from 'three/addons/exporters/STLExporter.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let scene, camera, renderer, exporter, mesh; - -const params = { - exportASCII: exportASCII, - exportBinary: exportBinary, -}; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(4, 2, 4); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xa0a0a0); - scene.fog = new THREE.Fog(0xa0a0a0, 4, 20); - - exporter = new STLExporter(); - - // - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 3); - hemiLight.position.set(0, 20, 0); - scene.add(hemiLight); - - const directionalLight = new THREE.DirectionalLight(0xffffff, 3); - directionalLight.position.set(0, 20, 10); - directionalLight.castShadow = true; - directionalLight.shadow.camera.top = 2; - directionalLight.shadow.camera.bottom = -2; - directionalLight.shadow.camera.left = -2; - directionalLight.shadow.camera.right = 2; - scene.add(directionalLight); - - // ground - - const ground = new THREE.Mesh( - new THREE.PlaneGeometry(40, 40), - new THREE.MeshPhongMaterial({ color: 0xbbbbbb, depthWrite: false }), - ); - ground.rotation.x = -Math.PI / 2; - ground.receiveShadow = true; - scene.add(ground); - - const grid = new THREE.GridHelper(40, 20, 0x000000, 0x000000); - grid.material.opacity = 0.2; - grid.material.transparent = true; - scene.add(grid); - - // export mesh - - const geometry = new THREE.BoxGeometry(); - const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 }); - - mesh = new THREE.Mesh(geometry, material); - mesh.castShadow = true; - mesh.position.y = 0.5; - scene.add(mesh); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - document.body.appendChild(renderer.domElement); - - // - - const controls = new OrbitControls(camera, renderer.domElement); - controls.target.set(0, 0.5, 0); - controls.update(); - - // - - window.addEventListener('resize', onWindowResize); - - const gui = new GUI(); - - gui.add(params, 'exportASCII').name('Export STL (ASCII)'); - gui.add(params, 'exportBinary').name('Export STL (Binary)'); - gui.open(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - renderer.render(scene, camera); -} - -function exportASCII() { - const result = exporter.parse(mesh); - saveString(result, 'box.stl'); -} - -function exportBinary() { - const result = exporter.parse(mesh, { binary: true }); - saveArrayBuffer(result, 'box.stl'); -} - -const link = document.createElement('a'); -link.style.display = 'none'; -document.body.appendChild(link); - -function save(blob, filename) { - link.href = URL.createObjectURL(blob); - link.download = filename; - link.click(); -} - -function saveString(text, filename) { - save(new Blob([text], { type: 'text/plain' }), filename); -} - -function saveArrayBuffer(buffer, filename) { - save(new Blob([buffer], { type: 'application/octet-stream' }), filename); -} diff --git a/examples-testing/examples/misc_exporter_usdz.ts b/examples-testing/examples/misc_exporter_usdz.ts deleted file mode 100644 index 97630ab41..000000000 --- a/examples-testing/examples/misc_exporter_usdz.ts +++ /dev/null @@ -1,110 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js'; - -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; -import { USDZExporter } from 'three/addons/exporters/USDZExporter.js'; - -let camera, scene, renderer; - -init(); -render(); - -function init() { - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.toneMapping = THREE.ACESFilmicToneMapping; - document.body.appendChild(renderer.domElement); - - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.25, 20); - camera.position.set(-2.5, 0.6, 3.0); - - const pmremGenerator = new THREE.PMREMGenerator(renderer); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xf0f0f0); - scene.environment = pmremGenerator.fromScene(new RoomEnvironment(renderer), 0.04).texture; - - const loader = new GLTFLoader().setPath('models/gltf/DamagedHelmet/glTF/'); - loader.load('DamagedHelmet.gltf', async function (gltf) { - scene.add(gltf.scene); - - const shadowMesh = createSpotShadowMesh(); - shadowMesh.position.y = -1.1; - shadowMesh.position.z = -0.25; - shadowMesh.scale.setScalar(2); - scene.add(shadowMesh); - - render(); - - // USDZ - - const exporter = new USDZExporter(); - const arraybuffer = await exporter.parse(gltf.scene); - const blob = new Blob([arraybuffer], { type: 'application/octet-stream' }); - - const link = document.getElementById('link'); - link.href = URL.createObjectURL(blob); - }); - - const controls = new OrbitControls(camera, renderer.domElement); - controls.addEventListener('change', render); // use if there is no animation loop - controls.minDistance = 2; - controls.maxDistance = 10; - controls.target.set(0, -0.15, -0.2); - controls.update(); - - window.addEventListener('resize', onWindowResize); -} - -function createSpotShadowMesh() { - const canvas = document.createElement('canvas'); - canvas.width = 128; - canvas.height = 128; - - const context = canvas.getContext('2d'); - const gradient = context.createRadialGradient( - canvas.width / 2, - canvas.height / 2, - 0, - canvas.width / 2, - canvas.height / 2, - canvas.width / 2, - ); - gradient.addColorStop(0.1, 'rgba(130,130,130,1)'); - gradient.addColorStop(1, 'rgba(255,255,255,1)'); - - context.fillStyle = gradient; - context.fillRect(0, 0, canvas.width, canvas.height); - - const shadowTexture = new THREE.CanvasTexture(canvas); - - const geometry = new THREE.PlaneGeometry(); - const material = new THREE.MeshBasicMaterial({ - map: shadowTexture, - blending: THREE.MultiplyBlending, - toneMapped: false, - }); - - const mesh = new THREE.Mesh(geometry, material); - mesh.rotation.x = -Math.PI / 2; - - return mesh; -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - render(); -} - -// - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/misc_lookat.ts b/examples-testing/examples/misc_lookat.ts deleted file mode 100644 index f6241b9e1..000000000 --- a/examples-testing/examples/misc_lookat.ts +++ /dev/null @@ -1,97 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let camera, scene, renderer, stats; - -let sphere; - -let mouseX = 0, - mouseY = 0; - -let windowHalfX = window.innerWidth / 2; -let windowHalfY = window.innerHeight / 2; - -document.addEventListener('mousemove', onDocumentMouseMove); - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 15000); - camera.position.z = 3200; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xffffff); - - sphere = new THREE.Mesh(new THREE.SphereGeometry(100, 20, 20), new THREE.MeshNormalMaterial()); - scene.add(sphere); - - const geometry = new THREE.CylinderGeometry(0, 10, 100, 12); - geometry.rotateX(Math.PI / 2); - - const material = new THREE.MeshNormalMaterial(); - - for (let i = 0; i < 1000; i++) { - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = Math.random() * 4000 - 2000; - mesh.position.y = Math.random() * 4000 - 2000; - mesh.position.z = Math.random() * 4000 - 2000; - mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 4 + 2; - scene.add(mesh); - } - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - stats = new Stats(); - document.body.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - windowHalfX = window.innerWidth / 2; - windowHalfY = window.innerHeight / 2; - - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function onDocumentMouseMove(event) { - mouseX = (event.clientX - windowHalfX) * 10; - mouseY = (event.clientY - windowHalfY) * 10; -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.0005; - - sphere.position.x = Math.sin(time * 0.7) * 2000; - sphere.position.y = Math.cos(time * 0.5) * 2000; - sphere.position.z = Math.cos(time * 0.3) * 2000; - - for (let i = 1, l = scene.children.length; i < l; i++) { - scene.children[i].lookAt(sphere.position); - } - - camera.position.x += (mouseX - camera.position.x) * 0.05; - camera.position.y += (-mouseY - camera.position.y) * 0.05; - camera.lookAt(scene.position); - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/misc_uv_tests.ts b/examples-testing/examples/misc_uv_tests.ts deleted file mode 100644 index 4f782d45f..000000000 --- a/examples-testing/examples/misc_uv_tests.ts +++ /dev/null @@ -1,44 +0,0 @@ -import * as THREE from 'three'; - -import { UVsDebug } from 'three/addons/utils/UVsDebug.js'; - -/* - * This is to help debug UVs problems in geometry, - * as well as allow a new user to visualize what UVs are about. - */ - -function test(name, geometry) { - const d = document.createElement('div'); - - d.innerHTML = '

' + name + '

'; - - d.appendChild(UVsDebug(geometry)); - - document.body.appendChild(d); -} - -const points = []; - -for (let i = 0; i < 10; i++) { - points.push(new THREE.Vector2(Math.sin(i * 0.2) * 15 + 50, (i - 5) * 2)); -} - -// - -test('new THREE.PlaneGeometry( 100, 100, 4, 4 )', new THREE.PlaneGeometry(100, 100, 4, 4)); - -test('new THREE.SphereGeometry( 75, 12, 6 )', new THREE.SphereGeometry(75, 12, 6)); - -test('new THREE.IcosahedronGeometry( 30, 1 )', new THREE.IcosahedronGeometry(30, 1)); - -test('new THREE.OctahedronGeometry( 30, 2 )', new THREE.OctahedronGeometry(30, 2)); - -test('new THREE.CylinderGeometry( 25, 75, 100, 10, 5 )', new THREE.CylinderGeometry(25, 75, 100, 10, 5)); - -test('new THREE.BoxGeometry( 100, 100, 100, 4, 4, 4 )', new THREE.BoxGeometry(100, 100, 100, 4, 4, 4)); - -test('new THREE.LatheGeometry( points, 8 )', new THREE.LatheGeometry(points, 8)); - -test('new THREE.TorusGeometry( 50, 20, 8, 8 )', new THREE.TorusGeometry(50, 20, 8, 8)); - -test('new THREE.TorusKnotGeometry( 50, 10, 12, 6 )', new THREE.TorusKnotGeometry(50, 10, 12, 6)); diff --git a/examples-testing/examples/physics_ammo_instancing.ts b/examples-testing/examples/physics_ammo_instancing.ts deleted file mode 100644 index fdfc815e7..000000000 --- a/examples-testing/examples/physics_ammo_instancing.ts +++ /dev/null @@ -1,122 +0,0 @@ -import * as THREE from 'three'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { AmmoPhysics } from 'three/addons/physics/AmmoPhysics.js'; -import Stats from 'three/addons/libs/stats.module.js'; - -let camera, scene, renderer, stats; -let physics, position; - -let boxes, spheres; - -init(); - -async function init() { - physics = await AmmoPhysics(); - position = new THREE.Vector3(); - - // - - camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(-1, 1.5, 2); - camera.lookAt(0, 0.5, 0); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x666666); - - const hemiLight = new THREE.HemisphereLight(); - scene.add(hemiLight); - - const dirLight = new THREE.DirectionalLight(0xffffff, 3); - dirLight.position.set(5, 5, 5); - dirLight.castShadow = true; - dirLight.shadow.camera.zoom = 2; - scene.add(dirLight); - - const floor = new THREE.Mesh(new THREE.BoxGeometry(10, 5, 10), new THREE.ShadowMaterial({ color: 0x444444 })); - floor.position.y = -2.5; - floor.receiveShadow = true; - scene.add(floor); - physics.addMesh(floor); - - // - - const material = new THREE.MeshLambertMaterial(); - - const matrix = new THREE.Matrix4(); - const color = new THREE.Color(); - - // Boxes - - const geometryBox = new THREE.BoxGeometry(0.075, 0.075, 0.075); - boxes = new THREE.InstancedMesh(geometryBox, material, 400); - boxes.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // will be updated every frame - boxes.castShadow = true; - boxes.receiveShadow = true; - scene.add(boxes); - - for (let i = 0; i < boxes.count; i++) { - matrix.setPosition(Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5); - boxes.setMatrixAt(i, matrix); - boxes.setColorAt(i, color.setHex(0xffffff * Math.random())); - } - - physics.addMesh(boxes, 1); - - // Spheres - - const geometrySphere = new THREE.IcosahedronGeometry(0.05, 4); - spheres = new THREE.InstancedMesh(geometrySphere, material, 400); - spheres.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // will be updated every frame - spheres.castShadow = true; - spheres.receiveShadow = true; - scene.add(spheres); - - for (let i = 0; i < spheres.count; i++) { - matrix.setPosition(Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5); - spheres.setMatrixAt(i, matrix); - spheres.setColorAt(i, color.setHex(0xffffff * Math.random())); - } - - physics.addMesh(spheres, 1); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - document.body.appendChild(renderer.domElement); - - stats = new Stats(); - document.body.appendChild(stats.dom); - - // - - const controls = new OrbitControls(camera, renderer.domElement); - controls.target.y = 0.5; - controls.update(); - - animate(); - - setInterval(() => { - let index = Math.floor(Math.random() * boxes.count); - - position.set(0, Math.random() + 1, 0); - physics.setMeshPosition(boxes, position, index); - - // - - index = Math.floor(Math.random() * spheres.count); - - position.set(0, Math.random() + 1, 0); - physics.setMeshPosition(spheres, position, index); - }, 1000 / 60); -} - -function animate() { - requestAnimationFrame(animate); - - renderer.render(scene, camera); - - stats.update(); -} diff --git a/examples-testing/examples/physics_rapier_instancing.ts b/examples-testing/examples/physics_rapier_instancing.ts deleted file mode 100644 index 42116a6ec..000000000 --- a/examples-testing/examples/physics_rapier_instancing.ts +++ /dev/null @@ -1,122 +0,0 @@ -import * as THREE from 'three'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { RapierPhysics } from 'three/addons/physics/RapierPhysics.js'; -import Stats from 'three/addons/libs/stats.module.js'; - -let camera, scene, renderer, stats; -let physics, position; - -let boxes, spheres; - -init(); - -async function init() { - physics = await RapierPhysics(); - position = new THREE.Vector3(); - - // - - camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(-1, 1.5, 2); - camera.lookAt(0, 0.5, 0); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x666666); - - const hemiLight = new THREE.HemisphereLight(); - scene.add(hemiLight); - - const dirLight = new THREE.DirectionalLight(0xffffff, 3); - dirLight.position.set(5, 5, 5); - dirLight.castShadow = true; - dirLight.shadow.camera.zoom = 2; - scene.add(dirLight); - - const floor = new THREE.Mesh(new THREE.BoxGeometry(10, 5, 10), new THREE.ShadowMaterial({ color: 0x444444 })); - floor.position.y = -2.5; - floor.receiveShadow = true; - scene.add(floor); - physics.addMesh(floor); - - // - - const material = new THREE.MeshLambertMaterial(); - - const matrix = new THREE.Matrix4(); - const color = new THREE.Color(); - - // Boxes - - const geometryBox = new THREE.BoxGeometry(0.075, 0.075, 0.075); - boxes = new THREE.InstancedMesh(geometryBox, material, 400); - boxes.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // will be updated every frame - boxes.castShadow = true; - boxes.receiveShadow = true; - scene.add(boxes); - - for (let i = 0; i < boxes.count; i++) { - matrix.setPosition(Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5); - boxes.setMatrixAt(i, matrix); - boxes.setColorAt(i, color.setHex(0xffffff * Math.random())); - } - - physics.addMesh(boxes, 1); - - // Spheres - - const geometrySphere = new THREE.IcosahedronGeometry(0.05, 4); - spheres = new THREE.InstancedMesh(geometrySphere, material, 400); - spheres.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // will be updated every frame - spheres.castShadow = true; - spheres.receiveShadow = true; - scene.add(spheres); - - for (let i = 0; i < spheres.count; i++) { - matrix.setPosition(Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5); - spheres.setMatrixAt(i, matrix); - spheres.setColorAt(i, color.setHex(0xffffff * Math.random())); - } - - physics.addMesh(spheres, 1); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - document.body.appendChild(renderer.domElement); - - stats = new Stats(); - document.body.appendChild(stats.dom); - - // - - const controls = new OrbitControls(camera, renderer.domElement); - controls.target.y = 0.5; - controls.update(); - - animate(); - - setInterval(() => { - let index = Math.floor(Math.random() * boxes.count); - - position.set(0, Math.random() + 1, 0); - physics.setMeshPosition(boxes, position, index); - - // - - index = Math.floor(Math.random() * spheres.count); - - position.set(0, Math.random() + 1, 0); - physics.setMeshPosition(spheres, position, index); - }, 1000 / 60); -} - -function animate() { - requestAnimationFrame(animate); - - renderer.render(scene, camera); - - stats.update(); -} diff --git a/examples-testing/examples/svg_lines.ts b/examples-testing/examples/svg_lines.ts deleted file mode 100644 index 99b74c405..000000000 --- a/examples-testing/examples/svg_lines.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as THREE from 'three'; - -import { SVGRenderer } from 'three/addons/renderers/SVGRenderer.js'; - -THREE.ColorManagement.enabled = false; - -let camera, scene, renderer; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(33, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.z = 10; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0, 0, 0); - - renderer = new SVGRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - // - - const vertices = []; - const divisions = 50; - - for (let i = 0; i <= divisions; i++) { - const v = (i / divisions) * (Math.PI * 2); - - const x = Math.sin(v); - const z = Math.cos(v); - - vertices.push(x, 0, z); - } - - const geometry = new THREE.BufferGeometry(); - geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); - - // - - for (let i = 1; i <= 3; i++) { - const material = new THREE.LineBasicMaterial({ - color: Math.random() * 0xffffff, - linewidth: 10, - }); - const line = new THREE.Line(geometry, material); - line.scale.setScalar(i / 3); - scene.add(line); - } - - const material = new THREE.LineDashedMaterial({ - color: 'blue', - linewidth: 1, - dashSize: 10, - gapSize: 10, - }); - const line = new THREE.Line(geometry, material); - line.scale.setScalar(2); - scene.add(line); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - let count = 0; - const time = performance.now() / 1000; - - scene.traverse(function (child) { - child.rotation.x = count + time / 3; - child.rotation.z = count + time / 4; - - count++; - }); - - renderer.render(scene, camera); - requestAnimationFrame(animate); -} diff --git a/examples-testing/examples/svg_sandbox.ts b/examples-testing/examples/svg_sandbox.ts deleted file mode 100644 index e6be8386c..000000000 --- a/examples-testing/examples/svg_sandbox.ts +++ /dev/null @@ -1,212 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import { SVGRenderer, SVGObject } from 'three/addons/renderers/SVGRenderer.js'; - -THREE.ColorManagement.enabled = false; - -let camera, scene, renderer, stats; - -let group; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000); - camera.position.z = 500; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xf0f0f0); - - // QRCODE - - const loader = new THREE.BufferGeometryLoader(); - loader.load('models/json/QRCode_buffergeometry.json', function (geometry) { - mesh = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ vertexColors: true })); - mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; - scene.add(mesh); - }); - - // CUBES - - const boxGeometry = new THREE.BoxGeometry(100, 100, 100); - - let mesh = new THREE.Mesh( - boxGeometry, - new THREE.MeshBasicMaterial({ color: 0x0000ff, opacity: 0.5, transparent: true }), - ); - mesh.position.x = 500; - mesh.rotation.x = Math.random(); - mesh.rotation.y = Math.random(); - mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; - scene.add(mesh); - - mesh = new THREE.Mesh(boxGeometry, new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff })); - mesh.position.x = 500; - mesh.position.y = 500; - mesh.rotation.x = Math.random(); - mesh.rotation.y = Math.random(); - mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; - scene.add(mesh); - - // PLANE - - mesh = new THREE.Mesh( - new THREE.PlaneGeometry(100, 100), - new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff, side: THREE.DoubleSide }), - ); - mesh.position.y = -500; - mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; - scene.add(mesh); - - // CYLINDER - - mesh = new THREE.Mesh( - new THREE.CylinderGeometry(20, 100, 200, 10), - new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff }), - ); - mesh.position.x = -500; - mesh.rotation.x = -Math.PI / 2; - mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; - scene.add(mesh); - - // POLYFIELD - - const geometry = new THREE.BufferGeometry(); - const material = new THREE.MeshBasicMaterial({ vertexColors: true, side: THREE.DoubleSide }); - - const v = new THREE.Vector3(); - const v0 = new THREE.Vector3(); - const v1 = new THREE.Vector3(); - const v2 = new THREE.Vector3(); - const color = new THREE.Color(); - - const vertices = []; - const colors = []; - - for (let i = 0; i < 100; i++) { - v.set(Math.random() * 1000 - 500, Math.random() * 1000 - 500, Math.random() * 1000 - 500); - - v0.set(Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50); - - v1.set(Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50); - - v2.set(Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50); - - v0.add(v); - v1.add(v); - v2.add(v); - - color.setHex(Math.random() * 0xffffff); - - // create a single triangle - - vertices.push(v0.x, v0.y, v0.z); - vertices.push(v1.x, v1.y, v1.z); - vertices.push(v2.x, v2.y, v2.z); - - colors.push(color.r, color.g, color.b); - colors.push(color.r, color.g, color.b); - colors.push(color.r, color.g, color.b); - } - - geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); - geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); - - group = new THREE.Mesh(geometry, material); - group.scale.set(2, 2, 2); - scene.add(group); - - // SPRITES - - for (let i = 0; i < 50; i++) { - const material = new THREE.SpriteMaterial({ color: Math.random() * 0xffffff }); - const sprite = new THREE.Sprite(material); - sprite.position.x = Math.random() * 1000 - 500; - sprite.position.y = Math.random() * 1000 - 500; - sprite.position.z = Math.random() * 1000 - 500; - sprite.scale.set(64, 64, 1); - scene.add(sprite); - } - - // CUSTOM - - const node = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); - node.setAttribute('stroke', 'black'); - node.setAttribute('fill', 'red'); - node.setAttribute('r', '40'); - - for (let i = 0; i < 50; i++) { - const object = new SVGObject(node.cloneNode()); - object.position.x = Math.random() * 1000 - 500; - object.position.y = Math.random() * 1000 - 500; - object.position.z = Math.random() * 1000 - 500; - scene.add(object); - } - - // CUSTOM FROM FILE - - const fileLoader = new THREE.FileLoader(); - fileLoader.load('models/svg/hexagon.svg', function (svg) { - const node = document.createElementNS('http://www.w3.org/2000/svg', 'g'); - const parser = new DOMParser(); - const doc = parser.parseFromString(svg, 'image/svg+xml'); - - node.appendChild(doc.documentElement); - - const object = new SVGObject(node); - object.position.x = 500; - scene.add(object); - }); - - // LIGHTS - - const ambient = new THREE.AmbientLight(0x80ffff); - scene.add(ambient); - - const directional = new THREE.DirectionalLight(0xffff00); - directional.position.set(-1, 0.5, 0); - scene.add(directional); - - renderer = new SVGRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.setQuality('low'); - document.body.appendChild(renderer.domElement); - - stats = new Stats(); - document.body.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.0002; - - camera.position.x = Math.sin(time) * 500; - camera.position.z = Math.cos(time) * 500; - camera.lookAt(scene.position); - - group.rotation.x += 0.01; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webaudio_orientation.ts b/examples-testing/examples/webaudio_orientation.ts deleted file mode 100644 index d5cff3934..000000000 --- a/examples-testing/examples/webaudio_orientation.ts +++ /dev/null @@ -1,141 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { PositionalAudioHelper } from 'three/addons/helpers/PositionalAudioHelper.js'; -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; - -let scene, camera, renderer; - -const startButton = document.getElementById('startButton'); -startButton.addEventListener('click', init); - -function init() { - const overlay = document.getElementById('overlay'); - overlay.remove(); - - const container = document.getElementById('container'); - - // - - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(3, 2, 3); - - const reflectionCube = new THREE.CubeTextureLoader() - .setPath('textures/cube/SwedishRoyalCastle/') - .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xa0a0a0); - scene.fog = new THREE.Fog(0xa0a0a0, 2, 20); - - // - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x8d8d8d, 3); - hemiLight.position.set(0, 20, 0); - scene.add(hemiLight); - - const dirLight = new THREE.DirectionalLight(0xffffff, 3); - dirLight.position.set(5, 5, 0); - dirLight.castShadow = true; - dirLight.shadow.camera.top = 1; - dirLight.shadow.camera.bottom = -1; - dirLight.shadow.camera.left = -1; - dirLight.shadow.camera.right = 1; - dirLight.shadow.camera.near = 0.1; - dirLight.shadow.camera.far = 20; - scene.add(dirLight); - - // scene.add( new THREE.CameraHelper( dirLight.shadow.camera ) ); - - // - - const mesh = new THREE.Mesh( - new THREE.PlaneGeometry(50, 50), - new THREE.MeshPhongMaterial({ color: 0xcbcbcb, depthWrite: false }), - ); - mesh.rotation.x = -Math.PI / 2; - mesh.receiveShadow = true; - scene.add(mesh); - - const grid = new THREE.GridHelper(50, 50, 0xc1c1c1, 0xc1c1c1); - scene.add(grid); - - // - - const listener = new THREE.AudioListener(); - camera.add(listener); - - const audioElement = document.getElementById('music'); - audioElement.play(); - - const positionalAudio = new THREE.PositionalAudio(listener); - positionalAudio.setMediaElementSource(audioElement); - positionalAudio.setRefDistance(1); - positionalAudio.setDirectionalCone(180, 230, 0.1); - - const helper = new PositionalAudioHelper(positionalAudio, 0.1); - positionalAudio.add(helper); - - // - - const gltfLoader = new GLTFLoader(); - gltfLoader.load('models/gltf/BoomBox.glb', function (gltf) { - const boomBox = gltf.scene; - boomBox.position.set(0, 0.2, 0); - boomBox.scale.set(20, 20, 20); - - boomBox.traverse(function (object) { - if (object.isMesh) { - object.material.envMap = reflectionCube; - object.geometry.rotateY(-Math.PI); - object.castShadow = true; - } - }); - - boomBox.add(positionalAudio); - scene.add(boomBox); - animate(); - }); - - // sound is damped behind this wall - - const wallGeometry = new THREE.BoxGeometry(2, 1, 0.1); - const wallMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, transparent: true, opacity: 0.5 }); - - const wall = new THREE.Mesh(wallGeometry, wallMaterial); - wall.position.set(0, 0.5, -0.5); - scene.add(wall); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - container.appendChild(renderer.domElement); - - // - - const controls = new OrbitControls(camera, renderer.domElement); - controls.target.set(0, 0.1, 0); - controls.update(); - controls.minDistance = 0.5; - controls.maxDistance = 10; - controls.maxPolarAngle = 0.5 * Math.PI; - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webaudio_sandbox.ts b/examples-testing/examples/webaudio_sandbox.ts deleted file mode 100644 index 56bd042a0..000000000 --- a/examples-testing/examples/webaudio_sandbox.ts +++ /dev/null @@ -1,228 +0,0 @@ -import * as THREE from 'three'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { FirstPersonControls } from 'three/addons/controls/FirstPersonControls.js'; - -let camera, controls, scene, renderer, light; - -let material1, material2, material3; - -let analyser1, analyser2, analyser3; - -const clock = new THREE.Clock(); - -const startButton = document.getElementById('startButton'); -startButton.addEventListener('click', init); - -function init() { - const overlay = document.getElementById('overlay'); - overlay.remove(); - - camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000); - camera.position.set(0, 25, 0); - - const listener = new THREE.AudioListener(); - camera.add(listener); - - scene = new THREE.Scene(); - scene.fog = new THREE.FogExp2(0x000000, 0.0025); - - light = new THREE.DirectionalLight(0xffffff, 3); - light.position.set(0, 0.5, 1).normalize(); - scene.add(light); - - const sphere = new THREE.SphereGeometry(20, 32, 16); - - material1 = new THREE.MeshPhongMaterial({ color: 0xffaa00, flatShading: true, shininess: 0 }); - material2 = new THREE.MeshPhongMaterial({ color: 0xff2200, flatShading: true, shininess: 0 }); - material3 = new THREE.MeshPhongMaterial({ color: 0x6622aa, flatShading: true, shininess: 0 }); - - // sound spheres - - const mesh1 = new THREE.Mesh(sphere, material1); - mesh1.position.set(-250, 30, 0); - scene.add(mesh1); - - const sound1 = new THREE.PositionalAudio(listener); - const songElement = document.getElementById('song'); - sound1.setMediaElementSource(songElement); - sound1.setRefDistance(20); - songElement.play(); - mesh1.add(sound1); - - // - - const mesh2 = new THREE.Mesh(sphere, material2); - mesh2.position.set(250, 30, 0); - scene.add(mesh2); - - const sound2 = new THREE.PositionalAudio(listener); - const skullbeatzElement = document.getElementById('skullbeatz'); - sound2.setMediaElementSource(skullbeatzElement); - sound2.setRefDistance(20); - skullbeatzElement.play(); - mesh2.add(sound2); - - // - - const mesh3 = new THREE.Mesh(sphere, material3); - mesh3.position.set(0, 30, -250); - scene.add(mesh3); - - const sound3 = new THREE.PositionalAudio(listener); - const oscillator = listener.context.createOscillator(); - oscillator.type = 'sine'; - oscillator.frequency.setValueAtTime(144, sound3.context.currentTime); - oscillator.start(0); - sound3.setNodeSource(oscillator); - sound3.setRefDistance(20); - sound3.setVolume(0.5); - mesh3.add(sound3); - - // analysers - - analyser1 = new THREE.AudioAnalyser(sound1, 32); - analyser2 = new THREE.AudioAnalyser(sound2, 32); - analyser3 = new THREE.AudioAnalyser(sound3, 32); - - // global ambient audio - - const sound4 = new THREE.Audio(listener); - const utopiaElement = document.getElementById('utopia'); - sound4.setMediaElementSource(utopiaElement); - sound4.setVolume(0.5); - utopiaElement.play(); - - // ground - - const helper = new THREE.GridHelper(1000, 10, 0x444444, 0x444444); - helper.position.y = 0.1; - scene.add(helper); - - // - - const SoundControls = function () { - this.master = listener.getMasterVolume(); - this.firstSphere = sound1.getVolume(); - this.secondSphere = sound2.getVolume(); - this.thirdSphere = sound3.getVolume(); - this.Ambient = sound4.getVolume(); - }; - - const GeneratorControls = function () { - this.frequency = oscillator.frequency.value; - this.wavetype = oscillator.type; - }; - - const gui = new GUI(); - const soundControls = new SoundControls(); - const generatorControls = new GeneratorControls(); - const volumeFolder = gui.addFolder('sound volume'); - const generatorFolder = gui.addFolder('sound generator'); - - volumeFolder - .add(soundControls, 'master') - .min(0.0) - .max(1.0) - .step(0.01) - .onChange(function () { - listener.setMasterVolume(soundControls.master); - }); - volumeFolder - .add(soundControls, 'firstSphere') - .min(0.0) - .max(1.0) - .step(0.01) - .onChange(function () { - sound1.setVolume(soundControls.firstSphere); - }); - volumeFolder - .add(soundControls, 'secondSphere') - .min(0.0) - .max(1.0) - .step(0.01) - .onChange(function () { - sound2.setVolume(soundControls.secondSphere); - }); - - volumeFolder - .add(soundControls, 'thirdSphere') - .min(0.0) - .max(1.0) - .step(0.01) - .onChange(function () { - sound3.setVolume(soundControls.thirdSphere); - }); - volumeFolder - .add(soundControls, 'Ambient') - .min(0.0) - .max(1.0) - .step(0.01) - .onChange(function () { - sound4.setVolume(soundControls.Ambient); - }); - volumeFolder.open(); - generatorFolder - .add(generatorControls, 'frequency') - .min(50.0) - .max(5000.0) - .step(1.0) - .onChange(function () { - oscillator.frequency.setValueAtTime(generatorControls.frequency, listener.context.currentTime); - }); - generatorFolder - .add(generatorControls, 'wavetype', ['sine', 'square', 'sawtooth', 'triangle']) - .onChange(function () { - oscillator.type = generatorControls.wavetype; - }); - - generatorFolder.open(); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - // - - controls = new FirstPersonControls(camera, renderer.domElement); - - controls.movementSpeed = 70; - controls.lookSpeed = 0.05; - controls.lookVertical = false; - - // - - window.addEventListener('resize', onWindowResize); - - animate(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - controls.handleResize(); -} - -function animate() { - requestAnimationFrame(animate); - render(); -} - -function render() { - const delta = clock.getDelta(); - - controls.update(delta); - - material1.emissive.b = analyser1.getAverageFrequency() / 256; - material2.emissive.b = analyser2.getAverageFrequency() / 256; - material3.emissive.b = analyser3.getAverageFrequency() / 256; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webaudio_timing.ts b/examples-testing/examples/webaudio_timing.ts deleted file mode 100644 index bab79dd74..000000000 --- a/examples-testing/examples/webaudio_timing.ts +++ /dev/null @@ -1,158 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -let scene, camera, renderer, clock; - -const objects = []; - -const speed = 2.5; -const height = 3; -const offset = 0.5; - -const startButton = document.getElementById('startButton'); -startButton.addEventListener('click', init); - -function init() { - const overlay = document.getElementById('overlay'); - overlay.remove(); - - const container = document.getElementById('container'); - - scene = new THREE.Scene(); - - clock = new THREE.Clock(); - - // - - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(7, 3, 7); - - // lights - - const ambientLight = new THREE.AmbientLight(0xcccccc); - scene.add(ambientLight); - - const directionalLight = new THREE.DirectionalLight(0xffffff, 2.5); - directionalLight.position.set(0, 5, 5); - scene.add(directionalLight); - - const d = 5; - directionalLight.castShadow = true; - directionalLight.shadow.camera.left = -d; - directionalLight.shadow.camera.right = d; - directionalLight.shadow.camera.top = d; - directionalLight.shadow.camera.bottom = -d; - - directionalLight.shadow.camera.near = 1; - directionalLight.shadow.camera.far = 20; - - directionalLight.shadow.mapSize.x = 1024; - directionalLight.shadow.mapSize.y = 1024; - - // audio - - const audioLoader = new THREE.AudioLoader(); - - const listener = new THREE.AudioListener(); - camera.add(listener); - - // floor - - const floorGeometry = new THREE.PlaneGeometry(10, 10); - const floorMaterial = new THREE.MeshLambertMaterial({ color: 0x4676b6 }); - - const floor = new THREE.Mesh(floorGeometry, floorMaterial); - floor.rotation.x = Math.PI * -0.5; - floor.receiveShadow = true; - scene.add(floor); - - // objects - - const count = 5; - const radius = 3; - - const ballGeometry = new THREE.SphereGeometry(0.3, 32, 16); - ballGeometry.translate(0, 0.3, 0); - const ballMaterial = new THREE.MeshLambertMaterial({ color: 0xcccccc }); - - // create objects when audio buffer is loaded - - audioLoader.load('sounds/ping_pong.mp3', function (buffer) { - for (let i = 0; i < count; i++) { - const s = (i / count) * Math.PI * 2; - - const ball = new THREE.Mesh(ballGeometry, ballMaterial); - ball.castShadow = true; - ball.userData.down = false; - - ball.position.x = radius * Math.cos(s); - ball.position.z = radius * Math.sin(s); - - const audio = new THREE.PositionalAudio(listener); - audio.setBuffer(buffer); - ball.add(audio); - - scene.add(ball); - objects.push(ball); - } - - animate(); - }); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - container.appendChild(renderer.domElement); - - // - - const controls = new OrbitControls(camera, renderer.domElement); - controls.minDistance = 1; - controls.maxDistance = 25; - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - render(); -} - -function render() { - const time = clock.getElapsedTime(); - - for (let i = 0; i < objects.length; i++) { - const ball = objects[i]; - - const previousHeight = ball.position.y; - ball.position.y = Math.abs(Math.sin(i * offset + time * speed) * height); - - if (ball.position.y < previousHeight) { - ball.userData.down = true; - } else { - if (ball.userData.down === true) { - // ball changed direction from down to up - - const audio = ball.children[0]; - audio.play(); // play audio with perfect timing when ball hits the surface - ball.userData.down = false; - } - } - } - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webaudio_visualizer.ts b/examples-testing/examples/webaudio_visualizer.ts deleted file mode 100644 index 6c4244f82..000000000 --- a/examples-testing/examples/webaudio_visualizer.ts +++ /dev/null @@ -1,93 +0,0 @@ -import * as THREE from 'three'; - -let scene, camera, renderer, analyser, uniforms; - -const startButton = document.getElementById('startButton'); -startButton.addEventListener('click', init); - -function init() { - const fftSize = 128; - - // - - const overlay = document.getElementById('overlay'); - overlay.remove(); - - // - - const container = document.getElementById('container'); - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - scene = new THREE.Scene(); - - camera = new THREE.Camera(); - - // - - const listener = new THREE.AudioListener(); - - const audio = new THREE.Audio(listener); - const file = './sounds/376737_Skullbeatz___Bad_Cat_Maste.mp3'; - - if (/(iPad|iPhone|iPod)/g.test(navigator.userAgent)) { - const loader = new THREE.AudioLoader(); - loader.load(file, function (buffer) { - audio.setBuffer(buffer); - audio.play(); - }); - } else { - const mediaElement = new Audio(file); - mediaElement.play(); - - audio.setMediaElementSource(mediaElement); - } - - analyser = new THREE.AudioAnalyser(audio, fftSize); - - // - - const format = renderer.capabilities.isWebGL2 ? THREE.RedFormat : THREE.LuminanceFormat; - - uniforms = { - tAudioData: { value: new THREE.DataTexture(analyser.data, fftSize / 2, 1, format) }, - }; - - const material = new THREE.ShaderMaterial({ - uniforms: uniforms, - vertexShader: document.getElementById('vertexShader').textContent, - fragmentShader: document.getElementById('fragmentShader').textContent, - }); - - const geometry = new THREE.PlaneGeometry(1, 1); - - const mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // - - window.addEventListener('resize', onWindowResize); - - animate(); -} - -function onWindowResize() { - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - render(); -} - -function render() { - analyser.getFrequencyData(); - - uniforms.tAudioData.value.needsUpdate = true; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts b/examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts deleted file mode 100644 index 848814cd0..000000000 --- a/examples-testing/examples/webgl2_buffergeometry_attributes_integer.ts +++ /dev/null @@ -1,121 +0,0 @@ -import * as THREE from 'three'; - -import WebGL from 'three/addons/capabilities/WebGL.js'; - -if (WebGL.isWebGL2Available() === false) { - document.body.appendChild(WebGL.getWebGL2ErrorMessage()); -} - -let camera, scene, renderer, mesh; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500); - camera.position.z = 2500; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x050505); - scene.fog = new THREE.Fog(0x050505, 2000, 3500); - - // geometry - - const triangles = 10000; - - const geometry = new THREE.BufferGeometry(); - - const positions = []; - const uvs = []; - const textureIndices = []; - - const n = 800, - n2 = n / 2; // triangles spread in the cube - const d = 50, - d2 = d / 2; // individual triangle size - - for (let i = 0; i < triangles; i++) { - // positions - - const x = Math.random() * n - n2; - const y = Math.random() * n - n2; - const z = Math.random() * n - n2; - - const ax = x + Math.random() * d - d2; - const ay = y + Math.random() * d - d2; - const az = z + Math.random() * d - d2; - - const bx = x + Math.random() * d - d2; - const by = y + Math.random() * d - d2; - const bz = z + Math.random() * d - d2; - - const cx = x + Math.random() * d - d2; - const cy = y + Math.random() * d - d2; - const cz = z + Math.random() * d - d2; - - positions.push(ax, ay, az); - positions.push(bx, by, bz); - positions.push(cx, cy, cz); - - // uvs - - uvs.push(0, 0); - uvs.push(0.5, 1); - uvs.push(1, 0); - - // texture indices - - const t = i % 3; - textureIndices.push(t, t, t); - } - - geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); - geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2)); - geometry.setAttribute('textureIndex', new THREE.Int16BufferAttribute(textureIndices, 1)); - geometry.attributes.textureIndex.gpuType = THREE.IntType; - - geometry.computeBoundingSphere(); - - // material - - const loader = new THREE.TextureLoader(); - - const map1 = loader.load('textures/crate.gif'); - const map2 = loader.load('textures/floors/FloorsCheckerboard_S_Diffuse.jpg'); - const map3 = loader.load('textures/terrain/grasslight-big.jpg'); - - const material = new THREE.ShaderMaterial({ - uniforms: { - uTextures: { - value: [map1, map2, map3], - }, - }, - vertexShader: document.getElementById('vertexShader').textContent, - fragmentShader: document.getElementById('fragmentShader').textContent, - side: THREE.DoubleSide, - glslVersion: THREE.GLSL3, - }); - - // mesh - - mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // renderer - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); -} - -function animate() { - requestAnimationFrame(animate); - - const time = Date.now() * 0.001; - - mesh.rotation.x = time * 0.25; - mesh.rotation.y = time * 0.5; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl2_buffergeometry_attributes_none.ts b/examples-testing/examples/webgl2_buffergeometry_attributes_none.ts deleted file mode 100644 index a77b973df..000000000 --- a/examples-testing/examples/webgl2_buffergeometry_attributes_none.ts +++ /dev/null @@ -1,64 +0,0 @@ -import * as THREE from 'three'; - -import WebGL from 'three/addons/capabilities/WebGL.js'; - -if (WebGL.isWebGL2Available() === false) { - document.body.appendChild(WebGL.getWebGL2ErrorMessage()); -} - -let camera, scene, renderer, mesh; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500); - camera.position.z = 4; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x050505); - scene.fog = new THREE.Fog(0x050505, 2000, 3500); - - // geometry - - const triangleCount = 10000; - const vertexCountPerTriangle = 3; - const vertexCount = triangleCount * vertexCountPerTriangle; - - const geometry = new THREE.BufferGeometry(); - geometry.setDrawRange(0, vertexCount); - - // material - - const material = new THREE.RawShaderMaterial({ - uniforms: { - seed: { value: 42 }, - }, - vertexShader: document.getElementById('vertexShader').textContent, - fragmentShader: document.getElementById('fragmentShader').textContent, - side: THREE.DoubleSide, - glslVersion: THREE.GLSL3, - }); - - // mesh - - mesh = new THREE.Mesh(geometry, material); - mesh.frustumCulled = false; - scene.add(mesh); - - // renderer - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); -} - -function animate(time) { - requestAnimationFrame(animate); - - mesh.rotation.x = (time / 1000.0) * 0.25; - mesh.rotation.y = (time / 1000.0) * 0.5; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl2_materials_texture3d.ts b/examples-testing/examples/webgl2_materials_texture3d.ts deleted file mode 100644 index b746daf0b..000000000 --- a/examples-testing/examples/webgl2_materials_texture3d.ts +++ /dev/null @@ -1,133 +0,0 @@ -import * as THREE from 'three'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { NRRDLoader } from 'three/addons/loaders/NRRDLoader.js'; -import { VolumeRenderShader1 } from 'three/addons/shaders/VolumeShader.js'; -import WebGL from 'three/addons/capabilities/WebGL.js'; - -if (WebGL.isWebGL2Available() === false) { - document.body.appendChild(WebGL.getWebGL2ErrorMessage()); -} - -let renderer, scene, camera, controls, material, volconfig, cmtextures; - -init(); - -function init() { - scene = new THREE.Scene(); - - // Create renderer - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - // Create camera (The volume renderer does not work very well with perspective yet) - const h = 512; // frustum height - const aspect = window.innerWidth / window.innerHeight; - camera = new THREE.OrthographicCamera((-h * aspect) / 2, (h * aspect) / 2, h / 2, -h / 2, 1, 1000); - camera.position.set(-64, -64, 128); - camera.up.set(0, 0, 1); // In our data, z is up - - // Create controls - controls = new OrbitControls(camera, renderer.domElement); - controls.addEventListener('change', render); - controls.target.set(64, 64, 128); - controls.minZoom = 0.5; - controls.maxZoom = 4; - controls.enablePan = false; - controls.update(); - - // scene.add( new AxesHelper( 128 ) ); - - // Lighting is baked into the shader a.t.m. - // let dirLight = new DirectionalLight( 0xffffff ); - - // The gui for interaction - volconfig = { clim1: 0, clim2: 1, renderstyle: 'iso', isothreshold: 0.15, colormap: 'viridis' }; - const gui = new GUI(); - gui.add(volconfig, 'clim1', 0, 1, 0.01).onChange(updateUniforms); - gui.add(volconfig, 'clim2', 0, 1, 0.01).onChange(updateUniforms); - gui.add(volconfig, 'colormap', { gray: 'gray', viridis: 'viridis' }).onChange(updateUniforms); - gui.add(volconfig, 'renderstyle', { mip: 'mip', iso: 'iso' }).onChange(updateUniforms); - gui.add(volconfig, 'isothreshold', 0, 1, 0.01).onChange(updateUniforms); - - // Load the data ... - new NRRDLoader().load('models/nrrd/stent.nrrd', function (volume) { - // Texture to hold the volume. We have scalars, so we put our data in the red channel. - // THREEJS will select R32F (33326) based on the THREE.RedFormat and THREE.FloatType. - // Also see https://www.khronos.org/registry/webgl/specs/latest/2.0/#TEXTURE_TYPES_FORMATS_FROM_DOM_ELEMENTS_TABLE - // TODO: look the dtype up in the volume metadata - const texture = new THREE.Data3DTexture(volume.data, volume.xLength, volume.yLength, volume.zLength); - texture.format = THREE.RedFormat; - texture.type = THREE.FloatType; - texture.minFilter = texture.magFilter = THREE.LinearFilter; - texture.unpackAlignment = 1; - texture.needsUpdate = true; - - // Colormap textures - cmtextures = { - viridis: new THREE.TextureLoader().load('textures/cm_viridis.png', render), - gray: new THREE.TextureLoader().load('textures/cm_gray.png', render), - }; - - // Material - const shader = VolumeRenderShader1; - - const uniforms = THREE.UniformsUtils.clone(shader.uniforms); - - uniforms['u_data'].value = texture; - uniforms['u_size'].value.set(volume.xLength, volume.yLength, volume.zLength); - uniforms['u_clim'].value.set(volconfig.clim1, volconfig.clim2); - uniforms['u_renderstyle'].value = volconfig.renderstyle == 'mip' ? 0 : 1; // 0: MIP, 1: ISO - uniforms['u_renderthreshold'].value = volconfig.isothreshold; // For ISO renderstyle - uniforms['u_cmdata'].value = cmtextures[volconfig.colormap]; - - material = new THREE.ShaderMaterial({ - uniforms: uniforms, - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader, - side: THREE.BackSide, // The volume shader uses the backface as its "reference point" - }); - - // THREE.Mesh - const geometry = new THREE.BoxGeometry(volume.xLength, volume.yLength, volume.zLength); - geometry.translate(volume.xLength / 2 - 0.5, volume.yLength / 2 - 0.5, volume.zLength / 2 - 0.5); - - const mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - render(); - }); - - window.addEventListener('resize', onWindowResize); -} - -function updateUniforms() { - material.uniforms['u_clim'].value.set(volconfig.clim1, volconfig.clim2); - material.uniforms['u_renderstyle'].value = volconfig.renderstyle == 'mip' ? 0 : 1; // 0: MIP, 1: ISO - material.uniforms['u_renderthreshold'].value = volconfig.isothreshold; // For ISO renderstyle - material.uniforms['u_cmdata'].value = cmtextures[volconfig.colormap]; - - render(); -} - -function onWindowResize() { - renderer.setSize(window.innerWidth, window.innerHeight); - - const aspect = window.innerWidth / window.innerHeight; - - const frustumHeight = camera.top - camera.bottom; - - camera.left = (-frustumHeight * aspect) / 2; - camera.right = (frustumHeight * aspect) / 2; - - camera.updateProjectionMatrix(); - - render(); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts b/examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts deleted file mode 100644 index 026813023..000000000 --- a/examples-testing/examples/webgl2_materials_texture3d_partialupdate.ts +++ /dev/null @@ -1,333 +0,0 @@ -import * as THREE from 'three'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { ImprovedNoise } from 'three/addons/math/ImprovedNoise.js'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import WebGL from 'three/addons/capabilities/WebGL.js'; - -if (WebGL.isWebGL2Available() === false) { - document.body.appendChild(WebGL.getWebGL2ErrorMessage()); -} - -const INITIAL_CLOUD_SIZE = 128; - -let renderer, scene, camera; -let mesh; -let prevTime = performance.now(); -let cloudTexture = null; - -init(); -animate(); - -function generateCloudTexture(size, scaleFactor = 1.0) { - const data = new Uint8Array(size * size * size); - const scale = (scaleFactor * 10.0) / size; - - let i = 0; - const perlin = new ImprovedNoise(); - const vector = new THREE.Vector3(); - - for (let z = 0; z < size; z++) { - for (let y = 0; y < size; y++) { - for (let x = 0; x < size; x++) { - const dist = vector - .set(x, y, z) - .subScalar(size / 2) - .divideScalar(size) - .length(); - const fadingFactor = (1.0 - dist) * (1.0 - dist); - data[i] = (128 + 128 * perlin.noise((x * scale) / 1.5, y * scale, (z * scale) / 1.5)) * fadingFactor; - - i++; - } - } - } - - return new THREE.Data3DTexture(data, size, size, size); -} - -function init() { - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(0, 0, 1.5); - - new OrbitControls(camera, renderer.domElement); - - // Sky - - const canvas = document.createElement('canvas'); - canvas.width = 1; - canvas.height = 32; - - const context = canvas.getContext('2d'); - const gradient = context.createLinearGradient(0, 0, 0, 32); - gradient.addColorStop(0.0, '#014a84'); - gradient.addColorStop(0.5, '#0561a0'); - gradient.addColorStop(1.0, '#437ab6'); - context.fillStyle = gradient; - context.fillRect(0, 0, 1, 32); - - const skyMap = new THREE.CanvasTexture(canvas); - skyMap.colorSpace = THREE.SRGBColorSpace; - - const sky = new THREE.Mesh( - new THREE.SphereGeometry(10), - new THREE.MeshBasicMaterial({ map: skyMap, side: THREE.BackSide }), - ); - scene.add(sky); - - // Texture - - const texture = new THREE.Data3DTexture( - new Uint8Array(INITIAL_CLOUD_SIZE * INITIAL_CLOUD_SIZE * INITIAL_CLOUD_SIZE).fill(0), - INITIAL_CLOUD_SIZE, - INITIAL_CLOUD_SIZE, - INITIAL_CLOUD_SIZE, - ); - texture.format = THREE.RedFormat; - texture.minFilter = THREE.LinearFilter; - texture.magFilter = THREE.LinearFilter; - texture.unpackAlignment = 1; - texture.needsUpdate = true; - - cloudTexture = texture; - - // Material - - const vertexShader = /* glsl */ ` - in vec3 position; - - uniform mat4 modelMatrix; - uniform mat4 modelViewMatrix; - uniform mat4 projectionMatrix; - uniform vec3 cameraPos; - - out vec3 vOrigin; - out vec3 vDirection; - - void main() { - vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); - - vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz; - vDirection = position - vOrigin; - - gl_Position = projectionMatrix * mvPosition; - } - `; - - const fragmentShader = /* glsl */ ` - precision highp float; - precision highp sampler3D; - - uniform mat4 modelViewMatrix; - uniform mat4 projectionMatrix; - - in vec3 vOrigin; - in vec3 vDirection; - - out vec4 color; - - uniform vec3 base; - uniform sampler3D map; - - uniform float threshold; - uniform float range; - uniform float opacity; - uniform float steps; - uniform float frame; - - uint wang_hash(uint seed) - { - seed = (seed ^ 61u) ^ (seed >> 16u); - seed *= 9u; - seed = seed ^ (seed >> 4u); - seed *= 0x27d4eb2du; - seed = seed ^ (seed >> 15u); - return seed; - } - - float randomFloat(inout uint seed) - { - return float(wang_hash(seed)) / 4294967296.; - } - - vec2 hitBox( vec3 orig, vec3 dir ) { - const vec3 box_min = vec3( - 0.5 ); - const vec3 box_max = vec3( 0.5 ); - vec3 inv_dir = 1.0 / dir; - vec3 tmin_tmp = ( box_min - orig ) * inv_dir; - vec3 tmax_tmp = ( box_max - orig ) * inv_dir; - vec3 tmin = min( tmin_tmp, tmax_tmp ); - vec3 tmax = max( tmin_tmp, tmax_tmp ); - float t0 = max( tmin.x, max( tmin.y, tmin.z ) ); - float t1 = min( tmax.x, min( tmax.y, tmax.z ) ); - return vec2( t0, t1 ); - } - - float sample1( vec3 p ) { - return texture( map, p ).r; - } - - float shading( vec3 coord ) { - float step = 0.01; - return sample1( coord + vec3( - step ) ) - sample1( coord + vec3( step ) ); - } - - vec4 linearToSRGB( in vec4 value ) { - return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); - } - - void main(){ - vec3 rayDir = normalize( vDirection ); - vec2 bounds = hitBox( vOrigin, rayDir ); - - if ( bounds.x > bounds.y ) discard; - - bounds.x = max( bounds.x, 0.0 ); - - vec3 p = vOrigin + bounds.x * rayDir; - vec3 inc = 1.0 / abs( rayDir ); - float delta = min( inc.x, min( inc.y, inc.z ) ); - delta /= steps; - - // Jitter - - // Nice little seed from - // https://blog.demofox.org/2020/05/25/casual-shadertoy-path-tracing-1-basic-camera-diffuse-emissive/ - uint seed = uint( gl_FragCoord.x ) * uint( 1973 ) + uint( gl_FragCoord.y ) * uint( 9277 ) + uint( frame ) * uint( 26699 ); - vec3 size = vec3( textureSize( map, 0 ) ); - float randNum = randomFloat( seed ) * 2.0 - 1.0; - p += rayDir * randNum * ( 1.0 / size ); - - // - - vec4 ac = vec4( base, 0.0 ); - - for ( float t = bounds.x; t < bounds.y; t += delta ) { - - float d = sample1( p + 0.5 ); - - d = smoothstep( threshold - range, threshold + range, d ) * opacity; - - float col = shading( p + 0.5 ) * 3.0 + ( ( p.x + p.y ) * 0.25 ) + 0.2; - - ac.rgb += ( 1.0 - ac.a ) * d * col; - - ac.a += ( 1.0 - ac.a ) * d; - - if ( ac.a >= 0.95 ) break; - - p += rayDir * delta; - - } - - color = linearToSRGB( ac ); - - if ( color.a == 0.0 ) discard; - - } - `; - - const geometry = new THREE.BoxGeometry(1, 1, 1); - const material = new THREE.RawShaderMaterial({ - glslVersion: THREE.GLSL3, - uniforms: { - base: { value: new THREE.Color(0x798aa0) }, - map: { value: texture }, - cameraPos: { value: new THREE.Vector3() }, - threshold: { value: 0.25 }, - opacity: { value: 0.25 }, - range: { value: 0.1 }, - steps: { value: 100 }, - frame: { value: 0 }, - }, - vertexShader, - fragmentShader, - side: THREE.BackSide, - transparent: true, - }); - - mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // - - const parameters = { - threshold: 0.25, - opacity: 0.25, - range: 0.1, - steps: 100, - }; - - function update() { - material.uniforms.threshold.value = parameters.threshold; - material.uniforms.opacity.value = parameters.opacity; - material.uniforms.range.value = parameters.range; - material.uniforms.steps.value = parameters.steps; - } - - const gui = new GUI(); - gui.add(parameters, 'threshold', 0, 1, 0.01).onChange(update); - gui.add(parameters, 'opacity', 0, 1, 0.01).onChange(update); - gui.add(parameters, 'range', 0, 1, 0.01).onChange(update); - gui.add(parameters, 'steps', 0, 200, 1).onChange(update); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -let curr = 0; -const countPerRow = 4; -const countPerSlice = countPerRow * countPerRow; -const sliceCount = 4; -const totalCount = sliceCount * countPerSlice; -const margins = 8; - -const perElementPaddedSize = (INITIAL_CLOUD_SIZE - margins) / countPerRow; -const perElementSize = Math.floor((INITIAL_CLOUD_SIZE - 1) / countPerRow); - -function animate() { - requestAnimationFrame(animate); - - const time = performance.now(); - if (time - prevTime > 1500.0 && curr < totalCount) { - const position = new THREE.Vector3( - Math.floor(curr % countPerRow) * perElementSize + margins * 0.5, - Math.floor((curr % countPerSlice) / countPerRow) * perElementSize + margins * 0.5, - Math.floor(curr / countPerSlice) * perElementSize + margins * 0.5, - ).floor(); - - const maxDimension = perElementPaddedSize - 1; - const box = new THREE.Box3( - new THREE.Vector3(0, 0, 0), - new THREE.Vector3(maxDimension, maxDimension, maxDimension), - ); - const scaleFactor = (Math.random() + 0.5) * 0.5; - const source = generateCloudTexture(perElementPaddedSize, scaleFactor); - - renderer.copyTextureToTexture3D(box, position, source, cloudTexture); - - prevTime = time; - - curr++; - } - - mesh.material.uniforms.cameraPos.value.copy(camera.position); - // mesh.rotation.y = - performance.now() / 7500; - - mesh.material.uniforms.frame.value++; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl2_multiple_rendertargets.ts b/examples-testing/examples/webgl2_multiple_rendertargets.ts deleted file mode 100644 index cc1082731..000000000 --- a/examples-testing/examples/webgl2_multiple_rendertargets.ts +++ /dev/null @@ -1,139 +0,0 @@ -import * as THREE from 'three'; - -import WebGL from 'three/addons/capabilities/WebGL.js'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let camera, scene, renderer, controls; -let renderTarget; -let postScene, postCamera; - -const parameters = { - samples: 4, - wireframe: false, -}; - -const gui = new GUI(); -gui.add(parameters, 'samples', 0, 4).step(1); -gui.add(parameters, 'wireframe'); -gui.onChange(render); - -init(); - -function init() { - if (WebGL.isWebGL2Available() === false) { - document.body.appendChild(WebGL.getWebGL2ErrorMessage()); - return; - } - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - // Create a multi render target with Float buffers - - renderTarget = new THREE.WebGLMultipleRenderTargets( - window.innerWidth * window.devicePixelRatio, - window.innerHeight * window.devicePixelRatio, - 2, - ); - - for (let i = 0, il = renderTarget.texture.length; i < il; i++) { - renderTarget.texture[i].minFilter = THREE.NearestFilter; - renderTarget.texture[i].magFilter = THREE.NearestFilter; - } - - // Name our G-Buffer attachments for debugging - - renderTarget.texture[0].name = 'diffuse'; - renderTarget.texture[1].name = 'normal'; - - // Scene setup - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x222222); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 50); - camera.position.z = 4; - - const loader = new THREE.TextureLoader(); - - const diffuse = loader.load('textures/hardwood2_diffuse.jpg', render); - diffuse.wrapS = THREE.RepeatWrapping; - diffuse.wrapT = THREE.RepeatWrapping; - diffuse.colorSpace = THREE.SRGBColorSpace; - - scene.add( - new THREE.Mesh( - new THREE.TorusKnotGeometry(1, 0.3, 128, 32), - new THREE.RawShaderMaterial({ - vertexShader: document.querySelector('#gbuffer-vert').textContent.trim(), - fragmentShader: document.querySelector('#gbuffer-frag').textContent.trim(), - uniforms: { - tDiffuse: { value: diffuse }, - repeat: { value: new THREE.Vector2(5, 0.5) }, - }, - glslVersion: THREE.GLSL3, - }), - ), - ); - - // PostProcessing setup - - postScene = new THREE.Scene(); - postCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); - - postScene.add( - new THREE.Mesh( - new THREE.PlaneGeometry(2, 2), - new THREE.RawShaderMaterial({ - vertexShader: document.querySelector('#render-vert').textContent.trim(), - fragmentShader: document.querySelector('#render-frag').textContent.trim(), - uniforms: { - tDiffuse: { value: renderTarget.texture[0] }, - tNormal: { value: renderTarget.texture[1] }, - }, - glslVersion: THREE.GLSL3, - }), - ), - ); - - // Controls - - controls = new OrbitControls(camera, renderer.domElement); - controls.addEventListener('change', render); - //controls.enableZoom = false; - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - const dpr = renderer.getPixelRatio(); - renderTarget.setSize(window.innerWidth * dpr, window.innerHeight * dpr); - - render(); -} - -function render() { - renderTarget.samples = parameters.samples; - - scene.traverse(function (child) { - if (child.material !== undefined) { - child.material.wireframe = parameters.wireframe; - } - }); - - // render scene into target - renderer.setRenderTarget(renderTarget); - renderer.render(scene, camera); - - // render post FX - renderer.setRenderTarget(null); - renderer.render(postScene, postCamera); -} diff --git a/examples-testing/examples/webgl2_multisampled_renderbuffers.ts b/examples-testing/examples/webgl2_multisampled_renderbuffers.ts deleted file mode 100644 index c3197be2a..000000000 --- a/examples-testing/examples/webgl2_multisampled_renderbuffers.ts +++ /dev/null @@ -1,139 +0,0 @@ -import * as THREE from 'three'; - -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; -import WebGL from 'three/addons/capabilities/WebGL.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let camera, renderer, group, container; - -let composer1, composer2; - -const params = { - animate: true, -}; - -init(); - -function init() { - if (WebGL.isWebGL2Available() === false) { - document.body.appendChild(WebGL.getWebGL2ErrorMessage()); - return; - } - - container = document.getElementById('container'); - - camera = new THREE.PerspectiveCamera(45, container.offsetWidth / container.offsetHeight, 10, 2000); - camera.position.z = 500; - - const scene = new THREE.Scene(); - scene.background = new THREE.Color(0xffffff); - scene.fog = new THREE.Fog(0xcccccc, 100, 1500); - - // - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x222222, 5); - hemiLight.position.set(1, 1, 1); - scene.add(hemiLight); - - // - - group = new THREE.Group(); - - const geometry = new THREE.SphereGeometry(10, 64, 40); - const material = new THREE.MeshLambertMaterial({ - color: 0xee0808, - polygonOffset: true, - polygonOffsetFactor: 1, // positive value pushes polygon further away - polygonOffsetUnits: 1, - }); - const material2 = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }); - - for (let i = 0; i < 50; i++) { - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = Math.random() * 600 - 300; - mesh.position.y = Math.random() * 600 - 300; - mesh.position.z = Math.random() * 600 - 300; - mesh.rotation.x = Math.random(); - mesh.rotation.z = Math.random(); - mesh.scale.setScalar(Math.random() * 5 + 5); - group.add(mesh); - - const mesh2 = new THREE.Mesh(geometry, material2); - mesh2.position.copy(mesh.position); - mesh2.rotation.copy(mesh.rotation); - mesh2.scale.copy(mesh.scale); - group.add(mesh2); - } - - scene.add(group); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(container.offsetWidth, container.offsetHeight); - renderer.autoClear = false; - container.appendChild(renderer.domElement); - - // - - const size = renderer.getDrawingBufferSize(new THREE.Vector2()); - const renderTarget = new THREE.WebGLRenderTarget(size.width, size.height, { samples: 4 }); - - const renderPass = new RenderPass(scene, camera); - const outputPass = new OutputPass(); - - // - - composer1 = new EffectComposer(renderer); - composer1.addPass(renderPass); - composer1.addPass(outputPass); - - // - - composer2 = new EffectComposer(renderer, renderTarget); - composer2.addPass(renderPass); - composer2.addPass(outputPass); - - // - - const gui = new GUI(); - gui.add(params, 'animate'); - - // - - window.addEventListener('resize', onWindowResize); - - animate(); -} - -function onWindowResize() { - camera.aspect = container.offsetWidth / container.offsetHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(container.offsetWidth, container.offsetHeight); - composer1.setSize(container.offsetWidth, container.offsetHeight); - composer2.setSize(container.offsetWidth, container.offsetHeight); -} - -function animate() { - requestAnimationFrame(animate); - - const halfWidth = container.offsetWidth / 2; - - if (params.animate) { - group.rotation.y += 0.002; - } - - renderer.setScissorTest(true); - - renderer.setScissor(0, 0, halfWidth - 1, container.offsetHeight); - composer1.render(); - - renderer.setScissor(halfWidth, 0, halfWidth, container.offsetHeight); - composer2.render(); - - renderer.setScissorTest(false); -} diff --git a/examples-testing/examples/webgl2_texture2darray_compressed.ts b/examples-testing/examples/webgl2_texture2darray_compressed.ts deleted file mode 100644 index bf86320c0..000000000 --- a/examples-testing/examples/webgl2_texture2darray_compressed.ts +++ /dev/null @@ -1,96 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'; - -import WebGL from 'three/addons/capabilities/WebGL.js'; - -if (WebGL.isWebGL2Available() === false) { - document.body.appendChild(WebGL.getWebGL2ErrorMessage()); -} - -let camera, scene, mesh, renderer, stats, clock; - -const planeWidth = 50; -const planeHeight = 25; - -let depthStep = 1; - -init(); -animate(); - -function init() { - const container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000); - camera.position.z = 70; - - scene = new THREE.Scene(); - - // - clock = new THREE.Clock(); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - // - - const ktx2Loader = new KTX2Loader(); - ktx2Loader.setTranscoderPath('jsm/libs/basis/'); - ktx2Loader.detectSupport(renderer); - - ktx2Loader.load('textures/spiritedaway.ktx2', function (texturearray) { - const material = new THREE.ShaderMaterial({ - uniforms: { - diffuse: { value: texturearray }, - depth: { value: 55 }, - size: { value: new THREE.Vector2(planeWidth, planeHeight) }, - }, - vertexShader: document.getElementById('vs').textContent.trim(), - fragmentShader: document.getElementById('fs').textContent.trim(), - glslVersion: THREE.GLSL3, - }); - - const geometry = new THREE.PlaneGeometry(planeWidth, planeHeight); - - mesh = new THREE.Mesh(geometry, material); - - scene.add(mesh); - }); - - stats = new Stats(); - container.appendChild(stats.dom); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - if (mesh) { - const delta = clock.getDelta() * 10; - - depthStep += delta; - - const value = depthStep % 5; - - mesh.material.uniforms['depth'].value = value; - } - - render(); - stats.update(); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl2_ubo.ts b/examples-testing/examples/webgl2_ubo.ts deleted file mode 100644 index e296fdced..000000000 --- a/examples-testing/examples/webgl2_ubo.ts +++ /dev/null @@ -1,146 +0,0 @@ -import * as THREE from 'three'; - -import WebGL from 'three/addons/capabilities/WebGL.js'; - -let camera, scene, renderer, clock; - -init(); -animate(); - -function init() { - if (WebGL.isWebGL2Available() === false) { - document.body.appendChild(WebGL.getWebGL2ErrorMessage()); - return; - } - - const container = document.getElementById('container'); - - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(0, 0, 25); - - scene = new THREE.Scene(); - camera.lookAt(scene.position); - - clock = new THREE.Clock(); - - // geometry - - const geometry1 = new THREE.TetrahedronGeometry(); - const geometry2 = new THREE.BoxGeometry(); - - // texture - - const texture = new THREE.TextureLoader().load('textures/crate.gif'); - texture.colorSpace = THREE.SRGBColorSpace; - - // uniforms groups - - // Camera and lighting related data are perfect examples of using UBOs since you have to store these - // data just once. They can be shared across all shader programs. - - const cameraUniformsGroup = new THREE.UniformsGroup(); - cameraUniformsGroup.setName('ViewData'); - cameraUniformsGroup.add(new THREE.Uniform(camera.projectionMatrix)); // projection matrix - cameraUniformsGroup.add(new THREE.Uniform(camera.matrixWorldInverse)); // view matrix - - const lightingUniformsGroup = new THREE.UniformsGroup(); - lightingUniformsGroup.setName('LightingData'); - lightingUniformsGroup.add(new THREE.Uniform(new THREE.Vector3(0, 0, 10))); // light position - lightingUniformsGroup.add(new THREE.Uniform(new THREE.Color(0x7c7c7c))); // ambient color - lightingUniformsGroup.add(new THREE.Uniform(new THREE.Color(0xd5d5d5))); // diffuse color - lightingUniformsGroup.add(new THREE.Uniform(new THREE.Color(0xe7e7e7))); // specular color - lightingUniformsGroup.add(new THREE.Uniform(64)); // shininess - - // materials - - const material1 = new THREE.RawShaderMaterial({ - uniforms: { - modelMatrix: { value: null }, - normalMatrix: { value: null }, - color: { value: null }, - }, - vertexShader: document.getElementById('vertexShader1').textContent, - fragmentShader: document.getElementById('fragmentShader1').textContent, - glslVersion: THREE.GLSL3, - }); - - const material2 = new THREE.RawShaderMaterial({ - uniforms: { - modelMatrix: { value: null }, - diffuseMap: { value: null }, - }, - vertexShader: document.getElementById('vertexShader2').textContent, - fragmentShader: document.getElementById('fragmentShader2').textContent, - glslVersion: THREE.GLSL3, - }); - - // meshes - - for (let i = 0; i < 200; i++) { - let mesh; - - if (i % 2 === 0) { - mesh = new THREE.Mesh(geometry1, material1.clone()); - - mesh.material.uniformsGroups = [cameraUniformsGroup, lightingUniformsGroup]; - mesh.material.uniforms.modelMatrix.value = mesh.matrixWorld; - mesh.material.uniforms.normalMatrix.value = mesh.normalMatrix; - mesh.material.uniforms.color.value = new THREE.Color(0xffffff * Math.random()); - } else { - mesh = new THREE.Mesh(geometry2, material2.clone()); - - mesh.material.uniformsGroups = [cameraUniformsGroup, lightingUniformsGroup]; - mesh.material.uniforms.modelMatrix.value = mesh.matrixWorld; - mesh.material.uniforms.diffuseMap.value = texture; - } - - scene.add(mesh); - - const s = 1 + Math.random() * 0.5; - - mesh.scale.x = s; - mesh.scale.y = s; - mesh.scale.z = s; - - mesh.rotation.x = Math.random() * Math.PI; - mesh.rotation.y = Math.random() * Math.PI; - mesh.rotation.z = Math.random() * Math.PI; - - mesh.position.x = Math.random() * 40 - 20; - mesh.position.y = Math.random() * 40 - 20; - mesh.position.z = Math.random() * 20 - 10; - } - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - window.addEventListener('resize', onWindowResize, false); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - const delta = clock.getDelta(); - - scene.traverse(function (child) { - if (child.isMesh) { - child.rotation.x += delta * 0.5; - child.rotation.y += delta * 0.3; - } - }); - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl2_volume_cloud.ts b/examples-testing/examples/webgl2_volume_cloud.ts deleted file mode 100644 index bc5473299..000000000 --- a/examples-testing/examples/webgl2_volume_cloud.ts +++ /dev/null @@ -1,286 +0,0 @@ -import * as THREE from 'three'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { ImprovedNoise } from 'three/addons/math/ImprovedNoise.js'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import WebGL from 'three/addons/capabilities/WebGL.js'; - -if (WebGL.isWebGL2Available() === false) { - document.body.appendChild(WebGL.getWebGL2ErrorMessage()); -} - -let renderer, scene, camera; -let mesh; - -init(); -animate(); - -function init() { - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(0, 0, 1.5); - - new OrbitControls(camera, renderer.domElement); - - // Sky - - const canvas = document.createElement('canvas'); - canvas.width = 1; - canvas.height = 32; - - const context = canvas.getContext('2d'); - const gradient = context.createLinearGradient(0, 0, 0, 32); - gradient.addColorStop(0.0, '#014a84'); - gradient.addColorStop(0.5, '#0561a0'); - gradient.addColorStop(1.0, '#437ab6'); - context.fillStyle = gradient; - context.fillRect(0, 0, 1, 32); - - const skyMap = new THREE.CanvasTexture(canvas); - skyMap.colorSpace = THREE.SRGBColorSpace; - - const sky = new THREE.Mesh( - new THREE.SphereGeometry(10), - new THREE.MeshBasicMaterial({ map: skyMap, side: THREE.BackSide }), - ); - scene.add(sky); - - // Texture - - const size = 128; - const data = new Uint8Array(size * size * size); - - let i = 0; - const scale = 0.05; - const perlin = new ImprovedNoise(); - const vector = new THREE.Vector3(); - - for (let z = 0; z < size; z++) { - for (let y = 0; y < size; y++) { - for (let x = 0; x < size; x++) { - const d = - 1.0 - - vector - .set(x, y, z) - .subScalar(size / 2) - .divideScalar(size) - .length(); - data[i] = (128 + 128 * perlin.noise((x * scale) / 1.5, y * scale, (z * scale) / 1.5)) * d * d; - i++; - } - } - } - - const texture = new THREE.Data3DTexture(data, size, size, size); - texture.format = THREE.RedFormat; - texture.minFilter = THREE.LinearFilter; - texture.magFilter = THREE.LinearFilter; - texture.unpackAlignment = 1; - texture.needsUpdate = true; - - // Material - - const vertexShader = /* glsl */ ` - in vec3 position; - - uniform mat4 modelMatrix; - uniform mat4 modelViewMatrix; - uniform mat4 projectionMatrix; - uniform vec3 cameraPos; - - out vec3 vOrigin; - out vec3 vDirection; - - void main() { - vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); - - vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz; - vDirection = position - vOrigin; - - gl_Position = projectionMatrix * mvPosition; - } - `; - - const fragmentShader = /* glsl */ ` - precision highp float; - precision highp sampler3D; - - uniform mat4 modelViewMatrix; - uniform mat4 projectionMatrix; - - in vec3 vOrigin; - in vec3 vDirection; - - out vec4 color; - - uniform vec3 base; - uniform sampler3D map; - - uniform float threshold; - uniform float range; - uniform float opacity; - uniform float steps; - uniform float frame; - - uint wang_hash(uint seed) - { - seed = (seed ^ 61u) ^ (seed >> 16u); - seed *= 9u; - seed = seed ^ (seed >> 4u); - seed *= 0x27d4eb2du; - seed = seed ^ (seed >> 15u); - return seed; - } - - float randomFloat(inout uint seed) - { - return float(wang_hash(seed)) / 4294967296.; - } - - vec2 hitBox( vec3 orig, vec3 dir ) { - const vec3 box_min = vec3( - 0.5 ); - const vec3 box_max = vec3( 0.5 ); - vec3 inv_dir = 1.0 / dir; - vec3 tmin_tmp = ( box_min - orig ) * inv_dir; - vec3 tmax_tmp = ( box_max - orig ) * inv_dir; - vec3 tmin = min( tmin_tmp, tmax_tmp ); - vec3 tmax = max( tmin_tmp, tmax_tmp ); - float t0 = max( tmin.x, max( tmin.y, tmin.z ) ); - float t1 = min( tmax.x, min( tmax.y, tmax.z ) ); - return vec2( t0, t1 ); - } - - float sample1( vec3 p ) { - return texture( map, p ).r; - } - - float shading( vec3 coord ) { - float step = 0.01; - return sample1( coord + vec3( - step ) ) - sample1( coord + vec3( step ) ); - } - - vec4 linearToSRGB( in vec4 value ) { - return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); - } - - void main(){ - vec3 rayDir = normalize( vDirection ); - vec2 bounds = hitBox( vOrigin, rayDir ); - - if ( bounds.x > bounds.y ) discard; - - bounds.x = max( bounds.x, 0.0 ); - - vec3 p = vOrigin + bounds.x * rayDir; - vec3 inc = 1.0 / abs( rayDir ); - float delta = min( inc.x, min( inc.y, inc.z ) ); - delta /= steps; - - // Jitter - - // Nice little seed from - // https://blog.demofox.org/2020/05/25/casual-shadertoy-path-tracing-1-basic-camera-diffuse-emissive/ - uint seed = uint( gl_FragCoord.x ) * uint( 1973 ) + uint( gl_FragCoord.y ) * uint( 9277 ) + uint( frame ) * uint( 26699 ); - vec3 size = vec3( textureSize( map, 0 ) ); - float randNum = randomFloat( seed ) * 2.0 - 1.0; - p += rayDir * randNum * ( 1.0 / size ); - - // - - vec4 ac = vec4( base, 0.0 ); - - for ( float t = bounds.x; t < bounds.y; t += delta ) { - - float d = sample1( p + 0.5 ); - - d = smoothstep( threshold - range, threshold + range, d ) * opacity; - - float col = shading( p + 0.5 ) * 3.0 + ( ( p.x + p.y ) * 0.25 ) + 0.2; - - ac.rgb += ( 1.0 - ac.a ) * d * col; - - ac.a += ( 1.0 - ac.a ) * d; - - if ( ac.a >= 0.95 ) break; - - p += rayDir * delta; - - } - - color = linearToSRGB( ac ); - - if ( color.a == 0.0 ) discard; - - } - `; - - const geometry = new THREE.BoxGeometry(1, 1, 1); - const material = new THREE.RawShaderMaterial({ - glslVersion: THREE.GLSL3, - uniforms: { - base: { value: new THREE.Color(0x798aa0) }, - map: { value: texture }, - cameraPos: { value: new THREE.Vector3() }, - threshold: { value: 0.25 }, - opacity: { value: 0.25 }, - range: { value: 0.1 }, - steps: { value: 100 }, - frame: { value: 0 }, - }, - vertexShader, - fragmentShader, - side: THREE.BackSide, - transparent: true, - }); - - mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // - - const parameters = { - threshold: 0.25, - opacity: 0.25, - range: 0.1, - steps: 100, - }; - - function update() { - material.uniforms.threshold.value = parameters.threshold; - material.uniforms.opacity.value = parameters.opacity; - material.uniforms.range.value = parameters.range; - material.uniforms.steps.value = parameters.steps; - } - - const gui = new GUI(); - gui.add(parameters, 'threshold', 0, 1, 0.01).onChange(update); - gui.add(parameters, 'opacity', 0, 1, 0.01).onChange(update); - gui.add(parameters, 'range', 0, 1, 0.01).onChange(update); - gui.add(parameters, 'steps', 0, 200, 1).onChange(update); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - mesh.material.uniforms.cameraPos.value.copy(camera.position); - mesh.rotation.y = -performance.now() / 7500; - - mesh.material.uniforms.frame.value++; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl2_volume_instancing.ts b/examples-testing/examples/webgl2_volume_instancing.ts deleted file mode 100644 index 89328698d..000000000 --- a/examples-testing/examples/webgl2_volume_instancing.ts +++ /dev/null @@ -1,198 +0,0 @@ -import * as THREE from 'three'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { VOXLoader, VOXData3DTexture } from 'three/addons/loaders/VOXLoader.js'; - -import WebGL from 'three/addons/capabilities/WebGL.js'; - -if (WebGL.isWebGL2Available() === false) { - document.body.appendChild(WebGL.getWebGL2ErrorMessage()); -} - -let renderer, scene, camera; -let controls; - -init(); -animate(); - -function init() { - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000); - camera.position.set(0, 0, 4); - - controls = new OrbitControls(camera, renderer.domElement); - controls.autoRotate = true; - controls.autoRotateSpeed = -1.0; - controls.enableDamping = true; - - // Material - - const vertexShader = /* glsl */ ` - in vec3 position; - in mat4 instanceMatrix; - - uniform mat4 modelMatrix; - uniform mat4 modelViewMatrix; - uniform mat4 projectionMatrix; - uniform vec3 cameraPos; - - out vec3 vOrigin; - out vec3 vDirection; - - void main() { - vec4 mvPosition = modelViewMatrix * instanceMatrix * vec4( position, 1.0 ); - - vOrigin = vec3( inverse( instanceMatrix * modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz; - vDirection = position - vOrigin; - - gl_Position = projectionMatrix * mvPosition; - } - `; - - const fragmentShader = /* glsl */ ` - precision highp float; - precision highp sampler3D; - - uniform mat4 modelViewMatrix; - uniform mat4 projectionMatrix; - - in vec3 vOrigin; - in vec3 vDirection; - - out vec4 color; - - uniform sampler3D map; - - uniform float threshold; - uniform float steps; - - vec2 hitBox( vec3 orig, vec3 dir ) { - const vec3 box_min = vec3( - 0.5 ); - const vec3 box_max = vec3( 0.5 ); - vec3 inv_dir = 1.0 / dir; - vec3 tmin_tmp = ( box_min - orig ) * inv_dir; - vec3 tmax_tmp = ( box_max - orig ) * inv_dir; - vec3 tmin = min( tmin_tmp, tmax_tmp ); - vec3 tmax = max( tmin_tmp, tmax_tmp ); - float t0 = max( tmin.x, max( tmin.y, tmin.z ) ); - float t1 = min( tmax.x, min( tmax.y, tmax.z ) ); - return vec2( t0, t1 ); - } - - float sample1( vec3 p ) { - return texture( map, p ).r; - } - - #define epsilon .0001 - - vec3 normal( vec3 coord ) { - if ( coord.x < epsilon ) return vec3( 1.0, 0.0, 0.0 ); - if ( coord.y < epsilon ) return vec3( 0.0, 1.0, 0.0 ); - if ( coord.z < epsilon ) return vec3( 0.0, 0.0, 1.0 ); - if ( coord.x > 1.0 - epsilon ) return vec3( - 1.0, 0.0, 0.0 ); - if ( coord.y > 1.0 - epsilon ) return vec3( 0.0, - 1.0, 0.0 ); - if ( coord.z > 1.0 - epsilon ) return vec3( 0.0, 0.0, - 1.0 ); - - float step = 0.01; - float x = sample1( coord + vec3( - step, 0.0, 0.0 ) ) - sample1( coord + vec3( step, 0.0, 0.0 ) ); - float y = sample1( coord + vec3( 0.0, - step, 0.0 ) ) - sample1( coord + vec3( 0.0, step, 0.0 ) ); - float z = sample1( coord + vec3( 0.0, 0.0, - step ) ) - sample1( coord + vec3( 0.0, 0.0, step ) ); - - return normalize( vec3( x, y, z ) ); - } - - void main(){ - - vec3 rayDir = normalize( vDirection ); - vec2 bounds = hitBox( vOrigin, rayDir ); - - if ( bounds.x > bounds.y ) discard; - - bounds.x = max( bounds.x, 0.0 ); - - vec3 p = vOrigin + bounds.x * rayDir; - vec3 inc = 1.0 / abs( rayDir ); - float delta = min( inc.x, min( inc.y, inc.z ) ); - delta /= 50.0; - - for ( float t = bounds.x; t < bounds.y; t += delta ) { - - float d = sample1( p + 0.5 ); - - if ( d > 0.5 ) { - - color.rgb = p * 2.0; // normal( p + 0.5 ); // * 0.5 + ( p * 1.5 + 0.25 ); - color.a = 1.; - break; - - } - - p += rayDir * delta; - - } - - if ( color.a == 0.0 ) discard; - - } - `; - - const loader = new VOXLoader(); - loader.load('models/vox/menger.vox', function (chunks) { - for (let i = 0; i < chunks.length; i++) { - const chunk = chunks[i]; - - const geometry = new THREE.BoxGeometry(1, 1, 1); - const material = new THREE.RawShaderMaterial({ - glslVersion: THREE.GLSL3, - uniforms: { - map: { value: new VOXData3DTexture(chunk) }, - cameraPos: { value: new THREE.Vector3() }, - }, - vertexShader, - fragmentShader, - side: THREE.BackSide, - }); - - const mesh = new THREE.InstancedMesh(geometry, material, 50000); - mesh.onBeforeRender = function () { - this.material.uniforms.cameraPos.value.copy(camera.position); - }; - - const transform = new THREE.Object3D(); - - for (let i = 0; i < mesh.count; i++) { - transform.position.random().subScalar(0.5).multiplyScalar(150); - transform.rotation.x = Math.random() * Math.PI; - transform.rotation.y = Math.random() * Math.PI; - transform.rotation.z = Math.random() * Math.PI; - transform.updateMatrix(); - - mesh.setMatrixAt(i, transform.matrix); - } - - scene.add(mesh); - } - }); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - controls.update(); - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl2_volume_perlin.ts b/examples-testing/examples/webgl2_volume_perlin.ts deleted file mode 100644 index a75328f92..000000000 --- a/examples-testing/examples/webgl2_volume_perlin.ts +++ /dev/null @@ -1,215 +0,0 @@ -import * as THREE from 'three'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { ImprovedNoise } from 'three/addons/math/ImprovedNoise.js'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import WebGL from 'three/addons/capabilities/WebGL.js'; - -if (WebGL.isWebGL2Available() === false) { - document.body.appendChild(WebGL.getWebGL2ErrorMessage()); -} - -let renderer, scene, camera; -let mesh; - -init(); -animate(); - -function init() { - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(0, 0, 2); - - new OrbitControls(camera, renderer.domElement); - - // Texture - - const size = 128; - const data = new Uint8Array(size * size * size); - - let i = 0; - const perlin = new ImprovedNoise(); - const vector = new THREE.Vector3(); - - for (let z = 0; z < size; z++) { - for (let y = 0; y < size; y++) { - for (let x = 0; x < size; x++) { - vector.set(x, y, z).divideScalar(size); - - const d = perlin.noise(vector.x * 6.5, vector.y * 6.5, vector.z * 6.5); - - data[i++] = d * 128 + 128; - } - } - } - - const texture = new THREE.Data3DTexture(data, size, size, size); - texture.format = THREE.RedFormat; - texture.minFilter = THREE.LinearFilter; - texture.magFilter = THREE.LinearFilter; - texture.unpackAlignment = 1; - texture.needsUpdate = true; - - // Material - - const vertexShader = /* glsl */ ` - in vec3 position; - - uniform mat4 modelMatrix; - uniform mat4 modelViewMatrix; - uniform mat4 projectionMatrix; - uniform vec3 cameraPos; - - out vec3 vOrigin; - out vec3 vDirection; - - void main() { - vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); - - vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz; - vDirection = position - vOrigin; - - gl_Position = projectionMatrix * mvPosition; - } - `; - - const fragmentShader = /* glsl */ ` - precision highp float; - precision highp sampler3D; - - uniform mat4 modelViewMatrix; - uniform mat4 projectionMatrix; - - in vec3 vOrigin; - in vec3 vDirection; - - out vec4 color; - - uniform sampler3D map; - - uniform float threshold; - uniform float steps; - - vec2 hitBox( vec3 orig, vec3 dir ) { - const vec3 box_min = vec3( - 0.5 ); - const vec3 box_max = vec3( 0.5 ); - vec3 inv_dir = 1.0 / dir; - vec3 tmin_tmp = ( box_min - orig ) * inv_dir; - vec3 tmax_tmp = ( box_max - orig ) * inv_dir; - vec3 tmin = min( tmin_tmp, tmax_tmp ); - vec3 tmax = max( tmin_tmp, tmax_tmp ); - float t0 = max( tmin.x, max( tmin.y, tmin.z ) ); - float t1 = min( tmax.x, min( tmax.y, tmax.z ) ); - return vec2( t0, t1 ); - } - - float sample1( vec3 p ) { - return texture( map, p ).r; - } - - #define epsilon .0001 - - vec3 normal( vec3 coord ) { - if ( coord.x < epsilon ) return vec3( 1.0, 0.0, 0.0 ); - if ( coord.y < epsilon ) return vec3( 0.0, 1.0, 0.0 ); - if ( coord.z < epsilon ) return vec3( 0.0, 0.0, 1.0 ); - if ( coord.x > 1.0 - epsilon ) return vec3( - 1.0, 0.0, 0.0 ); - if ( coord.y > 1.0 - epsilon ) return vec3( 0.0, - 1.0, 0.0 ); - if ( coord.z > 1.0 - epsilon ) return vec3( 0.0, 0.0, - 1.0 ); - - float step = 0.01; - float x = sample1( coord + vec3( - step, 0.0, 0.0 ) ) - sample1( coord + vec3( step, 0.0, 0.0 ) ); - float y = sample1( coord + vec3( 0.0, - step, 0.0 ) ) - sample1( coord + vec3( 0.0, step, 0.0 ) ); - float z = sample1( coord + vec3( 0.0, 0.0, - step ) ) - sample1( coord + vec3( 0.0, 0.0, step ) ); - - return normalize( vec3( x, y, z ) ); - } - - void main(){ - - vec3 rayDir = normalize( vDirection ); - vec2 bounds = hitBox( vOrigin, rayDir ); - - if ( bounds.x > bounds.y ) discard; - - bounds.x = max( bounds.x, 0.0 ); - - vec3 p = vOrigin + bounds.x * rayDir; - vec3 inc = 1.0 / abs( rayDir ); - float delta = min( inc.x, min( inc.y, inc.z ) ); - delta /= steps; - - for ( float t = bounds.x; t < bounds.y; t += delta ) { - - float d = sample1( p + 0.5 ); - - if ( d > threshold ) { - - color.rgb = normal( p + 0.5 ) * 0.5 + ( p * 1.5 + 0.25 ); - color.a = 1.; - break; - - } - - p += rayDir * delta; - - } - - if ( color.a == 0.0 ) discard; - - } - `; - - const geometry = new THREE.BoxGeometry(1, 1, 1); - const material = new THREE.RawShaderMaterial({ - glslVersion: THREE.GLSL3, - uniforms: { - map: { value: texture }, - cameraPos: { value: new THREE.Vector3() }, - threshold: { value: 0.6 }, - steps: { value: 200 }, - }, - vertexShader, - fragmentShader, - side: THREE.BackSide, - }); - - mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // - - const parameters = { threshold: 0.6, steps: 200 }; - - function update() { - material.uniforms.threshold.value = parameters.threshold; - material.uniforms.steps.value = parameters.steps; - } - - const gui = new GUI(); - gui.add(parameters, 'threshold', 0, 1, 0.01).onChange(update); - gui.add(parameters, 'steps', 0, 300, 1).onChange(update); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - mesh.material.uniforms.cameraPos.value.copy(camera.position); - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_animation_keyframes.ts b/examples-testing/examples/webgl_animation_keyframes.ts deleted file mode 100644 index 22dd961e4..000000000 --- a/examples-testing/examples/webgl_animation_keyframes.ts +++ /dev/null @@ -1,82 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js'; - -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; -import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'; - -let mixer; - -const clock = new THREE.Clock(); -const container = document.getElementById('container'); - -const stats = new Stats(); -container.appendChild(stats.dom); - -const renderer = new THREE.WebGLRenderer({ antialias: true }); -renderer.setPixelRatio(window.devicePixelRatio); -renderer.setSize(window.innerWidth, window.innerHeight); -container.appendChild(renderer.domElement); - -const pmremGenerator = new THREE.PMREMGenerator(renderer); - -const scene = new THREE.Scene(); -scene.background = new THREE.Color(0xbfe3dd); -scene.environment = pmremGenerator.fromScene(new RoomEnvironment(renderer), 0.04).texture; - -const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 100); -camera.position.set(5, 2, 8); - -const controls = new OrbitControls(camera, renderer.domElement); -controls.target.set(0, 0.5, 0); -controls.update(); -controls.enablePan = false; -controls.enableDamping = true; - -const dracoLoader = new DRACOLoader(); -dracoLoader.setDecoderPath('jsm/libs/draco/gltf/'); - -const loader = new GLTFLoader(); -loader.setDRACOLoader(dracoLoader); -loader.load( - 'models/gltf/LittlestTokyo.glb', - function (gltf) { - const model = gltf.scene; - model.position.set(1, 1, 0); - model.scale.set(0.01, 0.01, 0.01); - scene.add(model); - - mixer = new THREE.AnimationMixer(model); - mixer.clipAction(gltf.animations[0]).play(); - - animate(); - }, - undefined, - function (e) { - console.error(e); - }, -); - -window.onresize = function () { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -}; - -function animate() { - requestAnimationFrame(animate); - - const delta = clock.getDelta(); - - mixer.update(delta); - - controls.update(); - - stats.update(); - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_animation_multiple.ts b/examples-testing/examples/webgl_animation_multiple.ts deleted file mode 100644 index 8f9934099..000000000 --- a/examples-testing/examples/webgl_animation_multiple.ts +++ /dev/null @@ -1,104 +0,0 @@ -import * as THREE from 'three'; - -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; -import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.js'; - -let camera, scene, renderer; -let clock; - -const mixers = []; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.set(2, 3, -6); - camera.lookAt(0, 1, 0); - - clock = new THREE.Clock(); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xa0a0a0); - scene.fog = new THREE.Fog(0xa0a0a0, 10, 50); - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x8d8d8d, 3); - hemiLight.position.set(0, 20, 0); - scene.add(hemiLight); - - const dirLight = new THREE.DirectionalLight(0xffffff, 3); - dirLight.position.set(-3, 10, -10); - dirLight.castShadow = true; - dirLight.shadow.camera.top = 4; - dirLight.shadow.camera.bottom = -4; - dirLight.shadow.camera.left = -4; - dirLight.shadow.camera.right = 4; - dirLight.shadow.camera.near = 0.1; - dirLight.shadow.camera.far = 40; - scene.add(dirLight); - - // scene.add( new THREE.CameraHelper( dirLight.shadow.camera ) ); - - // ground - - const mesh = new THREE.Mesh( - new THREE.PlaneGeometry(200, 200), - new THREE.MeshPhongMaterial({ color: 0xcbcbcb, depthWrite: false }), - ); - mesh.rotation.x = -Math.PI / 2; - mesh.receiveShadow = true; - scene.add(mesh); - - const loader = new GLTFLoader(); - loader.load('models/gltf/Soldier.glb', function (gltf) { - gltf.scene.traverse(function (object) { - if (object.isMesh) object.castShadow = true; - }); - - const model1 = SkeletonUtils.clone(gltf.scene); - const model2 = SkeletonUtils.clone(gltf.scene); - const model3 = SkeletonUtils.clone(gltf.scene); - - const mixer1 = new THREE.AnimationMixer(model1); - const mixer2 = new THREE.AnimationMixer(model2); - const mixer3 = new THREE.AnimationMixer(model3); - - mixer1.clipAction(gltf.animations[0]).play(); // idle - mixer2.clipAction(gltf.animations[1]).play(); // run - mixer3.clipAction(gltf.animations[3]).play(); // walk - - model1.position.x = -2; - model2.position.x = 0; - model3.position.x = 2; - - scene.add(model1, model2, model3); - mixers.push(mixer1, mixer2, mixer3); - - animate(); - }); - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - document.body.appendChild(renderer.domElement); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - const delta = clock.getDelta(); - - for (const mixer of mixers) mixer.update(delta); - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_animation_skinning_morph.ts b/examples-testing/examples/webgl_animation_skinning_morph.ts deleted file mode 100644 index 6aa1368d4..000000000 --- a/examples-testing/examples/webgl_animation_skinning_morph.ts +++ /dev/null @@ -1,189 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; - -let container, stats, clock, gui, mixer, actions, activeAction, previousAction; -let camera, scene, renderer, model, face; - -const api = { state: 'Walking' }; - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.25, 100); - camera.position.set(-5, 3, 10); - camera.lookAt(0, 2, 0); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xe0e0e0); - scene.fog = new THREE.Fog(0xe0e0e0, 20, 100); - - clock = new THREE.Clock(); - - // lights - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x8d8d8d, 3); - hemiLight.position.set(0, 20, 0); - scene.add(hemiLight); - - const dirLight = new THREE.DirectionalLight(0xffffff, 3); - dirLight.position.set(0, 20, 10); - scene.add(dirLight); - - // ground - - const mesh = new THREE.Mesh( - new THREE.PlaneGeometry(2000, 2000), - new THREE.MeshPhongMaterial({ color: 0xcbcbcb, depthWrite: false }), - ); - mesh.rotation.x = -Math.PI / 2; - scene.add(mesh); - - const grid = new THREE.GridHelper(200, 40, 0x000000, 0x000000); - grid.material.opacity = 0.2; - grid.material.transparent = true; - scene.add(grid); - - // model - - const loader = new GLTFLoader(); - loader.load( - 'models/gltf/RobotExpressive/RobotExpressive.glb', - function (gltf) { - model = gltf.scene; - scene.add(model); - - createGUI(model, gltf.animations); - }, - undefined, - function (e) { - console.error(e); - }, - ); - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - window.addEventListener('resize', onWindowResize); - - // stats - stats = new Stats(); - container.appendChild(stats.dom); -} - -function createGUI(model, animations) { - const states = ['Idle', 'Walking', 'Running', 'Dance', 'Death', 'Sitting', 'Standing']; - const emotes = ['Jump', 'Yes', 'No', 'Wave', 'Punch', 'ThumbsUp']; - - gui = new GUI(); - - mixer = new THREE.AnimationMixer(model); - - actions = {}; - - for (let i = 0; i < animations.length; i++) { - const clip = animations[i]; - const action = mixer.clipAction(clip); - actions[clip.name] = action; - - if (emotes.indexOf(clip.name) >= 0 || states.indexOf(clip.name) >= 4) { - action.clampWhenFinished = true; - action.loop = THREE.LoopOnce; - } - } - - // states - - const statesFolder = gui.addFolder('States'); - - const clipCtrl = statesFolder.add(api, 'state').options(states); - - clipCtrl.onChange(function () { - fadeToAction(api.state, 0.5); - }); - - statesFolder.open(); - - // emotes - - const emoteFolder = gui.addFolder('Emotes'); - - function createEmoteCallback(name) { - api[name] = function () { - fadeToAction(name, 0.2); - - mixer.addEventListener('finished', restoreState); - }; - - emoteFolder.add(api, name); - } - - function restoreState() { - mixer.removeEventListener('finished', restoreState); - - fadeToAction(api.state, 0.2); - } - - for (let i = 0; i < emotes.length; i++) { - createEmoteCallback(emotes[i]); - } - - emoteFolder.open(); - - // expressions - - face = model.getObjectByName('Head_4'); - - const expressions = Object.keys(face.morphTargetDictionary); - const expressionFolder = gui.addFolder('Expressions'); - - for (let i = 0; i < expressions.length; i++) { - expressionFolder.add(face.morphTargetInfluences, i, 0, 1, 0.01).name(expressions[i]); - } - - activeAction = actions['Walking']; - activeAction.play(); - - expressionFolder.open(); -} - -function fadeToAction(name, duration) { - previousAction = activeAction; - activeAction = actions[name]; - - if (previousAction !== activeAction) { - previousAction.fadeOut(duration); - } - - activeAction.reset().setEffectiveTimeScale(1).setEffectiveWeight(1).fadeIn(duration).play(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - const dt = clock.getDelta(); - - if (mixer) mixer.update(dt); - - requestAnimationFrame(animate); - - renderer.render(scene, camera); - - stats.update(); -} diff --git a/examples-testing/examples/webgl_buffergeometry.ts b/examples-testing/examples/webgl_buffergeometry.ts deleted file mode 100644 index 5f9bb39c4..000000000 --- a/examples-testing/examples/webgl_buffergeometry.ts +++ /dev/null @@ -1,182 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let container, stats; - -let camera, scene, renderer; - -let mesh; - -init(); -animate(); - -function init() { - container = document.getElementById('container'); - - // - - camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500); - camera.position.z = 2750; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x050505); - scene.fog = new THREE.Fog(0x050505, 2000, 3500); - - // - - scene.add(new THREE.AmbientLight(0xcccccc)); - - const light1 = new THREE.DirectionalLight(0xffffff, 1.5); - light1.position.set(1, 1, 1); - scene.add(light1); - - const light2 = new THREE.DirectionalLight(0xffffff, 4.5); - light2.position.set(0, -1, 0); - scene.add(light2); - - // - - const triangles = 160000; - - const geometry = new THREE.BufferGeometry(); - - const positions = []; - const normals = []; - const colors = []; - - const color = new THREE.Color(); - - const n = 800, - n2 = n / 2; // triangles spread in the cube - const d = 12, - d2 = d / 2; // individual triangle size - - const pA = new THREE.Vector3(); - const pB = new THREE.Vector3(); - const pC = new THREE.Vector3(); - - const cb = new THREE.Vector3(); - const ab = new THREE.Vector3(); - - for (let i = 0; i < triangles; i++) { - // positions - - const x = Math.random() * n - n2; - const y = Math.random() * n - n2; - const z = Math.random() * n - n2; - - const ax = x + Math.random() * d - d2; - const ay = y + Math.random() * d - d2; - const az = z + Math.random() * d - d2; - - const bx = x + Math.random() * d - d2; - const by = y + Math.random() * d - d2; - const bz = z + Math.random() * d - d2; - - const cx = x + Math.random() * d - d2; - const cy = y + Math.random() * d - d2; - const cz = z + Math.random() * d - d2; - - positions.push(ax, ay, az); - positions.push(bx, by, bz); - positions.push(cx, cy, cz); - - // flat face normals - - pA.set(ax, ay, az); - pB.set(bx, by, bz); - pC.set(cx, cy, cz); - - cb.subVectors(pC, pB); - ab.subVectors(pA, pB); - cb.cross(ab); - - cb.normalize(); - - const nx = cb.x; - const ny = cb.y; - const nz = cb.z; - - normals.push(nx, ny, nz); - normals.push(nx, ny, nz); - normals.push(nx, ny, nz); - - // colors - - const vx = x / n + 0.5; - const vy = y / n + 0.5; - const vz = z / n + 0.5; - - color.setRGB(vx, vy, vz); - - const alpha = Math.random(); - - colors.push(color.r, color.g, color.b, alpha); - colors.push(color.r, color.g, color.b, alpha); - colors.push(color.r, color.g, color.b, alpha); - } - - function disposeArray() { - this.array = null; - } - - geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3).onUpload(disposeArray)); - geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3).onUpload(disposeArray)); - geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 4).onUpload(disposeArray)); - - geometry.computeBoundingSphere(); - - const material = new THREE.MeshPhongMaterial({ - color: 0xd5d5d5, - specular: 0xffffff, - shininess: 250, - side: THREE.DoubleSide, - vertexColors: true, - transparent: true, - }); - - mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - // - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.001; - - mesh.rotation.x = time * 0.25; - mesh.rotation.y = time * 0.5; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts b/examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts deleted file mode 100644 index e9e115dcb..000000000 --- a/examples-testing/examples/webgl_buffergeometry_custom_attributes_particles.ts +++ /dev/null @@ -1,108 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let renderer, scene, camera, stats; - -let particleSystem, uniforms, geometry; - -const particles = 100000; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000); - camera.position.z = 300; - - scene = new THREE.Scene(); - - uniforms = { - pointTexture: { value: new THREE.TextureLoader().load('textures/sprites/spark1.png') }, - }; - - const shaderMaterial = new THREE.ShaderMaterial({ - uniforms: uniforms, - vertexShader: document.getElementById('vertexshader').textContent, - fragmentShader: document.getElementById('fragmentshader').textContent, - - blending: THREE.AdditiveBlending, - depthTest: false, - transparent: true, - vertexColors: true, - }); - - const radius = 200; - - geometry = new THREE.BufferGeometry(); - - const positions = []; - const colors = []; - const sizes = []; - - const color = new THREE.Color(); - - for (let i = 0; i < particles; i++) { - positions.push((Math.random() * 2 - 1) * radius); - positions.push((Math.random() * 2 - 1) * radius); - positions.push((Math.random() * 2 - 1) * radius); - - color.setHSL(i / particles, 1.0, 0.5); - - colors.push(color.r, color.g, color.b); - - sizes.push(20); - } - - geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); - geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); - geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1).setUsage(THREE.DynamicDrawUsage)); - - particleSystem = new THREE.Points(geometry, shaderMaterial); - - scene.add(particleSystem); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - - const container = document.getElementById('container'); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.005; - - particleSystem.rotation.z = 0.01 * time; - - const sizes = geometry.attributes.size.array; - - for (let i = 0; i < particles; i++) { - sizes[i] = 10 * (1 + Math.sin(0.1 * i + time)); - } - - geometry.attributes.size.needsUpdate = true; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_drawrange.ts b/examples-testing/examples/webgl_buffergeometry_drawrange.ts deleted file mode 100644 index b69868ce4..000000000 --- a/examples-testing/examples/webgl_buffergeometry_drawrange.ts +++ /dev/null @@ -1,241 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -let group; -let container, stats; -const particlesData = []; -let camera, scene, renderer; -let positions, colors; -let particles; -let pointCloud; -let particlePositions; -let linesMesh; - -const maxParticleCount = 1000; -let particleCount = 500; -const r = 800; -const rHalf = r / 2; - -const effectController = { - showDots: true, - showLines: true, - minDistance: 150, - limitConnections: false, - maxConnections: 20, - particleCount: 500, -}; - -init(); -animate(); - -function initGUI() { - const gui = new GUI(); - - gui.add(effectController, 'showDots').onChange(function (value) { - pointCloud.visible = value; - }); - gui.add(effectController, 'showLines').onChange(function (value) { - linesMesh.visible = value; - }); - gui.add(effectController, 'minDistance', 10, 300); - gui.add(effectController, 'limitConnections'); - gui.add(effectController, 'maxConnections', 0, 30, 1); - gui.add(effectController, 'particleCount', 0, maxParticleCount, 1).onChange(function (value) { - particleCount = parseInt(value); - particles.setDrawRange(0, particleCount); - }); -} - -function init() { - initGUI(); - - container = document.getElementById('container'); - - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 4000); - camera.position.z = 1750; - - const controls = new OrbitControls(camera, container); - controls.minDistance = 1000; - controls.maxDistance = 3000; - - scene = new THREE.Scene(); - - group = new THREE.Group(); - scene.add(group); - - const helper = new THREE.BoxHelper(new THREE.Mesh(new THREE.BoxGeometry(r, r, r))); - helper.material.color.setHex(0x474747); - helper.material.blending = THREE.AdditiveBlending; - helper.material.transparent = true; - group.add(helper); - - const segments = maxParticleCount * maxParticleCount; - - positions = new Float32Array(segments * 3); - colors = new Float32Array(segments * 3); - - const pMaterial = new THREE.PointsMaterial({ - color: 0xffffff, - size: 3, - blending: THREE.AdditiveBlending, - transparent: true, - sizeAttenuation: false, - }); - - particles = new THREE.BufferGeometry(); - particlePositions = new Float32Array(maxParticleCount * 3); - - for (let i = 0; i < maxParticleCount; i++) { - const x = Math.random() * r - r / 2; - const y = Math.random() * r - r / 2; - const z = Math.random() * r - r / 2; - - particlePositions[i * 3] = x; - particlePositions[i * 3 + 1] = y; - particlePositions[i * 3 + 2] = z; - - // add it to the geometry - particlesData.push({ - velocity: new THREE.Vector3(-1 + Math.random() * 2, -1 + Math.random() * 2, -1 + Math.random() * 2), - numConnections: 0, - }); - } - - particles.setDrawRange(0, particleCount); - particles.setAttribute( - 'position', - new THREE.BufferAttribute(particlePositions, 3).setUsage(THREE.DynamicDrawUsage), - ); - - // create the particle system - pointCloud = new THREE.Points(particles, pMaterial); - group.add(pointCloud); - - const geometry = new THREE.BufferGeometry(); - - geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3).setUsage(THREE.DynamicDrawUsage)); - geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3).setUsage(THREE.DynamicDrawUsage)); - - geometry.computeBoundingSphere(); - - geometry.setDrawRange(0, 0); - - const material = new THREE.LineBasicMaterial({ - vertexColors: true, - blending: THREE.AdditiveBlending, - transparent: true, - }); - - linesMesh = new THREE.LineSegments(geometry, material); - group.add(linesMesh); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - - container.appendChild(renderer.domElement); - - // - - stats = new Stats(); - container.appendChild(stats.dom); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - let vertexpos = 0; - let colorpos = 0; - let numConnected = 0; - - for (let i = 0; i < particleCount; i++) particlesData[i].numConnections = 0; - - for (let i = 0; i < particleCount; i++) { - // get the particle - const particleData = particlesData[i]; - - particlePositions[i * 3] += particleData.velocity.x; - particlePositions[i * 3 + 1] += particleData.velocity.y; - particlePositions[i * 3 + 2] += particleData.velocity.z; - - if (particlePositions[i * 3 + 1] < -rHalf || particlePositions[i * 3 + 1] > rHalf) - particleData.velocity.y = -particleData.velocity.y; - - if (particlePositions[i * 3] < -rHalf || particlePositions[i * 3] > rHalf) - particleData.velocity.x = -particleData.velocity.x; - - if (particlePositions[i * 3 + 2] < -rHalf || particlePositions[i * 3 + 2] > rHalf) - particleData.velocity.z = -particleData.velocity.z; - - if (effectController.limitConnections && particleData.numConnections >= effectController.maxConnections) - continue; - - // Check collision - for (let j = i + 1; j < particleCount; j++) { - const particleDataB = particlesData[j]; - if (effectController.limitConnections && particleDataB.numConnections >= effectController.maxConnections) - continue; - - const dx = particlePositions[i * 3] - particlePositions[j * 3]; - const dy = particlePositions[i * 3 + 1] - particlePositions[j * 3 + 1]; - const dz = particlePositions[i * 3 + 2] - particlePositions[j * 3 + 2]; - const dist = Math.sqrt(dx * dx + dy * dy + dz * dz); - - if (dist < effectController.minDistance) { - particleData.numConnections++; - particleDataB.numConnections++; - - const alpha = 1.0 - dist / effectController.minDistance; - - positions[vertexpos++] = particlePositions[i * 3]; - positions[vertexpos++] = particlePositions[i * 3 + 1]; - positions[vertexpos++] = particlePositions[i * 3 + 2]; - - positions[vertexpos++] = particlePositions[j * 3]; - positions[vertexpos++] = particlePositions[j * 3 + 1]; - positions[vertexpos++] = particlePositions[j * 3 + 2]; - - colors[colorpos++] = alpha; - colors[colorpos++] = alpha; - colors[colorpos++] = alpha; - - colors[colorpos++] = alpha; - colors[colorpos++] = alpha; - colors[colorpos++] = alpha; - - numConnected++; - } - } - } - - linesMesh.geometry.setDrawRange(0, numConnected * 2); - linesMesh.geometry.attributes.position.needsUpdate = true; - linesMesh.geometry.attributes.color.needsUpdate = true; - - pointCloud.geometry.attributes.position.needsUpdate = true; - - requestAnimationFrame(animate); - - stats.update(); - render(); -} - -function render() { - const time = Date.now() * 0.001; - - group.rotation.y = time * 0.1; - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts b/examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts deleted file mode 100644 index daf8a0607..000000000 --- a/examples-testing/examples/webgl_buffergeometry_glbufferattribute.ts +++ /dev/null @@ -1,145 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let container, stats; - -let camera, scene, renderer; - -let points; - -const particles = 300000; -let drawCount = 10000; - -init(); -animate(); - -function init() { - container = document.getElementById('container'); - - // - - renderer = new THREE.WebGLRenderer({ antialias: false }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - - container.appendChild(renderer.domElement); - - // - - camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 5, 3500); - camera.position.z = 2750; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x050505); - scene.fog = new THREE.Fog(0x050505, 2000, 3500); - - // - - const geometry = new THREE.BufferGeometry(); - - const positions = []; - const positions2 = []; - const colors = []; - - const color = new THREE.Color(); - - const n = 1000, - n2 = n / 2; // particles spread in the cube - - for (let i = 0; i < particles; i++) { - // positions - - const x = Math.random() * n - n2; - const y = Math.random() * n - n2; - const z = Math.random() * n - n2; - - positions.push(x, y, z); - positions2.push(z * 0.3, x * 0.3, y * 0.3); - - // colors - - const vx = x / n + 0.5; - const vy = y / n + 0.5; - const vz = z / n + 0.5; - - color.setRGB(vx, vy, vz, THREE.SRGBColorSpace); - - colors.push(color.r, color.g, color.b); - } - - const gl = renderer.getContext(); - - const pos = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, pos); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); - - const pos2 = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, pos2); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions2), gl.STATIC_DRAW); - - const rgb = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, rgb); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); - - const posAttr1 = new THREE.GLBufferAttribute(pos, gl.FLOAT, 3, 4, particles); - const posAttr2 = new THREE.GLBufferAttribute(pos2, gl.FLOAT, 3, 4, particles); - geometry.setAttribute('position', posAttr1); - - setInterval(function () { - const attr = geometry.getAttribute('position'); - - geometry.setAttribute('position', attr === posAttr1 ? posAttr2 : posAttr1); - }, 2000); - - geometry.setAttribute('color', new THREE.GLBufferAttribute(rgb, gl.FLOAT, 3, 4, particles)); - - // - - const material = new THREE.PointsMaterial({ size: 15, vertexColors: true }); - - points = new THREE.Points(geometry, material); - - // Choose one: - // geometry.boundingSphere = ( new THREE.Sphere() ).set( new THREE.Vector3(), Infinity ); - points.frustumCulled = false; - - scene.add(points); - - // - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - drawCount = (Math.max(5000, drawCount) + Math.floor(500 * Math.random())) % particles; - points.geometry.setDrawRange(0, drawCount); - - const time = Date.now() * 0.001; - - points.rotation.x = time * 0.1; - points.rotation.y = time * 0.2; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_indexed.ts b/examples-testing/examples/webgl_buffergeometry_indexed.ts deleted file mode 100644 index 1e9f668cc..000000000 --- a/examples-testing/examples/webgl_buffergeometry_indexed.ts +++ /dev/null @@ -1,142 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let camera, scene, renderer, stats; - -let mesh; - -init(); -animate(); - -function init() { - // - - camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500); - camera.position.z = 64; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x050505); - - // - - const light = new THREE.HemisphereLight(); - light.intensity = 3; - scene.add(light); - - // - - const geometry = new THREE.BufferGeometry(); - - const indices = []; - - const vertices = []; - const normals = []; - const colors = []; - - const size = 20; - const segments = 10; - - const halfSize = size / 2; - const segmentSize = size / segments; - - const _color = new THREE.Color(); - - // generate vertices, normals and color data for a simple grid geometry - - for (let i = 0; i <= segments; i++) { - const y = i * segmentSize - halfSize; - - for (let j = 0; j <= segments; j++) { - const x = j * segmentSize - halfSize; - - vertices.push(x, -y, 0); - normals.push(0, 0, 1); - - const r = x / size + 0.5; - const g = y / size + 0.5; - - _color.setRGB(r, g, 1, THREE.SRGBColorSpace); - - colors.push(_color.r, _color.g, _color.b); - } - } - - // generate indices (data for element array buffer) - - for (let i = 0; i < segments; i++) { - for (let j = 0; j < segments; j++) { - const a = i * (segments + 1) + (j + 1); - const b = i * (segments + 1) + j; - const c = (i + 1) * (segments + 1) + j; - const d = (i + 1) * (segments + 1) + (j + 1); - - // generate two faces (triangles) per iteration - - indices.push(a, b, d); // face one - indices.push(b, c, d); // face two - } - } - - // - - geometry.setIndex(indices); - geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); - geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3)); - geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); - - const material = new THREE.MeshPhongMaterial({ - side: THREE.DoubleSide, - vertexColors: true, - }); - - mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - // - - stats = new Stats(); - document.body.appendChild(stats.dom); - - // - - const gui = new GUI(); - gui.add(material, 'wireframe'); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.001; - - mesh.rotation.x = time * 0.25; - mesh.rotation.y = time * 0.5; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_instancing.ts b/examples-testing/examples/webgl_buffergeometry_instancing.ts deleted file mode 100644 index adff12a8a..000000000 --- a/examples-testing/examples/webgl_buffergeometry_instancing.ts +++ /dev/null @@ -1,148 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let container, stats; - -let camera, scene, renderer; - -init(); -animate(); - -function init() { - container = document.getElementById('container'); - - camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10); - camera.position.z = 2; - - scene = new THREE.Scene(); - - // geometry - - const vector = new THREE.Vector4(); - - const instances = 50000; - - const positions = []; - const offsets = []; - const colors = []; - const orientationsStart = []; - const orientationsEnd = []; - - positions.push(0.025, -0.025, 0); - positions.push(-0.025, 0.025, 0); - positions.push(0, 0, 0.025); - - // instanced attributes - - for (let i = 0; i < instances; i++) { - // offsets - - offsets.push(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5); - - // colors - - colors.push(Math.random(), Math.random(), Math.random(), Math.random()); - - // orientation start - - vector.set(Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1); - vector.normalize(); - - orientationsStart.push(vector.x, vector.y, vector.z, vector.w); - - // orientation end - - vector.set(Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1); - vector.normalize(); - - orientationsEnd.push(vector.x, vector.y, vector.z, vector.w); - } - - const geometry = new THREE.InstancedBufferGeometry(); - geometry.instanceCount = instances; // set so its initalized for dat.GUI, will be set in first draw otherwise - - geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); - - geometry.setAttribute('offset', new THREE.InstancedBufferAttribute(new Float32Array(offsets), 3)); - geometry.setAttribute('color', new THREE.InstancedBufferAttribute(new Float32Array(colors), 4)); - geometry.setAttribute( - 'orientationStart', - new THREE.InstancedBufferAttribute(new Float32Array(orientationsStart), 4), - ); - geometry.setAttribute('orientationEnd', new THREE.InstancedBufferAttribute(new Float32Array(orientationsEnd), 4)); - - // material - - const material = new THREE.RawShaderMaterial({ - uniforms: { - time: { value: 1.0 }, - sineTime: { value: 1.0 }, - }, - vertexShader: document.getElementById('vertexShader').textContent, - fragmentShader: document.getElementById('fragmentShader').textContent, - side: THREE.DoubleSide, - forceSinglePass: true, - transparent: true, - }); - - // - - const mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - if (renderer.capabilities.isWebGL2 === false && renderer.extensions.has('ANGLE_instanced_arrays') === false) { - document.getElementById('notSupported').style.display = ''; - return; - } - - // - - const gui = new GUI({ width: 350 }); - gui.add(geometry, 'instanceCount', 0, instances); - - // - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = performance.now(); - - const object = scene.children[0]; - - object.rotation.y = time * 0.0005; - object.material.uniforms['time'].value = time * 0.005; - object.material.uniforms['sineTime'].value = Math.sin(object.material.uniforms['time'].value * 0.05); - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts b/examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts deleted file mode 100644 index 785389c8b..000000000 --- a/examples-testing/examples/webgl_buffergeometry_instancing_billboards.ts +++ /dev/null @@ -1,98 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let container, stats; - -let camera, scene, renderer; -let geometry, material, mesh; - -function init() { - renderer = new THREE.WebGLRenderer(); - - if (renderer.capabilities.isWebGL2 === false && renderer.extensions.has('ANGLE_instanced_arrays') === false) { - document.getElementById('notSupported').style.display = ''; - return false; - } - - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 5000); - camera.position.z = 1400; - - scene = new THREE.Scene(); - - const circleGeometry = new THREE.CircleGeometry(1, 6); - - geometry = new THREE.InstancedBufferGeometry(); - geometry.index = circleGeometry.index; - geometry.attributes = circleGeometry.attributes; - - const particleCount = 75000; - - const translateArray = new Float32Array(particleCount * 3); - - for (let i = 0, i3 = 0, l = particleCount; i < l; i++, i3 += 3) { - translateArray[i3 + 0] = Math.random() * 2 - 1; - translateArray[i3 + 1] = Math.random() * 2 - 1; - translateArray[i3 + 2] = Math.random() * 2 - 1; - } - - geometry.setAttribute('translate', new THREE.InstancedBufferAttribute(translateArray, 3)); - - material = new THREE.RawShaderMaterial({ - uniforms: { - map: { value: new THREE.TextureLoader().load('textures/sprites/circle.png') }, - time: { value: 0.0 }, - }, - vertexShader: document.getElementById('vshader').textContent, - fragmentShader: document.getElementById('fshader').textContent, - depthTest: true, - depthWrite: true, - }); - - mesh = new THREE.Mesh(geometry, material); - mesh.scale.set(500, 500, 500); - scene.add(mesh); - - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - window.addEventListener('resize', onWindowResize); - - return true; -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = performance.now() * 0.0005; - - material.uniforms['time'].value = time; - - mesh.rotation.x = time * 0.2; - mesh.rotation.y = time * 0.4; - - renderer.render(scene, camera); -} - -if (init()) { - animate(); -} diff --git a/examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts b/examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts deleted file mode 100644 index 132e1e6df..000000000 --- a/examples-testing/examples/webgl_buffergeometry_instancing_interleaved.ts +++ /dev/null @@ -1,162 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let container, stats; -let camera, scene, renderer, mesh; - -const instances = 5000; -let lastTime = 0; - -const moveQ = new THREE.Quaternion(0.5, 0.5, 0.5, 0.0).normalize(); -const tmpQ = new THREE.Quaternion(); -const tmpM = new THREE.Matrix4(); -const currentM = new THREE.Matrix4(); - -init(); -animate(); - -function init() { - container = document.getElementById('container'); - - camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1000); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x101010); - - // geometry - - const geometry = new THREE.InstancedBufferGeometry(); - - // per mesh data x,y,z,w,u,v,s,t for 4-element alignment - // only use x,y,z and u,v; but x, y, z, nx, ny, nz, u, v would be a good layout - const vertexBuffer = new THREE.InterleavedBuffer( - new Float32Array([ - // Front - -1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, -1, -1, 1, 0, 0, 1, 0, 0, 1, -1, 1, 0, 1, 1, 0, 0, - // Back - 1, 1, -1, 0, 1, 0, 0, 0, -1, 1, -1, 0, 0, 0, 0, 0, 1, -1, -1, 0, 1, 1, 0, 0, -1, -1, -1, 0, 0, 1, 0, 0, - // Left - -1, 1, -1, 0, 1, 1, 0, 0, -1, 1, 1, 0, 1, 0, 0, 0, -1, -1, -1, 0, 0, 1, 0, 0, -1, -1, 1, 0, 0, 0, 0, 0, - // Right - 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, -1, 0, 1, 1, 0, 0, 1, -1, 1, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 1, 0, 0, - // Top - -1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, -1, 1, -1, 0, 0, 1, 0, 0, 1, 1, -1, 0, 1, 1, 0, 0, - // Bottom - 1, -1, 1, 0, 1, 0, 0, 0, -1, -1, 1, 0, 0, 0, 0, 0, 1, -1, -1, 0, 1, 1, 0, 0, -1, -1, -1, 0, 0, 1, 0, 0, - ]), - 8, - ); - - // Use vertexBuffer, starting at offset 0, 3 items in position attribute - const positions = new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0); - geometry.setAttribute('position', positions); - // Use vertexBuffer, starting at offset 4, 2 items in uv attribute - const uvs = new THREE.InterleavedBufferAttribute(vertexBuffer, 2, 4); - geometry.setAttribute('uv', uvs); - - const indices = new Uint16Array([ - 0, 2, 1, 2, 3, 1, 4, 6, 5, 6, 7, 5, 8, 10, 9, 10, 11, 9, 12, 14, 13, 14, 15, 13, 16, 17, 18, 18, 17, 19, 20, 21, - 22, 22, 21, 23, - ]); - - geometry.setIndex(new THREE.BufferAttribute(indices, 1)); - - // material - - const material = new THREE.MeshBasicMaterial(); - material.map = new THREE.TextureLoader().load('textures/crate.gif'); - material.map.colorSpace = THREE.SRGBColorSpace; - material.map.flipY = false; - - // per instance data - - const matrix = new THREE.Matrix4(); - const offset = new THREE.Vector3(); - const orientation = new THREE.Quaternion(); - const scale = new THREE.Vector3(1, 1, 1); - let x, y, z, w; - - mesh = new THREE.InstancedMesh(geometry, material, instances); - - for (let i = 0; i < instances; i++) { - // offsets - - x = Math.random() * 100 - 50; - y = Math.random() * 100 - 50; - z = Math.random() * 100 - 50; - - offset.set(x, y, z).normalize(); - offset.multiplyScalar(5); // move out at least 5 units from center in current direction - offset.set(x + offset.x, y + offset.y, z + offset.z); - - // orientations - - x = Math.random() * 2 - 1; - y = Math.random() * 2 - 1; - z = Math.random() * 2 - 1; - w = Math.random() * 2 - 1; - - orientation.set(x, y, z, w).normalize(); - - matrix.compose(offset, orientation, scale); - - mesh.setMatrixAt(i, matrix); - } - - scene.add(mesh); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - if (renderer.capabilities.isWebGL2 === false && renderer.extensions.has('ANGLE_instanced_arrays') === false) { - document.getElementById('notSupported').style.display = ''; - return; - } - - stats = new Stats(); - container.appendChild(stats.dom); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = performance.now(); - - mesh.rotation.y = time * 0.00005; - - const delta = (time - lastTime) / 5000; - tmpQ.set(moveQ.x * delta, moveQ.y * delta, moveQ.z * delta, 1).normalize(); - tmpM.makeRotationFromQuaternion(tmpQ); - - for (let i = 0, il = instances; i < il; i++) { - mesh.getMatrixAt(i, currentM); - currentM.multiply(tmpM); - mesh.setMatrixAt(i, currentM); - } - - mesh.instanceMatrix.needsUpdate = true; - mesh.computeBoundingSphere(); - - lastTime = time; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_lines.ts b/examples-testing/examples/webgl_buffergeometry_lines.ts deleted file mode 100644 index c23ea0cdd..000000000 --- a/examples-testing/examples/webgl_buffergeometry_lines.ts +++ /dev/null @@ -1,123 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let container, stats, clock; - -let camera, scene, renderer; - -let line; - -const segments = 10000; -const r = 800; -let t = 0; - -init(); -animate(); - -function init() { - container = document.getElementById('container'); - - // - - camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 4000); - camera.position.z = 2750; - - scene = new THREE.Scene(); - - clock = new THREE.Clock(); - - const geometry = new THREE.BufferGeometry(); - const material = new THREE.LineBasicMaterial({ vertexColors: true }); - - const positions = []; - const colors = []; - - for (let i = 0; i < segments; i++) { - const x = Math.random() * r - r / 2; - const y = Math.random() * r - r / 2; - const z = Math.random() * r - r / 2; - - // positions - - positions.push(x, y, z); - - // colors - - colors.push(x / r + 0.5); - colors.push(y / r + 0.5); - colors.push(z / r + 0.5); - } - - geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); - geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); - generateMorphTargets(geometry); - - geometry.computeBoundingSphere(); - - line = new THREE.Line(geometry, material); - scene.add(line); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - - container.appendChild(renderer.domElement); - - // - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const delta = clock.getDelta(); - const time = clock.getElapsedTime(); - - line.rotation.x = time * 0.25; - line.rotation.y = time * 0.5; - - t += delta * 0.5; - line.morphTargetInfluences[0] = Math.abs(Math.sin(t)); - - renderer.render(scene, camera); -} - -function generateMorphTargets(geometry) { - const data = []; - - for (let i = 0; i < segments; i++) { - const x = Math.random() * r - r / 2; - const y = Math.random() * r - r / 2; - const z = Math.random() * r - r / 2; - - data.push(x, y, z); - } - - const morphTarget = new THREE.Float32BufferAttribute(data, 3); - morphTarget.name = 'target1'; - - geometry.morphAttributes.position = [morphTarget]; -} diff --git a/examples-testing/examples/webgl_buffergeometry_lines_indexed.ts b/examples-testing/examples/webgl_buffergeometry_lines_indexed.ts deleted file mode 100644 index d81c1736a..000000000 --- a/examples-testing/examples/webgl_buffergeometry_lines_indexed.ts +++ /dev/null @@ -1,186 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let container, stats; - -let camera, scene, renderer; - -let parent_node; - -init(); -animate(); - -function init() { - container = document.getElementById('container'); - - camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 10000); - camera.position.z = 9000; - - scene = new THREE.Scene(); - - const geometry = new THREE.BufferGeometry(); - const material = new THREE.LineBasicMaterial({ vertexColors: true }); - - const indices = []; - const positions = []; - const colors = []; - - let next_positions_index = 0; - - // - - const iteration_count = 4; - const rangle = (60 * Math.PI) / 180.0; - - function add_vertex(v) { - if (next_positions_index == 0xffff) console.error('Too many points.'); - - positions.push(v.x, v.y, v.z); - colors.push(Math.random() * 0.5 + 0.5, Math.random() * 0.5 + 0.5, 1); - - return next_positions_index++; - } - - // simple Koch curve - - function snowflake_iteration(p0, p4, depth) { - if (--depth < 0) { - const i = next_positions_index - 1; // p0 already there - add_vertex(p4); - indices.push(i, i + 1); - - return; - } - - const v = p4.clone().sub(p0); - const v_tier = v.clone().multiplyScalar(1 / 3); - const p1 = p0.clone().add(v_tier); - - const angle = Math.atan2(v.y, v.x) + rangle; - const length = v_tier.length(); - const p2 = p1.clone(); - p2.x += Math.cos(angle) * length; - p2.y += Math.sin(angle) * length; - - const p3 = p0.clone().add(v_tier).add(v_tier); - - snowflake_iteration(p0, p1, depth); - snowflake_iteration(p1, p2, depth); - snowflake_iteration(p2, p3, depth); - snowflake_iteration(p3, p4, depth); - } - - function snowflake(points, loop, x_offset) { - for (let iteration = 0; iteration != iteration_count; iteration++) { - add_vertex(points[0]); - - for (let p_index = 0, p_count = points.length - 1; p_index != p_count; p_index++) { - snowflake_iteration(points[p_index], points[p_index + 1], iteration); - } - - if (loop) snowflake_iteration(points[points.length - 1], points[0], iteration); - - // translate input curve for next iteration - - for (let p_index = 0, p_count = points.length; p_index != p_count; p_index++) { - points[p_index].x += x_offset; - } - } - } - - let y = 0; - - snowflake([new THREE.Vector3(0, y, 0), new THREE.Vector3(500, y, 0)], false, 600); - - y += 600; - snowflake( - [new THREE.Vector3(0, y, 0), new THREE.Vector3(250, y + 400, 0), new THREE.Vector3(500, y, 0)], - true, - 600, - ); - - y += 600; - snowflake( - [ - new THREE.Vector3(0, y, 0), - new THREE.Vector3(500, y, 0), - new THREE.Vector3(500, y + 500, 0), - new THREE.Vector3(0, y + 500, 0), - ], - true, - 600, - ); - - y += 1000; - snowflake( - [ - new THREE.Vector3(250, y, 0), - new THREE.Vector3(500, y, 0), - new THREE.Vector3(250, y, 0), - new THREE.Vector3(250, y + 250, 0), - new THREE.Vector3(250, y, 0), - new THREE.Vector3(0, y, 0), - new THREE.Vector3(250, y, 0), - new THREE.Vector3(250, y - 250, 0), - new THREE.Vector3(250, y, 0), - ], - false, - 600, - ); - - // - - geometry.setIndex(indices); - geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); - geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); - geometry.computeBoundingSphere(); - - const lineSegments = new THREE.LineSegments(geometry, material); - lineSegments.position.x -= 1200; - lineSegments.position.y -= 1200; - - parent_node = new THREE.Object3D(); - parent_node.add(lineSegments); - - scene.add(parent_node); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - - container.appendChild(renderer.domElement); - - // - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.001; - - parent_node.rotation.z = time * 0.5; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_points.ts b/examples-testing/examples/webgl_buffergeometry_points.ts deleted file mode 100644 index fdfd9575d..000000000 --- a/examples-testing/examples/webgl_buffergeometry_points.ts +++ /dev/null @@ -1,113 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let container, stats; - -let camera, scene, renderer; - -let points; - -init(); -animate(); - -function init() { - container = document.getElementById('container'); - - // - - camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 5, 3500); - camera.position.z = 2750; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x050505); - scene.fog = new THREE.Fog(0x050505, 2000, 3500); - - // - - const particles = 500000; - - const geometry = new THREE.BufferGeometry(); - - const positions = []; - const colors = []; - - const color = new THREE.Color(); - - const n = 1000, - n2 = n / 2; // particles spread in the cube - - for (let i = 0; i < particles; i++) { - // positions - - const x = Math.random() * n - n2; - const y = Math.random() * n - n2; - const z = Math.random() * n - n2; - - positions.push(x, y, z); - - // colors - - const vx = x / n + 0.5; - const vy = y / n + 0.5; - const vz = z / n + 0.5; - - color.setRGB(vx, vy, vz, THREE.SRGBColorSpace); - - colors.push(color.r, color.g, color.b); - } - - geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); - geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); - - geometry.computeBoundingSphere(); - - // - - const material = new THREE.PointsMaterial({ size: 15, vertexColors: true }); - - points = new THREE.Points(geometry, material); - scene.add(points); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - - container.appendChild(renderer.domElement); - - // - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.001; - - points.rotation.x = time * 0.25; - points.rotation.y = time * 0.5; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_points_interleaved.ts b/examples-testing/examples/webgl_buffergeometry_points_interleaved.ts deleted file mode 100644 index 9d1ac41e3..000000000 --- a/examples-testing/examples/webgl_buffergeometry_points_interleaved.ts +++ /dev/null @@ -1,127 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let container, stats; - -let camera, scene, renderer; - -let points; - -init(); -animate(); - -function init() { - container = document.getElementById('container'); - - camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 5, 3500); - camera.position.z = 2750; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x050505); - scene.fog = new THREE.Fog(0x050505, 2000, 3500); - - // - - const particles = 500000; - - const geometry = new THREE.BufferGeometry(); - - // create a generic buffer of binary data (a single particle has 16 bytes of data) - - const arrayBuffer = new ArrayBuffer(particles * 16); - - // the following typed arrays share the same buffer - - const interleavedFloat32Buffer = new Float32Array(arrayBuffer); - const interleavedUint8Buffer = new Uint8Array(arrayBuffer); - - // - - const color = new THREE.Color(); - - const n = 1000, - n2 = n / 2; // particles spread in the cube - - for (let i = 0; i < interleavedFloat32Buffer.length; i += 4) { - // position (first 12 bytes) - - const x = Math.random() * n - n2; - const y = Math.random() * n - n2; - const z = Math.random() * n - n2; - - interleavedFloat32Buffer[i + 0] = x; - interleavedFloat32Buffer[i + 1] = y; - interleavedFloat32Buffer[i + 2] = z; - - // color (last 4 bytes) - - const vx = x / n + 0.5; - const vy = y / n + 0.5; - const vz = z / n + 0.5; - - color.setRGB(vx, vy, vz, THREE.SRGBColorSpace); - - const j = (i + 3) * 4; - - interleavedUint8Buffer[j + 0] = color.r * 255; - interleavedUint8Buffer[j + 1] = color.g * 255; - interleavedUint8Buffer[j + 2] = color.b * 255; - interleavedUint8Buffer[j + 3] = 0; // not needed - } - - const interleavedBuffer32 = new THREE.InterleavedBuffer(interleavedFloat32Buffer, 4); - const interleavedBuffer8 = new THREE.InterleavedBuffer(interleavedUint8Buffer, 16); - - geometry.setAttribute('position', new THREE.InterleavedBufferAttribute(interleavedBuffer32, 3, 0, false)); - geometry.setAttribute('color', new THREE.InterleavedBufferAttribute(interleavedBuffer8, 3, 12, true)); - - // - - const material = new THREE.PointsMaterial({ size: 15, vertexColors: true }); - - points = new THREE.Points(geometry, material); - scene.add(points); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - - container.appendChild(renderer.domElement); - - // - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.001; - - points.rotation.x = time * 0.25; - points.rotation.y = time * 0.5; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_rawshader.ts b/examples-testing/examples/webgl_buffergeometry_rawshader.ts deleted file mode 100644 index 0d0533951..000000000 --- a/examples-testing/examples/webgl_buffergeometry_rawshader.ts +++ /dev/null @@ -1,102 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let container, stats; - -let camera, scene, renderer; - -init(); -animate(); - -function init() { - container = document.getElementById('container'); - - camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10); - camera.position.z = 2; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x101010); - - // geometry - // nr of triangles with 3 vertices per triangle - const vertexCount = 200 * 3; - - const geometry = new THREE.BufferGeometry(); - - const positions = []; - const colors = []; - - for (let i = 0; i < vertexCount; i++) { - // adding x,y,z - positions.push(Math.random() - 0.5); - positions.push(Math.random() - 0.5); - positions.push(Math.random() - 0.5); - - // adding r,g,b,a - colors.push(Math.random() * 255); - colors.push(Math.random() * 255); - colors.push(Math.random() * 255); - colors.push(Math.random() * 255); - } - - const positionAttribute = new THREE.Float32BufferAttribute(positions, 3); - const colorAttribute = new THREE.Uint8BufferAttribute(colors, 4); - - colorAttribute.normalized = true; // this will map the buffer values to 0.0f - +1.0f in the shader - - geometry.setAttribute('position', positionAttribute); - geometry.setAttribute('color', colorAttribute); - - // material - - const material = new THREE.RawShaderMaterial({ - uniforms: { - time: { value: 1.0 }, - }, - vertexShader: document.getElementById('vertexShader').textContent, - fragmentShader: document.getElementById('fragmentShader').textContent, - side: THREE.DoubleSide, - transparent: true, - }); - - const mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = performance.now(); - - const object = scene.children[0]; - - object.rotation.y = time * 0.0005; - object.material.uniforms.time.value = time * 0.005; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_selective_draw.ts b/examples-testing/examples/webgl_buffergeometry_selective_draw.ts deleted file mode 100644 index f0752a2b3..000000000 --- a/examples-testing/examples/webgl_buffergeometry_selective_draw.ts +++ /dev/null @@ -1,151 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let camera, scene, renderer, stats; -let geometry, mesh; -const numLat = 100; -const numLng = 200; -let numLinesCulled = 0; - -init(); -animate(); - -function init() { - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 10); - camera.position.z = 3.5; - - stats = new Stats(); - document.body.appendChild(stats.dom); - - window.addEventListener('resize', onWindowResize); - - addLines(1.0); - - const hideLinesButton = document.getElementById('hideLines'); - hideLinesButton.addEventListener('click', hideLines); - - const showAllLinesButton = document.getElementById('showAllLines'); - showAllLinesButton.addEventListener('click', showAllLines); -} - -function addLines(radius) { - geometry = new THREE.BufferGeometry(); - const linePositions = new Float32Array(numLat * numLng * 3 * 2); - const lineColors = new Float32Array(numLat * numLng * 3 * 2); - const visible = new Float32Array(numLat * numLng * 2); - - for (let i = 0; i < numLat; ++i) { - for (let j = 0; j < numLng; ++j) { - const lat = (Math.random() * Math.PI) / 50.0 + (i / numLat) * Math.PI; - const lng = (Math.random() * Math.PI) / 50.0 + (j / numLng) * 2 * Math.PI; - - const index = i * numLng + j; - - linePositions[index * 6 + 0] = 0; - linePositions[index * 6 + 1] = 0; - linePositions[index * 6 + 2] = 0; - linePositions[index * 6 + 3] = radius * Math.sin(lat) * Math.cos(lng); - linePositions[index * 6 + 4] = radius * Math.cos(lat); - linePositions[index * 6 + 5] = radius * Math.sin(lat) * Math.sin(lng); - - const color = new THREE.Color(0xffffff); - - color.setHSL(lat / Math.PI, 1.0, 0.2); - lineColors[index * 6 + 0] = color.r; - lineColors[index * 6 + 1] = color.g; - lineColors[index * 6 + 2] = color.b; - - color.setHSL(lat / Math.PI, 1.0, 0.7); - lineColors[index * 6 + 3] = color.r; - lineColors[index * 6 + 4] = color.g; - lineColors[index * 6 + 5] = color.b; - - // non-0 is visible - visible[index * 2 + 0] = 1.0; - visible[index * 2 + 1] = 1.0; - } - } - - geometry.setAttribute('position', new THREE.BufferAttribute(linePositions, 3)); - geometry.setAttribute('vertColor', new THREE.BufferAttribute(lineColors, 3)); - geometry.setAttribute('visible', new THREE.BufferAttribute(visible, 1)); - - geometry.computeBoundingSphere(); - - const shaderMaterial = new THREE.ShaderMaterial({ - vertexShader: document.getElementById('vertexshader').textContent, - fragmentShader: document.getElementById('fragmentshader').textContent, - }); - - mesh = new THREE.LineSegments(geometry, shaderMaterial); - scene.add(mesh); - - updateCount(); -} - -function updateCount() { - const str = - '1 draw call, ' + - numLat * numLng + - ' lines, ' + - numLinesCulled + - ' culled (author)'; - document.getElementById('title').innerHTML = str.replace(/\B(?=(\d{3})+(?!\d))/g, ','); -} - -function hideLines() { - for (let i = 0; i < geometry.attributes.visible.array.length; i += 2) { - if (Math.random() > 0.75) { - if (geometry.attributes.visible.array[i + 0]) { - ++numLinesCulled; - } - - geometry.attributes.visible.array[i + 0] = 0; - geometry.attributes.visible.array[i + 1] = 0; - } - } - - geometry.attributes.visible.needsUpdate = true; - - updateCount(); -} - -function showAllLines() { - numLinesCulled = 0; - - for (let i = 0; i < geometry.attributes.visible.array.length; i += 2) { - geometry.attributes.visible.array[i + 0] = 1; - geometry.attributes.visible.array[i + 1] = 1; - } - - geometry.attributes.visible.needsUpdate = true; - - updateCount(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - const time = Date.now() * 0.001; - - mesh.rotation.x = time * 0.25; - mesh.rotation.y = time * 0.5; - - stats.update(); - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_buffergeometry_uint.ts b/examples-testing/examples/webgl_buffergeometry_uint.ts deleted file mode 100644 index d248a0d15..000000000 --- a/examples-testing/examples/webgl_buffergeometry_uint.ts +++ /dev/null @@ -1,182 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let container, stats; - -let camera, scene, renderer; - -let mesh; - -init(); -animate(); - -function init() { - container = document.getElementById('container'); - - // - - camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500); - camera.position.z = 2750; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x050505); - scene.fog = new THREE.Fog(0x050505, 2000, 3500); - - // - - scene.add(new THREE.AmbientLight(0xcccccc)); - - const light1 = new THREE.DirectionalLight(0xffffff, 1.5); - light1.position.set(1, 1, 1); - scene.add(light1); - - const light2 = new THREE.DirectionalLight(0xffffff, 4.5); - light2.position.set(0, -1, 0); - scene.add(light2); - - // - - const triangles = 500000; - - const geometry = new THREE.BufferGeometry(); - - const positions = []; - const normals = []; - const colors = []; - - const color = new THREE.Color(); - - const n = 800, - n2 = n / 2; // triangles spread in the cube - const d = 12, - d2 = d / 2; // individual triangle size - - const pA = new THREE.Vector3(); - const pB = new THREE.Vector3(); - const pC = new THREE.Vector3(); - - const cb = new THREE.Vector3(); - const ab = new THREE.Vector3(); - - for (let i = 0; i < triangles; i++) { - // positions - - const x = Math.random() * n - n2; - const y = Math.random() * n - n2; - const z = Math.random() * n - n2; - - const ax = x + Math.random() * d - d2; - const ay = y + Math.random() * d - d2; - const az = z + Math.random() * d - d2; - - const bx = x + Math.random() * d - d2; - const by = y + Math.random() * d - d2; - const bz = z + Math.random() * d - d2; - - const cx = x + Math.random() * d - d2; - const cy = y + Math.random() * d - d2; - const cz = z + Math.random() * d - d2; - - positions.push(ax, ay, az); - positions.push(bx, by, bz); - positions.push(cx, cy, cz); - - // flat face normals - - pA.set(ax, ay, az); - pB.set(bx, by, bz); - pC.set(cx, cy, cz); - - cb.subVectors(pC, pB); - ab.subVectors(pA, pB); - cb.cross(ab); - - cb.normalize(); - - const nx = cb.x; - const ny = cb.y; - const nz = cb.z; - - normals.push(nx * 32767, ny * 32767, nz * 32767); - normals.push(nx * 32767, ny * 32767, nz * 32767); - normals.push(nx * 32767, ny * 32767, nz * 32767); - - // colors - - const vx = x / n + 0.5; - const vy = y / n + 0.5; - const vz = z / n + 0.5; - - color.setRGB(vx, vy, vz); - - colors.push(color.r * 255, color.g * 255, color.b * 255); - colors.push(color.r * 255, color.g * 255, color.b * 255); - colors.push(color.r * 255, color.g * 255, color.b * 255); - } - - const positionAttribute = new THREE.Float32BufferAttribute(positions, 3); - const normalAttribute = new THREE.Int16BufferAttribute(normals, 3); - const colorAttribute = new THREE.Uint8BufferAttribute(colors, 3); - - normalAttribute.normalized = true; // this will map the buffer values to 0.0f - +1.0f in the shader - colorAttribute.normalized = true; - - geometry.setAttribute('position', positionAttribute); - geometry.setAttribute('normal', normalAttribute); - geometry.setAttribute('color', colorAttribute); - - geometry.computeBoundingSphere(); - - const material = new THREE.MeshPhongMaterial({ - color: 0xd5d5d5, - specular: 0xffffff, - shininess: 250, - side: THREE.DoubleSide, - vertexColors: true, - }); - - mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - // - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.001; - - mesh.rotation.x = time * 0.25; - mesh.rotation.y = time * 0.5; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_camera.ts b/examples-testing/examples/webgl_camera.ts deleted file mode 100644 index d8319ec26..000000000 --- a/examples-testing/examples/webgl_camera.ts +++ /dev/null @@ -1,214 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let SCREEN_WIDTH = window.innerWidth; -let SCREEN_HEIGHT = window.innerHeight; -let aspect = SCREEN_WIDTH / SCREEN_HEIGHT; - -let container, stats; -let camera, scene, renderer, mesh; -let cameraRig, activeCamera, activeHelper; -let cameraPerspective, cameraOrtho; -let cameraPerspectiveHelper, cameraOrthoHelper; -const frustumSize = 600; - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - scene = new THREE.Scene(); - - // - - camera = new THREE.PerspectiveCamera(50, 0.5 * aspect, 1, 10000); - camera.position.z = 2500; - - cameraPerspective = new THREE.PerspectiveCamera(50, 0.5 * aspect, 150, 1000); - - cameraPerspectiveHelper = new THREE.CameraHelper(cameraPerspective); - scene.add(cameraPerspectiveHelper); - - // - cameraOrtho = new THREE.OrthographicCamera( - (0.5 * frustumSize * aspect) / -2, - (0.5 * frustumSize * aspect) / 2, - frustumSize / 2, - frustumSize / -2, - 150, - 1000, - ); - - cameraOrthoHelper = new THREE.CameraHelper(cameraOrtho); - scene.add(cameraOrthoHelper); - - // - - activeCamera = cameraPerspective; - activeHelper = cameraPerspectiveHelper; - - // counteract different front orientation of cameras vs rig - - cameraOrtho.rotation.y = Math.PI; - cameraPerspective.rotation.y = Math.PI; - - cameraRig = new THREE.Group(); - - cameraRig.add(cameraPerspective); - cameraRig.add(cameraOrtho); - - scene.add(cameraRig); - - // - - mesh = new THREE.Mesh( - new THREE.SphereGeometry(100, 16, 8), - new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }), - ); - scene.add(mesh); - - const mesh2 = new THREE.Mesh( - new THREE.SphereGeometry(50, 16, 8), - new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true }), - ); - mesh2.position.y = 150; - mesh.add(mesh2); - - const mesh3 = new THREE.Mesh( - new THREE.SphereGeometry(5, 16, 8), - new THREE.MeshBasicMaterial({ color: 0x0000ff, wireframe: true }), - ); - mesh3.position.z = 150; - cameraRig.add(mesh3); - - // - - const geometry = new THREE.BufferGeometry(); - const vertices = []; - - for (let i = 0; i < 10000; i++) { - vertices.push(THREE.MathUtils.randFloatSpread(2000)); // x - vertices.push(THREE.MathUtils.randFloatSpread(2000)); // y - vertices.push(THREE.MathUtils.randFloatSpread(2000)); // z - } - - geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); - - const particles = new THREE.Points(geometry, new THREE.PointsMaterial({ color: 0x888888 })); - scene.add(particles); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); - container.appendChild(renderer.domElement); - - renderer.autoClear = false; - - // - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); - document.addEventListener('keydown', onKeyDown); -} - -// - -function onKeyDown(event) { - switch (event.keyCode) { - case 79 /*O*/: - activeCamera = cameraOrtho; - activeHelper = cameraOrthoHelper; - - break; - - case 80 /*P*/: - activeCamera = cameraPerspective; - activeHelper = cameraPerspectiveHelper; - - break; - } -} - -// - -function onWindowResize() { - SCREEN_WIDTH = window.innerWidth; - SCREEN_HEIGHT = window.innerHeight; - aspect = SCREEN_WIDTH / SCREEN_HEIGHT; - - renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); - - camera.aspect = 0.5 * aspect; - camera.updateProjectionMatrix(); - - cameraPerspective.aspect = 0.5 * aspect; - cameraPerspective.updateProjectionMatrix(); - - cameraOrtho.left = (-0.5 * frustumSize * aspect) / 2; - cameraOrtho.right = (0.5 * frustumSize * aspect) / 2; - cameraOrtho.top = frustumSize / 2; - cameraOrtho.bottom = -frustumSize / 2; - cameraOrtho.updateProjectionMatrix(); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const r = Date.now() * 0.0005; - - mesh.position.x = 700 * Math.cos(r); - mesh.position.z = 700 * Math.sin(r); - mesh.position.y = 700 * Math.sin(r); - - mesh.children[0].position.x = 70 * Math.cos(2 * r); - mesh.children[0].position.z = 70 * Math.sin(r); - - if (activeCamera === cameraPerspective) { - cameraPerspective.fov = 35 + 30 * Math.sin(0.5 * r); - cameraPerspective.far = mesh.position.length(); - cameraPerspective.updateProjectionMatrix(); - - cameraPerspectiveHelper.update(); - cameraPerspectiveHelper.visible = true; - - cameraOrthoHelper.visible = false; - } else { - cameraOrtho.far = mesh.position.length(); - cameraOrtho.updateProjectionMatrix(); - - cameraOrthoHelper.update(); - cameraOrthoHelper.visible = true; - - cameraPerspectiveHelper.visible = false; - } - - cameraRig.lookAt(mesh.position); - - renderer.clear(); - - activeHelper.visible = false; - - renderer.setViewport(0, 0, SCREEN_WIDTH / 2, SCREEN_HEIGHT); - renderer.render(scene, activeCamera); - - activeHelper.visible = true; - - renderer.setViewport(SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2, SCREEN_HEIGHT); - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts b/examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts deleted file mode 100644 index a80cc19e9..000000000 --- a/examples-testing/examples/webgl_camera_logarithmicdepthbuffer.ts +++ /dev/null @@ -1,248 +0,0 @@ -import * as THREE from 'three'; - -import { FontLoader } from 'three/addons/loaders/FontLoader.js'; -import { TextGeometry } from 'three/addons/geometries/TextGeometry.js'; - -import Stats from 'three/addons/libs/stats.module.js'; - -// 1 micrometer to 100 billion light years in one scene, with 1 unit = 1 meter? preposterous! and yet... -const NEAR = 1e-6, - FAR = 1e27; -let SCREEN_WIDTH = window.innerWidth; -let SCREEN_HEIGHT = window.innerHeight; -let screensplit = 0.25, - screensplit_right = 0; -const mouse = [0.5, 0.5]; -let zoompos = -100, - minzoomspeed = 0.015; -let zoomspeed = minzoomspeed; - -let container, border, stats; -const objects = {}; - -// Generate a number of text labels, from 1µm in size up to 100,000,000 light years -// Try to use some descriptive real-world examples of objects at each scale - -const labeldata = [ - { size: 0.01, scale: 0.0001, label: 'microscopic (1µm)' }, // FIXME - triangulating text fails at this size, so we scale instead - { size: 0.01, scale: 0.1, label: 'minuscule (1mm)' }, - { size: 0.01, scale: 1.0, label: 'tiny (1cm)' }, - { size: 1, scale: 1.0, label: 'child-sized (1m)' }, - { size: 10, scale: 1.0, label: 'tree-sized (10m)' }, - { size: 100, scale: 1.0, label: 'building-sized (100m)' }, - { size: 1000, scale: 1.0, label: 'medium (1km)' }, - { size: 10000, scale: 1.0, label: 'city-sized (10km)' }, - { size: 3400000, scale: 1.0, label: 'moon-sized (3,400 Km)' }, - { size: 12000000, scale: 1.0, label: 'planet-sized (12,000 km)' }, - { size: 1400000000, scale: 1.0, label: 'sun-sized (1,400,000 km)' }, - { size: 7.47e12, scale: 1.0, label: 'solar system-sized (50Au)' }, - { size: 9.4605284e15, scale: 1.0, label: 'gargantuan (1 light year)' }, - { size: 3.08567758e16, scale: 1.0, label: 'ludicrous (1 parsec)' }, - { size: 1e19, scale: 1.0, label: 'mind boggling (1000 light years)' }, -]; - -init(); - -function init() { - container = document.getElementById('container'); - - const loader = new FontLoader(); - loader.load('fonts/helvetiker_regular.typeface.json', function (font) { - const scene = initScene(font); - - // Initialize two copies of the same scene, one with normal z-buffer and one with logarithmic z-buffer - objects.normal = initView(scene, 'normal', false); - objects.logzbuf = initView(scene, 'logzbuf', true); - - animate(); - }); - - stats = new Stats(); - container.appendChild(stats.dom); - - // Resize border allows the user to easily compare effects of logarithmic depth buffer over the whole scene - border = document.getElementById('renderer_border'); - border.addEventListener('pointerdown', onBorderPointerDown); - - window.addEventListener('mousemove', onMouseMove); - window.addEventListener('resize', onWindowResize); - window.addEventListener('wheel', onMouseWheel); -} - -function initView(scene, name, logDepthBuf) { - const framecontainer = document.getElementById('container_' + name); - - const camera = new THREE.PerspectiveCamera(50, (screensplit * SCREEN_WIDTH) / SCREEN_HEIGHT, NEAR, FAR); - scene.add(camera); - - const renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: logDepthBuf }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(SCREEN_WIDTH / 2, SCREEN_HEIGHT); - renderer.domElement.style.position = 'relative'; - renderer.domElement.id = 'renderer_' + name; - framecontainer.appendChild(renderer.domElement); - - return { container: framecontainer, renderer: renderer, scene: scene, camera: camera }; -} - -function initScene(font) { - const scene = new THREE.Scene(); - - scene.add(new THREE.AmbientLight(0x777777)); - - const light = new THREE.DirectionalLight(0xffffff, 3); - light.position.set(100, 100, 100); - scene.add(light); - - const materialargs = { - color: 0xffffff, - specular: 0x050505, - shininess: 50, - emissive: 0x000000, - }; - - const geometry = new THREE.SphereGeometry(0.5, 24, 12); - - for (let i = 0; i < labeldata.length; i++) { - const scale = labeldata[i].scale || 1; - - const labelgeo = new TextGeometry(labeldata[i].label, { - font: font, - size: labeldata[i].size, - height: labeldata[i].size / 2, - }); - - labelgeo.computeBoundingSphere(); - - // center text - labelgeo.translate(-labelgeo.boundingSphere.radius, 0, 0); - - materialargs.color = new THREE.Color().setHSL(Math.random(), 0.5, 0.5); - - const material = new THREE.MeshPhongMaterial(materialargs); - - const group = new THREE.Group(); - group.position.z = -labeldata[i].size * scale; - scene.add(group); - - const textmesh = new THREE.Mesh(labelgeo, material); - textmesh.scale.set(scale, scale, scale); - textmesh.position.z = -labeldata[i].size * scale; - textmesh.position.y = (labeldata[i].size / 4) * scale; - group.add(textmesh); - - const dotmesh = new THREE.Mesh(geometry, material); - dotmesh.position.y = (-labeldata[i].size / 4) * scale; - dotmesh.scale.multiplyScalar(labeldata[i].size * scale); - group.add(dotmesh); - } - - return scene; -} - -function updateRendererSizes() { - // Recalculate size for both renderers when screen size or split location changes - - SCREEN_WIDTH = window.innerWidth; - SCREEN_HEIGHT = window.innerHeight; - - screensplit_right = 1 - screensplit; - - objects.normal.renderer.setSize(screensplit * SCREEN_WIDTH, SCREEN_HEIGHT); - objects.normal.camera.aspect = (screensplit * SCREEN_WIDTH) / SCREEN_HEIGHT; - objects.normal.camera.updateProjectionMatrix(); - objects.normal.camera.setViewOffset(SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, SCREEN_WIDTH * screensplit, SCREEN_HEIGHT); - objects.normal.container.style.width = screensplit * 100 + '%'; - - objects.logzbuf.renderer.setSize(screensplit_right * SCREEN_WIDTH, SCREEN_HEIGHT); - objects.logzbuf.camera.aspect = (screensplit_right * SCREEN_WIDTH) / SCREEN_HEIGHT; - objects.logzbuf.camera.updateProjectionMatrix(); - objects.logzbuf.camera.setViewOffset( - SCREEN_WIDTH, - SCREEN_HEIGHT, - SCREEN_WIDTH * screensplit, - 0, - SCREEN_WIDTH * screensplit_right, - SCREEN_HEIGHT, - ); - objects.logzbuf.container.style.width = screensplit_right * 100 + '%'; - - border.style.left = screensplit * 100 + '%'; -} - -function animate() { - requestAnimationFrame(animate); - render(); -} - -function render() { - // Put some limits on zooming - const minzoom = labeldata[0].size * labeldata[0].scale * 1; - const maxzoom = labeldata[labeldata.length - 1].size * labeldata[labeldata.length - 1].scale * 100; - let damping = Math.abs(zoomspeed) > minzoomspeed ? 0.95 : 1.0; - - // Zoom out faster the further out you go - const zoom = THREE.MathUtils.clamp(Math.pow(Math.E, zoompos), minzoom, maxzoom); - zoompos = Math.log(zoom); - - // Slow down quickly at the zoom limits - if ((zoom == minzoom && zoomspeed < 0) || (zoom == maxzoom && zoomspeed > 0)) { - damping = 0.85; - } - - zoompos += zoomspeed; - zoomspeed *= damping; - - objects.normal.camera.position.x = Math.sin(0.5 * Math.PI * (mouse[0] - 0.5)) * zoom; - objects.normal.camera.position.y = Math.sin(0.25 * Math.PI * (mouse[1] - 0.5)) * zoom; - objects.normal.camera.position.z = Math.cos(0.5 * Math.PI * (mouse[0] - 0.5)) * zoom; - objects.normal.camera.lookAt(objects.normal.scene.position); - - // Clone camera settings across both scenes - objects.logzbuf.camera.position.copy(objects.normal.camera.position); - objects.logzbuf.camera.quaternion.copy(objects.normal.camera.quaternion); - - // Update renderer sizes if the split has changed - if (screensplit_right != 1 - screensplit) { - updateRendererSizes(); - } - - objects.normal.renderer.render(objects.normal.scene, objects.normal.camera); - objects.logzbuf.renderer.render(objects.logzbuf.scene, objects.logzbuf.camera); - - stats.update(); -} - -function onWindowResize() { - updateRendererSizes(); -} - -function onBorderPointerDown() { - // activate draggable window resizing bar - window.addEventListener('pointermove', onBorderPointerMove); - window.addEventListener('pointerup', onBorderPointerUp); -} - -function onBorderPointerMove(ev) { - screensplit = Math.max(0, Math.min(1, ev.clientX / window.innerWidth)); -} - -function onBorderPointerUp() { - window.removeEventListener('pointermove', onBorderPointerMove); - window.removeEventListener('pointerup', onBorderPointerUp); -} - -function onMouseMove(ev) { - mouse[0] = ev.clientX / window.innerWidth; - mouse[1] = ev.clientY / window.innerHeight; -} - -function onMouseWheel(ev) { - const amount = ev.deltaY; - if (amount === 0) return; - const dir = amount / Math.abs(amount); - zoomspeed = dir / 10; - - // Slow down default zoom speed after user starts zooming, to give them more control - minzoomspeed = 0.001; -} diff --git a/examples-testing/examples/webgl_clipping.ts b/examples-testing/examples/webgl_clipping.ts deleted file mode 100644 index f0a18f3ab..000000000 --- a/examples-testing/examples/webgl_clipping.ts +++ /dev/null @@ -1,184 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -let camera, scene, renderer, startTime, object, stats; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(36, window.innerWidth / window.innerHeight, 0.25, 16); - - camera.position.set(0, 1.3, 3); - - scene = new THREE.Scene(); - - // Lights - - scene.add(new THREE.AmbientLight(0xcccccc)); - - const spotLight = new THREE.SpotLight(0xffffff, 60); - spotLight.angle = Math.PI / 5; - spotLight.penumbra = 0.2; - spotLight.position.set(2, 3, 3); - spotLight.castShadow = true; - spotLight.shadow.camera.near = 3; - spotLight.shadow.camera.far = 10; - spotLight.shadow.mapSize.width = 1024; - spotLight.shadow.mapSize.height = 1024; - scene.add(spotLight); - - const dirLight = new THREE.DirectionalLight(0x55505a, 3); - dirLight.position.set(0, 3, 0); - dirLight.castShadow = true; - dirLight.shadow.camera.near = 1; - dirLight.shadow.camera.far = 10; - - dirLight.shadow.camera.right = 1; - dirLight.shadow.camera.left = -1; - dirLight.shadow.camera.top = 1; - dirLight.shadow.camera.bottom = -1; - - dirLight.shadow.mapSize.width = 1024; - dirLight.shadow.mapSize.height = 1024; - scene.add(dirLight); - - // ***** Clipping planes: ***** - - const localPlane = new THREE.Plane(new THREE.Vector3(0, -1, 0), 0.8); - const globalPlane = new THREE.Plane(new THREE.Vector3(-1, 0, 0), 0.1); - - // Geometry - - const material = new THREE.MeshPhongMaterial({ - color: 0x80ee10, - shininess: 100, - side: THREE.DoubleSide, - - // ***** Clipping setup (material): ***** - clippingPlanes: [localPlane], - clipShadows: true, - }); - - const geometry = new THREE.TorusKnotGeometry(0.4, 0.08, 95, 20); - - object = new THREE.Mesh(geometry, material); - object.castShadow = true; - scene.add(object); - - const ground = new THREE.Mesh( - new THREE.PlaneGeometry(9, 9, 1, 1), - new THREE.MeshPhongMaterial({ color: 0xa0adaf, shininess: 150 }), - ); - - ground.rotation.x = -Math.PI / 2; // rotates X/Y to X/Z - ground.receiveShadow = true; - scene.add(ground); - - // Stats - - stats = new Stats(); - document.body.appendChild(stats.dom); - - // Renderer - - renderer = new THREE.WebGLRenderer(); - renderer.shadowMap.enabled = true; - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - window.addEventListener('resize', onWindowResize); - document.body.appendChild(renderer.domElement); - - // ***** Clipping setup (renderer): ***** - const globalPlanes = [globalPlane], - Empty = Object.freeze([]); - renderer.clippingPlanes = Empty; // GUI sets it to globalPlanes - renderer.localClippingEnabled = true; - - // Controls - - const controls = new OrbitControls(camera, renderer.domElement); - controls.target.set(0, 1, 0); - controls.update(); - - // GUI - - const gui = new GUI(), - folderLocal = gui.addFolder('Local Clipping'), - propsLocal = { - get Enabled() { - return renderer.localClippingEnabled; - }, - set Enabled(v) { - renderer.localClippingEnabled = v; - }, - - get Shadows() { - return material.clipShadows; - }, - set Shadows(v) { - material.clipShadows = v; - }, - - get Plane() { - return localPlane.constant; - }, - set Plane(v) { - localPlane.constant = v; - }, - }, - folderGlobal = gui.addFolder('Global Clipping'), - propsGlobal = { - get Enabled() { - return renderer.clippingPlanes !== Empty; - }, - set Enabled(v) { - renderer.clippingPlanes = v ? globalPlanes : Empty; - }, - - get Plane() { - return globalPlane.constant; - }, - set Plane(v) { - globalPlane.constant = v; - }, - }; - - folderLocal.add(propsLocal, 'Enabled'); - folderLocal.add(propsLocal, 'Shadows'); - folderLocal.add(propsLocal, 'Plane', 0.3, 1.25); - - folderGlobal.add(propsGlobal, 'Enabled'); - folderGlobal.add(propsGlobal, 'Plane', -0.4, 3); - - // Start - - startTime = Date.now(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - const currentTime = Date.now(); - const time = (currentTime - startTime) / 1000; - - requestAnimationFrame(animate); - - object.position.y = 0.8; - object.rotation.x = time * 0.5; - object.rotation.y = time * 0.2; - object.scale.setScalar(Math.cos(time) * 0.125 + 0.875); - - stats.begin(); - renderer.render(scene, camera); - stats.end(); -} diff --git a/examples-testing/examples/webgl_clipping_advanced.ts b/examples-testing/examples/webgl_clipping_advanced.ts deleted file mode 100644 index d60532ca2..000000000 --- a/examples-testing/examples/webgl_clipping_advanced.ts +++ /dev/null @@ -1,356 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -function planesFromMesh(vertices, indices) { - // creates a clipping volume from a convex triangular mesh - // specified by the arrays 'vertices' and 'indices' - - const n = indices.length / 3, - result = new Array(n); - - for (let i = 0, j = 0; i < n; ++i, j += 3) { - const a = vertices[indices[j]], - b = vertices[indices[j + 1]], - c = vertices[indices[j + 2]]; - - result[i] = new THREE.Plane().setFromCoplanarPoints(a, b, c); - } - - return result; -} - -function createPlanes(n) { - // creates an array of n uninitialized plane objects - - const result = new Array(n); - - for (let i = 0; i !== n; ++i) result[i] = new THREE.Plane(); - - return result; -} - -function assignTransformedPlanes(planesOut, planesIn, matrix) { - // sets an array of existing planes to transformed 'planesIn' - - for (let i = 0, n = planesIn.length; i !== n; ++i) planesOut[i].copy(planesIn[i]).applyMatrix4(matrix); -} - -function cylindricalPlanes(n, innerRadius) { - const result = createPlanes(n); - - for (let i = 0; i !== n; ++i) { - const plane = result[i], - angle = (i * Math.PI * 2) / n; - - plane.normal.set(Math.cos(angle), 0, Math.sin(angle)); - - plane.constant = innerRadius; - } - - return result; -} - -const planeToMatrix = (function () { - // creates a matrix that aligns X/Y to a given plane - - // temporaries: - const xAxis = new THREE.Vector3(), - yAxis = new THREE.Vector3(), - trans = new THREE.Vector3(); - - return function planeToMatrix(plane) { - const zAxis = plane.normal, - matrix = new THREE.Matrix4(); - - // Hughes & Moeller '99 - // "Building an Orthonormal Basis from a Unit Vector." - - if (Math.abs(zAxis.x) > Math.abs(zAxis.z)) { - yAxis.set(-zAxis.y, zAxis.x, 0); - } else { - yAxis.set(0, -zAxis.z, zAxis.y); - } - - xAxis.crossVectors(yAxis.normalize(), zAxis); - - plane.coplanarPoint(trans); - return matrix.set( - xAxis.x, - yAxis.x, - zAxis.x, - trans.x, - xAxis.y, - yAxis.y, - zAxis.y, - trans.y, - xAxis.z, - yAxis.z, - zAxis.z, - trans.z, - 0, - 0, - 0, - 1, - ); - }; -})(); - -// A regular tetrahedron for the clipping volume: - -const Vertices = [ - new THREE.Vector3(+1, 0, +Math.SQRT1_2), - new THREE.Vector3(-1, 0, +Math.SQRT1_2), - new THREE.Vector3(0, +1, -Math.SQRT1_2), - new THREE.Vector3(0, -1, -Math.SQRT1_2), - ], - Indices = [0, 1, 2, 0, 2, 3, 0, 3, 1, 1, 3, 2], - Planes = planesFromMesh(Vertices, Indices), - PlaneMatrices = Planes.map(planeToMatrix), - GlobalClippingPlanes = cylindricalPlanes(5, 2.5), - Empty = Object.freeze([]); - -let camera, scene, renderer, startTime, stats, object, clipMaterial, volumeVisualization, globalClippingPlanes; - -function init() { - camera = new THREE.PerspectiveCamera(36, window.innerWidth / window.innerHeight, 0.25, 16); - - camera.position.set(0, 1.5, 3); - - scene = new THREE.Scene(); - - // Lights - - scene.add(new THREE.AmbientLight(0xffffff)); - - const spotLight = new THREE.SpotLight(0xffffff, 60); - spotLight.angle = Math.PI / 5; - spotLight.penumbra = 0.2; - spotLight.position.set(2, 3, 3); - spotLight.castShadow = true; - spotLight.shadow.camera.near = 3; - spotLight.shadow.camera.far = 10; - spotLight.shadow.mapSize.width = 1024; - spotLight.shadow.mapSize.height = 1024; - scene.add(spotLight); - - const dirLight = new THREE.DirectionalLight(0xffffff, 1.5); - dirLight.position.set(0, 2, 0); - dirLight.castShadow = true; - dirLight.shadow.camera.near = 1; - dirLight.shadow.camera.far = 10; - - dirLight.shadow.camera.right = 1; - dirLight.shadow.camera.left = -1; - dirLight.shadow.camera.top = 1; - dirLight.shadow.camera.bottom = -1; - - dirLight.shadow.mapSize.width = 1024; - dirLight.shadow.mapSize.height = 1024; - scene.add(dirLight); - - // Geometry - - clipMaterial = new THREE.MeshPhongMaterial({ - color: 0xee0a10, - shininess: 100, - side: THREE.DoubleSide, - // Clipping setup: - clippingPlanes: createPlanes(Planes.length), - clipShadows: true, - }); - - object = new THREE.Group(); - - const geometry = new THREE.BoxGeometry(0.18, 0.18, 0.18); - - for (let z = -2; z <= 2; ++z) - for (let y = -2; y <= 2; ++y) - for (let x = -2; x <= 2; ++x) { - const mesh = new THREE.Mesh(geometry, clipMaterial); - mesh.position.set(x / 5, y / 5, z / 5); - mesh.castShadow = true; - object.add(mesh); - } - - scene.add(object); - - const planeGeometry = new THREE.PlaneGeometry(3, 3, 1, 1), - color = new THREE.Color(); - - volumeVisualization = new THREE.Group(); - volumeVisualization.visible = false; - - for (let i = 0, n = Planes.length; i !== n; ++i) { - const material = new THREE.MeshBasicMaterial({ - color: color.setHSL(i / n, 0.5, 0.5).getHex(), - side: THREE.DoubleSide, - - opacity: 0.2, - transparent: true, - - // clip to the others to show the volume (wildly - // intersecting transparent planes look bad) - clippingPlanes: clipMaterial.clippingPlanes.filter(function (_, j) { - return j !== i; - }), - - // no need to enable shadow clipping - the plane - // visualization does not cast shadows - }); - - const mesh = new THREE.Mesh(planeGeometry, material); - mesh.matrixAutoUpdate = false; - - volumeVisualization.add(mesh); - } - - scene.add(volumeVisualization); - - const ground = new THREE.Mesh( - planeGeometry, - new THREE.MeshPhongMaterial({ - color: 0xa0adaf, - shininess: 10, - }), - ); - ground.rotation.x = -Math.PI / 2; - ground.scale.multiplyScalar(3); - ground.receiveShadow = true; - scene.add(ground); - - // Renderer - - const container = document.body; - - renderer = new THREE.WebGLRenderer(); - renderer.shadowMap.enabled = true; - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - window.addEventListener('resize', onWindowResize); - container.appendChild(renderer.domElement); - // Clipping setup: - globalClippingPlanes = createPlanes(GlobalClippingPlanes.length); - renderer.clippingPlanes = Empty; - renderer.localClippingEnabled = true; - - // Stats - - stats = new Stats(); - container.appendChild(stats.dom); - - // Controls - - const controls = new OrbitControls(camera, renderer.domElement); - controls.minDistance = 1; - controls.maxDistance = 8; - controls.target.set(0, 1, 0); - controls.update(); - - // GUI - - const gui = new GUI(), - folder = gui.addFolder('Local Clipping'), - props = { - get Enabled() { - return renderer.localClippingEnabled; - }, - set Enabled(v) { - renderer.localClippingEnabled = v; - if (!v) volumeVisualization.visible = false; - }, - - get Shadows() { - return clipMaterial.clipShadows; - }, - set Shadows(v) { - clipMaterial.clipShadows = v; - }, - - get Visualize() { - return volumeVisualization.visible; - }, - set Visualize(v) { - if (renderer.localClippingEnabled) volumeVisualization.visible = v; - }, - }; - - folder.add(props, 'Enabled'); - folder.add(props, 'Shadows'); - folder.add(props, 'Visualize').listen(); - - gui.addFolder('Global Clipping').add( - { - get Enabled() { - return renderer.clippingPlanes !== Empty; - }, - set Enabled(v) { - renderer.clippingPlanes = v ? globalClippingPlanes : Empty; - }, - }, - 'Enabled', - ); - - // Start - - startTime = Date.now(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function setObjectWorldMatrix(object, matrix) { - // set the orientation of an object based on a world matrix - - const parent = object.parent; - scene.updateMatrixWorld(); - object.matrix.copy(parent.matrixWorld).invert(); - object.applyMatrix4(matrix); -} - -const transform = new THREE.Matrix4(), - tmpMatrix = new THREE.Matrix4(); - -function animate() { - const currentTime = Date.now(), - time = (currentTime - startTime) / 1000; - - requestAnimationFrame(animate); - - object.position.y = 1; - object.rotation.x = time * 0.5; - object.rotation.y = time * 0.2; - - object.updateMatrix(); - transform.copy(object.matrix); - - const bouncy = Math.cos(time * 0.5) * 0.5 + 0.7; - transform.multiply(tmpMatrix.makeScale(bouncy, bouncy, bouncy)); - - assignTransformedPlanes(clipMaterial.clippingPlanes, Planes, transform); - - const planeMeshes = volumeVisualization.children; - - for (let i = 0, n = planeMeshes.length; i !== n; ++i) { - tmpMatrix.multiplyMatrices(transform, PlaneMatrices[i]); - setObjectWorldMatrix(planeMeshes[i], tmpMatrix); - } - - transform.makeRotationY(time * 0.1); - - assignTransformedPlanes(globalClippingPlanes, GlobalClippingPlanes, transform); - - stats.begin(); - renderer.render(scene, camera); - stats.end(); -} - -init(); -animate(); diff --git a/examples-testing/examples/webgl_clipping_intersection.ts b/examples-testing/examples/webgl_clipping_intersection.ts deleted file mode 100644 index 74022d774..000000000 --- a/examples-testing/examples/webgl_clipping_intersection.ts +++ /dev/null @@ -1,126 +0,0 @@ -import * as THREE from 'three'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -let camera, scene, renderer; - -const params = { - clipIntersection: true, - planeConstant: 0, - showHelpers: false, -}; - -const clipPlanes = [ - new THREE.Plane(new THREE.Vector3(1, 0, 0), 0), - new THREE.Plane(new THREE.Vector3(0, -1, 0), 0), - new THREE.Plane(new THREE.Vector3(0, 0, -1), 0), -]; - -init(); -render(); - -function init() { - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.localClippingEnabled = true; - document.body.appendChild(renderer.domElement); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 200); - - camera.position.set(-1.5, 2.5, 3.0); - - const controls = new OrbitControls(camera, renderer.domElement); - controls.addEventListener('change', render); // use only if there is no animation loop - controls.minDistance = 1; - controls.maxDistance = 10; - controls.enablePan = false; - - const light = new THREE.HemisphereLight(0xffffff, 0x080808, 4.5); - light.position.set(-1.25, 1, 1.25); - scene.add(light); - - // - - const group = new THREE.Group(); - - for (let i = 1; i <= 30; i += 2) { - const geometry = new THREE.SphereGeometry(i / 30, 48, 24); - - const material = new THREE.MeshLambertMaterial({ - color: new THREE.Color().setHSL(Math.random(), 0.5, 0.5, THREE.SRGBColorSpace), - side: THREE.DoubleSide, - clippingPlanes: clipPlanes, - clipIntersection: params.clipIntersection, - }); - - group.add(new THREE.Mesh(geometry, material)); - } - - scene.add(group); - - // helpers - - const helpers = new THREE.Group(); - helpers.add(new THREE.PlaneHelper(clipPlanes[0], 2, 0xff0000)); - helpers.add(new THREE.PlaneHelper(clipPlanes[1], 2, 0x00ff00)); - helpers.add(new THREE.PlaneHelper(clipPlanes[2], 2, 0x0000ff)); - helpers.visible = false; - scene.add(helpers); - - // gui - - const gui = new GUI(); - - gui.add(params, 'clipIntersection') - .name('clip intersection') - .onChange(function (value) { - const children = group.children; - - for (let i = 0; i < children.length; i++) { - children[i].material.clipIntersection = value; - } - - render(); - }); - - gui.add(params, 'planeConstant', -1, 1) - .step(0.01) - .name('plane constant') - .onChange(function (value) { - for (let j = 0; j < clipPlanes.length; j++) { - clipPlanes[j].constant = value; - } - - render(); - }); - - gui.add(params, 'showHelpers') - .name('show helpers') - .onChange(function (value) { - helpers.visible = value; - - render(); - }); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - render(); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_clipping_stencil.ts b/examples-testing/examples/webgl_clipping_stencil.ts deleted file mode 100644 index 365087d65..000000000 --- a/examples-testing/examples/webgl_clipping_stencil.ts +++ /dev/null @@ -1,260 +0,0 @@ -import * as THREE from 'three'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import Stats from 'three/addons/libs/stats.module.js'; - -let camera, scene, renderer, object, stats; -let planes, planeObjects, planeHelpers; -let clock; - -const params = { - animate: true, - planeX: { - constant: 0, - negated: false, - displayHelper: false, - }, - planeY: { - constant: 0, - negated: false, - displayHelper: false, - }, - planeZ: { - constant: 0, - negated: false, - displayHelper: false, - }, -}; - -init(); -animate(); - -function createPlaneStencilGroup(geometry, plane, renderOrder) { - const group = new THREE.Group(); - const baseMat = new THREE.MeshBasicMaterial(); - baseMat.depthWrite = false; - baseMat.depthTest = false; - baseMat.colorWrite = false; - baseMat.stencilWrite = true; - baseMat.stencilFunc = THREE.AlwaysStencilFunc; - - // back faces - const mat0 = baseMat.clone(); - mat0.side = THREE.BackSide; - mat0.clippingPlanes = [plane]; - mat0.stencilFail = THREE.IncrementWrapStencilOp; - mat0.stencilZFail = THREE.IncrementWrapStencilOp; - mat0.stencilZPass = THREE.IncrementWrapStencilOp; - - const mesh0 = new THREE.Mesh(geometry, mat0); - mesh0.renderOrder = renderOrder; - group.add(mesh0); - - // front faces - const mat1 = baseMat.clone(); - mat1.side = THREE.FrontSide; - mat1.clippingPlanes = [plane]; - mat1.stencilFail = THREE.DecrementWrapStencilOp; - mat1.stencilZFail = THREE.DecrementWrapStencilOp; - mat1.stencilZPass = THREE.DecrementWrapStencilOp; - - const mesh1 = new THREE.Mesh(geometry, mat1); - mesh1.renderOrder = renderOrder; - - group.add(mesh1); - - return group; -} - -function init() { - clock = new THREE.Clock(); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(36, window.innerWidth / window.innerHeight, 1, 100); - camera.position.set(2, 2, 2); - - scene.add(new THREE.AmbientLight(0xffffff, 1.5)); - - const dirLight = new THREE.DirectionalLight(0xffffff, 3); - dirLight.position.set(5, 10, 7.5); - dirLight.castShadow = true; - dirLight.shadow.camera.right = 2; - dirLight.shadow.camera.left = -2; - dirLight.shadow.camera.top = 2; - dirLight.shadow.camera.bottom = -2; - - dirLight.shadow.mapSize.width = 1024; - dirLight.shadow.mapSize.height = 1024; - scene.add(dirLight); - - planes = [ - new THREE.Plane(new THREE.Vector3(-1, 0, 0), 0), - new THREE.Plane(new THREE.Vector3(0, -1, 0), 0), - new THREE.Plane(new THREE.Vector3(0, 0, -1), 0), - ]; - - planeHelpers = planes.map(p => new THREE.PlaneHelper(p, 2, 0xffffff)); - planeHelpers.forEach(ph => { - ph.visible = false; - scene.add(ph); - }); - - const geometry = new THREE.TorusKnotGeometry(0.4, 0.15, 220, 60); - object = new THREE.Group(); - scene.add(object); - - // Set up clip plane rendering - planeObjects = []; - const planeGeom = new THREE.PlaneGeometry(4, 4); - - for (let i = 0; i < 3; i++) { - const poGroup = new THREE.Group(); - const plane = planes[i]; - const stencilGroup = createPlaneStencilGroup(geometry, plane, i + 1); - - // plane is clipped by the other clipping planes - const planeMat = new THREE.MeshStandardMaterial({ - color: 0xe91e63, - metalness: 0.1, - roughness: 0.75, - clippingPlanes: planes.filter(p => p !== plane), - - stencilWrite: true, - stencilRef: 0, - stencilFunc: THREE.NotEqualStencilFunc, - stencilFail: THREE.ReplaceStencilOp, - stencilZFail: THREE.ReplaceStencilOp, - stencilZPass: THREE.ReplaceStencilOp, - }); - const po = new THREE.Mesh(planeGeom, planeMat); - po.onAfterRender = function (renderer) { - renderer.clearStencil(); - }; - - po.renderOrder = i + 1.1; - - object.add(stencilGroup); - poGroup.add(po); - planeObjects.push(po); - scene.add(poGroup); - } - - const material = new THREE.MeshStandardMaterial({ - color: 0xffc107, - metalness: 0.1, - roughness: 0.75, - clippingPlanes: planes, - clipShadows: true, - shadowSide: THREE.DoubleSide, - }); - - // add the color - const clippedColorFront = new THREE.Mesh(geometry, material); - clippedColorFront.castShadow = true; - clippedColorFront.renderOrder = 6; - object.add(clippedColorFront); - - const ground = new THREE.Mesh( - new THREE.PlaneGeometry(9, 9, 1, 1), - new THREE.ShadowMaterial({ color: 0x000000, opacity: 0.25, side: THREE.DoubleSide }), - ); - - ground.rotation.x = -Math.PI / 2; // rotates X/Y to X/Z - ground.position.y = -1; - ground.receiveShadow = true; - scene.add(ground); - - // Stats - stats = new Stats(); - document.body.appendChild(stats.dom); - - // Renderer - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.shadowMap.enabled = true; - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.setClearColor(0x263238); - window.addEventListener('resize', onWindowResize); - document.body.appendChild(renderer.domElement); - - renderer.localClippingEnabled = true; - - // Controls - const controls = new OrbitControls(camera, renderer.domElement); - controls.minDistance = 2; - controls.maxDistance = 20; - controls.update(); - - // GUI - const gui = new GUI(); - gui.add(params, 'animate'); - - const planeX = gui.addFolder('planeX'); - planeX.add(params.planeX, 'displayHelper').onChange(v => (planeHelpers[0].visible = v)); - planeX - .add(params.planeX, 'constant') - .min(-1) - .max(1) - .onChange(d => (planes[0].constant = d)); - planeX.add(params.planeX, 'negated').onChange(() => { - planes[0].negate(); - params.planeX.constant = planes[0].constant; - }); - planeX.open(); - - const planeY = gui.addFolder('planeY'); - planeY.add(params.planeY, 'displayHelper').onChange(v => (planeHelpers[1].visible = v)); - planeY - .add(params.planeY, 'constant') - .min(-1) - .max(1) - .onChange(d => (planes[1].constant = d)); - planeY.add(params.planeY, 'negated').onChange(() => { - planes[1].negate(); - params.planeY.constant = planes[1].constant; - }); - planeY.open(); - - const planeZ = gui.addFolder('planeZ'); - planeZ.add(params.planeZ, 'displayHelper').onChange(v => (planeHelpers[2].visible = v)); - planeZ - .add(params.planeZ, 'constant') - .min(-1) - .max(1) - .onChange(d => (planes[2].constant = d)); - planeZ.add(params.planeZ, 'negated').onChange(() => { - planes[2].negate(); - params.planeZ.constant = planes[2].constant; - }); - planeZ.open(); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - const delta = clock.getDelta(); - - requestAnimationFrame(animate); - - if (params.animate) { - object.rotation.x += delta * 0.5; - object.rotation.y += delta * 0.2; - } - - for (let i = 0; i < planeObjects.length; i++) { - const plane = planes[i]; - const po = planeObjects[i]; - plane.coplanarPoint(po.position); - po.lookAt(po.position.x - plane.normal.x, po.position.y - plane.normal.y, po.position.z - plane.normal.z); - } - - stats.begin(); - renderer.render(scene, camera); - stats.end(); -} diff --git a/examples-testing/examples/webgl_custom_attributes.ts b/examples-testing/examples/webgl_custom_attributes.ts deleted file mode 100644 index 648e097dd..000000000 --- a/examples-testing/examples/webgl_custom_attributes.ts +++ /dev/null @@ -1,102 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let renderer, scene, camera, stats; - -let sphere, uniforms; - -let displacement, noise; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 10000); - camera.position.z = 300; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x050505); - - uniforms = { - amplitude: { value: 1.0 }, - color: { value: new THREE.Color(0xff2200) }, - colorTexture: { value: new THREE.TextureLoader().load('textures/water.jpg') }, - }; - - uniforms['colorTexture'].value.wrapS = uniforms['colorTexture'].value.wrapT = THREE.RepeatWrapping; - - const shaderMaterial = new THREE.ShaderMaterial({ - uniforms: uniforms, - vertexShader: document.getElementById('vertexshader').textContent, - fragmentShader: document.getElementById('fragmentshader').textContent, - }); - - const radius = 50, - segments = 128, - rings = 64; - - const geometry = new THREE.SphereGeometry(radius, segments, rings); - - displacement = new Float32Array(geometry.attributes.position.count); - noise = new Float32Array(geometry.attributes.position.count); - - for (let i = 0; i < displacement.length; i++) { - noise[i] = Math.random() * 5; - } - - geometry.setAttribute('displacement', new THREE.BufferAttribute(displacement, 1)); - - sphere = new THREE.Mesh(geometry, shaderMaterial); - scene.add(sphere); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - - const container = document.getElementById('container'); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.01; - - sphere.rotation.y = sphere.rotation.z = 0.01 * time; - - uniforms['amplitude'].value = 2.5 * Math.sin(sphere.rotation.y * 0.125); - uniforms['color'].value.offsetHSL(0.0005, 0, 0); - - for (let i = 0; i < displacement.length; i++) { - displacement[i] = Math.sin(0.1 * i + time); - - noise[i] += 0.5 * (0.5 - Math.random()); - noise[i] = THREE.MathUtils.clamp(noise[i], -5, 5); - - displacement[i] += noise[i]; - } - - sphere.geometry.attributes.displacement.needsUpdate = true; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_custom_attributes_lines.ts b/examples-testing/examples/webgl_custom_attributes_lines.ts deleted file mode 100644 index 29b8a0645..000000000 --- a/examples-testing/examples/webgl_custom_attributes_lines.ts +++ /dev/null @@ -1,123 +0,0 @@ -import * as THREE from 'three'; - -import { FontLoader } from 'three/addons/loaders/FontLoader.js'; -import { TextGeometry } from 'three/addons/geometries/TextGeometry.js'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let renderer, scene, camera, stats; - -let line, uniforms; - -const loader = new FontLoader(); -loader.load('fonts/helvetiker_bold.typeface.json', function (font) { - init(font); - animate(); -}); - -function init(font) { - camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 10000); - camera.position.z = 400; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x050505); - - uniforms = { - amplitude: { value: 5.0 }, - opacity: { value: 0.3 }, - color: { value: new THREE.Color(0xffffff) }, - }; - - const shaderMaterial = new THREE.ShaderMaterial({ - uniforms: uniforms, - vertexShader: document.getElementById('vertexshader').textContent, - fragmentShader: document.getElementById('fragmentshader').textContent, - blending: THREE.AdditiveBlending, - depthTest: false, - transparent: true, - }); - - const geometry = new TextGeometry('three.js', { - font: font, - - size: 50, - height: 15, - curveSegments: 10, - - bevelThickness: 5, - bevelSize: 1.5, - bevelEnabled: true, - bevelSegments: 10, - }); - - geometry.center(); - - const count = geometry.attributes.position.count; - - const displacement = new THREE.Float32BufferAttribute(count * 3, 3); - geometry.setAttribute('displacement', displacement); - - const customColor = new THREE.Float32BufferAttribute(count * 3, 3); - geometry.setAttribute('customColor', customColor); - - const color = new THREE.Color(0xffffff); - - for (let i = 0, l = customColor.count; i < l; i++) { - color.setHSL(i / l, 0.5, 0.5); - color.toArray(customColor.array, i * customColor.itemSize); - } - - line = new THREE.Line(geometry, shaderMaterial); - line.rotation.x = 0.2; - scene.add(line); - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - - const container = document.getElementById('container'); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.001; - - line.rotation.y = 0.25 * time; - - uniforms.amplitude.value = Math.sin(0.5 * time); - uniforms.color.value.offsetHSL(0.0005, 0, 0); - - const attributes = line.geometry.attributes; - const array = attributes.displacement.array; - - for (let i = 0, l = array.length; i < l; i += 3) { - array[i] += 0.3 * (0.5 - Math.random()); - array[i + 1] += 0.3 * (0.5 - Math.random()); - array[i + 2] += 0.3 * (0.5 - Math.random()); - } - - attributes.displacement.needsUpdate = true; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_custom_attributes_points.ts b/examples-testing/examples/webgl_custom_attributes_points.ts deleted file mode 100644 index f1cfedc09..000000000 --- a/examples-testing/examples/webgl_custom_attributes_points.ts +++ /dev/null @@ -1,119 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let renderer, scene, camera, stats; - -let sphere; - -const WIDTH = window.innerWidth; -const HEIGHT = window.innerHeight; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(40, WIDTH / HEIGHT, 1, 10000); - camera.position.z = 300; - - scene = new THREE.Scene(); - - const amount = 100000; - const radius = 200; - - const positions = new Float32Array(amount * 3); - const colors = new Float32Array(amount * 3); - const sizes = new Float32Array(amount); - - const vertex = new THREE.Vector3(); - const color = new THREE.Color(0xffffff); - - for (let i = 0; i < amount; i++) { - vertex.x = (Math.random() * 2 - 1) * radius; - vertex.y = (Math.random() * 2 - 1) * radius; - vertex.z = (Math.random() * 2 - 1) * radius; - vertex.toArray(positions, i * 3); - - if (vertex.x < 0) { - color.setHSL(0.5 + 0.1 * (i / amount), 0.7, 0.5); - } else { - color.setHSL(0.0 + 0.1 * (i / amount), 0.9, 0.5); - } - - color.toArray(colors, i * 3); - - sizes[i] = 10; - } - - const geometry = new THREE.BufferGeometry(); - geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); - geometry.setAttribute('customColor', new THREE.BufferAttribute(colors, 3)); - geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1)); - - // - - const material = new THREE.ShaderMaterial({ - uniforms: { - color: { value: new THREE.Color(0xffffff) }, - pointTexture: { value: new THREE.TextureLoader().load('textures/sprites/spark1.png') }, - }, - vertexShader: document.getElementById('vertexshader').textContent, - fragmentShader: document.getElementById('fragmentshader').textContent, - - blending: THREE.AdditiveBlending, - depthTest: false, - transparent: true, - }); - - // - - sphere = new THREE.Points(geometry, material); - scene.add(sphere); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(WIDTH, HEIGHT); - - const container = document.getElementById('container'); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.005; - - sphere.rotation.z = 0.01 * time; - - const geometry = sphere.geometry; - const attributes = geometry.attributes; - - for (let i = 0; i < attributes.size.array.length; i++) { - attributes.size.array[i] = 14 + 13 * Math.sin(0.1 * i + time); - } - - attributes.size.needsUpdate = true; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_custom_attributes_points2.ts b/examples-testing/examples/webgl_custom_attributes_points2.ts deleted file mode 100644 index f744a1eb1..000000000 --- a/examples-testing/examples/webgl_custom_attributes_points2.ts +++ /dev/null @@ -1,195 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'; - -let renderer, scene, camera, stats; -let sphere, length1; - -const WIDTH = window.innerWidth; -const HEIGHT = window.innerHeight; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(45, WIDTH / HEIGHT, 1, 10000); - camera.position.z = 300; - - scene = new THREE.Scene(); - - const radius = 100, - segments = 68, - rings = 38; - - let sphereGeometry = new THREE.SphereGeometry(radius, segments, rings); - let boxGeometry = new THREE.BoxGeometry(0.8 * radius, 0.8 * radius, 0.8 * radius, 10, 10, 10); - - // if normal and uv attributes are not removed, mergeVertices() can't consolidate identical vertices with different normal/uv data - - sphereGeometry.deleteAttribute('normal'); - sphereGeometry.deleteAttribute('uv'); - - boxGeometry.deleteAttribute('normal'); - boxGeometry.deleteAttribute('uv'); - - sphereGeometry = BufferGeometryUtils.mergeVertices(sphereGeometry); - boxGeometry = BufferGeometryUtils.mergeVertices(boxGeometry); - - const combinedGeometry = BufferGeometryUtils.mergeGeometries([sphereGeometry, boxGeometry]); - const positionAttribute = combinedGeometry.getAttribute('position'); - - const colors = []; - const sizes = []; - - const color = new THREE.Color(); - const vertex = new THREE.Vector3(); - - length1 = sphereGeometry.getAttribute('position').count; - - for (let i = 0, l = positionAttribute.count; i < l; i++) { - vertex.fromBufferAttribute(positionAttribute, i); - - if (i < length1) { - color.setHSL(0.01 + 0.1 * (i / length1), 0.99, (vertex.y + radius) / (4 * radius)); - } else { - color.setHSL(0.6, 0.75, 0.25 + vertex.y / (2 * radius)); - } - - color.toArray(colors, i * 3); - - sizes[i] = i < length1 ? 10 : 40; - } - - const geometry = new THREE.BufferGeometry(); - geometry.setAttribute('position', positionAttribute); - geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1)); - geometry.setAttribute('ca', new THREE.Float32BufferAttribute(colors, 3)); - - // - - const texture = new THREE.TextureLoader().load('textures/sprites/disc.png'); - texture.wrapS = THREE.RepeatWrapping; - texture.wrapT = THREE.RepeatWrapping; - - const material = new THREE.ShaderMaterial({ - uniforms: { - color: { value: new THREE.Color(0xffffff) }, - pointTexture: { value: texture }, - }, - vertexShader: document.getElementById('vertexshader').textContent, - fragmentShader: document.getElementById('fragmentshader').textContent, - transparent: true, - }); - - // - - sphere = new THREE.Points(geometry, material); - scene.add(sphere); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(WIDTH, HEIGHT); - - const container = document.getElementById('container'); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function sortPoints() { - const vector = new THREE.Vector3(); - - // Model View Projection matrix - - const matrix = new THREE.Matrix4(); - matrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); - matrix.multiply(sphere.matrixWorld); - - // - - const geometry = sphere.geometry; - - let index = geometry.getIndex(); - const positions = geometry.getAttribute('position').array; - const length = positions.length / 3; - - if (index === null) { - const array = new Uint16Array(length); - - for (let i = 0; i < length; i++) { - array[i] = i; - } - - index = new THREE.BufferAttribute(array, 1); - - geometry.setIndex(index); - } - - const sortArray = []; - - for (let i = 0; i < length; i++) { - vector.fromArray(positions, i * 3); - vector.applyMatrix4(matrix); - - sortArray.push([vector.z, i]); - } - - function numericalSort(a, b) { - return b[0] - a[0]; - } - - sortArray.sort(numericalSort); - - const indices = index.array; - - for (let i = 0; i < length; i++) { - indices[i] = sortArray[i][1]; - } - - geometry.index.needsUpdate = true; -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.005; - - sphere.rotation.y = 0.02 * time; - sphere.rotation.z = 0.02 * time; - - const geometry = sphere.geometry; - const attributes = geometry.attributes; - - for (let i = 0; i < attributes.size.array.length; i++) { - if (i < length1) { - attributes.size.array[i] = 16 + 12 * Math.sin(0.1 * i + time); - } - } - - attributes.size.needsUpdate = true; - - sortPoints(); - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_custom_attributes_points3.ts b/examples-testing/examples/webgl_custom_attributes_points3.ts deleted file mode 100644 index 1ef2f1f82..000000000 --- a/examples-testing/examples/webgl_custom_attributes_points3.ts +++ /dev/null @@ -1,202 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'; - -let renderer, scene, camera, stats; - -let object; - -let vertices1; - -const WIDTH = window.innerWidth; -const HEIGHT = window.innerHeight; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(40, WIDTH / HEIGHT, 1, 1000); - camera.position.z = 500; - - scene = new THREE.Scene(); - - let radius = 100; - const inner = 0.6 * radius; - const vertex = new THREE.Vector3(); - const vertices = []; - - for (let i = 0; i < 100000; i++) { - vertex.x = Math.random() * 2 - 1; - vertex.y = Math.random() * 2 - 1; - vertex.z = Math.random() * 2 - 1; - vertex.multiplyScalar(radius); - - if ( - vertex.x > inner || - vertex.x < -inner || - vertex.y > inner || - vertex.y < -inner || - vertex.z > inner || - vertex.z < -inner - ) - vertices.push(vertex.x, vertex.y, vertex.z); - } - - vertices1 = vertices.length / 3; - - radius = 200; - - let boxGeometry1 = new THREE.BoxGeometry(radius, 0.1 * radius, 0.1 * radius, 50, 5, 5); - - // if normal and uv attributes are not removed, mergeVertices() can't consolidate indentical vertices with different normal/uv data - - boxGeometry1.deleteAttribute('normal'); - boxGeometry1.deleteAttribute('uv'); - - boxGeometry1 = BufferGeometryUtils.mergeVertices(boxGeometry1); - - const matrix = new THREE.Matrix4(); - const position = new THREE.Vector3(); - const rotation = new THREE.Euler(); - const quaternion = new THREE.Quaternion(); - const scale = new THREE.Vector3(1, 1, 1); - - function addGeo(geo, x, y, z, ry) { - position.set(x, y, z); - rotation.set(0, ry, 0); - - matrix.compose(position, quaternion.setFromEuler(rotation), scale); - - const positionAttribute = geo.getAttribute('position'); - - for (let i = 0, l = positionAttribute.count; i < l; i++) { - vertex.fromBufferAttribute(positionAttribute, i); - vertex.applyMatrix4(matrix); - vertices.push(vertex.x, vertex.y, vertex.z); - } - } - - // side 1 - - addGeo(boxGeometry1, 0, 110, 110, 0); - addGeo(boxGeometry1, 0, 110, -110, 0); - addGeo(boxGeometry1, 0, -110, 110, 0); - addGeo(boxGeometry1, 0, -110, -110, 0); - - // side 2 - - addGeo(boxGeometry1, 110, 110, 0, Math.PI / 2); - addGeo(boxGeometry1, 110, -110, 0, Math.PI / 2); - addGeo(boxGeometry1, -110, 110, 0, Math.PI / 2); - addGeo(boxGeometry1, -110, -110, 0, Math.PI / 2); - - // corner edges - - let boxGeometry2 = new THREE.BoxGeometry(0.1 * radius, radius * 1.2, 0.1 * radius, 5, 60, 5); - - boxGeometry2.deleteAttribute('normal'); - boxGeometry2.deleteAttribute('uv'); - - boxGeometry2 = BufferGeometryUtils.mergeVertices(boxGeometry2); - - addGeo(boxGeometry2, 110, 0, 110, 0); - addGeo(boxGeometry2, 110, 0, -110, 0); - addGeo(boxGeometry2, -110, 0, 110, 0); - addGeo(boxGeometry2, -110, 0, -110, 0); - - const positionAttribute = new THREE.Float32BufferAttribute(vertices, 3); - - const colors = []; - const sizes = []; - - const color = new THREE.Color(); - - for (let i = 0; i < positionAttribute.count; i++) { - if (i < vertices1) { - color.setHSL(0.5 + 0.2 * (i / vertices1), 1, 0.5); - } else { - color.setHSL(0.1, 1, 0.5); - } - - color.toArray(colors, i * 3); - - sizes[i] = i < vertices1 ? 10 : 40; - } - - const geometry = new THREE.BufferGeometry(); - geometry.setAttribute('position', positionAttribute); - geometry.setAttribute('ca', new THREE.Float32BufferAttribute(colors, 3)); - geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1)); - - // - - const texture = new THREE.TextureLoader().load('textures/sprites/ball.png'); - texture.wrapS = THREE.RepeatWrapping; - texture.wrapT = THREE.RepeatWrapping; - - const material = new THREE.ShaderMaterial({ - uniforms: { - amplitude: { value: 1.0 }, - color: { value: new THREE.Color(0xffffff) }, - pointTexture: { value: texture }, - }, - vertexShader: document.getElementById('vertexshader').textContent, - fragmentShader: document.getElementById('fragmentshader').textContent, - }); - - // - - object = new THREE.Points(geometry, material); - scene.add(object); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(WIDTH, HEIGHT); - - const container = document.getElementById('container'); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const time = Date.now() * 0.01; - - object.rotation.y = object.rotation.z = 0.02 * time; - - const geometry = object.geometry; - const attributes = geometry.attributes; - - for (let i = 0; i < attributes.size.array.length; i++) { - if (i < vertices1) { - attributes.size.array[i] = Math.max(0, 26 + 32 * Math.sin(0.1 * i + 0.6 * time)); - } - } - - attributes.size.needsUpdate = true; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_decals.ts b/examples-testing/examples/webgl_decals.ts deleted file mode 100644 index 1b3b791c2..000000000 --- a/examples-testing/examples/webgl_decals.ts +++ /dev/null @@ -1,238 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; -import { DecalGeometry } from 'three/addons/geometries/DecalGeometry.js'; - -const container = document.getElementById('container'); - -let renderer, scene, camera, stats; -let mesh; -let raycaster; -let line; - -const intersection = { - intersects: false, - point: new THREE.Vector3(), - normal: new THREE.Vector3(), -}; -const mouse = new THREE.Vector2(); -const intersects = []; - -const textureLoader = new THREE.TextureLoader(); -const decalDiffuse = textureLoader.load('textures/decal/decal-diffuse.png'); -decalDiffuse.colorSpace = THREE.SRGBColorSpace; -const decalNormal = textureLoader.load('textures/decal/decal-normal.jpg'); - -const decalMaterial = new THREE.MeshPhongMaterial({ - specular: 0x444444, - map: decalDiffuse, - normalMap: decalNormal, - normalScale: new THREE.Vector2(1, 1), - shininess: 30, - transparent: true, - depthTest: true, - depthWrite: false, - polygonOffset: true, - polygonOffsetFactor: -4, - wireframe: false, -}); - -const decals = []; -let mouseHelper; -const position = new THREE.Vector3(); -const orientation = new THREE.Euler(); -const size = new THREE.Vector3(10, 10, 10); - -const params = { - minScale: 10, - maxScale: 20, - rotate: true, - clear: function () { - removeDecals(); - }, -}; - -init(); -animate(); - -function init() { - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.z = 120; - - const controls = new OrbitControls(camera, renderer.domElement); - controls.minDistance = 50; - controls.maxDistance = 200; - - scene.add(new THREE.AmbientLight(0x666666)); - - const dirLight1 = new THREE.DirectionalLight(0xffddcc, 3); - dirLight1.position.set(1, 0.75, 0.5); - scene.add(dirLight1); - - const dirLight2 = new THREE.DirectionalLight(0xccccff, 3); - dirLight2.position.set(-1, 0.75, -0.5); - scene.add(dirLight2); - - const geometry = new THREE.BufferGeometry(); - geometry.setFromPoints([new THREE.Vector3(), new THREE.Vector3()]); - - line = new THREE.Line(geometry, new THREE.LineBasicMaterial()); - scene.add(line); - - loadLeePerrySmith(); - - raycaster = new THREE.Raycaster(); - - mouseHelper = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 10), new THREE.MeshNormalMaterial()); - mouseHelper.visible = false; - scene.add(mouseHelper); - - window.addEventListener('resize', onWindowResize); - - let moved = false; - - controls.addEventListener('change', function () { - moved = true; - }); - - window.addEventListener('pointerdown', function () { - moved = false; - }); - - window.addEventListener('pointerup', function (event) { - if (moved === false) { - checkIntersection(event.clientX, event.clientY); - - if (intersection.intersects) shoot(); - } - }); - - window.addEventListener('pointermove', onPointerMove); - - function onPointerMove(event) { - if (event.isPrimary) { - checkIntersection(event.clientX, event.clientY); - } - } - - function checkIntersection(x, y) { - if (mesh === undefined) return; - - mouse.x = (x / window.innerWidth) * 2 - 1; - mouse.y = -(y / window.innerHeight) * 2 + 1; - - raycaster.setFromCamera(mouse, camera); - raycaster.intersectObject(mesh, false, intersects); - - if (intersects.length > 0) { - const p = intersects[0].point; - mouseHelper.position.copy(p); - intersection.point.copy(p); - - const n = intersects[0].face.normal.clone(); - n.transformDirection(mesh.matrixWorld); - n.multiplyScalar(10); - n.add(intersects[0].point); - - intersection.normal.copy(intersects[0].face.normal); - mouseHelper.lookAt(n); - - const positions = line.geometry.attributes.position; - positions.setXYZ(0, p.x, p.y, p.z); - positions.setXYZ(1, n.x, n.y, n.z); - positions.needsUpdate = true; - - intersection.intersects = true; - - intersects.length = 0; - } else { - intersection.intersects = false; - } - } - - const gui = new GUI(); - - gui.add(params, 'minScale', 1, 30); - gui.add(params, 'maxScale', 1, 30); - gui.add(params, 'rotate'); - gui.add(params, 'clear'); - gui.open(); -} - -function loadLeePerrySmith() { - const map = textureLoader.load('models/gltf/LeePerrySmith/Map-COL.jpg'); - map.colorSpace = THREE.SRGBColorSpace; - const specularMap = textureLoader.load('models/gltf/LeePerrySmith/Map-SPEC.jpg'); - const normalMap = textureLoader.load('models/gltf/LeePerrySmith/Infinite-Level_02_Tangent_SmoothUV.jpg'); - - const loader = new GLTFLoader(); - - loader.load('models/gltf/LeePerrySmith/LeePerrySmith.glb', function (gltf) { - mesh = gltf.scene.children[0]; - mesh.material = new THREE.MeshPhongMaterial({ - specular: 0x111111, - map: map, - specularMap: specularMap, - normalMap: normalMap, - shininess: 25, - }); - - scene.add(mesh); - mesh.scale.set(10, 10, 10); - }); -} - -function shoot() { - position.copy(intersection.point); - orientation.copy(mouseHelper.rotation); - - if (params.rotate) orientation.z = Math.random() * 2 * Math.PI; - - const scale = params.minScale + Math.random() * (params.maxScale - params.minScale); - size.set(scale, scale, scale); - - const material = decalMaterial.clone(); - material.color.setHex(Math.random() * 0xffffff); - - const m = new THREE.Mesh(new DecalGeometry(mesh, position, orientation, size), material); - - decals.push(m); - scene.add(m); -} - -function removeDecals() { - decals.forEach(function (d) { - scene.remove(d); - }); - - decals.length = 0; -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - renderer.render(scene, camera); - - stats.update(); -} diff --git a/examples-testing/examples/webgl_effects_anaglyph.ts b/examples-testing/examples/webgl_effects_anaglyph.ts deleted file mode 100644 index 51329638c..000000000 --- a/examples-testing/examples/webgl_effects_anaglyph.ts +++ /dev/null @@ -1,116 +0,0 @@ -import * as THREE from 'three'; - -import { AnaglyphEffect } from 'three/addons/effects/AnaglyphEffect.js'; - -let container, camera, scene, renderer, effect; - -const spheres = []; - -let mouseX = 0; -let mouseY = 0; - -let windowHalfX = window.innerWidth / 2; -let windowHalfY = window.innerHeight / 2; - -document.addEventListener('mousemove', onDocumentMouseMove); - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 100); - camera.position.z = 3; - - const path = 'textures/cube/pisa/'; - const format = '.png'; - const urls = [ - path + 'px' + format, - path + 'nx' + format, - path + 'py' + format, - path + 'ny' + format, - path + 'pz' + format, - path + 'nz' + format, - ]; - - const textureCube = new THREE.CubeTextureLoader().load(urls); - - scene = new THREE.Scene(); - scene.background = textureCube; - - const geometry = new THREE.SphereGeometry(0.1, 32, 16); - const material = new THREE.MeshBasicMaterial({ color: 0xffffff, envMap: textureCube }); - - for (let i = 0; i < 500; i++) { - const mesh = new THREE.Mesh(geometry, material); - - mesh.position.x = Math.random() * 10 - 5; - mesh.position.y = Math.random() * 10 - 5; - mesh.position.z = Math.random() * 10 - 5; - - mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 3 + 1; - - scene.add(mesh); - - spheres.push(mesh); - } - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - container.appendChild(renderer.domElement); - - const width = window.innerWidth || 2; - const height = window.innerHeight || 2; - - effect = new AnaglyphEffect(renderer); - effect.setSize(width, height); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - windowHalfX = window.innerWidth / 2; - windowHalfY = window.innerHeight / 2; - - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - effect.setSize(window.innerWidth, window.innerHeight); -} - -function onDocumentMouseMove(event) { - mouseX = (event.clientX - windowHalfX) / 100; - mouseY = (event.clientY - windowHalfY) / 100; -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); -} - -function render() { - const timer = 0.0001 * Date.now(); - - camera.position.x += (mouseX - camera.position.x) * 0.05; - camera.position.y += (-mouseY - camera.position.y) * 0.05; - - camera.lookAt(scene.position); - - for (let i = 0, il = spheres.length; i < il; i++) { - const sphere = spheres[i]; - - sphere.position.x = 5 * Math.cos(timer + i); - sphere.position.y = 5 * Math.sin(timer + i * 1.1); - } - - effect.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_effects_ascii.ts b/examples-testing/examples/webgl_effects_ascii.ts deleted file mode 100644 index 60b7de88e..000000000 --- a/examples-testing/examples/webgl_effects_ascii.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as THREE from 'three'; - -import { AsciiEffect } from 'three/addons/effects/AsciiEffect.js'; -import { TrackballControls } from 'three/addons/controls/TrackballControls.js'; - -let camera, controls, scene, renderer, effect; - -let sphere, plane; - -const start = Date.now(); - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.y = 150; - camera.position.z = 500; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0, 0, 0); - - const pointLight1 = new THREE.PointLight(0xffffff, 3, 0, 0); - pointLight1.position.set(500, 500, 500); - scene.add(pointLight1); - - const pointLight2 = new THREE.PointLight(0xffffff, 1, 0, 0); - pointLight2.position.set(-500, -500, -500); - scene.add(pointLight2); - - sphere = new THREE.Mesh(new THREE.SphereGeometry(200, 20, 10), new THREE.MeshPhongMaterial({ flatShading: true })); - scene.add(sphere); - - // Plane - - plane = new THREE.Mesh(new THREE.PlaneGeometry(400, 400), new THREE.MeshBasicMaterial({ color: 0xe0e0e0 })); - plane.position.y = -200; - plane.rotation.x = -Math.PI / 2; - scene.add(plane); - - renderer = new THREE.WebGLRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - - effect = new AsciiEffect(renderer, ' .:-+*=%@#', { invert: true }); - effect.setSize(window.innerWidth, window.innerHeight); - effect.domElement.style.color = 'white'; - effect.domElement.style.backgroundColor = 'black'; - - // Special case: append effect.domElement, instead of renderer.domElement. - // AsciiEffect creates a custom domElement (a div container) where the ASCII elements are placed. - - document.body.appendChild(effect.domElement); - - controls = new TrackballControls(camera, effect.domElement); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - effect.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); -} - -function render() { - const timer = Date.now() - start; - - sphere.position.y = Math.abs(Math.sin(timer * 0.002)) * 150; - sphere.rotation.x = timer * 0.0003; - sphere.rotation.z = timer * 0.0002; - - controls.update(); - - effect.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_effects_parallaxbarrier.ts b/examples-testing/examples/webgl_effects_parallaxbarrier.ts deleted file mode 100644 index 45e74917a..000000000 --- a/examples-testing/examples/webgl_effects_parallaxbarrier.ts +++ /dev/null @@ -1,116 +0,0 @@ -import * as THREE from 'three'; - -import { ParallaxBarrierEffect } from 'three/addons/effects/ParallaxBarrierEffect.js'; - -let container, camera, scene, renderer, effect; - -const spheres = []; - -let mouseX = 0; -let mouseY = 0; - -let windowHalfX = window.innerWidth / 2; -let windowHalfY = window.innerHeight / 2; - -document.addEventListener('mousemove', onDocumentMouseMove); - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 100); - camera.position.z = 3; - - const path = 'textures/cube/pisa/'; - const format = '.png'; - const urls = [ - path + 'px' + format, - path + 'nx' + format, - path + 'py' + format, - path + 'ny' + format, - path + 'pz' + format, - path + 'nz' + format, - ]; - - const textureCube = new THREE.CubeTextureLoader().load(urls); - - scene = new THREE.Scene(); - scene.background = textureCube; - - const geometry = new THREE.SphereGeometry(0.1, 32, 16); - const material = new THREE.MeshBasicMaterial({ color: 0xffffff, envMap: textureCube }); - - for (let i = 0; i < 500; i++) { - const mesh = new THREE.Mesh(geometry, material); - - mesh.position.x = Math.random() * 10 - 5; - mesh.position.y = Math.random() * 10 - 5; - mesh.position.z = Math.random() * 10 - 5; - - mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 3 + 1; - - scene.add(mesh); - - spheres.push(mesh); - } - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - container.appendChild(renderer.domElement); - - const width = window.innerWidth || 2; - const height = window.innerHeight || 2; - - effect = new ParallaxBarrierEffect(renderer); - effect.setSize(width, height); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - windowHalfX = window.innerWidth / 2; - windowHalfY = window.innerHeight / 2; - - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - effect.setSize(window.innerWidth, window.innerHeight); -} - -function onDocumentMouseMove(event) { - mouseX = (event.clientX - windowHalfX) / 100; - mouseY = (event.clientY - windowHalfY) / 100; -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); -} - -function render() { - const timer = 0.0001 * Date.now(); - - camera.position.x += (mouseX - camera.position.x) * 0.05; - camera.position.y += (-mouseY - camera.position.y) * 0.05; - - camera.lookAt(scene.position); - - for (let i = 0, il = spheres.length; i < il; i++) { - const sphere = spheres[i]; - - sphere.position.x = 5 * Math.cos(timer + i); - sphere.position.y = 5 * Math.sin(timer + i * 1.1); - } - - effect.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_effects_peppersghost.ts b/examples-testing/examples/webgl_effects_peppersghost.ts deleted file mode 100644 index 90cfe01e3..000000000 --- a/examples-testing/examples/webgl_effects_peppersghost.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as THREE from 'three'; - -import { PeppersGhostEffect } from 'three/addons/effects/PeppersGhostEffect.js'; - -let container; - -let camera, scene, renderer, effect; -let group; - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100000); - - scene = new THREE.Scene(); - - group = new THREE.Group(); - scene.add(group); - - // Cube - - const geometry = new THREE.BoxGeometry().toNonIndexed(); // ensure unique vertices for each triangle - - const position = geometry.attributes.position; - const colors = []; - const color = new THREE.Color(); - - // generate for each side of the cube a different color - - for (let i = 0; i < position.count; i += 6) { - color.setHex(Math.random() * 0xffffff); - - // first face - - colors.push(color.r, color.g, color.b); - colors.push(color.r, color.g, color.b); - colors.push(color.r, color.g, color.b); - - // second face - - colors.push(color.r, color.g, color.b); - colors.push(color.r, color.g, color.b); - colors.push(color.r, color.g, color.b); - } - - geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); - - const material = new THREE.MeshBasicMaterial({ vertexColors: true }); - - for (let i = 0; i < 10; i++) { - const cube = new THREE.Mesh(geometry, material); - cube.position.x = Math.random() * 2 - 1; - cube.position.y = Math.random() * 2 - 1; - cube.position.z = Math.random() * 2 - 1; - cube.scale.multiplyScalar(Math.random() + 0.5); - group.add(cube); - } - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - container.appendChild(renderer.domElement); - - effect = new PeppersGhostEffect(renderer); - effect.setSize(window.innerWidth, window.innerHeight); - effect.cameraDistance = 5; - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - effect.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - group.rotation.y += 0.01; - - effect.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_effects_stereo.ts b/examples-testing/examples/webgl_effects_stereo.ts deleted file mode 100644 index 4db7184fb..000000000 --- a/examples-testing/examples/webgl_effects_stereo.ts +++ /dev/null @@ -1,104 +0,0 @@ -import * as THREE from 'three'; - -import { StereoEffect } from 'three/addons/effects/StereoEffect.js'; - -let container, camera, scene, renderer, effect; - -const spheres = []; - -let mouseX = 0, - mouseY = 0; - -let windowHalfX = window.innerWidth / 2; -let windowHalfY = window.innerHeight / 2; - -document.addEventListener('mousemove', onDocumentMouseMove); - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100000); - camera.position.z = 3200; - - scene = new THREE.Scene(); - scene.background = new THREE.CubeTextureLoader() - .setPath('textures/cube/Park3Med/') - .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']); - - const geometry = new THREE.SphereGeometry(100, 32, 16); - - const textureCube = new THREE.CubeTextureLoader() - .setPath('textures/cube/Park3Med/') - .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']); - textureCube.mapping = THREE.CubeRefractionMapping; - - const material = new THREE.MeshBasicMaterial({ color: 0xffffff, envMap: textureCube, refractionRatio: 0.95 }); - - for (let i = 0; i < 500; i++) { - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = Math.random() * 10000 - 5000; - mesh.position.y = Math.random() * 10000 - 5000; - mesh.position.z = Math.random() * 10000 - 5000; - mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 3 + 1; - scene.add(mesh); - - spheres.push(mesh); - } - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - container.appendChild(renderer.domElement); - - effect = new StereoEffect(renderer); - effect.setSize(window.innerWidth, window.innerHeight); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - windowHalfX = window.innerWidth / 2; - windowHalfY = window.innerHeight / 2; - - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - effect.setSize(window.innerWidth, window.innerHeight); -} - -function onDocumentMouseMove(event) { - mouseX = (event.clientX - windowHalfX) * 10; - mouseY = (event.clientY - windowHalfY) * 10; -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); -} - -function render() { - const timer = 0.0001 * Date.now(); - - camera.position.x += (mouseX - camera.position.x) * 0.05; - camera.position.y += (-mouseY - camera.position.y) * 0.05; - camera.lookAt(scene.position); - - for (let i = 0, il = spheres.length; i < il; i++) { - const sphere = spheres[i]; - - sphere.position.x = 5000 * Math.cos(timer + i); - sphere.position.y = 5000 * Math.sin(timer + i * 1.1); - } - - effect.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_framebuffer_texture.ts b/examples-testing/examples/webgl_framebuffer_texture.ts deleted file mode 100644 index 379737fe8..000000000 --- a/examples-testing/examples/webgl_framebuffer_texture.ts +++ /dev/null @@ -1,153 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import * as GeometryUtils from 'three/addons/utils/GeometryUtils.js'; - -let camera, scene, renderer; -let line, sprite, texture; - -let cameraOrtho, sceneOrtho; - -let offset = 0; - -const dpr = window.devicePixelRatio; - -const textureSize = 128 * dpr; -const vector = new THREE.Vector2(); -const color = new THREE.Color(); - -init(); -animate(); - -function init() { - // - - const width = window.innerWidth; - const height = window.innerHeight; - - camera = new THREE.PerspectiveCamera(70, width / height, 1, 1000); - camera.position.z = 20; - - cameraOrtho = new THREE.OrthographicCamera(-width / 2, width / 2, height / 2, -height / 2, 1, 10); - cameraOrtho.position.z = 10; - - scene = new THREE.Scene(); - sceneOrtho = new THREE.Scene(); - - // - - const points = GeometryUtils.gosper(8); - - const geometry = new THREE.BufferGeometry(); - const positionAttribute = new THREE.Float32BufferAttribute(points, 3); - geometry.setAttribute('position', positionAttribute); - geometry.center(); - - const colorAttribute = new THREE.BufferAttribute(new Float32Array(positionAttribute.array.length), 3); - colorAttribute.setUsage(THREE.DynamicDrawUsage); - geometry.setAttribute('color', colorAttribute); - - const material = new THREE.LineBasicMaterial({ vertexColors: true }); - - line = new THREE.Line(geometry, material); - line.scale.setScalar(0.05); - scene.add(line); - - // - - texture = new THREE.FramebufferTexture(textureSize, textureSize); - - // - - const spriteMaterial = new THREE.SpriteMaterial({ map: texture }); - sprite = new THREE.Sprite(spriteMaterial); - sprite.scale.set(textureSize, textureSize, 1); - sceneOrtho.add(sprite); - - updateSpritePosition(); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.autoClear = false; - document.body.appendChild(renderer.domElement); - - // - - const selection = document.getElementById('selection'); - const controls = new OrbitControls(camera, selection); - controls.enablePan = false; - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - const width = window.innerWidth; - const height = window.innerHeight; - - camera.aspect = width / height; - camera.updateProjectionMatrix(); - - cameraOrtho.left = -width / 2; - cameraOrtho.right = width / 2; - cameraOrtho.top = height / 2; - cameraOrtho.bottom = -height / 2; - cameraOrtho.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - updateSpritePosition(); -} - -function updateSpritePosition() { - const halfWidth = window.innerWidth / 2; - const halfHeight = window.innerHeight / 2; - - const halfImageWidth = textureSize / 2; - const halfImageHeight = textureSize / 2; - - sprite.position.set(-halfWidth + halfImageWidth, halfHeight - halfImageHeight, 1); -} - -function animate() { - requestAnimationFrame(animate); - - const colorAttribute = line.geometry.getAttribute('color'); - updateColors(colorAttribute); - - // scene rendering - - renderer.clear(); - renderer.render(scene, camera); - - // calculate start position for copying data - - vector.x = (window.innerWidth * dpr) / 2 - textureSize / 2; - vector.y = (window.innerHeight * dpr) / 2 - textureSize / 2; - - renderer.copyFramebufferToTexture(vector, texture); - - renderer.clearDepth(); - renderer.render(sceneOrtho, cameraOrtho); -} - -function updateColors(colorAttribute) { - const l = colorAttribute.count; - - for (let i = 0; i < l; i++) { - const h = ((offset + i) % l) / l; - - color.setHSL(h, 1, 0.5); - colorAttribute.setX(i, color.r); - colorAttribute.setY(i, color.g); - colorAttribute.setZ(i, color.b); - } - - colorAttribute.needsUpdate = true; - - offset -= 25; -} diff --git a/examples-testing/examples/webgl_furnace_test.ts b/examples-testing/examples/webgl_furnace_test.ts deleted file mode 100644 index a81954176..000000000 --- a/examples-testing/examples/webgl_furnace_test.ts +++ /dev/null @@ -1,96 +0,0 @@ -import * as THREE from 'three'; - -let scene, camera, renderer, radianceMap; - -const COLOR = 0xcccccc; - -function init() { - const width = window.innerWidth; - const height = window.innerHeight; - const aspect = width / height; - - // renderer - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setSize(width, height); - renderer.setPixelRatio(window.devicePixelRatio); - document.body.appendChild(renderer.domElement); - - window.addEventListener('resize', onWindowResize); - - document.body.addEventListener('mouseover', function () { - scene.traverse(function (child) { - if (child.isMesh) child.material.color.setHex(0xffffff); - }); - - render(); - }); - - document.body.addEventListener('mouseout', function () { - scene.traverse(function (child) { - if (child.isMesh) child.material.color.setHex(0xccccff); // tinted for visibility - }); - - render(); - }); - - // scene - - scene = new THREE.Scene(); - - // camera - camera = new THREE.PerspectiveCamera(40, aspect, 1, 30); - camera.position.set(0, 0, 18); -} - -function createObjects() { - const geometry = new THREE.SphereGeometry(0.4, 32, 16); - - for (let x = 0; x <= 10; x++) { - for (let y = 0; y <= 10; y++) { - const material = new THREE.MeshPhysicalMaterial({ - roughness: x / 10, - metalness: y / 10, - color: 0xffffff, - envMap: radianceMap, - envMapIntensity: 1, - transmission: 0, - ior: 1.5, - }); - - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = x - 5; - mesh.position.y = 5 - y; - scene.add(mesh); - } - } -} - -function createEnvironment() { - const envScene = new THREE.Scene(); - envScene.background = new THREE.Color(COLOR); - - const pmremGenerator = new THREE.PMREMGenerator(renderer); - radianceMap = pmremGenerator.fromScene(envScene).texture; - pmremGenerator.dispose(); - - scene.background = envScene.background; -} - -function onWindowResize() { - const width = window.innerWidth; - const height = window.innerHeight; - - camera.aspect = width / height; - camera.updateProjectionMatrix(); - - renderer.setSize(width, height); - - render(); -} - -function render() { - renderer.render(scene, camera); -} - -Promise.resolve().then(init).then(createEnvironment).then(createObjects).then(render); diff --git a/examples-testing/examples/webgl_geometries.ts b/examples-testing/examples/webgl_geometries.ts deleted file mode 100644 index 154164e13..000000000 --- a/examples-testing/examples/webgl_geometries.ts +++ /dev/null @@ -1,139 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -let camera, scene, renderer, stats; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000); - camera.position.y = 400; - - scene = new THREE.Scene(); - - let object; - - const ambientLight = new THREE.AmbientLight(0xcccccc, 1.5); - scene.add(ambientLight); - - const pointLight = new THREE.PointLight(0xffffff, 2.5, 0, 0); - camera.add(pointLight); - scene.add(camera); - - const map = new THREE.TextureLoader().load('textures/uv_grid_opengl.jpg'); - map.wrapS = map.wrapT = THREE.RepeatWrapping; - map.anisotropy = 16; - map.colorSpace = THREE.SRGBColorSpace; - - const material = new THREE.MeshPhongMaterial({ map: map, side: THREE.DoubleSide }); - - // - - object = new THREE.Mesh(new THREE.SphereGeometry(75, 20, 10), material); - object.position.set(-300, 0, 200); - scene.add(object); - - object = new THREE.Mesh(new THREE.IcosahedronGeometry(75, 1), material); - object.position.set(-100, 0, 200); - scene.add(object); - - object = new THREE.Mesh(new THREE.OctahedronGeometry(75, 2), material); - object.position.set(100, 0, 200); - scene.add(object); - - object = new THREE.Mesh(new THREE.TetrahedronGeometry(75, 0), material); - object.position.set(300, 0, 200); - scene.add(object); - - // - - object = new THREE.Mesh(new THREE.PlaneGeometry(100, 100, 4, 4), material); - object.position.set(-300, 0, 0); - scene.add(object); - - object = new THREE.Mesh(new THREE.BoxGeometry(100, 100, 100, 4, 4, 4), material); - object.position.set(-100, 0, 0); - scene.add(object); - - object = new THREE.Mesh(new THREE.CircleGeometry(50, 20, 0, Math.PI * 2), material); - object.position.set(100, 0, 0); - scene.add(object); - - object = new THREE.Mesh(new THREE.RingGeometry(10, 50, 20, 5, 0, Math.PI * 2), material); - object.position.set(300, 0, 0); - scene.add(object); - - // - - object = new THREE.Mesh(new THREE.CylinderGeometry(25, 75, 100, 40, 5), material); - object.position.set(-300, 0, -200); - scene.add(object); - - const points = []; - - for (let i = 0; i < 50; i++) { - points.push(new THREE.Vector2(Math.sin(i * 0.2) * Math.sin(i * 0.1) * 15 + 50, (i - 5) * 2)); - } - - object = new THREE.Mesh(new THREE.LatheGeometry(points, 20), material); - object.position.set(-100, 0, -200); - scene.add(object); - - object = new THREE.Mesh(new THREE.TorusGeometry(50, 20, 20, 20), material); - object.position.set(100, 0, -200); - scene.add(object); - - object = new THREE.Mesh(new THREE.TorusKnotGeometry(50, 10, 50, 20), material); - object.position.set(300, 0, -200); - scene.add(object); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - stats = new Stats(); - document.body.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const timer = Date.now() * 0.0001; - - camera.position.x = Math.cos(timer) * 800; - camera.position.z = Math.sin(timer) * 800; - - camera.lookAt(scene.position); - - scene.traverse(function (object) { - if (object.isMesh === true) { - object.rotation.x = timer * 5; - object.rotation.y = timer * 2.5; - } - }); - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_geometries_parametric.ts b/examples-testing/examples/webgl_geometries_parametric.ts deleted file mode 100644 index 8aa86c345..000000000 --- a/examples-testing/examples/webgl_geometries_parametric.ts +++ /dev/null @@ -1,126 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import * as Curves from 'three/addons/curves/CurveExtras.js'; -import { ParametricGeometry } from 'three/addons/geometries/ParametricGeometry.js'; -import { ParametricGeometries } from 'three/addons/geometries/ParametricGeometries.js'; - -let camera, scene, renderer, stats; - -init(); -animate(); - -function init() { - const container = document.getElementById('container'); - - camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000); - camera.position.y = 400; - - scene = new THREE.Scene(); - - // - - const ambientLight = new THREE.AmbientLight(0xcccccc, 1.5); - scene.add(ambientLight); - - const pointLight = new THREE.PointLight(0xffffff, 2.5, 0, 0); - camera.add(pointLight); - scene.add(camera); - - // - - const map = new THREE.TextureLoader().load('textures/uv_grid_opengl.jpg'); - map.wrapS = map.wrapT = THREE.RepeatWrapping; - map.anisotropy = 16; - map.colorSpace = THREE.SRGBColorSpace; - - const material = new THREE.MeshPhongMaterial({ map: map, side: THREE.DoubleSide }); - - // - - let geometry, object; - - geometry = new ParametricGeometry(ParametricGeometries.plane(100, 100), 10, 10); - geometry.center(); - object = new THREE.Mesh(geometry, material); - object.position.set(-200, 0, 200); - scene.add(object); - - geometry = new ParametricGeometry(ParametricGeometries.klein, 20, 20); - object = new THREE.Mesh(geometry, material); - object.position.set(0, 0, 200); - object.scale.multiplyScalar(5); - scene.add(object); - - geometry = new ParametricGeometry(ParametricGeometries.mobius, 20, 20); - object = new THREE.Mesh(geometry, material); - object.position.set(200, 0, 200); - object.scale.multiplyScalar(30); - scene.add(object); - - // - - const GrannyKnot = new Curves.GrannyKnot(); - - const torus = new ParametricGeometries.TorusKnotGeometry(50, 10, 50, 20, 2, 3); - const sphere = new ParametricGeometries.SphereGeometry(50, 20, 10); - const tube = new ParametricGeometries.TubeGeometry(GrannyKnot, 100, 3, 8, true); - - object = new THREE.Mesh(torus, material); - object.position.set(-200, 0, -200); - scene.add(object); - - object = new THREE.Mesh(sphere, material); - object.position.set(0, 0, -200); - scene.add(object); - - object = new THREE.Mesh(tube, material); - object.position.set(200, 0, -200); - object.scale.multiplyScalar(2); - scene.add(object); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const timer = Date.now() * 0.0001; - - camera.position.x = Math.cos(timer) * 800; - camera.position.z = Math.sin(timer) * 800; - - camera.lookAt(scene.position); - - scene.traverse(function (object) { - if (object.isMesh === true) { - object.rotation.x = timer * 5; - object.rotation.y = timer * 2.5; - } - }); - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_gpgpu_birds.ts b/examples-testing/examples/webgl_gpgpu_birds.ts deleted file mode 100644 index ecf53eb80..000000000 --- a/examples-testing/examples/webgl_gpgpu_birds.ts +++ /dev/null @@ -1,319 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { GPUComputationRenderer } from 'three/addons/misc/GPUComputationRenderer.js'; - -/* TEXTURE WIDTH FOR SIMULATION */ -const WIDTH = 32; - -const BIRDS = WIDTH * WIDTH; - -// Custom Geometry - using 3 triangles each. No UVs, no normals currently. -class BirdGeometry extends THREE.BufferGeometry { - constructor() { - super(); - - const trianglesPerBird = 3; - const triangles = BIRDS * trianglesPerBird; - const points = triangles * 3; - - const vertices = new THREE.BufferAttribute(new Float32Array(points * 3), 3); - const birdColors = new THREE.BufferAttribute(new Float32Array(points * 3), 3); - const references = new THREE.BufferAttribute(new Float32Array(points * 2), 2); - const birdVertex = new THREE.BufferAttribute(new Float32Array(points), 1); - - this.setAttribute('position', vertices); - this.setAttribute('birdColor', birdColors); - this.setAttribute('reference', references); - this.setAttribute('birdVertex', birdVertex); - - // this.setAttribute( 'normal', new Float32Array( points * 3 ), 3 ); - - let v = 0; - - function verts_push() { - for (let i = 0; i < arguments.length; i++) { - vertices.array[v++] = arguments[i]; - } - } - - const wingsSpan = 20; - - for (let f = 0; f < BIRDS; f++) { - // Body - - verts_push(0, -0, -20, 0, 4, -20, 0, 0, 30); - - // Wings - - verts_push(0, 0, -15, -wingsSpan, 0, 0, 0, 0, 15); - - verts_push(0, 0, 15, wingsSpan, 0, 0, 0, 0, -15); - } - - for (let v = 0; v < triangles * 3; v++) { - const triangleIndex = ~~(v / 3); - const birdIndex = ~~(triangleIndex / trianglesPerBird); - const x = (birdIndex % WIDTH) / WIDTH; - const y = ~~(birdIndex / WIDTH) / WIDTH; - - const c = new THREE.Color(0x666666 + (~~(v / 9) / BIRDS) * 0x666666); - - birdColors.array[v * 3 + 0] = c.r; - birdColors.array[v * 3 + 1] = c.g; - birdColors.array[v * 3 + 2] = c.b; - - references.array[v * 2] = x; - references.array[v * 2 + 1] = y; - - birdVertex.array[v] = v % 9; - } - - this.scale(0.2, 0.2, 0.2); - } -} - -// - -let container, stats; -let camera, scene, renderer; -let mouseX = 0, - mouseY = 0; - -let windowHalfX = window.innerWidth / 2; -let windowHalfY = window.innerHeight / 2; - -const BOUNDS = 800, - BOUNDS_HALF = BOUNDS / 2; - -let last = performance.now(); - -let gpuCompute; -let velocityVariable; -let positionVariable; -let positionUniforms; -let velocityUniforms; -let birdUniforms; - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 3000); - camera.position.z = 350; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xffffff); - scene.fog = new THREE.Fog(0xffffff, 100, 1000); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - initComputeRenderer(); - - stats = new Stats(); - container.appendChild(stats.dom); - - container.style.touchAction = 'none'; - container.addEventListener('pointermove', onPointerMove); - - // - - window.addEventListener('resize', onWindowResize); - - const gui = new GUI(); - - const effectController = { - separation: 20.0, - alignment: 20.0, - cohesion: 20.0, - freedom: 0.75, - }; - - const valuesChanger = function () { - velocityUniforms['separationDistance'].value = effectController.separation; - velocityUniforms['alignmentDistance'].value = effectController.alignment; - velocityUniforms['cohesionDistance'].value = effectController.cohesion; - velocityUniforms['freedomFactor'].value = effectController.freedom; - }; - - valuesChanger(); - - gui.add(effectController, 'separation', 0.0, 100.0, 1.0).onChange(valuesChanger); - gui.add(effectController, 'alignment', 0.0, 100, 0.001).onChange(valuesChanger); - gui.add(effectController, 'cohesion', 0.0, 100, 0.025).onChange(valuesChanger); - gui.close(); - - initBirds(); -} - -function initComputeRenderer() { - gpuCompute = new GPUComputationRenderer(WIDTH, WIDTH, renderer); - - if (renderer.capabilities.isWebGL2 === false) { - gpuCompute.setDataType(THREE.HalfFloatType); - } - - const dtPosition = gpuCompute.createTexture(); - const dtVelocity = gpuCompute.createTexture(); - fillPositionTexture(dtPosition); - fillVelocityTexture(dtVelocity); - - velocityVariable = gpuCompute.addVariable( - 'textureVelocity', - document.getElementById('fragmentShaderVelocity').textContent, - dtVelocity, - ); - positionVariable = gpuCompute.addVariable( - 'texturePosition', - document.getElementById('fragmentShaderPosition').textContent, - dtPosition, - ); - - gpuCompute.setVariableDependencies(velocityVariable, [positionVariable, velocityVariable]); - gpuCompute.setVariableDependencies(positionVariable, [positionVariable, velocityVariable]); - - positionUniforms = positionVariable.material.uniforms; - velocityUniforms = velocityVariable.material.uniforms; - - positionUniforms['time'] = { value: 0.0 }; - positionUniforms['delta'] = { value: 0.0 }; - velocityUniforms['time'] = { value: 1.0 }; - velocityUniforms['delta'] = { value: 0.0 }; - velocityUniforms['testing'] = { value: 1.0 }; - velocityUniforms['separationDistance'] = { value: 1.0 }; - velocityUniforms['alignmentDistance'] = { value: 1.0 }; - velocityUniforms['cohesionDistance'] = { value: 1.0 }; - velocityUniforms['freedomFactor'] = { value: 1.0 }; - velocityUniforms['predator'] = { value: new THREE.Vector3() }; - velocityVariable.material.defines.BOUNDS = BOUNDS.toFixed(2); - - velocityVariable.wrapS = THREE.RepeatWrapping; - velocityVariable.wrapT = THREE.RepeatWrapping; - positionVariable.wrapS = THREE.RepeatWrapping; - positionVariable.wrapT = THREE.RepeatWrapping; - - const error = gpuCompute.init(); - - if (error !== null) { - console.error(error); - } -} - -function initBirds() { - const geometry = new BirdGeometry(); - - // For Vertex and Fragment - birdUniforms = { - color: { value: new THREE.Color(0xff2200) }, - texturePosition: { value: null }, - textureVelocity: { value: null }, - time: { value: 1.0 }, - delta: { value: 0.0 }, - }; - - // THREE.ShaderMaterial - const material = new THREE.ShaderMaterial({ - uniforms: birdUniforms, - vertexShader: document.getElementById('birdVS').textContent, - fragmentShader: document.getElementById('birdFS').textContent, - side: THREE.DoubleSide, - }); - - const birdMesh = new THREE.Mesh(geometry, material); - birdMesh.rotation.y = Math.PI / 2; - birdMesh.matrixAutoUpdate = false; - birdMesh.updateMatrix(); - - scene.add(birdMesh); -} - -function fillPositionTexture(texture) { - const theArray = texture.image.data; - - for (let k = 0, kl = theArray.length; k < kl; k += 4) { - const x = Math.random() * BOUNDS - BOUNDS_HALF; - const y = Math.random() * BOUNDS - BOUNDS_HALF; - const z = Math.random() * BOUNDS - BOUNDS_HALF; - - theArray[k + 0] = x; - theArray[k + 1] = y; - theArray[k + 2] = z; - theArray[k + 3] = 1; - } -} - -function fillVelocityTexture(texture) { - const theArray = texture.image.data; - - for (let k = 0, kl = theArray.length; k < kl; k += 4) { - const x = Math.random() - 0.5; - const y = Math.random() - 0.5; - const z = Math.random() - 0.5; - - theArray[k + 0] = x * 10; - theArray[k + 1] = y * 10; - theArray[k + 2] = z * 10; - theArray[k + 3] = 1; - } -} - -function onWindowResize() { - windowHalfX = window.innerWidth / 2; - windowHalfY = window.innerHeight / 2; - - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function onPointerMove(event) { - if (event.isPrimary === false) return; - - mouseX = event.clientX - windowHalfX; - mouseY = event.clientY - windowHalfY; -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const now = performance.now(); - let delta = (now - last) / 1000; - - if (delta > 1) delta = 1; // safety cap on large deltas - last = now; - - positionUniforms['time'].value = now; - positionUniforms['delta'].value = delta; - velocityUniforms['time'].value = now; - velocityUniforms['delta'].value = delta; - birdUniforms['time'].value = now; - birdUniforms['delta'].value = delta; - - velocityUniforms['predator'].value.set((0.5 * mouseX) / windowHalfX, (-0.5 * mouseY) / windowHalfY, 0); - - mouseX = 10000; - mouseY = 10000; - - gpuCompute.compute(); - - birdUniforms['texturePosition'].value = gpuCompute.getCurrentRenderTarget(positionVariable).texture; - birdUniforms['textureVelocity'].value = gpuCompute.getCurrentRenderTarget(velocityVariable).texture; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_gpgpu_birds_gltf.ts b/examples-testing/examples/webgl_gpgpu_birds_gltf.ts deleted file mode 100644 index 58aee4f15..000000000 --- a/examples-testing/examples/webgl_gpgpu_birds_gltf.ts +++ /dev/null @@ -1,421 +0,0 @@ -import * as THREE from 'three'; -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; -import { GPUComputationRenderer } from 'three/addons/misc/GPUComputationRenderer.js'; - -/* TEXTURE WIDTH FOR SIMULATION */ -const WIDTH = 64; -const BIRDS = WIDTH * WIDTH; - -/* BAKE ANIMATION INTO TEXTURE and CREATE GEOMETRY FROM BASE MODEL */ -const BirdGeometry = new THREE.BufferGeometry(); -let textureAnimation, durationAnimation, birdMesh, materialShader, indicesPerBird; - -function nextPowerOf2(n) { - return Math.pow(2, Math.ceil(Math.log(n) / Math.log(2))); -} - -Math.lerp = function (value1, value2, amount) { - amount = Math.max(Math.min(amount, 1), 0); - return value1 + (value2 - value1) * amount; -}; - -const gltfs = ['models/gltf/Parrot.glb', 'models/gltf/Flamingo.glb']; -const colors = [0xccffff, 0xffdeff]; -const sizes = [0.2, 0.1]; -const selectModel = Math.floor(Math.random() * gltfs.length); -new GLTFLoader().load(gltfs[selectModel], function (gltf) { - const animations = gltf.animations; - durationAnimation = Math.round(animations[0].duration * 60); - const birdGeo = gltf.scene.children[0].geometry; - const morphAttributes = birdGeo.morphAttributes.position; - const tHeight = nextPowerOf2(durationAnimation); - const tWidth = nextPowerOf2(birdGeo.getAttribute('position').count); - indicesPerBird = birdGeo.index.count; - const tData = new Float32Array(4 * tWidth * tHeight); - - for (let i = 0; i < tWidth; i++) { - for (let j = 0; j < tHeight; j++) { - const offset = j * tWidth * 4; - - const curMorph = Math.floor((j / durationAnimation) * morphAttributes.length); - const nextMorph = - (Math.floor((j / durationAnimation) * morphAttributes.length) + 1) % morphAttributes.length; - const lerpAmount = ((j / durationAnimation) * morphAttributes.length) % 1; - - if (j < durationAnimation) { - let d0, d1; - - d0 = morphAttributes[curMorph].array[i * 3]; - d1 = morphAttributes[nextMorph].array[i * 3]; - - if (d0 !== undefined && d1 !== undefined) tData[offset + i * 4] = Math.lerp(d0, d1, lerpAmount); - - d0 = morphAttributes[curMorph].array[i * 3 + 1]; - d1 = morphAttributes[nextMorph].array[i * 3 + 1]; - - if (d0 !== undefined && d1 !== undefined) tData[offset + i * 4 + 1] = Math.lerp(d0, d1, lerpAmount); - - d0 = morphAttributes[curMorph].array[i * 3 + 2]; - d1 = morphAttributes[nextMorph].array[i * 3 + 2]; - - if (d0 !== undefined && d1 !== undefined) tData[offset + i * 4 + 2] = Math.lerp(d0, d1, lerpAmount); - - tData[offset + i * 4 + 3] = 1; - } - } - } - - textureAnimation = new THREE.DataTexture(tData, tWidth, tHeight, THREE.RGBAFormat, THREE.FloatType); - textureAnimation.needsUpdate = true; - - const vertices = [], - color = [], - reference = [], - seeds = [], - indices = []; - const totalVertices = birdGeo.getAttribute('position').count * 3 * BIRDS; - for (let i = 0; i < totalVertices; i++) { - const bIndex = i % (birdGeo.getAttribute('position').count * 3); - vertices.push(birdGeo.getAttribute('position').array[bIndex]); - color.push(birdGeo.getAttribute('color').array[bIndex]); - } - - let r = Math.random(); - for (let i = 0; i < birdGeo.getAttribute('position').count * BIRDS; i++) { - const bIndex = i % birdGeo.getAttribute('position').count; - const bird = Math.floor(i / birdGeo.getAttribute('position').count); - if (bIndex == 0) r = Math.random(); - const j = ~~bird; - const x = (j % WIDTH) / WIDTH; - const y = ~~(j / WIDTH) / WIDTH; - reference.push(x, y, bIndex / tWidth, durationAnimation / tHeight); - seeds.push(bird, r, Math.random(), Math.random()); - } - - for (let i = 0; i < birdGeo.index.array.length * BIRDS; i++) { - const offset = Math.floor(i / birdGeo.index.array.length) * birdGeo.getAttribute('position').count; - indices.push(birdGeo.index.array[i % birdGeo.index.array.length] + offset); - } - - BirdGeometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3)); - BirdGeometry.setAttribute('birdColor', new THREE.BufferAttribute(new Float32Array(color), 3)); - BirdGeometry.setAttribute('color', new THREE.BufferAttribute(new Float32Array(color), 3)); - BirdGeometry.setAttribute('reference', new THREE.BufferAttribute(new Float32Array(reference), 4)); - BirdGeometry.setAttribute('seeds', new THREE.BufferAttribute(new Float32Array(seeds), 4)); - - BirdGeometry.setIndex(indices); - - init(); - animate(); -}); - -let container, stats; -let camera, scene, renderer; -let mouseX = 0, - mouseY = 0; - -let windowHalfX = window.innerWidth / 2; -let windowHalfY = window.innerHeight / 2; - -const BOUNDS = 800, - BOUNDS_HALF = BOUNDS / 2; - -let last = performance.now(); - -let gpuCompute; -let velocityVariable; -let positionVariable; -let positionUniforms; -let velocityUniforms; - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 3000); - camera.position.z = 350; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(colors[selectModel]); - scene.fog = new THREE.Fog(colors[selectModel], 100, 1000); - - // LIGHTS - - const hemiLight = new THREE.HemisphereLight(colors[selectModel], 0xffffff, 4.5); - hemiLight.color.setHSL(0.6, 1, 0.6, THREE.SRGBColorSpace); - hemiLight.groundColor.setHSL(0.095, 1, 0.75, THREE.SRGBColorSpace); - hemiLight.position.set(0, 50, 0); - scene.add(hemiLight); - - const dirLight = new THREE.DirectionalLight(0x00ced1, 2.0); - dirLight.color.setHSL(0.1, 1, 0.95, THREE.SRGBColorSpace); - dirLight.position.set(-1, 1.75, 1); - dirLight.position.multiplyScalar(30); - scene.add(dirLight); - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - initComputeRenderer(); - - stats = new Stats(); - container.appendChild(stats.dom); - - container.style.touchAction = 'none'; - container.addEventListener('pointermove', onPointerMove); - - window.addEventListener('resize', onWindowResize); - - const gui = new GUI(); - - const effectController = { - separation: 20.0, - alignment: 20.0, - cohesion: 20.0, - freedom: 0.75, - size: sizes[selectModel], - count: Math.floor(BIRDS / 4), - }; - - const valuesChanger = function () { - velocityUniforms['separationDistance'].value = effectController.separation; - velocityUniforms['alignmentDistance'].value = effectController.alignment; - velocityUniforms['cohesionDistance'].value = effectController.cohesion; - velocityUniforms['freedomFactor'].value = effectController.freedom; - if (materialShader) materialShader.uniforms['size'].value = effectController.size; - BirdGeometry.setDrawRange(0, indicesPerBird * effectController.count); - }; - - valuesChanger(); - - gui.add(effectController, 'separation', 0.0, 100.0, 1.0).onChange(valuesChanger); - gui.add(effectController, 'alignment', 0.0, 100, 0.001).onChange(valuesChanger); - gui.add(effectController, 'cohesion', 0.0, 100, 0.025).onChange(valuesChanger); - gui.add(effectController, 'size', 0, 1, 0.01).onChange(valuesChanger); - gui.add(effectController, 'count', 0, BIRDS, 1).onChange(valuesChanger); - gui.close(); - - initBirds(effectController); -} - -function initComputeRenderer() { - gpuCompute = new GPUComputationRenderer(WIDTH, WIDTH, renderer); - - if (renderer.capabilities.isWebGL2 === false) { - gpuCompute.setDataType(THREE.HalfFloatType); - } - - const dtPosition = gpuCompute.createTexture(); - const dtVelocity = gpuCompute.createTexture(); - fillPositionTexture(dtPosition); - fillVelocityTexture(dtVelocity); - - velocityVariable = gpuCompute.addVariable( - 'textureVelocity', - document.getElementById('fragmentShaderVelocity').textContent, - dtVelocity, - ); - positionVariable = gpuCompute.addVariable( - 'texturePosition', - document.getElementById('fragmentShaderPosition').textContent, - dtPosition, - ); - - gpuCompute.setVariableDependencies(velocityVariable, [positionVariable, velocityVariable]); - gpuCompute.setVariableDependencies(positionVariable, [positionVariable, velocityVariable]); - - positionUniforms = positionVariable.material.uniforms; - velocityUniforms = velocityVariable.material.uniforms; - - positionUniforms['time'] = { value: 0.0 }; - positionUniforms['delta'] = { value: 0.0 }; - velocityUniforms['time'] = { value: 1.0 }; - velocityUniforms['delta'] = { value: 0.0 }; - velocityUniforms['testing'] = { value: 1.0 }; - velocityUniforms['separationDistance'] = { value: 1.0 }; - velocityUniforms['alignmentDistance'] = { value: 1.0 }; - velocityUniforms['cohesionDistance'] = { value: 1.0 }; - velocityUniforms['freedomFactor'] = { value: 1.0 }; - velocityUniforms['predator'] = { value: new THREE.Vector3() }; - velocityVariable.material.defines.BOUNDS = BOUNDS.toFixed(2); - - velocityVariable.wrapS = THREE.RepeatWrapping; - velocityVariable.wrapT = THREE.RepeatWrapping; - positionVariable.wrapS = THREE.RepeatWrapping; - positionVariable.wrapT = THREE.RepeatWrapping; - - const error = gpuCompute.init(); - - if (error !== null) { - console.error(error); - } -} - -function initBirds(effectController) { - const geometry = BirdGeometry; - - const m = new THREE.MeshStandardMaterial({ - vertexColors: true, - flatShading: true, - roughness: 1, - metalness: 0, - }); - - m.onBeforeCompile = shader => { - shader.uniforms.texturePosition = { value: null }; - shader.uniforms.textureVelocity = { value: null }; - shader.uniforms.textureAnimation = { value: textureAnimation }; - shader.uniforms.time = { value: 1.0 }; - shader.uniforms.size = { value: effectController.size }; - shader.uniforms.delta = { value: 0.0 }; - - let token = '#define STANDARD'; - - let insert = /* glsl */ ` - attribute vec4 reference; - attribute vec4 seeds; - attribute vec3 birdColor; - uniform sampler2D texturePosition; - uniform sampler2D textureVelocity; - uniform sampler2D textureAnimation; - uniform float size; - uniform float time; - `; - - shader.vertexShader = shader.vertexShader.replace(token, token + insert); - - token = '#include '; - - insert = /* glsl */ ` - vec4 tmpPos = texture2D( texturePosition, reference.xy ); - - vec3 pos = tmpPos.xyz; - vec3 velocity = normalize(texture2D( textureVelocity, reference.xy ).xyz); - vec3 aniPos = texture2D( textureAnimation, vec2( reference.z, mod( time + ( seeds.x ) * ( ( 0.0004 + seeds.y / 10000.0) + normalize( velocity ) / 20000.0 ), reference.w ) ) ).xyz; - vec3 newPosition = position; - - newPosition = mat3( modelMatrix ) * ( newPosition + aniPos ); - newPosition *= size + seeds.y * size * 0.2; - - velocity.z *= -1.; - float xz = length( velocity.xz ); - float xyz = 1.; - float x = sqrt( 1. - velocity.y * velocity.y ); - - float cosry = velocity.x / xz; - float sinry = velocity.z / xz; - - float cosrz = x / xyz; - float sinrz = velocity.y / xyz; - - mat3 maty = mat3( cosry, 0, -sinry, 0 , 1, 0 , sinry, 0, cosry ); - mat3 matz = mat3( cosrz , sinrz, 0, -sinrz, cosrz, 0, 0 , 0 , 1 ); - - newPosition = maty * matz * newPosition; - newPosition += pos; - - vec3 transformed = vec3( newPosition ); - `; - - shader.vertexShader = shader.vertexShader.replace(token, insert); - - materialShader = shader; - }; - - birdMesh = new THREE.Mesh(geometry, m); - birdMesh.rotation.y = Math.PI / 2; - - birdMesh.castShadow = true; - birdMesh.receiveShadow = true; - - scene.add(birdMesh); -} - -function fillPositionTexture(texture) { - const theArray = texture.image.data; - - for (let k = 0, kl = theArray.length; k < kl; k += 4) { - const x = Math.random() * BOUNDS - BOUNDS_HALF; - const y = Math.random() * BOUNDS - BOUNDS_HALF; - const z = Math.random() * BOUNDS - BOUNDS_HALF; - - theArray[k + 0] = x; - theArray[k + 1] = y; - theArray[k + 2] = z; - theArray[k + 3] = 1; - } -} - -function fillVelocityTexture(texture) { - const theArray = texture.image.data; - - for (let k = 0, kl = theArray.length; k < kl; k += 4) { - const x = Math.random() - 0.5; - const y = Math.random() - 0.5; - const z = Math.random() - 0.5; - - theArray[k + 0] = x * 10; - theArray[k + 1] = y * 10; - theArray[k + 2] = z * 10; - theArray[k + 3] = 1; - } -} - -function onWindowResize() { - windowHalfX = window.innerWidth / 2; - windowHalfY = window.innerHeight / 2; - - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function onPointerMove(event) { - if (event.isPrimary === false) return; - - mouseX = event.clientX - windowHalfX; - mouseY = event.clientY - windowHalfY; -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - const now = performance.now(); - let delta = (now - last) / 1000; - - if (delta > 1) delta = 1; // safety cap on large deltas - last = now; - - positionUniforms['time'].value = now; - positionUniforms['delta'].value = delta; - velocityUniforms['time'].value = now; - velocityUniforms['delta'].value = delta; - if (materialShader) materialShader.uniforms['time'].value = now / 1000; - if (materialShader) materialShader.uniforms['delta'].value = delta; - - velocityUniforms['predator'].value.set((0.5 * mouseX) / windowHalfX, (-0.5 * mouseY) / windowHalfY, 0); - - mouseX = 10000; - mouseY = 10000; - - gpuCompute.compute(); - - if (materialShader) - materialShader.uniforms['texturePosition'].value = gpuCompute.getCurrentRenderTarget(positionVariable).texture; - if (materialShader) - materialShader.uniforms['textureVelocity'].value = gpuCompute.getCurrentRenderTarget(velocityVariable).texture; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_gpgpu_protoplanet.ts b/examples-testing/examples/webgl_gpgpu_protoplanet.ts deleted file mode 100644 index b1a7e0287..000000000 --- a/examples-testing/examples/webgl_gpgpu_protoplanet.ts +++ /dev/null @@ -1,288 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { GPUComputationRenderer } from 'three/addons/misc/GPUComputationRenderer.js'; - -// Texture width for simulation (each texel is a debris particle) -const WIDTH = 64; - -let container, stats; -let camera, scene, renderer, geometry; - -const PARTICLES = WIDTH * WIDTH; - -let gpuCompute; -let velocityVariable; -let positionVariable; -let velocityUniforms; -let particleUniforms; -let effectController; - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 5, 15000); - camera.position.y = 120; - camera.position.z = 400; - - scene = new THREE.Scene(); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - const controls = new OrbitControls(camera, renderer.domElement); - controls.minDistance = 100; - controls.maxDistance = 1000; - - effectController = { - // Can be changed dynamically - gravityConstant: 100.0, - density: 0.45, - - // Must restart simulation - radius: 300, - height: 8, - exponent: 0.4, - maxMass: 15.0, - velocity: 70, - velocityExponent: 0.2, - randVelocity: 0.001, - }; - - initComputeRenderer(); - - stats = new Stats(); - container.appendChild(stats.dom); - - window.addEventListener('resize', onWindowResize); - - initGUI(); - - initProtoplanets(); - - dynamicValuesChanger(); -} - -function initComputeRenderer() { - gpuCompute = new GPUComputationRenderer(WIDTH, WIDTH, renderer); - - if (renderer.capabilities.isWebGL2 === false) { - gpuCompute.setDataType(THREE.HalfFloatType); - } - - const dtPosition = gpuCompute.createTexture(); - const dtVelocity = gpuCompute.createTexture(); - - fillTextures(dtPosition, dtVelocity); - - velocityVariable = gpuCompute.addVariable( - 'textureVelocity', - document.getElementById('computeShaderVelocity').textContent, - dtVelocity, - ); - positionVariable = gpuCompute.addVariable( - 'texturePosition', - document.getElementById('computeShaderPosition').textContent, - dtPosition, - ); - - gpuCompute.setVariableDependencies(velocityVariable, [positionVariable, velocityVariable]); - gpuCompute.setVariableDependencies(positionVariable, [positionVariable, velocityVariable]); - - velocityUniforms = velocityVariable.material.uniforms; - - velocityUniforms['gravityConstant'] = { value: 0.0 }; - velocityUniforms['density'] = { value: 0.0 }; - - const error = gpuCompute.init(); - - if (error !== null) { - console.error(error); - } -} - -function restartSimulation() { - const dtPosition = gpuCompute.createTexture(); - const dtVelocity = gpuCompute.createTexture(); - - fillTextures(dtPosition, dtVelocity); - - gpuCompute.renderTexture(dtPosition, positionVariable.renderTargets[0]); - gpuCompute.renderTexture(dtPosition, positionVariable.renderTargets[1]); - gpuCompute.renderTexture(dtVelocity, velocityVariable.renderTargets[0]); - gpuCompute.renderTexture(dtVelocity, velocityVariable.renderTargets[1]); -} - -function initProtoplanets() { - geometry = new THREE.BufferGeometry(); - - const positions = new Float32Array(PARTICLES * 3); - let p = 0; - - for (let i = 0; i < PARTICLES; i++) { - positions[p++] = (Math.random() * 2 - 1) * effectController.radius; - positions[p++] = 0; //( Math.random() * 2 - 1 ) * effectController.radius; - positions[p++] = (Math.random() * 2 - 1) * effectController.radius; - } - - const uvs = new Float32Array(PARTICLES * 2); - p = 0; - - for (let j = 0; j < WIDTH; j++) { - for (let i = 0; i < WIDTH; i++) { - uvs[p++] = i / (WIDTH - 1); - uvs[p++] = j / (WIDTH - 1); - } - } - - geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); - geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2)); - - particleUniforms = { - texturePosition: { value: null }, - textureVelocity: { value: null }, - cameraConstant: { value: getCameraConstant(camera) }, - density: { value: 0.0 }, - }; - - // THREE.ShaderMaterial - const material = new THREE.ShaderMaterial({ - uniforms: particleUniforms, - vertexShader: document.getElementById('particleVertexShader').textContent, - fragmentShader: document.getElementById('particleFragmentShader').textContent, - }); - - material.extensions.drawBuffers = true; - - const particles = new THREE.Points(geometry, material); - particles.matrixAutoUpdate = false; - particles.updateMatrix(); - - scene.add(particles); -} - -function fillTextures(texturePosition, textureVelocity) { - const posArray = texturePosition.image.data; - const velArray = textureVelocity.image.data; - - const radius = effectController.radius; - const height = effectController.height; - const exponent = effectController.exponent; - const maxMass = (effectController.maxMass * 1024) / PARTICLES; - const maxVel = effectController.velocity; - const velExponent = effectController.velocityExponent; - const randVel = effectController.randVelocity; - - for (let k = 0, kl = posArray.length; k < kl; k += 4) { - // Position - let x, z, rr; - - do { - x = Math.random() * 2 - 1; - z = Math.random() * 2 - 1; - rr = x * x + z * z; - } while (rr > 1); - - rr = Math.sqrt(rr); - - const rExp = radius * Math.pow(rr, exponent); - - // Velocity - const vel = maxVel * Math.pow(rr, velExponent); - - const vx = vel * z + (Math.random() * 2 - 1) * randVel; - const vy = (Math.random() * 2 - 1) * randVel * 0.05; - const vz = -vel * x + (Math.random() * 2 - 1) * randVel; - - x *= rExp; - z *= rExp; - const y = (Math.random() * 2 - 1) * height; - - const mass = Math.random() * maxMass + 1; - - // Fill in texture values - posArray[k + 0] = x; - posArray[k + 1] = y; - posArray[k + 2] = z; - posArray[k + 3] = 1; - - velArray[k + 0] = vx; - velArray[k + 1] = vy; - velArray[k + 2] = vz; - velArray[k + 3] = mass; - } -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - particleUniforms['cameraConstant'].value = getCameraConstant(camera); -} - -function dynamicValuesChanger() { - velocityUniforms['gravityConstant'].value = effectController.gravityConstant; - velocityUniforms['density'].value = effectController.density; - particleUniforms['density'].value = effectController.density; -} - -function initGUI() { - const gui = new GUI({ width: 280 }); - - const folder1 = gui.addFolder('Dynamic parameters'); - - folder1.add(effectController, 'gravityConstant', 0.0, 1000.0, 0.05).onChange(dynamicValuesChanger); - folder1.add(effectController, 'density', 0.0, 10.0, 0.001).onChange(dynamicValuesChanger); - - const folder2 = gui.addFolder('Static parameters'); - - folder2.add(effectController, 'radius', 10.0, 1000.0, 1.0); - folder2.add(effectController, 'height', 0.0, 50.0, 0.01); - folder2.add(effectController, 'exponent', 0.0, 2.0, 0.001); - folder2.add(effectController, 'maxMass', 1.0, 50.0, 0.1); - folder2.add(effectController, 'velocity', 0.0, 150.0, 0.1); - folder2.add(effectController, 'velocityExponent', 0.0, 1.0, 0.01); - folder2.add(effectController, 'randVelocity', 0.0, 50.0, 0.1); - - const buttonRestart = { - restartSimulation: function () { - restartSimulation(); - }, - }; - - folder2.add(buttonRestart, 'restartSimulation'); - - folder1.open(); - folder2.open(); -} - -function getCameraConstant(camera) { - return window.innerHeight / (Math.tan(THREE.MathUtils.DEG2RAD * 0.5 * camera.fov) / camera.zoom); -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - gpuCompute.compute(); - - particleUniforms['texturePosition'].value = gpuCompute.getCurrentRenderTarget(positionVariable).texture; - particleUniforms['textureVelocity'].value = gpuCompute.getCurrentRenderTarget(velocityVariable).texture; - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_gpgpu_water.ts b/examples-testing/examples/webgl_gpgpu_water.ts deleted file mode 100644 index dfc48210e..000000000 --- a/examples-testing/examples/webgl_gpgpu_water.ts +++ /dev/null @@ -1,403 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { GPUComputationRenderer } from 'three/addons/misc/GPUComputationRenderer.js'; -import { SimplexNoise } from 'three/addons/math/SimplexNoise.js'; - -// Texture width for simulation -const WIDTH = 128; - -// Water size in system units -const BOUNDS = 512; -const BOUNDS_HALF = BOUNDS * 0.5; - -let container, stats; -let camera, scene, renderer; -let mouseMoved = false; -const mouseCoords = new THREE.Vector2(); -const raycaster = new THREE.Raycaster(); - -let waterMesh; -let meshRay; -let gpuCompute; -let heightmapVariable; -let waterUniforms; -let smoothShader; -let readWaterLevelShader; -let readWaterLevelRenderTarget; -let readWaterLevelImage; -const waterNormal = new THREE.Vector3(); - -const NUM_SPHERES = 5; -const spheres = []; -let spheresEnabled = true; - -const simplex = new SimplexNoise(); - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 3000); - camera.position.set(0, 200, 350); - camera.lookAt(0, 0, 0); - - scene = new THREE.Scene(); - - const sun = new THREE.DirectionalLight(0xffffff, 3.0); - sun.position.set(300, 400, 175); - scene.add(sun); - - const sun2 = new THREE.DirectionalLight(0x40a040, 2.0); - sun2.position.set(-100, 350, -200); - scene.add(sun2); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - container.style.touchAction = 'none'; - container.addEventListener('pointermove', onPointerMove); - - document.addEventListener('keydown', function (event) { - // W Pressed: Toggle wireframe - if (event.keyCode === 87) { - waterMesh.material.wireframe = !waterMesh.material.wireframe; - waterMesh.material.needsUpdate = true; - } - }); - - window.addEventListener('resize', onWindowResize); - - const gui = new GUI(); - - const effectController = { - mouseSize: 20.0, - viscosity: 0.98, - spheresEnabled: spheresEnabled, - }; - - const valuesChanger = function () { - heightmapVariable.material.uniforms['mouseSize'].value = effectController.mouseSize; - heightmapVariable.material.uniforms['viscosityConstant'].value = effectController.viscosity; - spheresEnabled = effectController.spheresEnabled; - for (let i = 0; i < NUM_SPHERES; i++) { - if (spheres[i]) { - spheres[i].visible = spheresEnabled; - } - } - }; - - gui.add(effectController, 'mouseSize', 1.0, 100.0, 1.0).onChange(valuesChanger); - gui.add(effectController, 'viscosity', 0.9, 0.999, 0.001).onChange(valuesChanger); - gui.add(effectController, 'spheresEnabled', 0, 1, 1).onChange(valuesChanger); - const buttonSmooth = { - smoothWater: function () { - smoothWater(); - }, - }; - gui.add(buttonSmooth, 'smoothWater'); - - initWater(); - - createSpheres(); - - valuesChanger(); -} - -function initWater() { - const materialColor = 0x0040c0; - - const geometry = new THREE.PlaneGeometry(BOUNDS, BOUNDS, WIDTH - 1, WIDTH - 1); - - // material: make a THREE.ShaderMaterial clone of THREE.MeshPhongMaterial, with customized vertex shader - const material = new THREE.ShaderMaterial({ - uniforms: THREE.UniformsUtils.merge([ - THREE.ShaderLib['phong'].uniforms, - { - heightmap: { value: null }, - }, - ]), - vertexShader: document.getElementById('waterVertexShader').textContent, - fragmentShader: THREE.ShaderChunk['meshphong_frag'], - }); - - material.lights = true; - - // Material attributes from THREE.MeshPhongMaterial - // Sets the uniforms with the material values - material.uniforms['diffuse'].value = new THREE.Color(materialColor); - material.uniforms['specular'].value = new THREE.Color(0x111111); - material.uniforms['shininess'].value = Math.max(50, 1e-4); - material.uniforms['opacity'].value = material.opacity; - - // Defines - material.defines.WIDTH = WIDTH.toFixed(1); - material.defines.BOUNDS = BOUNDS.toFixed(1); - - waterUniforms = material.uniforms; - - waterMesh = new THREE.Mesh(geometry, material); - waterMesh.rotation.x = -Math.PI / 2; - waterMesh.matrixAutoUpdate = false; - waterMesh.updateMatrix(); - - scene.add(waterMesh); - - // THREE.Mesh just for mouse raycasting - const geometryRay = new THREE.PlaneGeometry(BOUNDS, BOUNDS, 1, 1); - meshRay = new THREE.Mesh(geometryRay, new THREE.MeshBasicMaterial({ color: 0xffffff, visible: false })); - meshRay.rotation.x = -Math.PI / 2; - meshRay.matrixAutoUpdate = false; - meshRay.updateMatrix(); - scene.add(meshRay); - - // Creates the gpu computation class and sets it up - - gpuCompute = new GPUComputationRenderer(WIDTH, WIDTH, renderer); - - if (renderer.capabilities.isWebGL2 === false) { - gpuCompute.setDataType(THREE.HalfFloatType); - } - - const heightmap0 = gpuCompute.createTexture(); - - fillTexture(heightmap0); - - heightmapVariable = gpuCompute.addVariable( - 'heightmap', - document.getElementById('heightmapFragmentShader').textContent, - heightmap0, - ); - - gpuCompute.setVariableDependencies(heightmapVariable, [heightmapVariable]); - - heightmapVariable.material.uniforms['mousePos'] = { value: new THREE.Vector2(10000, 10000) }; - heightmapVariable.material.uniforms['mouseSize'] = { value: 20.0 }; - heightmapVariable.material.uniforms['viscosityConstant'] = { value: 0.98 }; - heightmapVariable.material.uniforms['heightCompensation'] = { value: 0 }; - heightmapVariable.material.defines.BOUNDS = BOUNDS.toFixed(1); - - const error = gpuCompute.init(); - if (error !== null) { - console.error(error); - } - - // Create compute shader to smooth the water surface and velocity - smoothShader = gpuCompute.createShaderMaterial(document.getElementById('smoothFragmentShader').textContent, { - smoothTexture: { value: null }, - }); - - // Create compute shader to read water level - readWaterLevelShader = gpuCompute.createShaderMaterial( - document.getElementById('readWaterLevelFragmentShader').textContent, - { - point1: { value: new THREE.Vector2() }, - levelTexture: { value: null }, - }, - ); - readWaterLevelShader.defines.WIDTH = WIDTH.toFixed(1); - readWaterLevelShader.defines.BOUNDS = BOUNDS.toFixed(1); - - // Create a 4x1 pixel image and a render target (Uint8, 4 channels, 1 byte per channel) to read water height and orientation - readWaterLevelImage = new Uint8Array(4 * 1 * 4); - - readWaterLevelRenderTarget = new THREE.WebGLRenderTarget(4, 1, { - wrapS: THREE.ClampToEdgeWrapping, - wrapT: THREE.ClampToEdgeWrapping, - minFilter: THREE.NearestFilter, - magFilter: THREE.NearestFilter, - format: THREE.RGBAFormat, - type: THREE.UnsignedByteType, - depthBuffer: false, - }); -} - -function fillTexture(texture) { - const waterMaxHeight = 10; - - function noise(x, y) { - let multR = waterMaxHeight; - let mult = 0.025; - let r = 0; - for (let i = 0; i < 15; i++) { - r += multR * simplex.noise(x * mult, y * mult); - multR *= 0.53 + 0.025 * i; - mult *= 1.25; - } - - return r; - } - - const pixels = texture.image.data; - - let p = 0; - for (let j = 0; j < WIDTH; j++) { - for (let i = 0; i < WIDTH; i++) { - const x = (i * 128) / WIDTH; - const y = (j * 128) / WIDTH; - - pixels[p + 0] = noise(x, y); - pixels[p + 1] = pixels[p + 0]; - pixels[p + 2] = 0; - pixels[p + 3] = 1; - - p += 4; - } - } -} - -function smoothWater() { - const currentRenderTarget = gpuCompute.getCurrentRenderTarget(heightmapVariable); - const alternateRenderTarget = gpuCompute.getAlternateRenderTarget(heightmapVariable); - - for (let i = 0; i < 10; i++) { - smoothShader.uniforms['smoothTexture'].value = currentRenderTarget.texture; - gpuCompute.doRenderTarget(smoothShader, alternateRenderTarget); - - smoothShader.uniforms['smoothTexture'].value = alternateRenderTarget.texture; - gpuCompute.doRenderTarget(smoothShader, currentRenderTarget); - } -} - -function createSpheres() { - const sphereTemplate = new THREE.Mesh( - new THREE.SphereGeometry(4, 24, 12), - new THREE.MeshPhongMaterial({ color: 0xffff00 }), - ); - - for (let i = 0; i < NUM_SPHERES; i++) { - let sphere = sphereTemplate; - if (i < NUM_SPHERES - 1) { - sphere = sphereTemplate.clone(); - } - - sphere.position.x = (Math.random() - 0.5) * BOUNDS * 0.7; - sphere.position.z = (Math.random() - 0.5) * BOUNDS * 0.7; - - sphere.userData.velocity = new THREE.Vector3(); - - scene.add(sphere); - - spheres[i] = sphere; - } -} - -function sphereDynamics() { - const currentRenderTarget = gpuCompute.getCurrentRenderTarget(heightmapVariable); - - readWaterLevelShader.uniforms['levelTexture'].value = currentRenderTarget.texture; - - for (let i = 0; i < NUM_SPHERES; i++) { - const sphere = spheres[i]; - - if (sphere) { - // Read water level and orientation - const u = (0.5 * sphere.position.x) / BOUNDS_HALF + 0.5; - const v = 1 - ((0.5 * sphere.position.z) / BOUNDS_HALF + 0.5); - readWaterLevelShader.uniforms['point1'].value.set(u, v); - gpuCompute.doRenderTarget(readWaterLevelShader, readWaterLevelRenderTarget); - - renderer.readRenderTargetPixels(readWaterLevelRenderTarget, 0, 0, 4, 1, readWaterLevelImage); - const pixels = new Float32Array(readWaterLevelImage.buffer); - - // Get orientation - waterNormal.set(pixels[1], 0, -pixels[2]); - - const pos = sphere.position; - - // Set height - pos.y = pixels[0]; - - // Move sphere - waterNormal.multiplyScalar(0.1); - sphere.userData.velocity.add(waterNormal); - sphere.userData.velocity.multiplyScalar(0.998); - pos.add(sphere.userData.velocity); - - if (pos.x < -BOUNDS_HALF) { - pos.x = -BOUNDS_HALF + 0.001; - sphere.userData.velocity.x *= -0.3; - } else if (pos.x > BOUNDS_HALF) { - pos.x = BOUNDS_HALF - 0.001; - sphere.userData.velocity.x *= -0.3; - } - - if (pos.z < -BOUNDS_HALF) { - pos.z = -BOUNDS_HALF + 0.001; - sphere.userData.velocity.z *= -0.3; - } else if (pos.z > BOUNDS_HALF) { - pos.z = BOUNDS_HALF - 0.001; - sphere.userData.velocity.z *= -0.3; - } - } - } -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function setMouseCoords(x, y) { - mouseCoords.set((x / renderer.domElement.clientWidth) * 2 - 1, -(y / renderer.domElement.clientHeight) * 2 + 1); - mouseMoved = true; -} - -function onPointerMove(event) { - if (event.isPrimary === false) return; - - setMouseCoords(event.clientX, event.clientY); -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function render() { - // Set uniforms: mouse interaction - const uniforms = heightmapVariable.material.uniforms; - if (mouseMoved) { - raycaster.setFromCamera(mouseCoords, camera); - - const intersects = raycaster.intersectObject(meshRay); - - if (intersects.length > 0) { - const point = intersects[0].point; - uniforms['mousePos'].value.set(point.x, point.z); - } else { - uniforms['mousePos'].value.set(10000, 10000); - } - - mouseMoved = false; - } else { - uniforms['mousePos'].value.set(10000, 10000); - } - - // Do the gpu computation - gpuCompute.compute(); - - if (spheresEnabled) { - sphereDynamics(); - } - - // Get compute output in custom uniform - waterUniforms['heightmap'].value = gpuCompute.getCurrentRenderTarget(heightmapVariable).texture; - - // Render - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_materials_modified.ts b/examples-testing/examples/webgl_materials_modified.ts deleted file mode 100644 index 3708f65b7..000000000 --- a/examples-testing/examples/webgl_materials_modified.ts +++ /dev/null @@ -1,117 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; - -let camera, scene, renderer, stats; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.z = 20; - - scene = new THREE.Scene(); - - const loader = new GLTFLoader(); - loader.load('models/gltf/LeePerrySmith/LeePerrySmith.glb', function (gltf) { - const geometry = gltf.scene.children[0].geometry; - - let mesh = new THREE.Mesh(geometry, buildTwistMaterial(2.0)); - mesh.position.x = -3.5; - mesh.position.y = -0.5; - scene.add(mesh); - - mesh = new THREE.Mesh(geometry, buildTwistMaterial(-2.0)); - mesh.position.x = 3.5; - mesh.position.y = -0.5; - scene.add(mesh); - }); - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - const controls = new OrbitControls(camera, renderer.domElement); - controls.minDistance = 10; - controls.maxDistance = 50; - - // - - stats = new Stats(); - document.body.appendChild(stats.dom); - - // EVENTS - - window.addEventListener('resize', onWindowResize); -} - -function buildTwistMaterial(amount) { - const material = new THREE.MeshNormalMaterial(); - material.onBeforeCompile = function (shader) { - shader.uniforms.time = { value: 0 }; - - shader.vertexShader = 'uniform float time;\n' + shader.vertexShader; - shader.vertexShader = shader.vertexShader.replace( - '#include ', - [ - `float theta = sin( time + position.y ) / ${amount.toFixed(1)};`, - 'float c = cos( theta );', - 'float s = sin( theta );', - 'mat3 m = mat3( c, 0, s, 0, 1, 0, -s, 0, c );', - 'vec3 transformed = vec3( position ) * m;', - 'vNormal = vNormal * m;', - ].join('\n'), - ); - - material.userData.shader = shader; - }; - - // Make sure WebGLRenderer doesnt reuse a single program - - material.customProgramCacheKey = function () { - return amount.toFixed(1); - }; - - return material; -} - -// - -function onWindowResize() { - const width = window.innerWidth; - const height = window.innerHeight; - - camera.aspect = width / height; - camera.updateProjectionMatrix(); - - renderer.setSize(width, height); -} - -// - -function animate() { - requestAnimationFrame(animate); - - render(); - - stats.update(); -} - -function render() { - scene.traverse(function (child) { - if (child.isMesh) { - const shader = child.material.userData.shader; - - if (shader) { - shader.uniforms.time.value = performance.now() / 1000; - } - } - }); - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webgl_pmrem_test.ts b/examples-testing/examples/webgl_pmrem_test.ts deleted file mode 100644 index b33e4e2f1..000000000 --- a/examples-testing/examples/webgl_pmrem_test.ts +++ /dev/null @@ -1,141 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let scene, camera, controls, renderer; - -function init() { - const width = window.innerWidth; - const height = window.innerHeight; - const aspect = width / height; - - // renderer - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(width, height); - - // tonemapping - renderer.toneMapping = THREE.ACESFilmicToneMapping; - renderer.toneMappingExposure = 1; - - document.body.appendChild(renderer.domElement); - - window.addEventListener('resize', onWindowResize); - - // scene - - scene = new THREE.Scene(); - - // camera - - camera = new THREE.PerspectiveCamera(40, aspect, 1, 30); - updateCamera(); - camera.position.set(0, 0, 16); - - // controls - - controls = new OrbitControls(camera, renderer.domElement); - controls.addEventListener('change', render); // use if there is no animation loop - controls.minDistance = 4; - controls.maxDistance = 20; - - // light - - const directionalLight = new THREE.DirectionalLight(0xffffff, 0); // set intensity to 0 to start - const x = 597; - const y = 213; - const theta = ((x + 0.5) * Math.PI) / 512; - const phi = ((y + 0.5) * Math.PI) / 512; - - directionalLight.position.setFromSphericalCoords(100, -phi, Math.PI / 2 - theta); - - scene.add(directionalLight); - // scene.add( new THREE.DirectionalLightHelper( directionalLight ) ); - - // The spot1Lux HDR environment map is expressed in nits (lux / sr). The directional light has units of lux, - // so to match a 1 lux light, we set a single pixel with a value equal to 1 divided by the solid - // angle of the pixel in steradians. This image is 1024 x 512, - // so the value is 1 / ( sin( phi ) * ( pi / 512 ) ^ 2 ) = 27,490 nits. - - const gui = new GUI(); - gui.add({ enabled: true }, 'enabled') - .name('PMREM') - .onChange(value => { - directionalLight.intensity = value ? 0 : 1; - - scene.traverse(function (child) { - if (child.isMesh) { - child.material.envMapIntensity = 1 - directionalLight.intensity; - } - }); - - render(); - }); -} - -function createObjects() { - let radianceMap = null; - new RGBELoader() - // .setDataType( THREE.FloatType ) - .setPath('textures/equirectangular/') - .load('spot1Lux.hdr', function (texture) { - radianceMap = pmremGenerator.fromEquirectangular(texture).texture; - pmremGenerator.dispose(); - - scene.background = radianceMap; - - const geometry = new THREE.SphereGeometry(0.4, 32, 32); - - for (let x = 0; x <= 10; x++) { - for (let y = 0; y <= 2; y++) { - const material = new THREE.MeshPhysicalMaterial({ - roughness: x / 10, - metalness: y < 1 ? 1 : 0, - color: y < 2 ? 0xffffff : 0x000000, - envMap: radianceMap, - envMapIntensity: 1, - }); - - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = x - 5; - mesh.position.y = 1 - y; - scene.add(mesh); - } - } - - render(); - }); - - const pmremGenerator = new THREE.PMREMGenerator(renderer); - pmremGenerator.compileEquirectangularShader(); -} - -function onWindowResize() { - const width = window.innerWidth; - const height = window.innerHeight; - - camera.aspect = width / height; - updateCamera(); - - renderer.setSize(width, height); - - render(); -} - -function updateCamera() { - const horizontalFoV = 40; - const verticalFoV = - (2 * Math.atan(Math.tan(((horizontalFoV / 2) * Math.PI) / 180) / camera.aspect) * 180) / Math.PI; - camera.fov = verticalFoV; - camera.updateProjectionMatrix(); -} - -function render() { - renderer.render(scene, camera); -} - -Promise.resolve().then(init).then(createObjects).then(render); diff --git a/examples-testing/examples/webgl_postprocessing.ts b/examples-testing/examples/webgl_postprocessing.ts deleted file mode 100644 index 944115ba1..000000000 --- a/examples-testing/examples/webgl_postprocessing.ts +++ /dev/null @@ -1,88 +0,0 @@ -import * as THREE from 'three'; - -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; - -import { RGBShiftShader } from 'three/addons/shaders/RGBShiftShader.js'; -import { DotScreenShader } from 'three/addons/shaders/DotScreenShader.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; - -let camera, renderer, composer; -let object; - -init(); -animate(); - -function init() { - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - // - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.z = 400; - - const scene = new THREE.Scene(); - scene.fog = new THREE.Fog(0x000000, 1, 1000); - - object = new THREE.Object3D(); - scene.add(object); - - const geometry = new THREE.SphereGeometry(1, 4, 4); - const material = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); - - for (let i = 0; i < 100; i++) { - const mesh = new THREE.Mesh(geometry, material); - mesh.position.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize(); - mesh.position.multiplyScalar(Math.random() * 400); - mesh.rotation.set(Math.random() * 2, Math.random() * 2, Math.random() * 2); - mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 50; - object.add(mesh); - } - - scene.add(new THREE.AmbientLight(0xcccccc)); - - const light = new THREE.DirectionalLight(0xffffff, 3); - light.position.set(1, 1, 1); - scene.add(light); - - // postprocessing - - composer = new EffectComposer(renderer); - composer.addPass(new RenderPass(scene, camera)); - - const effect1 = new ShaderPass(DotScreenShader); - effect1.uniforms['scale'].value = 4; - composer.addPass(effect1); - - const effect2 = new ShaderPass(RGBShiftShader); - effect2.uniforms['amount'].value = 0.0015; - composer.addPass(effect2); - - const effect3 = new OutputPass(); - composer.addPass(effect3); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - composer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - object.rotation.x += 0.005; - object.rotation.y += 0.01; - - composer.render(); -} diff --git a/examples-testing/examples/webgl_postprocessing_advanced.ts b/examples-testing/examples/webgl_postprocessing_advanced.ts deleted file mode 100644 index bf49da5eb..000000000 --- a/examples-testing/examples/webgl_postprocessing_advanced.ts +++ /dev/null @@ -1,306 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; -import { BloomPass } from 'three/addons/postprocessing/BloomPass.js'; -import { FilmPass } from 'three/addons/postprocessing/FilmPass.js'; -import { DotScreenPass } from 'three/addons/postprocessing/DotScreenPass.js'; -import { MaskPass, ClearMaskPass } from 'three/addons/postprocessing/MaskPass.js'; -import { TexturePass } from 'three/addons/postprocessing/TexturePass.js'; - -import { BleachBypassShader } from 'three/addons/shaders/BleachBypassShader.js'; -import { ColorifyShader } from 'three/addons/shaders/ColorifyShader.js'; -import { HorizontalBlurShader } from 'three/addons/shaders/HorizontalBlurShader.js'; -import { VerticalBlurShader } from 'three/addons/shaders/VerticalBlurShader.js'; -import { SepiaShader } from 'three/addons/shaders/SepiaShader.js'; -import { VignetteShader } from 'three/addons/shaders/VignetteShader.js'; -import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.js'; - -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; - -let container, stats; - -let composerScene, composer1, composer2, composer3, composer4; - -let cameraOrtho, cameraPerspective, sceneModel, sceneBG, renderer, mesh, directionalLight; - -const width = window.innerWidth || 2; -const height = window.innerHeight || 2; - -let halfWidth = width / 2; -let halfHeight = height / 2; - -let quadBG, quadMask, renderScene; - -const delta = 0.01; - -init(); -animate(); - -function init() { - container = document.getElementById('container'); - - // - - cameraOrtho = new THREE.OrthographicCamera(-halfWidth, halfWidth, halfHeight, -halfHeight, -10000, 10000); - cameraOrtho.position.z = 100; - - cameraPerspective = new THREE.PerspectiveCamera(50, width / height, 1, 10000); - cameraPerspective.position.z = 900; - - // - - sceneModel = new THREE.Scene(); - sceneBG = new THREE.Scene(); - - // - - directionalLight = new THREE.DirectionalLight(0xffffff, 3); - directionalLight.position.set(0, -0.1, 1).normalize(); - sceneModel.add(directionalLight); - - const loader = new GLTFLoader(); - loader.load('models/gltf/LeePerrySmith/LeePerrySmith.glb', function (gltf) { - createMesh(gltf.scene.children[0].geometry, sceneModel, 100); - }); - - // - - const diffuseMap = new THREE.TextureLoader().load('textures/cube/SwedishRoyalCastle/pz.jpg'); - diffuseMap.colorSpace = THREE.SRGBColorSpace; - - const materialColor = new THREE.MeshBasicMaterial({ - map: diffuseMap, - depthTest: false, - }); - - quadBG = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), materialColor); - quadBG.position.z = -500; - quadBG.scale.set(width, height, 1); - sceneBG.add(quadBG); - - // - - const sceneMask = new THREE.Scene(); - - quadMask = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), new THREE.MeshBasicMaterial({ color: 0xffaa00 })); - quadMask.position.z = -300; - quadMask.scale.set(width / 2, height / 2, 1); - sceneMask.add(quadMask); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(width, height); - renderer.autoClear = false; - - // - - container.appendChild(renderer.domElement); - - // - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - const shaderBleach = BleachBypassShader; - const shaderSepia = SepiaShader; - const shaderVignette = VignetteShader; - - const effectBleach = new ShaderPass(shaderBleach); - const effectSepia = new ShaderPass(shaderSepia); - const effectVignette = new ShaderPass(shaderVignette); - const gammaCorrection = new ShaderPass(GammaCorrectionShader); - - effectBleach.uniforms['opacity'].value = 0.95; - - effectSepia.uniforms['amount'].value = 0.9; - - effectVignette.uniforms['offset'].value = 0.95; - effectVignette.uniforms['darkness'].value = 1.6; - - const effectBloom = new BloomPass(0.5); - const effectFilm = new FilmPass(0.35, 0.025, 648, false); - const effectFilmBW = new FilmPass(0.35, 0.5, 2048, true); - const effectDotScreen = new DotScreenPass(new THREE.Vector2(0, 0), 0.5, 0.8); - - const effectHBlur = new ShaderPass(HorizontalBlurShader); - const effectVBlur = new ShaderPass(VerticalBlurShader); - effectHBlur.uniforms['h'].value = 2 / (width / 2); - effectVBlur.uniforms['v'].value = 2 / (height / 2); - - const effectColorify1 = new ShaderPass(ColorifyShader); - const effectColorify2 = new ShaderPass(ColorifyShader); - effectColorify1.uniforms['color'] = new THREE.Uniform(new THREE.Color(1, 0.8, 0.8)); - effectColorify2.uniforms['color'] = new THREE.Uniform(new THREE.Color(1, 0.75, 0.5)); - - const clearMask = new ClearMaskPass(); - const renderMask = new MaskPass(sceneModel, cameraPerspective); - const renderMaskInverse = new MaskPass(sceneModel, cameraPerspective); - - renderMaskInverse.inverse = true; - - // - - const rtParameters = { - stencilBuffer: true, - }; - - const rtWidth = width / 2; - const rtHeight = height / 2; - - // - - const renderBackground = new RenderPass(sceneBG, cameraOrtho); - const renderModel = new RenderPass(sceneModel, cameraPerspective); - - renderModel.clear = false; - - composerScene = new EffectComposer(renderer, new THREE.WebGLRenderTarget(rtWidth * 2, rtHeight * 2, rtParameters)); - - composerScene.addPass(renderBackground); - composerScene.addPass(renderModel); - composerScene.addPass(renderMaskInverse); - composerScene.addPass(effectHBlur); - composerScene.addPass(effectVBlur); - composerScene.addPass(clearMask); - - // - - renderScene = new TexturePass(composerScene.renderTarget2.texture); - - // - - composer1 = new EffectComposer(renderer, new THREE.WebGLRenderTarget(rtWidth, rtHeight, rtParameters)); - - composer1.addPass(renderScene); - composer1.addPass(gammaCorrection); - composer1.addPass(effectFilmBW); - composer1.addPass(effectVignette); - - // - - composer2 = new EffectComposer(renderer, new THREE.WebGLRenderTarget(rtWidth, rtHeight, rtParameters)); - - composer2.addPass(renderScene); - composer2.addPass(gammaCorrection); - composer2.addPass(effectDotScreen); - composer2.addPass(renderMask); - composer2.addPass(effectColorify1); - composer2.addPass(clearMask); - composer2.addPass(renderMaskInverse); - composer2.addPass(effectColorify2); - composer2.addPass(clearMask); - composer2.addPass(effectVignette); - - // - - composer3 = new EffectComposer(renderer, new THREE.WebGLRenderTarget(rtWidth, rtHeight, rtParameters)); - - composer3.addPass(renderScene); - composer3.addPass(gammaCorrection); - composer3.addPass(effectSepia); - composer3.addPass(effectFilm); - composer3.addPass(effectVignette); - - // - - composer4 = new EffectComposer(renderer, new THREE.WebGLRenderTarget(rtWidth, rtHeight, rtParameters)); - - composer4.addPass(renderScene); - composer4.addPass(gammaCorrection); - composer4.addPass(effectBloom); - composer4.addPass(effectFilm); - composer4.addPass(effectBleach); - composer4.addPass(effectVignette); - - renderScene.uniforms['tDiffuse'].value = composerScene.renderTarget2.texture; - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - halfWidth = window.innerWidth / 2; - halfHeight = window.innerHeight / 2; - - cameraPerspective.aspect = window.innerWidth / window.innerHeight; - cameraPerspective.updateProjectionMatrix(); - - cameraOrtho.left = -halfWidth; - cameraOrtho.right = halfWidth; - cameraOrtho.top = halfHeight; - cameraOrtho.bottom = -halfHeight; - - cameraOrtho.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - - composerScene.setSize(halfWidth * 2, halfHeight * 2); - - composer1.setSize(halfWidth, halfHeight); - composer2.setSize(halfWidth, halfHeight); - composer3.setSize(halfWidth, halfHeight); - composer4.setSize(halfWidth, halfHeight); - - renderScene.uniforms['tDiffuse'].value = composerScene.renderTarget2.texture; - - quadBG.scale.set(window.innerWidth, window.innerHeight, 1); - quadMask.scale.set(window.innerWidth / 2, window.innerHeight / 2, 1); -} - -function createMesh(geometry, scene, scale) { - const diffuseMap = new THREE.TextureLoader().load('models/gltf/LeePerrySmith/Map-COL.jpg'); - diffuseMap.colorSpace = THREE.SRGBColorSpace; - - const mat2 = new THREE.MeshPhongMaterial({ - color: 0xcbcbcb, - specular: 0x080808, - shininess: 20, - map: diffuseMap, - normalMap: new THREE.TextureLoader().load('models/gltf/LeePerrySmith/Infinite-Level_02_Tangent_SmoothUV.jpg'), - normalScale: new THREE.Vector2(0.75, 0.75), - }); - - mesh = new THREE.Mesh(geometry, mat2); - mesh.position.set(0, -50, 0); - mesh.scale.set(scale, scale, scale); - - scene.add(mesh); -} - -// - -function animate() { - requestAnimationFrame(animate); - - stats.begin(); - render(); - stats.end(); -} - -function render() { - const time = Date.now() * 0.0004; - - if (mesh) mesh.rotation.y = -time; - - renderer.setViewport(0, 0, halfWidth, halfHeight); - composerScene.render(delta); - - renderer.setViewport(0, 0, halfWidth, halfHeight); - composer1.render(delta); - - renderer.setViewport(halfWidth, 0, halfWidth, halfHeight); - composer2.render(delta); - - renderer.setViewport(0, halfHeight, halfWidth, halfHeight); - composer3.render(delta); - - renderer.setViewport(halfWidth, halfHeight, halfWidth, halfHeight); - composer4.render(delta); -} diff --git a/examples-testing/examples/webgl_postprocessing_afterimage.ts b/examples-testing/examples/webgl_postprocessing_afterimage.ts deleted file mode 100644 index 2477c5002..000000000 --- a/examples-testing/examples/webgl_postprocessing_afterimage.ts +++ /dev/null @@ -1,86 +0,0 @@ -import * as THREE from 'three'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { AfterimagePass } from 'three/addons/postprocessing/AfterimagePass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; - -let camera, scene, renderer, composer; -let mesh; - -let afterimagePass; - -const params = { - enable: true, -}; - -init(); -createGUI(); -animate(); - -function init() { - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.z = 400; - - scene = new THREE.Scene(); - scene.fog = new THREE.Fog(0x000000, 1, 1000); - - const geometry = new THREE.BoxGeometry(150, 150, 150, 2, 2, 2); - const material = new THREE.MeshNormalMaterial(); - mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // postprocessing - - composer = new EffectComposer(renderer); - composer.addPass(new RenderPass(scene, camera)); - - afterimagePass = new AfterimagePass(); - composer.addPass(afterimagePass); - - const outputPass = new OutputPass(); - composer.addPass(outputPass); - - window.addEventListener('resize', onWindowResize); - - if (typeof TESTING !== 'undefined') { - for (let i = 0; i < 45; i++) { - render(); - } - } -} - -function createGUI() { - const gui = new GUI({ title: 'Damp setting' }); - gui.add(afterimagePass.uniforms['damp'], 'value', 0, 1).step(0.001); - gui.add(params, 'enable'); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - composer.setSize(window.innerWidth, window.innerHeight); -} - -function render() { - mesh.rotation.x += 0.005; - mesh.rotation.y += 0.01; - - afterimagePass.enabled = params.enable; - - composer.render(); -} - -function animate() { - requestAnimationFrame(animate); - render(); -} diff --git a/examples-testing/examples/webgl_postprocessing_backgrounds.ts b/examples-testing/examples/webgl_postprocessing_backgrounds.ts deleted file mode 100644 index 0bfb65506..000000000 --- a/examples-testing/examples/webgl_postprocessing_backgrounds.ts +++ /dev/null @@ -1,216 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { TexturePass } from 'three/addons/postprocessing/TexturePass.js'; -import { CubeTexturePass } from 'three/addons/postprocessing/CubeTexturePass.js'; -import { ClearPass } from 'three/addons/postprocessing/ClearPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -let scene, renderer, composer; -let clearPass, texturePass, renderPass; -let cameraP, cubeTexturePassP; -let gui, stats; - -const params = { - clearPass: true, - clearColor: 'white', - clearAlpha: 1.0, - - texturePass: true, - texturePassOpacity: 1.0, - - cubeTexturePass: true, - cubeTexturePassOpacity: 1.0, - - renderPass: true, -}; - -init(); -animate(); - -clearGui(); - -function clearGui() { - if (gui) gui.destroy(); - - gui = new GUI(); - - gui.add(params, 'clearPass'); - gui.add(params, 'clearColor', ['black', 'white', 'blue', 'green', 'red']); - gui.add(params, 'clearAlpha', 0, 1); - - gui.add(params, 'texturePass'); - gui.add(params, 'texturePassOpacity', 0, 1); - - gui.add(params, 'cubeTexturePass'); - gui.add(params, 'cubeTexturePassOpacity', 0, 1); - - gui.add(params, 'renderPass'); - - gui.open(); -} - -function init() { - const container = document.getElementById('container'); - - const width = window.innerWidth || 1; - const height = window.innerHeight || 1; - const aspect = width / height; - const devicePixelRatio = window.devicePixelRatio || 1; - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(devicePixelRatio); - renderer.setSize(width, height); - document.body.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - cameraP = new THREE.PerspectiveCamera(65, aspect, 1, 10); - cameraP.position.z = 7; - - scene = new THREE.Scene(); - - const group = new THREE.Group(); - scene.add(group); - - const light = new THREE.PointLight(0xefffef, 500); - light.position.z = 10; - light.position.y = -10; - light.position.x = -10; - scene.add(light); - - const light2 = new THREE.PointLight(0xffefef, 500); - light2.position.z = 10; - light2.position.x = -10; - light2.position.y = 10; - scene.add(light2); - - const light3 = new THREE.PointLight(0xefefff, 500); - light3.position.z = 10; - light3.position.x = 10; - light3.position.y = -10; - scene.add(light3); - - const geometry = new THREE.SphereGeometry(1, 48, 24); - - const material = new THREE.MeshStandardMaterial(); - material.roughness = 0.5 * Math.random() + 0.25; - material.metalness = 0; - material.color.setHSL(Math.random(), 1.0, 0.3); - - const mesh = new THREE.Mesh(geometry, material); - group.add(mesh); - - // postprocessing - - const genCubeUrls = function (prefix, postfix) { - return [ - prefix + 'px' + postfix, - prefix + 'nx' + postfix, - prefix + 'py' + postfix, - prefix + 'ny' + postfix, - prefix + 'pz' + postfix, - prefix + 'nz' + postfix, - ]; - }; - - composer = new EffectComposer(renderer); - - clearPass = new ClearPass(params.clearColor, params.clearAlpha); - composer.addPass(clearPass); - - texturePass = new TexturePass(); - composer.addPass(texturePass); - - const textureLoader = new THREE.TextureLoader(); - textureLoader.load('textures/hardwood2_diffuse.jpg', function (map) { - map.colorSpace = THREE.SRGBColorSpace; - texturePass.map = map; - }); - - cubeTexturePassP = null; - - const ldrUrls = genCubeUrls('textures/cube/pisa/', '.png'); - new THREE.CubeTextureLoader().load(ldrUrls, function (ldrCubeMap) { - cubeTexturePassP = new CubeTexturePass(cameraP, ldrCubeMap); - composer.insertPass(cubeTexturePassP, 2); - }); - - renderPass = new RenderPass(scene, cameraP); - renderPass.clear = false; - composer.addPass(renderPass); - - const outputPass = new OutputPass(); - composer.addPass(outputPass); - - const controls = new OrbitControls(cameraP, renderer.domElement); - controls.enableZoom = false; - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - const width = window.innerWidth; - const height = window.innerHeight; - const aspect = width / height; - - cameraP.aspect = aspect; - cameraP.updateProjectionMatrix(); - - renderer.setSize(width, height); - composer.setSize(width, height); -} - -function animate() { - requestAnimationFrame(animate); - - stats.begin(); - - cameraP.updateMatrixWorld(true); - - let newColor = clearPass.clearColor; - - switch (params.clearColor) { - case 'blue': - newColor = 0x0000ff; - break; - case 'red': - newColor = 0xff0000; - break; - case 'green': - newColor = 0x00ff00; - break; - case 'white': - newColor = 0xffffff; - break; - case 'black': - newColor = 0x000000; - break; - } - - clearPass.enabled = params.clearPass; - clearPass.clearColor = newColor; - clearPass.clearAlpha = params.clearAlpha; - - texturePass.enabled = params.texturePass; - texturePass.opacity = params.texturePassOpacity; - - if (cubeTexturePassP !== null) { - cubeTexturePassP.enabled = params.cubeTexturePass; - cubeTexturePassP.opacity = params.cubeTexturePassOpacity; - } - - renderPass.enabled = params.renderPass; - - composer.render(); - - stats.end(); -} diff --git a/examples-testing/examples/webgl_postprocessing_crossfade.ts b/examples-testing/examples/webgl_postprocessing_crossfade.ts deleted file mode 100644 index d3203e35b..000000000 --- a/examples-testing/examples/webgl_postprocessing_crossfade.ts +++ /dev/null @@ -1,302 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import TWEEN from 'three/addons/libs/tween.module.js'; - -let container, stats; -let renderer; -let transition; - -const transitionParams = { - useTexture: true, - transition: 0, - texture: 5, - cycle: true, - animate: true, - threshold: 0.3, -}; - -const clock = new THREE.Clock(); - -init(); -animate(); - -function init() { - initGUI(); - - container = document.getElementById('container'); - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - const geometryA = new THREE.BoxGeometry(2, 2, 2); - const geometryB = new THREE.IcosahedronGeometry(1, 1); - const sceneA = new FXScene(geometryA, new THREE.Vector3(0, -0.4, 0), 0xffffff); - const sceneB = new FXScene(geometryB, new THREE.Vector3(0, 0.2, 0.1), 0x000000); - - transition = new Transition(sceneA, sceneB); -} - -function animate() { - requestAnimationFrame(animate); - - render(); - stats.update(); -} - -function initGUI() { - const gui = new GUI(); - - gui.add(transitionParams, 'animate'); - gui.add(transitionParams, 'transition', 0, 1, 0.01).listen(); - - gui.add(transitionParams, 'useTexture').onChange(function (value) { - transition.useTexture(value); - }); - - gui.add(transitionParams, 'texture', { Perlin: 0, Squares: 1, Cells: 2, Distort: 3, Gradient: 4, Radial: 5 }) - .onChange(function (value) { - transition.setTexture(value); - }) - .listen(); - - gui.add(transitionParams, 'cycle'); - - gui.add(transitionParams, 'threshold', 0, 1, 0.01).onChange(function (value) { - transition.setTextureThreshold(value); - }); -} - -function render() { - transition.render(clock.getDelta()); -} - -function generateInstancedMesh(geometry, material, count) { - const mesh = new THREE.InstancedMesh(geometry, material, count); - - const dummy = new THREE.Object3D(); - const color = new THREE.Color(); - - for (let i = 0; i < count; i++) { - dummy.position.x = Math.random() * 100 - 50; - dummy.position.y = Math.random() * 60 - 30; - dummy.position.z = Math.random() * 80 - 40; - - dummy.rotation.x = Math.random() * 2 * Math.PI; - dummy.rotation.y = Math.random() * 2 * Math.PI; - dummy.rotation.z = Math.random() * 2 * Math.PI; - - dummy.scale.x = Math.random() * 2 + 1; - - if (geometry.type === 'BoxGeometry') { - dummy.scale.y = Math.random() * 2 + 1; - dummy.scale.z = Math.random() * 2 + 1; - } else { - dummy.scale.y = dummy.scale.x; - dummy.scale.z = dummy.scale.x; - } - - dummy.updateMatrix(); - - mesh.setMatrixAt(i, dummy.matrix); - mesh.setColorAt(i, color.setScalar(0.1 + 0.9 * Math.random())); - } - - return mesh; -} - -function FXScene(geometry, rotationSpeed, clearColor) { - this.clearColor = clearColor; - - const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.z = 20; - - // Setup scene - const scene = new THREE.Scene(); - scene.add(new THREE.AmbientLight(0xaaaaaa, 3)); - - const light = new THREE.DirectionalLight(0xffffff, 3); - light.position.set(0, 1, 4); - scene.add(light); - - this.rotationSpeed = rotationSpeed; - - const color = geometry.type === 'BoxGeometry' ? 0x0000ff : 0xff0000; - const material = new THREE.MeshPhongMaterial({ color: color, flatShading: true }); - const mesh = generateInstancedMesh(geometry, material, 500); - scene.add(mesh); - - this.fbo = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, { type: THREE.HalfFloatType }); - - this.render = function (delta, rtt) { - mesh.rotation.x += delta * this.rotationSpeed.x; - mesh.rotation.y += delta * this.rotationSpeed.y; - mesh.rotation.z += delta * this.rotationSpeed.z; - - renderer.setClearColor(this.clearColor); - - if (rtt) { - renderer.setRenderTarget(this.fbo); - renderer.clear(); - renderer.render(scene, camera); - } else { - renderer.setRenderTarget(null); - renderer.render(scene, camera); - } - }; -} - -function Transition(sceneA, sceneB) { - const scene = new THREE.Scene(); - - const width = window.innerWidth; - const height = window.innerHeight; - - const camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, -10, 10); - - const textures = []; - - const loader = new THREE.TextureLoader(); - - for (let i = 0; i < 6; i++) { - textures[i] = loader.load('textures/transition/transition' + (i + 1) + '.png'); - } - - const material = new THREE.ShaderMaterial({ - uniforms: { - tDiffuse1: { - value: null, - }, - tDiffuse2: { - value: null, - }, - mixRatio: { - value: 0.0, - }, - threshold: { - value: 0.1, - }, - useTexture: { - value: 1, - }, - tMixTexture: { - value: textures[0], - }, - }, - vertexShader: [ - 'varying vec2 vUv;', - - 'void main() {', - - 'vUv = vec2( uv.x, uv.y );', - 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', - - '}', - ].join('\n'), - fragmentShader: [ - 'uniform float mixRatio;', - - 'uniform sampler2D tDiffuse1;', - 'uniform sampler2D tDiffuse2;', - 'uniform sampler2D tMixTexture;', - - 'uniform int useTexture;', - 'uniform float threshold;', - - 'varying vec2 vUv;', - - 'void main() {', - - ' vec4 texel1 = texture2D( tDiffuse1, vUv );', - ' vec4 texel2 = texture2D( tDiffuse2, vUv );', - - ' if (useTexture==1) {', - - ' vec4 transitionTexel = texture2D( tMixTexture, vUv );', - ' float r = mixRatio * (1.0 + threshold * 2.0) - threshold;', - ' float mixf=clamp((transitionTexel.r - r)*(1.0/threshold), 0.0, 1.0);', - - ' gl_FragColor = mix( texel1, texel2, mixf );', - - ' } else {', - - ' gl_FragColor = mix( texel2, texel1, mixRatio );', - - ' }', - - ' #include ', - ' #include ', - - '}', - ].join('\n'), - }); - - const geometry = new THREE.PlaneGeometry(window.innerWidth, window.innerHeight); - const mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - material.uniforms.tDiffuse1.value = sceneA.fbo.texture; - material.uniforms.tDiffuse2.value = sceneB.fbo.texture; - - new TWEEN.Tween(transitionParams).to({ transition: 1 }, 1500).repeat(Infinity).delay(2000).yoyo(true).start(); - - this.needsTextureChange = false; - - this.setTextureThreshold = function (value) { - material.uniforms.threshold.value = value; - }; - - this.useTexture = function (value) { - material.uniforms.useTexture.value = value ? 1 : 0; - }; - - this.setTexture = function (i) { - material.uniforms.tMixTexture.value = textures[i]; - }; - - this.render = function (delta) { - // Transition animation - if (transitionParams.animate) { - TWEEN.update(); - - // Change the current alpha texture after each transition - if (transitionParams.cycle) { - if (transitionParams.transition == 0 || transitionParams.transition == 1) { - if (this.needsTextureChange) { - transitionParams.texture = (transitionParams.texture + 1) % textures.length; - material.uniforms.tMixTexture.value = textures[transitionParams.texture]; - this.needsTextureChange = false; - } - } else { - this.needsTextureChange = true; - } - } else { - this.needsTextureChange = true; - } - } - - material.uniforms.mixRatio.value = transitionParams.transition; - - // Prevent render both scenes when it's not necessary - if (transitionParams.transition == 0) { - sceneB.render(delta, false); - } else if (transitionParams.transition == 1) { - sceneA.render(delta, false); - } else { - // When 0 0) { - const selectedObject = intersects[0].object; - addSelectedObject(selectedObject); - outlinePass.selectedObjects = selectedObjects; - } else { - // outlinePass.selectedObjects = []; - } - } -} - -function onWindowResize() { - const width = window.innerWidth; - const height = window.innerHeight; - - camera.aspect = width / height; - camera.updateProjectionMatrix(); - - renderer.setSize(width, height); - composer.setSize(width, height); - - effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - stats.begin(); - - const timer = performance.now(); - - if (params.rotate) { - group.rotation.y = timer * 0.0001; - } - - controls.update(); - - composer.render(); - - stats.end(); -} diff --git a/examples-testing/examples/webgl_postprocessing_pixel.ts b/examples-testing/examples/webgl_postprocessing_pixel.ts deleted file mode 100644 index fa763090a..000000000 --- a/examples-testing/examples/webgl_postprocessing_pixel.ts +++ /dev/null @@ -1,230 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPixelatedPass } from 'three/addons/postprocessing/RenderPixelatedPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let camera, scene, renderer, composer, crystalMesh, clock; -let gui, params; - -init(); -animate(); - -function init() { - const aspectRatio = window.innerWidth / window.innerHeight; - - camera = new THREE.OrthographicCamera(-aspectRatio, aspectRatio, 1, -1, 0.1, 10); - camera.position.y = 2 * Math.tan(Math.PI / 6); - camera.position.z = 2; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x151729); - - clock = new THREE.Clock(); - - renderer = new THREE.WebGLRenderer(); - renderer.shadowMap.enabled = true; - //renderer.setPixelRatio( window.devicePixelRatio ); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - composer = new EffectComposer(renderer); - const renderPixelatedPass = new RenderPixelatedPass(6, scene, camera); - composer.addPass(renderPixelatedPass); - - const outputPass = new OutputPass(); - composer.addPass(outputPass); - - window.addEventListener('resize', onWindowResize); - - const controls = new OrbitControls(camera, renderer.domElement); - controls.maxZoom = 2; - - // gui - - gui = new GUI(); - params = { pixelSize: 6, normalEdgeStrength: 0.3, depthEdgeStrength: 0.4, pixelAlignedPanning: true }; - gui.add(params, 'pixelSize') - .min(1) - .max(16) - .step(1) - .onChange(() => { - renderPixelatedPass.setPixelSize(params.pixelSize); - }); - gui.add(renderPixelatedPass, 'normalEdgeStrength').min(0).max(2).step(0.05); - gui.add(renderPixelatedPass, 'depthEdgeStrength').min(0).max(1).step(0.05); - gui.add(params, 'pixelAlignedPanning'); - - // textures - - const loader = new THREE.TextureLoader(); - const texChecker = pixelTexture(loader.load('textures/checker.png')); - const texChecker2 = pixelTexture(loader.load('textures/checker.png')); - texChecker.repeat.set(3, 3); - texChecker2.repeat.set(1.5, 1.5); - - // meshes - - const boxMaterial = new THREE.MeshPhongMaterial({ map: texChecker2 }); - - function addBox(boxSideLength, x, z, rotation) { - const mesh = new THREE.Mesh(new THREE.BoxGeometry(boxSideLength, boxSideLength, boxSideLength), boxMaterial); - mesh.castShadow = true; - mesh.receiveShadow = true; - mesh.rotation.y = rotation; - mesh.position.y = boxSideLength / 2; - mesh.position.set(x, boxSideLength / 2 + 0.0001, z); - scene.add(mesh); - return mesh; - } - - addBox(0.4, 0, 0, Math.PI / 4); - addBox(0.5, -0.5, -0.5, Math.PI / 4); - - const planeSideLength = 2; - const planeMesh = new THREE.Mesh( - new THREE.PlaneGeometry(planeSideLength, planeSideLength), - new THREE.MeshPhongMaterial({ map: texChecker }), - ); - planeMesh.receiveShadow = true; - planeMesh.rotation.x = -Math.PI / 2; - scene.add(planeMesh); - - const radius = 0.2; - const geometry = new THREE.IcosahedronGeometry(radius); - crystalMesh = new THREE.Mesh( - geometry, - new THREE.MeshPhongMaterial({ - color: 0x68b7e9, - emissive: 0x4f7e8b, - shininess: 10, - specular: 0xffffff, - }), - ); - crystalMesh.receiveShadow = true; - crystalMesh.castShadow = true; - scene.add(crystalMesh); - - // lights - - scene.add(new THREE.AmbientLight(0x757f8e, 3)); - - const directionalLight = new THREE.DirectionalLight(0xfffecd, 1.5); - directionalLight.position.set(100, 100, 100); - directionalLight.castShadow = true; - directionalLight.shadow.mapSize.set(2048, 2048); - scene.add(directionalLight); - - const spotLight = new THREE.SpotLight(0xffc100, 10, 10, Math.PI / 16, 0.02, 2); - spotLight.position.set(2, 2, 0); - const target = spotLight.target; - scene.add(target); - target.position.set(0, 0, 0); - spotLight.castShadow = true; - scene.add(spotLight); -} - -function onWindowResize() { - const aspectRatio = window.innerWidth / window.innerHeight; - camera.left = -aspectRatio; - camera.right = aspectRatio; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - composer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - const t = clock.getElapsedTime(); - - crystalMesh.material.emissiveIntensity = Math.sin(t * 3) * 0.5 + 0.5; - crystalMesh.position.y = 0.7 + Math.sin(t * 2) * 0.05; - crystalMesh.rotation.y = stopGoEased(t, 2, 4) * 2 * Math.PI; - - const rendererSize = renderer.getSize(new THREE.Vector2()); - const aspectRatio = rendererSize.x / rendererSize.y; - if (params['pixelAlignedPanning']) { - pixelAlignFrustum( - camera, - aspectRatio, - Math.floor(rendererSize.x / params['pixelSize']), - Math.floor(rendererSize.y / params['pixelSize']), - ); - } else if (camera.left != -aspectRatio || camera.top != 1.0) { - // Reset the Camera Frustum if it has been modified - camera.left = -aspectRatio; - camera.right = aspectRatio; - camera.top = 1.0; - camera.bottom = -1.0; - camera.updateProjectionMatrix(); - } - - composer.render(); -} - -// Helper functions - -function pixelTexture(texture) { - texture.minFilter = THREE.NearestFilter; - texture.magFilter = THREE.NearestFilter; - texture.generateMipmaps = false; - texture.wrapS = THREE.RepeatWrapping; - texture.wrapT = THREE.RepeatWrapping; - texture.colorSpace = THREE.SRGBColorSpace; - return texture; -} - -function easeInOutCubic(x) { - return x ** 2 * 3 - x ** 3 * 2; -} - -function linearStep(x, edge0, edge1) { - const w = edge1 - edge0; - const m = 1 / w; - const y0 = -m * edge0; - return THREE.MathUtils.clamp(y0 + m * x, 0, 1); -} - -function stopGoEased(x, downtime, period) { - const cycle = (x / period) | 0; - const tween = x - cycle * period; - const linStep = easeInOutCubic(linearStep(tween, downtime, period)); - return cycle + linStep; -} - -function pixelAlignFrustum(camera, aspectRatio, pixelsPerScreenWidth, pixelsPerScreenHeight) { - // 0. Get Pixel Grid Units - const worldScreenWidth = (camera.right - camera.left) / camera.zoom; - const worldScreenHeight = (camera.top - camera.bottom) / camera.zoom; - const pixelWidth = worldScreenWidth / pixelsPerScreenWidth; - const pixelHeight = worldScreenHeight / pixelsPerScreenHeight; - - // 1. Project the current camera position along its local rotation bases - const camPos = new THREE.Vector3(); - camera.getWorldPosition(camPos); - const camRot = new THREE.Quaternion(); - camera.getWorldQuaternion(camRot); - const camRight = new THREE.Vector3(1.0, 0.0, 0.0).applyQuaternion(camRot); - const camUp = new THREE.Vector3(0.0, 1.0, 0.0).applyQuaternion(camRot); - const camPosRight = camPos.dot(camRight); - const camPosUp = camPos.dot(camUp); - - // 2. Find how far along its position is along these bases in pixel units - const camPosRightPx = camPosRight / pixelWidth; - const camPosUpPx = camPosUp / pixelHeight; - - // 3. Find the fractional pixel units and convert to world units - const fractX = camPosRightPx - Math.round(camPosRightPx); - const fractY = camPosUpPx - Math.round(camPosUpPx); - - // 4. Add fractional world units to the left/right top/bottom to align with the pixel grid - camera.left = -aspectRatio - fractX * pixelWidth; - camera.right = aspectRatio - fractX * pixelWidth; - camera.top = 1.0 - fractY * pixelHeight; - camera.bottom = -1.0 - fractY * pixelHeight; - camera.updateProjectionMatrix(); -} diff --git a/examples-testing/examples/webgl_postprocessing_procedural.ts b/examples-testing/examples/webgl_postprocessing_procedural.ts deleted file mode 100644 index 860b1c4d7..000000000 --- a/examples-testing/examples/webgl_postprocessing_procedural.ts +++ /dev/null @@ -1,81 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -let postCamera, postScene, renderer; -let postMaterial, noiseRandom1DMaterial, noiseRandom2DMaterial, noiseRandom3DMaterial, postQuad; -let stats; - -const params = { procedure: 'noiseRandom3D' }; - -init(); -animate(); -initGui(); - -// Init gui -function initGui() { - const gui = new GUI(); - gui.add(params, 'procedure', ['noiseRandom1D', 'noiseRandom2D', 'noiseRandom3D']); -} - -function init() { - const container = document.getElementById('container'); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - // Setup post processing stage - postCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); - noiseRandom1DMaterial = new THREE.ShaderMaterial({ - vertexShader: document.querySelector('#procedural-vert').textContent.trim(), - fragmentShader: document.querySelector('#noiseRandom1D-frag').textContent.trim(), - }); - noiseRandom2DMaterial = new THREE.ShaderMaterial({ - vertexShader: document.querySelector('#procedural-vert').textContent.trim(), - fragmentShader: document.querySelector('#noiseRandom2D-frag').textContent.trim(), - }); - noiseRandom3DMaterial = new THREE.ShaderMaterial({ - vertexShader: document.querySelector('#procedural-vert').textContent.trim(), - fragmentShader: document.querySelector('#noiseRandom3D-frag').textContent.trim(), - }); - postMaterial = noiseRandom3DMaterial; - const postPlane = new THREE.PlaneGeometry(2, 2); - postQuad = new THREE.Mesh(postPlane, postMaterial); - postScene = new THREE.Scene(); - postScene.add(postQuad); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - switch (params.procedure) { - case 'noiseRandom1D': - postMaterial = noiseRandom1DMaterial; - break; - case 'noiseRandom2D': - postMaterial = noiseRandom2DMaterial; - break; - case 'noiseRandom3D': - postMaterial = noiseRandom3DMaterial; - break; - } - - postQuad.material = postMaterial; - - // render post FX - renderer.render(postScene, postCamera); - - stats.update(); -} diff --git a/examples-testing/examples/webgl_postprocessing_rgb_halftone.ts b/examples-testing/examples/webgl_postprocessing_rgb_halftone.ts deleted file mode 100644 index e81303e9f..000000000 --- a/examples-testing/examples/webgl_postprocessing_rgb_halftone.ts +++ /dev/null @@ -1,169 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { HalftonePass } from 'three/addons/postprocessing/HalftonePass.js'; - -let renderer, clock, camera, stats; - -const rotationSpeed = Math.PI / 64; - -let composer, group; - -init(); -animate(); - -function init() { - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - - clock = new THREE.Clock(); - - camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.z = 12; - - stats = new Stats(); - - document.body.appendChild(renderer.domElement); - document.body.appendChild(stats.dom); - - // camera controls - const controls = new OrbitControls(camera, renderer.domElement); - controls.target.set(0, 0, 0); - controls.update(); - - // scene - - const scene = new THREE.Scene(); - scene.background = new THREE.Color(0x444444); - - group = new THREE.Group(); - const floor = new THREE.Mesh(new THREE.BoxGeometry(100, 1, 100), new THREE.MeshPhongMaterial({})); - floor.position.y = -10; - const light = new THREE.PointLight(0xffffff, 250); - light.position.y = 2; - group.add(floor, light); - scene.add(group); - - const mat = new THREE.ShaderMaterial({ - uniforms: {}, - - vertexShader: [ - 'varying vec2 vUV;', - 'varying vec3 vNormal;', - - 'void main() {', - - 'vUV = uv;', - 'vNormal = vec3( normal );', - 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', - - '}', - ].join('\n'), - - fragmentShader: [ - 'varying vec2 vUV;', - 'varying vec3 vNormal;', - - 'void main() {', - - 'vec4 c = vec4( abs( vNormal ) + vec3( vUV, 0.0 ), 0.0 );', - 'gl_FragColor = c;', - - '}', - ].join('\n'), - }); - - for (let i = 0; i < 50; ++i) { - // fill scene with coloured cubes - const mesh = new THREE.Mesh(new THREE.BoxGeometry(2, 2, 2), mat); - mesh.position.set(Math.random() * 16 - 8, Math.random() * 16 - 8, Math.random() * 16 - 8); - mesh.rotation.set(Math.random() * Math.PI * 2, Math.random() * Math.PI * 2, Math.random() * Math.PI * 2); - group.add(mesh); - } - - // post-processing - - composer = new EffectComposer(renderer); - const renderPass = new RenderPass(scene, camera); - const params = { - shape: 1, - radius: 4, - rotateR: Math.PI / 12, - rotateB: (Math.PI / 12) * 2, - rotateG: (Math.PI / 12) * 3, - scatter: 0, - blending: 1, - blendingMode: 1, - greyscale: false, - disable: false, - }; - const halftonePass = new HalftonePass(window.innerWidth, window.innerHeight, params); - composer.addPass(renderPass); - composer.addPass(halftonePass); - - window.onresize = function () { - // resize composer - renderer.setSize(window.innerWidth, window.innerHeight); - composer.setSize(window.innerWidth, window.innerHeight); - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - }; - - // GUI - - const controller = { - radius: halftonePass.uniforms['radius'].value, - rotateR: halftonePass.uniforms['rotateR'].value / (Math.PI / 180), - rotateG: halftonePass.uniforms['rotateG'].value / (Math.PI / 180), - rotateB: halftonePass.uniforms['rotateB'].value / (Math.PI / 180), - scatter: halftonePass.uniforms['scatter'].value, - shape: halftonePass.uniforms['shape'].value, - greyscale: halftonePass.uniforms['greyscale'].value, - blending: halftonePass.uniforms['blending'].value, - blendingMode: halftonePass.uniforms['blendingMode'].value, - disable: halftonePass.uniforms['disable'].value, - }; - - function onGUIChange() { - // update uniforms - halftonePass.uniforms['radius'].value = controller.radius; - halftonePass.uniforms['rotateR'].value = controller.rotateR * (Math.PI / 180); - halftonePass.uniforms['rotateG'].value = controller.rotateG * (Math.PI / 180); - halftonePass.uniforms['rotateB'].value = controller.rotateB * (Math.PI / 180); - halftonePass.uniforms['scatter'].value = controller.scatter; - halftonePass.uniforms['shape'].value = controller.shape; - halftonePass.uniforms['greyscale'].value = controller.greyscale; - halftonePass.uniforms['blending'].value = controller.blending; - halftonePass.uniforms['blendingMode'].value = controller.blendingMode; - halftonePass.uniforms['disable'].value = controller.disable; - } - - const gui = new GUI(); - gui.add(controller, 'shape', { Dot: 1, Ellipse: 2, Line: 3, Square: 4 }).onChange(onGUIChange); - gui.add(controller, 'radius', 1, 25).onChange(onGUIChange); - gui.add(controller, 'rotateR', 0, 90).onChange(onGUIChange); - gui.add(controller, 'rotateG', 0, 90).onChange(onGUIChange); - gui.add(controller, 'rotateB', 0, 90).onChange(onGUIChange); - gui.add(controller, 'scatter', 0, 1, 0.01).onChange(onGUIChange); - gui.add(controller, 'greyscale').onChange(onGUIChange); - gui.add(controller, 'blending', 0, 1, 0.01).onChange(onGUIChange); - gui.add(controller, 'blendingMode', { Linear: 1, Multiply: 2, Add: 3, Lighter: 4, Darker: 5 }).onChange( - onGUIChange, - ); - gui.add(controller, 'disable').onChange(onGUIChange); -} - -function animate() { - requestAnimationFrame(animate); - - const delta = clock.getDelta(); - stats.update(); - group.rotation.y += delta * rotationSpeed; - composer.render(delta); -} diff --git a/examples-testing/examples/webgl_postprocessing_sao.ts b/examples-testing/examples/webgl_postprocessing_sao.ts deleted file mode 100644 index f8ae1e4f9..000000000 --- a/examples-testing/examples/webgl_postprocessing_sao.ts +++ /dev/null @@ -1,142 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { SAOPass } from 'three/addons/postprocessing/SAOPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; - -let container, stats; -let camera, scene, renderer; -let composer, renderPass, saoPass; -let group; - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - const width = window.innerWidth || 1; - const height = window.innerHeight || 1; - const devicePixelRatio = window.devicePixelRatio || 1; - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setClearColor(0x000000); - renderer.setPixelRatio(devicePixelRatio); - renderer.setSize(width, height); - document.body.appendChild(renderer.domElement); - - camera = new THREE.PerspectiveCamera(65, width / height, 3, 10); - camera.position.z = 7; - - scene = new THREE.Scene(); - - group = new THREE.Object3D(); - scene.add(group); - - const light = new THREE.PointLight(0xefffef, 500); - light.position.z = 10; - light.position.y = -10; - light.position.x = -10; - scene.add(light); - - const light2 = new THREE.PointLight(0xffefef, 500); - light2.position.z = 10; - light2.position.x = -10; - light2.position.y = 10; - scene.add(light2); - - const light3 = new THREE.PointLight(0xefefff, 500); - light3.position.z = 10; - light3.position.x = 10; - light3.position.y = -10; - scene.add(light3); - - const light4 = new THREE.AmbientLight(0xffffff, 0.2); - scene.add(light4); - - const geometry = new THREE.SphereGeometry(3, 48, 24); - - for (let i = 0; i < 120; i++) { - const material = new THREE.MeshStandardMaterial(); - material.roughness = 0.5 * Math.random() + 0.25; - material.metalness = 0; - material.color.setHSL(Math.random(), 1.0, 0.3); - - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = Math.random() * 4 - 2; - mesh.position.y = Math.random() * 4 - 2; - mesh.position.z = Math.random() * 4 - 2; - mesh.rotation.x = Math.random(); - mesh.rotation.y = Math.random(); - mesh.rotation.z = Math.random(); - - mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 0.2 + 0.05; - group.add(mesh); - } - - stats = new Stats(); - container.appendChild(stats.dom); - - composer = new EffectComposer(renderer); - renderPass = new RenderPass(scene, camera); - composer.addPass(renderPass); - saoPass = new SAOPass(scene, camera, false, true); - composer.addPass(saoPass); - const outputPass = new OutputPass(); - composer.addPass(outputPass); - - // Init gui - const gui = new GUI(); - gui.add(saoPass.params, 'output', { - Beauty: SAOPass.OUTPUT.Beauty, - 'Beauty+SAO': SAOPass.OUTPUT.Default, - SAO: SAOPass.OUTPUT.SAO, - Depth: SAOPass.OUTPUT.Depth, - Normal: SAOPass.OUTPUT.Normal, - }).onChange(function (value) { - saoPass.params.output = parseInt(value); - }); - gui.add(saoPass.params, 'saoBias', -1, 1); - gui.add(saoPass.params, 'saoIntensity', 0, 1); - gui.add(saoPass.params, 'saoScale', 0, 10); - gui.add(saoPass.params, 'saoKernelRadius', 1, 100); - gui.add(saoPass.params, 'saoMinResolution', 0, 1); - gui.add(saoPass.params, 'saoBlur'); - gui.add(saoPass.params, 'saoBlurRadius', 0, 200); - gui.add(saoPass.params, 'saoBlurStdDev', 0.5, 150); - gui.add(saoPass.params, 'saoBlurDepthCutoff', 0.0, 0.1); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - const width = window.innerWidth || 1; - const height = window.innerHeight || 1; - - camera.aspect = width / height; - camera.updateProjectionMatrix(); - renderer.setSize(width, height); - - composer.setSize(width, height); -} - -function animate() { - requestAnimationFrame(animate); - - stats.begin(); - render(); - stats.end(); -} - -function render() { - const timer = performance.now(); - group.rotation.x = timer * 0.0002; - group.rotation.y = timer * 0.0001; - - composer.render(); -} diff --git a/examples-testing/examples/webgl_postprocessing_smaa.ts b/examples-testing/examples/webgl_postprocessing_smaa.ts deleted file mode 100644 index 5eea466e3..000000000 --- a/examples-testing/examples/webgl_postprocessing_smaa.ts +++ /dev/null @@ -1,93 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { SMAAPass } from 'three/addons/postprocessing/SMAAPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; - -let camera, scene, renderer, composer, stats; - -init(); -animate(); - -function init() { - const container = document.getElementById('container'); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.z = 300; - - scene = new THREE.Scene(); - - const geometry = new THREE.BoxGeometry(120, 120, 120); - const material1 = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }); - - const mesh1 = new THREE.Mesh(geometry, material1); - mesh1.position.x = -100; - scene.add(mesh1); - - const texture = new THREE.TextureLoader().load('textures/brick_diffuse.jpg'); - texture.anisotropy = 4; - texture.colorSpace = THREE.SRGBColorSpace; - - const material2 = new THREE.MeshBasicMaterial({ map: texture }); - - const mesh2 = new THREE.Mesh(geometry, material2); - mesh2.position.x = 100; - scene.add(mesh2); - - // postprocessing - - composer = new EffectComposer(renderer); - composer.addPass(new RenderPass(scene, camera)); - - const pass = new SMAAPass( - window.innerWidth * renderer.getPixelRatio(), - window.innerHeight * renderer.getPixelRatio(), - ); - composer.addPass(pass); - - const outputPass = new OutputPass(); - composer.addPass(outputPass); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - const width = window.innerWidth; - const height = window.innerHeight; - - camera.aspect = width / height; - camera.updateProjectionMatrix(); - - renderer.setSize(width, height); - composer.setSize(width, height); -} - -function animate() { - requestAnimationFrame(animate); - - stats.begin(); - - for (let i = 0; i < scene.children.length; i++) { - const child = scene.children[i]; - - child.rotation.x += 0.005; - child.rotation.y += 0.01; - } - - composer.render(); - - stats.end(); -} diff --git a/examples-testing/examples/webgl_postprocessing_sobel.ts b/examples-testing/examples/webgl_postprocessing_sobel.ts deleted file mode 100644 index 32663120a..000000000 --- a/examples-testing/examples/webgl_postprocessing_sobel.ts +++ /dev/null @@ -1,113 +0,0 @@ -import * as THREE from 'three'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; - -import { LuminosityShader } from 'three/addons/shaders/LuminosityShader.js'; -import { SobelOperatorShader } from 'three/addons/shaders/SobelOperatorShader.js'; - -let camera, scene, renderer, composer; - -let effectSobel; - -const params = { - enable: true, -}; - -init(); -animate(); - -function init() { - // - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.set(0, 1, 3); - camera.lookAt(scene.position); - - // - - const geometry = new THREE.TorusKnotGeometry(1, 0.3, 256, 32); - const material = new THREE.MeshPhongMaterial({ color: 0xffff00 }); - - const mesh = new THREE.Mesh(geometry, material); - scene.add(mesh); - - // - - const ambientLight = new THREE.AmbientLight(0xe7e7e7); - scene.add(ambientLight); - - const pointLight = new THREE.PointLight(0xffffff, 20); - camera.add(pointLight); - scene.add(camera); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - // postprocessing - - composer = new EffectComposer(renderer); - const renderPass = new RenderPass(scene, camera); - composer.addPass(renderPass); - - // color to grayscale conversion - - const effectGrayScale = new ShaderPass(LuminosityShader); - composer.addPass(effectGrayScale); - - // you might want to use a gaussian blur filter before - // the next pass to improve the result of the Sobel operator - - // Sobel operator - - effectSobel = new ShaderPass(SobelOperatorShader); - effectSobel.uniforms['resolution'].value.x = window.innerWidth * window.devicePixelRatio; - effectSobel.uniforms['resolution'].value.y = window.innerHeight * window.devicePixelRatio; - composer.addPass(effectSobel); - - const controls = new OrbitControls(camera, renderer.domElement); - controls.enableZoom = false; - - // - - const gui = new GUI(); - - gui.add(params, 'enable'); - gui.open(); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - composer.setSize(window.innerWidth, window.innerHeight); - - effectSobel.uniforms['resolution'].value.x = window.innerWidth * window.devicePixelRatio; - effectSobel.uniforms['resolution'].value.y = window.innerHeight * window.devicePixelRatio; -} - -function animate() { - requestAnimationFrame(animate); - - if (params.enable === true) { - composer.render(); - } else { - renderer.render(scene, camera); - } -} diff --git a/examples-testing/examples/webgl_postprocessing_ssaa.ts b/examples-testing/examples/webgl_postprocessing_ssaa.ts deleted file mode 100644 index bca3b4632..000000000 --- a/examples-testing/examples/webgl_postprocessing_ssaa.ts +++ /dev/null @@ -1,208 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { SSAARenderPass } from 'three/addons/postprocessing/SSAARenderPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; - -let scene, renderer, composer; -let cameraP, ssaaRenderPassP; -let cameraO, ssaaRenderPassO; -let gui, stats; - -const params = { - sampleLevel: 4, - unbiased: true, - camera: 'perspective', - clearColor: 'black', - clearAlpha: 1.0, - viewOffsetX: 0, - autoRotate: true, -}; - -init(); -animate(); - -clearGui(); - -function clearGui() { - if (gui) gui.destroy(); - - gui = new GUI(); - - gui.add(params, 'unbiased'); - gui.add(params, 'sampleLevel', { - 'Level 0: 1 Sample': 0, - 'Level 1: 2 Samples': 1, - 'Level 2: 4 Samples': 2, - 'Level 3: 8 Samples': 3, - 'Level 4: 16 Samples': 4, - 'Level 5: 32 Samples': 5, - }); - gui.add(params, 'camera', ['perspective', 'orthographic']); - gui.add(params, 'clearColor', ['black', 'white', 'blue', 'green', 'red']); - gui.add(params, 'clearAlpha', 0, 1); - gui.add(params, 'viewOffsetX', -100, 100); - gui.add(params, 'autoRotate'); - - gui.open(); -} - -function init() { - const container = document.getElementById('container'); - - const width = window.innerWidth || 1; - const height = window.innerHeight || 1; - const aspect = width / height; - const devicePixelRatio = window.devicePixelRatio || 1; - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(devicePixelRatio); - renderer.setSize(width, height); - document.body.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - cameraP = new THREE.PerspectiveCamera(65, aspect, 3, 10); - cameraP.position.z = 7; - cameraP.setViewOffset(width, height, params.viewOffsetX, 0, width, height); - - cameraO = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 3, 10); - cameraO.position.z = 7; - - const fov = THREE.MathUtils.degToRad(cameraP.fov); - const hyperfocus = (cameraP.near + cameraP.far) / 2; - const _height = 2 * Math.tan(fov / 2) * hyperfocus; - cameraO.zoom = height / _height; - - scene = new THREE.Scene(); - - const group = new THREE.Group(); - scene.add(group); - - const light = new THREE.PointLight(0xefffef, 500); - light.position.z = 10; - light.position.y = -10; - light.position.x = -10; - scene.add(light); - - const light2 = new THREE.PointLight(0xffefef, 500); - light2.position.z = 10; - light2.position.x = -10; - light2.position.y = 10; - scene.add(light2); - - const light3 = new THREE.PointLight(0xefefff, 500); - light3.position.z = 10; - light3.position.x = 10; - light3.position.y = -10; - scene.add(light3); - - const light4 = new THREE.AmbientLight(0xffffff, 0.2); - scene.add(light4); - - const geometry = new THREE.SphereGeometry(3, 48, 24); - - for (let i = 0; i < 120; i++) { - const material = new THREE.MeshStandardMaterial(); - material.roughness = 0.5 * Math.random() + 0.25; - material.metalness = 0; - material.color.setHSL(Math.random(), 1.0, 0.3); - - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = Math.random() * 4 - 2; - mesh.position.y = Math.random() * 4 - 2; - mesh.position.z = Math.random() * 4 - 2; - mesh.rotation.x = Math.random(); - mesh.rotation.y = Math.random(); - mesh.rotation.z = Math.random(); - - mesh.scale.setScalar(Math.random() * 0.2 + 0.05); - group.add(mesh); - } - - // postprocessing - - composer = new EffectComposer(renderer); - composer.setPixelRatio(1); // ensure pixel ratio is always 1 for performance reasons - ssaaRenderPassP = new SSAARenderPass(scene, cameraP); - composer.addPass(ssaaRenderPassP); - ssaaRenderPassO = new SSAARenderPass(scene, cameraO); - composer.addPass(ssaaRenderPassO); - const outputPass = new OutputPass(); - composer.addPass(outputPass); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - const width = window.innerWidth; - const height = window.innerHeight; - const aspect = width / height; - - cameraP.aspect = aspect; - cameraP.setViewOffset(width, height, params.viewOffsetX, 0, width, height); - cameraO.updateProjectionMatrix(); - - cameraO.left = -height * aspect; - cameraO.right = height * aspect; - cameraO.top = height; - cameraO.bottom = -height; - cameraO.updateProjectionMatrix(); - - renderer.setSize(width, height); - composer.setSize(width, height); -} - -function animate() { - requestAnimationFrame(animate); - - stats.begin(); - - if (params.autoRotate) { - for (let i = 0; i < scene.children.length; i++) { - const child = scene.children[i]; - - child.rotation.x += 0.005; - child.rotation.y += 0.01; - } - } - - let newColor = ssaaRenderPassP.clearColor; - - switch (params.clearColor) { - case 'blue': - newColor = 0x0000ff; - break; - case 'red': - newColor = 0xff0000; - break; - case 'green': - newColor = 0x00ff00; - break; - case 'white': - newColor = 0xffffff; - break; - case 'black': - newColor = 0x000000; - break; - } - - ssaaRenderPassP.clearColor = ssaaRenderPassO.clearColor = newColor; - ssaaRenderPassP.clearAlpha = ssaaRenderPassO.clearAlpha = params.clearAlpha; - - ssaaRenderPassP.sampleLevel = ssaaRenderPassO.sampleLevel = params.sampleLevel; - ssaaRenderPassP.unbiased = ssaaRenderPassO.unbiased = params.unbiased; - - ssaaRenderPassP.enabled = params.camera === 'perspective'; - ssaaRenderPassO.enabled = params.camera === 'orthographic'; - - cameraP.view.offsetX = params.viewOffsetX; - - composer.render(); - - stats.end(); -} diff --git a/examples-testing/examples/webgl_postprocessing_ssao.ts b/examples-testing/examples/webgl_postprocessing_ssao.ts deleted file mode 100644 index 0f7f8e4ff..000000000 --- a/examples-testing/examples/webgl_postprocessing_ssao.ts +++ /dev/null @@ -1,117 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { SSAOPass } from 'three/addons/postprocessing/SSAOPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; - -let container, stats; -let camera, scene, renderer; -let composer; -let group; - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - renderer = new THREE.WebGLRenderer(); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 100, 700); - camera.position.z = 500; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xaaaaaa); - - scene.add(new THREE.DirectionalLight(0xffffff, 4)); - scene.add(new THREE.AmbientLight(0xffffff)); - - group = new THREE.Group(); - scene.add(group); - - const geometry = new THREE.BoxGeometry(10, 10, 10); - - for (let i = 0; i < 100; i++) { - const material = new THREE.MeshLambertMaterial({ - color: Math.random() * 0xffffff, - }); - - const mesh = new THREE.Mesh(geometry, material); - mesh.position.x = Math.random() * 400 - 200; - mesh.position.y = Math.random() * 400 - 200; - mesh.position.z = Math.random() * 400 - 200; - mesh.rotation.x = Math.random(); - mesh.rotation.y = Math.random(); - mesh.rotation.z = Math.random(); - - mesh.scale.setScalar(Math.random() * 10 + 2); - group.add(mesh); - } - - stats = new Stats(); - container.appendChild(stats.dom); - - const width = window.innerWidth; - const height = window.innerHeight; - - composer = new EffectComposer(renderer); - - const ssaoPass = new SSAOPass(scene, camera, width, height); - ssaoPass.kernelRadius = 16; - composer.addPass(ssaoPass); - - const outputPass = new OutputPass(); - composer.addPass(outputPass); - - // Init gui - const gui = new GUI(); - - gui.add(ssaoPass, 'output', { - Default: SSAOPass.OUTPUT.Default, - 'SSAO Only': SSAOPass.OUTPUT.SSAO, - 'SSAO Only + Blur': SSAOPass.OUTPUT.Blur, - Beauty: SSAOPass.OUTPUT.Beauty, - Depth: SSAOPass.OUTPUT.Depth, - Normal: SSAOPass.OUTPUT.Normal, - }).onChange(function (value) { - ssaoPass.output = parseInt(value); - }); - gui.add(ssaoPass, 'kernelRadius').min(0).max(32); - gui.add(ssaoPass, 'minDistance').min(0.001).max(0.02); - gui.add(ssaoPass, 'maxDistance').min(0.01).max(0.3); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - const width = window.innerWidth; - const height = window.innerHeight; - - camera.aspect = width / height; - camera.updateProjectionMatrix(); - - renderer.setSize(width, height); - composer.setSize(width, height); -} - -function animate() { - requestAnimationFrame(animate); - - stats.begin(); - render(); - stats.end(); -} - -function render() { - const timer = performance.now(); - group.rotation.x = timer * 0.0002; - group.rotation.y = timer * 0.0001; - - composer.render(); -} diff --git a/examples-testing/examples/webgl_postprocessing_ssr.ts b/examples-testing/examples/webgl_postprocessing_ssr.ts deleted file mode 100644 index 5fb1e0140..000000000 --- a/examples-testing/examples/webgl_postprocessing_ssr.ts +++ /dev/null @@ -1,263 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { SSRPass } from 'three/addons/postprocessing/SSRPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; -import { ReflectorForSSRPass } from 'three/addons/objects/ReflectorForSSRPass.js'; - -import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'; - -const params = { - enableSSR: true, - autoRotate: true, - otherMeshes: true, - groundReflector: true, -}; -let composer; -let ssrPass; -let gui; -let stats; -let controls; -let camera, scene, renderer; -const otherMeshes = []; -let groundReflector; -const selects = []; - -const container = document.querySelector('#container'); - -// Configure and create Draco decoder. -const dracoLoader = new DRACOLoader(); -dracoLoader.setDecoderPath('jsm/libs/draco/'); -dracoLoader.setDecoderConfig({ type: 'js' }); - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 15); - camera.position.set(0.13271600513224902, 0.3489546826045913, 0.43921296427927076); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x443333); - scene.fog = new THREE.Fog(0x443333, 1, 4); - - // Ground - const plane = new THREE.Mesh(new THREE.PlaneGeometry(8, 8), new THREE.MeshPhongMaterial({ color: 0xcbcbcb })); - plane.rotation.x = -Math.PI / 2; - plane.position.y = -0.0001; - // plane.receiveShadow = true; - scene.add(plane); - - // Lights - const hemiLight = new THREE.HemisphereLight(0x8d7c7c, 0x494966, 3); - scene.add(hemiLight); - - const spotLight = new THREE.SpotLight(); - spotLight.intensity = 8; - spotLight.angle = Math.PI / 16; - spotLight.penumbra = 0.5; - // spotLight.castShadow = true; - spotLight.position.set(-1, 1, 1); - scene.add(spotLight); - - dracoLoader.load('models/draco/bunny.drc', function (geometry) { - geometry.computeVertexNormals(); - - const material = new THREE.MeshStandardMaterial({ color: 0xa5a5a5 }); - const mesh = new THREE.Mesh(geometry, material); - mesh.position.y = -0.0365; - scene.add(mesh); - selects.push(mesh); - - // Release decoder resources. - dracoLoader.dispose(); - }); - - let geometry, material, mesh; - - geometry = new THREE.BoxGeometry(0.05, 0.05, 0.05); - material = new THREE.MeshStandardMaterial({ color: 'green' }); - mesh = new THREE.Mesh(geometry, material); - mesh.position.set(-0.12, 0.025, 0.015); - scene.add(mesh); - otherMeshes.push(mesh); - selects.push(mesh); - - geometry = new THREE.IcosahedronGeometry(0.025, 4); - material = new THREE.MeshStandardMaterial({ color: 'cyan' }); - mesh = new THREE.Mesh(geometry, material); - mesh.position.set(-0.05, 0.025, 0.08); - scene.add(mesh); - otherMeshes.push(mesh); - selects.push(mesh); - - geometry = new THREE.ConeGeometry(0.025, 0.05, 64); - material = new THREE.MeshStandardMaterial({ color: 'yellow' }); - mesh = new THREE.Mesh(geometry, material); - mesh.position.set(-0.05, 0.025, -0.055); - scene.add(mesh); - otherMeshes.push(mesh); - selects.push(mesh); - - geometry = new THREE.PlaneGeometry(1, 1); - groundReflector = new ReflectorForSSRPass(geometry, { - clipBias: 0.0003, - textureWidth: window.innerWidth, - textureHeight: window.innerHeight, - color: 0x888888, - useDepthTexture: true, - }); - groundReflector.material.depthWrite = false; - groundReflector.rotation.x = -Math.PI / 2; - groundReflector.visible = false; - scene.add(groundReflector); - - // renderer - renderer = new THREE.WebGLRenderer({ antialias: false }); - renderer.setSize(window.innerWidth, window.innerHeight); - container.appendChild(renderer.domElement); - - // - - controls = new OrbitControls(camera, renderer.domElement); - controls.enableDamping = true; - controls.target.set(0, 0.0635, 0); - controls.update(); - controls.enabled = !params.autoRotate; - - // STATS - - stats = new Stats(); - container.appendChild(stats.dom); - - window.addEventListener('resize', onWindowResize); - - // composer - - composer = new EffectComposer(renderer); - ssrPass = new SSRPass({ - renderer, - scene, - camera, - width: innerWidth, - height: innerHeight, - groundReflector: params.groundReflector ? groundReflector : null, - selects: params.groundReflector ? selects : null, - }); - - composer.addPass(ssrPass); - composer.addPass(new OutputPass()); - - // GUI - - gui = new GUI({ width: 260 }); - gui.add(params, 'enableSSR').name('Enable SSR'); - gui.add(params, 'groundReflector').onChange(() => { - if (params.groundReflector) { - (ssrPass.groundReflector = groundReflector), (ssrPass.selects = selects); - } else { - (ssrPass.groundReflector = null), (ssrPass.selects = null); - } - }); - ssrPass.thickness = 0.018; - gui.add(ssrPass, 'thickness').min(0).max(0.1).step(0.0001); - ssrPass.infiniteThick = false; - gui.add(ssrPass, 'infiniteThick'); - gui.add(params, 'autoRotate').onChange(() => { - controls.enabled = !params.autoRotate; - }); - - const folder = gui.addFolder('more settings'); - folder.add(ssrPass, 'fresnel').onChange(() => { - groundReflector.fresnel = ssrPass.fresnel; - }); - folder.add(ssrPass, 'distanceAttenuation').onChange(() => { - groundReflector.distanceAttenuation = ssrPass.distanceAttenuation; - }); - ssrPass.maxDistance = 0.1; - groundReflector.maxDistance = ssrPass.maxDistance; - folder - .add(ssrPass, 'maxDistance') - .min(0) - .max(0.5) - .step(0.001) - .onChange(() => { - groundReflector.maxDistance = ssrPass.maxDistance; - }); - folder.add(params, 'otherMeshes').onChange(() => { - if (params.otherMeshes) { - otherMeshes.forEach(mesh => (mesh.visible = true)); - } else { - otherMeshes.forEach(mesh => (mesh.visible = false)); - } - }); - folder.add(ssrPass, 'bouncing'); - folder - .add(ssrPass, 'output', { - Default: SSRPass.OUTPUT.Default, - 'SSR Only': SSRPass.OUTPUT.SSR, - Beauty: SSRPass.OUTPUT.Beauty, - Depth: SSRPass.OUTPUT.Depth, - Normal: SSRPass.OUTPUT.Normal, - Metalness: SSRPass.OUTPUT.Metalness, - }) - .onChange(function (value) { - ssrPass.output = parseInt(value); - }); - ssrPass.opacity = 1; - groundReflector.opacity = ssrPass.opacity; - folder - .add(ssrPass, 'opacity') - .min(0) - .max(1) - .onChange(() => { - groundReflector.opacity = ssrPass.opacity; - }); - folder.add(ssrPass, 'blur'); - // folder.open() - // gui.close() -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); - composer.setSize(window.innerWidth, window.innerHeight); - groundReflector.getRenderTarget().setSize(window.innerWidth, window.innerHeight); - groundReflector.resolution.set(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - stats.begin(); - render(); - stats.end(); -} - -function render() { - if (params.autoRotate) { - const timer = Date.now() * 0.0003; - - camera.position.x = Math.sin(timer) * 0.5; - camera.position.y = 0.2135; - camera.position.z = Math.cos(timer) * 0.5; - camera.lookAt(0, 0.0635, 0); - } else { - controls.update(); - } - - if (params.enableSSR) { - // TODO: groundReflector has full ground info, need use it to solve reflection gaps problem on objects when camera near ground. - // TODO: the normal and depth info where groundReflector reflected need to be changed. - composer.render(); - } else { - renderer.render(scene, camera); - } -} diff --git a/examples-testing/examples/webgl_postprocessing_taa.ts b/examples-testing/examples/webgl_postprocessing_taa.ts deleted file mode 100644 index b2a12b531..000000000 --- a/examples-testing/examples/webgl_postprocessing_taa.ts +++ /dev/null @@ -1,141 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { TAARenderPass } from 'three/addons/postprocessing/TAARenderPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; - -let camera, scene, renderer, composer, taaRenderPass, renderPass; -let gui, stats; -let index = 0; - -const param = { TAAEnabled: '1', TAASampleLevel: 0 }; - -init(); -animate(); - -clearGui(); - -function clearGui() { - if (gui) gui.destroy(); - - gui = new GUI(); - - gui.add(param, 'TAAEnabled', { - Disabled: '0', - Enabled: '1', - }).onFinishChange(function () { - if (taaRenderPass) { - taaRenderPass.enabled = param.TAAEnabled === '1'; - renderPass.enabled = param.TAAEnabled !== '1'; - } - }); - - gui.add(param, 'TAASampleLevel', { - 'Level 0: 1 Sample': 0, - 'Level 1: 2 Samples': 1, - 'Level 2: 4 Samples': 2, - 'Level 3: 8 Samples': 3, - 'Level 4: 16 Samples': 4, - 'Level 5: 32 Samples': 5, - }).onFinishChange(function () { - if (taaRenderPass) { - taaRenderPass.sampleLevel = param.TAASampleLevel; - } - }); - - gui.open(); -} - -function init() { - const container = document.getElementById('container'); - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.z = 300; - - scene = new THREE.Scene(); - - const geometry = new THREE.BoxGeometry(120, 120, 120); - const material1 = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true }); - - const mesh1 = new THREE.Mesh(geometry, material1); - mesh1.position.x = -100; - scene.add(mesh1); - - const texture = new THREE.TextureLoader().load('textures/brick_diffuse.jpg'); - texture.minFilter = THREE.NearestFilter; - texture.magFilter = THREE.NearestFilter; - texture.anisotropy = 1; - texture.generateMipmaps = false; - texture.colorSpace = THREE.SRGBColorSpace; - - const material2 = new THREE.MeshBasicMaterial({ map: texture }); - - const mesh2 = new THREE.Mesh(geometry, material2); - mesh2.position.x = 100; - scene.add(mesh2); - - // postprocessing - - composer = new EffectComposer(renderer); - - taaRenderPass = new TAARenderPass(scene, camera); - taaRenderPass.unbiased = false; - composer.addPass(taaRenderPass); - - renderPass = new RenderPass(scene, camera); - renderPass.enabled = false; - composer.addPass(renderPass); - - const outputPass = new OutputPass(); - composer.addPass(outputPass); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - const width = window.innerWidth; - const height = window.innerHeight; - - camera.aspect = width / height; - camera.updateProjectionMatrix(); - - renderer.setSize(width, height); - composer.setSize(width, height); -} - -function animate() { - requestAnimationFrame(animate); - - index++; - - if (Math.round(index / 200) % 2 === 0) { - for (let i = 0; i < scene.children.length; i++) { - const child = scene.children[i]; - - child.rotation.x += 0.005; - child.rotation.y += 0.01; - } - - if (taaRenderPass) taaRenderPass.accumulate = false; - } else { - if (taaRenderPass) taaRenderPass.accumulate = true; - } - - composer.render(); - - stats.update(); -} diff --git a/examples-testing/examples/webgl_postprocessing_unreal_bloom.ts b/examples-testing/examples/webgl_postprocessing_unreal_bloom.ts deleted file mode 100644 index 886f77fdd..000000000 --- a/examples-testing/examples/webgl_postprocessing_unreal_bloom.ts +++ /dev/null @@ -1,129 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; - -let camera, stats; -let composer, renderer, mixer, clock; - -const params = { - threshold: 0, - strength: 1, - radius: 0, - exposure: 1, -}; - -init(); - -function init() { - const container = document.getElementById('container'); - - stats = new Stats(); - container.appendChild(stats.dom); - - clock = new THREE.Clock(); - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.toneMapping = THREE.ReinhardToneMapping; - container.appendChild(renderer.domElement); - - const scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 100); - camera.position.set(-5, 2.5, -3.5); - scene.add(camera); - - const controls = new OrbitControls(camera, renderer.domElement); - controls.maxPolarAngle = Math.PI * 0.5; - controls.minDistance = 3; - controls.maxDistance = 8; - - scene.add(new THREE.AmbientLight(0xcccccc)); - - const pointLight = new THREE.PointLight(0xffffff, 100); - camera.add(pointLight); - - const renderScene = new RenderPass(scene, camera); - - const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85); - bloomPass.threshold = params.threshold; - bloomPass.strength = params.strength; - bloomPass.radius = params.radius; - - const outputPass = new OutputPass(); - - composer = new EffectComposer(renderer); - composer.addPass(renderScene); - composer.addPass(bloomPass); - composer.addPass(outputPass); - - new GLTFLoader().load('models/gltf/PrimaryIonDrive.glb', function (gltf) { - const model = gltf.scene; - - scene.add(model); - - mixer = new THREE.AnimationMixer(model); - const clip = gltf.animations[0]; - mixer.clipAction(clip.optimize()).play(); - - animate(); - }); - - const gui = new GUI(); - - const bloomFolder = gui.addFolder('bloom'); - - bloomFolder.add(params, 'threshold', 0.0, 1.0).onChange(function (value) { - bloomPass.threshold = Number(value); - }); - - bloomFolder.add(params, 'strength', 0.0, 3.0).onChange(function (value) { - bloomPass.strength = Number(value); - }); - - gui.add(params, 'radius', 0.0, 1.0) - .step(0.01) - .onChange(function (value) { - bloomPass.radius = Number(value); - }); - - const toneMappingFolder = gui.addFolder('tone mapping'); - - toneMappingFolder.add(params, 'exposure', 0.1, 2).onChange(function (value) { - renderer.toneMappingExposure = Math.pow(value, 4.0); - }); - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - const width = window.innerWidth; - const height = window.innerHeight; - - camera.aspect = width / height; - camera.updateProjectionMatrix(); - - renderer.setSize(width, height); - composer.setSize(width, height); -} - -function animate() { - requestAnimationFrame(animate); - - const delta = clock.getDelta(); - - mixer.update(delta); - - stats.update(); - - composer.render(); -} diff --git a/examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts b/examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts deleted file mode 100644 index d633806ee..000000000 --- a/examples-testing/examples/webgl_postprocessing_unreal_bloom_selective.ts +++ /dev/null @@ -1,195 +0,0 @@ -import * as THREE from 'three'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; -import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; -import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; -import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js'; -import { OutputPass } from 'three/addons/postprocessing/OutputPass.js'; - -const BLOOM_SCENE = 1; - -const bloomLayer = new THREE.Layers(); -bloomLayer.set(BLOOM_SCENE); - -const params = { - threshold: 0, - strength: 1, - radius: 0.5, - exposure: 1, -}; - -const darkMaterial = new THREE.MeshBasicMaterial({ color: 'black' }); -const materials = {}; - -const renderer = new THREE.WebGLRenderer({ antialias: true }); -renderer.setPixelRatio(window.devicePixelRatio); -renderer.setSize(window.innerWidth, window.innerHeight); -renderer.toneMapping = THREE.ReinhardToneMapping; -document.body.appendChild(renderer.domElement); - -const scene = new THREE.Scene(); - -const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 200); -camera.position.set(0, 0, 20); -camera.lookAt(0, 0, 0); - -const controls = new OrbitControls(camera, renderer.domElement); -controls.maxPolarAngle = Math.PI * 0.5; -controls.minDistance = 1; -controls.maxDistance = 100; -controls.addEventListener('change', render); - -const renderScene = new RenderPass(scene, camera); - -const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85); -bloomPass.threshold = params.threshold; -bloomPass.strength = params.strength; -bloomPass.radius = params.radius; - -const bloomComposer = new EffectComposer(renderer); -bloomComposer.renderToScreen = false; -bloomComposer.addPass(renderScene); -bloomComposer.addPass(bloomPass); - -const mixPass = new ShaderPass( - new THREE.ShaderMaterial({ - uniforms: { - baseTexture: { value: null }, - bloomTexture: { value: bloomComposer.renderTarget2.texture }, - }, - vertexShader: document.getElementById('vertexshader').textContent, - fragmentShader: document.getElementById('fragmentshader').textContent, - defines: {}, - }), - 'baseTexture', -); -mixPass.needsSwap = true; - -const outputPass = new OutputPass(); - -const finalComposer = new EffectComposer(renderer); -finalComposer.addPass(renderScene); -finalComposer.addPass(mixPass); -finalComposer.addPass(outputPass); - -const raycaster = new THREE.Raycaster(); - -const mouse = new THREE.Vector2(); - -window.addEventListener('pointerdown', onPointerDown); - -const gui = new GUI(); - -const bloomFolder = gui.addFolder('bloom'); - -bloomFolder.add(params, 'threshold', 0.0, 1.0).onChange(function (value) { - bloomPass.threshold = Number(value); - render(); -}); - -bloomFolder.add(params, 'strength', 0.0, 3).onChange(function (value) { - bloomPass.strength = Number(value); - render(); -}); - -bloomFolder - .add(params, 'radius', 0.0, 1.0) - .step(0.01) - .onChange(function (value) { - bloomPass.radius = Number(value); - render(); - }); - -const toneMappingFolder = gui.addFolder('tone mapping'); - -toneMappingFolder.add(params, 'exposure', 0.1, 2).onChange(function (value) { - renderer.toneMappingExposure = Math.pow(value, 4.0); - render(); -}); - -setupScene(); - -function onPointerDown(event) { - mouse.x = (event.clientX / window.innerWidth) * 2 - 1; - mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; - - raycaster.setFromCamera(mouse, camera); - const intersects = raycaster.intersectObjects(scene.children, false); - if (intersects.length > 0) { - const object = intersects[0].object; - object.layers.toggle(BLOOM_SCENE); - render(); - } -} - -window.onresize = function () { - const width = window.innerWidth; - const height = window.innerHeight; - - camera.aspect = width / height; - camera.updateProjectionMatrix(); - - renderer.setSize(width, height); - - bloomComposer.setSize(width, height); - finalComposer.setSize(width, height); - - render(); -}; - -function setupScene() { - scene.traverse(disposeMaterial); - scene.children.length = 0; - - const geometry = new THREE.IcosahedronGeometry(1, 15); - - for (let i = 0; i < 50; i++) { - const color = new THREE.Color(); - color.setHSL(Math.random(), 0.7, Math.random() * 0.2 + 0.05); - - const material = new THREE.MeshBasicMaterial({ color: color }); - const sphere = new THREE.Mesh(geometry, material); - sphere.position.x = Math.random() * 10 - 5; - sphere.position.y = Math.random() * 10 - 5; - sphere.position.z = Math.random() * 10 - 5; - sphere.position.normalize().multiplyScalar(Math.random() * 4.0 + 2.0); - sphere.scale.setScalar(Math.random() * Math.random() + 0.5); - scene.add(sphere); - - if (Math.random() < 0.25) sphere.layers.enable(BLOOM_SCENE); - } - - render(); -} - -function disposeMaterial(obj) { - if (obj.material) { - obj.material.dispose(); - } -} - -function render() { - scene.traverse(darkenNonBloomed); - bloomComposer.render(); - scene.traverse(restoreMaterial); - - // render the entire scene, then render bloom scene on top - finalComposer.render(); -} - -function darkenNonBloomed(obj) { - if (obj.isMesh && bloomLayer.test(obj.layers) === false) { - materials[obj.uuid] = obj.material; - obj.material = darkMaterial; - } -} - -function restoreMaterial(obj) { - if (materials[obj.uuid]) { - obj.material = materials[obj.uuid]; - delete materials[obj.uuid]; - } -} diff --git a/examples-testing/examples/webgl_raymarching_reflect.ts b/examples-testing/examples/webgl_raymarching_reflect.ts deleted file mode 100644 index 96f9a81d0..000000000 --- a/examples-testing/examples/webgl_raymarching_reflect.ts +++ /dev/null @@ -1,96 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -let dolly, camera, scene, renderer; -let geometry, material, mesh; -let stats, clock; - -const canvas = document.querySelector('#canvas'); - -const config = { - saveImage: function () { - renderer.render(scene, camera); - window.open(canvas.toDataURL()); - }, - resolution: '512', -}; - -init(); -render(); - -function init() { - renderer = new THREE.WebGLRenderer({ canvas: canvas }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(parseInt(config.resolution), parseInt(config.resolution)); - - window.addEventListener('resize', onWindowResize); - - // THREE.Scene - scene = new THREE.Scene(); - - dolly = new THREE.Group(); - scene.add(dolly); - - clock = new THREE.Clock(); - - camera = new THREE.PerspectiveCamera(60, canvas.width / canvas.height, 1, 2000); - camera.position.z = 4; - dolly.add(camera); - - geometry = new THREE.PlaneGeometry(2.0, 2.0); - material = new THREE.RawShaderMaterial({ - uniforms: { - resolution: { value: new THREE.Vector2(canvas.width, canvas.height) }, - cameraWorldMatrix: { value: camera.matrixWorld }, - cameraProjectionMatrixInverse: { value: camera.projectionMatrixInverse.clone() }, - }, - vertexShader: document.getElementById('vertex_shader').textContent, - fragmentShader: document.getElementById('fragment_shader').textContent, - }); - mesh = new THREE.Mesh(geometry, material); - mesh.frustumCulled = false; - scene.add(mesh); - - // Controls - const controls = new OrbitControls(camera, canvas); - controls.enableZoom = false; - - // GUI - const gui = new GUI(); - gui.add(config, 'saveImage').name('Save Image'); - gui.add(config, 'resolution', ['256', '512', '800', 'full']).name('Resolution').onChange(onWindowResize); - - stats = new Stats(); - document.body.appendChild(stats.dom); -} - -function onWindowResize() { - if (config.resolution === 'full') { - renderer.setSize(window.innerWidth, window.innerHeight); - } else { - renderer.setSize(parseInt(config.resolution), parseInt(config.resolution)); - } - - camera.aspect = canvas.width / canvas.height; - camera.updateProjectionMatrix(); - - material.uniforms.resolution.value.set(canvas.width, canvas.height); - material.uniforms.cameraProjectionMatrixInverse.value.copy(camera.projectionMatrixInverse); -} - -function render() { - stats.begin(); - - const elapsedTime = clock.getElapsedTime(); - - dolly.position.z = -elapsedTime; - - renderer.render(scene, camera); - - stats.end(); - requestAnimationFrame(render); -} diff --git a/examples-testing/examples/webgl_shadowmap_csm.ts b/examples-testing/examples/webgl_shadowmap_csm.ts deleted file mode 100644 index f9df4abf5..000000000 --- a/examples-testing/examples/webgl_shadowmap_csm.ts +++ /dev/null @@ -1,244 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import { CSM } from 'three/addons/csm/CSM.js'; -import { CSMHelper } from 'three/addons/csm/CSMHelper.js'; - -let renderer, scene, camera, orthoCamera, controls, csm, csmHelper; - -const params = { - orthographic: false, - fade: false, - far: 1000, - mode: 'practical', - lightX: -1, - lightY: -1, - lightZ: -1, - margin: 100, - lightFar: 5000, - lightNear: 1, - autoUpdateHelper: true, - updateHelper: function () { - csmHelper.update(); - }, -}; - -init(); -animate(); - -function updateOrthoCamera() { - const size = controls.target.distanceTo(camera.position); - const aspect = camera.aspect; - - orthoCamera.left = (size * aspect) / -2; - orthoCamera.right = (size * aspect) / 2; - - orthoCamera.top = size / 2; - orthoCamera.bottom = size / -2; - orthoCamera.position.copy(camera.position); - orthoCamera.rotation.copy(camera.rotation); - orthoCamera.updateProjectionMatrix(); -} - -function init() { - scene = new THREE.Scene(); - scene.background = new THREE.Color('#454e61'); - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 5000); - orthoCamera = new THREE.OrthographicCamera(); - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - renderer.shadowMap.enabled = true; - renderer.shadowMap.type = THREE.PCFSoftShadowMap; - - controls = new OrbitControls(camera, renderer.domElement); - controls.maxPolarAngle = Math.PI / 2; - camera.position.set(60, 60, 0); - controls.target = new THREE.Vector3(-100, 10, 0); - controls.update(); - - const ambientLight = new THREE.AmbientLight(0xffffff, 1.5); - scene.add(ambientLight); - - const additionalDirectionalLight = new THREE.DirectionalLight(0x000020, 1.5); - additionalDirectionalLight.position - .set(params.lightX, params.lightY, params.lightZ) - .normalize() - .multiplyScalar(-200); - scene.add(additionalDirectionalLight); - - csm = new CSM({ - maxFar: params.far, - cascades: 4, - mode: params.mode, - parent: scene, - shadowMapSize: 1024, - lightDirection: new THREE.Vector3(params.lightX, params.lightY, params.lightZ).normalize(), - camera: camera, - }); - - csmHelper = new CSMHelper(csm); - csmHelper.visible = false; - scene.add(csmHelper); - - const floorMaterial = new THREE.MeshPhongMaterial({ color: '#252a34' }); - csm.setupMaterial(floorMaterial); - - const floor = new THREE.Mesh(new THREE.PlaneGeometry(10000, 10000, 8, 8), floorMaterial); - floor.rotation.x = -Math.PI / 2; - floor.castShadow = true; - floor.receiveShadow = true; - scene.add(floor); - - const material1 = new THREE.MeshPhongMaterial({ color: '#08d9d6' }); - csm.setupMaterial(material1); - - const material2 = new THREE.MeshPhongMaterial({ color: '#ff2e63' }); - csm.setupMaterial(material2); - - const geometry = new THREE.BoxGeometry(10, 10, 10); - - for (let i = 0; i < 40; i++) { - const cube1 = new THREE.Mesh(geometry, i % 2 === 0 ? material1 : material2); - cube1.castShadow = true; - cube1.receiveShadow = true; - scene.add(cube1); - cube1.position.set(-i * 25, 20, 30); - cube1.scale.y = Math.random() * 2 + 6; - - const cube2 = new THREE.Mesh(geometry, i % 2 === 0 ? material2 : material1); - cube2.castShadow = true; - cube2.receiveShadow = true; - scene.add(cube2); - cube2.position.set(-i * 25, 20, -30); - cube2.scale.y = Math.random() * 2 + 6; - } - - const gui = new GUI(); - - gui.add(params, 'orthographic').onChange(function (value) { - csm.camera = value ? orthoCamera : camera; - csm.updateFrustums(); - }); - - gui.add(params, 'fade').onChange(function (value) { - csm.fade = value; - csm.updateFrustums(); - }); - - gui.add(params, 'far', 1, 5000) - .step(1) - .name('shadow far') - .onChange(function (value) { - csm.maxFar = value; - csm.updateFrustums(); - }); - - gui.add(params, 'mode', ['uniform', 'logarithmic', 'practical']) - .name('frustum split mode') - .onChange(function (value) { - csm.mode = value; - csm.updateFrustums(); - }); - - gui.add(params, 'lightX', -1, 1) - .name('light direction x') - .onChange(function (value) { - csm.lightDirection.x = value; - }); - - gui.add(params, 'lightY', -1, 1) - .name('light direction y') - .onChange(function (value) { - csm.lightDirection.y = value; - }); - - gui.add(params, 'lightZ', -1, 1) - .name('light direction z') - .onChange(function (value) { - csm.lightDirection.z = value; - }); - - gui.add(params, 'margin', 0, 200) - .name('light margin') - .onChange(function (value) { - csm.lightMargin = value; - }); - - gui.add(params, 'lightNear', 1, 10000) - .name('light near') - .onChange(function (value) { - for (let i = 0; i < csm.lights.length; i++) { - csm.lights[i].shadow.camera.near = value; - csm.lights[i].shadow.camera.updateProjectionMatrix(); - } - }); - - gui.add(params, 'lightFar', 1, 10000) - .name('light far') - .onChange(function (value) { - for (let i = 0; i < csm.lights.length; i++) { - csm.lights[i].shadow.camera.far = value; - csm.lights[i].shadow.camera.updateProjectionMatrix(); - } - }); - - const helperFolder = gui.addFolder('helper'); - - helperFolder.add(csmHelper, 'visible'); - - helperFolder.add(csmHelper, 'displayFrustum').onChange(function () { - csmHelper.updateVisibility(); - }); - - helperFolder.add(csmHelper, 'displayPlanes').onChange(function () { - csmHelper.updateVisibility(); - }); - - helperFolder.add(csmHelper, 'displayShadowBounds').onChange(function () { - csmHelper.updateVisibility(); - }); - - helperFolder.add(params, 'autoUpdateHelper').name('auto update'); - - helperFolder.add(params, 'updateHelper').name('update'); - - helperFolder.open(); - - window.addEventListener('resize', function () { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - updateOrthoCamera(); - csm.updateFrustums(); - - renderer.setSize(window.innerWidth, window.innerHeight); - }); -} - -function animate() { - requestAnimationFrame(animate); - - camera.updateMatrixWorld(); - csm.update(); - controls.update(); - - if (params.orthographic) { - updateOrthoCamera(); - csm.updateFrustums(); - - if (params.autoUpdateHelper) { - csmHelper.update(); - } - - renderer.render(scene, orthoCamera); - } else { - if (params.autoUpdateHelper) { - csmHelper.update(); - } - - renderer.render(scene, camera); - } -} diff --git a/examples-testing/examples/webgl_shadowmap_pcss.ts b/examples-testing/examples/webgl_shadowmap_pcss.ts deleted file mode 100644 index 91ba36072..000000000 --- a/examples-testing/examples/webgl_shadowmap_pcss.ts +++ /dev/null @@ -1,163 +0,0 @@ -import * as THREE from 'three'; - -import Stats from 'three/addons/libs/stats.module.js'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -let stats; -let camera, scene, renderer; - -let group; - -init(); -animate(); - -function init() { - const container = document.createElement('div'); - document.body.appendChild(container); - - // scene - - scene = new THREE.Scene(); - scene.fog = new THREE.Fog(0xcce0ff, 5, 100); - - // camera - - camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 10000); - - // We use this particular camera position in order to expose a bug that can sometimes happen presumably - // due to lack of precision when interpolating values over really large triangles. - // It reproduced on at least NVIDIA GTX 1080 and GTX 1050 Ti GPUs when the ground plane was not - // subdivided into segments. - camera.position.x = 7; - camera.position.y = 13; - camera.position.z = 7; - - scene.add(camera); - - // lights - - scene.add(new THREE.AmbientLight(0xaaaaaa, 3)); - - const light = new THREE.DirectionalLight(0xf0f6ff, 4.5); - light.position.set(2, 8, 4); - - light.castShadow = true; - light.shadow.mapSize.width = 1024; - light.shadow.mapSize.height = 1024; - light.shadow.camera.far = 20; - - scene.add(light); - - // scene.add( new DirectionalLightHelper( light ) ); - scene.add(new THREE.CameraHelper(light.shadow.camera)); - - // group - - group = new THREE.Group(); - scene.add(group); - - const geometry = new THREE.SphereGeometry(0.3, 20, 20); - - for (let i = 0; i < 20; i++) { - const material = new THREE.MeshPhongMaterial({ color: Math.random() * 0xffffff }); - - const sphere = new THREE.Mesh(geometry, material); - sphere.position.x = Math.random() - 0.5; - sphere.position.z = Math.random() - 0.5; - sphere.position.normalize(); - sphere.position.multiplyScalar(Math.random() * 2 + 1); - sphere.castShadow = true; - sphere.receiveShadow = true; - sphere.userData.phase = Math.random() * Math.PI; - group.add(sphere); - } - - // ground - - const groundMaterial = new THREE.MeshPhongMaterial({ color: 0x898989 }); - - const ground = new THREE.Mesh(new THREE.PlaneGeometry(20000, 20000, 8, 8), groundMaterial); - ground.rotation.x = -Math.PI / 2; - ground.receiveShadow = true; - scene.add(ground); - - // column - - const column = new THREE.Mesh(new THREE.BoxGeometry(1, 4, 1), groundMaterial); - column.position.y = 2; - column.castShadow = true; - column.receiveShadow = true; - scene.add(column); - - // overwrite shadowmap code - - let shader = THREE.ShaderChunk.shadowmap_pars_fragment; - - shader = shader.replace( - '#ifdef USE_SHADOWMAP', - '#ifdef USE_SHADOWMAP' + document.getElementById('PCSS').textContent, - ); - - shader = shader.replace( - '#if defined( SHADOWMAP_TYPE_PCF )', - document.getElementById('PCSSGetShadow').textContent + '#if defined( SHADOWMAP_TYPE_PCF )', - ); - - THREE.ShaderChunk.shadowmap_pars_fragment = shader; - - // renderer - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.setClearColor(scene.fog.color); - - container.appendChild(renderer.domElement); - - renderer.shadowMap.enabled = true; - - // controls - const controls = new OrbitControls(camera, renderer.domElement); - controls.maxPolarAngle = Math.PI * 0.5; - controls.minDistance = 10; - controls.maxDistance = 75; - controls.target.set(0, 2.5, 0); - controls.update(); - - // performance monitor - - stats = new Stats(); - container.appendChild(stats.dom); - - // - - window.addEventListener('resize', onWindowResize); -} - -// - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - const time = performance.now() / 1000; - - group.traverse(function (child) { - if ('phase' in child.userData) { - child.position.y = Math.abs(Math.sin(time + child.userData.phase)) * 4 + 0.3; - } - }); - - renderer.render(scene, camera); - - stats.update(); - - requestAnimationFrame(animate); -} diff --git a/examples-testing/examples/webgl_shadowmap_progressive.ts b/examples-testing/examples/webgl_shadowmap_progressive.ts deleted file mode 100644 index eaf6e325c..000000000 --- a/examples-testing/examples/webgl_shadowmap_progressive.ts +++ /dev/null @@ -1,214 +0,0 @@ -import * as THREE from 'three'; -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { TransformControls } from 'three/addons/controls/TransformControls.js'; -import { ProgressiveLightMap } from 'three/addons/misc/ProgressiveLightMap.js'; - -// ShadowMap + LightMap Res and Number of Directional Lights -const shadowMapRes = 512, - lightMapRes = 1024, - lightCount = 8; -let camera, - scene, - renderer, - controls, - control, - control2, - object = new THREE.Mesh(), - lightOrigin = null, - progressiveSurfacemap; -const dirLights = [], - lightmapObjects = []; -const params = { - Enable: true, - 'Blur Edges': true, - 'Blend Window': 200, - 'Light Radius': 50, - 'Ambient Weight': 0.5, - 'Debug Lightmap': false, -}; -init(); -createGUI(); -animate(); - -function init() { - // renderer - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - document.body.appendChild(renderer.domElement); - - // camera - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); - camera.position.set(0, 100, 200); - camera.name = 'Camera'; - - // scene - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x949494); - scene.fog = new THREE.Fog(0x949494, 1000, 3000); - - // progressive lightmap - progressiveSurfacemap = new ProgressiveLightMap(renderer, lightMapRes); - - // directional lighting "origin" - lightOrigin = new THREE.Group(); - lightOrigin.position.set(60, 150, 100); - scene.add(lightOrigin); - - // transform gizmo - control = new TransformControls(camera, renderer.domElement); - control.addEventListener('dragging-changed', event => { - controls.enabled = !event.value; - }); - control.attach(lightOrigin); - scene.add(control); - - // create 8 directional lights to speed up the convergence - for (let l = 0; l < lightCount; l++) { - const dirLight = new THREE.DirectionalLight(0xffffff, 1.0 / lightCount); - dirLight.name = 'Dir. Light ' + l; - dirLight.position.set(200, 200, 200); - dirLight.castShadow = true; - dirLight.shadow.camera.near = 100; - dirLight.shadow.camera.far = 5000; - dirLight.shadow.camera.right = 150; - dirLight.shadow.camera.left = -150; - dirLight.shadow.camera.top = 150; - dirLight.shadow.camera.bottom = -150; - dirLight.shadow.mapSize.width = shadowMapRes; - dirLight.shadow.mapSize.height = shadowMapRes; - lightmapObjects.push(dirLight); - dirLights.push(dirLight); - } - - // ground - const groundMesh = new THREE.Mesh( - new THREE.PlaneGeometry(600, 600), - new THREE.MeshPhongMaterial({ color: 0xffffff, depthWrite: true }), - ); - groundMesh.position.y = -0.1; - groundMesh.rotation.x = -Math.PI / 2; - groundMesh.name = 'Ground Mesh'; - lightmapObjects.push(groundMesh); - scene.add(groundMesh); - - // model - function loadModel() { - object.traverse(function (child) { - if (child.isMesh) { - child.name = 'Loaded Mesh'; - child.castShadow = true; - child.receiveShadow = true; - child.material = new THREE.MeshPhongMaterial(); - - // This adds the model to the lightmap - lightmapObjects.push(child); - progressiveSurfacemap.addObjectsToLightMap(lightmapObjects); - } else { - child.layers.disableAll(); // Disable Rendering for this - } - }); - scene.add(object); - object.scale.set(2, 2, 2); - object.position.set(0, -16, 0); - control2 = new TransformControls(camera, renderer.domElement); - control2.addEventListener('dragging-changed', event => { - controls.enabled = !event.value; - }); - control2.attach(object); - scene.add(control2); - const lightTarget = new THREE.Group(); - lightTarget.position.set(0, 20, 0); - for (let l = 0; l < dirLights.length; l++) { - dirLights[l].target = lightTarget; - } - - object.add(lightTarget); - - if (typeof TESTING !== 'undefined') { - for (let i = 0; i < 300; i++) { - render(); - } - } - } - - const manager = new THREE.LoadingManager(loadModel); - const loader = new GLTFLoader(manager); - loader.load('models/gltf/ShadowmappableMesh.glb', function (obj) { - object = obj.scene.children[0]; - }); - - // controls - controls = new OrbitControls(camera, renderer.domElement); - controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled - controls.dampingFactor = 0.05; - controls.screenSpacePanning = true; - controls.minDistance = 100; - controls.maxDistance = 500; - controls.maxPolarAngle = Math.PI / 1.5; - controls.target.set(0, 100, 0); - window.addEventListener('resize', onWindowResize); -} - -function createGUI() { - const gui = new GUI({ title: 'Accumulation Settings' }); - gui.add(params, 'Enable'); - gui.add(params, 'Blur Edges'); - gui.add(params, 'Blend Window', 1, 500).step(1); - gui.add(params, 'Light Radius', 0, 200).step(10); - gui.add(params, 'Ambient Weight', 0, 1).step(0.1); - gui.add(params, 'Debug Lightmap'); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function render() { - // Update the inertia on the orbit controls - controls.update(); - - // Accumulate Surface Maps - if (params['Enable']) { - progressiveSurfacemap.update(camera, params['Blend Window'], params['Blur Edges']); - - if (!progressiveSurfacemap.firstUpdate) { - progressiveSurfacemap.showDebugLightmap(params['Debug Lightmap']); - } - } - - // Manually Update the Directional Lights - for (let l = 0; l < dirLights.length; l++) { - // Sometimes they will be sampled from the target direction - // Sometimes they will be uniformly sampled from the upper hemisphere - if (Math.random() > params['Ambient Weight']) { - dirLights[l].position.set( - lightOrigin.position.x + Math.random() * params['Light Radius'], - lightOrigin.position.y + Math.random() * params['Light Radius'], - lightOrigin.position.z + Math.random() * params['Light Radius'], - ); - } else { - // Uniform Hemispherical Surface Distribution for Ambient Occlusion - const lambda = Math.acos(2 * Math.random() - 1) - 3.14159 / 2.0; - const phi = 2 * 3.14159 * Math.random(); - dirLights[l].position.set( - Math.cos(lambda) * Math.cos(phi) * 300 + object.position.x, - Math.abs(Math.cos(lambda) * Math.sin(phi) * 300) + object.position.y + 20, - Math.sin(lambda) * 300 + object.position.z, - ); - } - } - - // Render Scene - renderer.render(scene, camera); -} - -function animate() { - requestAnimationFrame(animate); - render(); -} diff --git a/examples-testing/examples/webgl_simple_gi.ts b/examples-testing/examples/webgl_simple_gi.ts deleted file mode 100644 index cd5d567d9..000000000 --- a/examples-testing/examples/webgl_simple_gi.ts +++ /dev/null @@ -1,175 +0,0 @@ -import * as THREE from 'three'; - -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - -class GIMesh extends THREE.Mesh { - copy(source) { - super.copy(source); - - this.geometry = source.geometry.clone(); - - return this; - } -} - -// - -const SimpleGI = function (renderer, scene) { - const SIZE = 32, - SIZE2 = SIZE * SIZE; - - const camera = new THREE.PerspectiveCamera(90, 1, 0.01, 100); - - scene.updateMatrixWorld(true); - - let clone = scene.clone(); - clone.matrixWorldAutoUpdate = false; - - const rt = new THREE.WebGLRenderTarget(SIZE, SIZE); - - const normalMatrix = new THREE.Matrix3(); - - const position = new THREE.Vector3(); - const normal = new THREE.Vector3(); - - let bounces = 0; - let currentVertex = 0; - - const color = new Float32Array(3); - const buffer = new Uint8Array(SIZE2 * 4); - - function compute() { - if (bounces === 3) return; - - const object = scene.children[0]; // torusKnot - const geometry = object.geometry; - - const attributes = geometry.attributes; - const positions = attributes.position.array; - const normals = attributes.normal.array; - - if (attributes.color === undefined) { - const colors = new Float32Array(positions.length); - geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3).setUsage(THREE.DynamicDrawUsage)); - } - - const colors = attributes.color.array; - - const startVertex = currentVertex; - const totalVertex = positions.length / 3; - - for (let i = 0; i < 32; i++) { - if (currentVertex >= totalVertex) break; - - position.fromArray(positions, currentVertex * 3); - position.applyMatrix4(object.matrixWorld); - - normal.fromArray(normals, currentVertex * 3); - normal.applyMatrix3(normalMatrix.getNormalMatrix(object.matrixWorld)).normalize(); - - camera.position.copy(position); - camera.lookAt(position.add(normal)); - - renderer.setRenderTarget(rt); - renderer.render(clone, camera); - - renderer.readRenderTargetPixels(rt, 0, 0, SIZE, SIZE, buffer); - - color[0] = 0; - color[1] = 0; - color[2] = 0; - - for (let k = 0, kl = buffer.length; k < kl; k += 4) { - color[0] += buffer[k + 0]; - color[1] += buffer[k + 1]; - color[2] += buffer[k + 2]; - } - - colors[currentVertex * 3 + 0] = color[0] / (SIZE2 * 255); - colors[currentVertex * 3 + 1] = color[1] / (SIZE2 * 255); - colors[currentVertex * 3 + 2] = color[2] / (SIZE2 * 255); - - currentVertex++; - } - - attributes.color.updateRange.offset = startVertex * 3; - attributes.color.updateRange.count = (currentVertex - startVertex) * 3; - attributes.color.needsUpdate = true; - - if (currentVertex >= totalVertex) { - clone = scene.clone(); - clone.matrixWorldAutoUpdate = false; - - bounces++; - currentVertex = 0; - } - - requestAnimationFrame(compute); - } - - requestAnimationFrame(compute); -}; - -// - -let camera, scene, renderer; - -init(); -animate(); - -function init() { - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 100); - camera.position.z = 4; - - scene = new THREE.Scene(); - - // torus knot - - const torusGeometry = new THREE.TorusKnotGeometry(0.75, 0.3, 128, 32, 1); - const material = new THREE.MeshBasicMaterial({ vertexColors: true }); - - const torusKnot = new GIMesh(torusGeometry, material); - scene.add(torusKnot); - - // room - - const materials = []; - - for (let i = 0; i < 8; i++) { - materials.push(new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff, side: THREE.BackSide })); - } - - const boxGeometry = new THREE.BoxGeometry(3, 3, 3); - - const box = new THREE.Mesh(boxGeometry, materials); - scene.add(box); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - new SimpleGI(renderer, scene); - - const controls = new OrbitControls(camera, renderer.domElement); - controls.minDistance = 1; - controls.maxDistance = 10; - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - requestAnimationFrame(animate); - - renderer.setRenderTarget(null); - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webxr_ar_cones.ts b/examples-testing/examples/webxr_ar_cones.ts deleted file mode 100644 index 996e41f27..000000000 --- a/examples-testing/examples/webxr_ar_cones.ts +++ /dev/null @@ -1,70 +0,0 @@ -import * as THREE from 'three'; -import { ARButton } from 'three/addons/webxr/ARButton.js'; - -let camera, scene, renderer; -let controller; - -init(); -animate(); - -function init() { - const container = document.createElement('div'); - document.body.appendChild(container); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20); - - const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 3); - light.position.set(0.5, 1, 0.25); - scene.add(light); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.xr.enabled = true; - container.appendChild(renderer.domElement); - - // - - document.body.appendChild(ARButton.createButton(renderer)); - - // - - const geometry = new THREE.CylinderGeometry(0, 0.05, 0.2, 32).rotateX(Math.PI / 2); - - function onSelect() { - const material = new THREE.MeshPhongMaterial({ color: 0xffffff * Math.random() }); - const mesh = new THREE.Mesh(geometry, material); - mesh.position.set(0, 0, -0.3).applyMatrix4(controller.matrixWorld); - mesh.quaternion.setFromRotationMatrix(controller.matrixWorld); - scene.add(mesh); - } - - controller = renderer.xr.getController(0); - controller.addEventListener('select', onSelect); - scene.add(controller); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - renderer.setAnimationLoop(render); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webxr_ar_hittest.ts b/examples-testing/examples/webxr_ar_hittest.ts deleted file mode 100644 index 5540c90da..000000000 --- a/examples-testing/examples/webxr_ar_hittest.ts +++ /dev/null @@ -1,119 +0,0 @@ -import * as THREE from 'three'; -import { ARButton } from 'three/addons/webxr/ARButton.js'; - -let container; -let camera, scene, renderer; -let controller; - -let reticle; - -let hitTestSource = null; -let hitTestSourceRequested = false; - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20); - - const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 3); - light.position.set(0.5, 1, 0.25); - scene.add(light); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.xr.enabled = true; - container.appendChild(renderer.domElement); - - // - - document.body.appendChild(ARButton.createButton(renderer, { requiredFeatures: ['hit-test'] })); - - // - - const geometry = new THREE.CylinderGeometry(0.1, 0.1, 0.2, 32).translate(0, 0.1, 0); - - function onSelect() { - if (reticle.visible) { - const material = new THREE.MeshPhongMaterial({ color: 0xffffff * Math.random() }); - const mesh = new THREE.Mesh(geometry, material); - reticle.matrix.decompose(mesh.position, mesh.quaternion, mesh.scale); - mesh.scale.y = Math.random() * 2 + 1; - scene.add(mesh); - } - } - - controller = renderer.xr.getController(0); - controller.addEventListener('select', onSelect); - scene.add(controller); - - reticle = new THREE.Mesh( - new THREE.RingGeometry(0.15, 0.2, 32).rotateX(-Math.PI / 2), - new THREE.MeshBasicMaterial(), - ); - reticle.matrixAutoUpdate = false; - reticle.visible = false; - scene.add(reticle); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - renderer.setAnimationLoop(render); -} - -function render(timestamp, frame) { - if (frame) { - const referenceSpace = renderer.xr.getReferenceSpace(); - const session = renderer.xr.getSession(); - - if (hitTestSourceRequested === false) { - session.requestReferenceSpace('viewer').then(function (referenceSpace) { - session.requestHitTestSource({ space: referenceSpace }).then(function (source) { - hitTestSource = source; - }); - }); - - session.addEventListener('end', function () { - hitTestSourceRequested = false; - hitTestSource = null; - }); - - hitTestSourceRequested = true; - } - - if (hitTestSource) { - const hitTestResults = frame.getHitTestResults(hitTestSource); - - if (hitTestResults.length) { - const hit = hitTestResults[0]; - - reticle.visible = true; - reticle.matrix.fromArray(hit.getPose(referenceSpace).transform.matrix); - } else { - reticle.visible = false; - } - } - } - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webxr_ar_lighting.ts b/examples-testing/examples/webxr_ar_lighting.ts deleted file mode 100644 index 1a9c4de21..000000000 --- a/examples-testing/examples/webxr_ar_lighting.ts +++ /dev/null @@ -1,128 +0,0 @@ -import * as THREE from 'three'; -import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'; -import { ARButton } from 'three/addons/webxr/ARButton.js'; -import { XREstimatedLight } from 'three/addons/webxr/XREstimatedLight.js'; - -let camera, scene, renderer; -let controller; -let defaultEnvironment; - -init(); -animate(); - -function init() { - const container = document.createElement('div'); - document.body.appendChild(container); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20); - - const defaultLight = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1); - defaultLight.position.set(0.5, 1, 0.25); - scene.add(defaultLight); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.xr.enabled = true; - container.appendChild(renderer.domElement); - - // Don't add the XREstimatedLight to the scene initially. - // It doesn't have any estimated lighting values until an AR session starts. - - const xrLight = new XREstimatedLight(renderer); - - xrLight.addEventListener('estimationstart', () => { - // Swap the default light out for the estimated one one we start getting some estimated values. - scene.add(xrLight); - scene.remove(defaultLight); - - // The estimated lighting also provides an environment cubemap, which we can apply here. - if (xrLight.environment) { - scene.environment = xrLight.environment; - } - }); - - xrLight.addEventListener('estimationend', () => { - // Swap the lights back when we stop receiving estimated values. - scene.add(defaultLight); - scene.remove(xrLight); - - // Revert back to the default environment. - scene.environment = defaultEnvironment; - }); - - // - - new RGBELoader().setPath('textures/equirectangular/').load('royal_esplanade_1k.hdr', function (texture) { - texture.mapping = THREE.EquirectangularReflectionMapping; - - defaultEnvironment = texture; - - scene.environment = defaultEnvironment; - }); - - // - - // In order for lighting estimation to work, 'light-estimation' must be included as either an optional or required feature. - document.body.appendChild(ARButton.createButton(renderer, { optionalFeatures: ['light-estimation'] })); - - // - - const ballGeometry = new THREE.SphereGeometry(0.175, 32, 32); - const ballGroup = new THREE.Group(); - ballGroup.position.z = -2; - - const rows = 3; - const cols = 3; - - for (let i = 0; i < rows; i++) { - for (let j = 0; j < cols; j++) { - const ballMaterial = new THREE.MeshStandardMaterial({ - color: 0xdddddd, - roughness: i / rows, - metalness: j / cols, - }); - const ballMesh = new THREE.Mesh(ballGeometry, ballMaterial); - ballMesh.position.set((i + 0.5 - rows * 0.5) * 0.4, (j + 0.5 - cols * 0.5) * 0.4, 0); - ballGroup.add(ballMesh); - } - } - - scene.add(ballGroup); - - // - - function onSelect() { - ballGroup.position.set(0, 0, -2).applyMatrix4(controller.matrixWorld); - ballGroup.quaternion.setFromRotationMatrix(controller.matrixWorld); - } - - controller = renderer.xr.getController(0); - controller.addEventListener('select', onSelect); - scene.add(controller); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -function animate() { - renderer.setAnimationLoop(render); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webxr_ar_plane_detection.ts b/examples-testing/examples/webxr_ar_plane_detection.ts deleted file mode 100644 index 0826cc3a6..000000000 --- a/examples-testing/examples/webxr_ar_plane_detection.ts +++ /dev/null @@ -1,46 +0,0 @@ -import * as THREE from 'three'; -import { ARButton } from 'three/addons/webxr/ARButton.js'; -import { XRPlanes } from 'three/addons/webxr/XRPlanes.js'; - -// - -const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); -renderer.setPixelRatio(window.devicePixelRatio); -renderer.setSize(window.innerWidth, window.innerHeight); -renderer.setAnimationLoop(render); -renderer.xr.enabled = true; -document.body.appendChild(renderer.domElement); - -document.body.appendChild( - ARButton.createButton(renderer, { - requiredFeatures: ['plane-detection'], - }), -); - -window.addEventListener('resize', onWindowResize); - -// - -const scene = new THREE.Scene(); - -const planes = new XRPlanes(renderer); -scene.add(planes); - -const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20); - -const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 3); -light.position.set(0.5, 1, 0.25); -scene.add(light); - -// - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webxr_vr_handinput.ts b/examples-testing/examples/webxr_vr_handinput.ts deleted file mode 100644 index a896103ad..000000000 --- a/examples-testing/examples/webxr_vr_handinput.ts +++ /dev/null @@ -1,126 +0,0 @@ -import * as THREE from 'three'; -import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -import { VRButton } from 'three/addons/webxr/VRButton.js'; -import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js'; -import { XRHandModelFactory } from 'three/addons/webxr/XRHandModelFactory.js'; - -let container; -let camera, scene, renderer; -let hand1, hand2; -let controller1, controller2; -let controllerGrip1, controllerGrip2; - -let controls; - -init(); -animate(); - -function init() { - container = document.createElement('div'); - document.body.appendChild(container); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x444444); - - camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 10); - camera.position.set(0, 1.6, 3); - - controls = new OrbitControls(camera, container); - controls.target.set(0, 1.6, 0); - controls.update(); - - const floorGeometry = new THREE.PlaneGeometry(4, 4); - const floorMaterial = new THREE.MeshStandardMaterial({ color: 0x666666 }); - const floor = new THREE.Mesh(floorGeometry, floorMaterial); - floor.rotation.x = -Math.PI / 2; - floor.receiveShadow = true; - scene.add(floor); - - scene.add(new THREE.HemisphereLight(0xbcbcbc, 0xa5a5a5, 3)); - - const light = new THREE.DirectionalLight(0xffffff, 3); - light.position.set(0, 6, 0); - light.castShadow = true; - light.shadow.camera.top = 2; - light.shadow.camera.bottom = -2; - light.shadow.camera.right = 2; - light.shadow.camera.left = -2; - light.shadow.mapSize.set(4096, 4096); - scene.add(light); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.shadowMap.enabled = true; - renderer.xr.enabled = true; - - container.appendChild(renderer.domElement); - - document.body.appendChild(VRButton.createButton(renderer)); - - // controllers - - controller1 = renderer.xr.getController(0); - scene.add(controller1); - - controller2 = renderer.xr.getController(1); - scene.add(controller2); - - const controllerModelFactory = new XRControllerModelFactory(); - const handModelFactory = new XRHandModelFactory(); - - // Hand 1 - controllerGrip1 = renderer.xr.getControllerGrip(0); - controllerGrip1.add(controllerModelFactory.createControllerModel(controllerGrip1)); - scene.add(controllerGrip1); - - hand1 = renderer.xr.getHand(0); - hand1.add(handModelFactory.createHandModel(hand1)); - - scene.add(hand1); - - // Hand 2 - controllerGrip2 = renderer.xr.getControllerGrip(1); - controllerGrip2.add(controllerModelFactory.createControllerModel(controllerGrip2)); - scene.add(controllerGrip2); - - hand2 = renderer.xr.getHand(1); - hand2.add(handModelFactory.createHandModel(hand2)); - scene.add(hand2); - - // - - const geometry = new THREE.BufferGeometry().setFromPoints([ - new THREE.Vector3(0, 0, 0), - new THREE.Vector3(0, 0, -1), - ]); - - const line = new THREE.Line(geometry); - line.name = 'line'; - line.scale.z = 5; - - controller1.add(line.clone()); - controller2.add(line.clone()); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} -// - -function animate() { - renderer.setAnimationLoop(render); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webxr_vr_panorama.ts b/examples-testing/examples/webxr_vr_panorama.ts deleted file mode 100644 index fdd23aaa6..000000000 --- a/examples-testing/examples/webxr_vr_panorama.ts +++ /dev/null @@ -1,96 +0,0 @@ -import * as THREE from 'three'; -import { VRButton } from 'three/addons/webxr/VRButton.js'; - -let camera; -let renderer; -let scene; - -init(); -animate(); - -function init() { - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.xr.enabled = true; - renderer.xr.setReferenceSpaceType('local'); - document.body.appendChild(renderer.domElement); - - document.body.appendChild(VRButton.createButton(renderer)); - - // - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000); - camera.layers.enable(1); - - const geometry = new THREE.BoxGeometry(100, 100, 100); - geometry.scale(1, 1, -1); - - const textures = getTexturesFromAtlasFile('textures/cube/sun_temple_stripe_stereo.jpg', 12); - - const materials = []; - - for (let i = 0; i < 6; i++) { - materials.push(new THREE.MeshBasicMaterial({ map: textures[i] })); - } - - const skyBox = new THREE.Mesh(geometry, materials); - skyBox.layers.set(1); - scene.add(skyBox); - - const materialsR = []; - - for (let i = 6; i < 12; i++) { - materialsR.push(new THREE.MeshBasicMaterial({ map: textures[i] })); - } - - const skyBoxR = new THREE.Mesh(geometry, materialsR); - skyBoxR.layers.set(2); - scene.add(skyBoxR); - - window.addEventListener('resize', onWindowResize); -} - -function getTexturesFromAtlasFile(atlasImgUrl, tilesNum) { - const textures = []; - - for (let i = 0; i < tilesNum; i++) { - textures[i] = new THREE.Texture(); - } - - const loader = new THREE.ImageLoader(); - loader.load(atlasImgUrl, function (imageObj) { - let canvas, context; - const tileWidth = imageObj.height; - - for (let i = 0; i < textures.length; i++) { - canvas = document.createElement('canvas'); - context = canvas.getContext('2d'); - canvas.height = tileWidth; - canvas.width = tileWidth; - context.drawImage(imageObj, tileWidth * i, 0, tileWidth, tileWidth, 0, 0, tileWidth, tileWidth); - textures[i].colorSpace = THREE.SRGBColorSpace; - textures[i].image = canvas; - textures[i].needsUpdate = true; - } - }); - - return textures; -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - renderer.setAnimationLoop(render); -} - -function render() { - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webxr_vr_panorama_depth.ts b/examples-testing/examples/webxr_vr_panorama_depth.ts deleted file mode 100644 index a09b73344..000000000 --- a/examples-testing/examples/webxr_vr_panorama_depth.ts +++ /dev/null @@ -1,94 +0,0 @@ -import * as THREE from 'three'; -import { VRButton } from 'three/addons/webxr/VRButton.js'; - -let camera, scene, renderer, sphere, clock; - -init(); -animate(); - -function init() { - const container = document.getElementById('container'); - - clock = new THREE.Clock(); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x101010); - - const light = new THREE.AmbientLight(0xffffff, 3); - scene.add(light); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 2000); - scene.add(camera); - - // Create the panoramic sphere geometery - const panoSphereGeo = new THREE.SphereGeometry(6, 256, 256); - - // Create the panoramic sphere material - const panoSphereMat = new THREE.MeshStandardMaterial({ - side: THREE.BackSide, - displacementScale: -4.0, - }); - - // Create the panoramic sphere mesh - sphere = new THREE.Mesh(panoSphereGeo, panoSphereMat); - - // Load and assign the texture and depth map - const manager = new THREE.LoadingManager(); - const loader = new THREE.TextureLoader(manager); - - loader.load('./textures/kandao3.jpg', function (texture) { - texture.colorSpace = THREE.SRGBColorSpace; - texture.minFilter = THREE.NearestFilter; - texture.generateMipmaps = false; - sphere.material.map = texture; - }); - - loader.load('./textures/kandao3_depthmap.jpg', function (depth) { - depth.minFilter = THREE.NearestFilter; - depth.generateMipmaps = false; - sphere.material.displacementMap = depth; - }); - - // On load complete add the panoramic sphere to the scene - manager.onLoad = function () { - scene.add(sphere); - }; - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.xr.enabled = true; - renderer.xr.setReferenceSpaceType('local'); - container.appendChild(renderer.domElement); - - document.body.appendChild(VRButton.createButton(renderer)); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - renderer.setAnimationLoop(render); -} - -function render() { - // If we are not presenting move the camera a little so the effect is visible - - if (renderer.xr.isPresenting === false) { - const time = clock.getElapsedTime(); - - sphere.rotation.y += 0.001; - sphere.position.x = Math.sin(time) * 0.2; - sphere.position.z = Math.cos(time) * 0.2; - } - - renderer.render(scene, camera); -} diff --git a/examples-testing/examples/webxr_vr_rollercoaster.ts b/examples-testing/examples/webxr_vr_rollercoaster.ts deleted file mode 100644 index b65965267..000000000 --- a/examples-testing/examples/webxr_vr_rollercoaster.ts +++ /dev/null @@ -1,212 +0,0 @@ -import * as THREE from 'three'; - -import { - RollerCoasterGeometry, - RollerCoasterShadowGeometry, - RollerCoasterLiftersGeometry, - TreesGeometry, - SkyGeometry, -} from 'three/addons/misc/RollerCoaster.js'; -import { VRButton } from 'three/addons/webxr/VRButton.js'; - -let mesh, material, geometry; - -const renderer = new THREE.WebGLRenderer({ antialias: true }); -renderer.setPixelRatio(window.devicePixelRatio); -renderer.setSize(window.innerWidth, window.innerHeight); -renderer.xr.enabled = true; -renderer.xr.setReferenceSpaceType('local'); -document.body.appendChild(renderer.domElement); - -document.body.appendChild(VRButton.createButton(renderer)); - -// - -const scene = new THREE.Scene(); -scene.background = new THREE.Color(0xf0f0ff); - -const light = new THREE.HemisphereLight(0xfff0f0, 0x60606, 3); -light.position.set(1, 1, 1); -scene.add(light); - -const train = new THREE.Object3D(); -scene.add(train); - -const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 500); -train.add(camera); - -// environment - -geometry = new THREE.PlaneGeometry(500, 500, 15, 15); -geometry.rotateX(-Math.PI / 2); - -const positions = geometry.attributes.position.array; -const vertex = new THREE.Vector3(); - -for (let i = 0; i < positions.length; i += 3) { - vertex.fromArray(positions, i); - - vertex.x += Math.random() * 10 - 5; - vertex.z += Math.random() * 10 - 5; - - const distance = vertex.distanceTo(scene.position) / 5 - 25; - vertex.y = Math.random() * Math.max(0, distance); - - vertex.toArray(positions, i); -} - -geometry.computeVertexNormals(); - -material = new THREE.MeshLambertMaterial({ - color: 0x407000, -}); - -mesh = new THREE.Mesh(geometry, material); -scene.add(mesh); - -geometry = new TreesGeometry(mesh); -material = new THREE.MeshBasicMaterial({ - side: THREE.DoubleSide, - vertexColors: true, -}); -mesh = new THREE.Mesh(geometry, material); -scene.add(mesh); - -geometry = new SkyGeometry(); -material = new THREE.MeshBasicMaterial({ color: 0xffffff }); -mesh = new THREE.Mesh(geometry, material); -scene.add(mesh); - -// - -const PI2 = Math.PI * 2; - -const curve = (function () { - const vector = new THREE.Vector3(); - const vector2 = new THREE.Vector3(); - - return { - getPointAt: function (t) { - t = t * PI2; - - const x = Math.sin(t * 3) * Math.cos(t * 4) * 50; - const y = Math.sin(t * 10) * 2 + Math.cos(t * 17) * 2 + 5; - const z = Math.sin(t) * Math.sin(t * 4) * 50; - - return vector.set(x, y, z).multiplyScalar(2); - }, - - getTangentAt: function (t) { - const delta = 0.0001; - const t1 = Math.max(0, t - delta); - const t2 = Math.min(1, t + delta); - - return vector2.copy(this.getPointAt(t2)).sub(this.getPointAt(t1)).normalize(); - }, - }; -})(); - -geometry = new RollerCoasterGeometry(curve, 1500); -material = new THREE.MeshPhongMaterial({ - vertexColors: true, -}); -mesh = new THREE.Mesh(geometry, material); -scene.add(mesh); - -geometry = new RollerCoasterLiftersGeometry(curve, 100); -material = new THREE.MeshPhongMaterial(); -mesh = new THREE.Mesh(geometry, material); -mesh.position.y = 0.1; -scene.add(mesh); - -geometry = new RollerCoasterShadowGeometry(curve, 500); -material = new THREE.MeshBasicMaterial({ - color: 0x305000, - depthWrite: false, - transparent: true, -}); -mesh = new THREE.Mesh(geometry, material); -mesh.position.y = 0.1; -scene.add(mesh); - -const funfairs = []; - -// - -geometry = new THREE.CylinderGeometry(10, 10, 5, 15); -material = new THREE.MeshLambertMaterial({ - color: 0xff8080, -}); -mesh = new THREE.Mesh(geometry, material); -mesh.position.set(-80, 10, -70); -mesh.rotation.x = Math.PI / 2; -scene.add(mesh); - -funfairs.push(mesh); - -geometry = new THREE.CylinderGeometry(5, 6, 4, 10); -material = new THREE.MeshLambertMaterial({ - color: 0x8080ff, -}); -mesh = new THREE.Mesh(geometry, material); -mesh.position.set(50, 2, 30); -scene.add(mesh); - -funfairs.push(mesh); - -// - -window.addEventListener('resize', onWindowResize); - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -// - -const position = new THREE.Vector3(); -const tangent = new THREE.Vector3(); - -const lookAt = new THREE.Vector3(); - -let velocity = 0; -let progress = 0; - -let prevTime = performance.now(); - -function render() { - const time = performance.now(); - const delta = time - prevTime; - - for (let i = 0; i < funfairs.length; i++) { - funfairs[i].rotation.y = time * 0.0004; - } - - // - - progress += velocity; - progress = progress % 1; - - position.copy(curve.getPointAt(progress)); - position.y += 0.3; - - train.position.copy(position); - - tangent.copy(curve.getTangentAt(progress)); - - velocity -= tangent.y * 0.0000001 * delta; - velocity = Math.max(0.00004, Math.min(0.0002, velocity)); - - train.lookAt(lookAt.copy(position).sub(tangent)); - - // - - renderer.render(scene, camera); - - prevTime = time; -} - -renderer.setAnimationLoop(render); diff --git a/examples-testing/examples/webxr_vr_sandbox.ts b/examples-testing/examples/webxr_vr_sandbox.ts deleted file mode 100644 index aa80cf762..000000000 --- a/examples-testing/examples/webxr_vr_sandbox.ts +++ /dev/null @@ -1,209 +0,0 @@ -import * as THREE from 'three'; - -import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'; -import { Lensflare, LensflareElement } from 'three/addons/objects/Lensflare.js'; -import { Reflector } from 'three/addons/objects/Reflector.js'; -import { VRButton } from 'three/addons/webxr/VRButton.js'; - -import { HTMLMesh } from 'three/addons/interactive/HTMLMesh.js'; -import { InteractiveGroup } from 'three/addons/interactive/InteractiveGroup.js'; -import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js'; - -import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; -import Stats from 'three/addons/libs/stats.module.js'; - -let camera, scene, renderer; -let reflector; -let stats, statsMesh; - -const parameters = { - radius: 0.6, - tube: 0.2, - tubularSegments: 150, - radialSegments: 20, - p: 2, - q: 3, - thickness: 0.5, -}; - -init(); -animate(); - -function init() { - scene = new THREE.Scene(); - - new RGBELoader().setPath('textures/equirectangular/').load('moonless_golf_1k.hdr', function (texture) { - texture.mapping = THREE.EquirectangularReflectionMapping; - - scene.background = texture; - scene.environment = texture; - }); - - camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 10); - camera.position.set(0, 1.6, 1.5); - - // - - const torusGeometry = new THREE.TorusKnotGeometry(...Object.values(parameters)); - const torusMaterial = new THREE.MeshPhysicalMaterial({ - transmission: 1.0, - roughness: 0, - metalness: 0.25, - thickness: 0.5, - side: THREE.DoubleSide, - }); - const torus = new THREE.Mesh(torusGeometry, torusMaterial); - torus.name = 'torus'; - torus.position.y = 1.5; - torus.position.z = -2; - scene.add(torus); - - const cylinderGeometry = new THREE.CylinderGeometry(1, 1, 0.1, 50); - const cylinderMaterial = new THREE.MeshStandardMaterial(); - const cylinder = new THREE.Mesh(cylinderGeometry, cylinderMaterial); - cylinder.position.z = -2; - scene.add(cylinder); - - // lensflare - const loader = new THREE.TextureLoader(); - const texture0 = loader.load('textures/lensflare/lensflare0.png'); - const texture3 = loader.load('textures/lensflare/lensflare3.png'); - - const lensflare = new Lensflare(); - lensflare.position.set(0, 5, -5); - lensflare.addElement(new LensflareElement(texture0, 700, 0)); - lensflare.addElement(new LensflareElement(texture3, 60, 0.6)); - lensflare.addElement(new LensflareElement(texture3, 70, 0.7)); - lensflare.addElement(new LensflareElement(texture3, 120, 0.9)); - lensflare.addElement(new LensflareElement(texture3, 70, 1)); - scene.add(lensflare); - - // - - reflector = new Reflector(new THREE.PlaneGeometry(2, 2), { - textureWidth: window.innerWidth * window.devicePixelRatio, - textureHeight: window.innerHeight * window.devicePixelRatio, - }); - reflector.position.x = 1; - reflector.position.y = 1.5; - reflector.position.z = -3; - reflector.rotation.y = -Math.PI / 4; - // TOFIX: Reflector breaks transmission - // scene.add( reflector ); - - const frameGeometry = new THREE.BoxGeometry(2.1, 2.1, 0.1); - const frameMaterial = new THREE.MeshPhongMaterial(); - const frame = new THREE.Mesh(frameGeometry, frameMaterial); - frame.position.z = -0.07; - reflector.add(frame); - - // - - renderer = new THREE.WebGLRenderer({ antialias: true }); - renderer.autoClear = false; - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.xr.enabled = true; - renderer.toneMapping = THREE.ACESFilmicToneMapping; - renderer.toneMappingExposure = 1; - document.body.appendChild(renderer.domElement); - - document.body.appendChild(VRButton.createButton(renderer)); - - window.addEventListener('resize', onWindowResize); - - // - - const geometry = new THREE.BufferGeometry(); - geometry.setFromPoints([new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, -5)]); - - const controller1 = renderer.xr.getController(0); - controller1.add(new THREE.Line(geometry)); - scene.add(controller1); - - const controller2 = renderer.xr.getController(1); - controller2.add(new THREE.Line(geometry)); - scene.add(controller2); - - // - - const controllerModelFactory = new XRControllerModelFactory(); - - const controllerGrip1 = renderer.xr.getControllerGrip(0); - controllerGrip1.add(controllerModelFactory.createControllerModel(controllerGrip1)); - scene.add(controllerGrip1); - - const controllerGrip2 = renderer.xr.getControllerGrip(1); - controllerGrip2.add(controllerModelFactory.createControllerModel(controllerGrip2)); - scene.add(controllerGrip2); - - // GUI - - function onChange() { - torus.geometry.dispose(); - torus.geometry = new THREE.TorusKnotGeometry(...Object.values(parameters)); - } - - function onThicknessChange() { - torus.material.thickness = parameters.thickness; - } - - const gui = new GUI({ width: 300 }); - gui.add(parameters, 'radius', 0.0, 1.0).onChange(onChange); - gui.add(parameters, 'tube', 0.0, 1.0).onChange(onChange); - gui.add(parameters, 'tubularSegments', 10, 150, 1).onChange(onChange); - gui.add(parameters, 'radialSegments', 2, 20, 1).onChange(onChange); - gui.add(parameters, 'p', 1, 10, 1).onChange(onChange); - gui.add(parameters, 'q', 0, 10, 1).onChange(onChange); - gui.add(parameters, 'thickness', 0, 1).onChange(onThicknessChange); - gui.domElement.style.visibility = 'hidden'; - - const group = new InteractiveGroup(renderer, camera); - scene.add(group); - - const mesh = new HTMLMesh(gui.domElement); - mesh.position.x = -0.75; - mesh.position.y = 1.5; - mesh.position.z = -0.5; - mesh.rotation.y = Math.PI / 4; - mesh.scale.setScalar(2); - group.add(mesh); - - // Add stats.js - stats = new Stats(); - stats.dom.style.width = '80px'; - stats.dom.style.height = '48px'; - document.body.appendChild(stats.dom); - - statsMesh = new HTMLMesh(stats.dom); - statsMesh.position.x = -0.75; - statsMesh.position.y = 2; - statsMesh.position.z = -0.6; - statsMesh.rotation.y = Math.PI / 4; - statsMesh.scale.setScalar(2.5); - group.add(statsMesh); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - renderer.setAnimationLoop(render); -} - -function render() { - const time = performance.now() * 0.0002; - const torus = scene.getObjectByName('torus'); - torus.rotation.x = time * 0.4; - torus.rotation.y = time; - - renderer.render(scene, camera); - stats.update(); - - // Canvas elements doesn't trigger DOM updates, so we have to update the texture - statsMesh.material.map.update(); -} diff --git a/examples-testing/examples/webxr_vr_video.ts b/examples-testing/examples/webxr_vr_video.ts deleted file mode 100644 index 2baded481..000000000 --- a/examples-testing/examples/webxr_vr_video.ts +++ /dev/null @@ -1,96 +0,0 @@ -import * as THREE from 'three'; -import { VRButton } from 'three/addons/webxr/VRButton.js'; - -let camera, scene, renderer; - -init(); -animate(); - -function init() { - const container = document.getElementById('container'); - container.addEventListener('click', function () { - video.play(); - }); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 2000); - camera.layers.enable(1); // render left view when no stereo available - - // video - - const video = document.getElementById('video'); - video.play(); - - const texture = new THREE.VideoTexture(video); - texture.colorSpace = THREE.SRGBColorSpace; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0x101010); - - // left - - const geometry1 = new THREE.SphereGeometry(500, 60, 40); - // invert the geometry on the x-axis so that all of the faces point inward - geometry1.scale(-1, 1, 1); - - const uvs1 = geometry1.attributes.uv.array; - - for (let i = 0; i < uvs1.length; i += 2) { - uvs1[i] *= 0.5; - } - - const material1 = new THREE.MeshBasicMaterial({ map: texture }); - - const mesh1 = new THREE.Mesh(geometry1, material1); - mesh1.rotation.y = -Math.PI / 2; - mesh1.layers.set(1); // display in left eye only - scene.add(mesh1); - - // right - - const geometry2 = new THREE.SphereGeometry(500, 60, 40); - geometry2.scale(-1, 1, 1); - - const uvs2 = geometry2.attributes.uv.array; - - for (let i = 0; i < uvs2.length; i += 2) { - uvs2[i] *= 0.5; - uvs2[i] += 0.5; - } - - const material2 = new THREE.MeshBasicMaterial({ map: texture }); - - const mesh2 = new THREE.Mesh(geometry2, material2); - mesh2.rotation.y = -Math.PI / 2; - mesh2.layers.set(2); // display in right eye only - scene.add(mesh2); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.xr.enabled = true; - renderer.xr.setReferenceSpaceType('local'); - container.appendChild(renderer.domElement); - - document.body.appendChild(VRButton.createButton(renderer)); - - // - - window.addEventListener('resize', onWindowResize); -} - -function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() { - renderer.setAnimationLoop(render); -} - -function render() { - renderer.render(scene, camera); -}