@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
80 lines • 3.24 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Object3D } from "three";
import { serializable } from "../../engine/engine_serialization_decorator.js";
import * as utils from "../../engine/engine_utils.js";
import { Behaviour, GameObject } from "../Component.js";
import { Voip } from "../Voip.js";
import { AvatarMarker } from "../webxr/WebXRAvatar.js";
const debug = utils.getParam("debugmouth");
/** @internal */
export class Avatar_MouthShapes extends Behaviour {
idle = [];
talking = [];
marker = null;
voip = null;
lastMouthChangeTime = 0;
mouthChangeLength = 0;
awake() {
setTimeout(() => {
this.voip = GameObject.findObjectOfType(Voip, this.context);
if (!this.marker)
this.marker = GameObject.getComponentInParent(this.gameObject, AvatarMarker);
}, 3000);
}
update() {
if (!this.voip)
return;
if (this.context.time.frameCount % 10 !== 0)
return;
let id = this.marker?.connectionId ?? null;
if (!id) {
if (debug)
id = null;
return;
}
const freq = this.voip.getFrequency(id) ?? 0;
this.updateLips(freq);
}
updateLips(frequency) {
if (this.context.time.time - this.lastMouthChangeTime > this.mouthChangeLength) {
this.mouthChangeLength = .05 + Math.random() * .1;
if (this.talking && this.talking.length > 0 && frequency > 30) {
this.lastMouthChangeTime = this.context.time.time;
const index = Math.floor(Math.random() * this.talking.length);
this.setMouthShapeActive(this.talking, index);
}
else if (this.idle.length > 0 && this.context.time.time - this.lastMouthChangeTime > .5) {
this.lastMouthChangeTime = this.context.time.time;
const index = Math.floor(Math.random() * this.idle.length);
this.setMouthShapeActive(this.idle, index);
}
}
}
setMouthShapeActive(arr, index) {
if (!arr)
return;
// hide other
if (arr != this.idle)
this.idle.map(i => i.visible = false);
else
this.talking.map(i => i.visible = false);
for (let i = 0; i < arr.length; i++) {
const shape = arr[i];
if (shape) {
shape.visible = i === index;
}
}
}
}
__decorate([
serializable(Object3D)
], Avatar_MouthShapes.prototype, "idle", void 0);
__decorate([
serializable(Object3D)
], Avatar_MouthShapes.prototype, "talking", void 0);
//# sourceMappingURL=Avatar_MouthShapes.js.map