diff --git a/Playground.png b/Playground.png
deleted file mode 100644
index 3d3b12af..00000000
Binary files a/Playground.png and /dev/null differ
diff --git a/README.md b/README.md
index d972be6c..98ddc448 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,30 @@
# (MML) 3D Web Experience
-This repository contains packages used to run a web-based, multi-user 3D web experience that supports
-[MML (Metaverse Markup Language)](https://mml.io/). This repository includes two published packages:
-
-* [`@mml-io/3d-web-client-core`](./packages/3d-web-client-core) - A package that implements the main components of a 3D web experience.
-* [`@mml-io/3d-web-user-networking`](./packages/3d-web-user-networking) - A package that contains WebSocket server and client implementations that synchronize user positions.
-
-There is an example implementation of a 3D web experience in the `examples` directory. This example contains:
-
-* `web-client`
- * A THREE.js 3D experience utilizing the `@mml-io/3d-web-client-core` and `@mml-io/3d-web-user-networking` packages to create a multi-user 3D web client that connects to the server.
-* `server`
- * A server which serves the `web-client` and handles user networking WebSocket connections with `@mml-io/3d-web-user-networking`
- * Additionally, the server runs MML documents in the `mml-documents` directory which are then connected to by the `web-client`.
+This repository contains packages used to run a web-based, multi-user 3D web experience that
+supports [MML (Metaverse Markup Language)](https://mml.io/). This repository includes two published
+packages:
+
+- [`@mml-io/3d-web-client-core`](./packages/3d-web-client-core) - A package that implements the main
+ components of a 3D web experience.
+- [`@mml-io/3d-web-user-networking`](./packages/3d-web-user-networking) - A package that contains
+ WebSocket server and client implementations that synchronize user positions.
+
+There is an example implementation of a 3D web experience in the `examples` directory. This example
+contains:
+
+- `web-client`
+ - A THREE.js 3D experience utilizing the `@mml-io/3d-web-client-core` and
+ `@mml-io/3d-web-user-networking` packages to create a multi-user 3D web client that connects to
+ the server.
+- `server`
+ - A server which serves the `web-client` and handles user networking WebSocket connections with
+ `@mml-io/3d-web-user-networking`
+ - Additionally, the server runs MML documents in the `mml-documents` directory which are then
+ connected to by the `web-client`.
It can be easily deployed to environments that support Node.js and expose ports to the internet.
-
+
## Main features
diff --git a/example/assets/models/andor.glb b/example/assets/models/andor.glb
deleted file mode 100644
index 01c2f22b..00000000
--- a/example/assets/models/andor.glb
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:3715b17ffae5379afeac8598d93dc9d378d909fbd473a8f51c9af51e2fcd6881
-size 7305648
diff --git a/example/assets/models/bot.glb b/example/assets/models/bot.glb
new file mode 100644
index 00000000..050e7026
--- /dev/null
+++ b/example/assets/models/bot.glb
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:28effaa4bc6aca601e8988d46e8285e4c126107538055bd03962aa99929cb40b
+size 2142360
diff --git a/example/local-multi-web-client/src/LocalAvatarClient.ts b/example/local-multi-web-client/src/LocalAvatarClient.ts
index 75990a13..5d1706bd 100644
--- a/example/local-multi-web-client/src/LocalAvatarClient.ts
+++ b/example/local-multi-web-client/src/LocalAvatarClient.ts
@@ -15,11 +15,11 @@ import { MMLWebRunnerClient } from "mml-web-runner";
import { AudioListener, Euler, Scene, Vector3 } from "three";
import hdrUrl from "../../assets/hdr/industrial_sunset_2k.hdr";
-import meshFileUrl from "../../assets/models/andor.glb";
import airAnimationFileUrl from "../../assets/models/anim_air.glb";
import idleAnimationFileUrl from "../../assets/models/anim_idle.glb";
import jogAnimationFileUrl from "../../assets/models/anim_jog.glb";
import sprintAnimationFileUrl from "../../assets/models/anim_run.glb";
+import meshFileUrl from "../../assets/models/bot.glb";
import { LocalAvatarServer } from "./LocalAvatarServer";
import { Room } from "./Room";
diff --git a/example/web-client/src/index.ts b/example/web-client/src/index.ts
index 84f1d9f5..3a3be56d 100644
--- a/example/web-client/src/index.ts
+++ b/example/web-client/src/index.ts
@@ -29,11 +29,11 @@ import {
import { AudioListener, Euler, Scene, Vector3 } from "three";
import hdrUrl from "../../assets/hdr/industrial_sunset_2k.hdr";
-import meshFileUrl from "../../assets/models/andor.glb";
import airAnimationFileUrl from "../../assets/models/anim_air.glb";
import idleAnimationFileUrl from "../../assets/models/anim_idle.glb";
import jogAnimationFileUrl from "../../assets/models/anim_jog.glb";
import sprintAnimationFileUrl from "../../assets/models/anim_run.glb";
+import meshFileUrl from "../../assets/models/bot.glb";
import { LoadingScreen } from "./LoadingScreen";
import { Room } from "./Room";
@@ -157,10 +157,19 @@ export class App {
this.latestCharacterObject.characterState = characterState;
this.networkClient.sendUpdate(characterState);
},
+ /*
+ If you want to use an MML Character in the experience, this is where you should
+ pass it as an argument.
+
+ MML Characters can be loaded by passing a URL that can be fetched and serve your
+ tag, or just by passing your MML Character description in a string
+ like in the example below:
+
`
-
+
`,
+ */
);
this.scene.add(this.characterManager.group);
diff --git a/packages/3d-web-client-core/src/character/Character.ts b/packages/3d-web-client-core/src/character/Character.ts
index cf7c7bbf..bc922fb6 100644
--- a/packages/3d-web-client-core/src/character/Character.ts
+++ b/packages/3d-web-client-core/src/character/Character.ts
@@ -1,4 +1,4 @@
-import { Color, Group, Object3D, Vector3 } from "three";
+import { Color, Group, MeshStandardMaterial, Object3D, SkinnedMesh, Vector3 } from "three";
import { CameraManager } from "../camera/CameraManager";
import { Composer } from "../rendering/composer";
@@ -32,7 +32,6 @@ export class Character extends Group {
private readonly modelLoadedCallback: () => void,
private readonly cameraManager: CameraManager,
private readonly composer: Composer,
- private readonly isLocal: boolean,
) {
super();
this.tooltip = new CharacterTooltip();
@@ -41,11 +40,7 @@ export class Character extends Group {
}
private async load(): Promise {
- this.model = new CharacterModel(
- this.characterDescription,
- this.characterModelLoader,
- this.isLocal,
- );
+ this.model = new CharacterModel(this.characterDescription, this.characterModelLoader);
await this.model.init();
this.add(this.model.mesh!);
if (this.speakingIndicator === null) {
diff --git a/packages/3d-web-client-core/src/character/CharacterManager.ts b/packages/3d-web-client-core/src/character/CharacterManager.ts
index 35adc937..98f2b84c 100644
--- a/packages/3d-web-client-core/src/character/CharacterManager.ts
+++ b/packages/3d-web-client-core/src/character/CharacterManager.ts
@@ -127,7 +127,6 @@ export class CharacterManager {
},
this.cameraManager,
this.composer,
- true,
);
const quaternion = new Quaternion().setFromEuler(character.rotation);
this.sendUpdate({
@@ -172,7 +171,6 @@ export class CharacterManager {
},
this.cameraManager,
this.composer,
- false,
);
this.remoteCharacters.set(id, character);
diff --git a/packages/3d-web-client-core/src/character/CharacterMaterial.ts b/packages/3d-web-client-core/src/character/CharacterMaterial.ts
index 5883ccca..48c1e7ce 100644
--- a/packages/3d-web-client-core/src/character/CharacterMaterial.ts
+++ b/packages/3d-web-client-core/src/character/CharacterMaterial.ts
@@ -14,9 +14,11 @@ export class CharacterMaterial extends MeshPhysicalMaterial {
public uniforms: Record = {};
public colorsCube216: Color[] = [];
- constructor() {
+ constructor(color?: Color) {
super();
- this.color = new Color(0xffffff);
+ if (color) {
+ this.color = color;
+ }
this.transmission = characterValues.transmission;
this.metalness = characterValues.metalness;
this.roughness = characterValues.roughness;
@@ -124,8 +126,6 @@ export class CharacterMaterial extends MeshPhysicalMaterial {
vec3 grid = vec3(smoothstep(0.01, 0.0, a) * 1.15) * diffuseRandomColor;
outgoingLight += grid;
#endif
-
- outgoingLight += smoothstep(0.1, 0.0, scanLines) * 0.1;
`,
);
};
@@ -134,8 +134,8 @@ export class CharacterMaterial extends MeshPhysicalMaterial {
}
private generateColorCube() {
- const saturation = 0.4;
- const lightness = 0.7;
+ const saturation = 0.5;
+ const lightness = 0.9;
const goldenRatioConjugate = 0.618033988749895;
let hue = 0;
diff --git a/packages/3d-web-client-core/src/character/CharacterModel.ts b/packages/3d-web-client-core/src/character/CharacterModel.ts
index 7276b9fe..165d4e7c 100644
--- a/packages/3d-web-client-core/src/character/CharacterModel.ts
+++ b/packages/3d-web-client-core/src/character/CharacterModel.ts
@@ -4,10 +4,13 @@ import {
AnimationClip,
AnimationMixer,
Bone,
+ Color,
Group,
LoopRepeat,
Mesh,
+ MeshStandardMaterial,
Object3D,
+ SkinnedMesh,
} from "three";
import { CharacterDescription } from "./Character";
@@ -27,7 +30,6 @@ export class CharacterModel {
constructor(
private readonly characterDescription: CharacterDescription,
private characterModelLoader: CharacterModelLoader,
- private isLocal: boolean,
) {}
public async init(): Promise {
@@ -54,23 +56,33 @@ export class CharacterModel {
this.characterDescription.airAnimationFileUrl,
AnimationState.air,
);
- }
-
- public updateAnimation(targetAnimation: AnimationState) {
- if (this.currentAnimation !== targetAnimation) {
- this.transitionToAnimation(targetAnimation);
+ if (!this.characterDescription.meshModel) {
+ this.applyCustomMaterial(this.material);
}
}
- private applyMaterialToAllSkinnedMeshes(material: CharacterMaterial): void {
+ private applyCustomMaterial(material: CharacterMaterial): void {
if (!this.mesh) return;
this.mesh.traverse((child: Object3D) => {
- if (child.type === "SkinnedMesh") {
- (child as Mesh).material = material;
+ const asSkinnedMesh = child as SkinnedMesh;
+ if (asSkinnedMesh.isSkinnedMesh) {
+ const mat = asSkinnedMesh.material as MeshStandardMaterial;
+ if (!mat.name.includes("joints")) {
+ asSkinnedMesh.material = material;
+ } else {
+ const color = mat.color;
+ asSkinnedMesh.material = new CharacterMaterial(color);
+ }
}
});
}
+ public updateAnimation(targetAnimation: AnimationState) {
+ if (this.currentAnimation !== targetAnimation) {
+ this.transitionToAnimation(targetAnimation);
+ }
+ }
+
private setMainMesh(mainMesh: Object3D, name: string): void {
this.mesh = mainMesh;
this.mesh.position.set(0, -0.4, 0);
diff --git a/packages/3d-web-client-core/src/tweakpane/blades/characterFolder.ts b/packages/3d-web-client-core/src/tweakpane/blades/characterFolder.ts
index 43273026..5bb3142f 100644
--- a/packages/3d-web-client-core/src/tweakpane/blades/characterFolder.ts
+++ b/packages/3d-web-client-core/src/tweakpane/blades/characterFolder.ts
@@ -3,15 +3,15 @@ import { BladeApi, FolderApi, TpChangeEvent } from "tweakpane";
export const characterValues = {
transmission: 0.01,
- metalness: 0.8,
- roughness: 0.05,
+ metalness: 0.2,
+ roughness: 0.8,
ior: 1.0,
thickness: 0.1,
specularColor: { r: 1.0, g: 1.0, b: 1.0 },
specularIntensity: 0.1,
emissive: { r: 1.0, g: 1.0, b: 1.0 },
- emissiveIntensity: 0.1,
- envMapIntensity: 0.9,
+ emissiveIntensity: 0.01,
+ envMapIntensity: 0.12,
sheenColor: { r: 1.0, g: 1.0, b: 1.0 },
sheen: 0.5,
clearcoat: 0.0,
diff --git a/packages/3d-web-client-core/src/tweakpane/blades/environmentFolder.ts b/packages/3d-web-client-core/src/tweakpane/blades/environmentFolder.ts
index 3b1afc68..1dda4ab1 100644
--- a/packages/3d-web-client-core/src/tweakpane/blades/environmentFolder.ts
+++ b/packages/3d-web-client-core/src/tweakpane/blades/environmentFolder.ts
@@ -9,7 +9,7 @@ export const sunValues = {
sunPolarAngle: -39,
},
sunIntensity: 1,
- sunColor: { r: 1.0, g: 0.74, b: 0.5 },
+ sunColor: { r: 1.0, g: 1.0, b: 1.0 },
};
const sunOptions = {
@@ -22,7 +22,7 @@ const sunOptions = {
export const envValues = {
ambientLight: {
- ambientLightIntensity: 0.21,
+ ambientLightIntensity: 0.05,
ambientLightColor: { r: 1, g: 1, b: 1 },
},
fog: {
diff --git a/playground.png b/playground.png
new file mode 100644
index 00000000..502ce33f
Binary files /dev/null and b/playground.png differ