From 777bfb1b4a4b05942b99c322d0e00b8846fbf404 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Tue, 4 Jul 2023 16:01:36 -0400 Subject: [PATCH 1/4] Add example --- examples-testing/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples-testing/index.js b/examples-testing/index.js index 93e13d4f6..6a8b646b5 100644 --- a/examples-testing/index.js +++ b/examples-testing/index.js @@ -372,7 +372,7 @@ const files = { physics: [ // 'physics_ammo_break', // 'physics_ammo_cloth', - // 'physics_ammo_instancing', + 'physics_ammo_instancing', // 'physics_ammo_rope', // 'physics_ammo_terrain', // 'physics_ammo_volume', From 86a053ebfd2be1d33ac085455a55192a8a07f38d Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Tue, 4 Jul 2023 16:01:57 -0400 Subject: [PATCH 2/4] Fix types for AmmoPhysics --- types/three/examples/jsm/physics/AmmoPhysics.d.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/types/three/examples/jsm/physics/AmmoPhysics.d.ts b/types/three/examples/jsm/physics/AmmoPhysics.d.ts index 5e4fdcfd8..91988f838 100644 --- a/types/three/examples/jsm/physics/AmmoPhysics.d.ts +++ b/types/three/examples/jsm/physics/AmmoPhysics.d.ts @@ -1,7 +1,8 @@ import { Mesh, Vector3 } from '../../../src/Three'; -export class AmmoPhysics { - constructor(); - addMesh(mesh: Mesh, mass: number): void; - setMeshPosition(mesh: Mesh, position: Vector3, index: number): void; +export interface AmmoPhysicsObject { + addMesh: (mesh: Mesh, mass?: number) => void; + setMeshPosition: (mesh: Mesh, position: Vector3, index?: number) => void; } + +export function AmmoPhysics(): Promise; From 70d52163c7901203e9a30dabae52138effbb37c5 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Tue, 4 Jul 2023 16:02:41 -0400 Subject: [PATCH 3/4] 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 | 143 ++++ .../examples/misc_controls_arcball.ts | 212 +++++ .../examples/misc_controls_drag.ts | 149 ++++ .../examples/misc_controls_fly.ts | 228 +++++ .../examples/misc_controls_map.ts | 99 +++ .../examples/misc_controls_orbit.ts | 91 ++ .../examples/misc_controls_pointerlock.ts | 247 ++++++ .../examples/misc_controls_trackball.ts | 136 +++ .../examples/misc_controls_transform.ts | 170 ++++ .../examples/misc_exporter_draco.ts | 120 +++ .../examples/misc_exporter_gltf.ts | 492 +++++++++++ .../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 | 123 +++ .../examples/physics_rapier_instancing.ts | 123 +++ examples-testing/examples/svg_lines.ts | 87 ++ examples-testing/examples/svg_sandbox.ts | 212 +++++ .../examples/webaudio_orientation.ts | 141 ++++ 32 files changed, 6100 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 diff --git a/examples-testing/examples/css2d_label.ts b/examples-testing/examples/css2d_label.ts new file mode 100644 index 000000000..cf61d1e0b --- /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, 1); + 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..49dd6f395 --- /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, 0.5); +fillLight1.position.set(2, 1, 1); +scene.add(fillLight1); + +const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); +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..a78c71b31 --- /dev/null +++ b/examples-testing/examples/misc_boxselection.ts @@ -0,0 +1,143 @@ +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, 1, 5000); + camera.position.z = 1000; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xf0f0f0); + + scene.add(new THREE.AmbientLight(0x505050)); + + const light = new THREE.SpotLight(0xffffff, 1.5); + light.position.set(0, 500, 2000); + light.angle = Math.PI / 9; + + light.castShadow = true; + light.shadow.camera.near = 1000; + light.shadow.camera.far = 4000; + light.shadow.mapSize.width = 1024; + light.shadow.mapSize.height = 1024; + + scene.add(light); + + const geometry = new THREE.BoxGeometry(20, 20, 20); + + 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() * 1600 - 800; + object.position.y = Math.random() * 900 - 450; + object.position.z = Math.random() * 900 - 500; + + 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..f7ea233de --- /dev/null +++ b/examples-testing/examples/misc_controls_arcball.ts @@ -0,0 +1,212 @@ +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(); + scene.add(new THREE.HemisphereLight(0x443333, 0x222233, 4)); + + 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..da4bd2431 --- /dev/null +++ b/examples-testing/examples/misc_controls_drag.ts @@ -0,0 +1,149 @@ +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, 1, 5000); + camera.position.z = 1000; + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xf0f0f0); + + scene.add(new THREE.AmbientLight(0x505050)); + + const light = new THREE.SpotLight(0xffffff, 1.5); + light.position.set(0, 500, 2000); + light.angle = Math.PI / 9; + + light.castShadow = true; + light.shadow.camera.near = 1000; + light.shadow.camera.far = 4000; + 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(40, 40, 40); + + 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() * 1000 - 500; + object.position.y = Math.random() * 600 - 300; + object.position.z = Math.random() * 800 - 400; + + 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..2dd77ec7f --- /dev/null +++ b/examples-testing/examples/misc_controls_fly.ts @@ -0,0 +1,228 @@ +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 { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; +import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.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); + 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 gammaCorrection = new ShaderPass(GammaCorrectionShader); + + composer = new EffectComposer(renderer); + + composer.addPass(renderModel); + composer.addPass(effectFilm); + composer.addPass(gammaCorrection); +} + +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..35e03d2cf --- /dev/null +++ b/examples-testing/examples/misc_controls_map.ts @@ -0,0 +1,99 @@ +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(400, 200, 0); + + // 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(1, 1, 1); + 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); + dirLight1.position.set(1, 1, 1); + scene.add(dirLight1); + + const dirLight2 = new THREE.DirectionalLight(0x002288); + dirLight2.position.set(-1, -1, -1); + scene.add(dirLight2); + + const ambientLight = new THREE.AmbientLight(0x222222); + scene.add(ambientLight); + + // + + window.addEventListener('resize', onWindowResize); + + const gui = new GUI(); + 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..28bc3c01e --- /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.CylinderGeometry(0, 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); + dirLight1.position.set(1, 1, 1); + scene.add(dirLight1); + + const dirLight2 = new THREE.DirectionalLight(0x002288); + dirLight2.position.set(-1, -1, -1); + scene.add(dirLight2); + + const ambientLight = new THREE.AmbientLight(0x222222); + 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..d29ffaff6 --- /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, 0.75); + 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..19c42c6a7 --- /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.CylinderGeometry(0, 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); + dirLight1.position.set(1, 1, 1); + scene.add(dirLight1); + + const dirLight2 = new THREE.DirectionalLight(0x002288); + dirLight2.position.set(-1, -1, -1); + scene.add(dirLight2); + + const ambientLight = new THREE.AmbientLight(0x222222); + 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..aa4de6f31 --- /dev/null +++ b/examples-testing/examples/misc_controls_transform.ts @@ -0,0 +1,170 @@ +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(); + 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(1000, 500, 1000); + currentCamera.lookAt(0, 200, 0); + + scene = new THREE.Scene(); + scene.add(new THREE.GridHelper(1000, 10, 0x888888, 0x444444)); + + const light = new THREE.DirectionalLight(0xffffff, 2); + 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(200, 200, 200); + const material = new THREE.MeshLambertMaterial({ map: texture, transparent: true }); + + 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..ce1e69673 --- /dev/null +++ b/examples-testing/examples/misc_exporter_draco.ts @@ -0,0 +1,120 @@ +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, 1, 1000); + camera.position.set(200, 100, 200); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xa0a0a0); + scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000); + + exporter = new DRACOExporter(); + + // + + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444); + hemiLight.position.set(0, 200, 0); + scene.add(hemiLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); + directionalLight.position.set(0, 200, 100); + directionalLight.castShadow = true; + directionalLight.shadow.camera.top = 180; + directionalLight.shadow.camera.bottom = -100; + directionalLight.shadow.camera.left = -120; + directionalLight.shadow.camera.right = 120; + scene.add(directionalLight); + + // ground + + const ground = new THREE.Mesh( + new THREE.PlaneGeometry(2000, 2000), + new THREE.MeshPhongMaterial({ color: 0xbbbbbb, depthWrite: false }), + ); + ground.rotation.x = -Math.PI / 2; + ground.position.y = -75; + ground.receiveShadow = true; + scene.add(ground); + + const grid = new THREE.GridHelper(2000, 20, 0x000000, 0x000000); + grid.material.opacity = 0.2; + grid.material.transparent = true; + grid.position.y = -75; + scene.add(grid); + + // export mesh + + const geometry = new THREE.TorusKnotGeometry(50, 15, 200, 30); + const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 }); + mesh = new THREE.Mesh(geometry, material); + mesh.castShadow = true; + mesh.position.y = 25; + 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, 25, 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..c9d943330 --- /dev/null +++ b/examples-testing/examples/misc_exporter_gltf.ts @@ -0,0 +1,492 @@ +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(0xffffff, 0.2); + ambientLight.name = 'AmbientLight'; + scene1.add(ambientLight); + + // --------------------------------------------------------------------- + // DirectLight + // --------------------------------------------------------------------- + const dirLight = new THREE.DirectionalLight(0xffffff, 1); + 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; + 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..02ad9072b --- /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(0xcccccc, 0.4); + scene.add(ambientLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); + 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..b6a334ddc --- /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, 1, 1000); + camera.position.set(200, 100, 200); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xa0a0a0); + scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000); + + exporter = new PLYExporter(); + + // + + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x8d8d8d); + hemiLight.position.set(0, 200, 0); + scene.add(hemiLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff); + directionalLight.position.set(0, 200, 100); + directionalLight.castShadow = true; + directionalLight.shadow.camera.top = 180; + directionalLight.shadow.camera.bottom = -100; + directionalLight.shadow.camera.left = -120; + directionalLight.shadow.camera.right = 120; + scene.add(directionalLight); + + // ground + + const ground = new THREE.Mesh( + new THREE.PlaneGeometry(2000, 2000), + new THREE.MeshPhongMaterial({ color: 0xcbcbcb, depthWrite: false }), + ); + ground.rotation.x = -Math.PI / 2; + ground.receiveShadow = true; + scene.add(ground); + + const grid = new THREE.GridHelper(2000, 20, 0x000000, 0x000000); + grid.material.opacity = 0.2; + grid.material.transparent = true; + scene.add(grid); + + // export mesh + + const geometry = new THREE.BoxGeometry(50, 50, 50); + 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 = 25; + 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, 25, 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..673bad138 --- /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, 1, 1000); + camera.position.set(200, 100, 200); + + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xa0a0a0); + scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000); + + exporter = new STLExporter(); + + // + + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444); + hemiLight.position.set(0, 200, 0); + scene.add(hemiLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff); + directionalLight.position.set(0, 200, 100); + directionalLight.castShadow = true; + directionalLight.shadow.camera.top = 180; + directionalLight.shadow.camera.bottom = -100; + directionalLight.shadow.camera.left = -120; + directionalLight.shadow.camera.right = 120; + scene.add(directionalLight); + + // ground + + const ground = new THREE.Mesh( + new THREE.PlaneGeometry(2000, 2000), + new THREE.MeshPhongMaterial({ color: 0xbbbbbb, depthWrite: false }), + ); + ground.rotation.x = -Math.PI / 2; + ground.receiveShadow = true; + scene.add(ground); + + const grid = new THREE.GridHelper(2000, 20, 0x000000, 0x000000); + grid.material.opacity = 0.2; + grid.material.transparent = true; + scene.add(grid); + + // export mesh + + const geometry = new THREE.BoxGeometry(50, 50, 50); + const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 }); + + mesh = new THREE.Mesh(geometry, material); + mesh.castShadow = true; + mesh.position.y = 25; + 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, 25, 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..9117411b5 --- /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(), 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..eb33424b3 --- /dev/null +++ b/examples-testing/examples/physics_ammo_instancing.ts @@ -0,0 +1,123 @@ +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(); + hemiLight.intensity = 0.3; + scene.add(hemiLight); + + const dirLight = new THREE.DirectionalLight(); + 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..8f1bdda24 --- /dev/null +++ b/examples-testing/examples/physics_rapier_instancing.ts @@ -0,0 +1,123 @@ +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(); + hemiLight.intensity = 0.3; + scene.add(hemiLight); + + const dirLight = new THREE.DirectionalLight(); + 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..8a74c4187 --- /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); + hemiLight.position.set(0, 20, 0); + scene.add(hemiLight); + + const dirLight = new THREE.DirectionalLight(0xffffff); + 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.setSize(window.innerWidth, window.innerHeight); + renderer.setPixelRatio(window.devicePixelRatio); + 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); +} From 56f319f730883a87cb743547d217b07522e0e8df Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Tue, 4 Jul 2023 16:04:42 -0400 Subject: [PATCH 4/4] Update patch --- examples-testing/README.md | 5 +- examples-testing/changes.patch | 83 +- 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 | 143 ---- .../examples/misc_controls_arcball.ts | 212 ----- .../examples/misc_controls_drag.ts | 149 ---- .../examples/misc_controls_fly.ts | 228 ----- .../examples/misc_controls_map.ts | 99 --- .../examples/misc_controls_orbit.ts | 91 -- .../examples/misc_controls_pointerlock.ts | 247 ------ .../examples/misc_controls_trackball.ts | 136 --- .../examples/misc_controls_transform.ts | 170 ---- .../examples/misc_exporter_draco.ts | 120 --- .../examples/misc_exporter_gltf.ts | 492 ----------- .../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 | 123 --- .../examples/physics_rapier_instancing.ts | 123 --- examples-testing/examples/svg_lines.ts | 87 -- examples-testing/examples/svg_sandbox.ts | 212 ----- .../examples/webaudio_orientation.ts | 141 ---- 34 files changed, 55 insertions(+), 6133 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 diff --git a/examples-testing/README.md b/examples-testing/README.md index 0e46eba06..f517d0b83 100644 --- a/examples-testing/README.md +++ b/examples-testing/README.md @@ -1,5 +1,7 @@ # Update patch +- `npm run create-examples` +- Commit changes - `git apply changes.patch` - Make changes - `yarn run type-check` @@ -9,8 +11,7 @@ # Update sources -- Delete all examples -- `node index.js` +- `npm run create-examples` - Commit changes - `git apply --reject changes.patch` - Fix conflicts diff --git a/examples-testing/changes.patch b/examples-testing/changes.patch index f5fd88ca7..df544b0d3 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 cf61d1e0..693b1e2b 100644 +index cf61d1e..693b1e2 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'; @@ -39,7 +39,7 @@ index cf61d1e0..693b1e2b 100644 scene.add(moon); diff --git a/examples-testing/examples/css3d_molecules.ts b/examples-testing/examples/css3d_molecules.ts -index 53847260..f08bb34a 100644 +index 5384726..f08bb34 100644 --- a/examples-testing/examples/css3d_molecules.ts +++ b/examples-testing/examples/css3d_molecules.ts @@ -5,11 +5,11 @@ import { PDBLoader } from 'three/addons/loaders/PDBLoader.js'; @@ -155,7 +155,7 @@ index 53847260..f08bb34a 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 4aabbed0..5488635e 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'; @@ -287,7 +287,7 @@ index 4aabbed0..5488635e 100644 camera.setViewOffset( fullWidth || window.innerWidth, diff --git a/examples-testing/examples/css3d_periodictable.ts b/examples-testing/examples/css3d_periodictable.ts -index e3a33f79..516df464 100644 +index e3a33f7..516df46 100644 --- a/examples-testing/examples/css3d_periodictable.ts +++ b/examples-testing/examples/css3d_periodictable.ts @@ -597,11 +597,16 @@ const table = [ @@ -392,7 +392,7 @@ index e3a33f79..516df464 100644 .onUpdate(render) .start(); diff --git a/examples-testing/examples/css3d_sandbox.ts b/examples-testing/examples/css3d_sandbox.ts -index 1088b84b..b910c1f0 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'; @@ -524,7 +524,7 @@ index 1088b84b..b910c1f0 100644 camera.setViewOffset( fullWidth || window.innerWidth, diff --git a/examples-testing/examples/css3d_sprites.ts b/examples-testing/examples/css3d_sprites.ts -index dfe24e79..93f2c07b 100644 +index dfe24e7..93f2c07 100644 --- a/examples-testing/examples/css3d_sprites.ts +++ b/examples-testing/examples/css3d_sprites.ts @@ -4,12 +4,12 @@ import TWEEN from 'three/addons/libs/tween.module.js'; @@ -572,7 +572,7 @@ index dfe24e79..93f2c07b 100644 .onComplete(transition) .start(); diff --git a/examples-testing/examples/css3d_youtube.ts b/examples-testing/examples/css3d_youtube.ts -index 62652f87..3dcc2f12 100644 +index 62652f8..3dcc2f1 100644 --- a/examples-testing/examples/css3d_youtube.ts +++ b/examples-testing/examples/css3d_youtube.ts @@ -3,10 +3,10 @@ import * as THREE from 'three'; @@ -623,7 +623,7 @@ index 62652f87..3dcc2f12 100644 controls.addEventListener('start', function () { diff --git a/examples-testing/examples/games_fps.ts b/examples-testing/examples/games_fps.ts -index 49dd6f39..911a1493 100644 +index 49dd6f3..911a149 100644 --- a/examples-testing/examples/games_fps.ts +++ b/examples-testing/examples/games_fps.ts @@ -39,7 +39,7 @@ directionalLight.shadow.radius = 4; @@ -734,7 +734,7 @@ index 49dd6f39..911a1493 100644 }); diff --git a/examples-testing/examples/misc_animation_groups.ts b/examples-testing/examples/misc_animation_groups.ts -index 19d263f4..f8d0bed3 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 19d263f4..f8d0bed3 100644 init(); animate(); diff --git a/examples-testing/examples/misc_animation_keys.ts b/examples-testing/examples/misc_animation_keys.ts -index 4a808987..d2613d02 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 4a808987..d2613d02 100644 scene.add(mesh); diff --git a/examples-testing/examples/misc_boxselection.ts b/examples-testing/examples/misc_boxselection.ts -index a78c71b3..44337ff5 100644 +index a78c71b..44337ff 100644 --- a/examples-testing/examples/misc_boxselection.ts +++ b/examples-testing/examples/misc_boxselection.ts @@ -5,73 +5,70 @@ import Stats from 'three/addons/libs/stats.module.js'; @@ -933,7 +933,7 @@ index a78c71b3..44337ff5 100644 } }); diff --git a/examples-testing/examples/misc_controls_arcball.ts b/examples-testing/examples/misc_controls_arcball.ts -index f7ea233d..64a2143a 100644 +index f7ea233..64a2143 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' }; @@ -999,7 +999,7 @@ index f7ea233d..64a2143a 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 da4bd243..ec63df35 100644 +index da4bd24..ec63df3 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'; @@ -1051,7 +1051,7 @@ index da4bd243..ec63df35 100644 } diff --git a/examples-testing/examples/misc_controls_fly.ts b/examples-testing/examples/misc_controls_fly.ts -index 2dd77ec7..7c184f44 100644 +index 2dd77ec..7c184f4 100644 --- a/examples-testing/examples/misc_controls_fly.ts +++ b/examples-testing/examples/misc_controls_fly.ts @@ -20,11 +20,15 @@ const MARGIN = 0; @@ -1102,7 +1102,7 @@ index 2dd77ec7..7c184f44 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 35e03d2c..698e57ab 100644 +index 35e03d2..698e57a 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'; @@ -1127,7 +1127,7 @@ index 35e03d2c..698e57ab 100644 for (let i = 0; i < 500; i++) { const mesh = new THREE.Mesh(geometry, material); diff --git a/examples-testing/examples/misc_controls_orbit.ts b/examples-testing/examples/misc_controls_orbit.ts -index 28bc3c01..a13dc532 100644 +index 28bc3c0..a13dc53 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'; @@ -1152,7 +1152,7 @@ index 28bc3c01..a13dc532 100644 for (let i = 0; i < 500; i++) { const mesh = new THREE.Mesh(geometry, material); diff --git a/examples-testing/examples/misc_controls_pointerlock.ts b/examples-testing/examples/misc_controls_pointerlock.ts -index d29ffaff..7859eadb 100644 +index d29ffaf..7859ead 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'; @@ -1222,7 +1222,7 @@ index d29ffaff..7859eadb 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 19c42c6a..1b7f21ad 100644 +index 19c42c6..1b7f21a 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'; @@ -1270,7 +1270,7 @@ index 19c42c6a..1b7f21ad 100644 controls.rotateSpeed = 1.0; diff --git a/examples-testing/examples/misc_controls_transform.ts b/examples-testing/examples/misc_controls_transform.ts -index aa4de6f3..7c08981b 100644 +index aa4de6f..7c08981 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'; @@ -1308,7 +1308,7 @@ index aa4de6f3..7c08981b 100644 orbit.object = currentCamera; diff --git a/examples-testing/examples/misc_exporter_draco.ts b/examples-testing/examples/misc_exporter_draco.ts -index ce1e6967..f8b4b868 100644 +index ce1e696..f8b4b86 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'; @@ -1340,7 +1340,7 @@ index ce1e6967..f8b4b868 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 c9d94333..c57b22f0 100644 +index c9d9433..c57b22f 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'; @@ -1394,7 +1394,7 @@ index c9d94333..c57b22f0 100644 const params = { trs: false, diff --git a/examples-testing/examples/misc_exporter_obj.ts b/examples-testing/examples/misc_exporter_obj.ts -index 02ad9072..efb71b1d 100644 +index 02ad907..efb71b1 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'; @@ -1439,7 +1439,7 @@ index 02ad9072..efb71b1d 100644 } diff --git a/examples-testing/examples/misc_exporter_ply.ts b/examples-testing/examples/misc_exporter_ply.ts -index b6a334dd..a0e6691a 100644 +index b6a334d..a0e6691 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'; @@ -1476,7 +1476,7 @@ index b6a334dd..a0e6691a 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 673bad13..71e65414 100644 +index 673bad1..71e6541 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'; @@ -1513,7 +1513,7 @@ index 673bad13..71e65414 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 9117411b..e6c6e854 100644 +index 9117411..e6c6e85 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'; @@ -1544,7 +1544,7 @@ index 9117411b..e6c6e854 100644 canvas.width / 2, canvas.height / 2, diff --git a/examples-testing/examples/misc_lookat.ts b/examples-testing/examples/misc_lookat.ts -index f6241b9e..93e83400 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'; @@ -1569,7 +1569,7 @@ index f6241b9e..93e83400 100644 mouseY = (event.clientY - windowHalfY) * 10; } diff --git a/examples-testing/examples/misc_uv_tests.ts b/examples-testing/examples/misc_uv_tests.ts -index 4f782d45..0759cfca 100644 +index 4f782d4..0759cfc 100644 --- a/examples-testing/examples/misc_uv_tests.ts +++ b/examples-testing/examples/misc_uv_tests.ts @@ -7,7 +7,7 @@ import { UVsDebug } from 'three/addons/utils/UVsDebug.js'; @@ -1581,8 +1581,29 @@ index 4f782d45..0759cfca 100644 const d = document.createElement('div'); d.innerHTML = '

' + name + '

'; +diff --git a/examples-testing/examples/physics_ammo_instancing.ts b/examples-testing/examples/physics_ammo_instancing.ts +index eb33424..aed0936 100644 +--- a/examples-testing/examples/physics_ammo_instancing.ts ++++ b/examples-testing/examples/physics_ammo_instancing.ts +@@ -1,12 +1,12 @@ + import * as THREE from 'three'; + import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +-import { AmmoPhysics } from 'three/addons/physics/AmmoPhysics.js'; ++import { AmmoPhysics, AmmoPhysicsObject } from 'three/addons/physics/AmmoPhysics.js'; + import Stats from 'three/addons/libs/stats.module.js'; + +-let camera, scene, renderer, stats; +-let physics, position; ++let camera: THREE.PerspectiveCamera, scene: THREE.Scene, renderer: THREE.WebGLRenderer, stats: Stats; ++let physics: AmmoPhysicsObject, position: THREE.Vector3; + +-let boxes, spheres; ++let boxes: THREE.InstancedMesh, spheres: THREE.InstancedMesh; + + init(); + diff --git a/examples-testing/examples/physics_rapier_instancing.ts b/examples-testing/examples/physics_rapier_instancing.ts -index 8f1bdda2..67d3517f 100644 +index 8f1bdda..67d3517 100644 --- a/examples-testing/examples/physics_rapier_instancing.ts +++ b/examples-testing/examples/physics_rapier_instancing.ts @@ -1,12 +1,12 @@ @@ -1603,7 +1624,7 @@ index 8f1bdda2..67d3517f 100644 init(); diff --git a/examples-testing/examples/svg_lines.ts b/examples-testing/examples/svg_lines.ts -index 99b74c40..65aaf28d 100644 +index 99b74c4..65aaf28 100644 --- a/examples-testing/examples/svg_lines.ts +++ b/examples-testing/examples/svg_lines.ts @@ -4,7 +4,7 @@ import { SVGRenderer } from 'three/addons/renderers/SVGRenderer.js'; @@ -1616,7 +1637,7 @@ index 99b74c40..65aaf28d 100644 init(); animate(); diff --git a/examples-testing/examples/svg_sandbox.ts b/examples-testing/examples/svg_sandbox.ts -index e6be8386..faea9a7a 100644 +index e6be838..faea9a7 100644 --- a/examples-testing/examples/svg_sandbox.ts +++ b/examples-testing/examples/svg_sandbox.ts @@ -6,9 +6,9 @@ import { SVGRenderer, SVGObject } from 'three/addons/renderers/SVGRenderer.js'; @@ -1701,7 +1722,7 @@ index e6be8386..faea9a7a 100644 node.appendChild(doc.documentElement); diff --git a/examples-testing/examples/webaudio_orientation.ts b/examples-testing/examples/webaudio_orientation.ts -index 8a74c418..7258ed10 100644 +index 8a74c41..7258ed1 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'; diff --git a/examples-testing/examples/css2d_label.ts b/examples-testing/examples/css2d_label.ts deleted file mode 100644 index cf61d1e0b..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, 1); - 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 49dd6f395..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, 0.5); -fillLight1.position.set(2, 1, 1); -scene.add(fillLight1); - -const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); -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 a78c71b31..000000000 --- a/examples-testing/examples/misc_boxselection.ts +++ /dev/null @@ -1,143 +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, 1, 5000); - camera.position.z = 1000; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xf0f0f0); - - scene.add(new THREE.AmbientLight(0x505050)); - - const light = new THREE.SpotLight(0xffffff, 1.5); - light.position.set(0, 500, 2000); - light.angle = Math.PI / 9; - - light.castShadow = true; - light.shadow.camera.near = 1000; - light.shadow.camera.far = 4000; - light.shadow.mapSize.width = 1024; - light.shadow.mapSize.height = 1024; - - scene.add(light); - - const geometry = new THREE.BoxGeometry(20, 20, 20); - - 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() * 1600 - 800; - object.position.y = Math.random() * 900 - 450; - object.position.z = Math.random() * 900 - 500; - - 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 f7ea233de..000000000 --- a/examples-testing/examples/misc_controls_arcball.ts +++ /dev/null @@ -1,212 +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(); - scene.add(new THREE.HemisphereLight(0x443333, 0x222233, 4)); - - 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 da4bd2431..000000000 --- a/examples-testing/examples/misc_controls_drag.ts +++ /dev/null @@ -1,149 +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, 1, 5000); - camera.position.z = 1000; - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xf0f0f0); - - scene.add(new THREE.AmbientLight(0x505050)); - - const light = new THREE.SpotLight(0xffffff, 1.5); - light.position.set(0, 500, 2000); - light.angle = Math.PI / 9; - - light.castShadow = true; - light.shadow.camera.near = 1000; - light.shadow.camera.far = 4000; - 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(40, 40, 40); - - 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() * 1000 - 500; - object.position.y = Math.random() * 600 - 300; - object.position.z = Math.random() * 800 - 400; - - 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 2dd77ec7f..000000000 --- a/examples-testing/examples/misc_controls_fly.ts +++ /dev/null @@ -1,228 +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 { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; -import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.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); - 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 gammaCorrection = new ShaderPass(GammaCorrectionShader); - - composer = new EffectComposer(renderer); - - composer.addPass(renderModel); - composer.addPass(effectFilm); - composer.addPass(gammaCorrection); -} - -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 35e03d2cf..000000000 --- a/examples-testing/examples/misc_controls_map.ts +++ /dev/null @@ -1,99 +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(400, 200, 0); - - // 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(1, 1, 1); - 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); - dirLight1.position.set(1, 1, 1); - scene.add(dirLight1); - - const dirLight2 = new THREE.DirectionalLight(0x002288); - dirLight2.position.set(-1, -1, -1); - scene.add(dirLight2); - - const ambientLight = new THREE.AmbientLight(0x222222); - scene.add(ambientLight); - - // - - window.addEventListener('resize', onWindowResize); - - const gui = new GUI(); - 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 28bc3c01e..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.CylinderGeometry(0, 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); - dirLight1.position.set(1, 1, 1); - scene.add(dirLight1); - - const dirLight2 = new THREE.DirectionalLight(0x002288); - dirLight2.position.set(-1, -1, -1); - scene.add(dirLight2); - - const ambientLight = new THREE.AmbientLight(0x222222); - 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 d29ffaff6..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, 0.75); - 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 19c42c6a7..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.CylinderGeometry(0, 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); - dirLight1.position.set(1, 1, 1); - scene.add(dirLight1); - - const dirLight2 = new THREE.DirectionalLight(0x002288); - dirLight2.position.set(-1, -1, -1); - scene.add(dirLight2); - - const ambientLight = new THREE.AmbientLight(0x222222); - 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 aa4de6f31..000000000 --- a/examples-testing/examples/misc_controls_transform.ts +++ /dev/null @@ -1,170 +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(); - 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(1000, 500, 1000); - currentCamera.lookAt(0, 200, 0); - - scene = new THREE.Scene(); - scene.add(new THREE.GridHelper(1000, 10, 0x888888, 0x444444)); - - const light = new THREE.DirectionalLight(0xffffff, 2); - 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(200, 200, 200); - const material = new THREE.MeshLambertMaterial({ map: texture, transparent: true }); - - 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 ce1e69673..000000000 --- a/examples-testing/examples/misc_exporter_draco.ts +++ /dev/null @@ -1,120 +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, 1, 1000); - camera.position.set(200, 100, 200); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xa0a0a0); - scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000); - - exporter = new DRACOExporter(); - - // - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444); - hemiLight.position.set(0, 200, 0); - scene.add(hemiLight); - - const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); - directionalLight.position.set(0, 200, 100); - directionalLight.castShadow = true; - directionalLight.shadow.camera.top = 180; - directionalLight.shadow.camera.bottom = -100; - directionalLight.shadow.camera.left = -120; - directionalLight.shadow.camera.right = 120; - scene.add(directionalLight); - - // ground - - const ground = new THREE.Mesh( - new THREE.PlaneGeometry(2000, 2000), - new THREE.MeshPhongMaterial({ color: 0xbbbbbb, depthWrite: false }), - ); - ground.rotation.x = -Math.PI / 2; - ground.position.y = -75; - ground.receiveShadow = true; - scene.add(ground); - - const grid = new THREE.GridHelper(2000, 20, 0x000000, 0x000000); - grid.material.opacity = 0.2; - grid.material.transparent = true; - grid.position.y = -75; - scene.add(grid); - - // export mesh - - const geometry = new THREE.TorusKnotGeometry(50, 15, 200, 30); - const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 }); - mesh = new THREE.Mesh(geometry, material); - mesh.castShadow = true; - mesh.position.y = 25; - 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, 25, 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 c9d943330..000000000 --- a/examples-testing/examples/misc_exporter_gltf.ts +++ /dev/null @@ -1,492 +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(0xffffff, 0.2); - ambientLight.name = 'AmbientLight'; - scene1.add(ambientLight); - - // --------------------------------------------------------------------- - // DirectLight - // --------------------------------------------------------------------- - const dirLight = new THREE.DirectionalLight(0xffffff, 1); - 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; - 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 02ad9072b..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(0xcccccc, 0.4); - scene.add(ambientLight); - - const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); - 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 b6a334ddc..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, 1, 1000); - camera.position.set(200, 100, 200); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xa0a0a0); - scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000); - - exporter = new PLYExporter(); - - // - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x8d8d8d); - hemiLight.position.set(0, 200, 0); - scene.add(hemiLight); - - const directionalLight = new THREE.DirectionalLight(0xffffff); - directionalLight.position.set(0, 200, 100); - directionalLight.castShadow = true; - directionalLight.shadow.camera.top = 180; - directionalLight.shadow.camera.bottom = -100; - directionalLight.shadow.camera.left = -120; - directionalLight.shadow.camera.right = 120; - scene.add(directionalLight); - - // ground - - const ground = new THREE.Mesh( - new THREE.PlaneGeometry(2000, 2000), - new THREE.MeshPhongMaterial({ color: 0xcbcbcb, depthWrite: false }), - ); - ground.rotation.x = -Math.PI / 2; - ground.receiveShadow = true; - scene.add(ground); - - const grid = new THREE.GridHelper(2000, 20, 0x000000, 0x000000); - grid.material.opacity = 0.2; - grid.material.transparent = true; - scene.add(grid); - - // export mesh - - const geometry = new THREE.BoxGeometry(50, 50, 50); - 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 = 25; - 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, 25, 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 673bad138..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, 1, 1000); - camera.position.set(200, 100, 200); - - scene = new THREE.Scene(); - scene.background = new THREE.Color(0xa0a0a0); - scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000); - - exporter = new STLExporter(); - - // - - const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444); - hemiLight.position.set(0, 200, 0); - scene.add(hemiLight); - - const directionalLight = new THREE.DirectionalLight(0xffffff); - directionalLight.position.set(0, 200, 100); - directionalLight.castShadow = true; - directionalLight.shadow.camera.top = 180; - directionalLight.shadow.camera.bottom = -100; - directionalLight.shadow.camera.left = -120; - directionalLight.shadow.camera.right = 120; - scene.add(directionalLight); - - // ground - - const ground = new THREE.Mesh( - new THREE.PlaneGeometry(2000, 2000), - new THREE.MeshPhongMaterial({ color: 0xbbbbbb, depthWrite: false }), - ); - ground.rotation.x = -Math.PI / 2; - ground.receiveShadow = true; - scene.add(ground); - - const grid = new THREE.GridHelper(2000, 20, 0x000000, 0x000000); - grid.material.opacity = 0.2; - grid.material.transparent = true; - scene.add(grid); - - // export mesh - - const geometry = new THREE.BoxGeometry(50, 50, 50); - const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 }); - - mesh = new THREE.Mesh(geometry, material); - mesh.castShadow = true; - mesh.position.y = 25; - 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, 25, 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 9117411b5..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(), 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 eb33424b3..000000000 --- a/examples-testing/examples/physics_ammo_instancing.ts +++ /dev/null @@ -1,123 +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(); - hemiLight.intensity = 0.3; - scene.add(hemiLight); - - const dirLight = new THREE.DirectionalLight(); - 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 8f1bdda24..000000000 --- a/examples-testing/examples/physics_rapier_instancing.ts +++ /dev/null @@ -1,123 +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(); - hemiLight.intensity = 0.3; - scene.add(hemiLight); - - const dirLight = new THREE.DirectionalLight(); - 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 8a74c4187..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); - hemiLight.position.set(0, 20, 0); - scene.add(hemiLight); - - const dirLight = new THREE.DirectionalLight(0xffffff); - 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.setSize(window.innerWidth, window.innerHeight); - renderer.setPixelRatio(window.devicePixelRatio); - 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); -}