From 260c4df6414e9699a1c0f251475a818385d7fd97 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Tue, 4 Jul 2023 15:04:21 -0400 Subject: [PATCH] Add misc_exporter_usdz example (#523) * Add example * Update patch --- examples-testing/changes.patch | 31 +++++ .../examples/misc_exporter_usdz.ts | 110 ++++++++++++++++++ examples-testing/index.js | 2 +- 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 examples-testing/examples/misc_exporter_usdz.ts diff --git a/examples-testing/changes.patch b/examples-testing/changes.patch index 86e391b9e..bc1f3e4a5 100644 --- a/examples-testing/changes.patch +++ b/examples-testing/changes.patch @@ -1421,6 +1421,37 @@ index 673bad13..71e65414 100644 +function saveArrayBuffer(buffer: BufferSource, filename: string) { 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 +--- 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'; + import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; + import { USDZExporter } from 'three/addons/exporters/USDZExporter.js'; + +-let camera, scene, renderer; ++let camera: THREE.PerspectiveCamera, scene: THREE.Scene, renderer: THREE.WebGLRenderer; + + init(); + render(); +@@ -45,7 +45,7 @@ function init() { + const arraybuffer = await exporter.parse(gltf.scene); + const blob = new Blob([arraybuffer], { type: 'application/octet-stream' }); + +- const link = document.getElementById('link'); ++ const link = document.getElementById('link') as HTMLAnchorElement; + link.href = URL.createObjectURL(blob); + }); + +@@ -64,7 +64,7 @@ function createSpotShadowMesh() { + canvas.width = 128; + canvas.height = 128; + +- const context = canvas.getContext('2d'); ++ const context = canvas.getContext('2d')!; + const gradient = context.createRadialGradient( + 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 --- a/examples-testing/examples/misc_lookat.ts 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/index.js b/examples-testing/index.js index 2b155930f..501a029ad 100644 --- a/examples-testing/index.js +++ b/examples-testing/index.js @@ -395,7 +395,7 @@ const files = { 'misc_exporter_obj', // 'misc_exporter_ply', 'misc_exporter_stl', - // 'misc_exporter_usdz', + 'misc_exporter_usdz', 'misc_lookat', ], css2d: ['css2d_label'],