src's and global scene have separate animation mixers now yay! \o/
This commit is contained in:
parent
d474cb5e8d
commit
8be5e485ce
|
@ -218,13 +218,13 @@ sub-delims = "," / "="
|
|||
| vector3 | x,y,z | 2,3.0,4 | 3-dimensional vector |
|
||||
| timevector | speed | 1 | 1D timeline: play |
|
||||
| | | 0 | 1D timeline: stop |
|
||||
| | x,speed | 1,1 | 1D timeline: play at offset `1` at (normal) speed `1` |
|
||||
| | | 0,0 | 1D timeline: stop |
|
||||
| | x,speed | 1,2 | 1D timeline: play at offset `1` at (normal) speed `2` |
|
||||
| | | 0,0 | 1D timeline: stop (stopoffset-startoffset == 0) |
|
||||
| | | 0,1 | 1D timeline: unpause with (normal) speed `1` |
|
||||
| | | [1,100],1 | 1D timeline: play (loop) between offset `1` and `100` at normal speed (`1`) |
|
||||
| | | 1..100,1 | 1D timeline: play (loop) between offset `1` and `100` at normal speed (`1`) |
|
||||
| | x,y,xspeed,yspeed | 0,0.5,0,0 | 2D timeline: stop uv-coordinate at `0,0.5` |
|
||||
| | | 0,0.5,0.2,0 | 2D timeline: play uv-coordinate at offset `0,0.5` and scroll `x` (=u) `0.2` within each second |
|
||||
| | | 0,[0,0.5],0.2,0 | 2D timeline: play uv-coordinate between offset `0,0` and `0,0.5` (loop) and scroll `x` (=u) `0.2` within each second |
|
||||
| | | 0,0..0.5,0.2,0 | 2D timeline: play uv-coordinate between offset `0,0` and `0,0.5` (loop) and scroll `x` (=u) `0.2` within each second |
|
||||
| | x,y,z,xspeed,yspeed,zspeed | 0,0.5,1,0.2,0,2 | XD timeline: play uv-coordinate at `0,0.5` and scroll `x` (=u) `0.2` within each second and pass `1` and `2` as custom data to shader uniforms `za` and `zb` |
|
||||
|
||||
> NOTE: XR Fragments are optional but also file- and protocol-agnostic, which means that programmatic 3D scene(nodes) can also use the mechanism/metadata.
|
||||
|
@ -240,7 +240,8 @@ These are automatic fragment-to-metadata mappings, which only trigger if the 3D
|
|||
| `#<cameraname>` | string | `#cam01` | set camera as active camera |
|
||||
| `#<objectname>=<material>` | string=string | `#car=metallic`| set material of car to material with name `metallic` |
|
||||
| | string=string | `#product=metallic`| set material of objects tagged with `product` to material with name `metallic` |
|
||||
| `#<objectname>=<timevector>` | string=timevector | `#sky=0,0.5,0.1,0`| set uv-position to `0,0.5` (and autoscroll x with max `0.1` every second)|
|
||||
| `#<objectname>=<mediafrag>` | string=[media frag](https://www.w3.org/TR/media-frags/#valid-uri) | `#foo=0,1`| play media `src` using [media fragment URI](https://www.w3.org/TR/media-frags/#valid-uri) |
|
||||
| `#<objectname>=<timevector>` | string=timevector | `#sky=0,0.5,0.1,0`| sets 1D/2D/3D time(line) vectors (uv-position e.g.) to `0,0.5` (and autoscroll x with max `0.1` every second)|
|
||||
| | | `#music=1,2`| play media of object (`src: podcast.mp3` e.g.) from beginning (`1`) at double speed (`2`) |
|
||||
|
||||
# Spatial Referencing 3D
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<canvas id="qrcode" style="display:none" width="300" height="300"></canvas>
|
||||
|
||||
<a-scene light="defaultLightsEnabled: false">
|
||||
<a-entity id="player">
|
||||
<a-entity camera="fov:90" wasd-controls look-controls position="0 1.6 0" id="camera"></a-entity>
|
||||
<a-entity id="player" wasd-controls look-controls>
|
||||
<a-entity camera="fov:90" position="0 1.6 0" id="camera"></a-entity>
|
||||
<a-entity id="left-hand" laser-controls="hand: left" raycaster="objects:.ray" blink-controls="cameraRig:#player; teleportOrigin: #camera; collisionEntities: #floor">
|
||||
<a-entity rotation="-90 0 0" position="0 0.1 0" id="navigator">
|
||||
<a-entity id="back" xrf-button="label: <; width:0.05; action: history.back()" position="-0.025 0 0" class="ray"></a-entity>
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,262 @@
|
|||
{
|
||||
"accessors" : [
|
||||
{
|
||||
"bufferView" : 0,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 3,
|
||||
"max" : [
|
||||
2.000000
|
||||
],
|
||||
"min" : [
|
||||
0.000000
|
||||
],
|
||||
"type" : "SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView" : 1,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 3,
|
||||
"max" : [
|
||||
0.000000,
|
||||
1.000000,
|
||||
0.000000,
|
||||
1.000000
|
||||
],
|
||||
"min" : [
|
||||
0.000000,
|
||||
-8.742278e-008,
|
||||
0.000000,
|
||||
-1.000000
|
||||
],
|
||||
"type" : "VEC4"
|
||||
},
|
||||
{
|
||||
"bufferView" : 2,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5123,
|
||||
"count" : 36,
|
||||
"max" : [
|
||||
35
|
||||
],
|
||||
"min" : [
|
||||
0
|
||||
],
|
||||
"type" : "SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView" : 3,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 36,
|
||||
"max" : [
|
||||
1.000000,
|
||||
1.000000,
|
||||
1.000001
|
||||
],
|
||||
"min" : [
|
||||
-1.000000,
|
||||
-1.000000,
|
||||
-1.000000
|
||||
],
|
||||
"type" : "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView" : 4,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 36,
|
||||
"max" : [
|
||||
1.000000,
|
||||
1.000000,
|
||||
1.000000
|
||||
],
|
||||
"min" : [
|
||||
-1.000000,
|
||||
-1.000000,
|
||||
-1.000000
|
||||
],
|
||||
"type" : "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView" : 5,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 36,
|
||||
"max" : [
|
||||
1.000000,
|
||||
-0.000000,
|
||||
-0.000000,
|
||||
1.000000
|
||||
],
|
||||
"min" : [
|
||||
0.000000,
|
||||
-0.000000,
|
||||
-1.000000,
|
||||
-1.000000
|
||||
],
|
||||
"type" : "VEC4"
|
||||
},
|
||||
{
|
||||
"bufferView" : 6,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 36,
|
||||
"max" : [
|
||||
1.000000,
|
||||
1.000000
|
||||
],
|
||||
"min" : [
|
||||
-1.000000,
|
||||
-1.000000
|
||||
],
|
||||
"type" : "VEC2"
|
||||
}
|
||||
],
|
||||
"animations" : [
|
||||
{
|
||||
"channels" : [
|
||||
{
|
||||
"sampler" : 0,
|
||||
"target" : {
|
||||
"node" : 0,
|
||||
"path" : "rotation"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name" : "animation_AnimatedCube",
|
||||
"samplers" : [
|
||||
{
|
||||
"input" : 0,
|
||||
"interpolation" : "LINEAR",
|
||||
"output" : 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"asset" : {
|
||||
"generator" : "VKTS glTF 2.0 exporter",
|
||||
"version" : "2.0"
|
||||
},
|
||||
"bufferViews" : [
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 12,
|
||||
"byteOffset" : 0
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 48,
|
||||
"byteOffset" : 12
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 72,
|
||||
"byteOffset" : 60,
|
||||
"target" : 34963
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 432,
|
||||
"byteOffset" : 132,
|
||||
"target" : 34962
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 432,
|
||||
"byteOffset" : 564,
|
||||
"target" : 34962
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 576,
|
||||
"byteOffset" : 996,
|
||||
"target" : 34962
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 288,
|
||||
"byteOffset" : 1572,
|
||||
"target" : 34962
|
||||
}
|
||||
],
|
||||
"buffers" : [
|
||||
{
|
||||
"byteLength" : 1860,
|
||||
"uri" : "AnimatedCube.bin"
|
||||
}
|
||||
],
|
||||
"images" : [
|
||||
{
|
||||
"uri" : "AnimatedCube_BaseColor.png"
|
||||
},
|
||||
{
|
||||
"uri" : "AnimatedCube_MetallicRoughness.png"
|
||||
}
|
||||
],
|
||||
"materials" : [
|
||||
{
|
||||
"name" : "AnimatedCube",
|
||||
"pbrMetallicRoughness" : {
|
||||
"baseColorTexture" : {
|
||||
"index" : 0
|
||||
},
|
||||
"metallicRoughnessTexture" : {
|
||||
"index" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes" : [
|
||||
{
|
||||
"name" : "AnimatedCube",
|
||||
"primitives" : [
|
||||
{
|
||||
"attributes" : {
|
||||
"NORMAL" : 4,
|
||||
"POSITION" : 3,
|
||||
"TANGENT" : 5,
|
||||
"TEXCOORD_0" : 6
|
||||
},
|
||||
"indices" : 2,
|
||||
"material" : 0,
|
||||
"mode" : 4
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes" : [
|
||||
{
|
||||
"mesh" : 0,
|
||||
"name" : "AnimatedCube",
|
||||
"rotation" : [
|
||||
0.000000,
|
||||
-1.000000,
|
||||
0.000000,
|
||||
0.000000
|
||||
]
|
||||
}
|
||||
],
|
||||
"samplers" : [
|
||||
{}
|
||||
],
|
||||
"scene" : 0,
|
||||
"scenes" : [
|
||||
{
|
||||
"nodes" : [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures" : [
|
||||
{
|
||||
"sampler" : 0,
|
||||
"source" : 0
|
||||
},
|
||||
{
|
||||
"sampler" : 0,
|
||||
"source" : 1
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
{
|
||||
"asset":{
|
||||
"generator":"Khronos glTF Blender I/O v3.5.30",
|
||||
"version":"2.0"
|
||||
},
|
||||
"scene":0,
|
||||
"scenes":[
|
||||
{
|
||||
"name":"Scene",
|
||||
"nodes":[
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes":[
|
||||
{
|
||||
"mesh":0,
|
||||
"name":"AnimatedCube"
|
||||
}
|
||||
],
|
||||
"animations":[
|
||||
{
|
||||
"channels":[
|
||||
{
|
||||
"sampler":0,
|
||||
"target":{
|
||||
"node":0,
|
||||
"path":"rotation"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name":"walk",
|
||||
"samplers":[
|
||||
{
|
||||
"input":4,
|
||||
"interpolation":"LINEAR",
|
||||
"output":5
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials":[
|
||||
{
|
||||
"name":"AnimatedCube",
|
||||
"pbrMetallicRoughness":{}
|
||||
}
|
||||
],
|
||||
"meshes":[
|
||||
{
|
||||
"name":"AnimatedCube",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":0,
|
||||
"TEXCOORD_0":1,
|
||||
"NORMAL":2
|
||||
},
|
||||
"indices":3,
|
||||
"material":0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"accessors":[
|
||||
{
|
||||
"bufferView":0,
|
||||
"componentType":5126,
|
||||
"count":36,
|
||||
"max":[
|
||||
1,
|
||||
1,
|
||||
1.0000009536743164
|
||||
],
|
||||
"min":[
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":1,
|
||||
"componentType":5126,
|
||||
"count":36,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":2,
|
||||
"componentType":5126,
|
||||
"count":36,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":3,
|
||||
"componentType":5123,
|
||||
"count":36,
|
||||
"type":"SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView":4,
|
||||
"componentType":5126,
|
||||
"count":3,
|
||||
"max":[
|
||||
2
|
||||
],
|
||||
"min":[
|
||||
0
|
||||
],
|
||||
"type":"SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView":5,
|
||||
"componentType":5126,
|
||||
"count":3,
|
||||
"type":"VEC4"
|
||||
}
|
||||
],
|
||||
"bufferViews":[
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":432,
|
||||
"byteOffset":0,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":432,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":432,
|
||||
"byteOffset":720,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":72,
|
||||
"byteOffset":1152,
|
||||
"target":34963
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":12,
|
||||
"byteOffset":1224
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":1236
|
||||
}
|
||||
],
|
||||
"buffers":[
|
||||
{
|
||||
"byteLength":1284,
|
||||
"uri":"data:application/octet-stream;base64,AACAPwAAgL8AAIA/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAvwAAgD8AAIC/7/9/PwAAgD8IAIA/AACAPwAAgD/v/3+/AACAPwAAgD/v/3+/AACAPwAAgL8AAIA/AACAPwAAgL8AAIC/7/9/PwAAgD8IAIA/AACAvwAAgL8AAIA/AACAPwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgD8AAIC/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAvwAAgD8AAIC/AACAPwAAgD/v/3+/AACAPwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIA/7/9/PwAAgD8IAIA/AACAPwAAgD/v/3+/7/9/PwAAgD8IAIA/AACAPwAAgL8AAIA/7/9/PwAAgD8IAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIC/AACAPwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AAAAAAAAAAAAAIC/AACAPwAAAAAAAIA/AAAAAAAAAAAAAIA/AACAvwAAgD8AAAAAAACAPwAAAAAAAAAAAACAvwAAgD8AAIC/AACAPwAAAAAAAACAAACAvwAAgD8AAIC/AAAAAAAAAAAAAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAIC/AACAPwAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAgL8AAIA/AAAAAAAAAAAAAACAAACAvwAAgD8AAIC/AACAPwAAAAAAAACAAAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAAAAAAAAAIAAAIC/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AAAAAAAAAAAAAIC/AAAAAAAAgL8AAIA/AAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAACAPwAAAAAAAACAAACAPwAAAAAAAACAAACAPwAAAAAAAACAAAAAAAAAAIAAAIA/AAAAAAAAAIAAAIA/AAAAAAAAAIAAAIA/AACAvwAAAAAAAACAAACAvwAAAAAAAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAgAAAAAAAAIA/AAAAgAAAAAAAAIA/AAAAgAAAAAAAAIA/AACAvwAAAAAAAACAAACAvwAAAAAAAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAAAAAAAAAgD8AAABAAAAAAAAAAAAAAACAAACAPwAAAIAAAIC/AAAAAC69OzMAAAAALr27MwAAAIAAAIA/"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -130,6 +130,7 @@ a#model{
|
|||
}
|
||||
|
||||
html.a-fullscreen a.btn-foot {
|
||||
line-height:36px;
|
||||
margin-right:10px;
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
2
make
2
make
|
@ -69,7 +69,7 @@ build_js(){
|
|||
cat dist/xrfragment.js \
|
||||
src/3rd/js/*.js \
|
||||
src/3rd/js/three/*.js \
|
||||
src/3rd/js/three/xrmacro/*.js \
|
||||
src/3rd/js/three/xrmacro/env.js \
|
||||
src/3rd/js/three/xrf/*.js \
|
||||
src/3rd/js/three/xrf/dynamic/*.js \
|
||||
src/3rd/js/three/xrf/src/*.js > dist/xrfragment.three.js
|
||||
|
|
|
@ -5,16 +5,18 @@ xrf.frag.src = function(v, opts){
|
|||
opts.embedded = v // indicate embedded XR fragment
|
||||
let { mesh, model, camera, scene, renderer, THREE, hashbus, frag} = opts
|
||||
|
||||
console.log(" └ instancing src")
|
||||
let src;
|
||||
let url = v.string
|
||||
let vfrag = xrfragment.URI.parse(url)
|
||||
opts.isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4
|
||||
|
||||
const addScene = (scene,url,frag) => {
|
||||
const addModel = (model,url,frag) => {
|
||||
let scene = model.scene
|
||||
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
||||
xrf.frag.src.scale( src, opts, url )
|
||||
xrf.frag.src.eval( src, opts, url )
|
||||
// allow 't'-fragment to setup separate animmixer
|
||||
xrf.emit('parseModel', {...opts, scene:src, model})
|
||||
enableSourcePortation(src)
|
||||
mesh.add(src)
|
||||
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
||||
|
@ -49,20 +51,23 @@ xrf.frag.src = function(v, opts){
|
|||
return xrf.frag.src.type[ mimetype ] ? xrf.frag.src.type[ mimetype ](url,opts) : xrf.frag.src.type.unknown(url,opts)
|
||||
})
|
||||
.then( (model) => {
|
||||
if( model && model.scene ) addScene(model.scene, url, frag )
|
||||
if( model && model.scene ) addModel(model, url, frag )
|
||||
})
|
||||
.finally( () => { })
|
||||
.catch( console.error )
|
||||
}
|
||||
|
||||
if( url[0] == "#" ) addScene(scene,url,vfrag) // current file
|
||||
else externalSRC(url,vfrag) // external file
|
||||
if( url[0] == "#" ){
|
||||
let modelClone = {...model, scene: model.scene.clone()}
|
||||
modelClone.scenes = [modelClone.scene]
|
||||
modelClone.animations = modelClone.animations.map( (a) => a.clone() )
|
||||
addModel(modelClone,url,vfrag) // current file
|
||||
}else externalSRC(url,vfrag) // external file
|
||||
}
|
||||
|
||||
xrf.frag.src.eval = function(scene, opts, url){
|
||||
let { mesh, model, camera, renderer, THREE, hashbus} = opts
|
||||
if( url ){
|
||||
console.log(mesh.name+" url="+url)
|
||||
//let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||
//let frag = xrfragment.URI.parse(url)
|
||||
//// scale URI XR Fragments (queries) inside src-value
|
||||
|
@ -123,13 +128,13 @@ xrf.frag.src.filterScene = (scene,opts) => {
|
|||
}
|
||||
hashbus.pub.fragment(i, Object.assign(opts,{frag, model,scene}))
|
||||
}
|
||||
}else src = scene.clone(true)
|
||||
}
|
||||
if( src.children.length == 1 ) obj.position.set(0,0,0);
|
||||
}
|
||||
|
||||
// filtering of objects using query
|
||||
if( frag.q ){
|
||||
src = scene.clone(true);
|
||||
src = scene
|
||||
xrf.frag.q.filter(src,frag)
|
||||
}
|
||||
src.traverse( (m) => {
|
||||
|
|
|
@ -47,6 +47,7 @@ let loadAudio = (mimetype) => function(url,opts){
|
|||
// setting loop
|
||||
if( t.z ) sound.setLoop( true )
|
||||
// apply embedded audio/video samplerate/fps or global mixer fps
|
||||
return console.warn("TODO: convert samplerate frames to seconds!")
|
||||
let loopStart = hardcodedLoop ? t.y / buffer.sampleRate : t.y / xrf.model.mixer.loop.fps
|
||||
let loopEnd = hardcodedLoop ? t.z / buffer.sampleRate : t.z / xrf.model.mixer.loop.fps
|
||||
let timeStart = loopStart > 0 ? loopStart : (t.y == undefined ? xrf.model.mixer.time : t.y)
|
||||
|
|
|
@ -3,53 +3,45 @@ xrf.frag.t = function(v, opts){
|
|||
if( !model.mixer ) return
|
||||
if( !model.animations || model.animations[0] == undefined ) return console.warn('no animation in scene')
|
||||
|
||||
model.mixer.t = v
|
||||
let mixer = model.mixer
|
||||
xrf.frag.t.calculateLoop( v, mixer.loop, mixer.loop.fps )
|
||||
|
||||
// update speed
|
||||
mixer.timeScale = mixer.loop.speed
|
||||
xrf.mixers.map ( (mixer) => {
|
||||
mixer.t = v
|
||||
|
||||
// update speed
|
||||
mixer.timeScale = mixer.loop.speed = v.x
|
||||
mixer.loop.speedAbs = Math.abs(v.x)
|
||||
|
||||
if( v.y != undefined || v.z != undefined ) xrf.mixers[0].updateLoop( mixer.loop.timeStart )
|
||||
if( v.y > 0 && v.z > 0 ){
|
||||
xrf.model.animations.map( (anim) => {
|
||||
if( !anim.action ) return
|
||||
anim.action.setLoop( v.z == 0 ? THREE.LoopOnce : THREE.LoopRepeat, v.z == 0 ? 0 : 99999999)
|
||||
})
|
||||
}
|
||||
|
||||
// play animations
|
||||
mixer.play( v.x != 0 )
|
||||
if( v.y != undefined || v.z != undefined ) mixer.updateLoop( v )
|
||||
|
||||
// play animations
|
||||
mixer.play( v.x != 0 )
|
||||
})
|
||||
}
|
||||
|
||||
xrf.frag.t.default = {x:1, y:0, z:0}
|
||||
|
||||
xrf.frag.t.calculateLoop = (t,obj,fps) => {
|
||||
obj.speed = t ? t.x : 0
|
||||
obj.speedAbs = Math.abs(obj.speed)
|
||||
obj.frameStart = t ? t.y || obj.frameStart : 1
|
||||
obj.frameStop = t ? t.z || obj.frameStop : 0
|
||||
// always recalculate time using frameStart/Stop
|
||||
obj.timeStart = obj.frameStart == 0 ? obj.mixerStart || 0 : obj.frameStart-1 / (fps * obj.speedAbs)
|
||||
obj.timeStop = obj.frameStop / (fps * obj.speedAbs)
|
||||
xrf.frag.t.default = {
|
||||
x:0, // (play from) offset (in seconds)
|
||||
y:0 // optional: (stop at) offset (in seconds)
|
||||
}
|
||||
|
||||
xrf.frag.t.setupMixer = function(opts){
|
||||
let {model,file,url} = opts
|
||||
let mixer = model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
||||
// setup animation mixer for global scene & src scenes
|
||||
xrf.addEventListener('parseModel', (opts) => {
|
||||
let {model} = opts
|
||||
let mixer = model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
||||
mixer.model = model
|
||||
mixer.loop = {}
|
||||
mixer.i = xrf.mixers.length
|
||||
|
||||
mixer.initClips = () => {
|
||||
if( mixer.clipsInited ) return // fire only once
|
||||
model.animations.map( (anim) => {
|
||||
model.animations.map( (anim) => {
|
||||
anim.action = mixer.clipAction( anim, model.scene )
|
||||
})
|
||||
|
||||
mixer.checkZombies = (animations) => {
|
||||
if( mixer.zombieCheck ) return // fire only once
|
||||
animations.map( (anim) => {
|
||||
// collect zombie animations and warn user
|
||||
let zombies = anim.tracks.map( (t) => {
|
||||
let name = t.name.replace(/\..*/,'')
|
||||
return !model.scene.getObjectByName(name) ? {anim:anim.name,obj:t.name} : undefined
|
||||
})
|
||||
if( !anim.action ){
|
||||
anim.action = mixer.clipAction( anim )
|
||||
anim.action.setLoop(THREE.LoopOnce)
|
||||
}
|
||||
if( zombies.length > 0 ){
|
||||
zombies
|
||||
.filter( (z) => z ) // filter out undefined
|
||||
|
@ -57,31 +49,37 @@ xrf.frag.t.setupMixer = function(opts){
|
|||
console.warn(`TIP: remove dots in objectnames in blender (which adds dots when duplicating)`)
|
||||
}
|
||||
})
|
||||
mixer.clipsInited = true
|
||||
mixer.zombieCheck = true
|
||||
}
|
||||
|
||||
mixer.play = (play) => {
|
||||
mixer.initClips()
|
||||
mixer.isPlaying = play
|
||||
model.animations.map( (anim) => {
|
||||
if( mixer.isPlaying === false) anim.action.stop()
|
||||
else{
|
||||
anim.action.play()
|
||||
}
|
||||
mixer.update(0)
|
||||
})
|
||||
xrf.emit( play === false ? 'stop' : 'play',{play})
|
||||
mixer.play = (t) => {
|
||||
mixer.isPlaying = t.x != 0
|
||||
mixer.updateLoop(t)
|
||||
xrf.emit( mixer.isPlaying === false ? 'stop' : 'play',{isPlaying: mixer.isPlaying})
|
||||
}
|
||||
|
||||
mixer.stop = () => {
|
||||
mixer.play(false)
|
||||
}
|
||||
|
||||
mixer.updateLoop = (time) => {
|
||||
console.log("updateLoop "+time)
|
||||
mixer.setTime(time)
|
||||
mixer.time = Math.abs(time)
|
||||
mixer.update(0) // (forgetting) this little buddy costed me lots of time :]
|
||||
mixer.updateLoop = (t) => {
|
||||
mixer.loop.timeStart = t.y != undefined ? t.y : mixer.loop.timeStart
|
||||
mixer.loop.timeStop = t.z != undefined ? t.z : mixer.loop.timeStop
|
||||
mixer.model.animations.map( (anim) => {
|
||||
if( mixer.loop.timeStart != undefined ){
|
||||
//if( anim.action ) delete anim.action
|
||||
//anim.action = mixer.clipAction( anim )
|
||||
anim.action.time = mixer.loop.timeStart
|
||||
anim.action.setLoop( THREE.LoopOnce, )
|
||||
anim.action.timeScale = mixer.timeScale
|
||||
anim.action.enabled = true
|
||||
anim.action.play()
|
||||
}
|
||||
})
|
||||
mixer.setTime(mixer.loop.timeStart)
|
||||
mixer.time = Math.abs( mixer.loop.timeStart )
|
||||
mixer.update(0)
|
||||
mixer.checkZombies( model.animations)
|
||||
}
|
||||
|
||||
// update loop when needed
|
||||
|
@ -92,9 +90,9 @@ xrf.frag.t.setupMixer = function(opts){
|
|||
if( time == 0 ) return update.call(this,time)
|
||||
|
||||
// loop jump
|
||||
//if( mixer.loop.speed > 0.0 && mixer.time > mixer.loop.timeStop * mixer.loop.speedAbs ){
|
||||
// setTimeout( (time) => mixer.updateLoop(time),0,mixer.loop.timeStart) // prevent recursion
|
||||
//}
|
||||
if( mixer.loop.speed > 0.0 && mixer.time > mixer.loop.timeStop ){
|
||||
setTimeout( (time,anims) => mixer.updateLoop(time), 0, mixer.loop.timeStart ) // prevent recursion
|
||||
}
|
||||
return update.call( this, time )
|
||||
}
|
||||
mixer.update.patched = true
|
||||
|
@ -102,19 +100,12 @@ xrf.frag.t.setupMixer = function(opts){
|
|||
|
||||
// calculate total duration/frame based on longest animation
|
||||
mixer.duration = 0
|
||||
mixer.frames = 0
|
||||
if( model.animations.length ){
|
||||
model.animations.map( (a) => {
|
||||
mixer.duration = a.duration > mixer.duration ? a.duration : mixer.duration
|
||||
mixer.frames = a.tracks[0].times.length > mixer.frames ? a.tracks[0].times.length : mixer.frames
|
||||
})
|
||||
model.animations.map( (a) => mixer.duration = ( a.duration > mixer.duration ) ? a.duration : mixer.duration )
|
||||
}
|
||||
|
||||
mixer.loop = {fps: mixer.frames / mixer.duration}
|
||||
xrf.frag.t.calculateLoop( null, mixer.loop, mixer.loop.fps ) // gltf uses looppoints in seconds (not frames)
|
||||
xrf.mixers.push(mixer)
|
||||
console.log("mixer fps="+mixer.loop.fps+" frames:"+mixer.frames+" duration:"+mixer.duration)
|
||||
}
|
||||
})
|
||||
|
||||
if( document.location.hash.match(/t=/) ){
|
||||
let url = document.location.href
|
||||
|
@ -127,17 +118,11 @@ if( document.location.hash.match(/t=/) ){
|
|||
window.addEventListener('touchstart', playAfterUserGesture )
|
||||
}
|
||||
|
||||
xrf.addEventListener('parseModel', (opts) => {
|
||||
let {model,file,url} = opts
|
||||
// add animations
|
||||
xrf.frag.t.setupMixer(opts)
|
||||
})
|
||||
|
||||
xrf.addEventListener('render', (opts) => {
|
||||
let model = xrf.model
|
||||
let {time} = opts
|
||||
if( !model ) return
|
||||
if( xrf.mixers.length ) xrf.mixers.map( (m) => m.update( time ) )
|
||||
if( xrf.mixers.length ) xrf.mixers.map( (m) => m.isPlaying ? m.update( time ) : false )
|
||||
|
||||
// update camera if possible
|
||||
if( model.cameras && model.cameras.length && xrf.mixers.length ){
|
||||
|
|
|
@ -33,7 +33,8 @@ class Parser {
|
|||
Frag.set("env", XRF.ASSET | XRF.PV_OVERRIDE | XRF.T_STRING | XRF.METADATA );
|
||||
|
||||
// category: animation
|
||||
Frag.set("t", XRF.ASSET | XRF.PV_OVERRIDE | XRF.T_FLOAT | XRF.T_VECTOR2 | XRF.T_VECTOR3 | XRF.NAVIGATOR | XRF.METADATA);
|
||||
Frag.set("t", XRF.ASSET | XRF.PV_OVERRIDE | XRF.T_FLOAT | XRF.T_VECTOR2 | XRF.T_STRING | XRF.NAVIGATOR | XRF.METADATA);
|
||||
Frag.set("tv", XRF.ASSET | XRF.PV_OVERRIDE | XRF.T_FLOAT | XRF.T_VECTOR2 | XRF.T_VECTOR3 | XRF.NAVIGATOR | XRF.METADATA);
|
||||
Frag.set("gravity", XRF.ASSET | XRF.PV_OVERRIDE | XRF.T_VECTOR3 | XRF.METADATA );
|
||||
Frag.set("physics", XRF.ASSET | XRF.PV_OVERRIDE | XRF.T_VECTOR3 | XRF.METADATA );
|
||||
|
||||
|
|
Loading…
Reference in New Issue