This commit is contained in:
Vendored
+46
@@ -0,0 +1,46 @@
|
|||||||
|
# Basis Universal GPU Texture Compression
|
||||||
|
|
||||||
|
Basis Universal is a "[supercompressed](http://gamma.cs.unc.edu/GST/gst.pdf)"
|
||||||
|
GPU texture and texture video compression system that outputs a highly
|
||||||
|
compressed intermediate file format (.basis) that can be quickly transcoded to
|
||||||
|
a wide variety of GPU texture compression formats.
|
||||||
|
|
||||||
|
[GitHub](https://github.com/BinomialLLC/basis_universal)
|
||||||
|
|
||||||
|
## Transcoders
|
||||||
|
|
||||||
|
Basis Universal texture data may be used in two different file formats:
|
||||||
|
`.basis` and `.ktx2`, where `ktx2` is a standardized wrapper around basis texture data.
|
||||||
|
|
||||||
|
For further documentation about the Basis compressor and transcoder, refer to
|
||||||
|
the [Basis GitHub repository](https://github.com/BinomialLLC/basis_universal).
|
||||||
|
|
||||||
|
The folder contains two files required for transcoding `.basis` or `.ktx2` textures:
|
||||||
|
|
||||||
|
* `basis_transcoder.js` — JavaScript wrapper for the WebAssembly transcoder.
|
||||||
|
* `basis_transcoder.wasm` — WebAssembly transcoder.
|
||||||
|
|
||||||
|
Both are dependencies of `KTX2Loader`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const ktx2Loader = new KTX2Loader();
|
||||||
|
ktx2Loader.setTranscoderPath( 'examples/jsm/libs/basis/' );
|
||||||
|
ktx2Loader.detectSupport( renderer );
|
||||||
|
ktx2Loader.load( 'diffuse.ktx2', function ( texture ) {
|
||||||
|
|
||||||
|
const material = new THREE.MeshStandardMaterial( { map: texture } );
|
||||||
|
|
||||||
|
}, function () {
|
||||||
|
|
||||||
|
console.log( 'onProgress' );
|
||||||
|
|
||||||
|
}, function ( e ) {
|
||||||
|
|
||||||
|
console.error( e );
|
||||||
|
|
||||||
|
} );
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[Apache License 2.0](https://github.com/BinomialLLC/basis_universal/blob/master/LICENSE)
|
||||||
+19
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
@@ -45,8 +45,8 @@ export default{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
gameEngine?.stop();
|
gameEngine?.dispose();
|
||||||
gameEngine?.destroy();
|
gameEngine = null;
|
||||||
},
|
},
|
||||||
watch:{
|
watch:{
|
||||||
object(n){
|
object(n){
|
||||||
@@ -72,7 +72,7 @@ export default{
|
|||||||
methods:{
|
methods:{
|
||||||
async loadAsset() {
|
async loadAsset() {
|
||||||
if (this.forRendering) {
|
if (this.forRendering) {
|
||||||
gameEngine.activeObjects.clear();
|
gameEngine.resetScene();
|
||||||
if (this.obj.type == 'panorama2d') {
|
if (this.obj.type == 'panorama2d') {
|
||||||
await gameEngine.loadPanorama(this.obj.asset.name);
|
await gameEngine.loadPanorama(this.obj.asset.name);
|
||||||
// let t = await gameEngine.loadTexture(`/asset/default/${this.obj.asset.name}`);
|
// let t = await gameEngine.loadTexture(`/asset/default/${this.obj.asset.name}`);
|
||||||
@@ -89,9 +89,6 @@ export default{
|
|||||||
}));
|
}));
|
||||||
autoScale(gltf.scene);
|
autoScale(gltf.scene);
|
||||||
let bb = new gameEngine.$.Box3().setFromObject(gltf.scene);
|
let bb = new gameEngine.$.Box3().setFromObject(gltf.scene);
|
||||||
gltf.scene.traverse(function (o) {
|
|
||||||
o.frustumCulled = false;
|
|
||||||
});
|
|
||||||
//console.log(bb)
|
//console.log(bb)
|
||||||
gameEngine.camera.position.set(bb.max.x, bb.max.y, bb.max.z);
|
gameEngine.camera.position.set(bb.max.x, bb.max.y, bb.max.z);
|
||||||
gameEngine.orbitControls.target.set((bb.max.x + bb.min.x) / 2, (bb.max.y + bb.min.y) / 2, (bb.max.z + bb.min.z) / 2)
|
gameEngine.orbitControls.target.set((bb.max.x + bb.min.x) / 2, (bb.max.y + bb.min.y) / 2, (bb.max.z + bb.min.z) / 2)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { TextureLoader, MeshStandardMaterial, MeshBasicMaterial, PlaneGeometry, Mesh, DoubleSide, Vector3 } from "three";
|
import { MeshStandardMaterial, MeshBasicMaterial, PlaneGeometry, Mesh, DoubleSide, Vector3 } from "three";
|
||||||
|
|
||||||
class ImageObject {
|
class ImageObject {
|
||||||
constructor(engine, obj) {
|
constructor(engine, obj) {
|
||||||
@@ -10,13 +10,13 @@ class ImageObject {
|
|||||||
side: DoubleSide
|
side: DoubleSide
|
||||||
};
|
};
|
||||||
if (obj.nm) {
|
if (obj.nm) {
|
||||||
mp.normalMap = new TextureLoader().setPath(obj.path).load(obj.nm);
|
mp.normalMap = engine.loadTexture(obj.nm, obj.path);
|
||||||
}
|
}
|
||||||
if (obj.em) {
|
if (obj.em) {
|
||||||
mp.emissiveMap = new TextureLoader().setPath(obj.path).load(obj.em);
|
mp.emissiveMap = engine.loadTexture(obj.em, obj.path);
|
||||||
}
|
}
|
||||||
if (obj.am) {
|
if (obj.am) {
|
||||||
mp.alphaMap = new TextureLoader().setPath(obj.path).load(obj.am);
|
mp.alphaMap = engine.loadTexture(obj.am, obj.path);
|
||||||
}
|
}
|
||||||
obj.material && Object.assign(mp, obj.material);
|
obj.material && Object.assign(mp, obj.material);
|
||||||
let geo = new PlaneGeometry(obj.width || 1, obj.height || 1);
|
let geo = new PlaneGeometry(obj.width || 1, obj.height || 1);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MeshBasicMaterial, Color, Vector3, DoubleSide } from "three";
|
import { MeshBasicMaterial, Color, DoubleSide } from "three";
|
||||||
import { Text } from "troika-three-text";
|
import { Text } from "troika-three-text";
|
||||||
import { assignParams } from "@/lib/MeshUtils";
|
import { assignParams } from "@/lib/MeshUtils";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
PlaneGeometry, CylinderGeometry, CanvasTexture, Group, SphereGeometry,
|
PlaneGeometry, CylinderGeometry, Group, SphereGeometry,
|
||||||
Mesh, MeshStandardMaterial, MeshBasicMaterial, DoubleSide
|
Mesh, MeshStandardMaterial, MeshBasicMaterial, DoubleSide
|
||||||
} from "three";
|
} from "three";
|
||||||
|
|
||||||
@@ -12,14 +12,10 @@ class DashBoard extends EventManager {
|
|||||||
constructor(engine) {
|
constructor(engine) {
|
||||||
super();
|
super();
|
||||||
let levelProgress;
|
let levelProgress;
|
||||||
let canvas = document.createElement('canvas');
|
|
||||||
let ctx = canvas.getContext('2d');
|
|
||||||
let texture = new CanvasTexture(canvas)
|
|
||||||
let updating = false;
|
|
||||||
let params = {}
|
|
||||||
let occupied = false;
|
let occupied = false;
|
||||||
|
|
||||||
const dash = new Group(), hud = new Group(), hudTarget = new Group();
|
const dash = new Group(), hud = new Group(), hudTarget = new Group();
|
||||||
|
this.object = dash;
|
||||||
hud.visible = false;
|
hud.visible = false;
|
||||||
let hudAnimation, hudPlane, textPlane, sceneHeader;
|
let hudAnimation, hudPlane, textPlane, sceneHeader;
|
||||||
this.group = dash;
|
this.group = dash;
|
||||||
@@ -38,7 +34,7 @@ class DashBoard extends EventManager {
|
|||||||
const dashGeometry = new PlaneGeometry(dashWidth, dashHeight);
|
const dashGeometry = new PlaneGeometry(dashWidth, dashHeight);
|
||||||
const dashMesh = new Mesh(dashGeometry, new MeshBasicMaterial({
|
const dashMesh = new Mesh(dashGeometry, new MeshBasicMaterial({
|
||||||
transparent: true,
|
transparent: true,
|
||||||
map: texture
|
opacity: 0
|
||||||
}))
|
}))
|
||||||
|
|
||||||
dash.add(dashMesh);
|
dash.add(dashMesh);
|
||||||
|
|||||||
+206
-148
@@ -12,6 +12,7 @@ import { PointerControls } from './PointerControls';
|
|||||||
import { ARButton } from 'three/addons/webxr/ARButton.js';
|
import { ARButton } from 'three/addons/webxr/ARButton.js';
|
||||||
import { XRButton } from 'three/addons/webxr/XRButton.js';
|
import { XRButton } from 'three/addons/webxr/XRButton.js';
|
||||||
import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js';
|
import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js';
|
||||||
|
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';
|
||||||
import { Physics } from './Physics.js';
|
import { Physics } from './Physics.js';
|
||||||
import { Clickable } from './Clickable.js';
|
import { Clickable } from './Clickable.js';
|
||||||
import { DashBoard } from './Dashboard.js';
|
import { DashBoard } from './Dashboard.js';
|
||||||
@@ -26,14 +27,9 @@ const assetPath = '/asset/default/';
|
|||||||
const defaultLightIntensity = 22;
|
const defaultLightIntensity = 22;
|
||||||
|
|
||||||
class GameEngine extends EventManager{
|
class GameEngine extends EventManager{
|
||||||
async init(domNode, opts = {}) {
|
|
||||||
this.w = domNode.clientWidth || 1200, this.h = domNode.clientHeight || 800;
|
|
||||||
this.aspect = this.w / this.h
|
|
||||||
this.opts = opts;
|
|
||||||
const gameEngine = this;
|
|
||||||
|
|
||||||
|
async initScene(){
|
||||||
this.perspectiveCamera = new THREE.PerspectiveCamera(45, this.aspect, 0.001, 99);
|
this.perspectiveCamera = new THREE.PerspectiveCamera(45, this.aspect, 0.001, 99);
|
||||||
this.raycaster = new THREE.Raycaster();
|
|
||||||
//this.perspectiveCamera.position.set(0, 0, 10);
|
//this.perspectiveCamera.position.set(0, 0, 10);
|
||||||
|
|
||||||
this.camera = this.perspectiveCamera;
|
this.camera = this.perspectiveCamera;
|
||||||
@@ -67,7 +63,7 @@ class GameEngine extends EventManager{
|
|||||||
dirLight.position.set(12, 33, -37);
|
dirLight.position.set(12, 33, -37);
|
||||||
dirLight.position.multiplyScalar( 0.20 );
|
dirLight.position.multiplyScalar( 0.20 );
|
||||||
// hemiLight.position.multiplyScalar( 0.20 );
|
// hemiLight.position.multiplyScalar( 0.20 );
|
||||||
//scene.add(dirLight);
|
scene.add(dirLight);
|
||||||
dirLight.castShadow = true;
|
dirLight.castShadow = true;
|
||||||
dirLight.shadow.mapSize.width = 1024;
|
dirLight.shadow.mapSize.width = 1024;
|
||||||
dirLight.shadow.mapSize.height = 1024;
|
dirLight.shadow.mapSize.height = 1024;
|
||||||
@@ -82,11 +78,83 @@ class GameEngine extends EventManager{
|
|||||||
// const spotLight = new THREE.SpotLight(0xffffff);
|
// const spotLight = new THREE.SpotLight(0xffffff);
|
||||||
// scene.add(spotLight);
|
// scene.add(spotLight);
|
||||||
|
|
||||||
|
this.listener = new THREE.AudioListener();
|
||||||
|
this.camera.add(this.listener);
|
||||||
|
this.ambientSound = new THREE.Audio(this.listener);
|
||||||
|
|
||||||
|
this.activeObjects = new THREE.Group();
|
||||||
|
scene.add(this.activeObjects);
|
||||||
|
|
||||||
|
if (this.opts.gizmo) {
|
||||||
|
this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement);
|
||||||
|
this.orbitControls.enableZoom = false;
|
||||||
|
const gizmo = new ViewportGizmo(this.camera, this.renderer, {
|
||||||
|
container: '.renderer-gizmo',
|
||||||
|
//type:'cube'
|
||||||
|
});
|
||||||
|
gizmo.attachControls(this.orbitControls);
|
||||||
|
this.gizmo = gizmo;
|
||||||
|
this.perspectiveCamera.position.set(0, 0, 10);
|
||||||
|
this.orthographicCamera.position.set(0, 0, 100);
|
||||||
|
this.cameraRig.rotation.y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//const controls = new MapControls( camera, renderer.domElement );
|
||||||
|
|
||||||
|
if (this.opts.mode == 'GameDesigner'){
|
||||||
|
const gameEngine = this;
|
||||||
|
this.transformControls = new TransformControls(this.camera, this.renderer.domElement);
|
||||||
|
this.transformControls.addEventListener('dragging-changed', function (event) {
|
||||||
|
if (gameEngine.orbitControls){
|
||||||
|
gameEngine.orbitControls.enabled = !event.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
scene.add(this.transformControls.getHelper());
|
||||||
|
}else if (['GamePlay', 'GamePreview'].includes(this.opts.mode)){
|
||||||
|
const dashboard = new DashBoard(this);
|
||||||
|
this.dashboard = dashboard;
|
||||||
|
dashboard.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pointerControls = new PointerControls(this);
|
||||||
|
|
||||||
|
scene.background = new THREE.Color(1, 1, 1);
|
||||||
|
|
||||||
|
const mixer = new THREE.AnimationMixer(this.scene);
|
||||||
|
const clock = new THREE.Clock();
|
||||||
|
|
||||||
|
this.clock = clock;
|
||||||
|
this.mixers = [mixer];
|
||||||
|
|
||||||
|
await this.initPhysics();
|
||||||
|
|
||||||
|
if (this.opts.xr){
|
||||||
|
this.cameraRig.add(this.xrController1);
|
||||||
|
this.cameraRig.add(this.xrController2);
|
||||||
|
this.cameraRig.add(this.xrControllerGrip1);
|
||||||
|
this.cameraRig.add(this.xrControllerGrip2);
|
||||||
|
|
||||||
|
const geometry = new THREE.BufferGeometry().setFromPoints([new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, - 1)]);
|
||||||
|
|
||||||
|
let line = new THREE.Line(geometry);
|
||||||
|
line.scale.z = 5;
|
||||||
|
|
||||||
|
this.controllerLine = line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(domNode, opts = {}) {
|
||||||
|
this.w = domNode.clientWidth || 1200, this.h = domNode.clientHeight || 800;
|
||||||
|
this.aspect = this.w / this.h
|
||||||
|
this.opts = opts;
|
||||||
|
const gameEngine = this;
|
||||||
|
this.raycaster = new THREE.Raycaster();
|
||||||
|
|
||||||
const renderer = new THREE.WebGLRenderer({
|
const renderer = new THREE.WebGLRenderer({
|
||||||
antialias: true,
|
antialias: true,
|
||||||
alpha: false,
|
alpha: false,
|
||||||
preserveDrawingBuffer: true, //this is important for screenshots capturing
|
preserveDrawingBuffer: true, //this is important for screenshots capturing
|
||||||
powerPreference: "high-performance",
|
//powerPreference: "high-performance",
|
||||||
//precision: 'mediump'
|
//precision: 'mediump'
|
||||||
});
|
});
|
||||||
renderer.setPixelRatio(window.devicePixelRatio);
|
renderer.setPixelRatio(window.devicePixelRatio);
|
||||||
@@ -114,111 +182,16 @@ class GameEngine extends EventManager{
|
|||||||
this.motionQueue = new MotionEngine();
|
this.motionQueue = new MotionEngine();
|
||||||
this.assetPath = assetPath;
|
this.assetPath = assetPath;
|
||||||
|
|
||||||
const dashboard = new DashBoard(this);
|
|
||||||
this.dashboard = dashboard;
|
|
||||||
|
|
||||||
this.listener = new THREE.AudioListener();
|
|
||||||
this.camera.add(this.listener);
|
|
||||||
this.ambientSound = new THREE.Audio(this.listener);
|
|
||||||
|
|
||||||
this.activeObjects = new THREE.Group();
|
|
||||||
scene.add(this.activeObjects);
|
|
||||||
|
|
||||||
if (opts.gizmo) {
|
|
||||||
this.orbitControls = new OrbitControls(this.camera, renderer.domElement);
|
|
||||||
this.orbitControls.enableZoom = false;
|
|
||||||
const gizmo = new ViewportGizmo(this.camera, renderer, {
|
|
||||||
container: '.renderer-gizmo',
|
|
||||||
//type:'cube'
|
|
||||||
});
|
|
||||||
gizmo.attachControls(this.orbitControls);
|
|
||||||
this.gizmo = gizmo;
|
|
||||||
this.perspectiveCamera.position.set(0, 0, 10);
|
|
||||||
this.orthographicCamera.position.set(0, 0, 100);
|
|
||||||
this.cameraRig.rotation.y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.telemetry){
|
if (opts.telemetry){
|
||||||
this.tm = new Telemetry(opts.telemetry, opts.mode);
|
this.tm = new Telemetry(opts.telemetry, opts.mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
//const controls = new MapControls( camera, renderer.domElement );
|
|
||||||
this.transformControls = new TransformControls(this.camera, renderer.domElement);
|
|
||||||
this.transformControls.addEventListener('dragging-changed', function (event) {
|
|
||||||
if (gameEngine.orbitControls){
|
|
||||||
gameEngine.orbitControls.enabled = !event.value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.pointerControls = new PointerControls(this);
|
|
||||||
// controls.enableDamping = true;
|
// controls.enableDamping = true;
|
||||||
// controls.screenSpacePanning = true;
|
// controls.screenSpacePanning = true;
|
||||||
|
|
||||||
this.renderType = 'ST';
|
this.renderType = 'ST';
|
||||||
|
|
||||||
this.handleXrAction = ['ObjectPreview', 'DesignMode'].includes(opts.mode) ? this.handleXrActionDesignMode : this.handleXrActionGameMode;
|
this.handleXrAction = ['ObjectPreview', 'DesignMode'].includes(opts.mode) ? this.handleXrActionDesignMode : this.handleXrActionGameMode;
|
||||||
|
|
||||||
function animate(time) {
|
|
||||||
let delta = clock.getDelta();
|
|
||||||
gameEngine.physics?.step();
|
|
||||||
gameEngine.handleXrAction(gameEngine, delta);
|
|
||||||
gameEngine.hero?.update(delta);
|
|
||||||
gameEngine.mixers.forEach(m => m.update(delta));
|
|
||||||
gameEngine.dispatchEvent({type: 'beforeRender'})
|
|
||||||
gameEngine.processHideIfFar();
|
|
||||||
this.motionQueue.update(delta);
|
|
||||||
|
|
||||||
gameEngine.render(scene, gameEngine.camera);
|
|
||||||
if (!renderer.xr.isPresenting) {
|
|
||||||
gameEngine.gizmo?.render();
|
|
||||||
}
|
|
||||||
// renderer.autoClear = false;
|
|
||||||
// dashboard.render();
|
|
||||||
// renderer.autoClear = true;
|
|
||||||
}
|
|
||||||
renderer.setAnimationLoop(animate.bind(this));
|
|
||||||
|
|
||||||
const mixer = new THREE.AnimationMixer(this.scene);
|
|
||||||
const clock = new THREE.Clock();
|
|
||||||
|
|
||||||
this.clock = clock;
|
|
||||||
|
|
||||||
this.draco = new DRACOLoader().setDecoderPath('/3rdparty/draco/');
|
|
||||||
this.loader = new GLTFLoader();
|
|
||||||
this.loader.setDRACOLoader(this.draco);
|
|
||||||
this.mixers = [mixer];
|
|
||||||
|
|
||||||
domNode.appendChild(renderer.domElement);
|
|
||||||
|
|
||||||
// let texture = await GameEngine.loadTexture('/static/textures/bck.webp', '');
|
|
||||||
// // let bck = await this.loadTexture('/static/textures/bck.webp');
|
|
||||||
// // bck.premultiplyAlpha = true;
|
|
||||||
// texture.mapping = THREE.EquirectangularReflectionMapping;
|
|
||||||
// // scene.background = bck; //new THREE.Color(0.7,0.7,0.7);
|
|
||||||
// scene.environment = texture;
|
|
||||||
scene.background = new THREE.Color(1, 1, 1);
|
|
||||||
//console.log('GameEngine started')
|
|
||||||
renderer.domElement.addEventListener('wheel', (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
if (gameEngine.hero){
|
|
||||||
if (!gameEngine.pointerControls.isLocked){
|
|
||||||
gameEngine.hero.cameraZ += event.deltaY / 100;
|
|
||||||
}else{
|
|
||||||
gameEngine.camera.fov += event.deltaY / 100;
|
|
||||||
gameEngine.camera.fov = Math.min(Math.max(gameEngine.camera.fov, 0.01), 90);
|
|
||||||
gameEngine.camera.updateProjectionMatrix();
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
gameEngine.camera.zoom -= event.deltaY / (1000 / gameEngine.camera.zoom);
|
|
||||||
gameEngine.camera.zoom = Math.max(gameEngine.camera.zoom, .01);
|
|
||||||
//controls.rotateSpeed = 1 / Math.sqrt(gameEngine.camera.zoom);
|
|
||||||
gameEngine.orbitControls.panSpeed = 1 / gameEngine.camera.zoom;
|
|
||||||
gameEngine.camera.updateProjectionMatrix();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
await this.initPhysics();
|
|
||||||
|
|
||||||
if (opts.stats){
|
if (opts.stats){
|
||||||
this.stats = new Stats();
|
this.stats = new Stats();
|
||||||
this.stats.dom.classList.add('engine-stats');
|
this.stats.dom.classList.add('engine-stats');
|
||||||
@@ -250,6 +223,50 @@ class GameEngine extends EventManager{
|
|||||||
|
|
||||||
this.clickable = new Clickable(this, 20);
|
this.clickable = new Clickable(this, 20);
|
||||||
this.draggable = new Draggable(this, 20);
|
this.draggable = new Draggable(this, 20);
|
||||||
|
|
||||||
|
await this.initScene();
|
||||||
|
|
||||||
|
function animate(time) {
|
||||||
|
let delta = gameEngine.clock.getDelta();
|
||||||
|
gameEngine.physics?.step();
|
||||||
|
gameEngine.handleXrAction(gameEngine, delta);
|
||||||
|
gameEngine.hero?.update(delta);
|
||||||
|
gameEngine.mixers.forEach(m => m.update(delta));
|
||||||
|
gameEngine.dispatchEvent({type: 'beforeRender'})
|
||||||
|
gameEngine.processHideIfFar();
|
||||||
|
this.motionQueue.update(delta);
|
||||||
|
|
||||||
|
gameEngine.render(gameEngine.scene, gameEngine.camera);
|
||||||
|
if (!renderer.xr.isPresenting) {
|
||||||
|
gameEngine.gizmo?.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
renderer.setAnimationLoop(animate.bind(this));
|
||||||
|
|
||||||
|
this.loadedObjects = [];
|
||||||
|
|
||||||
|
domNode.appendChild(renderer.domElement);
|
||||||
|
|
||||||
|
renderer.domElement.addEventListener('wheel', (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (gameEngine.hero){
|
||||||
|
if (!gameEngine.pointerControls.isLocked){
|
||||||
|
gameEngine.hero.cameraZ += event.deltaY / 100;
|
||||||
|
}else{
|
||||||
|
gameEngine.camera.fov += event.deltaY / 100;
|
||||||
|
gameEngine.camera.fov = Math.min(Math.max(gameEngine.camera.fov, 0.01), 90);
|
||||||
|
gameEngine.camera.updateProjectionMatrix();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
gameEngine.camera.zoom -= event.deltaY / (1000 / gameEngine.camera.zoom);
|
||||||
|
gameEngine.camera.zoom = Math.max(gameEngine.camera.zoom, .01);
|
||||||
|
//controls.rotateSpeed = 1 / Math.sqrt(gameEngine.camera.zoom);
|
||||||
|
gameEngine.orbitControls.panSpeed = 1 / gameEngine.camera.zoom;
|
||||||
|
gameEngine.camera.updateProjectionMatrix();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
GameEngine.ktxLoader.detectSupport(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
initXr() {
|
initXr() {
|
||||||
@@ -264,7 +281,6 @@ class GameEngine extends EventManager{
|
|||||||
// this.session = this.renderer.xr.getSession();
|
// this.session = this.renderer.xr.getSession();
|
||||||
// this.session.addEventListener('selectstart', this.onControllerEvent.bind(this));
|
// this.session.addEventListener('selectstart', this.onControllerEvent.bind(this));
|
||||||
})
|
})
|
||||||
this.cameraRig.add(c1);
|
|
||||||
|
|
||||||
let c2 = this.renderer.xr.getController(1);
|
let c2 = this.renderer.xr.getController(1);
|
||||||
c2.addEventListener('select', this.onSelect.bind(this));
|
c2.addEventListener('select', this.onSelect.bind(this));
|
||||||
@@ -275,47 +291,25 @@ class GameEngine extends EventManager{
|
|||||||
c2.addEventListener('connected', e => {
|
c2.addEventListener('connected', e => {
|
||||||
c2.gamepad = e.data.gamepad;
|
c2.gamepad = e.data.gamepad;
|
||||||
})
|
})
|
||||||
this.cameraRig.add(c2);
|
|
||||||
|
|
||||||
const controllerModelFactory = new XRControllerModelFactory();
|
const controllerModelFactory = new XRControllerModelFactory();
|
||||||
|
|
||||||
let controllerGrip1 = this.renderer.xr.getControllerGrip(0);
|
let controllerGrip1 = this.renderer.xr.getControllerGrip(0);
|
||||||
controllerGrip1.add(controllerModelFactory.createControllerModel(controllerGrip1));
|
controllerGrip1.add(controllerModelFactory.createControllerModel(controllerGrip1));
|
||||||
this.cameraRig.add(controllerGrip1);
|
|
||||||
|
|
||||||
let controllerGrip2 = this.renderer.xr.getControllerGrip(1);
|
let controllerGrip2 = this.renderer.xr.getControllerGrip(1);
|
||||||
controllerGrip2.add(controllerModelFactory.createControllerModel(controllerGrip2));
|
controllerGrip2.add(controllerModelFactory.createControllerModel(controllerGrip2));
|
||||||
this.cameraRig.add(controllerGrip2);
|
|
||||||
|
|
||||||
const geometry = new THREE.BufferGeometry().setFromPoints([new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, - 1)]);
|
|
||||||
|
|
||||||
let line = new THREE.Line(geometry);
|
|
||||||
line.name = 'line';
|
|
||||||
line.scale.z = 5;
|
|
||||||
|
|
||||||
this.controllerLine = line;
|
|
||||||
|
|
||||||
this.xrController1 = c1
|
this.xrController1 = c1
|
||||||
this.xrController2 = c2
|
this.xrController2 = c2
|
||||||
|
|
||||||
|
this.xrControllerGrip1 = controllerGrip1;
|
||||||
|
this.xrControllerGrip2 = controllerGrip2;
|
||||||
|
|
||||||
this.xrCamera = this.renderer.xr.getCamera();
|
this.xrCamera = this.renderer.xr.getCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
initCameraPivot() {
|
initCameraPivot() {
|
||||||
// const pivot = new THREE.Object3D()
|
|
||||||
// pivot.position.set(0, 0, 0)
|
|
||||||
|
|
||||||
// const yaw = new THREE.Object3D()
|
|
||||||
// const pitch = new THREE.Object3D()
|
|
||||||
|
|
||||||
// this.scene.add(pivot)
|
|
||||||
// pivot.add(yaw)
|
|
||||||
// yaw.add(pitch)
|
|
||||||
// this.scene.add(this.perspectiveCamera);
|
|
||||||
// this.scene.add(this.orthographicCamera);
|
|
||||||
// this.cameraPivot = pivot;
|
|
||||||
// this.cameraYaw = yaw;
|
|
||||||
|
|
||||||
this.cameraWorld = new THREE.Group();
|
this.cameraWorld = new THREE.Group();
|
||||||
this.cameraRig = new THREE.Group();
|
this.cameraRig = new THREE.Group();
|
||||||
this.cameraRig.add(this.perspectiveCamera);
|
this.cameraRig.add(this.perspectiveCamera);
|
||||||
@@ -443,7 +437,7 @@ class GameEngine extends EventManager{
|
|||||||
|
|
||||||
async load(url, path = assetPath, progress) {
|
async load(url, path = assetPath, progress) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.loader.load(`${path}${url}`, o => {
|
GameEngine.gltfLoader.load(`${path}${url}`, o => {
|
||||||
o.scene.traverse(object => {
|
o.scene.traverse(object => {
|
||||||
if (object.name == 'environment' || object.material){
|
if (object.name == 'environment' || object.material){
|
||||||
//console.log('env recomputing')
|
//console.log('env recomputing')
|
||||||
@@ -470,6 +464,7 @@ class GameEngine extends EventManager{
|
|||||||
object.receiveShadow = true;
|
object.receiveShadow = true;
|
||||||
});
|
});
|
||||||
resolve(o);
|
resolve(o);
|
||||||
|
this.loadedObjects.push(o);
|
||||||
}, progress, reject)
|
}, progress, reject)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -477,9 +472,13 @@ class GameEngine extends EventManager{
|
|||||||
async loadPanorama(url, path = assetPath) {
|
async loadPanorama(url, path = assetPath) {
|
||||||
let t = await GameEngine.loadTexture(url, path);
|
let t = await GameEngine.loadTexture(url, path);
|
||||||
t.mapping = THREE.EquirectangularReflectionMapping;
|
t.mapping = THREE.EquirectangularReflectionMapping;
|
||||||
|
t.generateMipmaps = false;
|
||||||
|
t.minFilter = THREE.LinearFilter;
|
||||||
|
this.scene.background?.dispose?.();
|
||||||
|
this.scene.environment?.dispose?.();
|
||||||
this.scene.background = t;
|
this.scene.background = t;
|
||||||
//this.scene.environment = t;
|
this.scene.environment = t;
|
||||||
this.scene.environment = this.pmremGenerator.fromEquirectangular(t).texture;
|
//this.scene.environment = this.pmremGenerator.fromEquirectangular(t).texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
async captureScreenshot(type = 'image/webp', quality = 80) {
|
async captureScreenshot(type = 'image/webp', quality = 80) {
|
||||||
@@ -635,19 +634,6 @@ class GameEngine extends EventManager{
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
clearScene(){
|
|
||||||
this.hero?.destroy();
|
|
||||||
this.dashboard?.reset();
|
|
||||||
this.activeObjects.clear();
|
|
||||||
this.physics.stop();
|
|
||||||
this.physics.clear();
|
|
||||||
this.clickable.removeAll();
|
|
||||||
this.motionQueue.clearAll();
|
|
||||||
this.ambientSound.stop();
|
|
||||||
this.tm?.setScene(null);
|
|
||||||
this.removeAllListenersOfType('beforeRender')
|
|
||||||
}
|
|
||||||
|
|
||||||
async playAmbientSound(source, path){
|
async playAmbientSound(source, path){
|
||||||
let buffer = await GameEngine.loadAudio(source, path);
|
let buffer = await GameEngine.loadAudio(source, path);
|
||||||
this.ambientSound.setBuffer(buffer);
|
this.ambientSound.setBuffer(buffer);
|
||||||
@@ -671,25 +657,97 @@ class GameEngine extends EventManager{
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy(){
|
clearObject(o){
|
||||||
|
let disposables = []
|
||||||
|
o.traverse(object => {
|
||||||
|
if (!object.isMesh) return;
|
||||||
|
disposables.push(object);
|
||||||
|
});
|
||||||
|
disposables.forEach(object=>{
|
||||||
|
object.removeFromParent();
|
||||||
|
object.geometry.dispose();
|
||||||
|
if (object.material.isMaterial) {
|
||||||
|
this.clearMaterial(object.material)
|
||||||
|
} else {
|
||||||
|
for (const material of object.material) this.clearMaterial(material)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
clearMaterial(material) {
|
||||||
|
material.dispose();
|
||||||
|
for (const key of Object.keys(material)) {
|
||||||
|
const value = material[key]
|
||||||
|
if (value && typeof value == 'object' && 'minFilter' in value) {
|
||||||
|
//console.log('Disposing', value.name, this.renderer.info.memory.textures );
|
||||||
|
value.dispose();
|
||||||
|
//console.log('Disposed', value.name, this.renderer.info.memory.textures );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearScene(){
|
||||||
|
this.hero?.dispose();
|
||||||
|
this.dashboard?.reset();
|
||||||
|
//this.activeObjects.clear();
|
||||||
|
this.physics.stop();
|
||||||
|
this.physics.clear();
|
||||||
|
this.clickable.removeAll();
|
||||||
|
this.gizmo?.dispose();
|
||||||
|
this.motionQueue.clearAll();
|
||||||
|
this.ambientSound.stop();
|
||||||
|
this.loadedObjects.forEach(o=>this.clearObject(o.scene))
|
||||||
|
GameEngine.loadedTextures.forEach(t=>{
|
||||||
|
//console.log('Disposing', t.name, this.renderer.info.memory.textures );
|
||||||
|
t.dispose();
|
||||||
|
//console.log('Disposed', t.name, this.renderer.info.memory.textures );
|
||||||
|
});
|
||||||
|
this.scene.background?.dispose?.();
|
||||||
|
this.scene.environment?.dispose?.();
|
||||||
|
this.clearObject(this.scene);
|
||||||
|
this.scene = null;
|
||||||
|
this.tm?.setScene(null);
|
||||||
|
this.removeAllListenersOfType('beforeRender');
|
||||||
|
this.renderer.renderLists.dispose();
|
||||||
|
this.renderer.properties.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
async resetScene(){
|
||||||
|
this.clearScene();
|
||||||
|
await this.initScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(){
|
||||||
|
this.stop();
|
||||||
|
this.clearScene();
|
||||||
this.renderer.dispose();
|
this.renderer.dispose();
|
||||||
|
this.pmremGenerator.dispose();
|
||||||
this.arBtn?.remove();
|
this.arBtn?.remove();
|
||||||
this.xrBtn?.remove();
|
this.xrBtn?.remove();
|
||||||
this.stats?.dom?.remove();
|
this.stats?.dom?.remove();
|
||||||
this.renderer.domElement.remove();
|
this.renderer.domElement.remove();
|
||||||
|
//console.log('Engine Disposed', this.renderer.info.memory.textures );
|
||||||
}
|
}
|
||||||
|
|
||||||
static textureLoader = new THREE.TextureLoader();
|
static textureLoader = new THREE.TextureLoader();
|
||||||
static audioLoader = new THREE.AudioLoader();
|
static audioLoader = new THREE.AudioLoader();
|
||||||
|
static draco = new DRACOLoader().setDecoderPath('/3rdparty/draco/');
|
||||||
|
static gltfLoader = new GLTFLoader().setDRACOLoader(this.draco);
|
||||||
|
static ktxLoader = new KTX2Loader().setTranscoderPath( '/3rdparty/basis/' );
|
||||||
|
|
||||||
|
static loadedTextures = []
|
||||||
|
|
||||||
static async loadTexture(url, path = assetPath, progress, assignTo) {
|
static async loadTexture(url, path = assetPath, progress, assignTo) {
|
||||||
|
let loader = url.toLowerCase().endsWith('.ktx2') ? GameEngine.ktxLoader : GameEngine.textureLoader;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
GameEngine.textureLoader.load(`${path}${url}`, texture => {
|
loader.load(`${path}${url}`, texture => {
|
||||||
texture.colorSpace = THREE.SRGBColorSpace;
|
texture.colorSpace = THREE.SRGBColorSpace;
|
||||||
|
texture.name = url;
|
||||||
if (assignTo){
|
if (assignTo){
|
||||||
assignTo[0][assignTo[1]] = texture;
|
assignTo[0][assignTo[1]] = texture;
|
||||||
}
|
}
|
||||||
resolve(texture)
|
resolve(texture)
|
||||||
|
GameEngine.loadedTextures.push(texture);
|
||||||
}, progress, reject)
|
}, progress, reject)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { TextureLoader, Box3, Vector3, Group } from "three";
|
import { Box3, Vector3, Group } from "three";
|
||||||
|
import { GameEngine } from "./GameEngine";
|
||||||
|
|
||||||
function assignParams(mesh, params){
|
function assignParams(mesh, params){
|
||||||
['scale', 'rotation', 'position'].forEach(p=>params[p] && mesh[p].fromArray(params[p]));
|
['scale', 'rotation', 'position'].forEach(p=>params[p] && mesh[p].fromArray(params[p]));
|
||||||
@@ -15,14 +16,17 @@ function assignMaterial(mesh, params){
|
|||||||
//let mp = params.material.metalness ? new MeshStandardMaterial(params.material) : new MeshBasicMaterial(params.material)
|
//let mp = params.material.metalness ? new MeshStandardMaterial(params.material) : new MeshBasicMaterial(params.material)
|
||||||
Object.assign(mesh.material, params.material)
|
Object.assign(mesh.material, params.material)
|
||||||
if (params.dm){
|
if (params.dm){
|
||||||
var dm = new TextureLoader().setPath(params.path).load(params.dm);
|
GameEngine.loadTexture(params.dm, params.path, undefined, [mesh.material, 'map'])
|
||||||
mesh.material.map = dm;
|
// var dm = new TextureLoader().setPath(params.path).load(params.dm);
|
||||||
|
// mesh.material.map = dm;
|
||||||
}
|
}
|
||||||
if (params.nm){
|
if (params.nm){
|
||||||
mesh.material.normalMap = new TextureLoader().setPath(params.path).load(params.nm);
|
GameEngine.loadTexture(params.nm, params.path, undefined, [mesh.material, 'normalMap'])
|
||||||
|
//mesh.material.normalMap = new TextureLoader().setPath(params.path).load(params.nm);
|
||||||
}
|
}
|
||||||
if (params.em) {
|
if (params.em) {
|
||||||
mesh.material.emissiveMap = new TextureLoader().setPath(params.path).load(params.em);
|
GameEngine.loadTexture(params.em, params.path, undefined, [mesh.material, 'emissiveMap'])
|
||||||
|
//mesh.material.emissiveMap = new TextureLoader().setPath(params.path).load(params.em);
|
||||||
}
|
}
|
||||||
//mesh.material = mp;
|
//mesh.material = mp;
|
||||||
mesh.material.needsUpdate = true;
|
mesh.material.needsUpdate = true;
|
||||||
|
|||||||
@@ -19,11 +19,6 @@ export default {
|
|||||||
mode: this.env
|
mode: this.env
|
||||||
});
|
});
|
||||||
//engine.scene.add(new engine.$.GridHelper(100,100));
|
//engine.scene.add(new engine.$.GridHelper(100,100));
|
||||||
if (this.env == 'GameDesigner'){
|
|
||||||
engine.scene.add(engine.transformControls.getHelper());
|
|
||||||
}else{
|
|
||||||
engine.dashboard.enable();
|
|
||||||
}
|
|
||||||
this.resize();
|
this.resize();
|
||||||
|
|
||||||
if (!this.scenario) {
|
if (!this.scenario) {
|
||||||
@@ -32,12 +27,12 @@ export default {
|
|||||||
window.addEventListener('resize', this.resize);
|
window.addEventListener('resize', this.resize);
|
||||||
},
|
},
|
||||||
|
|
||||||
unmounted(){
|
async unmounted(){
|
||||||
|
this.debug('Disposing scene')
|
||||||
window.removeEventListener('resize', this.resize);
|
window.removeEventListener('resize', this.resize);
|
||||||
engine.clearScene();
|
|
||||||
engine.stop();
|
|
||||||
engine.tm?.setGame(null);
|
engine.tm?.setGame(null);
|
||||||
engine.destroy();
|
engine.dispose();
|
||||||
|
this.debug('Disposed scene', engine.renderer.info.memory)
|
||||||
},
|
},
|
||||||
|
|
||||||
computed:{
|
computed:{
|
||||||
@@ -124,9 +119,9 @@ export default {
|
|||||||
engine.tm?.setGame(this.object?.id);
|
engine.tm?.setGame(this.object?.id);
|
||||||
//await engine.loadPanorama(`/asset/default/43.webp`);
|
//await engine.loadPanorama(`/asset/default/43.webp`);
|
||||||
let intro;
|
let intro;
|
||||||
engine.clearScene();
|
await engine.resetScene();
|
||||||
engine.activeObjects.visible = false;
|
engine.activeObjects.visible = false;
|
||||||
await engine.dashboard.ready;
|
await engine.dashboard?.ready;
|
||||||
engine.dashboard?.initScene(scene, async ()=>{
|
engine.dashboard?.initScene(scene, async ()=>{
|
||||||
if (this.scene.data.$audio){
|
if (this.scene.data.$audio){
|
||||||
await engine.playAmbientSound(this.scene.data.$audio.asset.name);
|
await engine.playAmbientSound(this.scene.data.$audio.asset.name);
|
||||||
@@ -149,6 +144,7 @@ export default {
|
|||||||
target.objects = target.objects || {};
|
target.objects = target.objects || {};
|
||||||
let l = target.objects;
|
let l = target.objects;
|
||||||
if (this.scene.data.$environment){
|
if (this.scene.data.$environment){
|
||||||
|
this.debug('loading panorama', this.scene.data.$environment.asset.name)
|
||||||
await engine.loadPanorama(this.scene.data.$environment.asset.name);
|
await engine.loadPanorama(this.scene.data.$environment.asset.name);
|
||||||
}
|
}
|
||||||
if (this.scene.data.$scene){
|
if (this.scene.data.$scene){
|
||||||
@@ -168,7 +164,7 @@ export default {
|
|||||||
if (this.scene.data.items){
|
if (this.scene.data.items){
|
||||||
let loaded = 0;
|
let loaded = 0;
|
||||||
for (let i of this.scene.data.items) {
|
for (let i of this.scene.data.items) {
|
||||||
this.debug('Loading', i);
|
this.debug('Loading', i.data.id);
|
||||||
if (this.env != 'GameDesigner'){
|
if (this.env != 'GameDesigner'){
|
||||||
if (i.data.activationTriggers?.length || i.data.activationScore){
|
if (i.data.activationTriggers?.length || i.data.activationScore){
|
||||||
i.data.shouldBeLocked = true;
|
i.data.shouldBeLocked = true;
|
||||||
@@ -247,6 +243,7 @@ export default {
|
|||||||
|
|
||||||
engine.dashboard?.loading(1)
|
engine.dashboard?.loading(1)
|
||||||
engine.physics.start();
|
engine.physics.start();
|
||||||
|
this.debug('Scene loaded', engine.renderer.info.memory)
|
||||||
},
|
},
|
||||||
|
|
||||||
targetPointerDown(){
|
targetPointerDown(){
|
||||||
|
|||||||
Reference in New Issue
Block a user