Skip to content

Commit

Permalink
Default Character Update (#102)
Browse files Browse the repository at this point in the history
* updates default character

* removes unecessary arguments indicating if character is Local or Remote

* removes unecessary arguments indicating if character is Local or Remote

* prevents custom material application for MML Characters

* updates LocalAvatarClient to use the new default character

* improves custom material for the default character

* updates default character and documents how to use MML Characters in the experience

* tweaks default rendering settings to better suit MML characters and the new default character

* updates project's README screenshot

* updates README.md
  • Loading branch information
TheCodeTherapy authored Jan 31, 2024
1 parent 02315ee commit 535ad4e
Show file tree
Hide file tree
Showing 13 changed files with 72 additions and 50 deletions.
Binary file removed Playground.png
Binary file not shown.
36 changes: 22 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

<img src="./Playground.png">
<img src="./playground.png">

## Main features

Expand Down
3 changes: 0 additions & 3 deletions example/assets/models/andor.glb

This file was deleted.

3 changes: 3 additions & 0 deletions example/assets/models/bot.glb
Git LFS file not shown
2 changes: 1 addition & 1 deletion example/local-multi-web-client/src/LocalAvatarClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
13 changes: 11 additions & 2 deletions example/web-client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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
<m-character> tag, or just by passing your MML Character description in a string
like in the example below:
`
<m-character src="../../assets/models/andor.glb">
<m-character src="../../assets/models/bot.glb">
</m-character>
`,
*/
);
this.scene.add(this.characterManager.group);

Expand Down
9 changes: 2 additions & 7 deletions packages/3d-web-client-core/src/character/Character.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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();
Expand All @@ -41,11 +40,7 @@ export class Character extends Group {
}

private async load(): Promise<void> {
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) {
Expand Down
2 changes: 0 additions & 2 deletions packages/3d-web-client-core/src/character/CharacterManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ export class CharacterManager {
},
this.cameraManager,
this.composer,
true,
);
const quaternion = new Quaternion().setFromEuler(character.rotation);
this.sendUpdate({
Expand Down Expand Up @@ -172,7 +171,6 @@ export class CharacterManager {
},
this.cameraManager,
this.composer,
false,
);

this.remoteCharacters.set(id, character);
Expand Down
12 changes: 6 additions & 6 deletions packages/3d-web-client-core/src/character/CharacterMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ export class CharacterMaterial extends MeshPhysicalMaterial {
public uniforms: Record<string, TUniform> = {};
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;
Expand Down Expand Up @@ -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;
`,
);
};
Expand All @@ -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;

Expand Down
30 changes: 21 additions & 9 deletions packages/3d-web-client-core/src/character/CharacterModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import {
AnimationClip,
AnimationMixer,
Bone,
Color,
Group,
LoopRepeat,
Mesh,
MeshStandardMaterial,
Object3D,
SkinnedMesh,
} from "three";

import { CharacterDescription } from "./Character";
Expand All @@ -27,7 +30,6 @@ export class CharacterModel {
constructor(
private readonly characterDescription: CharacterDescription,
private characterModelLoader: CharacterModelLoader,
private isLocal: boolean,
) {}

public async init(): Promise<void> {
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -22,7 +22,7 @@ const sunOptions = {

export const envValues = {
ambientLight: {
ambientLightIntensity: 0.21,
ambientLightIntensity: 0.05,
ambientLightColor: { r: 1, g: 1, b: 1 },
},
fog: {
Expand Down
Binary file added playground.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 535ad4e

Please sign in to comment.