diff --git a/examples/src/examples/compute/indirect-dispatch.example.mjs b/examples/src/examples/compute/indirect-dispatch.example.mjs index 5269798a036..059bb088c8b 100644 --- a/examples/src/examples/compute/indirect-dispatch.example.mjs +++ b/examples/src/examples/compute/indirect-dispatch.example.mjs @@ -62,9 +62,11 @@ import { UNIFORMTYPE_VEC3, UniformBufferFormat, UniformFormat, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -76,8 +78,7 @@ window.focus(); const assets = { statue: new Asset('statue', 'container', { url: './assets/models/statue.glb' }), - hdri: new Asset('hdri', 'texture', { url: './assets/hdri/wide-street.hdr' }, { mipmaps: false }), - orbit: new Asset('orbit', 'script', { url: './scripts/camera/orbit-camera.js' }) + hdri: new Asset('hdri', 'texture', { url: './assets/hdri/wide-street.hdr' }, { mipmaps: false }) }; const gfxOptions = { @@ -285,20 +286,16 @@ rtCamera.addComponent('camera', { // Add orbit camera script rtCamera.addComponent('script'); -rtCamera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: statueEntity, - distanceMax: 500, - frameOnStart: false - } -}); -rtCamera.script.create('orbitCameraInputMouse'); -rtCamera.script.create('orbitCameraInputTouch'); - rtCamera.setLocalPosition(-4, 5, 22); rtCamera.lookAt(0, 0, 1); app.root.addChild(rtCamera); +rtCamera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 1), + enableFly: false, + zoomRange: new Vec2(0.01, 500) + } +}); // Create main camera (for final view - only immediate layer for drawTexture) const immediateLayer = app.scene.layers.getLayerByName('Immediate'); diff --git a/examples/src/examples/compute/particles.example.mjs b/examples/src/examples/compute/particles.example.mjs index 8c224c8ace9..acaf07ed994 100644 --- a/examples/src/examples/compute/particles.example.mjs +++ b/examples/src/examples/compute/particles.example.mjs @@ -28,9 +28,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -43,7 +45,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -99,17 +100,16 @@ cameraEntity.addComponent('camera', { app.root.addChild(cameraEntity); cameraEntity.setPosition(-150, -60, 190); -// Add orbit camera script with a mouse and a touch support +// Add camera controls with a mouse and a touch support cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - frameOnStart: false, - distanceMax: 500 - } -}); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); +const cameraControls = /** @type {CameraControls} */ ( + cameraEntity.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(0.01, 500), + enableFly: false + } + }) +); // ------- Particle simulation ------- @@ -210,7 +210,7 @@ const s1 = addSphere(1, -38, -130, 0, 35); addSphere(2, 45, -210, 35, 70); // Camera focuses on one of the spheres -cameraEntity.script.orbitCamera.focusEntity = s1; +cameraControls.focusPoint = s1.getPosition(); // Upload the sphere data to the buffer const sphereStorageBuffer = new StorageBuffer(device, numSpheres * 16, BUFFERUSAGE_COPY_DST); diff --git a/examples/src/examples/compute/vertex-update.example.mjs b/examples/src/examples/compute/vertex-update.example.mjs index 5525f708f79..61de99b8e18 100644 --- a/examples/src/examples/compute/vertex-update.example.mjs +++ b/examples/src/examples/compute/vertex-update.example.mjs @@ -38,8 +38,10 @@ import { UNIFORMTYPE_UINT, UniformBufferFormat, UniformFormat, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -52,7 +54,6 @@ const assets = { color: new Asset('color', 'texture', { url: './assets/textures/seaside-rocks01-color.jpg' }, { srgb: true }), normal: new Asset('normal', 'texture', { url: './assets/textures/seaside-rocks01-normal.jpg' }), gloss: new Asset('gloss', 'texture', { url: './assets/textures/seaside-rocks01-gloss.jpg' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -143,15 +144,13 @@ cameraEntity.translate(0, 0, 5); // Add orbit camera script with a mouse and a touch support cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: entity +app.root.addChild(cameraEntity); +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false } }); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); -app.root.addChild(cameraEntity); // a compute shader that will modify the vertex buffer of the mesh every frame const shader = device.supportsCompute diff --git a/examples/src/examples/gaussian-splatting-legacy/picking.example.mjs b/examples/src/examples/gaussian-splatting-legacy/picking.example.mjs index 5eb28973545..43aec5d38ec 100644 --- a/examples/src/examples/gaussian-splatting-legacy/picking.example.mjs +++ b/examples/src/examples/gaussian-splatting-legacy/picking.example.mjs @@ -33,9 +33,11 @@ import { TONEMAP_NEUTRAL, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -81,7 +83,6 @@ app.on('destroy', () => { const assets = { logo: new Asset('gsplat', 'gsplat', { url: './assets/splats/playcanvas-logo/meta.json' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -128,21 +129,20 @@ camera.addComponent('camera', { }); camera.setLocalPosition(-2, -0.5, 2); -// Add orbit camera script with a mouse and a touch support +// Add camera controls with a mouse and a touch support camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMin: 14, - distanceMax: 50 - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(14, 50), + enableFly: false + } + }) +); // Set camera position looking at origin -camera.script.orbitCamera.resetAndLookAtPoint(new Vec3(10, 4, 10), Vec3.ZERO); +cameraControls.reset(Vec3.ZERO, new Vec3(10, 4, 10)); // Custom render passes set up with bloom const cameraFrame = new CameraFrame(app, camera.camera); diff --git a/examples/src/examples/gaussian-splatting/crop.example.mjs b/examples/src/examples/gaussian-splatting/crop.example.mjs index 3304131a7c8..5603ab5ff37 100644 --- a/examples/src/examples/gaussian-splatting/crop.example.mjs +++ b/examples/src/examples/gaussian-splatting/crop.example.mjs @@ -25,8 +25,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { GSplatCropShaderEffect } from 'playcanvas/scripts/esm/gsplat/shader-effect-crop.mjs'; import { data, deviceType } from 'examples/context'; @@ -73,8 +76,7 @@ app.on('destroy', () => { }); const assets = { - hotel: new Asset('gsplat', 'gsplat', { url: './assets/splats/hotel-culpture.compressed.ply' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + hotel: new Asset('gsplat', 'gsplat', { url: './assets/splats/hotel-culpture.compressed.ply' }) }; await new Promise((resolve) => { @@ -171,19 +173,19 @@ camera.addComponent('camera', { }); camera.setLocalPosition(3, 1, 0.5); -// Add orbit camera script with a mouse and a touch support +// Add camera controls with a mouse and a touch support camera.addComponent('script'); -camera.script?.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: hotel, - distanceMax: 2, - frameOnStart: false - } -}); -camera.script?.create('orbitCameraInputMouse'); -camera.script?.create('orbitCameraInputTouch'); app.root.addChild(camera); +const orbitPivot = hotel.getPosition().clone(); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: orbitPivot, + zoomRange: new Vec2(0.01, 2), + enableFly: false + } + }) +); // Setup bloom post-processing if (camera.camera) { @@ -239,12 +241,21 @@ app.on('update', (dt) => { autoRotateEnabled = true; } - // Apply auto-rotation + // Apply auto-rotation by advancing the camera's azimuth around the pivot if (autoRotateEnabled) { - const orbitCamera = camera.script?.get('orbitCamera'); - if (orbitCamera) { - orbitCamera.yaw += autoRotateSpeed * dt; - } + const offset = camera.getPosition().clone().sub(orbitPivot); + const r = offset.length(); + const pitch = Math.asin(Math.max(-1, Math.min(1, offset.y / r))); + const yaw = Math.atan2(offset.x, offset.z) + (autoRotateSpeed * dt * Math.PI) / 180; + const cp = Math.cos(pitch); + cameraControls.reset( + orbitPivot, + new Vec3( + orbitPivot.x + r * Math.sin(yaw) * cp, + orbitPivot.y + r * Math.sin(pitch), + orbitPivot.z + r * Math.cos(yaw) * cp + ) + ); } // Animate AABB with soft bounce (sin-based easing) diff --git a/examples/src/examples/gaussian-splatting/editor.example.mjs b/examples/src/examples/gaussian-splatting/editor.example.mjs index 93c7a874a85..e8cf216061e 100644 --- a/examples/src/examples/gaussian-splatting/editor.example.mjs +++ b/examples/src/examples/gaussian-splatting/editor.example.mjs @@ -49,6 +49,7 @@ import { WORKBUFFER_UPDATE_ONCE, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -102,7 +103,6 @@ app.on('destroy', () => { data.set('boxSize', 0.67); const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), biker: new Asset('biker', 'gsplat', { url: './assets/splats/biker.compressed.ply' }), apartment: new Asset('apartment', 'gsplat', { url: './assets/splats/apartment.sog' }) }; @@ -537,23 +537,23 @@ gizmoLayer = Gizmo.createLayer(app); gizmo = new TranslateGizmo(camera.camera, gizmoLayer); camera.addComponent('script'); -const orbitCamera = camera.script.create('orbitCamera', { - attributes: { - frameOnStart: false, - inertiaFactor: 0.07 - } -}); -const orbitInput = camera.script.create('orbitCameraInputMouse'); -orbitCamera.resetAndLookAtPoint(cameraPos, focusPos); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + enableFly: false + } + }) +); +cameraControls.reset(focusPos, cameraPos); // Gizmo interaction - disable camera when using gizmo gizmo.on('pointer:down', (_x, _y, meshInstance) => { if (meshInstance) { - orbitInput.enabled = false; + cameraControls.enabled = false; } }); gizmo.on('pointer:up', () => { - orbitInput.enabled = true; + cameraControls.enabled = true; }); app.mouse.disableContextMenu(); diff --git a/examples/src/examples/gaussian-splatting/flipbook.example.mjs b/examples/src/examples/gaussian-splatting/flipbook.example.mjs index 5cbb6161346..d7a6b612b42 100644 --- a/examples/src/examples/gaussian-splatting/flipbook.example.mjs +++ b/examples/src/examples/gaussian-splatting/flipbook.example.mjs @@ -40,9 +40,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { GSplatFlipbook } from 'playcanvas/scripts/esm/gsplat/gsplat-flipbook.mjs'; import { ShadowCatcher } from 'playcanvas/scripts/esm/shadow-catcher.mjs'; @@ -99,8 +101,7 @@ const assets = { { url: './assets/cubemaps/helipad-env-atlas.png' }, { type: TEXTURETYPE_RGBP, mipmaps: false } ), - apartment: new Asset('apartment', 'container', { url: './assets/models/apartment.glb' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + apartment: new Asset('apartment', 'container', { url: './assets/models/apartment.glb' }) }; await new Promise((resolve) => { @@ -131,24 +132,19 @@ camera.addComponent('camera', { fov: 80 }); -const focusPoint = new Entity(); -focusPoint.setLocalPosition(-80, 80, -20); +camera.setLocalPosition(-50, 100, 220); +camera.lookAt(0, 0, 100); -// Add orbit camera script with a mouse and a touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: focusPoint, - distanceMax: 500, - frameOnStart: false +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 100), + enableFly: false, + zoomRange: new Vec2(0.01, 500) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -camera.setLocalPosition(-50, 100, 220); -camera.lookAt(0, 0, 100); -app.root.addChild(camera); // Create player flipbook const player = new Entity('Player'); diff --git a/examples/src/examples/gaussian-splatting/glass-refraction.example.mjs b/examples/src/examples/gaussian-splatting/glass-refraction.example.mjs index 0f3fc299637..6bb1e95e0f2 100644 --- a/examples/src/examples/gaussian-splatting/glass-refraction.example.mjs +++ b/examples/src/examples/gaussian-splatting/glass-refraction.example.mjs @@ -53,9 +53,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -102,7 +104,6 @@ app.on('destroy', () => { const assets = { hall: new Asset('gsplat', 'gsplat', { url: './assets/splats/knock-community-hall.sog' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), // HDRI environment referenced directly from Poly Haven (no local copy needed) hdri: new Asset( 'hdri', @@ -481,20 +482,19 @@ camera.addComponent('camera', { // positioned slightly above the shape so the top face is visible camera.setLocalPosition(0.8, 1.35, 2.9); -// add orbit camera script with a mouse and a touch support +// add camera controls with a mouse and a touch support camera.addComponent('script'); -camera.script?.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: glass, - distanceMin: 1.2, - distanceMax: 8, - frameOnStart: false - } -}); -camera.script?.create('orbitCameraInputMouse'); -camera.script?.create('orbitCameraInputTouch'); app.root.addChild(camera); +const orbitPivot = glass.getPosition().clone(); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: orbitPivot, + zoomRange: new Vec2(1.2, 8), + enableFly: false + } + }) +); // Camera frame with the scene color map enabled for dynamic refraction. The grab boundary is // moved past the splat layer, so the grabbed scene color includes the splat. @@ -544,11 +544,20 @@ app.on('update', (dt) => { autoRotateEnabled = true; } - // Apply auto-rotation + // Apply auto-rotation by advancing the camera's azimuth around the pivot if (autoRotateEnabled) { - const orbitCamera = camera.script?.get('orbitCamera'); - if (orbitCamera) { - orbitCamera.yaw += autoRotateSpeed * dt; - } + const offset = camera.getPosition().clone().sub(orbitPivot); + const r = offset.length(); + const pitch = Math.asin(Math.max(-1, Math.min(1, offset.y / r))); + const yaw = Math.atan2(offset.x, offset.z) + (autoRotateSpeed * dt * Math.PI) / 180; + const cp = Math.cos(pitch); + cameraControls.reset( + orbitPivot, + new Vec3( + orbitPivot.x + r * Math.sin(yaw) * cp, + orbitPivot.y + r * Math.sin(pitch), + orbitPivot.z + r * Math.cos(yaw) * cp + ) + ); } }); diff --git a/examples/src/examples/gaussian-splatting/global-sorting.example.mjs b/examples/src/examples/gaussian-splatting/global-sorting.example.mjs index bec52c60192..aac7c48c167 100644 --- a/examples/src/examples/gaussian-splatting/global-sorting.example.mjs +++ b/examples/src/examples/gaussian-splatting/global-sorting.example.mjs @@ -25,9 +25,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -75,8 +77,7 @@ app.on('destroy', () => { const assets = { hotel: new Asset('gsplat', 'gsplat', { url: './assets/splats/hotel-culpture.compressed.ply' }), biker: new Asset('gsplat', 'gsplat', { url: './assets/splats/biker.compressed.ply' }), - guitar: new Asset('gsplat', 'gsplat', { url: './assets/splats/guitar.compressed.ply' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + guitar: new Asset('gsplat', 'gsplat', { url: './assets/splats/guitar.compressed.ply' }) }; await new Promise((resolve) => { @@ -137,20 +138,19 @@ camera.addComponent('camera', { }); camera.setLocalPosition(3, 1, 0.5); -// Add orbit camera script with a mouse and a touch support +// Add camera controls with mouse and touch support camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 3.2, - frameOnStart: false - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(0.01, 3.2), + enableFly: false + } + }) +); // Orbit around the statue's world-space centre const orbitPivot = new Vec3(); hotel.getWorldTransform().transformPoint(new Vec3(0, 0.2, 0), orbitPivot); -camera.script.orbitCamera.resetAndLookAtPoint(new Vec3(3, 1, 0.5), orbitPivot); +cameraControls.reset(orbitPivot, new Vec3(3, 1, 0.5)); diff --git a/examples/src/examples/gaussian-splatting/multi-splat.example.mjs b/examples/src/examples/gaussian-splatting/multi-splat.example.mjs index cdd4577b5a4..b02206d54ff 100644 --- a/examples/src/examples/gaussian-splatting/multi-splat.example.mjs +++ b/examples/src/examples/gaussian-splatting/multi-splat.example.mjs @@ -30,9 +30,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -83,8 +85,7 @@ const assets = { gallery: new Asset('gallery', 'container', { url: './assets/models/vr-gallery.glb' }), guitar: new Asset('gsplat', 'gsplat', { url: './assets/splats/guitar.compressed.ply' }), biker: new Asset('gsplat', 'gsplat', { url: './assets/splats/biker.compressed.ply' }), - skull: new Asset('gsplat', 'gsplat', { url: './assets/splats/skull.sog' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + skull: new Asset('gsplat', 'gsplat', { url: './assets/splats/skull.sog' }) }; await new Promise((resolve) => { @@ -149,22 +150,26 @@ skull.rotate(0, 150, 0); app.root.addChild(camera); camera.addComponent('script'); -const orbitCam = /** @type {any} */ ( - camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 60, - frameOnStart: false +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(0.01, 60), + enableFly: false } }) ); -if (orbitCam) { - orbitCam.pivotPoint.copy(ORBIT_PIVOT); - orbitCam.reset(ORBIT_INITIAL_YAW, ORBIT_INITIAL_PITCH, ORBIT_DISTANCE); - orbitCam._updatePosition(); -} -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); + +// place the camera on an orbit around the pivot (yaw/pitch in degrees, at ORBIT_DISTANCE) +const orbitYaw = (ORBIT_INITIAL_YAW * Math.PI) / 180; +const orbitPitch = (ORBIT_INITIAL_PITCH * Math.PI) / 180; +cameraControls.reset( + ORBIT_PIVOT, + new Vec3( + ORBIT_PIVOT.x + ORBIT_DISTANCE * Math.sin(orbitYaw) * Math.cos(orbitPitch), + ORBIT_PIVOT.y - ORBIT_DISTANCE * Math.sin(orbitPitch), + ORBIT_PIVOT.z + ORBIT_DISTANCE * Math.cos(orbitYaw) * Math.cos(orbitPitch) + ) +); const glslVs = shaderGlslVert; const wgslVs = shaderWgslVert; diff --git a/examples/src/examples/gaussian-splatting/multi-view.example.mjs b/examples/src/examples/gaussian-splatting/multi-view.example.mjs index 8d7ceb38f3d..0aa507a05c0 100644 --- a/examples/src/examples/gaussian-splatting/multi-view.example.mjs +++ b/examples/src/examples/gaussian-splatting/multi-view.example.mjs @@ -27,10 +27,12 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, Vec4, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -77,7 +79,6 @@ app.on('destroy', () => { const assets = { logo: new Asset('gsplat', 'gsplat', { url: './assets/splats/playcanvas-logo/meta.json' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -161,19 +162,16 @@ cameraTop.addComponent('camera', { cameraTop.translate(-2, 6, 9); app.root.addChild(cameraTop); -// Add orbit camera script with a mouse and a touch support to top camera +// Add camera controls to top camera cameraTop.addComponent('script'); if (cameraTop.script) { - cameraTop.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: logoEntity2, - distanceMax: 60, - frameOnStart: false + cameraTop.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, -0.5, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 60) } }); - cameraTop.script.create('orbitCameraInputMouse'); - cameraTop.script.create('orbitCameraInputTouch'); } // Update function called once per frame diff --git a/examples/src/examples/gaussian-splatting/paint.example.mjs b/examples/src/examples/gaussian-splatting/paint.example.mjs index 069df57b02e..492f675e115 100644 --- a/examples/src/examples/gaussian-splatting/paint.example.mjs +++ b/examples/src/examples/gaussian-splatting/paint.example.mjs @@ -46,6 +46,7 @@ import { WORKBUFFER_UPDATE_ONCE, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -179,7 +180,6 @@ data.set('paintIntensity', 0.5); data.set('brushSize', 0.15); const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), biker: new Asset('biker', 'gsplat', { url: './assets/splats/biker.compressed.ply' }), apartment: new Asset('apartment', 'gsplat', { url: './assets/splats/apartment.sog' }) }; @@ -268,18 +268,18 @@ camera.setLocalPosition(cameraPos); camera.lookAt(focusPos); app.root.addChild(camera); -// Add orbit camera script with native mouse input (LMB orbit, MMB pan, wheel zoom) +// Add camera controls with native mouse input (LMB orbit, MMB pan, wheel zoom) camera.addComponent('script'); -const orbitCamera = camera.script.create('orbitCamera', { - attributes: { - frameOnStart: false, - inertiaFactor: 0.07 - } -}); -const orbitInput = camera.script.create('orbitCameraInputMouse'); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + enableFly: false + } + }) +); -// Initialize orbit camera to match current camera position and focus -orbitCamera.resetAndLookAtPoint(cameraPos, focusPos); +// Initialize camera controls to match current camera position and focus +cameraControls.reset(focusPos, cameraPos); // Paint state let isPainting = false; @@ -370,8 +370,7 @@ app.mouse.on(EVENT_MOUSEDOWN, (e) => { if (e.button === MOUSEBUTTON_RIGHT) { isPainting = true; pickerDirty = true; - orbitInput.enabled = false; - orbitInput.panButtonDown = false; // Cancel pan that orbit-camera started + cameraControls.enabled = false; paintAt(e.x, e.y); } }); @@ -383,13 +382,13 @@ app.mouse.on(EVENT_MOUSEMOVE, (e) => { app.mouse.on(EVENT_MOUSEUP, (e) => { if (e.button === MOUSEBUTTON_RIGHT) { isPainting = false; - orbitInput.enabled = true; + cameraControls.enabled = true; } }); window.addEventListener('mouseup', () => { isPainting = false; - orbitInput.enabled = true; + cameraControls.enabled = true; }); // Cleanup on destroy diff --git a/examples/src/examples/gaussian-splatting/picking.example.mjs b/examples/src/examples/gaussian-splatting/picking.example.mjs index af58c247efd..a5ae6739f7b 100644 --- a/examples/src/examples/gaussian-splatting/picking.example.mjs +++ b/examples/src/examples/gaussian-splatting/picking.example.mjs @@ -33,9 +33,11 @@ import { TONEMAP_NEUTRAL, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -81,7 +83,6 @@ app.on('destroy', () => { const assets = { logo: new Asset('gsplat', 'gsplat', { url: './assets/splats/playcanvas-logo/meta.json' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -146,21 +147,20 @@ data.on('orthoCamera:set', (/** @type {boolean} */ value) => { camera.camera.orthoHeight = 6; }); -// Add orbit camera script with a mouse and a touch support +// Add camera controls with a mouse and a touch support camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMin: 14, - distanceMax: 50 - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(14, 50), + enableFly: false + } + }) +); // Set camera position looking at origin -camera.script.orbitCamera.resetAndLookAtPoint(new Vec3(10, 4, 10), Vec3.ZERO); +cameraControls.reset(Vec3.ZERO, new Vec3(10, 4, 10)); // Custom render passes set up with bloom const cameraFrame = new CameraFrame(app, camera.camera); diff --git a/examples/src/examples/gaussian-splatting/procedural-mesh.example.mjs b/examples/src/examples/gaussian-splatting/procedural-mesh.example.mjs index 19295d2ed67..2c3e874d697 100644 --- a/examples/src/examples/gaussian-splatting/procedural-mesh.example.mjs +++ b/examples/src/examples/gaussian-splatting/procedural-mesh.example.mjs @@ -32,8 +32,11 @@ import { TEXTURETYPE_RGBP, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { GSplatMesh } from 'playcanvas/scripts/esm/gsplat/gsplat-mesh.mjs'; import { GSplatBoxShaderEffect } from 'playcanvas/scripts/esm/gsplat/shader-effect-box.mjs'; @@ -43,7 +46,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), terrain: new Asset('terrain', 'container', { url: './assets/models/terrain.glb' }), helipad: new Asset( 'helipad-env-atlas', @@ -217,9 +219,7 @@ srcClouds.forEach((srcCloud, srcIndex) => { // Shuffle the clouds array for random order (same as shadow-cascades) clouds.sort(() => Math.random() - 0.5); -// Find a tree to use as focus point (same as shadow-cascades) // @ts-ignore -const tree = terrain.findOne('name', 'Arbol 2.002'); // Create camera with orbit controls (same setup as shadow-cascades) const camera = new Entity('Camera'); @@ -233,16 +233,16 @@ camera.setLocalPosition(-500, 160, 300); // Add orbit camera script with mouse and touch support camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: tree, - distanceMax: 600 - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(-4.473, 37.152, 27.631), + zoomRange: new Vec2(0.01, 600), + enableFly: false + } + }) +); // Animate clouds (same as shadow-cascades) const cloudSpeed = 0.2; @@ -254,8 +254,8 @@ app.on('update', (/** @type {number} */ dt) => { // On the first frame, move camera further away if (frameNumber === 0) { - // @ts-ignore - camera.script.orbitCamera.distance = 470; + // match the original orbit-camera framing of the focus tree + cameraControls.reset(new Vec3(-4.473, 37.152, 27.631), new Vec3(-401.718, 135.635, 245.979)); } // Disable reveal effect when complete diff --git a/examples/src/examples/gaussian-splatting/reveal.example.mjs b/examples/src/examples/gaussian-splatting/reveal.example.mjs index 01cdb810205..fc528a568c2 100644 --- a/examples/src/examples/gaussian-splatting/reveal.example.mjs +++ b/examples/src/examples/gaussian-splatting/reveal.example.mjs @@ -24,8 +24,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { GSplatRevealGridEruption } from 'playcanvas/scripts/esm/gsplat/reveal-grid-eruption.mjs'; import { GSplatRevealRadial } from 'playcanvas/scripts/esm/gsplat/reveal-radial.mjs'; import { GSplatRevealRain } from 'playcanvas/scripts/esm/gsplat/reveal-rain.mjs'; @@ -74,8 +77,7 @@ app.on('destroy', () => { }); const assets = { - hotel: new Asset('gsplat', 'gsplat', { url: './assets/splats/hotel-culpture.compressed.ply' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + hotel: new Asset('gsplat', 'gsplat', { url: './assets/splats/hotel-culpture.compressed.ply' }) }; await new Promise((resolve) => { @@ -227,19 +229,19 @@ camera.addComponent('camera', { }); camera.setLocalPosition(3, 1, 0.5); -// Add orbit camera script with a mouse and a touch support +// Add camera controls with a mouse and a touch support camera.addComponent('script'); -camera.script?.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: hotel, - distanceMax: 3.2, - frameOnStart: false - } -}); -camera.script?.create('orbitCameraInputMouse'); -camera.script?.create('orbitCameraInputTouch'); app.root.addChild(camera); +const orbitPivot = hotel.getPosition().clone(); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: orbitPivot, + zoomRange: new Vec2(0.01, 3.2), + enableFly: false + } + }) +); // Auto-rotate camera when idle let autoRotateEnabled = true; @@ -269,11 +271,20 @@ app.on('update', (dt) => { autoRotateEnabled = true; } - // Apply auto-rotation + // Apply auto-rotation by advancing the camera's azimuth around the pivot if (autoRotateEnabled) { - const orbitCamera = camera.script?.get('orbitCamera'); - if (orbitCamera) { - orbitCamera.yaw += autoRotateSpeed * dt; - } + const offset = camera.getPosition().clone().sub(orbitPivot); + const r = offset.length(); + const pitch = Math.asin(Math.max(-1, Math.min(1, offset.y / r))); + const yaw = Math.atan2(offset.x, offset.z) + (autoRotateSpeed * dt * Math.PI) / 180; + const cp = Math.cos(pitch); + cameraControls.reset( + orbitPivot, + new Vec3( + orbitPivot.x + r * Math.sin(yaw) * cp, + orbitPivot.y + r * Math.sin(pitch), + orbitPivot.z + r * Math.cos(yaw) * cp + ) + ); } }); diff --git a/examples/src/examples/gaussian-splatting/shader-dissolve.example.mjs b/examples/src/examples/gaussian-splatting/shader-dissolve.example.mjs index 0a4b6af0bf5..de72bbdc6b0 100644 --- a/examples/src/examples/gaussian-splatting/shader-dissolve.example.mjs +++ b/examples/src/examples/gaussian-splatting/shader-dissolve.example.mjs @@ -25,9 +25,11 @@ import { ScriptHandler, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { GSplatDissolveShaderEffect } from 'playcanvas/scripts/esm/gsplat/shader-effect-dissolve.mjs'; import { data, deviceType } from 'examples/context'; @@ -74,8 +76,7 @@ app.on('destroy', () => { }); const assets = { - hotel: new Asset('gsplat', 'gsplat', { url: './assets/splats/hotel-culpture.compressed.ply' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + hotel: new Asset('gsplat', 'gsplat', { url: './assets/splats/hotel-culpture.compressed.ply' }) }; await new Promise((resolve) => { @@ -308,19 +309,19 @@ camera.addComponent('camera', { }); camera.setLocalPosition(3, 1, 0.5); -// Add orbit camera script with a mouse and a touch support +// Add camera controls with a mouse and a touch support camera.addComponent('script'); -camera.script?.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: hotel, - distanceMax: 2, - frameOnStart: false - } -}); -camera.script?.create('orbitCameraInputMouse'); -camera.script?.create('orbitCameraInputTouch'); app.root.addChild(camera); +const orbitPivot = hotel.getPosition().clone(); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: orbitPivot, + zoomRange: new Vec2(0.01, 2), + enableFly: false + } + }) +); // Auto-rotate camera when idle let autoRotateEnabled = true; @@ -350,11 +351,20 @@ app.on('update', (dt) => { autoRotateEnabled = true; } - // Apply auto-rotation + // Apply auto-rotation by advancing the camera's azimuth around the pivot if (autoRotateEnabled) { - const orbitCamera = camera.script?.get('orbitCamera'); - if (orbitCamera) { - orbitCamera.yaw += autoRotateSpeed * dt; - } + const offset = camera.getPosition().clone().sub(orbitPivot); + const r = offset.length(); + const pitch = Math.asin(Math.max(-1, Math.min(1, offset.y / r))); + const yaw = Math.atan2(offset.x, offset.z) + (autoRotateSpeed * dt * Math.PI) / 180; + const cp = Math.cos(pitch); + cameraControls.reset( + orbitPivot, + new Vec3( + orbitPivot.x + r * Math.sin(yaw) * cp, + orbitPivot.y + r * Math.sin(pitch), + orbitPivot.z + r * Math.cos(yaw) * cp + ) + ); } }); diff --git a/examples/src/examples/gaussian-splatting/shader-effects.example.mjs b/examples/src/examples/gaussian-splatting/shader-effects.example.mjs index 293e05d454f..1a8ee02e448 100644 --- a/examples/src/examples/gaussian-splatting/shader-effects.example.mjs +++ b/examples/src/examples/gaussian-splatting/shader-effects.example.mjs @@ -23,9 +23,11 @@ import { ScriptHandler, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { GSplatBoxShaderEffect } from 'playcanvas/scripts/esm/gsplat/shader-effect-box.mjs'; import { data, deviceType } from 'examples/context'; @@ -72,8 +74,7 @@ app.on('destroy', () => { }); const assets = { - hotel: new Asset('gsplat', 'gsplat', { url: './assets/splats/hotel-culpture.compressed.ply' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + hotel: new Asset('gsplat', 'gsplat', { url: './assets/splats/hotel-culpture.compressed.ply' }) }; await new Promise((resolve) => { @@ -299,19 +300,19 @@ camera.addComponent('camera', { }); camera.setLocalPosition(3, 1, 0.5); -// Add orbit camera script with a mouse and a touch support +// Add camera controls with a mouse and a touch support camera.addComponent('script'); -camera.script?.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: hotel, - distanceMax: 2, - frameOnStart: false - } -}); -camera.script?.create('orbitCameraInputMouse'); -camera.script?.create('orbitCameraInputTouch'); app.root.addChild(camera); +const orbitPivot = hotel.getPosition().clone(); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: orbitPivot, + zoomRange: new Vec2(0.01, 2), + enableFly: false + } + }) +); // Auto-rotate camera when idle let autoRotateEnabled = true; @@ -341,11 +342,20 @@ app.on('update', (dt) => { autoRotateEnabled = true; } - // Apply auto-rotation + // Apply auto-rotation by advancing the camera's azimuth around the pivot if (autoRotateEnabled) { - const orbitCamera = camera.script?.get('orbitCamera'); - if (orbitCamera) { - orbitCamera.yaw += autoRotateSpeed * dt; - } + const offset = camera.getPosition().clone().sub(orbitPivot); + const r = offset.length(); + const pitch = Math.asin(Math.max(-1, Math.min(1, offset.y / r))); + const yaw = Math.atan2(offset.x, offset.z) + (autoRotateSpeed * dt * Math.PI) / 180; + const cp = Math.cos(pitch); + cameraControls.reset( + orbitPivot, + new Vec3( + orbitPivot.x + r * Math.sin(yaw) * cp, + orbitPivot.y + r * Math.sin(pitch), + orbitPivot.z + r * Math.cos(yaw) * cp + ) + ); } }); diff --git a/examples/src/examples/gaussian-splatting/shader-rings.example.mjs b/examples/src/examples/gaussian-splatting/shader-rings.example.mjs index 7b83532bd51..c31edc4bbb1 100644 --- a/examples/src/examples/gaussian-splatting/shader-rings.example.mjs +++ b/examples/src/examples/gaussian-splatting/shader-rings.example.mjs @@ -24,9 +24,11 @@ import { ScriptHandler, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -75,8 +77,7 @@ app.on('destroy', () => { }); const assets = { - skull: new Asset('gsplat', 'gsplat', { url: './assets/splats/skull.compressed.ply' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + skull: new Asset('gsplat', 'gsplat', { url: './assets/splats/skull.compressed.ply' }) }; await new Promise((resolve) => { @@ -114,24 +115,29 @@ camera.addComponent('camera', { }); app.root.addChild(camera); -// Add orbit camera script with a mouse and a touch support +// Add camera controls with mouse and touch support camera.addComponent('script'); -const orbitCam = /** @type {any} */ ( - camera.script?.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 6, - frameOnStart: false +const orbitPivot = new Vec3(0, 0.9, -0.28); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(0.01, 6), + enableFly: false } }) ); -if (orbitCam) { - orbitCam.pivotPoint.copy(new Vec3(0, 0.9, -0.28)); - orbitCam.reset(88, -28, 0.9); - orbitCam._updatePosition(); -} -camera.script?.create('orbitCameraInputMouse'); -camera.script?.create('orbitCameraInputTouch'); + +// initial view: yaw 88, pitch -28 (degrees) at a distance of 0.9 around the pivot +const initYaw = (88 * Math.PI) / 180; +const initPitch = (-28 * Math.PI) / 180; +cameraControls.reset( + orbitPivot, + new Vec3( + orbitPivot.x + 0.9 * Math.sin(initYaw) * Math.cos(initPitch), + orbitPivot.y - 0.9 * Math.sin(initPitch), + orbitPivot.z + 0.9 * Math.cos(initYaw) * Math.cos(initPitch) + ) +); // Auto-rotate camera when idle let autoRotateEnabled = true; @@ -169,11 +175,20 @@ app.on('update', (dt) => { autoRotateEnabled = true; } - // Apply auto-rotation + // Apply auto-rotation by advancing the camera's azimuth around the pivot if (autoRotateEnabled) { - const orbitCamera = camera.script?.get('orbitCamera'); - if (orbitCamera) { - orbitCamera.yaw += autoRotateSpeed * dt; - } + const offset = camera.getPosition().clone().sub(orbitPivot); + const r = offset.length(); + const pitch = Math.asin(Math.max(-1, Math.min(1, offset.y / r))); + const yaw = Math.atan2(offset.x, offset.z) + (autoRotateSpeed * dt * Math.PI) / 180; + const cp = Math.cos(pitch); + cameraControls.reset( + orbitPivot, + new Vec3( + orbitPivot.x + r * Math.sin(yaw) * cp, + orbitPivot.y + r * Math.sin(pitch), + orbitPivot.z + r * Math.cos(yaw) * cp + ) + ); } }); diff --git a/examples/src/examples/gaussian-splatting/shadow-soft.example.mjs b/examples/src/examples/gaussian-splatting/shadow-soft.example.mjs index dcc5002e1b6..74f75fca712 100644 --- a/examples/src/examples/gaussian-splatting/shadow-soft.example.mjs +++ b/examples/src/examples/gaussian-splatting/shadow-soft.example.mjs @@ -33,9 +33,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -87,8 +89,7 @@ const assets = { 'texture', { url: './assets/cubemaps/helipad-env-atlas.png' }, { type: TEXTURETYPE_RGBP, mipmaps: false } - ), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + ) }; await new Promise((resolve) => { @@ -177,19 +178,18 @@ camera.addComponent('camera', { }); camera.setLocalPosition(-3, 2, 4); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 15, - frameOnStart: false - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(0.01, 15), + enableFly: false + } + }) +); // Orbit around the scene center (the bikes' average center / cylinder center) -camera.script.orbitCamera.resetAndLookAtPoint(new Vec3(-3, 2, 4), new Vec3(0, 0, 0)); +cameraControls.reset(new Vec3(0, 0, 0), new Vec3(-3, 2, 4)); // Single directional light casting soft shadows const { soft: softShadows, ...lightSettings } = data.get('settings.light'); diff --git a/examples/src/examples/gaussian-splatting/shadows.example.mjs b/examples/src/examples/gaussian-splatting/shadows.example.mjs index 796e349fd17..9d8a05c5f58 100644 --- a/examples/src/examples/gaussian-splatting/shadows.example.mjs +++ b/examples/src/examples/gaussian-splatting/shadows.example.mjs @@ -35,9 +35,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { ShadowCatcher } from 'playcanvas/scripts/esm/shadow-catcher.mjs'; import { data, deviceType } from 'examples/context'; @@ -88,8 +90,7 @@ app.on('destroy', () => { const assets = { biker: new Asset('gsplat', 'gsplat', { url: './assets/splats/biker.compressed.ply' }), - hdri: new Asset('hdri', 'texture', { url: './assets/hdri/st-peters-square.hdr' }, { mipmaps: false }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + hdri: new Asset('hdri', 'texture', { url: './assets/hdri/st-peters-square.hdr' }, { mipmaps: false }) }; await new Promise((resolve) => { @@ -181,19 +182,16 @@ camera.addComponent('camera', { }); camera.setLocalPosition(-3, 2, 4); -// Add orbit camera script with mouse and touch support +// Add camera controls camera.addComponent('script'); -camera.script?.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: biker, - distanceMax: 10, - frameOnStart: false +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(-1.5, 0.05, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 10) } }); -camera.script?.create('orbitCameraInputMouse'); -camera.script?.create('orbitCameraInputTouch'); -app.root.addChild(camera); // Create shadow catcher const shadowCatcher = new Entity('ShadowCatcher'); diff --git a/examples/src/examples/gaussian-splatting/simple-glb.example.mjs b/examples/src/examples/gaussian-splatting/simple-glb.example.mjs index 9c7efb38098..116c0334ed2 100644 --- a/examples/src/examples/gaussian-splatting/simple-glb.example.mjs +++ b/examples/src/examples/gaussian-splatting/simple-glb.example.mjs @@ -25,9 +25,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -73,8 +75,7 @@ app.on('destroy', () => { }); const assets = { - biker: new Asset('gsplat-glb', 'container', { url: './assets/splats/biker.glb' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + biker: new Asset('gsplat-glb', 'container', { url: './assets/splats/biker.glb' }) }; await new Promise((resolve) => { @@ -113,22 +114,26 @@ camera.addComponent('camera', { app.root.addChild(camera); camera.addComponent('script'); -const orbitCam = /** @type {any} */ ( - camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 60, - frameOnStart: false +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(0.01, 60), + enableFly: false } }) ); -if (orbitCam) { - orbitCam.pivotPoint.copy(ORBIT_PIVOT); - orbitCam.reset(ORBIT_INITIAL_YAW, ORBIT_INITIAL_PITCH, ORBIT_DISTANCE); - orbitCam._updatePosition(); -} -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); + +// place the camera on an orbit around the pivot (yaw/pitch in degrees, at ORBIT_DISTANCE) +const orbitYaw = (ORBIT_INITIAL_YAW * Math.PI) / 180; +const orbitPitch = (ORBIT_INITIAL_PITCH * Math.PI) / 180; +cameraControls.reset( + ORBIT_PIVOT, + new Vec3( + ORBIT_PIVOT.x + ORBIT_DISTANCE * Math.sin(orbitYaw) * Math.cos(orbitPitch), + ORBIT_PIVOT.y - ORBIT_DISTANCE * Math.sin(orbitPitch), + ORBIT_PIVOT.z + ORBIT_DISTANCE * Math.cos(orbitYaw) * Math.cos(orbitPitch) + ) +); // Create ground to receive shadows const material = new StandardMaterial(); diff --git a/examples/src/examples/gaussian-splatting/simple-on-demand.example.mjs b/examples/src/examples/gaussian-splatting/simple-on-demand.example.mjs index 4d4f811d4f1..94bd596ffaa 100644 --- a/examples/src/examples/gaussian-splatting/simple-on-demand.example.mjs +++ b/examples/src/examples/gaussian-splatting/simple-on-demand.example.mjs @@ -28,9 +28,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -82,8 +84,7 @@ app.on('destroy', () => { }); const assets = { - biker: new Asset('gsplat', 'gsplat', { url: './assets/splats/biker.compressed.ply' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + biker: new Asset('gsplat', 'gsplat', { url: './assets/splats/biker.compressed.ply' }) }; await new Promise((resolve) => { @@ -143,22 +144,26 @@ camera.addComponent('camera', { app.root.addChild(camera); camera.addComponent('script'); -const orbitCam = /** @type {any} */ ( - camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 60, - frameOnStart: false +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(0.01, 60), + enableFly: false } }) ); -if (orbitCam) { - orbitCam.pivotPoint.copy(ORBIT_PIVOT); - orbitCam.reset(ORBIT_INITIAL_YAW, ORBIT_INITIAL_PITCH, ORBIT_DISTANCE); - orbitCam._updatePosition(); -} -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); + +// place the camera on an orbit around the pivot (yaw/pitch in degrees, at ORBIT_DISTANCE) +const orbitYaw = (ORBIT_INITIAL_YAW * Math.PI) / 180; +const orbitPitch = (ORBIT_INITIAL_PITCH * Math.PI) / 180; +cameraControls.reset( + ORBIT_PIVOT, + new Vec3( + ORBIT_PIVOT.x + ORBIT_DISTANCE * Math.sin(orbitYaw) * Math.cos(orbitPitch), + ORBIT_PIVOT.y - ORBIT_DISTANCE * Math.sin(orbitPitch), + ORBIT_PIVOT.z + ORBIT_DISTANCE * Math.cos(orbitYaw) * Math.cos(orbitPitch) + ) +); // Create ground to receive shadows const material = new StandardMaterial(); diff --git a/examples/src/examples/gaussian-splatting/simple-spz.example.mjs b/examples/src/examples/gaussian-splatting/simple-spz.example.mjs index dba30feda56..539d2d797cd 100644 --- a/examples/src/examples/gaussian-splatting/simple-spz.example.mjs +++ b/examples/src/examples/gaussian-splatting/simple-spz.example.mjs @@ -24,10 +24,12 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, WasmModule, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { SpzParser } from 'playcanvas/scripts/esm/parsers/spz-parser.mjs'; import { deviceType } from 'examples/context'; @@ -83,8 +85,7 @@ app.on('destroy', () => { }); const assets = { - biker: new Asset('gsplat', 'gsplat', { url: './assets/splats/biker.spz' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + biker: new Asset('gsplat', 'gsplat', { url: './assets/splats/biker.spz' }) }; await new Promise((resolve) => { @@ -116,19 +117,23 @@ camera.addComponent('camera', { app.root.addChild(camera); camera.addComponent('script'); -const orbitCam = /** @type {any} */ ( - camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 60, - frameOnStart: false +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(0.01, 60), + enableFly: false } }) ); -if (orbitCam) { - orbitCam.pivotPoint.copy(ORBIT_PIVOT); - orbitCam.reset(ORBIT_INITIAL_YAW, ORBIT_INITIAL_PITCH, ORBIT_DISTANCE); - orbitCam._updatePosition(); -} -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); + +// place the camera on an orbit around the pivot (yaw/pitch in degrees, at ORBIT_DISTANCE) +const orbitYaw = (ORBIT_INITIAL_YAW * Math.PI) / 180; +const orbitPitch = (ORBIT_INITIAL_PITCH * Math.PI) / 180; +cameraControls.reset( + ORBIT_PIVOT, + new Vec3( + ORBIT_PIVOT.x + ORBIT_DISTANCE * Math.sin(orbitYaw) * Math.cos(orbitPitch), + ORBIT_PIVOT.y - ORBIT_DISTANCE * Math.sin(orbitPitch), + ORBIT_PIVOT.z + ORBIT_DISTANCE * Math.cos(orbitYaw) * Math.cos(orbitPitch) + ) +); diff --git a/examples/src/examples/gaussian-splatting/simple.example.mjs b/examples/src/examples/gaussian-splatting/simple.example.mjs index 97451dd4400..1f35f399921 100644 --- a/examples/src/examples/gaussian-splatting/simple.example.mjs +++ b/examples/src/examples/gaussian-splatting/simple.example.mjs @@ -26,9 +26,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -74,8 +76,7 @@ app.on('destroy', () => { }); const assets = { - biker: new Asset('gsplat', 'gsplat', { url: './assets/splats/biker.compressed.ply' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + biker: new Asset('gsplat', 'gsplat', { url: './assets/splats/biker.compressed.ply' }) }; await new Promise((resolve) => { @@ -129,22 +130,26 @@ camera.addComponent('camera', { app.root.addChild(camera); camera.addComponent('script'); -const orbitCam = /** @type {any} */ ( - camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 60, - frameOnStart: false +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(0.01, 60), + enableFly: false } }) ); -if (orbitCam) { - orbitCam.pivotPoint.copy(ORBIT_PIVOT); - orbitCam.reset(ORBIT_INITIAL_YAW, ORBIT_INITIAL_PITCH, ORBIT_DISTANCE); - orbitCam._updatePosition(); -} -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); + +// place the camera on an orbit around the pivot (yaw/pitch in degrees, at ORBIT_DISTANCE) +const orbitYaw = (ORBIT_INITIAL_YAW * Math.PI) / 180; +const orbitPitch = (ORBIT_INITIAL_PITCH * Math.PI) / 180; +cameraControls.reset( + ORBIT_PIVOT, + new Vec3( + ORBIT_PIVOT.x + ORBIT_DISTANCE * Math.sin(orbitYaw) * Math.cos(orbitPitch), + ORBIT_PIVOT.y - ORBIT_DISTANCE * Math.sin(orbitPitch), + ORBIT_PIVOT.z + ORBIT_DISTANCE * Math.cos(orbitYaw) * Math.cos(orbitPitch) + ) +); // Create ground to receive shadows const material = new StandardMaterial(); diff --git a/examples/src/examples/gaussian-splatting/spherical-harmonics.example.mjs b/examples/src/examples/gaussian-splatting/spherical-harmonics.example.mjs index 7c410c18e50..fbc66ec7123 100644 --- a/examples/src/examples/gaussian-splatting/spherical-harmonics.example.mjs +++ b/examples/src/examples/gaussian-splatting/spherical-harmonics.example.mjs @@ -26,9 +26,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -74,8 +76,7 @@ app.on('destroy', () => { }); const assets = { - skull: new Asset('gsplat', 'gsplat', { url: './assets/splats/skull.compressed.ply' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + skull: new Asset('gsplat', 'gsplat', { url: './assets/splats/skull.compressed.ply' }) }; await new Promise((resolve) => { @@ -122,22 +123,26 @@ camera.addComponent('camera', { app.root.addChild(camera); camera.addComponent('script'); -const orbitCam = /** @type {any} */ ( - camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 60, - frameOnStart: false +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(0.01, 60), + enableFly: false } }) ); -if (orbitCam) { - orbitCam.pivotPoint.copy(ORBIT_PIVOT); - orbitCam.reset(ORBIT_INITIAL_YAW, ORBIT_INITIAL_PITCH, ORBIT_DISTANCE); - orbitCam._updatePosition(); -} -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); + +// place the camera on an orbit around the pivot (yaw/pitch in degrees, at ORBIT_DISTANCE) +const orbitYaw = (ORBIT_INITIAL_YAW * Math.PI) / 180; +const orbitPitch = (ORBIT_INITIAL_PITCH * Math.PI) / 180; +cameraControls.reset( + ORBIT_PIVOT, + new Vec3( + ORBIT_PIVOT.x + ORBIT_DISTANCE * Math.sin(orbitYaw) * Math.cos(orbitPitch), + ORBIT_PIVOT.y - ORBIT_DISTANCE * Math.sin(orbitPitch), + ORBIT_PIVOT.z + ORBIT_DISTANCE * Math.cos(orbitYaw) * Math.cos(orbitPitch) + ) +); // Create ground to receive shadows const material = new StandardMaterial(); diff --git a/examples/src/examples/gaussian-splatting/viewer.example.mjs b/examples/src/examples/gaussian-splatting/viewer.example.mjs index ad05d2ea1b2..3d963c47c56 100644 --- a/examples/src/examples/gaussian-splatting/viewer.example.mjs +++ b/examples/src/examples/gaussian-splatting/viewer.example.mjs @@ -37,8 +37,10 @@ import { TextureHandler, TouchDevice, WasmModule, + Vec2, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { SpzParser } from 'playcanvas/scripts/esm/parsers/spz-parser.mjs'; import { data, deviceType } from 'examples/context'; @@ -131,7 +133,6 @@ app.on('destroy', () => { // Load orbit camera script and HDRI const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), hdri: new Asset('hdri', 'texture', { url: './assets/hdri/wide-street.hdr' }, { mipmaps: false }) }; @@ -474,14 +475,11 @@ canvas.addEventListener('drop', async (e) => { // Add orbit camera script camera.addComponent('script'); - camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: entity, - distanceMax: size * 5, - frameOnStart: true + camera.script.create(CameraControls, { + properties: { + focusPoint: center.clone(), + zoomRange: new Vec2(0.01, size * 5), + enableFly: false } }); - camera.script.create('orbitCameraInputMouse'); - camera.script.create('orbitCameraInputTouch'); }); diff --git a/examples/src/examples/gaussian-splatting/xr-views.example.mjs b/examples/src/examples/gaussian-splatting/xr-views.example.mjs index e44bda91f4f..719baf5260e 100644 --- a/examples/src/examples/gaussian-splatting/xr-views.example.mjs +++ b/examples/src/examples/gaussian-splatting/xr-views.example.mjs @@ -28,9 +28,11 @@ import { ScriptHandler, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -76,8 +78,7 @@ app.on('destroy', () => { }); const assets = { - hotel: new Asset('gsplat', 'gsplat', { url: './assets/splats/hotel-culpture.compressed.ply' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + hotel: new Asset('gsplat', 'gsplat', { url: './assets/splats/hotel-culpture.compressed.ply' }) }; await new Promise((resolve) => { @@ -103,17 +104,14 @@ camera.addComponent('camera', { camera.setLocalPosition(3, 1, 0.5); camera.addComponent('script'); -camera.script?.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: hotel, - distanceMax: 2, - frameOnStart: false +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 2) } }); -camera.script?.create('orbitCameraInputMouse'); -camera.script?.create('orbitCameraInputTouch'); -app.root.addChild(camera); data.on('renderer:set', () => { app.scene.gsplat.renderer = data.get('renderer'); diff --git a/examples/src/examples/graphics/ambient-occlusion.example.mjs b/examples/src/examples/graphics/ambient-occlusion.example.mjs index 3df62e15125..7b4b51b0f53 100644 --- a/examples/src/examples/graphics/ambient-occlusion.example.mjs +++ b/examples/src/examples/graphics/ambient-occlusion.example.mjs @@ -34,10 +34,12 @@ import { TONEMAP_NEUTRAL, TextureHandler, TouchDevice, + Vec2, Vec3, WasmModule, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -53,7 +55,6 @@ WasmModule.setConfig('DracoDecoderModule', { const assets = { laboratory: new Asset('statue', 'container', { url: './assets/models/laboratory.glb' }), - orbit: new Asset('orbit', 'script', { url: './scripts/camera/orbit-camera.js' }), ssao: new Asset('ssao', 'script', { url: './scripts/posteffects/posteffect-ssao.js' }), helipad: new Asset( 'helipad-env-atlas', @@ -183,21 +184,19 @@ cameraEntity.addComponent('camera', { toneMapping: TONEMAP_NEUTRAL }); -// Add orbit camera script +// Position the camera in the world +cameraEntity.setLocalPosition(-233.333, 116.667, 233.333); cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: laboratoryEntity, - distanceMax: 350 +app.root.addChild(cameraEntity); + +// Add camera controls +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 350) } }); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); - -// Position the camera in the world -cameraEntity.setLocalPosition(-60, 30, 60); -app.root.addChild(cameraEntity); // ------ Custom render passes set up ------ diff --git a/examples/src/examples/graphics/asset-viewer.example.mjs b/examples/src/examples/graphics/asset-viewer.example.mjs index cdc2122b2f8..690491ea216 100644 --- a/examples/src/examples/graphics/asset-viewer.example.mjs +++ b/examples/src/examples/graphics/asset-viewer.example.mjs @@ -56,6 +56,7 @@ import { Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -63,7 +64,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -223,16 +223,15 @@ camera.setLocalPosition(0, 55, 160); camera.camera.requestSceneColorMap(true); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMin: 8, - distanceMax: 50 - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + zoomRange: new Vec2(8, 50), + enableFly: false + } + }) +); const directionalLight = new Entity(); directionalLight.addComponent('light', { @@ -283,8 +282,7 @@ function jumpToAsset(offset) { const newPos = new Vec3(0, 2.0, 6.0).add(pos); camera.setLocalPosition(newPos); - // @ts-ignore engine-tsd - camera.script.orbitCamera.focusEntity = assetList[currentAssetIndex]; + cameraControls.focusPoint = assetList[currentAssetIndex].getPosition(); } // Focus on mosquito diff --git a/examples/src/examples/graphics/clustered-area-lights.example.mjs b/examples/src/examples/graphics/clustered-area-lights.example.mjs index 70f5854a737..6825d602cd9 100644 --- a/examples/src/examples/graphics/clustered-area-lights.example.mjs +++ b/examples/src/examples/graphics/clustered-area-lights.example.mjs @@ -26,9 +26,11 @@ import { TONEMAP_NONE, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -43,7 +45,6 @@ data.set('settings', { }); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), color: new Asset('color', 'texture', { url: './assets/textures/seaside-rocks01-color.jpg' }, { srgb: true }), normal: new Asset('normal', 'texture', { url: './assets/textures/seaside-rocks01-normal.jpg' }), gloss: new Asset('gloss', 'texture', { url: './assets/textures/seaside-rocks01-gloss.jpg' }), @@ -230,7 +231,7 @@ const luts = assets.luts.resource; app.setAreaLightLuts(luts.LTC_MAT_1, luts.LTC_MAT_2); // Create ground plane -const ground = createPrimitive('plane', new Vec3(0, 0, 0), new Vec3(45, 1, 45), assets); +createPrimitive('plane', new Vec3(0, 0, 0), new Vec3(45, 1, 45), assets); // Create the camera, which renders entities const camera = new Entity(); @@ -240,20 +241,17 @@ camera.addComponent('camera', { farClip: 1000 }); camera.setLocalPosition(3, 3, 12); +app.root.addChild(camera); -// Add orbit camera script with a mouse and a touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: ground, - distanceMax: 60, - frameOnStart: false +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 60) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); // Custom render passes const cameraFrame = new CameraFrame(app, camera.camera); diff --git a/examples/src/examples/graphics/clustered-light-cookies.example.mjs b/examples/src/examples/graphics/clustered-light-cookies.example.mjs index 396fb9e1f2f..fcf8ed9d44e 100644 --- a/examples/src/examples/graphics/clustered-light-cookies.example.mjs +++ b/examples/src/examples/graphics/clustered-light-cookies.example.mjs @@ -33,11 +33,13 @@ import { Texture, TextureHandler, TouchDevice, + Vec2, Vec3, WasmModule, createGraphicsDevice, math } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -56,7 +58,6 @@ await new Promise((resolve) => { }); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), board: new Asset('board', 'container', { url: './assets/models/chess-board.glb' }) }; @@ -253,19 +254,16 @@ camera.addComponent('camera', { }); camera.setLocalPosition(0, 50, 70); -// Add orbit camera script with mouse and touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: board, - distanceMax: 200, - frameOnStart: false +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 200) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); let frame = 0; let phase = 0; diff --git a/examples/src/examples/graphics/clustered-lighting.example.mjs b/examples/src/examples/graphics/clustered-lighting.example.mjs index 399b236dba9..846b570a5f9 100644 --- a/examples/src/examples/graphics/clustered-lighting.example.mjs +++ b/examples/src/examples/graphics/clustered-lighting.example.mjs @@ -28,9 +28,11 @@ import { TONEMAP_NONE, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -38,7 +40,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), normal: new Asset('normal', 'texture', { url: './assets/textures/normal-map.png' }) }; @@ -232,19 +233,16 @@ camera.addComponent('camera', { camera.setLocalPosition(140, 140, 140); camera.lookAt(new Vec3(0, 40, 0)); -// Add orbit camera script with mouse and touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: app.root, - distanceMax: 400, - frameOnStart: false +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 40, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 400) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); // Set an update function on the app's update event let time = 0; diff --git a/examples/src/examples/graphics/clustered-omni-shadows.example.mjs b/examples/src/examples/graphics/clustered-omni-shadows.example.mjs index 43fce50df2a..3ebbd86135e 100644 --- a/examples/src/examples/graphics/clustered-omni-shadows.example.mjs +++ b/examples/src/examples/graphics/clustered-omni-shadows.example.mjs @@ -19,9 +19,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -29,7 +31,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), normal: new Asset('normal', 'texture', { url: './assets/textures/normal-map.png' }), xmas_negx: new Asset('xmas_negx', 'texture', { url: './assets/cubemaps/xmas_faces/xmas_negx.png' @@ -251,20 +252,17 @@ camera.addComponent('camera', { // and position it in the world camera.setLocalPosition(300, 120, 25); +app.root.addChild(camera); -// Add orbit camera script with a mouse and a touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: app.root, - distanceMax: 1200, - frameOnStart: false +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 191.428, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 1200) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); // Handle HUD changes - update properties on the scene data.on('*:set', (/** @type {string} */ path, value) => { diff --git a/examples/src/examples/graphics/clustered-spot-shadows.example.mjs b/examples/src/examples/graphics/clustered-spot-shadows.example.mjs index 4467c97ec0d..9191d2aad46 100644 --- a/examples/src/examples/graphics/clustered-spot-shadows.example.mjs +++ b/examples/src/examples/graphics/clustered-spot-shadows.example.mjs @@ -20,9 +20,11 @@ import { TEXTURETYPE_RGBP, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -35,7 +37,6 @@ window.focus(); const observer = data; const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), channels: new Asset('channels', 'texture', { url: './assets/textures/channels.png' }), heart: new Asset('heart', 'texture', { url: './assets/textures/heart.png' }), normal: new Asset('normal', 'texture', { url: './assets/textures/normal-map.png' }), @@ -196,7 +197,7 @@ function createPrimitive(primitiveType, position, scale, mat) { } // Create some visible geometry -const ground = createPrimitive('box', new Vec3(0, 0, 0), new Vec3(500, 1, 500), groundMaterial); +createPrimitive('box', new Vec3(0, 0, 0), new Vec3(500, 1, 500), groundMaterial); const numTowers = 8; for (let i = 0; i < numTowers; i++) { @@ -281,18 +282,15 @@ camera.addComponent('camera', { app.root.addChild(camera); camera.setLocalPosition(300 * Math.sin(0), 150, 300 * Math.cos(0)); -// Add orbit camera script with mouse and touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: ground, - distanceMax: 1200, - frameOnStart: false +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 1200) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); // Handle HUD changes - update properties on the scene data.on('*:set', (/** @type {string} */ path, value) => { diff --git a/examples/src/examples/graphics/custom-compose-shader.example.mjs b/examples/src/examples/graphics/custom-compose-shader.example.mjs index bb37a9303cb..ff002fce969 100644 --- a/examples/src/examples/graphics/custom-compose-shader.example.mjs +++ b/examples/src/examples/graphics/custom-compose-shader.example.mjs @@ -41,8 +41,11 @@ import { TONEMAP_NEUTRAL, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -50,7 +53,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), apartment: new Asset('apartment', 'container', { url: './assets/models/apartment.glb' }), love: new Asset('love', 'container', { url: './assets/models/love.glb' }), helipad: new Asset( @@ -143,25 +145,19 @@ cameraEntity.addComponent('camera', { fov: 80 }); -const focusPoint = new Entity(); -focusPoint.setLocalPosition(-80, 80, -20); +cameraEntity.setLocalPosition(-50, 100, 220); +cameraEntity.lookAt(0, 0, 100); +app.root.addChild(cameraEntity); -// Add orbit camera script with a mouse and a touch support +// Add camera controls cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: focusPoint, - distanceMax: 500, - frameOnStart: false +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 500) } }); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); - -cameraEntity.setLocalPosition(-50, 100, 220); -cameraEntity.lookAt(0, 0, 100); -app.root.addChild(cameraEntity); // ------ Custom shader chunks for the camera frame ------ diff --git a/examples/src/examples/graphics/depth-of-field.example.mjs b/examples/src/examples/graphics/depth-of-field.example.mjs index 7f2c75a2e27..26884bf43fd 100644 --- a/examples/src/examples/graphics/depth-of-field.example.mjs +++ b/examples/src/examples/graphics/depth-of-field.example.mjs @@ -40,8 +40,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -49,7 +52,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), apartment: new Asset('apartment', 'container', { url: './assets/models/apartment.glb' }), love: new Asset('love', 'container', { url: './assets/models/love.glb' }), cat: new Asset('cat', 'container', { url: './assets/models/cat.glb' }), @@ -147,23 +149,20 @@ cameraEntity.addComponent('camera', { fov: 80 }); -// Add orbit camera script with a mouse and a touch support -cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: cat, - distanceMax: 500, - frameOnStart: false - } -}); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); - cameraEntity.setLocalPosition(-50, 100, 220); cameraEntity.lookAt(0, 0, 100); +cameraEntity.addComponent('script'); app.root.addChild(cameraEntity); +// Add camera controls +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(-80, 80, -20), + enableFly: false, + zoomRange: new Vec2(0.01, 500) + } +}); + // ------ Custom render passes set up ------ const cameraFrame = new CameraFrame(app, cameraEntity.camera); diff --git a/examples/src/examples/graphics/dithered-transparency.example.mjs b/examples/src/examples/graphics/dithered-transparency.example.mjs index 1d7343b7624..a5900553ede 100644 --- a/examples/src/examples/graphics/dithered-transparency.example.mjs +++ b/examples/src/examples/graphics/dithered-transparency.example.mjs @@ -37,9 +37,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -58,7 +60,6 @@ const assets = { { type: TEXTURETYPE_RGBP, mipmaps: false } ), table: new Asset('table', 'container', { url: './assets/models/glass-table.glb' }), - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), diffuse: new Asset('color', 'texture', { url: './assets/textures/playcanvas.png' }, { srgb: true }) }; @@ -205,17 +206,15 @@ cameraEntity.translate(-14, 12, 20); cameraEntity.lookAt(0, 4, 0); app.root.addChild(cameraEntity); -// Add orbit camera script with a mouse and a touch support +// Add camera controls cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 40, - frameOnStart: false +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 4, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 40) } }); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); // ------ Custom render passes set up ------ diff --git a/examples/src/examples/graphics/instancing-glb.example.mjs b/examples/src/examples/graphics/instancing-glb.example.mjs index 15c864354fb..df7e286c83f 100644 --- a/examples/src/examples/graphics/instancing-glb.example.mjs +++ b/examples/src/examples/graphics/instancing-glb.example.mjs @@ -24,8 +24,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -33,7 +36,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -98,20 +100,16 @@ camera.addComponent('camera', { }); camera.translate(15, 15, -25); -// Add orbit camera script with a mouse and a touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: entity, - distanceMax: 60, - frameOnStart: false +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 60) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); - -app.root.addChild(camera); // Set skybox app.scene.envAtlas = assets.helipad.resource; diff --git a/examples/src/examples/graphics/light-physical-units.example.mjs b/examples/src/examples/graphics/light-physical-units.example.mjs index 0be62ff73dc..60f007009c2 100644 --- a/examples/src/examples/graphics/light-physical-units.example.mjs +++ b/examples/src/examples/graphics/light-physical-units.example.mjs @@ -32,9 +32,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType, win } from 'examples/context'; @@ -46,7 +48,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -282,21 +283,19 @@ camera.addComponent('camera', { sensitivity: data.get('script.camera.sensitivity') }); camera.setLocalPosition(0, 5, 11); +app.root.addChild(camera); camera.camera.requestSceneColorMap(true); + +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: sheen1, - distanceMin: 1, - distanceMax: 400, - frameOnStart: false +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(7, -1, 0), + enableFly: false, + zoomRange: new Vec2(1, 400) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); data.on('*:set', (/** @type {string} */ path, value) => { if (path === 'script.sun.luminance') { diff --git a/examples/src/examples/graphics/lights-baked-a-o.example.mjs b/examples/src/examples/graphics/lights-baked-a-o.example.mjs index 20c07278b75..a3ff4a11fe5 100644 --- a/examples/src/examples/graphics/lights-baked-a-o.example.mjs +++ b/examples/src/examples/graphics/lights-baked-a-o.example.mjs @@ -29,8 +29,11 @@ import { TEXTURETYPE_RGBP, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -48,8 +51,7 @@ const assets = { { url: './assets/cubemaps/helipad-env-atlas.png' }, { type: TEXTURETYPE_RGBP, mipmaps: false } ), - house: new Asset('house', 'container', { url: './assets/models/house.glb' }), - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + house: new Asset('house', 'container', { url: './assets/models/house.glb' }) }; const gfxOptions = { @@ -186,19 +188,17 @@ camera.addComponent('camera', { nearClip: 1 }); camera.setLocalPosition(40, 20, 40); +app.root.addChild(camera); -// Add orbit camera script with a mouse and a touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: house, - distanceMax: 60 +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 60) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); // lightmap baking properties const bakeType = BAKE_COLOR; diff --git a/examples/src/examples/graphics/lights-baked.example.mjs b/examples/src/examples/graphics/lights-baked.example.mjs index b3c79999cd1..aed9603ab92 100644 --- a/examples/src/examples/graphics/lights-baked.example.mjs +++ b/examples/src/examples/graphics/lights-baked.example.mjs @@ -1,7 +1,6 @@ import { AppBase, AppOptions, - Asset, AssetListLoader, BAKE_COLOR, CameraComponentSystem, @@ -18,17 +17,18 @@ import { ScriptHandler, StandardMaterial, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('application-canvas')); window.focus(); -const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) -}; +const assets = {}; const gfxOptions = { deviceTypes: [deviceType] @@ -246,19 +246,18 @@ camera.addComponent('camera', { farClip: 100, nearClip: 0.05 }); -camera.setLocalPosition(1, 3, -1); +camera.setLocalPosition(9.37, 9.278, -9.37); +app.root.addChild(camera); -// Add orbit camera script with mouse and touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 15 +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 2.25, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 15) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); // lightmap baking properties const bakeType = BAKE_COLOR; diff --git a/examples/src/examples/graphics/lights.example.mjs b/examples/src/examples/graphics/lights.example.mjs index c94b93a3aee..c4275c0439e 100644 --- a/examples/src/examples/graphics/lights.example.mjs +++ b/examples/src/examples/graphics/lights.example.mjs @@ -23,9 +23,11 @@ import { StandardMaterial, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -43,7 +45,6 @@ function createMaterial(colors) { const assets = { statue: new Asset('statue', 'container', { url: './assets/models/statue.glb' }), - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), heart: new Asset('heart', 'texture', { url: './assets/textures/heart.png' }), xmas_negx: new Asset('xmas_negx', 'texture', { url: './assets/cubemaps/xmas_faces/xmas_negx.png' @@ -127,15 +128,13 @@ camera.rotate(-14, 0, 0); app.root.addChild(camera); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - frameOnStart: false, - distanceMax: 500 +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0.173, 7.523, 0.018), + enableFly: false, + zoomRange: new Vec2(0.01, 500) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); // Ground material const material = new StandardMaterial(); diff --git a/examples/src/examples/graphics/multi-view.example.mjs b/examples/src/examples/graphics/multi-view.example.mjs index 7ba7bb8306b..ca072fe080f 100644 --- a/examples/src/examples/graphics/multi-view.example.mjs +++ b/examples/src/examples/graphics/multi-view.example.mjs @@ -29,11 +29,13 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, Vec4, WasmModule, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -52,7 +54,6 @@ await new Promise((resolve) => { }); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -156,20 +157,17 @@ cameraTop.addComponent('camera', { }); cameraTop.translate(-100, 75, 100); cameraTop.lookAt(0, 7, 0); +cameraTop.addComponent('script'); app.root.addChild(cameraTop); -// Add orbit camera script with a mouse and a touch support -cameraTop.addComponent('script'); -cameraTop.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: app.root, - distanceMax: 300, - frameOnStart: false +// Add camera controls +cameraTop.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 7, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 300) } }); -cameraTop.script.create('orbitCameraInputMouse'); -cameraTop.script.create('orbitCameraInputTouch'); // Create a directional light which casts shadows const dirLight = new Entity(); diff --git a/examples/src/examples/graphics/outlines-colored.example.mjs b/examples/src/examples/graphics/outlines-colored.example.mjs index 6ff21a9bb03..dd709717943 100644 --- a/examples/src/examples/graphics/outlines-colored.example.mjs +++ b/examples/src/examples/graphics/outlines-colored.example.mjs @@ -26,9 +26,12 @@ import { TEXTURETYPE_RGBP, TextureHandler, TouchDevice, + Vec2, + Vec3, WasmModule, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -44,7 +47,6 @@ WasmModule.setConfig('DracoDecoderModule', { const assets = { laboratory: new Asset('statue', 'container', { url: './assets/models/laboratory.glb' }), - orbit: new Asset('orbit', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -109,21 +111,19 @@ cameraEntity.addComponent('camera', { farClip: 600 }); -// Add orbit camera script +// Position the camera in the world +cameraEntity.setLocalPosition(-200, 100, 200); cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: laboratoryEntity, - distanceMax: 300 +app.root.addChild(cameraEntity); + +// Add camera controls +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 300) } }); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); - -// Position the camera in the world -cameraEntity.setLocalPosition(-60, 30, 60); -app.root.addChild(cameraEntity); // Create the outline renderer const outlineRenderer = new OutlineRenderer(app); diff --git a/examples/src/examples/graphics/particles-mesh.example.mjs b/examples/src/examples/graphics/particles-mesh.example.mjs index 1f37d8a8c9a..d7cfcf09069 100644 --- a/examples/src/examples/graphics/particles-mesh.example.mjs +++ b/examples/src/examples/graphics/particles-mesh.example.mjs @@ -24,9 +24,11 @@ import { TEXTURETYPE_RGBP, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -36,7 +38,6 @@ window.focus(); const assets = { torus: new Asset('heart', 'container', { url: './assets/models/torus.glb' }), color: new Asset('color', 'texture', { url: './assets/textures/clouds.jpg' }, { srgb: true }), - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -101,18 +102,14 @@ cameraEntity.rotateLocal(0, 0, 0); cameraEntity.setPosition(0, 4, 20); cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 50, - frameOnStart: false +app.root.addChild(cameraEntity); +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 5, 0), + zoomRange: new Vec2(0.01, 50), + enableFly: false } }); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); - -app.root.addChild(cameraEntity); -cameraEntity.script.orbitCamera.pivotPoint = new Vec3(0, 5, 0); // Create an Entity for the ground const material = new StandardMaterial(); diff --git a/examples/src/examples/graphics/particles-snow.example.mjs b/examples/src/examples/graphics/particles-snow.example.mjs index 70f9a41bc46..8964657f69a 100644 --- a/examples/src/examples/graphics/particles-snow.example.mjs +++ b/examples/src/examples/graphics/particles-snow.example.mjs @@ -18,9 +18,11 @@ import { ScriptHandler, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -28,7 +30,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), snowflake: new Asset('snowflake', 'texture', { url: './assets/textures/snowflake.png' }, { srgb: true }) }; @@ -81,17 +82,8 @@ cameraEntity.addComponent('camera', { cameraEntity.rotateLocal(0, 0, 0); cameraEntity.translateLocal(0, 7, 10); -// Add orbit camera script with a mouse and a touch support +// Add camera controls cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 190, - frameOnStart: false - } -}); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); // Create a directional light const lightDirEntity = new Entity(); @@ -106,6 +98,14 @@ lightDirEntity.setLocalEulerAngles(45, 0, 0); app.root.addChild(cameraEntity); app.root.addChild(lightDirEntity); +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 190) + } +}); + // Set up random downwards velocity from -0.4 to -0.7 const velocityCurve = new CurveSet([ [0, 0], // x diff --git a/examples/src/examples/graphics/post-processing.example.mjs b/examples/src/examples/graphics/post-processing.example.mjs index a733a3d2875..9a4a9b4e13d 100644 --- a/examples/src/examples/graphics/post-processing.example.mjs +++ b/examples/src/examples/graphics/post-processing.example.mjs @@ -42,11 +42,13 @@ import { TextureHandler, TouchDevice, Vec2, + Vec3, Vec4, WasmModule, createGraphicsDevice, math } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -61,7 +63,6 @@ WasmModule.setConfig('DracoDecoderModule', { }); const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), platform: new Asset('statue', 'container', { url: './assets/models/scifi-platform.glb' }), mosquito: new Asset('mosquito', 'container', { url: './assets/models/MosquitoInAmber.glb' }), font: new Asset('font', 'font', { url: './assets/fonts/arial.json' }), @@ -186,24 +187,19 @@ cameraEntity.addComponent('camera', { fov: 80 }); -// Add orbit camera script with a mouse and a touch support +cameraEntity.setLocalPosition(-0.072, 37.641, -193.528); +cameraEntity.lookAt(0, 0, 100); cameraEntity.addComponent('script'); +app.root.addChild(cameraEntity); -// Add orbit camera script with a mouse and a touch support -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: mosquitoEntity, - distanceMax: 190, - frameOnStart: false +// Add camera controls +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(-0.588, 20.778, -4.279), + enableFly: false, + zoomRange: new Vec2(0.01, 190) } }); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); - -cameraEntity.setLocalPosition(0, 40, -220); -cameraEntity.lookAt(0, 0, 100); -app.root.addChild(cameraEntity); // Create a 2D screen to place UI on const screen = new Entity(); diff --git a/examples/src/examples/graphics/reflection-box.example.mjs b/examples/src/examples/graphics/reflection-box.example.mjs index 4cec956a21f..91f4f3e9406 100644 --- a/examples/src/examples/graphics/reflection-box.example.mjs +++ b/examples/src/examples/graphics/reflection-box.example.mjs @@ -27,9 +27,11 @@ import { Texture, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -41,7 +43,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script1: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), script2: new Asset('script', 'script', { url: './scripts/utils/cubemap-renderer.js' }), normal: new Asset('normal', 'texture', { url: './assets/textures/normal-map.png' }) }; @@ -289,18 +290,16 @@ camera.addComponent('camera', { }); camera.setLocalPosition(270, 90, -260); -// Add orbit camera script with a mouse and a touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 390, - frameOnStart: false +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 390) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); // Create a probe object with cubemapRenderer script which takes care of rendering dynamic cubemap const probe = new Entity('probeCamera'); diff --git a/examples/src/examples/graphics/render-to-texture.example.mjs b/examples/src/examples/graphics/render-to-texture.example.mjs index cb23bf15225..a6d1b843f67 100644 --- a/examples/src/examples/graphics/render-to-texture.example.mjs +++ b/examples/src/examples/graphics/render-to-texture.example.mjs @@ -30,9 +30,11 @@ import { Texture, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -55,8 +57,7 @@ const assets = { { url: './assets/cubemaps/helipad-env-atlas.png' }, { type: TEXTURETYPE_RGBP, mipmaps: false } ), - checkerboard: new Asset('checkerboard', 'texture', { url: './assets/textures/checkboard.png' }, { srgb: true }), - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + checkerboard: new Asset('checkerboard', 'texture', { url: './assets/textures/checkboard.png' }, { srgb: true }) }; const gfxOptions = { @@ -245,18 +246,15 @@ camera.translate(0, 9, 15); camera.lookAt(1, 4, 0); app.root.addChild(camera); -// Add orbit camera script with a mouse and a touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: plane, - distanceMax: 20, - frameOnStart: false +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(1, 4, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 20) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); // Create texture camera, which renders entities in world and skybox layers into the texture const textureCamera = new Entity('TextureCamera'); diff --git a/examples/src/examples/graphics/shadow-cascades.example.mjs b/examples/src/examples/graphics/shadow-cascades.example.mjs index 8108c7cf3ef..d1ddcc2d5d1 100644 --- a/examples/src/examples/graphics/shadow-cascades.example.mjs +++ b/examples/src/examples/graphics/shadow-cascades.example.mjs @@ -30,8 +30,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -39,7 +42,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), terrain: new Asset('terrain', 'container', { url: './assets/models/terrain.glb' }), helipad: new Asset( 'helipad-env-atlas', @@ -146,9 +148,7 @@ srcClouds.forEach((cloud) => { // Shuffle the array to give clouds random order clouds.sort(() => Math.random() - 0.5); -// Find a tree in the middle to use as a focus point // @ts-ignore -const tree = terrain.findOne('name', 'Arbol 2.002'); // Create an Entity with a camera component const camera = new Entity(); @@ -163,16 +163,16 @@ camera.setLocalPosition(300, 160, 25); // Add orbit camera script with a mouse and a touch support camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: tree, - distanceMax: 1800 - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(-4.473, 37.152, 27.631), + zoomRange: new Vec2(0.01, 1800), + enableFly: false + } + }) +); // Create a directional light casting cascaded shadows const { everyFrame, ...lightSettings } = data.get('settings.light'); @@ -217,8 +217,8 @@ app.on('update', (/** @type {number} */ dt) => { // On the first frame, when camera is updated, move it further away from the focus tree if (frameNumber === 0) { - // @ts-ignore engine-tsd - camera.script.orbitCamera.distance = 470; + // match the original orbit-camera framing of the focus tree + cameraControls.reset(new Vec3(-4.473, 37.152, 27.631), new Vec3(430.891, 212.811, 23.869)); } if (updateEveryFrame) { diff --git a/examples/src/examples/graphics/shadow-catcher.example.mjs b/examples/src/examples/graphics/shadow-catcher.example.mjs index d0cda69f3b4..59d8cde4caf 100644 --- a/examples/src/examples/graphics/shadow-catcher.example.mjs +++ b/examples/src/examples/graphics/shadow-catcher.example.mjs @@ -33,9 +33,11 @@ import { TONEMAP_NONE, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { ShadowCatcher } from 'playcanvas/scripts/esm/shadow-catcher.mjs'; import { data, deviceType } from 'examples/context'; @@ -44,7 +46,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), statue: new Asset('statue', 'container', { url: './assets/models/statue.glb' }), hdri_street: new Asset('hdri', 'texture', { url: './assets/hdri/st-peters-square.hdr' }, { mipmaps: false }) }; @@ -116,24 +117,21 @@ cameraEntity.addComponent('camera', { gammaCorrection: GAMMA_SRGB }); -// Add orbit camera script with a mouse and a touch support -cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: statueEntity, - distanceMax: 500, - frameOnStart: false - } -}); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); - // Position the camera in the world cameraEntity.setLocalPosition(35, 12, -17); cameraEntity.lookAt(0, 0, 1); +cameraEntity.addComponent('script'); app.root.addChild(cameraEntity); +// Add camera controls +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 1), + enableFly: false, + zoomRange: new Vec2(0.01, 500) + } +}); + // Apply hdri texture const applyHdri = (source) => { // Convert it to high resolution cubemap for the skybox diff --git a/examples/src/examples/graphics/shadow-soft.example.mjs b/examples/src/examples/graphics/shadow-soft.example.mjs index 9ddc4171131..69aec1b713b 100644 --- a/examples/src/examples/graphics/shadow-soft.example.mjs +++ b/examples/src/examples/graphics/shadow-soft.example.mjs @@ -30,8 +30,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -39,7 +42,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), terrain: new Asset('terrain', 'container', { url: './assets/models/terrain.glb' }), helipad: new Asset( 'helipad-env-atlas', @@ -153,9 +155,6 @@ pillar.setLocalScale(10, 130, 10); pillar.setLocalPosition(180, 50, 110); app.root.addChild(pillar); -// Find a tree in the middle to use as a focus point -const tree = terrain.findOne('name', 'Arbol 2.002'); - // Create an Entity with a camera component const camera = new Entity(); camera.addComponent('camera', { @@ -169,16 +168,16 @@ camera.setLocalPosition(-500, 160, 300); // Add orbit camera script with a mouse and a touch support camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: tree, - distanceMax: 600 - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(-4.473, 37.152, 27.631), + zoomRange: new Vec2(0.01, 600), + enableFly: false + } + }) +); // Create a directional light casting soft shadows const { soft: softShadows, ...lightSettings } = data.get('settings.light'); @@ -219,8 +218,8 @@ app.on('update', (/** @type {number} */ dt) => { // On the first frame, when camera is updated, move it further away from the focus tree if (frameNumber === 0) { - // @ts-ignore engine-tsd - camera.script.orbitCamera.distance = 470; + // match the original orbit-camera framing of the focus tree + cameraControls.reset(new Vec3(-4.473, 37.152, 27.631), new Vec3(-406.258, 136.76, 248.474)); } // Move the clouds around diff --git a/examples/src/examples/graphics/sky.example.mjs b/examples/src/examples/graphics/sky.example.mjs index 8b59ef88d39..ff50513de35 100644 --- a/examples/src/examples/graphics/sky.example.mjs +++ b/examples/src/examples/graphics/sky.example.mjs @@ -38,9 +38,11 @@ import { TONEMAP_NONE, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -48,7 +50,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), statue: new Asset('statue', 'container', { url: './assets/models/statue.glb' }), hdri_street: new Asset('hdri', 'texture', { url: './assets/hdri/wide-street.hdr' }, { mipmaps: false }), hdri_room: new Asset('hdri', 'texture', { url: './assets/hdri/empty-room.hdr' }, { mipmaps: false }) @@ -107,24 +108,21 @@ cameraEntity.addComponent('camera', { gammaCorrection: GAMMA_SRGB }); -// Add orbit camera script with a mouse and a touch support -cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: statueEntity, - distanceMax: 500, - frameOnStart: false - } -}); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); - // Position the camera in the world cameraEntity.setLocalPosition(-4, 5, 22); cameraEntity.lookAt(0, 0, 1); +cameraEntity.addComponent('script'); app.root.addChild(cameraEntity); +// Add camera controls +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0.173, 7.523, 0.018), + enableFly: false, + zoomRange: new Vec2(0.01, 500) + } +}); + // ------ Custom render passes set up ------ const cameraFrame = new CameraFrame(app, cameraEntity.camera); cameraFrame.update(); diff --git a/examples/src/examples/graphics/taa.example.mjs b/examples/src/examples/graphics/taa.example.mjs index 9ac8158585c..4fdd5410463 100644 --- a/examples/src/examples/graphics/taa.example.mjs +++ b/examples/src/examples/graphics/taa.example.mjs @@ -27,8 +27,10 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -36,7 +38,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), house: new Asset('house', 'container', { url: './assets/models/pbr-house.glb' }), cube: new Asset('cube', 'container', { url: './assets/models/playcanvas-cube.glb' }), envatlas: new Asset( @@ -108,21 +109,17 @@ cameraEntity.addComponent('camera', { fov: 80 }); -// Add orbit camera script with a mouse and a touch support +// Add camera controls with a mouse and a touch support +cameraEntity.setLocalPosition(0, 40, -220); cameraEntity.addComponent('script'); -cameraEntity.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: houseEntity, - distanceMax: 400, - frameOnStart: true +app.root.addChild(cameraEntity); +cameraEntity.script.create(CameraControls, { + properties: { + focusPoint: houseEntity.getPosition(), + zoomRange: new Vec2(0.01, 400), + enableFly: false } }); -cameraEntity.script.create('orbitCameraInputMouse'); -cameraEntity.script.create('orbitCameraInputTouch'); -cameraEntity.setLocalPosition(0, 40, -220); -cameraEntity.lookAt(0, 0, 100); -app.root.addChild(cameraEntity); // Add a shadow casting directional light const lightColor = new Color(1, 1, 1); diff --git a/examples/src/examples/graphics/volumetric-fog-local-lights.example.mjs b/examples/src/examples/graphics/volumetric-fog-local-lights.example.mjs index c979dd5a736..328cba86cea 100644 --- a/examples/src/examples/graphics/volumetric-fog-local-lights.example.mjs +++ b/examples/src/examples/graphics/volumetric-fog-local-lights.example.mjs @@ -31,9 +31,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -41,7 +43,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), terrain: new Asset('terrain', 'container', { url: './assets/models/terrain.glb' }), helipad: new Asset( 'helipad-env-atlas', @@ -169,9 +170,6 @@ pillar.setLocalScale(10, 130, 10); pillar.setLocalPosition(180, 50, 110); app.root.addChild(pillar); -// Find a tree in the middle to use as a focus point -const tree = terrain.findOne('name', 'Arbol 2.002'); - // Create an Entity with a camera component const camera = new Entity(); camera.addComponent('camera', { @@ -184,16 +182,16 @@ camera.setLocalPosition(-500, 160, 300); // Add orbit camera script with a mouse and a touch support camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: tree, - distanceMax: 600 - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(-4.473, 37.152, 27.631), + zoomRange: new Vec2(0.01, 600), + enableFly: false + } + }) +); // A dim directional light acting as the moon, still casting long shafts through the fog const dirLight = new Entity('MainLight'); @@ -321,12 +319,8 @@ app.on('update', (/** @type {number} */ dt) => { // On the first frame, when camera is updated, frame the view over the lit valley if (frameNumber === 0) { - // @ts-ignore engine-tsd - camera.script.orbitCamera.distance = 470; - // @ts-ignore engine-tsd - camera.script.orbitCamera.yaw = 304; - // @ts-ignore engine-tsd - camera.script.orbitCamera.pitch = -6; + // match the original orbit-camera framing of the focus tree + cameraControls.reset(new Vec3(-4.473, 37.152, 27.631), new Vec3(-373.493, 86.582, 273.753)); } // Move the clouds around diff --git a/examples/src/examples/graphics/volumetric-fog.example.mjs b/examples/src/examples/graphics/volumetric-fog.example.mjs index 3f4d5ce1d82..6122cc1d3f8 100644 --- a/examples/src/examples/graphics/volumetric-fog.example.mjs +++ b/examples/src/examples/graphics/volumetric-fog.example.mjs @@ -31,8 +31,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -40,7 +43,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), terrain: new Asset('terrain', 'container', { url: './assets/models/terrain.glb' }), helipad: new Asset( 'helipad-env-atlas', @@ -165,9 +167,6 @@ pillar.setLocalScale(10, 130, 10); pillar.setLocalPosition(180, 50, 110); app.root.addChild(pillar); -// Find a tree in the middle to use as a focus point -const tree = terrain.findOne('name', 'Arbol 2.002'); - // Create an Entity with a camera component const camera = new Entity(); camera.addComponent('camera', { @@ -180,16 +179,16 @@ camera.setLocalPosition(-500, 160, 300); // Add orbit camera script with a mouse and a touch support camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: tree, - distanceMax: 600 - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(-4.473, 37.152, 27.631), + zoomRange: new Vec2(0.01, 600), + enableFly: false + } + }) +); // Create a directional light casting soft shadows, positioned low above the horizon so the // terrain, trees and clouds cast long shafts through the fog @@ -258,12 +257,8 @@ app.on('update', (/** @type {number} */ dt) => { // On the first frame, when camera is updated, frame the view looking towards the low sun, // where the light shafts through the fog are the most visible if (frameNumber === 0) { - // @ts-ignore engine-tsd - camera.script.orbitCamera.distance = 420; - // @ts-ignore engine-tsd - camera.script.orbitCamera.yaw = 304; - // @ts-ignore engine-tsd - camera.script.orbitCamera.pitch = -5; + // match the original orbit-camera framing of the focus tree + cameraControls.reset(new Vec3(-4.473, 37.152, 27.631), new Vec3(-348.027, 74.002, 258.829)); } // Move the clouds around diff --git a/examples/src/examples/materials/anisotropy-disc.example.mjs b/examples/src/examples/materials/anisotropy-disc.example.mjs index 4daaf0bb7c7..ca3ae3a7556 100644 --- a/examples/src/examples/materials/anisotropy-disc.example.mjs +++ b/examples/src/examples/materials/anisotropy-disc.example.mjs @@ -25,8 +25,10 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -34,7 +36,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -96,22 +97,20 @@ leftEntity.setPosition(0, 0, 1); leftEntity.setLocalScale(0.8, 0.8, 0.8); app.root.addChild(leftEntity); -// Create a camera with an orbit camera script +// Create a camera with camera controls, viewing from the side (yaw 90) at a distance of 6 const camera = new Entity(); camera.addComponent('camera', { toneMapping: TONEMAP_ACES }); +camera.setLocalPosition(5.859, -2.428, 0.422); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0.553, 0.958, 1.424), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); -camera.script.orbitCamera.yaw = 90; -camera.script.orbitCamera.distance = 6; const directionalLight = new Entity(); directionalLight.addComponent('light', { diff --git a/examples/src/examples/materials/anisotropy-lamp.example.mjs b/examples/src/examples/materials/anisotropy-lamp.example.mjs index 07db5ae879e..93d8feef01c 100644 --- a/examples/src/examples/materials/anisotropy-lamp.example.mjs +++ b/examples/src/examples/materials/anisotropy-lamp.example.mjs @@ -25,8 +25,10 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -34,7 +36,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -103,20 +104,18 @@ leftEntity.setPosition(0, 0, 1); leftEntity.setLocalScale(0.8, 0.8, 0.8); app.root.addChild(leftEntity); -// Create a camera with an orbit camera script +// Create a camera with camera controls, viewing from the side (yaw 90) at a distance of 0.3 const camera = new Entity(); camera.addComponent('camera', { toneMapping: TONEMAP_ACES }); +camera.setLocalPosition(0.3, 0, 1); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 1), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); -camera.script.orbitCamera.yaw = 90; -camera.script.orbitCamera.distance = 0.3; camera.camera.requestSceneColorMap(true); diff --git a/examples/src/examples/materials/anisotropy-rotation.example.mjs b/examples/src/examples/materials/anisotropy-rotation.example.mjs index 2cfd27a5a95..fe325a1013d 100644 --- a/examples/src/examples/materials/anisotropy-rotation.example.mjs +++ b/examples/src/examples/materials/anisotropy-rotation.example.mjs @@ -25,8 +25,10 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -34,7 +36,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -96,22 +97,20 @@ leftEntity.setPosition(0, 0, 1); leftEntity.setLocalScale(0.8, 0.8, 0.8); app.root.addChild(leftEntity); -// Create a camera with an orbit camera script +// Create a camera with camera controls, viewing from the side (yaw 90) at a distance of 12 const camera = new Entity(); camera.addComponent('camera', { toneMapping: TONEMAP_ACES }); +camera.setLocalPosition(9.939, 6.476, -9.387); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, -0.265, 0.552), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); -camera.script.orbitCamera.yaw = 90; -camera.script.orbitCamera.distance = 12; const directionalLight = new Entity(); directionalLight.addComponent('light', { diff --git a/examples/src/examples/materials/anisotropy-strength.example.mjs b/examples/src/examples/materials/anisotropy-strength.example.mjs index 39f1c507597..06e6212e37e 100644 --- a/examples/src/examples/materials/anisotropy-strength.example.mjs +++ b/examples/src/examples/materials/anisotropy-strength.example.mjs @@ -25,8 +25,10 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -34,7 +36,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -96,22 +97,20 @@ leftEntity.setPosition(0, 0, 1); leftEntity.setLocalScale(0.8, 0.8, 0.8); app.root.addChild(leftEntity); -// Create a camera with an orbit camera script +// Create a camera with camera controls, viewing from the side (yaw 90) at a distance of 12 const camera = new Entity(); camera.addComponent('camera', { toneMapping: TONEMAP_ACES }); +camera.setLocalPosition(10.518, -6.17, 1.301); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(1.508, 1.756, 1.308), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); -camera.script.orbitCamera.yaw = 90; -camera.script.orbitCamera.distance = 12; const directionalLight = new Entity(); directionalLight.addComponent('light', { diff --git a/examples/src/examples/materials/clear-coat.example.mjs b/examples/src/examples/materials/clear-coat.example.mjs index 3ac2a44a53d..63eba71c607 100644 --- a/examples/src/examples/materials/clear-coat.example.mjs +++ b/examples/src/examples/materials/clear-coat.example.mjs @@ -25,8 +25,10 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -34,7 +36,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -96,22 +97,20 @@ leftEntity.setPosition(0, 0, 1); leftEntity.setLocalScale(0.8, 0.8, 0.8); app.root.addChild(leftEntity); -// Create a camera with an orbit camera script +// Create a camera with camera controls, viewing the model from the side (yaw 90) at a distance of 12 const camera = new Entity(); camera.addComponent('camera', { toneMapping: TONEMAP_ACES }); +camera.setLocalPosition(12.632, -0.843, 1.948); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0.396, 0.242, 2.703), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); -camera.script.orbitCamera.yaw = 90; -camera.script.orbitCamera.distance = 12; const directionalLight = new Entity(); directionalLight.addComponent('light', { diff --git a/examples/src/examples/materials/dispersion.example.mjs b/examples/src/examples/materials/dispersion.example.mjs index a5cb7cc0316..4a455a259ed 100644 --- a/examples/src/examples/materials/dispersion.example.mjs +++ b/examples/src/examples/materials/dispersion.example.mjs @@ -19,8 +19,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -28,7 +31,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), model: new Asset('cube', 'container', { url: './assets/models/dispersion-test.glb' }), helipad: new Asset( 'helipad-env-atlas', @@ -100,16 +102,14 @@ camera.addComponent('camera', { // The color grab pass is needed camera.camera.requestSceneColorMap(true); -// Adjust the camera position -camera.translate(0, 0.3, 1); - +// position the camera close to the small model (was orbitCamera distanceMax 0.15) +camera.setLocalPosition(0, 0.043, 0.144); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 0.15 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + zoomRange: new Vec2(0.01, 0.15), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); diff --git a/examples/src/examples/materials/lit-material.example.mjs b/examples/src/examples/materials/lit-material.example.mjs index 5e68498483b..94162e27d69 100644 --- a/examples/src/examples/materials/lit-material.example.mjs +++ b/examples/src/examples/materials/lit-material.example.mjs @@ -26,8 +26,11 @@ import { TEXTURETYPE_RGBP, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -35,7 +38,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -97,19 +99,17 @@ const camera = new Entity(); camera.addComponent('camera', { clearColor: new Color(0.4, 0.45, 0.5) }); -camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMin: 2, - distanceMax: 15 - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); camera.translate(0, 1, 4); camera.lookAt(0, 0, 0); +camera.addComponent('script'); app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + zoomRange: new Vec2(2, 15), + enableFly: false + } +}); // Create an Entity with a omni light component and a sphere model component. const light = new Entity(); diff --git a/examples/src/examples/materials/normals-and-tangents.example.mjs b/examples/src/examples/materials/normals-and-tangents.example.mjs index ea60df0cbfb..772c0566a6a 100644 --- a/examples/src/examples/materials/normals-and-tangents.example.mjs +++ b/examples/src/examples/materials/normals-and-tangents.example.mjs @@ -29,8 +29,10 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -38,7 +40,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -100,23 +101,20 @@ leftEntity.setPosition(0, 0, 1); leftEntity.setLocalScale(0.8, 0.8, 0.8); app.root.addChild(leftEntity); -// Create a camera with an orbit camera script +// Create a camera with camera controls, viewing from the side (yaw 90) at a distance of 3 const camera = new Entity(); camera.addComponent('camera', { toneMapping: TONEMAP_ACES }); +camera.setLocalPosition(3, 0, 1); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 1), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); -camera.script.orbitCamera.pitch = 0; -camera.script.orbitCamera.yaw = 90; -camera.script.orbitCamera.distance = 3; const directionalLight = new Entity(); directionalLight.addComponent('light', { diff --git a/examples/src/examples/materials/transmission-roughness.example.mjs b/examples/src/examples/materials/transmission-roughness.example.mjs index cbeb1ed81b7..fef3e4d01ef 100644 --- a/examples/src/examples/materials/transmission-roughness.example.mjs +++ b/examples/src/examples/materials/transmission-roughness.example.mjs @@ -26,8 +26,10 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -35,7 +37,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -101,7 +102,7 @@ modelEntity.setPosition(0, 0, 0); modelEntity.setLocalScale(1, 1, 1); app.root.addChild(modelEntity); -// Create a camera with an orbit camera script +// Create a camera with camera controls, viewing from the side (yaw 90) at a distance of 2 const camera = new Entity(); camera.addComponent('camera', { clearColor: new Color(0.1, 0.1, 0.1), @@ -111,17 +112,15 @@ camera.addComponent('camera', { // The color grab pass is needed for transmission effects camera.camera.requestSceneColorMap(true); +camera.setLocalPosition(2, 0, 0); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); -camera.script.orbitCamera.yaw = 90; -camera.script.orbitCamera.distance = 2; // Add a directional light const directionalLight = new Entity(); diff --git a/examples/src/examples/shaders/ground-fog.example.mjs b/examples/src/examples/shaders/ground-fog.example.mjs index 936b4f38ec4..075395853bf 100644 --- a/examples/src/examples/shaders/ground-fog.example.mjs +++ b/examples/src/examples/shaders/ground-fog.example.mjs @@ -36,8 +36,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -50,7 +53,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), terrain: new Asset('terrain', 'container', { url: './assets/models/terrain.glb' }), helipad: new Asset( 'helipad-env-atlas', @@ -119,9 +121,6 @@ const terrain = assets.terrain.resource.instantiateRenderEntity(); terrain.setLocalScale(30, 30, 30); app.root.addChild(terrain); -// Find a tree in the middle to use as a focus point -const tree = terrain.findOne('name', 'Arbol 2.002'); - // Create an Entity with a camera component const camera = new Entity(); camera.addComponent('camera', { @@ -133,18 +132,18 @@ camera.addComponent('camera', { // and position it in the world camera.setLocalPosition(-200, 120, 225); -// Add orbit camera script with a mouse and a touch support +// Add camera controls with a mouse and a touch support camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: tree, - distanceMax: 600 - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(-4.473, 37.152, 27.631), + zoomRange: new Vec2(0.01, 600), + enableFly: false + } + }) +); // Enable the camera to render the scene's depth map. camera.camera.requestSceneDepthMap(true); @@ -201,11 +200,11 @@ app.root.addChild(ground); let firstFrame = true; let currentTime = 0; app.on('update', (dt) => { - // On the first frame, when camera is updated, move it further away from the focus tree + // On the first frame, move the camera to a fixed distance from the tree along its view direction if (firstFrame) { firstFrame = false; - // @ts-ignore engine-tsd - camera.script.orbitCamera.distance = 320; + // match the original orbit-camera framing of the focus tree + cameraControls.reset(new Vec3(-4.473, 37.152, 27.631), new Vec3(-220.064, 128.502, 245.253)); } // Update the time and pass it to shader diff --git a/examples/src/examples/shaders/shader-hatch.example.mjs b/examples/src/examples/shaders/shader-hatch.example.mjs index e6a2f9f8d37..dee75997f5c 100644 --- a/examples/src/examples/shaders/shader-hatch.example.mjs +++ b/examples/src/examples/shaders/shader-hatch.example.mjs @@ -46,10 +46,12 @@ import { ScriptHandler, TextureHandler, TouchDevice, + Vec2, Vec3, WasmModule, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { createHatchMaterial } from 'examples/assets/scripts/misc/hatch-material.mjs'; import { data, deviceType } from 'examples/context'; @@ -65,7 +67,6 @@ WasmModule.setConfig('DracoDecoderModule', { }); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), board: new Asset('board', 'container', { url: './assets/models/chess-board.glb' }), bitmoji: new Asset('model', 'container', { url: './assets/models/bitmoji.glb' }), @@ -217,20 +218,18 @@ const camera = new Entity(); camera.addComponent('camera', { clearColor: new Color(0.4, 0.45, 0.5) }); -camera.setLocalPosition(30, 30, 30); +camera.setLocalPosition(140.015, 85.42, 204.068); // Add orbit camera script to the camera camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: entity, - distanceMax: 250 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(11.039, 20.449, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 250) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); // Update things each frame let time = 0; diff --git a/examples/src/examples/shaders/shader-material-shadows.example.mjs b/examples/src/examples/shaders/shader-material-shadows.example.mjs index 9d2a354731a..e80a1c00b6b 100644 --- a/examples/src/examples/shaders/shader-material-shadows.example.mjs +++ b/examples/src/examples/shaders/shader-material-shadows.example.mjs @@ -43,8 +43,11 @@ import { Texture, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { createHatchMaterial } from 'examples/assets/scripts/misc/hatch-material.mjs'; import { data, deviceType } from 'examples/context'; @@ -53,8 +56,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), - bitmoji: new Asset('model', 'container', { url: './assets/models/bitmoji.glb' }), danceAnim: new Asset('danceAnim', 'container', { url: './assets/animations/bitmoji/win-dance.glb' }), morph: new Asset('glb', 'container', { url: './assets/models/morph-stress-test.glb' }), @@ -268,16 +269,14 @@ camera.setLocalEulerAngles(-23.69, -49.15, 0); // Add orbit camera script to the camera camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: bitmojiEntity, - distanceMax: 100 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 100) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); // Handle UI changes data.on('*:set', (path, value) => { diff --git a/examples/src/examples/shaders/texture-array.example.mjs b/examples/src/examples/shaders/texture-array.example.mjs index 6d7aab46221..805bbf33718 100644 --- a/examples/src/examples/shaders/texture-array.example.mjs +++ b/examples/src/examples/shaders/texture-array.example.mjs @@ -30,8 +30,11 @@ import { TextureHandler, TorusGeometry, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -108,8 +111,7 @@ const assets = { 'texture', { url: './assets/textures/aerial_rocks_02_diff_1k.jpg' }, { srgb: true } - ), - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + ) }; const gfxOptions = { @@ -264,23 +266,22 @@ camera.addComponent('camera', { }); // Adjust the camera position -camera.translate(3, -2, 4); +camera.setLocalPosition(5.099, 0.169, 6.799); camera.lookAt(0, 0, 0); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, // Override default of 0 (no inertia), - distanceMax: 10.0 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, -5.1, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 10) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); // Add the new Entities to the hierarchy app.root.addChild(light); app.root.addChild(shape); -app.root.addChild(camera); // Set an update function on the app's update event let angle = 0; diff --git a/examples/src/examples/test/attenuation.example.mjs b/examples/src/examples/test/attenuation.example.mjs index e38e37e479d..949f5614b76 100644 --- a/examples/src/examples/test/attenuation.example.mjs +++ b/examples/src/examples/test/attenuation.example.mjs @@ -23,8 +23,10 @@ import { TONEMAP_LINEAR, TextureHandler, TouchDevice, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -32,7 +34,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -95,17 +96,15 @@ camera.addComponent('camera', { toneMapping: TONEMAP_LINEAR }); camera.camera.requestSceneColorMap(true); +camera.setLocalPosition(24, 0, 1); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 1), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); -camera.script.orbitCamera.yaw = 90; -camera.script.orbitCamera.distance = 24; // Test with camera frame which uses linear rendering const cameraFrame = false; diff --git a/examples/src/examples/test/contact-hardening-shadows.example.mjs b/examples/src/examples/test/contact-hardening-shadows.example.mjs index e20d4ef702a..489f7171625 100644 --- a/examples/src/examples/test/contact-hardening-shadows.example.mjs +++ b/examples/src/examples/test/contact-hardening-shadows.example.mjs @@ -38,10 +38,12 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, Vec3, WasmModule, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType, win } from 'examples/context'; @@ -59,7 +61,6 @@ await new Promise((resolve) => { }); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -283,17 +284,16 @@ camera.setLocalPosition(0, 5, 11); camera.camera.requestSceneColorMap(true); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: occluder, - distanceMax: 500, - frameOnStart: false - } -}); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); app.root.addChild(camera); +const cameraControls = /** @type {CameraControls} */ ( + camera.script.create(CameraControls, { + properties: { + focusPoint: occluder.getPosition(), + zoomRange: new Vec2(0.01, 500), + enableFly: false + } + }) +); data.on('*:set', (/** @type {string} */ path, value) => { switch (path) { @@ -348,8 +348,9 @@ let timeDiff = 0; let index = 0; app.on('update', (dt) => { if (time === 0) { - // @ts-ignore engine-tsd - camera.script.orbitCamera.distance = 25; + const focus = occluder.getPosition(); + const dir = camera.getPosition().clone().sub(focus).normalize(); + cameraControls.reset(focus, focus.clone().add(dir.mulScalar(25))); } timeDiff += dt; diff --git a/examples/src/examples/test/global-shader-properties.example.mjs b/examples/src/examples/test/global-shader-properties.example.mjs index 35468417a47..a69d8059190 100644 --- a/examples/src/examples/test/global-shader-properties.example.mjs +++ b/examples/src/examples/test/global-shader-properties.example.mjs @@ -39,8 +39,11 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { createGoochMaterial } from 'examples/assets/scripts/misc/gooch-material.mjs'; import { data, deviceType } from 'examples/context'; @@ -49,7 +52,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), terrain: new Asset('terrain', 'container', { url: './assets/models/terrain.glb' }), biker: new Asset('gsplat', 'gsplat', { url: './assets/splats/biker.compressed.ply' }), helipad: new Asset( @@ -245,17 +247,16 @@ camera.addComponent('camera', { // and position it in the world camera.setLocalPosition(-500, 60, 300); -// Add orbit camera script with a mouse and a touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMax: 500 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 500) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); // Create a directional light casting soft shadows const dirLight = new Entity('Cascaded Light'); diff --git a/examples/src/examples/test/opacity.example.mjs b/examples/src/examples/test/opacity.example.mjs index b557a6fd7c0..d49e81cc9d6 100644 --- a/examples/src/examples/test/opacity.example.mjs +++ b/examples/src/examples/test/opacity.example.mjs @@ -29,8 +29,11 @@ import { StandardMaterial, TextureHandler, TouchDevice, + Vec2, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -38,7 +41,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), font: new Asset('font', 'font', { url: './assets/fonts/arial.json' }), rocks: new Asset( 'rocks', @@ -98,19 +100,16 @@ camera.addComponent('camera', { }); camera.translate(10, 6, 22); -// Add orbit camera script with a mouse and a touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - distanceMin: 12, - distanceMax: 100 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(12, 100) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); - -app.root.addChild(camera); const NUM_BOXES = 5; diff --git a/examples/src/examples/test/primitive-mode.example.mjs b/examples/src/examples/test/primitive-mode.example.mjs index 27cd42c63db..9989ce8ef8b 100644 --- a/examples/src/examples/test/primitive-mode.example.mjs +++ b/examples/src/examples/test/primitive-mode.example.mjs @@ -27,8 +27,10 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -36,7 +38,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -95,22 +96,20 @@ const testEntity = assets.model.resource.instantiateRenderEntity(); testEntity.setLocalEulerAngles(0, 90, 0); app.root.addChild(testEntity); -// Create a camera with an orbit camera script +// Create a camera with camera controls, viewing from the side (yaw 90) at a distance of 25 const camera = new Entity(); camera.addComponent('camera', { toneMapping: TONEMAP_ACES }); +camera.setLocalPosition(25, 0, 0); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); -camera.script.orbitCamera.yaw = 90; -camera.script.orbitCamera.distance = 25; const directionalLight = new Entity(); directionalLight.addComponent('light', { diff --git a/examples/src/examples/test/specular.example.mjs b/examples/src/examples/test/specular.example.mjs index ee5bdf0dc7b..bc3041be61a 100644 --- a/examples/src/examples/test/specular.example.mjs +++ b/examples/src/examples/test/specular.example.mjs @@ -33,8 +33,10 @@ import { TONEMAP_ACES, TextureHandler, TouchDevice, + Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -42,7 +44,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - orbitCamera: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), helipad: new Asset( 'helipad-env-atlas', 'texture', @@ -103,18 +104,15 @@ camera.addComponent('camera', { clearColor: new Color(0.1, 0.1, 0.1), toneMapping: TONEMAP_ACES }); +camera.setLocalPosition(-0.174, 0, 2.206); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: testEntity +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(-0.188, 0, 0), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); -camera.script.orbitCamera.pitch = 0; -camera.script.orbitCamera.yaw = 0; const directionalLight = new Entity(); directionalLight.addComponent('light', { diff --git a/examples/src/examples/test/taa-alpha.example.mjs b/examples/src/examples/test/taa-alpha.example.mjs index ab9fc6a52ed..157e85aef8f 100644 --- a/examples/src/examples/test/taa-alpha.example.mjs +++ b/examples/src/examples/test/taa-alpha.example.mjs @@ -8,7 +8,6 @@ import { ADDRESS_CLAMP_TO_EDGE, AppBase, AppOptions, - Asset, AssetListLoader, BLEND_NORMAL, CULLFACE_NONE, @@ -35,9 +34,11 @@ import { Texture, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { data, deviceType } from 'examples/context'; @@ -48,9 +49,7 @@ import { data, deviceType } from 'examples/context'; const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('application-canvas')); window.focus(); -const assets = { - orbit: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) -}; +const assets = {}; const vertGLSL = /* glsl */ ` attribute vec3 vertex_position; @@ -282,16 +281,13 @@ app.root.addChild(sceneCamera); sceneCamera.setLocalPosition(300 * Math.sin(0.3), 150, 300 * Math.cos(0.3)); sceneCamera.addComponent('script'); -sceneCamera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: orbitFocus, - distanceMax: 1200, - frameOnStart: false +sceneCamera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 35, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 1200) } }); -sceneCamera.script.create('orbitCameraInputMouse'); -sceneCamera.script.create('orbitCameraInputTouch'); const cameraFrame = new CameraFrame(app, sceneCamera.camera); cameraFrame.rendering.renderFormats = [PIXELFORMAT_RGBA8]; diff --git a/examples/src/examples/test/texture-ktx2-cubemap.example.mjs b/examples/src/examples/test/texture-ktx2-cubemap.example.mjs index a58a9fb2f09..f6d82967f25 100644 --- a/examples/src/examples/test/texture-ktx2-cubemap.example.mjs +++ b/examples/src/examples/test/texture-ktx2-cubemap.example.mjs @@ -29,9 +29,11 @@ import { TextureHandler, TouchDevice, TONEMAP_ACES, + Vec3, basisInitialize, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -55,8 +57,7 @@ const assets = { 'texture', { url: './assets/cubemaps/yokohama-cubemap.ktx2' }, { srgb: true } - ), - orbit: new Asset('orbit-camera', 'script', { url: './scripts/camera/orbit-camera.js' }) + ) }; const createOptions = new AppOptions(); @@ -114,16 +115,13 @@ camera.addComponent('camera', { }); camera.setPosition(0, 0, 3); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - focusEntity: sphere, - frameOnStart: false, - inertiaFactor: 0.2 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); app.start(); diff --git a/examples/src/examples/test/xr-views.example.mjs b/examples/src/examples/test/xr-views.example.mjs index 289961fe123..a5c5aa76485 100644 --- a/examples/src/examples/test/xr-views.example.mjs +++ b/examples/src/examples/test/xr-views.example.mjs @@ -36,9 +36,11 @@ import { Texture, TextureHandler, TouchDevice, + Vec2, Vec3, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -46,7 +48,6 @@ const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('applic window.focus(); const assets = { - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }), terrain: new Asset('terrain', 'container', { url: './assets/models/terrain.glb' }), helipad: new Asset( 'helipad-env-atlas', @@ -211,18 +212,16 @@ camera.addComponent('camera', { // and position it in the world camera.setLocalPosition(-500, 160, 300); -// Add orbit camera script with a mouse and a touch support +// Add camera controls camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2, - focusEntity: terrain, - distanceMax: 600 +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false, + zoomRange: new Vec2(0.01, 600) } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); // Create mock XR views using a loop. The number of views differs between backends because // each backend uses a different visualisation: diff --git a/examples/src/examples/user-interface/world-ui.example.mjs b/examples/src/examples/user-interface/world-ui.example.mjs index 69655d84d10..61b5a213aaa 100644 --- a/examples/src/examples/user-interface/world-ui.example.mjs +++ b/examples/src/examples/user-interface/world-ui.example.mjs @@ -25,9 +25,11 @@ import { TextureHandler, TouchDevice, Vec2, + Vec3, Vec4, createGraphicsDevice } from 'playcanvas'; +import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs'; import { deviceType } from 'examples/context'; @@ -36,8 +38,7 @@ window.focus(); const assets = { checkboard: new Asset('checkboard', 'texture', { url: './assets/textures/checkboard.png' }, { srgb: true }), - font: new Asset('font', 'font', { url: './assets/fonts/courier.json' }), - script: new Asset('script', 'script', { url: './scripts/camera/orbit-camera.js' }) + font: new Asset('font', 'font', { url: './assets/fonts/courier.json' }) }; const gfxOptions = { @@ -89,17 +90,15 @@ const camera = new Entity(); camera.addComponent('camera', { clearColor: new Color(30 / 255, 30 / 255, 30 / 255) }); -camera.rotateLocal(-30, 0, 0); -camera.translateLocal(0, 0, 7); +camera.setLocalPosition(0, 0.98, 1.697); camera.addComponent('script'); -camera.script.create('orbitCamera', { - attributes: { - inertiaFactor: 0.2 // Override default of 0 (no inertia) +app.root.addChild(camera); +camera.script.create(CameraControls, { + properties: { + focusPoint: new Vec3(0, 0, 0), + enableFly: false } }); -camera.script.create('orbitCameraInputMouse'); -camera.script.create('orbitCameraInputTouch'); -app.root.addChild(camera); // Create an Entity for the ground const material = new StandardMaterial();