Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default Character Update #102

Merged
merged 10 commits into from
Jan 31, 2024
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.
Loading