Initial Commit
This commit is contained in:
commit
ec55aece38
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
11
index.html
Normal file
11
index.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Title of Your Project</title>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="module" src="./src/app.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1607
package-lock.json
generated
Normal file
1607
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
package.json
Normal file
24
package.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "immersive",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@babylonjs/core": "^6.8.0",
|
||||||
|
"@babylonjs/havok": "^1.0.1",
|
||||||
|
"@babylonjs/inspector": "^6.8.0",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"@auth0/auth0-spa-js": "^2.0.8"
|
||||||
|
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.0.2",
|
||||||
|
"vite": "^4.3.9",
|
||||||
|
"vite-plugin-api": "^0.1.11"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
public/environment.env
Normal file
BIN
public/environment.env
Normal file
Binary file not shown.
BIN
public/grass1.jpeg
Normal file
BIN
public/grass1.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
BIN
public/outdoor_field.jpeg
Normal file
BIN
public/outdoor_field.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 MiB |
136
src/app.ts
Normal file
136
src/app.ts
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import "@babylonjs/core/Debug/debugLayer";
|
||||||
|
import "@babylonjs/inspector";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ArcRotateCamera, Color3,
|
||||||
|
Engine,
|
||||||
|
HavokPlugin,
|
||||||
|
HemisphericLight,
|
||||||
|
Mesh,
|
||||||
|
MeshBuilder, PBRMaterial, PBRMetallicRoughnessMaterial,
|
||||||
|
PhotoDome,
|
||||||
|
PhysicsAggregate,
|
||||||
|
PhysicsShapeType, Quaternion,
|
||||||
|
Scene, StandardMaterial, Texture,
|
||||||
|
Vector3,
|
||||||
|
WebXRDefaultExperience
|
||||||
|
} from "@babylonjs/core";
|
||||||
|
import {Right} from "./controllers/right";
|
||||||
|
import {Left} from "./controllers/left";
|
||||||
|
import {havokModule} from "./util/havok";
|
||||||
|
|
||||||
|
|
||||||
|
class App {
|
||||||
|
preTasks = [havokModule];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
async initialize() {
|
||||||
|
// create the canvas html element and attach it to the webpage
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
canvas.style.width = "100%";
|
||||||
|
canvas.style.height = "100%";
|
||||||
|
canvas.id = "gameCanvas";
|
||||||
|
document.body.appendChild(canvas);
|
||||||
|
|
||||||
|
// initialize babylon scene and engine
|
||||||
|
const engine = new Engine(canvas, true);
|
||||||
|
const scene = new Scene(engine);
|
||||||
|
const hk = new HavokPlugin(true, await havokModule);
|
||||||
|
scene.enablePhysics(new Vector3(0 , -9.8, 0), hk);
|
||||||
|
|
||||||
|
const camera: ArcRotateCamera = new ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 2, 2,
|
||||||
|
new Vector3(0, 1.6, 0), scene);
|
||||||
|
camera.attachControl(canvas, true);
|
||||||
|
const light1: HemisphericLight = new HemisphericLight("light1", new Vector3(1, 1, 0), scene);
|
||||||
|
const sphere: Mesh = MeshBuilder.CreateCylinder("sphere", {diameter: 1}, scene);
|
||||||
|
sphere.setAbsolutePosition(new Vector3(0, 2, -5));
|
||||||
|
|
||||||
|
const cylinder: Mesh = MeshBuilder.CreateCylinder("platform", {diameter: 1.5, height: .01}, scene);
|
||||||
|
const myMaterial = new StandardMaterial("myMaterial", scene);
|
||||||
|
myMaterial.diffuseColor = Color3.Blue();
|
||||||
|
cylinder.material = myMaterial;
|
||||||
|
cylinder.setAbsolutePosition(new Vector3(0, .1, -3));
|
||||||
|
const sphereAggregate =
|
||||||
|
new PhysicsAggregate(
|
||||||
|
cylinder,
|
||||||
|
PhysicsShapeType.CYLINDER,
|
||||||
|
{ friction: 1, center: Vector3.Zero(), radius: .5, mass: .1, restitution: .1},
|
||||||
|
scene);
|
||||||
|
|
||||||
|
sphereAggregate.body.setGravityFactor(0);
|
||||||
|
|
||||||
|
//sphereAggregate.body.applyForce(new Vector3(0, 0,-1), cylinder.position);
|
||||||
|
const photoDome = new PhotoDome('sky',
|
||||||
|
'./outdoor_field.jpeg', {},
|
||||||
|
scene);
|
||||||
|
const groundMaterial = new PBRMetallicRoughnessMaterial("groundMaterial", scene);
|
||||||
|
const gText = new Texture("./grass1.jpeg", scene);
|
||||||
|
gText.uScale =40;
|
||||||
|
gText.vScale=40;
|
||||||
|
|
||||||
|
scene.registerBeforeRender(() => {
|
||||||
|
const q = cylinder.rotationQuaternion;
|
||||||
|
const e = q.toEulerAngles();
|
||||||
|
q.copyFrom(Quaternion.FromEulerAngles(0, e.y, 0));
|
||||||
|
});
|
||||||
|
|
||||||
|
groundMaterial.baseTexture = gText;
|
||||||
|
groundMaterial.metallic =0;
|
||||||
|
groundMaterial.roughness=1;
|
||||||
|
const ground = MeshBuilder.CreateGround("ground", {width: 100, height: 100, subdivisions: 1}, scene);
|
||||||
|
|
||||||
|
ground.material = groundMaterial;
|
||||||
|
const groundAggregate = new PhysicsAggregate(ground, PhysicsShapeType.BOX, {mass: 0}, scene);
|
||||||
|
|
||||||
|
const xr = await WebXRDefaultExperience.CreateAsync(scene, {floorMeshes: [ground],
|
||||||
|
optionalFeatures: true});
|
||||||
|
xr.baseExperience.camera.parent = cylinder;
|
||||||
|
|
||||||
|
const stickVector = Vector3.Zero();
|
||||||
|
|
||||||
|
xr.input.onControllerAddedObservable.add((source, state) => {
|
||||||
|
let controller;
|
||||||
|
switch (source.inputSource.handedness) {
|
||||||
|
case "right":
|
||||||
|
controller = new Right(source);
|
||||||
|
break;
|
||||||
|
case "left":
|
||||||
|
controller = new Left(source);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
xr.baseExperience.camera.position = new Vector3(0, 1.6, 0);
|
||||||
|
if (controller) {
|
||||||
|
controller.setStickVector(stickVector);
|
||||||
|
controller.setCamera(xr.baseExperience.camera);
|
||||||
|
controller.setRig(sphereAggregate.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(source);
|
||||||
|
console.log(state);
|
||||||
|
});
|
||||||
|
xr.teleportation.detach();
|
||||||
|
|
||||||
|
// hide/show the Inspector
|
||||||
|
window.addEventListener("keydown", (ev) => {
|
||||||
|
// Shift+Ctrl+Alt+I
|
||||||
|
if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) {
|
||||||
|
if (scene.debugLayer.isVisible()) {
|
||||||
|
scene.debugLayer.hide();
|
||||||
|
} else {
|
||||||
|
scene.debugLayer.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// run the main render loop
|
||||||
|
engine.runRenderLoop(() => {
|
||||||
|
scene.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new App();
|
||||||
23
src/controllers/base.ts
Normal file
23
src/controllers/base.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import {Observable, PhysicsBody, Scene, Vector3, WebXRCamera, WebXRInputSource} from "@babylonjs/core";
|
||||||
|
|
||||||
|
export class Base {
|
||||||
|
protected controller: WebXRInputSource;
|
||||||
|
protected stickVector: Vector3;
|
||||||
|
protected body: PhysicsBody;
|
||||||
|
protected camera: WebXRCamera;
|
||||||
|
protected speedFactor = 2;
|
||||||
|
constructor(controller:
|
||||||
|
WebXRInputSource) {
|
||||||
|
this.controller = controller;
|
||||||
|
}
|
||||||
|
setRig(body: PhysicsBody) {
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
setCamera(camera: WebXRCamera) {
|
||||||
|
this.camera = camera;
|
||||||
|
}
|
||||||
|
setStickVector(vector: Vector3) {
|
||||||
|
this.stickVector = vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
44
src/controllers/left.ts
Normal file
44
src/controllers/left.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import {Quaternion, Vector3, WebXRInputSource} from "@babylonjs/core";
|
||||||
|
import {Base} from "./base";
|
||||||
|
|
||||||
|
export class Left extends Base {
|
||||||
|
private y90 = Quaternion.RotationAxis(Vector3.Right(), 1.5708);
|
||||||
|
private x90 = Quaternion.RotationAxis(Vector3.Up(), 1.5708);
|
||||||
|
|
||||||
|
constructor(controller:
|
||||||
|
WebXRInputSource) {
|
||||||
|
super(controller);
|
||||||
|
this.controller.onMotionControllerInitObservable.add((init) => {
|
||||||
|
if (init.components['xr-standard-thumbstick']) {
|
||||||
|
init.components['xr-standard-thumbstick']
|
||||||
|
.onAxisValueChangedObservable.add((value) => {
|
||||||
|
const ray = this.camera.getForwardRay();
|
||||||
|
if (Math.abs(value.x) > .1) {
|
||||||
|
const direction = ray.direction.applyRotationQuaternion(this.x90).scale(value.x*this.speedFactor);
|
||||||
|
this.body.setLinearVelocity(direction);
|
||||||
|
this.stickVector.x = 1;
|
||||||
|
} else {
|
||||||
|
this.stickVector.x = 0;
|
||||||
|
}
|
||||||
|
if (Math.abs(value.y) > .1) {
|
||||||
|
let direction = Vector3.Zero();
|
||||||
|
this.body.getLinearVelocityToRef(direction);
|
||||||
|
direction.y = (value.y*-1*this.speedFactor);
|
||||||
|
this.body.setLinearVelocity(direction);
|
||||||
|
this.stickVector.y = 1;
|
||||||
|
} else {
|
||||||
|
this.stickVector.y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.stickVector.equals(Vector3.Zero())) {
|
||||||
|
this.body.setLinearVelocity(Vector3.Zero());
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/controllers/right.ts
Normal file
40
src/controllers/right.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import {Base} from "./base";
|
||||||
|
import {Observer, Quaternion, Vector3, WebXRInputSource} from "@babylonjs/core";
|
||||||
|
import {Logger} from "../util/logger";
|
||||||
|
|
||||||
|
export class Right extends Base {
|
||||||
|
public stickY;
|
||||||
|
public stickX;
|
||||||
|
|
||||||
|
constructor(controller:
|
||||||
|
WebXRInputSource) {
|
||||||
|
super(controller);
|
||||||
|
this.controller.onMotionControllerInitObservable.add((init)=> {
|
||||||
|
if (init.components['xr-standard-thumbstick']) {
|
||||||
|
init.components['xr-standard-thumbstick']
|
||||||
|
.onAxisValueChangedObservable.add((value) => {
|
||||||
|
const ray = this.camera.getForwardRay();
|
||||||
|
if (Math.abs(value.x) > .1) {
|
||||||
|
this.body.setAngularVelocity(Vector3.Up().scale(value.x));
|
||||||
|
} else {
|
||||||
|
this.body.setAngularVelocity(Vector3.Zero());
|
||||||
|
}
|
||||||
|
if (Math.abs(value.y) > .1) {
|
||||||
|
this.body.setLinearVelocity(ray.direction.scale(value.y*-1*this.speedFactor));
|
||||||
|
this.stickVector.z = 1;
|
||||||
|
} else {
|
||||||
|
this.stickVector.z = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (this.stickVector.equals(Vector3.Zero())) {
|
||||||
|
this.body.setLinearVelocity(Vector3.Zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
5
src/database.ts
Normal file
5
src/database.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class Database {
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/util/havok.ts
Normal file
3
src/util/havok.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import HavokPlugin from "@babylonjs/havok";
|
||||||
|
|
||||||
|
export const havokModule = HavokPlugin();
|
||||||
5
src/util/logger.ts
Normal file
5
src/util/logger.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export class Logger {
|
||||||
|
static debug(value) {
|
||||||
|
console.log(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
22
tsconfig.json
Normal file
22
tsconfig.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6", // choose our ECMA/JavaScript version (all modern browsers support ES6 so it's your best bet)
|
||||||
|
"lib": [ // choose our default ECMA/libraries to import
|
||||||
|
"dom", // mandatory for all browser-based apps
|
||||||
|
"es6" // mandatory for targeting ES6
|
||||||
|
],
|
||||||
|
"useDefineForClassFields": true, // enable latest ECMA runtime behavior with older ECMA/JavaScript versions (delete this line if target: "ESNext" or "ES2022"+)
|
||||||
|
"module": "ESNext", // use the latest ECMA/JavaScript syntax for our import statements and such
|
||||||
|
"moduleResolution": "node", // ensures we are using CommonJS for our npm packages
|
||||||
|
"noResolve": false, // disable TypeScript from automatically detecting/adding files based on import statements and etc (it's less helpful than you think)
|
||||||
|
"isolatedModules": true, // allows our code to be processed by other transpilers, such as preventing non-module TS files (you could delete this since we're only using base TypeScript)
|
||||||
|
"removeComments": true, // remove comments from our outputted code to save on space (look into terser if you want to protect the outputted JS even more)
|
||||||
|
"esModuleInterop": true, // treats non-ES6 modules separately from ES6 modules (helpful if module: "ESNext")
|
||||||
|
"noImplicitAny": false, // usually prevents code from using "any" type fallbacks to prevent untraceable JS errors, but we'll need this disabled for our example code
|
||||||
|
"noUnusedLocals": false, // usually raises an error for any unused local variables, but we'll need this disabled for our example code
|
||||||
|
"noUnusedParameters": true, // raises an error for unused parameters
|
||||||
|
"noImplicitReturns": true, // raises an error for functions that return nothing
|
||||||
|
"skipLibCheck": true // skip type-checking of .d.ts files (it speeds up transpiling)
|
||||||
|
},
|
||||||
|
"include": ["src"] // specify location(s) of .ts files
|
||||||
|
}
|
||||||
20
vite.config.ts
Normal file
20
vite.config.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import { pluginAPI } from "vite-plugin-api";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
server: {
|
||||||
|
port: 3000
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
pluginAPI({
|
||||||
|
// routeBase?: "api",
|
||||||
|
// dirs?: [{ dir: "src/api"; route: "", exclude?: ["*.txt", ".csv", "data/*.*"] }],
|
||||||
|
// include?: ["**/*.js", "**/*.ts"],
|
||||||
|
// exclude?: ["node_modules", ".git"],
|
||||||
|
// moduleId?: "virtual:vite-plugin-api",
|
||||||
|
// mapper?: { default: "use", GET: "get", ... },
|
||||||
|
// entry?: "[node_module:lib]/server.js",
|
||||||
|
// handler?: "[node_module:lib]/handler.js",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user