janusweb 1.5.29 → 1.5.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/media/assets/janus-avatar-animations.glb +0 -0
- package/media/assets/janus-avatar-base.glb +0 -0
- package/media/assets/webui/apps/avatar/avatar.css +6 -2
- package/media/assets/webui/apps/avatar/avatar.js +97 -10
- package/media/assets/webui/apps/buttons/buttons.html +2 -2
- package/media/assets/webui/apps/buttons/buttons.js +3 -3
- package/media/assets/webui/apps/comms/comms.js +7 -4
- package/media/assets/webui/apps/comms/voip.js +138 -55
- package/media/assets/webui/apps/editor/editor.js +2 -0
- package/media/assets/webui/apps/inventory/inventory.html +7 -4
- package/media/assets/webui/apps/inventory/inventory.js +1 -1
- package/media/assets/webui/apps/locomotion/teleporter.js +9 -8
- package/media/assets/webui/apps/settings/settings.html +1 -1
- package/media/assets/webui/apps/virtualgamepad/virtualgamepad.js +9 -7
- package/media/assets/webui/apps/xrmenu/xrmenu.js +13 -4
- package/media/assets/webui/none.json +1 -0
- package/media/assets.json +2 -1
- package/media/index.html +1 -1
- package/media/lib/draco/README.md +32 -0
- package/media/lib/draco/draco_decoder.js +52 -0
- package/media/lib/draco/draco_decoder.wasm +0 -0
- package/media/lib/draco/draco_encoder.js +33 -0
- package/media/lib/draco/draco_wasm_wrapper.js +104 -0
- package/media/lib/draco/gltf/draco_decoder.js +48 -0
- package/media/lib/draco/gltf/draco_decoder.wasm +0 -0
- package/media/lib/draco/gltf/draco_encoder.js +33 -0
- package/media/lib/draco/gltf/draco_wasm_wrapper.js +104 -0
- package/media/lib/physx/physx.release.js +21 -0
- package/media/lib/physx/physx.release.wasm +0 -0
- package/media/manifest.json +5 -5
- package/media/service-worker.js +7 -0
- package/package.json +1 -1
- package/scripts/client.js +4 -3
- package/scripts/config.js +2 -0
- package/scripts/elements/linesegments.js +5 -1
- package/scripts/external/JanusFireboxParser.js +1 -0
- package/scripts/image.js +7 -1
- package/scripts/janusbase.js +83 -34
- package/scripts/janusghost.js +314 -15
- package/scripts/januslight.js +11 -2
- package/scripts/janusparagraph.js +3 -3
- package/scripts/janusparticle.js +16 -5
- package/scripts/janusplayer.js +124 -35
- package/scripts/janusweb.js +5 -0
- package/scripts/janusxrplayer.js +2 -3
- package/scripts/multiplayermanager.js +3 -1
- package/scripts/object.js +106 -10
- package/scripts/portal.js +28 -12
- package/scripts/remoteplayer.js +1 -25
- package/scripts/room.js +116 -36
- package/scripts/sound.js +8 -5
- package/scripts/text.js +3 -3
- package/scripts/websurface.js +6 -1
- package/utils/build.sh +3 -0
- package/utils/init.sh +2 -2
- package/scripts/chat.js +0 -80
- package/scripts/ui.js +0 -265
- package/scripts/urlbar.js +0 -93
- package/templates/janusweb.tpl +0 -3
package/scripts/janusbase.js
CHANGED
|
@@ -54,6 +54,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
|
|
|
54
54
|
ongazeleave: { type: 'callback' },
|
|
55
55
|
ongazeprogress: { type: 'callback' },
|
|
56
56
|
ongazeactivate: { type: 'callback' },
|
|
57
|
+
oncollision: { type: 'callback' },
|
|
57
58
|
});
|
|
58
59
|
this.lastframevalues = {
|
|
59
60
|
position: new THREE.Vector3(0,0,0),
|
|
@@ -129,7 +130,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
|
|
|
129
130
|
this.removeCollider();
|
|
130
131
|
if (!(this.collidable || this.pickable) || !this.objects['dynamics']) return;
|
|
131
132
|
var collision_id = this.collision_id || this.collider_id;
|
|
132
|
-
var collision_scale = this.scale
|
|
133
|
+
var collision_scale = V().copy(this.scale);
|
|
133
134
|
if (this.collision_scale) {
|
|
134
135
|
collision_scale.multiply(this.collision_scale);
|
|
135
136
|
}
|
|
@@ -154,7 +155,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
|
|
|
154
155
|
} else if (collision_id == 'cylinder') {
|
|
155
156
|
this.setCollider('cylinder', {height: 1, radius: .5, offset: new THREE.Vector3(0, 0.5, 0), trigger: this.collision_trigger});
|
|
156
157
|
} else if (collision_id == 'capsule') {
|
|
157
|
-
this.setCollider('capsule', {
|
|
158
|
+
this.setCollider('capsule', {length: 1, radius: .5, offset: new THREE.Vector3(0, 0, 0), trigger: this.collision_trigger});
|
|
158
159
|
} else {
|
|
159
160
|
var colliderasset = this.getAsset('model', collision_id);
|
|
160
161
|
if (colliderasset) {
|
|
@@ -174,24 +175,25 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
|
|
|
174
175
|
let remove = [];
|
|
175
176
|
collider.traverse(n => {
|
|
176
177
|
// Ignore collider if it's too high-poly
|
|
177
|
-
if (n instanceof THREE.Mesh &&
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
178
|
+
if (n instanceof THREE.Mesh && n.geometry instanceof THREE.BufferGeometry) {
|
|
179
|
+
if (n.geometry.attributes.position.count > 65536) {
|
|
180
|
+
console.warn('Collider mesh rejected, too many polys!', collision_id, this, n, collider);
|
|
181
|
+
elation.events.fire({type: 'thing_collider_rejected', element: this, data: {root: collider, mesh: n}});
|
|
182
|
+
remove.push(n);
|
|
183
|
+
} else {
|
|
184
|
+
if (n.material) {
|
|
185
|
+
n.material = new THREE.MeshPhongMaterial({
|
|
186
|
+
color: collidercolor,
|
|
187
|
+
opacity: .2,
|
|
188
|
+
transparent: true,
|
|
189
|
+
emissive: 0x444400,
|
|
190
|
+
alphaTest: .01,
|
|
191
|
+
depthTest: false,
|
|
192
|
+
depthWrite: false
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
n.userData.thing = this;
|
|
193
196
|
}
|
|
194
|
-
n.userData.thing = this;
|
|
195
197
|
}
|
|
196
198
|
});
|
|
197
199
|
if (remove.length > 0) {
|
|
@@ -205,8 +207,12 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
|
|
|
205
207
|
//this.colliders.add(collider);
|
|
206
208
|
processMeshCollider(collider);
|
|
207
209
|
} else {
|
|
210
|
+
let meshColliderLoaded = false;
|
|
208
211
|
elation.events.add(collider, 'asset_load', elation.bind(this, function(ev) {
|
|
209
|
-
|
|
212
|
+
if (!meshColliderLoaded) {
|
|
213
|
+
processMeshCollider(collider);
|
|
214
|
+
}
|
|
215
|
+
meshColliderLoaded = true;
|
|
210
216
|
}) );
|
|
211
217
|
}
|
|
212
218
|
}
|
|
@@ -286,7 +292,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
|
|
|
286
292
|
}
|
|
287
293
|
} else if (val instanceof THREE.Color) {
|
|
288
294
|
if (defaultval instanceof THREE.Color) defaultval = defaultval.toArray();
|
|
289
|
-
if (!('default' in propdef) || ('default' in propdef && !(val.r == defaultval[0] && val.g == defaultval[1] && val.b == defaultval[2]))) {
|
|
295
|
+
if (!('default' in propdef) || defaultval === null || ('default' in propdef && !(val.r == defaultval[0] && val.g == defaultval[1] && val.b == defaultval[2]))) {
|
|
290
296
|
attrs[k] = val.toArray().map(n => Math.round(n * 10000) / 10000).join(' ');
|
|
291
297
|
}
|
|
292
298
|
} else if (val instanceof THREE.Euler) {
|
|
@@ -372,6 +378,9 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
|
|
|
372
378
|
rotate_deg_per_sec: [ 'property', 'rotate_deg_per_sec'],
|
|
373
379
|
rotate_axis: [ 'property', 'rotate_axis'],
|
|
374
380
|
|
|
381
|
+
anim_id: ['property', 'anim_id'],
|
|
382
|
+
anim_transition_time: ['property', 'anim_transition_time'],
|
|
383
|
+
|
|
375
384
|
fwd: ['property', 'zdir'],
|
|
376
385
|
xdir: ['property', 'xdir'],
|
|
377
386
|
ydir: ['property', 'ydir'],
|
|
@@ -739,7 +748,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
|
|
|
739
748
|
dir = new THREE.Vector3(),
|
|
740
749
|
up = new THREE.Vector3();
|
|
741
750
|
return function(ev) {
|
|
742
|
-
let parent = this.parent;
|
|
751
|
+
let parent = this.properties.parent;
|
|
743
752
|
let billboard = this.properties.billboard;
|
|
744
753
|
if (billboard && parent) {
|
|
745
754
|
//player.camera.localToWorld(playerpos.set(0,0,0));
|
|
@@ -896,7 +905,7 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
|
|
|
896
905
|
}
|
|
897
906
|
|
|
898
907
|
this.createObject = function(type, args, skipstart) {
|
|
899
|
-
return room.createObject(type, args, this, !this.started);
|
|
908
|
+
return this.room.createObject(type, args, this, !this.started);
|
|
900
909
|
}
|
|
901
910
|
this.appendChild = function(obj) {
|
|
902
911
|
var proxyobj = obj
|
|
@@ -934,8 +943,8 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
|
|
|
934
943
|
realobj.stop();
|
|
935
944
|
this.remove(realobj);
|
|
936
945
|
this.updateScriptChildren();
|
|
937
|
-
if (room.objects[obj.js_id]) {
|
|
938
|
-
delete room.objects[obj.js_id];
|
|
946
|
+
if (this.room.objects[obj.js_id]) {
|
|
947
|
+
delete this.room.objects[obj.js_id];
|
|
939
948
|
}
|
|
940
949
|
}
|
|
941
950
|
}
|
|
@@ -1009,25 +1018,58 @@ elation.require(['engine.things.generic', 'utils.template', 'janusweb.parts'], f
|
|
|
1009
1018
|
}
|
|
1010
1019
|
this.updateAnimation = function() {
|
|
1011
1020
|
// Triggered whenever this.anim_id changes
|
|
1012
|
-
|
|
1021
|
+
if (this.anim_id) {
|
|
1022
|
+
this.setAnimation(this.anim_id);
|
|
1023
|
+
} else if (this.activeanimation) {
|
|
1024
|
+
this.stopAnimation();
|
|
1025
|
+
}
|
|
1013
1026
|
}
|
|
1014
1027
|
this.setAnimation = function(anim_id) {
|
|
1015
|
-
if (!this.
|
|
1016
|
-
|
|
1028
|
+
if (!this.started) return;
|
|
1029
|
+
if (!this.activeanimation || anim_id != this.activeanimation._clip.name) {
|
|
1030
|
+
if (!this.animationmixer) this.extractAnimations(this.objects['3d']);
|
|
1017
1031
|
if (this.activeanimation) {
|
|
1018
1032
|
//console.log('pause active animation', this.activeanimation);
|
|
1019
1033
|
// TODO - interpolating between actions would make transitions smoother
|
|
1020
|
-
this.activeanimation.stop();
|
|
1034
|
+
//this.activeanimation.stop();
|
|
1035
|
+
//this.activeanimation.fadeOut(.5);
|
|
1036
|
+
let oldaction = this.activeanimation;
|
|
1037
|
+
if (!this.fadetimers) this.fadetimers = {};
|
|
1038
|
+
let clipname = oldaction._clip.name;
|
|
1039
|
+
if (!this.fadetimers[clipname]) {
|
|
1040
|
+
// FIXME - for some reason, THREE.AnimationAction.fadeIn() / fadeOut() / etc are just causing the animations to stop, so we'll handle fading ourselves
|
|
1041
|
+
this.fadetimers[clipname] = setInterval(() => {
|
|
1042
|
+
oldaction.weight *= .95;
|
|
1043
|
+
if (oldaction.weight <= .001) {
|
|
1044
|
+
oldaction.weight = 0;
|
|
1045
|
+
oldaction.stop();
|
|
1046
|
+
clearTimeout(this.fadetimers[clipname]);
|
|
1047
|
+
this.fadetimers[clipname] = false;
|
|
1048
|
+
}
|
|
1049
|
+
}, 20);
|
|
1050
|
+
}
|
|
1021
1051
|
}
|
|
1022
|
-
if (this.
|
|
1023
|
-
var action = this.
|
|
1024
|
-
|
|
1052
|
+
if (this.animations && this.animations[anim_id]) {
|
|
1053
|
+
var action = this.animations[anim_id];
|
|
1054
|
+
let clipname = action._clip.name;
|
|
1055
|
+
if (this.fadetimers && this.fadetimers[clipname]) {
|
|
1056
|
+
clearTimeout(this.fadetimers[clipname]);
|
|
1057
|
+
this.fadetimers[clipname] = false;
|
|
1058
|
+
}
|
|
1059
|
+
action.weight = 1;
|
|
1060
|
+
action.reset();
|
|
1025
1061
|
action.play();
|
|
1026
1062
|
this.activeanimation = action;
|
|
1027
1063
|
}
|
|
1028
1064
|
this.anim_id = anim_id;
|
|
1029
1065
|
}
|
|
1030
1066
|
}
|
|
1067
|
+
this.stopAnimation = function() {
|
|
1068
|
+
if (this.activeanimation) {
|
|
1069
|
+
this.activeanimation.stop();
|
|
1070
|
+
this.activeanimation = false;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1031
1073
|
this.dispatchEvent = function(event, target) {
|
|
1032
1074
|
if (!event.element) event.element = target || this;
|
|
1033
1075
|
if (!event.target) {
|
|
@@ -1315,9 +1357,10 @@ console.log('clone', props);
|
|
|
1315
1357
|
}
|
|
1316
1358
|
}
|
|
1317
1359
|
this.setRoom = function(newroom, ischild) {
|
|
1318
|
-
if (newroom._target) newroom = newroom._target; // If the proxy object is passed in, use its target instead
|
|
1360
|
+
if (newroom && newroom._target) newroom = newroom._target; // If the proxy object is passed in, use its target instead
|
|
1319
1361
|
|
|
1320
1362
|
if (this.room !== newroom) {
|
|
1363
|
+
let oldroom = this.room;
|
|
1321
1364
|
if (!ischild) {
|
|
1322
1365
|
this.stop();
|
|
1323
1366
|
}
|
|
@@ -1327,7 +1370,13 @@ console.log('clone', props);
|
|
|
1327
1370
|
this.children[k].setRoom(newroom, true);
|
|
1328
1371
|
}
|
|
1329
1372
|
}
|
|
1330
|
-
if (!ischild) {
|
|
1373
|
+
if (newroom && !ischild) {
|
|
1374
|
+
let roomproxy = (newroom._target ? newroom : newroom.getProxyObject()),
|
|
1375
|
+
objproxy = (this._target ? this : this.getProxyObject());
|
|
1376
|
+
if (!roomproxy.contains(objproxy)) {
|
|
1377
|
+
//newroom.add(this);
|
|
1378
|
+
roomproxy.appendChild(objproxy);
|
|
1379
|
+
}
|
|
1331
1380
|
this.start();
|
|
1332
1381
|
}
|
|
1333
1382
|
}
|
package/scripts/janusghost.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
2
|
+
|
|
2
3
|
elation.component.add('engine.things.janusghost', function() {
|
|
3
4
|
this.postinit = function() {
|
|
4
5
|
elation.engine.things.janusghost.extendclass.postinit.call(this);
|
|
@@ -16,9 +17,29 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
16
17
|
ghostassets: { type: 'object' },
|
|
17
18
|
auto_play: { type: 'boolean', default: true },
|
|
18
19
|
screen_name: { type: 'string' },
|
|
20
|
+
animation_extras: { type: 'string' },
|
|
21
|
+
bone_head: { type: 'string' },
|
|
22
|
+
morphtarget_mouth: { type: 'string' },
|
|
23
|
+
morphtarget_eyes: { type: 'string' },
|
|
19
24
|
});
|
|
20
25
|
|
|
21
26
|
this.frames = false;
|
|
27
|
+
|
|
28
|
+
if (!('project_vertex_discard_close' in THREE.ShaderChunk)) {
|
|
29
|
+
THREE.ShaderChunk['color_fragment_discard_close'] = `
|
|
30
|
+
#if defined( USE_COLOR_ALPHA )
|
|
31
|
+
diffuseColor *= vColor;
|
|
32
|
+
#elif defined( USE_COLOR )
|
|
33
|
+
diffuseColor.rgb *= vColor;
|
|
34
|
+
#endif
|
|
35
|
+
float dist = length(vViewPosition);
|
|
36
|
+
float mindist = .4;
|
|
37
|
+
float maxdist = .6;
|
|
38
|
+
if (dist < maxdist) {
|
|
39
|
+
diffuseColor.a = clamp(((dist - mindist) / (maxdist - mindist)), 0., 1.);
|
|
40
|
+
}
|
|
41
|
+
`;
|
|
42
|
+
}
|
|
22
43
|
}
|
|
23
44
|
this.createObject3D = function() {
|
|
24
45
|
if (this.ghost_src) {
|
|
@@ -114,6 +135,45 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
114
135
|
console.log(this.ghostassets);
|
|
115
136
|
this.assetpack.loadJSON(assets.assetlist);
|
|
116
137
|
}
|
|
138
|
+
|
|
139
|
+
let animnames = []; //'idle', 'walk', 'walk_left', 'walk_right', 'walk_back', 'run', 'jump', 'fly', 'speak', 'type', 'portal'];
|
|
140
|
+
let animassets = assets.assetlist.filter(asset => animnames.indexOf(asset.name) != -1);
|
|
141
|
+
console.log('some ghost animations', animassets, assets);
|
|
142
|
+
|
|
143
|
+
if (!this.animationmixer) {
|
|
144
|
+
// Set up our animation mixer with a simple bone mapper for our head. We'll add more animations to this ass other assets load
|
|
145
|
+
// TODO - this is probably also where we'd map any other tracked objects (hands, hips, etc). and set up IK
|
|
146
|
+
|
|
147
|
+
/*
|
|
148
|
+
let headtrack = new THREE.QuaternionKeyframeTrack('Neck.quaternion', [0], [0, 0, 0, 1]),
|
|
149
|
+
headclip = new THREE.AnimationClip('head_rotation', -1, [headtrack]);
|
|
150
|
+
this.headtrack = headtrack;
|
|
151
|
+
|
|
152
|
+
this.initAnimations([ headclip ]);
|
|
153
|
+
//this.animations['head_rotation'].play();
|
|
154
|
+
*/
|
|
155
|
+
this.initAnimations([]);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
animassets.forEach(anim => {
|
|
159
|
+
let asset = this.getAsset('model', anim.name);
|
|
160
|
+
console.log('try to load the animation', asset, anim);
|
|
161
|
+
if (asset) {
|
|
162
|
+
if (!asset.loaded) {
|
|
163
|
+
let model = asset.getInstance();
|
|
164
|
+
elation.events.add(asset, 'asset_load', ev => {
|
|
165
|
+
let clip = false;
|
|
166
|
+
model.traverse(n => { if (n.animations && n.animations.length > 0) clip = n.animations[0]; });
|
|
167
|
+
if (clip) {
|
|
168
|
+
if (this.animationmixer && !this.animations[anim.name]) {
|
|
169
|
+
let action = this.animationmixer.clipAction(clip);
|
|
170
|
+
this.animations[anim.name] = action;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
});
|
|
117
177
|
}
|
|
118
178
|
this.getGhostObjects = function() {
|
|
119
179
|
var objects = {};
|
|
@@ -186,6 +246,8 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
186
246
|
this.head.appendChild(headid);
|
|
187
247
|
this.face.start();
|
|
188
248
|
}
|
|
249
|
+
this.head.pos = headpos.clone().multiplyScalar(this.scale.y);
|
|
250
|
+
this.face.applyPosition(headpos.negate());
|
|
189
251
|
if (this.remotevideo) {
|
|
190
252
|
this.updateVideoScreen();
|
|
191
253
|
this.face.addEventListener('load', (ev) => {
|
|
@@ -217,6 +279,11 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
217
279
|
//rotation: V(0, 180, 0),
|
|
218
280
|
lighting: this.lighting,
|
|
219
281
|
//cull_face: 'none'
|
|
282
|
+
opacity: 0.9999,
|
|
283
|
+
renderorder: this.renderorder || 100,
|
|
284
|
+
shader_chunk_replace: (this.lighting ? {
|
|
285
|
+
'color_fragment': 'color_fragment_discard_close',
|
|
286
|
+
} : {}),
|
|
220
287
|
});
|
|
221
288
|
} else {
|
|
222
289
|
this.body = bodyid;
|
|
@@ -225,11 +292,169 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
225
292
|
if (pos) this.body.pos = pos;
|
|
226
293
|
this.body.start();
|
|
227
294
|
if (scale && this.body) this.body.scale.fromArray(scale);
|
|
295
|
+
|
|
296
|
+
elation.events.add(this, 'load', ev => {
|
|
297
|
+
if (this.body.modelasset) {
|
|
298
|
+
if (this.body.modelasset.loaded) {
|
|
299
|
+
this.loadAnimations();
|
|
300
|
+
if (this.animation_extras) {
|
|
301
|
+
this.loadAnimationExtras();
|
|
302
|
+
}
|
|
303
|
+
} else {
|
|
304
|
+
elation.events.add(this.body.modelasset, 'asset_load_complete', () => {
|
|
305
|
+
this.loadAnimations();
|
|
306
|
+
if (this.animation_extras) {
|
|
307
|
+
this.loadAnimationExtras();
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// FIXME - this prevents avatars from being culled, which prevents our default mesh from disappearing but also means we lose out on possible performance optimizations in rooms with lots of avatars
|
|
313
|
+
this.objects['3d'].traverse(n => {
|
|
314
|
+
if (n instanceof THREE.Mesh) {
|
|
315
|
+
n.frustumCulled = false;
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
this.loadAnimations = function(assetid) {
|
|
322
|
+
if (!assetid) assetid = 'avatar_animations';
|
|
323
|
+
let animasset = this.getAsset('model', assetid);
|
|
324
|
+
if (!animasset.loaded) {
|
|
325
|
+
let animationsLoaded = false;
|
|
326
|
+
elation.events.add(animasset, 'asset_load_complete', ev => {
|
|
327
|
+
if (!animationsLoaded) {
|
|
328
|
+
animationsLoaded = true;
|
|
329
|
+
if (this.body.animationmixer) {
|
|
330
|
+
this.cloneAnimations(animasset);
|
|
331
|
+
}
|
|
332
|
+
this.body.setAnimation('idle');
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
animasset.load();
|
|
336
|
+
} else {
|
|
337
|
+
if (this.body.animationmixer) {
|
|
338
|
+
this.cloneAnimations(animasset);
|
|
339
|
+
}
|
|
340
|
+
this.body.setAnimation('idle');
|
|
228
341
|
}
|
|
229
342
|
}
|
|
343
|
+
this.cloneAnimations = function(animasset) {
|
|
344
|
+
let animations = animasset.animations;
|
|
345
|
+
//console.log('clone all the animations', animations, animasset._model);
|
|
346
|
+
if (this.body) {
|
|
347
|
+
if (this.bone_head) {
|
|
348
|
+
this.initHeadAnimation(animasset);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
animations.forEach(clip => {
|
|
352
|
+
this.body.animations[clip.name] = this.body.animationmixer.clipAction(this.retargetAnimation(clip, animasset._model));
|
|
353
|
+
//console.log('new clip', clip.name, clip, this.body.animations[clip.name]);
|
|
354
|
+
});
|
|
355
|
+
//console.log('head rot', this.body.animations['head_rotation'], headclip, headaction);
|
|
356
|
+
//console.log(this.body.modelasset, this.body.modelasset.vrm);
|
|
357
|
+
if (this.body.modelasset && this.body.modelasset.vrm) {
|
|
358
|
+
let rename = {};
|
|
359
|
+
let bonemap = this.body.modelasset.vrm.humanoid.humanBones;
|
|
360
|
+
for (let k in bonemap) {
|
|
361
|
+
console.log(k, bonemap[k]);
|
|
362
|
+
if (bonemap[k].length > 0) {
|
|
363
|
+
rename[bonemap[k][0].node.name] = k;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
let bones = [];
|
|
367
|
+
let meshes = [];
|
|
368
|
+
this.body.objects['3d'].traverse(n => { if (n instanceof THREE.Bone) bones.push(n); else if (n instanceof THREE.SkinnedMesh) meshes.push(n); });
|
|
369
|
+
/*
|
|
370
|
+
console.log('rename the bones!', rename);
|
|
371
|
+
THREE.SkeletonUtils.renameBones(bones, rename);
|
|
372
|
+
console.log('bones now', bones);
|
|
373
|
+
*/
|
|
374
|
+
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
this.retargetAnimation = function(clip, sourcecontainer) {
|
|
379
|
+
let newclip = clip.clone();
|
|
380
|
+
let sourcemesh = null,
|
|
381
|
+
destmesh = null;
|
|
382
|
+
if (sourcecontainer) {
|
|
383
|
+
sourcecontainer.traverse(n => { /*console.log(' - ', n); */ if (n instanceof THREE.SkinnedMesh && n.skeleton) sourcemesh = n; });
|
|
384
|
+
}
|
|
385
|
+
this.objects['3d'].traverse(n => { if (n instanceof THREE.SkinnedMesh && n.skeleton) destmesh = n; });
|
|
386
|
+
//console.log('RETARGET ANI*MATION', clip, sourcemesh, destmesh, sourcecontainer);
|
|
387
|
+
let remove = [];
|
|
388
|
+
if (this.body && this.body.modelasset && this.body.modelasset.vrm) {
|
|
389
|
+
let vrm = this.body.modelasset.vrm;
|
|
390
|
+
//console.log('RETARGET ANI*MATION', clip, this.body.modelasset.vrm, sourcemesh, destmesh);
|
|
391
|
+
newclip.tracks.forEach(track => {
|
|
392
|
+
let parts = track.name.split('.');
|
|
393
|
+
console.log(parts, track.name);
|
|
394
|
+
try {
|
|
395
|
+
let bone = vrm.humanoid.getBone(parts[0]);
|
|
396
|
+
if (bone) {
|
|
397
|
+
track.name = bone.node.name + '.' + parts[1];
|
|
398
|
+
let sourcebone = sourcemesh.skeleton.getBone(bone.node.name);
|
|
399
|
+
//console.log(track, bone);
|
|
400
|
+
} else {
|
|
401
|
+
//console.log('no bone!', parts, track);
|
|
402
|
+
}
|
|
403
|
+
} catch (e) {
|
|
404
|
+
console.log('omgwtf', e.message);
|
|
405
|
+
remove.push(track);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
remove.forEach(track => {
|
|
409
|
+
let idx = newclip.tracks.indexOf(track);
|
|
410
|
+
if (idx != -1) {
|
|
411
|
+
newclip.tracks.splice(idx, 1);
|
|
412
|
+
//console.log('removed track', track);
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
} else if (destmesh && sourcemesh) {
|
|
416
|
+
// FIXME - silly hack to store skeleton, we should just be extracting it at load time
|
|
417
|
+
this.body.skeleton = destmesh.skeleton;
|
|
418
|
+
this.body.objects['3d'].skeleton = destmesh.skeleton;
|
|
419
|
+
//newclip = THREE.SkeletonUtils.retargetClip(destmesh, sourcemesh, newclip, {useFirstFramePosition: true});
|
|
420
|
+
//console.log('retarget it!', newclip, destmesh, sourcemesh);
|
|
421
|
+
newclip.tracks.forEach(track => {
|
|
422
|
+
let [name, property] = track.name.split('.');
|
|
423
|
+
let srcbone = sourcemesh.skeleton.getBoneByName(name);
|
|
424
|
+
let dstbone = destmesh.skeleton.getBoneByName(name);
|
|
425
|
+
//console.log(' - fix track', name, property, track, srcbone, dstbone);
|
|
426
|
+
if (dstbone) {
|
|
427
|
+
let scale = srcbone.position.length() / dstbone.position.length();
|
|
428
|
+
if (property == 'position') {
|
|
429
|
+
for (let i = 0; i < track.values.length; i++) {
|
|
430
|
+
track.values[i] /= scale;
|
|
431
|
+
}
|
|
432
|
+
//remove.push(track);
|
|
433
|
+
} else if (property == 'quaternion') {
|
|
434
|
+
}
|
|
435
|
+
} else {
|
|
436
|
+
//console.log('missing bone!', srcbone, track);
|
|
437
|
+
remove.push(track);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
remove.forEach(track => {
|
|
442
|
+
let idx = newclip.tracks.indexOf(track);
|
|
443
|
+
if (idx != -1) {
|
|
444
|
+
newclip.tracks.splice(idx, 1);
|
|
445
|
+
//console.log('removed track', track);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
//console.log('finished clip', newclip);
|
|
449
|
+
return newclip;
|
|
450
|
+
}
|
|
230
451
|
this.rebindAnimations = function() {
|
|
231
452
|
this.body.rebindAnimations();
|
|
232
453
|
}
|
|
454
|
+
this.loadAnimationExtras = function() {
|
|
455
|
+
let animids = this.animation_extras.split(' ');
|
|
456
|
+
animids.forEach(animid => this.loadAnimations(animid));
|
|
457
|
+
}
|
|
233
458
|
|
|
234
459
|
this.start = function() {
|
|
235
460
|
elation.engine.things.janusghost.extendclass.start.call(this);
|
|
@@ -289,13 +514,16 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
289
514
|
|
|
290
515
|
matrix.makeBasis(xdir, ydir, zdir);
|
|
291
516
|
q1.setFromRotationMatrix(matrix);
|
|
292
|
-
this.head.properties.orientation.copy(this.orientation).
|
|
517
|
+
this.head.properties.orientation.copy(this.orientation).invert().multiply(q1);
|
|
518
|
+
if (this.body && this.headaction) {
|
|
519
|
+
this.setHeadOrientation(this.head.orientation);
|
|
520
|
+
}
|
|
293
521
|
if (movedata.head_pos && this.face) {
|
|
294
522
|
var headpos = this.head.properties.position;
|
|
295
523
|
var facepos = this.face.properties.position;
|
|
296
524
|
var newpos = parser.getVectorValue(movedata.head_pos);
|
|
297
|
-
headpos.copy(this.head_pos);
|
|
298
|
-
facepos.fromArray(newpos).sub(headpos);
|
|
525
|
+
//headpos.copy(this.head_pos);
|
|
526
|
+
//facepos.fromArray(newpos).sub(headpos);
|
|
299
527
|
if (this.body) {
|
|
300
528
|
if (this.head.parent != this.body) {
|
|
301
529
|
this.body.appendChild(this.head);
|
|
@@ -357,6 +585,20 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
357
585
|
if (movedata.userid_pos) {
|
|
358
586
|
this.userid_pos = movedata.userid_pos;
|
|
359
587
|
}
|
|
588
|
+
|
|
589
|
+
// FIXME - workaround for null values
|
|
590
|
+
if (isNaN(this.position.x)) this.position.x = 0;
|
|
591
|
+
if (isNaN(this.position.y)) this.position.y = 0;
|
|
592
|
+
if (isNaN(this.position.z)) this.position.z = 0;
|
|
593
|
+
if (isNaN(this.orientation.x) || isNaN(this.orientation.y) || isNaN(this.orientation.z) || isNaN(this.orientation.w)) this.orientation.set(0,0,0,1);
|
|
594
|
+
|
|
595
|
+
if (this.head) {
|
|
596
|
+
if (isNaN(this.head.position.x)) this.head.position.x = 0;
|
|
597
|
+
if (isNaN(this.head.position.y)) this.head.position.y = 0;
|
|
598
|
+
if (isNaN(this.head.position.z)) this.head.position.z = 0;
|
|
599
|
+
if (isNaN(this.head.orientation.x) || isNaN(this.head.orientation.y) || isNaN(this.head.orientation.z) || isNaN(this.head.orientation.w)) this.head.orientation.set(0,0,0,1);
|
|
600
|
+
}
|
|
601
|
+
|
|
360
602
|
this.objects.dynamics.updateState();
|
|
361
603
|
this.refresh();
|
|
362
604
|
}
|
|
@@ -391,6 +633,14 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
391
633
|
this.screen_name = ghostdef.screen_name;
|
|
392
634
|
}
|
|
393
635
|
this.setGhostAssets(things.assets);
|
|
636
|
+
this.animation_extras = ghostdef.animation_extras;
|
|
637
|
+
this.bone_head = ghostdef.bone_head;
|
|
638
|
+
this.morphtarget_mouth = ghostdef.morphtarget_mouth;
|
|
639
|
+
this.morphtarget_eyes = ghostdef.morphtarget_eyes;
|
|
640
|
+
this.lighting = elation.utils.any(ghostdef.lighting, true);
|
|
641
|
+
if (ghostdef.morphtarget_eyes) {
|
|
642
|
+
this.blink();
|
|
643
|
+
}
|
|
394
644
|
if (ghostdef.head_id) {
|
|
395
645
|
this.setHead(ghostdef.head_id, headpos, ghostdef.scale);
|
|
396
646
|
}
|
|
@@ -431,7 +681,7 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
431
681
|
}
|
|
432
682
|
|
|
433
683
|
var inverse = new THREE.Matrix4();
|
|
434
|
-
inverse.
|
|
684
|
+
inverse.copy(this.objects['3d'].matrixWorld).invert();
|
|
435
685
|
if (hand0 && hand0.state) {
|
|
436
686
|
this.hands.left.show();
|
|
437
687
|
this.hands.left.setState(hand0.state, inverse);
|
|
@@ -460,6 +710,7 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
460
710
|
}
|
|
461
711
|
}
|
|
462
712
|
this.updateTransparency = function() {
|
|
713
|
+
return;
|
|
463
714
|
var player = this.engine.client.player;
|
|
464
715
|
|
|
465
716
|
var dist = player.distanceTo(this);
|
|
@@ -478,17 +729,6 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
478
729
|
m.visible = (opacity > 0);
|
|
479
730
|
});
|
|
480
731
|
}
|
|
481
|
-
this.setRoom = function(room) {
|
|
482
|
-
if (room !== this.room) {
|
|
483
|
-
if (this.room) {
|
|
484
|
-
this.room.remove(this);
|
|
485
|
-
}
|
|
486
|
-
this.room = room;
|
|
487
|
-
if (room && this.parent != this.room) {
|
|
488
|
-
room.add(this);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
732
|
this.setRemoteVideo = function(video) {
|
|
493
733
|
if (video) {
|
|
494
734
|
this.remotevideo = video;
|
|
@@ -540,5 +780,64 @@ elation.require(['janusweb.janusbase', 'engine.things.leapmotion'], function() {
|
|
|
540
780
|
});
|
|
541
781
|
}
|
|
542
782
|
}
|
|
783
|
+
this.setAnimation = function(anim) {
|
|
784
|
+
if (this.body) this.body.anim_id = anim;
|
|
785
|
+
}
|
|
786
|
+
this.initHeadAnimation = function(animasset) {
|
|
787
|
+
let body = this.body || this._target.body,
|
|
788
|
+
head = this.head || this._target.head;
|
|
789
|
+
if (body && this.bone_head && !this.headaction) {
|
|
790
|
+
if (!body.animationmixer) {
|
|
791
|
+
body.initAnimations([]);
|
|
792
|
+
}
|
|
793
|
+
// Set up our animation mixer with a simple bone mapper for our head. We'll add more animations to this as other assets load
|
|
794
|
+
// TODO - this is probably also where we'd map any other tracked objects (hands, hips, etc). and set up IK
|
|
795
|
+
|
|
796
|
+
let headtrack = new THREE.QuaternionKeyframeTrack(this.bone_head + '.quaternion', [0], [0, 0, 0, 1]),
|
|
797
|
+
headclip = new THREE.AnimationClip('head_rotation', -1, [headtrack]);
|
|
798
|
+
let headaction = body.animationmixer.clipAction(this.retargetAnimation(headclip, animasset._model));
|
|
799
|
+
headaction.weight = 5;
|
|
800
|
+
this.headaction = headaction;
|
|
801
|
+
headaction.play();
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
this.setHeadOrientation = function(orientation, invert) {
|
|
805
|
+
let headaction = this.headaction || this._target.headaction;
|
|
806
|
+
if (headaction && headaction._clip.tracks[0]) {
|
|
807
|
+
let track = headaction._clip.tracks[0];
|
|
808
|
+
track.values[0] = orientation.x * (invert ? -1 : 1);
|
|
809
|
+
track.values[1] = orientation.y * (invert ? -1 : 1);
|
|
810
|
+
track.values[2] = orientation.z * (invert ? -1 : 1);
|
|
811
|
+
track.values[3] = orientation.w; // * (invert ? -1 : 1);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
this.blink = function() {
|
|
815
|
+
if (!this.blinktimer) {
|
|
816
|
+
if (this.body && this.morphtarget_eyes) {
|
|
817
|
+
this.body.setMorphTargetInfluence(this.morphtarget_eyes, 1);
|
|
818
|
+
setTimeout(() => {
|
|
819
|
+
this.body.setMorphTargetInfluence(this.morphtarget_eyes, 0);
|
|
820
|
+
}, 100);
|
|
821
|
+
}
|
|
822
|
+
this.blinktimer = setTimeout(() => {
|
|
823
|
+
this.blinktimer = false;
|
|
824
|
+
this.blink();
|
|
825
|
+
}, 2500 + Math.random() * 8500);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
this.setSpeakingVolume = function(volume) {
|
|
829
|
+
if (this.body && this.morphtarget_mouth) {
|
|
830
|
+
this.body.setMorphTargetInfluence(this.morphtarget_mouth, volume);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
this.getProxyObject = function(classdef) {
|
|
834
|
+
if (!this._proxyobject) {
|
|
835
|
+
this._proxyobject = elation.engine.things.janusghost.extendclass.getProxyObject.call(this, classdef);
|
|
836
|
+
this._proxyobject._proxydefs = {
|
|
837
|
+
body: [ 'property', 'body'],
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
return this._proxyobject;
|
|
841
|
+
}
|
|
543
842
|
}, elation.engine.things.janusbase);
|
|
544
843
|
});
|
package/scripts/januslight.js
CHANGED
|
@@ -18,6 +18,8 @@ elation.require(['janusweb.janusbase'], function() {
|
|
|
18
18
|
light_shadow_bias: { type: 'float', default: .0001, set: this.updateLight },
|
|
19
19
|
light_shadow_radius: { type: 'float', default: 2.5, set: this.updateLight },
|
|
20
20
|
light_helper: { type: 'boolean', default: false, set: this.updateLightHelper },
|
|
21
|
+
light_style: { type: 'string', default: '' },
|
|
22
|
+
light_style_fps: { type: 'float', default: 10 },
|
|
21
23
|
collision_id: { type: 'string', default: 'sphere', set: this.updateCollider },
|
|
22
24
|
collision_trigger: { type: 'boolean', default: true, set: this.updateCollider },
|
|
23
25
|
});
|
|
@@ -98,8 +100,14 @@ elation.require(['janusweb.janusbase'], function() {
|
|
|
98
100
|
this.updateLightTarget();
|
|
99
101
|
}
|
|
100
102
|
if (this.light_directional || this.light_cone_angle == 1) {
|
|
101
|
-
this.light.position.subVectors(this.light.position, this.light.target.position).add(player.pos);
|
|
102
|
-
this.light.target.position.
|
|
103
|
+
//this.light.position.subVectors(this.light.position, this.light.target.position).add(player.pos).sub(this.pos);
|
|
104
|
+
this.light.position.subVectors(this.position, this.light.target.position).normalize().multiplyScalar(this.light_range / 2).add(player.pos).sub(this.pos);
|
|
105
|
+
this.light.target.position.copy(player.pos).sub(this.pos);
|
|
106
|
+
}
|
|
107
|
+
if (this.light_style != '') {
|
|
108
|
+
let idx = Math.floor(Date.now() / (1000 / this.light_style_fps)) % this.light_style.length;
|
|
109
|
+
let brightness = (this.light_style.charCodeAt(idx) - 97) / 13;
|
|
110
|
+
this.light.intensity = .1 * brightness;
|
|
103
111
|
}
|
|
104
112
|
}
|
|
105
113
|
this.createLight = function() {
|
|
@@ -127,6 +135,7 @@ elation.require(['janusweb.janusbase'], function() {
|
|
|
127
135
|
//this.light.intensity = this.light_intensity / 100;
|
|
128
136
|
var avgscale = (this.scale.x + this.scale.y + this.scale.z) / 3;
|
|
129
137
|
//this.light.intensity = this.light_intensity / 100;
|
|
138
|
+
let brightness = 1;
|
|
130
139
|
this.light.intensity = .1;
|
|
131
140
|
this.light.penumbra = this.light_penumbra;
|
|
132
141
|
this.light.decay = this.light_decay;
|