UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in

102 lines (86 loc) 4.6 kB
import { PerspectiveCamera } from "three"; import { getCameraController } from "../engine/engine_camera.js"; import { addNewComponent, getOrAddComponent } from "../engine/engine_components.js"; import { Context } from "../engine/engine_context.js"; import { ContextEvent, ContextRegistry } from "../engine/engine_context_registry.js"; import { NeedleEngineHTMLElement } from "../engine/engine_element.js"; import type { ICamera, IContext } from "../engine/engine_types.js"; import { getParam } from "../engine/engine_utils.js"; import { RGBAColor } from "../engine/js-extensions/index.js"; import { Camera, ClearFlags } from "./Camera.js"; import { OrbitControls } from "./OrbitControls.js"; const debug = getParam("debugmissingcamera"); ContextRegistry.registerCallback(ContextEvent.MissingCamera, (evt) => { if (debug) console.warn("Creating missing camera") const scene = evt.context.scene; const cameraObject = new PerspectiveCamera(); cameraObject.name = "Default Fallback Camera" scene.add(cameraObject); const camInstance = new Camera(); camInstance.sourceId = evt.files?.[0]?.src ?? "unknown" // Set the clearFlags to a skybox if we have one OR if the user set a skybox image attribute if(evt.context.domElement.getAttribute("skybox-image")?.length || 0 > 0 || (evt.context as Context).lightmaps.tryGetSkybox(camInstance.sourceId)) camInstance.clearFlags = ClearFlags.Skybox; else // TODO provide a nice default skybox camInstance.clearFlags = ClearFlags.SolidColor; camInstance.backgroundColor = new RGBAColor(0.5, 0.5, 0.5, 1); camInstance.fieldOfView = 35; const transparentAttribute = evt.context.domElement.getAttribute("transparent"); if (transparentAttribute != undefined) { camInstance.clearFlags = ClearFlags.Uninitialized; } // TODO: can we store the backgroundBlurriness in the gltf file somewhere except inside the camera? // e.g. when we export a scene from blender without a camera in the scene camInstance.backgroundBlurriness = .2; // same as in blender 0.5 const cam = addNewComponent(cameraObject, camInstance, true) as ICamera; cameraObject.position.x = 0; cameraObject.position.y = 1; cameraObject.position.z = 2; const engineElement = evt.context.domElement as NeedleEngineHTMLElement // If the camera is missing and the <needle-engine controls> is not set to false, create default camera controls // That way we still create controls if the attribute is not added to <needle-engine> at all if (engineElement?.cameraControls != false) { createDefaultCameraControls(evt.context, cam); } return cam; }); ContextRegistry.registerCallback(ContextEvent.ContextCreated, (evt) => { if (!evt.context.mainCamera) { if (debug) console.log("Will not auto-fit because a default camera exists"); return; } // check if <needle-engine camera-controls> attribute is present or enabled const engineElement = evt.context.domElement as NeedleEngineHTMLElement if (engineElement?.cameraControls == true) { // Check if something else already acts as a camera controller const existing = getCameraController(evt.context.mainCamera); if (existing?.isCameraController == true) { if (debug) console.log("Will not auto-fit because a camera controller exists"); return; } createDefaultCameraControls(evt.context); } }) function createDefaultCameraControls(context: IContext, cam?: ICamera) { cam = cam ?? context.mainCameraComponent; const cameraObject = cam?.gameObject; if (debug) console.log("Creating default camera controls", cam?.name) if (cameraObject) { const orbit = getOrAddComponent(cameraObject, OrbitControls) as OrbitControls; orbit.sourceId = cam?.sourceId ?? "unknown"; const autoRotate = context.domElement.getAttribute("auto-rotate"); orbit.autoRotate = autoRotate !== undefined && autoRotate !== null && (autoRotate != "0" && autoRotate?.toLowerCase() != "false"); orbit.autoRotateSpeed = 0.5; orbit.autoFit = true; if (orbit.autoRotate && autoRotate) { const autoRotateValue = parseFloat(autoRotate); if (!isNaN(autoRotateValue)) { orbit.autoRotateSpeed = autoRotateValue; } } } else { console.warn("Missing camera object, can not add orbit controls") } }