Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
fktz008
three.js
提交
c32f31a5
T
three.js
项目概览
fktz008
/
three.js
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
three.js
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c32f31a5
编写于
10月 21, 2015
作者:
T
tschw
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Animation: New API, caching and masses.
上级
6db066d9
变更
37
展开全部
隐藏空白更改
内联
并排
Showing
37 changed file
with
2488 addition
and
743 deletion
+2488
-743
examples/canvas_morphtargets_horse.html
examples/canvas_morphtargets_horse.html
+1
-1
examples/js/BlendCharacter.js
examples/js/BlendCharacter.js
+23
-28
examples/js/BlendCharacterGui.js
examples/js/BlendCharacterGui.js
+3
-10
examples/js/MD2Character.js
examples/js/MD2Character.js
+26
-12
examples/js/MorphAnimMesh.js
examples/js/MorphAnimMesh.js
+3
-4
examples/js/UCSCharacter.js
examples/js/UCSCharacter.js
+1
-1
examples/webgl_animation_blend.html
examples/webgl_animation_blend.html
+1
-1
examples/webgl_animation_scene.html
examples/webgl_animation_scene.html
+1
-1
examples/webgl_animation_skinning_blending.html
examples/webgl_animation_skinning_blending.html
+1
-11
examples/webgl_animation_skinning_morph.html
examples/webgl_animation_skinning_morph.html
+372
-48
examples/webgl_lights_hemisphere.html
examples/webgl_lights_hemisphere.html
+1
-1
examples/webgl_loader_json_blender.html
examples/webgl_loader_json_blender.html
+8
-13
examples/webgl_loader_scene.html
examples/webgl_loader_scene.html
+1
-1
examples/webgl_morphnormals.html
examples/webgl_morphnormals.html
+2
-2
examples/webgl_morphtargets_horse.html
examples/webgl_morphtargets_horse.html
+1
-1
examples/webgl_shading_physical.html
examples/webgl_shading_physical.html
+1
-1
examples/webgl_shadowmap.html
examples/webgl_shadowmap.html
+12
-7
examples/webgl_shadowmap_performance.html
examples/webgl_shadowmap_performance.html
+42
-5
examples/webgl_skinning_simple.html
examples/webgl_skinning_simple.html
+1
-1
examples/webgl_terrain_dynamic.html
examples/webgl_terrain_dynamic.html
+1
-1
src/animation/AnimationAction.js
src/animation/AnimationAction.js
+0
-190
src/animation/AnimationClip.js
src/animation/AnimationClip.js
+1
-1
src/animation/AnimationMixer.js
src/animation/AnimationMixer.js
+1187
-216
src/animation/AnimationObjectGroup.js
src/animation/AnimationObjectGroup.js
+370
-0
src/animation/AnimationUtils.js
src/animation/AnimationUtils.js
+1
-2
src/animation/KeyframeTrack.js
src/animation/KeyframeTrack.js
+6
-6
src/animation/PropertyBinding.js
src/animation/PropertyBinding.js
+293
-167
src/animation/PropertyMixer.js
src/animation/PropertyMixer.js
+3
-2
src/animation/tracks/BooleanKeyframeTrack.js
src/animation/tracks/BooleanKeyframeTrack.js
+2
-1
src/animation/tracks/ColorKeyframeTrack.js
src/animation/tracks/ColorKeyframeTrack.js
+2
-1
src/animation/tracks/NumberKeyframeTrack.js
src/animation/tracks/NumberKeyframeTrack.js
+2
-1
src/animation/tracks/QuaternionKeyframeTrack.js
src/animation/tracks/QuaternionKeyframeTrack.js
+2
-1
src/animation/tracks/StringKeyframeTrack.js
src/animation/tracks/StringKeyframeTrack.js
+2
-1
src/animation/tracks/VectorKeyframeTrack.js
src/animation/tracks/VectorKeyframeTrack.js
+2
-1
test/unit/animation/AnimationObjectGroup.js
test/unit/animation/AnimationObjectGroup.js
+107
-0
test/unit/unittests_three.html
test/unit/unittests_three.html
+5
-2
utils/build/includes/common.json
utils/build/includes/common.json
+1
-1
未找到文件。
examples/canvas_morphtargets_horse.html
浏览文件 @
c32f31a5
...
...
@@ -78,7 +78,7 @@
mixer
=
new
THREE
.
AnimationMixer
(
mesh
);
var
clip
=
THREE
.
AnimationClip
.
CreateFromMorphTargetSequence
(
'
gallop
'
,
geometry
.
morphTargets
,
30
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
clip
).
warpToDuration
(
1
)
);
mixer
.
clipAction
(
clip
).
setDuration
(
1
).
play
(
);
}
);
...
...
examples/js/BlendCharacter.js
浏览文件 @
c32f31a5
...
...
@@ -4,7 +4,6 @@
THREE
.
BlendCharacter
=
function
()
{
this
.
animations
=
{};
this
.
weightSchedule
=
[];
this
.
warpSchedule
=
[];
...
...
@@ -20,13 +19,13 @@ THREE.BlendCharacter = function () {
THREE
.
SkinnedMesh
.
call
(
scope
,
geometry
,
originalMaterial
);
scope
.
mixer
=
new
THREE
.
AnimationMixer
(
scope
);
var
mixer
=
new
THREE
.
AnimationMixer
(
scope
);
scope
.
mixer
=
mixer
;
// Create the animations
// Create the animations
for
(
var
i
=
0
;
i
<
geometry
.
animations
.
length
;
++
i
)
{
var
animName
=
geometry
.
animations
[
i
].
name
;
scope
.
animations
[
animName
]
=
geometry
.
animations
[
i
];
mixer
.
clipAction
(
geometry
.
animations
[
i
]
);
}
...
...
@@ -45,49 +44,45 @@ THREE.BlendCharacter = function () {
this
.
play
=
function
(
animName
,
weight
)
{
this
.
mixer
.
removeAllActions
();
this
.
mixer
.
play
(
new
THREE
.
AnimationAction
(
this
.
animations
[
animName
]
)
);
//console.log("play('%s', %f)", animName, weight);
return
this
.
mixer
.
clipAction
(
animName
).
setEffectiveWeight
(
weight
).
play
();
};
this
.
crossfade
=
function
(
fromAnimName
,
toAnimName
,
duration
)
{
this
.
mixer
.
removeAllActions
();
var
fromAction
=
new
THREE
.
AnimationAction
(
this
.
animations
[
fromAnimName
]
);
var
toAction
=
new
THREE
.
AnimationAction
(
this
.
animations
[
toAnimName
]
);
this
.
mixer
.
stopAllAction
();
this
.
mixer
.
play
(
fromAction
);
this
.
mixer
.
play
(
toAction
);
var
fromAction
=
this
.
play
(
fromAnimName
,
1
);
var
toAction
=
this
.
play
(
toAnimName
,
1
);
this
.
mixer
.
crossFade
(
fromAction
,
toAction
,
duration
,
false
);
fromAction
.
crossFadeTo
(
toAction
,
duration
,
false
);
};
this
.
warp
=
function
(
fromAnimName
,
toAnimName
,
duration
)
{
this
.
mixer
.
removeAllActions
();
var
fromAction
=
new
THREE
.
AnimationAction
(
this
.
animations
[
fromAnimName
]
);
var
toAction
=
new
THREE
.
AnimationAction
(
this
.
animations
[
toAnimName
]
);
this
.
mixer
.
stopAllAction
();
this
.
mixer
.
play
(
fromAction
);
this
.
mixer
.
play
(
toAction
);
var
fromAction
=
this
.
play
(
fromAnimName
,
1
);
var
toAction
=
this
.
play
(
toAnimName
,
1
);
this
.
mixer
.
crossFade
(
fromAction
,
toAction
,
duration
,
true
);
fromAction
.
crossFadeTo
(
toAction
,
duration
,
true
);
};
this
.
applyWeight
=
function
(
animName
,
weight
)
{
var
action
=
this
.
mixer
.
findActionByName
(
animName
);
if
(
action
)
{
action
.
weight
=
weight
;
}
this
.
mixer
.
clipAction
(
animName
).
setEffectiveWeight
(
weight
);
};
this
.
getWeight
=
function
(
animName
)
{
return
this
.
mixer
.
clipAction
(
animName
).
getEffectiveWeight
();
}
this
.
pauseAll
=
function
()
{
this
.
mixer
.
timeScale
=
0
;
...
...
@@ -103,7 +98,7 @@ THREE.BlendCharacter = function () {
this
.
stopAll
=
function
()
{
this
.
mixer
.
removeAllActions
();
this
.
mixer
.
stopAllAction
();
};
...
...
examples/js/BlendCharacterGui.js
浏览文件 @
c32f31a5
...
...
@@ -40,16 +40,9 @@ function BlendCharacterGui( blendMesh ) {
this
.
update
=
function
(
time
)
{
var
getWeight
=
function
(
actionName
)
{
var
action
=
blendMesh
.
mixer
.
findActionByName
(
actionName
);
return
(
action
!==
null
)
?
action
.
getWeightAt
(
time
)
:
0
;
}
controls
[
'
idle
'
]
=
getWeight
(
'
idle
'
);
controls
[
'
walk
'
]
=
getWeight
(
'
walk
'
);
controls
[
'
run
'
]
=
getWeight
(
'
run
'
);
controls
[
'
idle
'
]
=
blendMesh
.
getWeight
(
'
idle
'
);
controls
[
'
walk
'
]
=
blendMesh
.
getWeight
(
'
walk
'
);
controls
[
'
run
'
]
=
blendMesh
.
getWeight
(
'
run
'
);
};
...
...
examples/js/MD2Character.js
浏览文件 @
c32f31a5
...
...
@@ -33,7 +33,6 @@ THREE.MD2Character = function () {
var
weaponsTextures
=
[];
for
(
var
i
=
0
;
i
<
config
.
weapons
.
length
;
i
++
)
weaponsTextures
[
i
]
=
config
.
weapons
[
i
][
1
];
// SKINS
this
.
skinsBody
=
loadTextures
(
config
.
baseUrl
+
"
skins/
"
,
config
.
skins
);
...
...
@@ -81,6 +80,21 @@ THREE.MD2Character = function () {
scope
.
weapons
[
index
]
=
mesh
;
scope
.
meshWeapon
=
mesh
;
// the animation system requires unique names, so append the
// uuid of the source geometry:
var
geometry
=
mesh
.
geometry
,
animations
=
geometry
.
animations
;
for
(
var
i
=
0
,
n
=
animations
.
length
;
i
!==
n
;
++
i
)
{
var
animation
=
animations
[
i
];
animation
.
name
+=
geometry
.
uuid
;
}
checkLoadingComplete
();
}
...
...
@@ -154,17 +168,15 @@ THREE.MD2Character = function () {
if
(
this
.
meshBody
)
{
if
(
this
.
meshBody
.
activeAction
)
{
scope
.
mixer
.
removeAction
(
this
.
meshBody
.
activeAction
);
this
.
meshBody
.
activeAction
.
stop
(
);
this
.
meshBody
.
activeAction
=
null
;
}
var
clip
=
THREE
.
AnimationClip
.
findByName
(
this
.
meshBody
.
geometry
.
animations
,
clipName
);
if
(
clip
)
{
var
action
=
new
THREE
.
AnimationAction
(
clip
,
this
.
mixer
.
time
).
setLocalRoot
(
this
.
meshBody
);
scope
.
mixer
.
addAction
(
action
);
this
.
meshBody
.
activeAction
=
action
;
this
.
meshBody
.
activeAction
=
this
.
mixer
.
clipAction
(
clip
,
this
.
meshBody
).
play
();
}
...
...
@@ -183,17 +195,19 @@ THREE.MD2Character = function () {
if
(
scope
.
meshWeapon
)
{
if
(
this
.
meshWeapon
.
activeAction
)
{
scope
.
mixer
.
removeAction
(
this
.
meshWeapon
.
activeAction
);
this
.
meshWeapon
.
activeAction
.
stop
(
);
this
.
meshWeapon
.
activeAction
=
null
;
}
var
clip
=
THREE
.
AnimationClip
.
findByName
(
this
.
meshWeapon
.
geometry
.
animations
,
clipName
);
if
(
clip
)
{
var
geometry
=
this
.
meshWeapon
.
geometry
,
animations
=
geometry
.
animations
;
var
action
=
new
THREE
.
AnimationAction
(
clip
).
syncWith
(
this
.
meshBody
.
activeAction
).
setLocalRoot
(
this
.
meshWeapon
);
scope
.
mixer
.
addAction
(
action
);
var
clip
=
THREE
.
AnimationClip
.
findByName
(
animations
,
clipName
+
geometry
.
uuid
);
if
(
clip
)
{
this
.
meshWeapon
.
activeAction
=
action
;
this
.
meshWeapon
.
activeAction
=
this
.
mixer
.
clipAction
(
clip
,
this
.
meshWeapon
).
syncWith
(
this
.
meshBody
.
activeAction
).
play
();
}
...
...
examples/js/MorphAnimMesh.js
浏览文件 @
c32f31a5
...
...
@@ -31,7 +31,7 @@ THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) {
if
(
this
.
activeAction
)
{
this
.
mixer
.
removeAction
(
this
.
activeAction
);
this
.
activeAction
.
stop
(
);
this
.
activeAction
=
null
;
}
...
...
@@ -40,10 +40,9 @@ THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) {
if
(
clip
)
{
var
action
=
new
THREE
.
Animation
Action
(
clip
);
var
action
=
this
.
mixer
.
clip
Action
(
clip
);
action
.
timeScale
=
(
clip
.
tracks
.
length
*
fps
)
/
clip
.
duration
;
this
.
mixer
.
addAction
(
action
);
this
.
activeAction
=
action
;
this
.
activeAction
=
action
.
play
();
}
else
{
...
...
examples/js/UCSCharacter.js
浏览文件 @
c32f31a5
...
...
@@ -55,7 +55,7 @@ THREE.UCSCharacter = function() {
mesh
.
castShadow
=
true
;
mesh
.
receiveShadow
=
true
;
scope
.
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
geometry
.
animations
[
0
]
).
setLocalRoot
(
mesh
)
);
scope
.
mixer
.
clipAction
(
geometry
.
animations
[
0
],
mesh
).
play
(
);
scope
.
setSkin
(
0
);
...
...
examples/webgl_animation_blend.html
浏览文件 @
c32f31a5
...
...
@@ -133,7 +133,7 @@
var
blendObject
=
scene
.
getObjectByName
(
'
tree-morph
'
);
var
clip
=
blendObject
.
geometry
.
animations
[
0
];
mixer
=
new
THREE
.
AnimationMixer
(
blendObject
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
clip
)
);
mixer
.
clipAction
(
clip
).
play
(
);
}
);
...
...
examples/webgl_animation_scene.html
浏览文件 @
c32f31a5
...
...
@@ -131,7 +131,7 @@
mixer
=
new
THREE
.
AnimationMixer
(
scene
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
sceneAnimationClip
)
);
mixer
.
clipAction
(
sceneAnimationClip
).
play
(
);
}
);
...
...
examples/webgl_animation_skinning_blending.html
浏览文件 @
c32f31a5
...
...
@@ -156,17 +156,7 @@
var
data
=
event
.
detail
;
for
(
var
i
=
0
;
i
<
data
.
anims
.
length
;
++
i
)
{
var
action
=
blendMesh
.
mixer
.
findActionByName
(
data
.
anims
[
i
]
);
if
(
action
!==
null
)
{
if
(
action
.
getWeightAt
(
blendMesh
.
mixer
.
time
)
!==
data
.
weights
[
i
]
)
{
action
.
weight
=
data
.
weights
[
i
];
}
}
blendMesh
.
applyWeight
(
data
.
anims
[
i
],
data
.
weights
[
i
]
);
}
...
...
examples/webgl_animation_skinning_morph.html
浏览文件 @
c32f31a5
...
...
@@ -22,6 +22,12 @@
padding
:
5px
;
}
#meminfo
{
margin-top
:
8px
;
font-size
:
10px
;
display
:
none
;
}
a
{
color
:
#0af
;
}
...
...
@@ -40,6 +46,7 @@
<div
id=
"info"
>
<a
href=
"http://threejs.org"
target=
"_blank"
>
three.js
</a>
webgl - clip system
- knight by
<a
href=
"http://vimeo.com/36113323"
>
apendua
</a>
<div
id=
"meminfo"
></div>
</div>
<script
src=
"../build/three.min.js"
></script>
...
...
@@ -59,9 +66,9 @@
var
camera
,
scene
;
var
renderer
;
var
mesh
,
helper
;
var
mesh
,
mesh2
,
helper
;
var
mixer
,
faces
Action
,
bonesAction
;
var
mixer
,
faces
Clip
,
bonesClip
;
var
mouseX
=
0
,
mouseY
=
0
;
...
...
@@ -70,6 +77,9 @@
var
clock
=
new
THREE
.
Clock
();
var
domMemInfo
=
document
.
getElementById
(
'
meminfo
'
),
showMemInfo
=
false
;
document
.
addEventListener
(
'
mousemove
'
,
onDocumentMouseMove
,
false
);
init
();
...
...
@@ -212,6 +222,7 @@
}
mesh
=
new
THREE
.
SkinnedMesh
(
geometry
,
new
THREE
.
MeshFaceMaterial
(
materials
)
);
mesh
.
name
=
"
Knight Mesh
"
;
mesh
.
position
.
set
(
x
,
y
-
bb
.
min
.
y
*
s
,
z
);
mesh
.
scale
.
set
(
s
,
s
,
s
);
scene
.
add
(
mesh
);
...
...
@@ -219,6 +230,19 @@
mesh
.
castShadow
=
true
;
mesh
.
receiveShadow
=
true
;
mesh2
=
new
THREE
.
SkinnedMesh
(
geometry
,
new
THREE
.
MeshFaceMaterial
(
materials
)
);
mesh2
.
name
=
"
Lil' Bro Mesh
"
;
mesh2
.
position
.
set
(
x
-
240
,
y
-
bb
.
min
.
y
*
s
,
z
+
500
);
mesh2
.
scale
.
set
(
s
/
2
,
s
/
2
,
s
/
2
);
mesh2
.
rotation
.
y
=
THREE
.
Math
.
degToRad
(
60
);
mesh2
.
visible
=
false
;
mesh2
.
castShadow
=
true
;
mesh2
.
receiveShadow
=
true
;
scene
.
add
(
mesh2
);
helper
=
new
THREE
.
SkeletonHelper
(
mesh
);
helper
.
material
.
linewidth
=
3
;
helper
.
visible
=
false
;
...
...
@@ -226,87 +250,375 @@
mixer
=
new
THREE
.
AnimationMixer
(
mesh
);
var
clipBones
=
geometry
.
animations
[
0
];
bonesAction
=
new
THREE
.
AnimationAction
(
clipBones
);
var
clipMorpher
=
THREE
.
AnimationClip
.
CreateFromMorphTargetSequence
(
'
facialExpressions
'
,
mesh
.
geometry
.
morphTargets
,
3
);
facesAction
=
new
THREE
.
AnimationAction
(
clipMorpher
);
bonesClip
=
geometry
.
animations
[
0
];
facesClip
=
THREE
.
AnimationClip
.
CreateFromMorphTargetSequence
(
'
facialExpressions
'
,
mesh
.
geometry
.
morphTargets
,
3
);
}
function
initGUI
()
{
var
API
=
{
'
show model
'
:
true
,
'
show skeleton
'
:
false
,
'
bones action
'
:
true
,
// use false to see initial allocation
'
bones enable
'
:
true
,
'
faces action
'
:
true
,
'
faces enable
'
:
true
,
'
release props
'
:
function
()
{
mixer
.
releaseCachedBindings
(
true
);
},
'
purge cache
'
:
function
()
{
mixer
.
releaseCachedBindings
();
}
'
show model
'
:
true
,
'
show skeleton
'
:
false
,
'
show 2nd model
'
:
false
,
'
show mem. info
'
:
false
};
var
gui
=
new
dat
.
GUI
();
gui
.
add
(
API
,
'
show model
'
).
onChange
(
function
()
{
mesh
.
visible
=
API
[
'
show model
'
];
}
);
gui
.
add
(
API
,
'
show model
'
).
onChange
(
function
()
{
mesh
.
visible
=
API
[
'
show model
'
];
}
);
gui
.
add
(
API
,
'
show skeleton
'
).
onChange
(
function
()
{
helper
.
visible
=
API
[
'
show skeleton
'
];
}
);
gui
.
add
(
API
,
'
show skeleton
'
).
onChange
(
function
()
{
helper
.
visible
=
API
[
'
show skeleton
'
];
}
);
gui
.
add
(
API
,
'
show 2nd model
'
).
onChange
(
function
()
{
mesh2
.
visible
=
API
[
'
show 2nd model
'
];
}
);
// Note: .add/removeAction and .enabled = true / false have
// different performance characteristics:
//
// The former changes dynamic data structures in the mixer,
// therefore the switch is more expensive but removes the
// per-action base cost caused by the unique property
// bindings it uses.
//
// The latter is a zero-cost switch, but the per-frame base
// cost for having the action added to the mixer remains.
gui
.
add
(
API
,
'
show mem. info
'
).
onChange
(
function
()
{
function
actionControls
(
key
,
action
)
{
showMemInfo
=
API
[
'
show mem. info
'
];
domMemInfo
.
style
.
display
=
showMemInfo
?
'
block
'
:
'
none
'
;
var
guiNameAddRemove
=
key
+
'
action
'
;
var
guiNameEnabled
=
key
+
'
enable
'
;
}
);
// utility function used for drop-down options lists in the GUI
var
objectNames
=
function
(
objects
)
{
// set initial state
var
result
=
[];
if
(
API
[
guiNameAddRemove
]
)
{
for
(
var
i
=
0
,
n
=
objects
.
length
;
i
!==
n
;
++
i
)
{
action
.
enabled
=
API
[
guiNameEnabled
];
mixer
.
addAction
(
action
);
var
obj
=
objects
[
i
];
result
.
push
(
obj
&&
obj
.
name
||
'
<null>
'
);
}
// attach controls
return
result
;
gui
.
add
(
API
,
guiNameAddRemove
).
onChange
(
function
()
{
};
if
(
API
[
guiNameAddRemove
]
)
{
mixer
.
addAction
(
action
);
// creates gui folder with tests / examples for the action API
var
clipControl
=
function
clipControl
(
gui
,
mixer
,
clip
,
rootObjects
)
{
}
else
{
var
folder
=
gui
.
addFolder
(
"
Clip '
"
+
clip
.
name
+
"
'
"
),
mixer
.
removeAction
(
action
);
rootNames
=
objectNames
(
rootObjects
),
rootName
=
rootNames
[
0
],
root
=
rootObjects
[
0
],
}
action
=
null
,
}
);
API
=
{
'
play()
'
:
function
play
()
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
play
();
},
'
stop()
'
:
function
()
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
stop
();
},
'
reset()
'
:
function
()
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
reset
();
},
get
'
time =
'
()
{
return
action
!==
null
?
action
.
time
:
0
;
},
set
'
time =
'
(
value
)
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
time
=
value
;
},
get
'
paused =
'
()
{
return
action
!==
null
&&
action
.
paused
;
},
set
'
paused =
'
(
value
)
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
paused
=
value
;
},
get
'
enabled =
'
()
{
return
action
!==
null
&&
action
.
enabled
;
},
set
'
enabled =
'
(
value
)
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
enabled
=
value
;
},
get
'
clamp =
'
()
{
return
action
!==
null
?
action
.
clampWhenFinished
:
true
;
},
set
'
clamp =
'
(
value
)
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
clampWhenFinished
=
value
;
},
get
'
isRunning() =
'
()
{
return
action
!==
null
&&
action
.
isRunning
();
},
set
'
isRunning() =
'
(
value
)
{
alert
(
"
Read only - this is the result of a method.
"
);
},
'
play delayed
'
:
function
()
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
startAt
(
mixer
.
time
+
0.5
).
play
();
},
get
'
weight =
'
()
{
return
action
!==
null
?
action
.
weight
:
1
;
},
set
'
weight =
'
(
value
)
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
weight
=
value
;
},
get
'
eff. weight
'
()
{
return
action
!==
null
?
action
.
getEffectiveWeight
()
:
1
;
},
set
'
eff. weight
'
(
value
)
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
setEffectiveWeight
(
value
);
},
gui
.
add
(
API
,
guiNameEnabled
).
onChange
(
function
()
{
'
fade in
'
:
function
()
{
action
.
enabled
=
API
[
guiNameEnabled
];
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
reset
().
fadeIn
(
0.25
).
play
();
},
'
fade out
'
:
function
()
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
fadeOut
(
0.25
).
play
();
},
get
'
timeScale =
'
()
{
return
(
action
!==
null
)
?
action
.
timeScale
:
1
;
},
set
'
timeScale =
'
(
value
)
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
timeScale
=
value
;
},
get
'
eff.T.Scale
'
()
{
return
(
action
!==
null
)
?
action
.
getEffectiveTimeScale
()
:
1
;
},
set
'
eff.T.Scale
'
(
value
)
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
setEffectiveTimeScale
(
value
);
},
'
time warp
'
:
function
()
{
action
=
mixer
.
clipAction
(
clip
,
root
);
var
timeScaleNow
=
action
.
getEffectiveTimeScale
();
var
destTimeScale
=
timeScaleNow
>
0
?
-
1
:
1
;
action
.
warp
(
timeScaleNow
,
destTimeScale
,
4
).
play
();
},
get
'
loop mode
'
()
{
return
action
!==
null
?
action
.
loop
:
THREE
.
LoopRepeat
;
},
set
'
loop mode
'
(
value
)
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
loop
=
+
value
;
},
get
'
repetitions
'
()
{
return
action
!==
null
?
action
.
repetitions
:
Infinity
;
},
set
'
repetitions
'
(
value
)
{
action
=
mixer
.
clipAction
(
clip
,
root
);
action
.
repetitions
=
+
value
;
},
get
'
local root
'
()
{
return
rootName
;
},
set
'
local root
'
(
value
)
{
rootName
=
value
;
root
=
rootObjects
[
rootNames
.
indexOf
(
rootName
)
];
if
(
action
!==
null
)
{
// TODO
}
}
};
folder
.
add
(
API
,
'
play()
'
);
folder
.
add
(
API
,
'
stop()
'
);
folder
.
add
(
API
,
'
reset()
'
);
folder
.
add
(
API
,
'
time =
'
,
0
,
clip
.
duration
).
listen
();
folder
.
add
(
API
,
'
paused =
'
).
listen
();
folder
.
add
(
API
,
'
enabled =
'
).
listen
();
folder
.
add
(
API
,
'
clamp =
'
);
folder
.
add
(
API
,
'
isRunning() =
'
).
listen
();
folder
.
add
(
API
,
'
play delayed
'
);
folder
.
add
(
API
,
'
weight =
'
,
0
,
1
).
listen
();
folder
.
add
(
API
,
'
eff. weight
'
,
0
,
1
).
listen
();
folder
.
add
(
API
,
'
fade in
'
);
folder
.
add
(
API
,
'
fade out
'
);
folder
.
add
(
API
,
'
timeScale =
'
,
-
2
,
2
).
listen
();
folder
.
add
(
API
,
'
eff.T.Scale
'
,
-
2
,
2
).
listen
();
folder
.
add
(
API
,
'
time warp
'
);
folder
.
add
(
API
,
'
loop mode
'
,
{
"
LoopOnce
"
:
THREE
.
LoopOnce
,
"
LoopRepeat
"
:
THREE
.
LoopRepeat
,
"
LoopPingPong
"
:
THREE
.
LoopPingPong
}
);
folder
.
add
(
API
,
'
repetitions
'
,
0
,
Infinity
);
folder
.
add
(
API
,
'
local root
'
,
rootNames
);
};
// function clipControl
// one folder per clip
clipControl
(
gui
,
mixer
,
bonesClip
,
[
null
,
mesh
,
mesh2
]
);
clipControl
(
gui
,
mixer
,
facesClip
,
[
null
,
mesh
,
mesh2
]
);
var
memoryControl
=
function
(
gui
,
mixer
,
clips
,
rootObjects
)
{
var
clipNames
=
objectNames
(
clips
),
rootNames
=
objectNames
(
rootObjects
);
var
folder
=
gui
.
addFolder
(
"
Memory Management
"
),
clipName
=
clipNames
[
0
],
clip
=
clips
[
0
],
rootName
=
rootNames
[
0
],
root
=
rootObjects
[
0
],
API
=
{
get
'
clip
'
()
{
return
clipName
;
},
set
'
clip
'
(
value
)
{
clipName
=
value
;
clip
=
clips
[
clipNames
.
indexOf
(
clipName
)
];
},
get
'
root
'
()
{
return
rootName
;
},
set
'
root
'
(
value
)
{
rootName
=
value
;
root
=
rootObjects
[
rootNames
.
indexOf
(
rootName
)
];
},
'
uncache clip
'
:
function
()
{
mixer
.
uncacheClip
(
clip
);
},
'
uncache root
'
:
function
()
{
mixer
.
uncacheRoot
(
root
);
},
'
uncache action
'
:
function
()
{
mixer
.
uncacheAction
(
clip
,
root
);
}
};
folder
.
add
(
API
,
'
clip
'
,
clipNames
);
folder
.
add
(
API
,
'
root
'
,
rootNames
);
folder
.
add
(
API
,
'
uncache root
'
);
folder
.
add
(
API
,
'
uncache clip
'
);
folder
.
add
(
API
,
'
uncache action
'
);
}
actionControls
(
'
bones
'
,
bonesAction
);
actionControls
(
'
faces
'
,
facesAction
);
memoryControl
(
gui
,
mixer
,
[
bonesClip
,
facesClip
],
[
mesh
,
mesh2
]
);
gui
.
add
(
API
,
'
release props
'
);
gui
.
add
(
API
,
'
purge cache
'
);
}
...
...
@@ -326,6 +638,18 @@
render
();
stats
.
update
();
if
(
showMemInfo
)
{
var
s
=
mixer
.
stats
,
ciS
=
s
.
controlInterpolants
;
domMemInfo
.
innerHTML
=
s
.
actions
.
inUse
+
"
/
"
+
s
.
actions
.
total
+
"
actions
"
+
s
.
bindings
.
inUse
+
"
/
"
+
s
.
bindings
.
total
+
"
bindings
"
+
ciS
.
inUse
+
"
/
"
+
ciS
.
total
+
"
control interpolants
"
;
}
}
function
render
()
{
...
...
examples/webgl_lights_hemisphere.html
浏览文件 @
c32f31a5
...
...
@@ -214,7 +214,7 @@
scene
.
add
(
mesh
);
var
mixer
=
new
THREE
.
AnimationMixer
(
mesh
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
geometry
.
animations
[
0
]
).
warpToDuration
(
1
)
);
mixer
.
clipAction
(
geometry
.
animations
[
0
]
).
setDuration
(
1
).
play
(
);
mixers
.
push
(
mixer
);
}
);
...
...
examples/webgl_loader_json_blender.html
浏览文件 @
c32f31a5
...
...
@@ -59,7 +59,7 @@
var
dae
;
var
clock
=
new
THREE
.
Clock
();
var
mixer
s
=
[]
;
var
mixer
;
// Collada model
...
...
@@ -102,6 +102,8 @@
// Add Blender exported Collada model
mixer
=
new
THREE
.
AnimationMixer
(
scene
);
var
loader
=
new
THREE
.
JSONLoader
();
loader
.
load
(
'
models/animated/monster/monster.js
'
,
function
(
geometry
,
materials
)
{
...
...
@@ -137,13 +139,10 @@
scene
.
add
(
mesh
);
var
mixer
=
new
THREE
.
AnimationMixer
(
mesh
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
geometry
.
animations
[
0
]
).
warpToDuration
(
1
)
);
// random animation offset
mixer
.
update
(
1000
*
Math
.
random
()
);
mixers
.
push
(
mixer
);
mixer
.
clipAction
(
geometry
.
animations
[
0
],
mesh
)
.
setDuration
(
1
)
// one second
.
startAt
(
-
Math
.
random
()
)
// random phase (already running)
.
play
();
// let's go
}
...
...
@@ -203,11 +202,7 @@
THREE
.
AnimationHandler
.
update
(
delta
);
for
(
var
i
=
0
;
i
<
mixers
.
length
;
i
++
)
{
mixers
[
i
].
update
(
delta
);
}
mixer
.
update
(
delta
);
render
();
...
...
examples/webgl_loader_scene.html
浏览文件 @
c32f31a5
...
...
@@ -214,7 +214,7 @@
if
(
object
.
geometry
&&
object
.
geometry
.
animations
&&
object
.
geometry
.
animations
.
length
>
0
)
{
var
mixer
=
new
THREE
.
AnimationMixer
(
object
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
object
.
geometry
.
animations
[
0
]
)
);
mixer
.
clipAction
(
object
.
geometry
.
animations
[
0
]
).
play
(
);
mixers
.
push
(
mixer
);
}
...
...
examples/webgl_morphnormals.html
浏览文件 @
c32f31a5
...
...
@@ -93,7 +93,7 @@
scene
.
add
(
mesh
);
var
mixer
=
new
THREE
.
AnimationMixer
(
mesh
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
geometry
.
animations
[
0
]
).
warpToDuration
(
1
)
);
mixer
.
clipAction
(
geometry
.
animations
[
0
]
).
setDuration
(
1
).
play
(
);
mixers
.
push
(
mixer
);
...
...
@@ -120,7 +120,7 @@
scene
.
add
(
mesh
);
var
mixer
=
new
THREE
.
AnimationMixer
(
mesh
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
geometry
.
animations
[
0
]
).
warpToDuration
(
1
)
);
mixer
.
clipAction
(
geometry
.
animations
[
0
]
).
setDuration
(
1
).
play
(
);
mixers
.
push
(
mixer
);
...
...
examples/webgl_morphtargets_horse.html
浏览文件 @
c32f31a5
...
...
@@ -72,7 +72,7 @@
mixer
=
new
THREE
.
AnimationMixer
(
mesh
);
var
clip
=
THREE
.
AnimationClip
.
CreateFromMorphTargetSequence
(
'
gallop
'
,
geometry
.
morphTargets
,
30
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
clip
).
warpToDuration
(
1
)
);
mixer
.
clipAction
(
clip
).
setDuration
(
1
).
play
(
);
}
);
...
...
examples/webgl_shading_physical.html
浏览文件 @
c32f31a5
...
...
@@ -275,7 +275,7 @@
mixer
=
new
THREE
.
AnimationMixer
(
mesh
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
geometry
.
animations
[
0
]
).
warpToDuration
(
10
)
);
mixer
.
clipAction
(
geometry
.
animations
[
0
]
).
setDuration
(
10
).
play
(
);
var
s
=
200
;
mesh
.
scale
.
set
(
s
,
s
,
s
);
...
...
examples/webgl_shadowmap.html
浏览文件 @
c32f31a5
...
...
@@ -64,7 +64,7 @@
var
sceneHUD
,
cameraOrtho
,
hudMesh
;
var
morphs
=
[];
var
m
ixer
,
m
orphs
=
[];
var
light
;
...
...
@@ -306,6 +306,8 @@
// MORPHS
mixer
=
new
THREE
.
AnimationMixer
(
scene
);
function
addMorph
(
geometry
,
speed
,
duration
,
x
,
y
,
z
,
fudgeColor
)
{
var
material
=
new
THREE
.
MeshLambertMaterial
(
{
color
:
0xffaa55
,
morphTargets
:
true
,
vertexColors
:
THREE
.
FaceColors
}
);
...
...
@@ -319,10 +321,13 @@
var
mesh
=
new
THREE
.
Mesh
(
geometry
,
material
);
mesh
.
speed
=
speed
;
var
mixer
=
new
THREE
.
AnimationMixer
(
mesh
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
geometry
.
animations
[
0
]
).
warpToDuration
(
duration
)
);
mixer
.
update
(
600
*
Math
.
random
()
);
mesh
.
mixer
=
mixer
;
var
clip
=
geometry
.
animations
[
0
];
mixer
.
clipAction
(
clip
,
mesh
).
setDuration
(
duration
).
// to shift the playback out of phase:
startAt
(
-
duration
*
Math
.
random
()
).
play
();
mesh
.
position
.
set
(
x
,
y
,
z
);
mesh
.
rotation
.
y
=
Math
.
PI
/
2
;
...
...
@@ -383,12 +388,12 @@
var
delta
=
clock
.
getDelta
();
mixer
.
update
(
delta
);
for
(
var
i
=
0
;
i
<
morphs
.
length
;
i
++
)
{
morph
=
morphs
[
i
];
morph
.
mixer
.
update
(
delta
);
morph
.
position
.
x
+=
morph
.
speed
*
delta
;
if
(
morph
.
position
.
x
>
2000
)
{
...
...
examples/webgl_shadowmap_performance.html
浏览文件 @
c32f31a5
...
...
@@ -54,12 +54,14 @@
var
SCREEN_HEIGHT
=
window
.
innerHeight
;
var
FLOOR
=
-
250
;
var
ANIMATION_GROUPS
=
25
;
var
camera
,
controls
,
scene
,
renderer
;
var
container
,
stats
;
var
NEAR
=
5
,
FAR
=
3000
;
var
morph
,
morphs
=
[],
mixer
;
var
morph
,
morphs
=
[],
mixer
,
animGroups
=
[]
;
var
light
;
...
...
@@ -240,9 +242,16 @@
mixer
=
new
THREE
.
AnimationMixer
(
scene
);
for
(
var
i
=
0
;
i
!==
ANIMATION_GROUPS
;
++
i
)
{
var
group
=
new
THREE
.
AnimationObjectGroup
();
animGroups
.
push
(
new
THREE
.
AnimationObjectGroup
()
);
}
// MORPHS
function
addMorph
(
geometry
,
speed
,
duration
,
x
,
y
,
z
,
fudgeColor
)
{
function
addMorph
(
geometry
,
speed
,
duration
,
x
,
y
,
z
,
fudgeColor
,
massOptimization
)
{
var
material
=
new
THREE
.
MeshLambertMaterial
(
{
color
:
0xffaa55
,
morphTargets
:
true
,
vertexColors
:
THREE
.
FaceColors
}
);
...
...
@@ -255,7 +264,35 @@
var
mesh
=
new
THREE
.
Mesh
(
geometry
,
material
);
mesh
.
speed
=
speed
;
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
geometry
.
animations
[
0
],
Math
.
random
()
).
warpToDuration
(
duration
).
setLocalRoot
(
mesh
)
);
var
clip
=
geometry
.
animations
[
0
];
if
(
massOptimization
)
{
var
index
=
Math
.
floor
(
Math
.
random
()
*
ANIMATION_GROUPS
),
animGroup
=
animGroups
[
index
];
animGroup
.
add
(
mesh
);
if
(
!
mixer
.
existingAction
(
clip
,
animGroup
)
)
{
var
randomness
=
0.6
*
Math
.
random
()
-
0.3
;
var
phase
=
(
index
+
randomness
)
/
ANIMATION_GROUPS
;
mixer
.
clipAction
(
clip
,
animGroup
).
setDuration
(
duration
).
startAt
(
-
duration
*
phase
).
play
();
}
}
else
{
mixer
.
clipAction
(
clip
,
mesh
).
setDuration
(
duration
).
startAt
(
-
duration
*
Math
.
random
()
).
play
();
}
mesh
.
position
.
set
(
x
,
y
,
z
);
mesh
.
rotation
.
y
=
Math
.
PI
/
2
;
...
...
@@ -275,7 +312,7 @@
for
(
var
i
=
-
600
;
i
<
601
;
i
+=
2
)
{
addMorph
(
geometry
,
550
,
1
,
100
-
Math
.
random
()
*
3000
,
FLOOR
,
i
,
true
);
addMorph
(
geometry
,
550
,
1
,
100
-
Math
.
random
()
*
3000
,
FLOOR
,
i
,
true
,
true
);
}
...
...
@@ -342,7 +379,7 @@
var
delta
=
clock
.
getDelta
();
if
(
mixer
)
mixer
.
update
(
delta
);
if
(
mixer
)
mixer
.
update
(
delta
);
for
(
var
i
=
0
;
i
<
morphs
.
length
;
i
++
)
{
...
...
examples/webgl_skinning_simple.html
浏览文件 @
c32f31a5
...
...
@@ -76,7 +76,7 @@
scene
.
add
(
skinnedMesh
);
mixer
=
new
THREE
.
AnimationMixer
(
skinnedMesh
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
skinnedMesh
.
geometry
.
animations
[
0
]
)
);
mixer
.
clipAction
(
skinnedMesh
.
geometry
.
animations
[
0
]
).
play
();
});
...
...
examples/webgl_terrain_dynamic.html
浏览文件 @
c32f31a5
...
...
@@ -502,7 +502,7 @@
mesh
.
speed
=
speed
;
var
mixer
=
new
THREE
.
AnimationMixer
(
mesh
);
mixer
.
addAction
(
new
THREE
.
AnimationAction
(
geometry
.
animations
[
0
]
).
warpToDuration
(
duration
)
);
mixer
.
clipAction
(
geometry
.
animations
[
0
]
).
setDuration
(
duration
).
play
(
);
mixer
.
update
(
600
*
Math
.
random
()
);
mesh
.
mixer
=
mixer
;
...
...
src/animation/AnimationAction.js
已删除
100644 → 0
浏览文件 @
6db066d9
/**
*
* Runnable instance of an AnimationClip.
*
* Multiple Actions are required to add the same clip with the (same or
* different) mixer(s) simultaneously.
*
*
* @author Ben Houston / http://clara.io/
* @author David Sarno / http://lighthaus.us/
*/
THREE
.
AnimationAction
=
function
(
clip
,
startTime
,
timeScale
,
weight
,
loop
)
{
if
(
clip
===
undefined
)
throw
new
Error
(
'
clip is null
'
);
this
.
name
=
''
;
this
.
clip
=
clip
;
this
.
localRoot
=
null
;
this
.
startTime
=
startTime
||
0
;
this
.
timeScale
=
timeScale
||
1
;
this
.
weight
=
weight
||
1
;
this
.
loop
=
loop
||
THREE
.
LoopRepeat
;
this
.
loopCount
=
0
;
this
.
enabled
=
true
;
// allow for easy disabling of the action.
this
.
actionTime
=
-
this
.
startTime
;
this
.
clipTime
=
0
;
this
.
mixer
=
null
;
var
tracks
=
clip
.
tracks
,
nTracks
=
tracks
.
length
,
interpolants
=
new
Array
(
nTracks
);
for
(
var
i
=
0
;
i
!==
nTracks
;
++
i
)
{
interpolants
[
i
]
=
tracks
[
i
].
createInterpolant
(
null
);
}
this
.
_interpolants
=
interpolants
;
this
.
_propertyBindings
=
new
Array
(
nTracks
);
this
.
_prevRootUuid
=
''
;
this
.
_prevMixerUuid
=
''
;
};
/*
THREE.LoopOnce = 2200;
THREE.LoopRepeat = 2201;
THREE.LoopPingPing = 2202;
*/
THREE
.
AnimationAction
.
prototype
=
{
constructor
:
THREE
.
AnimationAction
,
getName
:
function
()
{
return
this
.
name
||
this
.
clip
.
name
;
},
setLocalRoot
:
function
(
localRoot
)
{
this
.
localRoot
=
localRoot
;
return
this
;
},
updateTime
:
function
(
clipDeltaTime
)
{
var
previousClipTime
=
this
.
clipTime
;
var
previousLoopCount
=
this
.
loopCount
;
var
previousActionTime
=
this
.
actionTime
;
var
duration
=
this
.
clip
.
duration
;
this
.
actionTime
=
this
.
actionTime
+
clipDeltaTime
;
if
(
this
.
loop
===
THREE
.
LoopOnce
)
{
this
.
loopCount
=
0
;
this
.
clipTime
=
Math
.
min
(
Math
.
max
(
this
.
actionTime
,
0
),
duration
);
// if time is changed since last time, see if we have hit a start/end limit
if
(
this
.
clipTime
!==
previousClipTime
)
{
if
(
this
.
clipTime
===
duration
)
{
this
.
mixer
.
dispatchEvent
(
{
type
:
'
finished
'
,
action
:
this
,
direction
:
1
}
);
}
else
if
(
this
.
clipTime
===
0
)
{
this
.
mixer
.
dispatchEvent
(
{
type
:
'
finished
'
,
action
:
this
,
direction
:
-
1
}
);
}
}
return
this
.
clipTime
;
}
this
.
loopCount
=
Math
.
floor
(
this
.
actionTime
/
duration
);
var
newClipTime
=
this
.
actionTime
-
this
.
loopCount
*
duration
;
newClipTime
=
newClipTime
%
duration
;
// if we are ping pong looping, ensure that we go backwards when appropriate
if
(
this
.
loop
==
THREE
.
LoopPingPong
)
{
if
(
Math
.
abs
(
this
.
loopCount
%
2
)
===
1
)
{
newClipTime
=
duration
-
newClipTime
;
}
}
this
.
clipTime
=
newClipTime
;
if
(
this
.
loopCount
!==
previousLoopCount
)
{
this
.
mixer
.
dispatchEvent
(
{
type
:
'
loop
'
,
action
:
this
,
loopDelta
:
(
this
.
loopCount
-
this
.
loopCount
)
}
);
}
return
this
.
clipTime
;
},
syncWith
:
function
(
action
)
{
this
.
actionTime
=
action
.
actionTime
;
this
.
timeScale
=
action
.
timeScale
;
return
this
;
},
warpToDuration
:
function
(
duration
)
{
this
.
timeScale
=
this
.
clip
.
duration
/
duration
;
return
this
;
},
init
:
function
(
time
)
{
this
.
clipTime
=
time
-
this
.
startTime
;
return
this
;
},
// pass in time, not clip time, allows for fadein/fadeout across multiple loops of the clip
getTimeScaleAt
:
function
(
time
)
{
var
timeScale
=
this
.
timeScale
;
if
(
timeScale
.
evaluate
!==
undefined
)
{
return
timeScale
.
evaluate
(
time
)[
0
];
}
return
timeScale
;
},
// pass in time, not clip time, allows for fadein/fadeout across multiple loops of the clip
getWeightAt
:
function
(
time
)
{
var
weight
=
this
.
weight
;
if
(
weight
.
evaluate
!==
undefined
)
{
return
weight
.
evaluate
(
time
)[
0
];
}
return
weight
;
}
};
src/animation/AnimationClip.js
浏览文件 @
c32f31a5
...
...
@@ -8,7 +8,7 @@
THREE
.
AnimationClip
=
function
(
name
,
duration
,
tracks
)
{
this
.
name
=
name
;
this
.
name
=
name
||
THREE
.
Math
.
generateUUID
()
;
this
.
tracks
=
tracks
;
this
.
duration
=
(
duration
!==
undefined
)
?
duration
:
-
1
;
...
...
src/animation/AnimationMixer.js
浏览文件 @
c32f31a5
此差异已折叠。
点击以展开。
src/animation/AnimationObjectGroup.js
0 → 100644
浏览文件 @
c32f31a5
/**
*
* A group of objects that receives a shared animation state.
*
* Usage:
*
* - Add objects you would otherwise pass as 'root' to the
* constructor or the .clipAction method of AnimationMixer.
*
* - Instead pass this object as 'root'.
*
* - You can also add and remove objects later when the mixer
* is running.
*
* Note:
*
* Objects of this class appear as one object to the mixer,
* so cache control of the individual objects must be done
* on the group.
*
* Limitation:
*
* - The animated properties must be compatible among the
* all objects in the group.
*
* - A single property can either be controlled through a
* target group or directly, but not both.
*
* @author tschw
*/
THREE
.
AnimationObjectGroup
=
function
(
var_args
)
{
this
.
uuid
=
THREE
.
Math
.
generateUUID
();
// cached objects followed by the active ones
this
.
_objects
=
Array
.
prototype
.
slice
.
call
(
arguments
);
this
.
nCachedObjects_
=
0
;
// threshold
// note: read by PropertyBinding.Composite
var
indices
=
{};
this
.
_indicesByUUID
=
indices
;
// for bookkeeping
for
(
var
i
=
0
,
n
=
arguments
.
length
;
i
!==
n
;
++
i
)
{
indices
[
arguments
[
i
].
uuid
]
=
i
;
}
this
.
_paths
=
[];
// inside: string
this
.
_parsedPaths
=
[];
// inside: { we don't care, here }
this
.
_bindings
=
[];
// inside: Array< PropertyBinding >
this
.
_bindingsIndicesByPath
=
{};
// inside: indices in these arrays
var
scope
=
this
;
this
.
stats
=
{
objects
:
{
get
total
()
{
return
scope
.
_objects
.
length
;
},
get
inUse
()
{
return
this
.
total
-
scope
.
nCachedObjects_
;
}
},
get
bindingsPerObject
()
{
return
scope
.
_bindings
.
length
;
}
};
};
THREE
.
AnimationObjectGroup
.
prototype
=
{
constructor
:
THREE
.
AnimationObjectGroup
,
add
:
function
(
var_args
)
{
var
objects
=
this
.
_objects
,
nObjects
=
objects
.
length
,
nCachedObjects
=
this
.
nCachedObjects_
,
indicesByUUID
=
this
.
_indicesByUUID
,
paths
=
this
.
_paths
,
parsedPaths
=
this
.
_parsedPaths
,
bindings
=
this
.
_bindings
,
nBindings
=
bindings
.
length
;
for
(
var
i
=
0
,
n
=
arguments
.
length
;
i
!==
n
;
++
i
)
{
var
object
=
arguments
[
i
],
uuid
=
object
.
uuid
,
index
=
indicesByUUID
[
uuid
];
if
(
index
===
undefined
)
{
// unknown object -> add it to the ACTIVE region
index
=
nObjects
++
;
indicesByUUID
[
uuid
]
=
index
;
objects
.
push
(
object
);
// accounting is done, now do the same for all bindings
for
(
var
j
=
0
,
m
=
nBindings
;
j
!==
m
;
++
j
)
{
bindings
[
j
].
push
(
new
THREE
.
PropertyBinding
(
object
,
paths
[
j
],
parsedPaths
[
j
]
)
);
}
}
else
if
(
index
<
nCachedObjects
)
{
var
knownObject
=
objects
[
index
];
// move existing object to the ACTIVE region
var
firstActiveIndex
=
--
nCachedObjects
,
lastCachedObject
=
objects
[
firstActiveIndex
];
indicesByUUID
[
lastCachedObject
.
uuid
]
=
index
;
objects
[
index
]
=
lastCachedObject
;
indicesByUUID
[
uuid
]
=
firstActiveIndex
;
objects
[
firstActiveIndex
]
=
object
;
// accounting is done, now do the same for all bindings
for
(
var
j
=
0
,
m
=
nBindings
;
j
!==
m
;
++
j
)
{
var
bindingsForPath
=
bindings
[
j
],
lastCached
=
bindingsForPath
[
firstActiveIndex
],
binding
=
bindingsForPath
[
index
];
bindingsForPath
[
index
]
=
lastCached
;
if
(
binding
===
undefined
)
{
// since we do not bother to create new bindings
// for objects that are cached, the binding may
// or may not exist
binding
=
new
THREE
.
PropertyBinding
(
object
,
paths
[
j
],
parsedPaths
[
j
]
);
}
bindingsForPath
[
firstActiveIndex
]
=
binding
;
}
}
else
if
(
objects
[
index
]
!==
knownObject
)
{
console
.
error
(
"
Different objects with the same UUID
"
+
"
detected. Clean the caches or recreate your
"
+
"
infrastructure when reloading scenes...
"
);
}
// else the object is already where we want it to be
}
// for arguments
this
.
nCachedObjects_
=
nCachedObjects
;
},
remove
:
function
(
var_args
)
{
var
objects
=
this
.
_objects
,
nObjects
=
objects
.
length
,
nCachedObjects
=
this
.
nCachedObjects_
,
indicesByUUID
=
this
.
_indicesByUUID
,
bindings
=
this
.
_bindings
,
nBindings
=
bindings
.
length
;
for
(
var
i
=
0
,
n
=
arguments
.
length
;
i
!==
n
;
++
i
)
{
var
object
=
arguments
[
i
],
uuid
=
object
.
uuid
,
index
=
indicesByUUID
[
uuid
];
if
(
index
!==
undefined
&&
index
>=
nCachedObjects
)
{
// move existing object into the CACHED region
var
lastCachedIndex
=
nCachedObjects
++
,
firstActiveObject
=
objects
[
lastCachedIndex
];
indicesByUUID
[
firstActiveObject
.
uuid
]
=
index
;
objects
[
index
]
=
firstActiveObject
;
indicesByUUID
[
uuid
]
=
lastCachedIndex
;
objects
[
lastCachedIndex
]
=
object
;
// accounting is done, now do the same for all bindings
for
(
var
j
=
0
,
m
=
nBindings
;
j
!==
m
;
++
j
)
{
var
bindingsForPath
=
bindings
[
j
],
firstActive
=
bindingsForPath
[
lastCachedIndex
],
binding
=
bindingsForPath
[
index
];
bindingsForPath
[
index
]
=
firstActive
;
bindingsForPath
[
lastCachedIndex
]
=
binding
;
}
}
}
// for arguments
this
.
nCachedObjects_
=
nCachedObjects
;
},
// remove & forget
uncache
:
function
(
var_args
)
{
var
objects
=
this
.
_objects
,
nObjects
=
objects
.
length
,
nCachedObjects
=
this
.
nCachedObjects_
,
indicesByUUID
=
this
.
_indicesByUUID
,
bindings
=
this
.
_bindings
,
nBindings
=
bindings
.
length
;
for
(
var
i
=
0
,
n
=
arguments
.
length
;
i
!==
n
;
++
i
)
{
var
object
=
arguments
[
i
],
uuid
=
object
.
uuid
,
index
=
indicesByUUID
[
uuid
];
if
(
index
!==
undefined
)
{
delete
indicesByUUID
[
uuid
];
if
(
index
<
nCachedObjects
)
{
// object is cached, shrink the CACHED region
var
firstActiveIndex
=
--
nCachedObjects
,
lastCachedObject
=
objects
[
firstActiveIndex
],
lastIndex
=
--
nObjects
,
lastObject
=
objects
[
lastIndex
];
// last cached object takes this object's place
indicesByUUID
[
lastCachedObject
.
uuid
]
=
index
;
objects
[
index
]
=
lastCachedObject
;
// last object goes to the activated slot and pop
indicesByUUID
[
lastObject
.
uuid
]
=
firstActiveIndex
;
objects
[
firstActiveIndex
]
=
lastObject
;
objects
.
pop
();
// accounting is done, now do the same for all bindings
for
(
var
j
=
0
,
m
=
nBindings
;
j
!==
m
;
++
j
)
{
var
bindingsForPath
=
bindings
[
j
],
lastCached
=
bindingsForPath
[
firstActiveIndex
],
last
=
bindingsForPath
[
lastIndex
];
bindingsForPath
[
index
]
=
lastCached
;
bindingsForPath
[
firstActiveIndex
]
=
last
;
bindingsForPath
.
pop
();
}
}
else
{
// object is active, just swap with the last and pop
var
lastIndex
=
--
nObjects
,
lastObject
=
objects
[
lastIndex
];
indicesByUUID
[
lastObject
.
uuid
]
=
index
;
objects
[
index
]
=
lastObject
;
objects
.
pop
();
// accounting is done, now do the same for all bindings
for
(
var
j
=
0
,
m
=
nBindings
;
j
!==
m
;
++
j
)
{
var
bindingsForPath
=
bindings
[
j
];
bindingsForPath
[
index
]
=
bindingsForPath
[
lastIndex
];
bindingsForPath
.
pop
();
}
}
// cached or active
}
// if object is known
}
// for arguments
this
.
nCachedObjects_
=
nCachedObjects
;
},
// Internal interface used by befriended PropertyBinding.Composite:
subscribe_
:
function
(
path
,
parsedPath
)
{
// returns an array of bindings for the given path that is changed
// according to the contained objects in the group
var
indicesByPath
=
this
.
_bindingsIndicesByPath
,
index
=
indicesByPath
[
path
],
bindings
=
this
.
_bindings
;
if
(
index
!==
undefined
)
return
bindings
[
index
];
var
paths
=
this
.
_paths
,
parsedPaths
=
this
.
_parsedPaths
,
objects
=
this
.
_objects
,
nObjects
=
objects
.
length
,
nCachedObjects
=
this
.
nCachedObjects_
,
bindingsForPath
=
new
Array
(
nObjects
);
index
=
bindings
.
length
;
indicesByPath
[
path
]
=
index
;
paths
.
push
(
path
);
parsedPaths
.
push
(
parsedPath
);
bindings
.
push
(
bindingsForPath
);
for
(
var
i
=
nCachedObjects
,
n
=
objects
.
length
;
i
!==
n
;
++
i
)
{
var
object
=
objects
[
i
];
bindingsForPath
[
i
]
=
new
THREE
.
PropertyBinding
(
object
,
path
,
parsedPath
);
}
return
bindingsForPath
;
},
unsubscribe_
:
function
(
path
)
{
// tells the group to forget about a property path and no longer
// update the array previously obtained with 'subscribe_'
var
indicesByPath
=
this
.
_bindingsIndicesByPath
,
index
=
indicesByPath
[
path
];
if
(
index
!==
undefined
)
{
var
paths
=
this
.
_paths
,
parsedPaths
=
this
.
_parsedPaths
,
bindings
=
this
.
_bindings
,
lastBindingsIndex
=
bindings
.
length
-
1
,
lastBindings
=
bindings
[
lastBindingsIndex
],
lastBindingsPath
=
path
[
lastBindingsIndex
];
indicesByPath
[
lastBindingsPath
]
=
index
;
bindings
[
index
]
=
lastBindings
;
bindings
.
pop
();
parsedPaths
[
index
]
=
parsedPaths
[
lastBindingsIndex
];
parsedPaths
.
pop
();
paths
[
index
]
=
paths
[
lastBindingsIndex
];
paths
.
pop
();
}
}
};
src/animation/AnimationUtils.js
浏览文件 @
c32f31a5
...
...
@@ -99,8 +99,7 @@ THREE.AnimationUtils = {
var
value
=
key
[
valuePropertyName
];
if
(
value
===
undefined
)
return
;
// no data
if
(
value
[
'
splice
'
]
!==
undefined
)
{
// ...assume array
if
(
Array
.
isArray
(
value
)
)
{
do
{
...
...
src/animation/KeyframeTrack.js
浏览文件 @
c32f31a5
...
...
@@ -34,8 +34,8 @@ THREE.KeyframeTrack.prototype = {
constructor
:
THREE
.
KeyframeTrack
,
TimeBufferType
:
Float
64
Array
,
ValueBufferType
:
Float
64
Array
,
TimeBufferType
:
Float
32
Array
,
ValueBufferType
:
Float
32
Array
,
DefaultInterpolation
:
THREE
.
InterpolateLinear
,
...
...
@@ -250,7 +250,7 @@ THREE.KeyframeTrack.prototype = {
var
currTime
=
times
[
i
];
if
(
Number
.
isNaN
(
currTime
)
)
{
if
(
typeof
currTime
===
'
number
'
&&
isNaN
(
currTime
)
)
{
console
.
error
(
"
time is not a valid number
"
,
this
,
i
,
currTime
);
valid
=
false
;
...
...
@@ -278,7 +278,7 @@ THREE.KeyframeTrack.prototype = {
var
value
=
values
[
i
];
if
(
Number
.
isNaN
(
value
)
)
{
if
(
isNaN
(
value
)
)
{
console
.
error
(
"
value is not a valid number
"
,
this
,
i
,
value
);
valid
=
false
;
...
...
@@ -392,7 +392,7 @@ Object.assign( THREE.KeyframeTrack, {
}
var
trackType
=
THREE
.
KeyframeTrack
.
G
etTrackTypeForValueTypeName
(
json
.
type
);
var
trackType
=
THREE
.
KeyframeTrack
.
_g
etTrackTypeForValueTypeName
(
json
.
type
);
if
(
json
[
'
times
'
]
===
undefined
)
{
...
...
@@ -460,7 +460,7 @@ Object.assign( THREE.KeyframeTrack, {
},
G
etTrackTypeForValueTypeName
:
function
(
typeName
)
{
_g
etTrackTypeForValueTypeName
:
function
(
typeName
)
{
switch
(
typeName
.
toLowerCase
()
)
{
...
...
src/animation/PropertyBinding.js
浏览文件 @
c32f31a5
...
...
@@ -8,21 +8,16 @@
* @author tschw
*/
THREE
.
PropertyBinding
=
function
(
rootNode
,
path
)
{
THREE
.
PropertyBinding
=
function
(
rootNode
,
path
,
parsedPath
)
{
this
.
rootNode
=
rootNode
;
this
.
path
=
path
;
this
.
parsedPath
=
parsedPath
||
THREE
.
PropertyBinding
.
parseTrackName
(
path
);
var
parseResults
=
THREE
.
PropertyBinding
.
parseTrackName
(
path
);
this
.
directoryName
=
parseResults
.
directoryName
;
this
.
nodeName
=
parseResults
.
nodeName
;
this
.
objectName
=
parseResults
.
objectName
;
this
.
objectIndex
=
parseResults
.
objectIndex
;
this
.
propertyName
=
parseResults
.
propertyName
;
this
.
propertyIndex
=
parseResults
.
propertyIndex
;
this
.
node
=
THREE
.
PropertyBinding
.
findNode
(
rootNode
,
this
.
parsedPath
.
nodeName
)
||
rootNode
;
this
.
setRootNode
(
rootNode
)
;
this
.
rootNode
=
rootNode
;
};
...
...
@@ -50,31 +45,20 @@ THREE.PropertyBinding.prototype = {
},
// change the root used for binding
setRootNode
:
function
(
rootNode
)
{
var
oldNode
=
this
.
node
,
newNode
=
THREE
.
PropertyBinding
.
findNode
(
rootNode
,
this
.
nodeName
)
||
rootNode
;
if
(
oldNode
&&
oldNode
!==
newNode
)
{
this
.
unbind
();
// for the change to take effect on the next call
}
this
.
rootNode
=
rootNode
;
this
.
node
=
newNode
;
},
// create getter / setter pair for a property in the scene graph
bind
:
function
()
{
var
targetObject
=
this
.
node
;
var
targetObject
=
this
.
node
,
parsedPath
=
this
.
parsedPath
,
objectName
=
parsedPath
.
objectName
,
propertyName
=
parsedPath
.
propertyName
,
propertyIndex
=
parsedPath
.
propertyIndex
;
if
(
!
targetObject
)
{
targetObject
=
THREE
.
PropertyBinding
.
findNode
(
this
.
rootNode
,
this
.
nodeName
)
||
this
.
rootNode
;
targetObject
=
THREE
.
PropertyBinding
.
findNode
(
this
.
rootNode
,
parsedPath
.
nodeName
)
||
this
.
rootNode
;
this
.
node
=
targetObject
;
...
...
@@ -85,262 +69,403 @@ THREE.PropertyBinding.prototype = {
this
.
setValue
=
this
.
_setValue_unavailable
;
// ensure there is a value node
if
(
!
targetObject
)
{
if
(
!
targetObject
)
{
console
.
error
(
"
trying to update node for track:
"
+
this
.
path
+
"
but it wasn't found.
"
);
return
;
}
if
(
this
.
objectName
)
{
// special case were we need to reach deeper into the hierarchy to get the face materials....
if
(
this
.
objectName
===
"
materials
"
)
{
if
(
!
targetObject
.
material
)
{
console
.
error
(
'
can not bind to material as node does not have a material
'
,
this
);
return
;
}
if
(
!
targetObject
.
material
.
materials
)
{
console
.
error
(
'
can not bind to material.materials as node.material does not have a materials array
'
,
this
);
return
;
}
targetObject
=
targetObject
.
material
.
materials
;
}
else
if
(
this
.
objectName
===
"
bones
"
)
{
if
(
!
targetObject
.
skeleton
)
{
console
.
error
(
'
can not bind to bones as node does not have a skeleton
'
,
this
);
return
;
}
// potential future optimization: skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
if
(
objectName
)
{
targetObject
=
targetObject
.
skeleton
.
bones
;
var
objectIndex
=
parsedPath
.
objectIndex
;
// special cases were we need to reach deeper into the hierarchy to get the face materials....
switch
(
objectName
)
{
case
'
materials
'
:
if
(
!
targetObject
.
material
)
{
console
.
error
(
'
can not bind to material as node does not have a material
'
,
this
);
return
;
// support resolving morphTarget names into indices.
for
(
var
i
=
0
;
i
<
targetObject
.
length
;
i
++
)
{
if
(
targetObject
[
i
].
name
===
this
.
objectIndex
)
{
this
.
objectIndex
=
i
;
break
;
}
}
}
else
{
if
(
targetObject
[
this
.
objectName
]
===
undefined
)
{
console
.
error
(
'
can not bind to objectName of node, undefined
'
,
this
);
return
;
}
targetObject
=
targetObject
[
this
.
objectName
];
if
(
!
targetObject
.
material
.
materials
)
{
console
.
error
(
'
can not bind to material.materials as node.material does not have a materials array
'
,
this
);
return
;
}
targetObject
=
targetObject
.
material
.
materials
;
break
;
case
'
bones
'
:
if
(
!
targetObject
.
skeleton
)
{
console
.
error
(
'
can not bind to bones as node does not have a skeleton
'
,
this
);
return
;
}
// potential future optimization: skip this if propertyIndex is already an integer
// and convert the integer string to a true integer.
targetObject
=
targetObject
.
skeleton
.
bones
;
// support resolving morphTarget names into indices.
for
(
var
i
=
0
;
i
<
targetObject
.
length
;
i
++
)
{
if
(
targetObject
[
i
].
name
===
objectIndex
)
{
objectIndex
=
i
;
break
;
}
}
break
;
default
:
if
(
targetObject
[
objectName
]
===
undefined
)
{
console
.
error
(
'
can not bind to objectName of node, undefined
'
,
this
);
return
;
}
targetObject
=
targetObject
[
objectName
];
}
if
(
this
.
objectIndex
!==
undefined
)
{
if
(
targetObject
[
this
.
objectIndex
]
===
undefined
)
{
if
(
objectIndex
!==
undefined
)
{
if
(
targetObject
[
objectIndex
]
===
undefined
)
{
console
.
error
(
"
trying to bind to objectIndex of objectName, but is undefined:
"
,
this
,
targetObject
);
return
;
}
targetObject
=
targetObject
[
this
.
objectIndex
];
targetObject
=
targetObject
[
objectIndex
];
}
}
// special case mappings
var
nodeProperty
=
targetObject
[
this
.
propertyName
];
if
(
!
nodeProperty
)
{
console
.
error
(
"
trying to update property for track:
"
+
this
.
nodeName
+
'
.
'
+
this
.
propertyName
+
"
but it wasn't found.
"
,
targetObject
);
// resolve property
var
nodeProperty
=
targetObject
[
propertyName
];
if
(
!
nodeProperty
)
{
var
nodeName
=
parsedPath
.
nodeName
;
console
.
error
(
"
trying to update property for track:
"
+
nodeName
+
'
.
'
+
propertyName
+
"
but it wasn't found.
"
,
targetObject
);
return
;
}
// determine versioning scheme
var
versioning
=
0
;
var
NeedsUpdate
=
1
;
var
MatrixWorldNeedsUpdate
=
2
;
var
versioning
=
this
.
Versioning
.
None
;
if
(
targetObject
.
needsUpdate
!==
undefined
)
{
// material
if
(
targetObject
.
needsUpdate
!==
undefined
)
{
// material
versioning
=
NeedsUpdate
;
versioning
=
this
.
Versioning
.
NeedsUpdate
;
this
.
targetObject
=
targetObject
;
}
else
if
(
targetObject
.
matrixWorldNeedsUpdate
!==
undefined
)
{
// node transform
}
else
if
(
targetObject
.
matrixWorldNeedsUpdate
!==
undefined
)
{
// node transform
versioning
=
MatrixWorldNeedsUpdate
;
versioning
=
this
.
Versioning
.
MatrixWorldNeedsUpdate
;
this
.
targetObject
=
targetObject
;
}
// access a sub element of the property array (only primitives are supported right now)
if
(
this
.
propertyIndex
!==
undefined
)
{
// determine how the property gets bound
var
bindingType
=
this
.
BindingType
.
Direct
;
if
(
propertyIndex
!==
undefined
)
{
// access a sub element of the property array (only primitives are supported right now)
if
(
this
.
propertyName
===
"
morphTargetInfluences
"
)
{
if
(
propertyName
===
"
morphTargetInfluences
"
)
{
// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
// support resolving morphTarget names into indices.
if
(
!
targetObject
.
geometry
)
{
if
(
!
targetObject
.
geometry
)
{
console
.
error
(
'
can not bind to morphTargetInfluences becasuse node does not have a geometry
'
,
this
);
return
;
}
if
(
!
targetObject
.
geometry
.
morphTargets
)
{
if
(
!
targetObject
.
geometry
.
morphTargets
)
{
console
.
error
(
'
can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets
'
,
this
);
return
;
}
for
(
var
i
=
0
;
i
<
this
.
node
.
geometry
.
morphTargets
.
length
;
i
++
)
{
if
(
targetObject
.
geometry
.
morphTargets
[
i
].
name
===
this
.
propertyIndex
)
{
this
.
propertyIndex
=
i
;
for
(
var
i
=
0
;
i
<
this
.
node
.
geometry
.
morphTargets
.
length
;
i
++
)
{
if
(
targetObject
.
geometry
.
morphTargets
[
i
].
name
===
propertyIndex
)
{
propertyIndex
=
i
;
break
;
}
}
}
var
propertyIndex
=
this
.
propertyIndex
;
bindingType
=
this
.
BindingType
.
ArrayElement
;
this
.
getValue
=
function
getValue_propertyIndexed
(
buffer
,
offset
)
{
this
.
resolvedProperty
=
nodeProperty
;
this
.
propertyIndex
=
propertyIndex
;
buffer
[
offset
]
=
nodeProperty
[
this
.
propertyIndex
];
}
else
if
(
nodeProperty
.
fromArray
!==
undefined
&&
nodeProperty
.
toArray
!==
undefined
)
{
// must use copy for Object3D.Euler/Quaternion
}
;
bindingType
=
this
.
BindingType
.
HasFromToArray
;
switch
(
versioning
)
{
this
.
resolvedProperty
=
nodeProperty
;
case
NeedsUpdate
:
}
else
{
this
.
setValue
=
function
setValue_propertyIndexed
(
buffer
,
offset
)
{
this
.
propertyName
=
propertyName
;
nodeProperty
[
propertyIndex
]
=
buffer
[
offset
];
targetObject
.
needsUpdate
=
true
;
}
};
// select getter / setter
this
.
getValue
=
this
.
GetterByBindingType
[
bindingType
];
this
.
setValue
=
this
.
SetterByBindingTypeAndVersioning
[
bindingType
][
versioning
];
break
;
},
case
MatrixWorldNeedsUpdate
:
unbind
:
function
()
{
this
.
setValue
=
function
setValue_propertyIndexed
(
buffer
,
offset
)
{
this
.
node
=
null
;
nodeProperty
[
propertyIndex
]
=
buffer
[
offset
];
targetObject
.
matrixWorldNeedsUpdate
=
true
;
// back to the prototype version of getValue / setValue
// note: avoiding to mutate the shape of 'this' via 'delete'
this
.
getValue
=
this
.
_getValue_unbound
;
this
.
setValue
=
this
.
_setValue_unbound
;
};
}
break
;
}
;
default
:
Object
.
assign
(
THREE
.
PropertyBinding
.
prototype
,
{
// prototype, continued
this
.
setValue
=
function
setValue_propertyIndexed
(
buffer
,
offset
)
{
// these are used to "bind" a nonexistent property
_getValue_unavailable
:
function
()
{},
_setValue_unavailable
:
function
()
{},
nodeProperty
[
propertyIndex
]
=
buffer
[
offset
];
// initial state of these methods that calls 'bind'
_getValue_unbound
:
THREE
.
PropertyBinding
.
prototype
.
getValue
,
_setValue_unbound
:
THREE
.
PropertyBinding
.
prototype
.
setValue
,
};
BindingType
:
{
Direct
:
0
,
ArrayElement
:
1
,
HasFromToArray
:
2
},
}
Versioning
:
{
None
:
0
,
NeedsUpdate
:
1
,
MatrixWorldNeedsUpdate
:
2
},
}
// must use copy for Object3D.Euler/Quaternion
else
if
(
nodeProperty
.
fromArray
!==
undefined
&&
nodeProperty
.
toArray
!==
undefined
)
{
GetterByBindingType
:
[
this
.
getValue
=
function
getValue_propertyObj
ect
(
buffer
,
offset
)
{
function
getValue_dir
ect
(
buffer
,
offset
)
{
nodeProperty
.
toArray
(
buffer
,
offset
)
;
buffer
[
offset
]
=
this
.
node
[
this
.
propertyName
]
;
};
},
function
getValue_arrayElement
(
buffer
,
offset
)
{
switch
(
versioning
)
{
buffer
[
offset
]
=
this
.
resolvedProperty
[
this
.
propertyIndex
];
case
NeedsUpdate
:
},
this
.
setValue
=
function
setValue_propertyObject
(
buffer
,
offset
)
{
function
getValue_toArray
(
buffer
,
offset
)
{
nodeProperty
.
fromArray
(
buffer
,
offset
);
targetObject
.
needsUpdate
=
true
;
this
.
resolvedProperty
.
toArray
(
buffer
,
offset
);
}
}
case
MatrixWorldNeedsUpdate
:
],
this
.
setValue
=
function
setValue_propertyObject
(
buffer
,
offset
)
{
SetterByBindingTypeAndVersioning
:
[
nodeProperty
.
fromArray
(
buffer
,
offset
);
targetObject
.
matrixWorldNeedsUpdate
=
true
;
[
// Direct
}
function
setValue_direct
(
buffer
,
offset
)
{
default
:
this
.
node
[
this
.
propertyName
]
=
buffer
[
offset
];
this
.
setValue
=
function
setValue_propertyObject
(
buffer
,
offset
)
{
},
nodeProperty
.
fromArray
(
buffer
,
offset
);
function
setValue_direct_setNeedsUpdate
(
buffer
,
offset
)
{
}
this
.
node
[
this
.
propertyName
]
=
buffer
[
offset
];
this
.
targetObject
.
needsUpdate
=
true
;
},
function
setValue_direct_setMatrixWorldNeedsUpdate
(
buffer
,
offset
)
{
this
.
node
[
this
.
propertyName
]
=
buffer
[
offset
];
this
.
targetObject
.
matrixWorldNeedsUpdate
=
true
;
}
}
// otherwise just set the property directly on the node (do not use nodeProperty as it may not be a reference object)
else
{
],
[
var
propertyName
=
this
.
propertyName
;
// ArrayElement
this
.
getValue
=
function
getValue_property
(
buffer
,
offset
)
{
function
setValue_arrayElement
(
buffer
,
offset
)
{
buffer
[
offset
]
=
nodeProperty
[
propertyName
];
this
.
resolvedProperty
[
this
.
propertyIndex
]
=
buffer
[
offset
];
}
;
}
,
switch
(
versioning
)
{
function
setValue_arrayElement_setNeedsUpdate
(
buffer
,
offset
)
{
case
NeedsUpdate
:
this
.
resolvedProperty
[
this
.
propertyIndex
]
=
buffer
[
offset
];
this
.
targetObject
.
needsUpdate
=
true
;
this
.
setValue
=
function
setValue_property
(
buffer
,
offset
)
{
},
nodeProperty
[
propertyName
]
=
buffer
[
offset
];
targetObject
.
needsUpdate
=
true
;
function
setValue_arrayElement_setMatrixWorldNeedsUpdate
(
buffer
,
offset
)
{
}
this
.
resolvedProperty
[
this
.
propertyIndex
]
=
buffer
[
offset
];
this
.
targetObject
.
matrixWorldNeedsUpdate
=
true
;
break
;
}
case
MatrixWorldNeedsUpdate
:
],
[
this
.
setValue
=
function
setValue_property
(
buffer
,
offset
)
{
// HasToFromArray
nodeProperty
[
propertyName
]
=
buffer
[
offset
];
targetObject
.
matrixWorldNeedsUpdate
=
true
;
function
setValue_fromArray
(
buffer
,
offset
)
{
}
this
.
resolvedProperty
.
fromArray
(
buffer
,
offset
);
break
;
},
default
:
function
setValue_fromArray_setNeedsUpdate
(
buffer
,
offset
)
{
this
.
setValue
=
function
setValue_property
(
buffer
,
offset
)
{
this
.
resolvedProperty
.
fromArray
(
buffer
,
offset
);
this
.
targetObject
.
needsUpdate
=
true
;
nodeProperty
[
propertyName
]
=
buffer
[
offset
];
},
}
function
setValue_fromArray_setMatrixWorldNeedsUpdate
(
buffer
,
offset
)
{
this
.
resolvedProperty
.
fromArray
(
buffer
,
offset
);
this
.
targetObject
.
matrixWorldNeedsUpdate
=
true
;
}
]
]
}
);
THREE
.
PropertyBinding
.
Composite
=
function
(
targetGroup
,
path
,
optionalParsedPath
)
{
var
parsedPath
=
optionalParsedPath
||
THREE
.
PropertyBinding
.
parseTrackName
(
path
);
this
.
_targetGroup
=
targetGroup
;
this
.
_bindings
=
targetGroup
.
subscribe_
(
path
,
parsedPath
);
};
THREE
.
PropertyBinding
.
Composite
.
prototype
=
{
constructor
:
THREE
.
PropertyBinding
.
Composite
,
getValue
:
function
(
array
,
offset
)
{
this
.
bind
();
// bind all binding
var
firstValidIndex
=
this
.
_targetGroup
.
nCachedObjects_
,
binding
=
this
.
_bindings
[
firstValidIndex
];
// and only call .getValue on the first
if
(
binding
!==
undefined
)
binding
.
getValue
(
array
,
offset
);
},
setValue
:
function
(
array
,
offset
)
{
var
bindings
=
this
.
_bindings
;
for
(
var
i
=
this
.
_targetGroup
.
nCachedObjects_
,
n
=
bindings
.
length
;
i
!==
n
;
++
i
)
{
bindings
[
i
].
setValue
(
array
,
offset
);
}
},
bind
:
function
()
{
var
bindings
=
this
.
_bindings
;
for
(
var
i
=
this
.
_targetGroup
.
nCachedObjects_
,
n
=
bindings
.
length
;
i
!==
n
;
++
i
)
{
bindings
[
i
].
bind
();
}
},
unbind
:
function
()
{
this
.
node
=
null
;
var
bindings
=
this
.
_bindings
;
// back to the prototype version of getValue / setValue
// note: avoiding to mutate the shape of 'this' via 'delete'
this
.
getValue
=
this
.
_getValue_unbound
;
this
.
setValue
=
this
.
_setValue_unbound
;
for
(
var
i
=
this
.
_targetGroup
.
nCachedObjects_
,
n
=
bindings
.
length
;
i
!==
n
;
++
i
)
{
bindings
[
i
].
unbind
();
}
}
};
Object
.
assign
(
THREE
.
PropertyBinding
.
prototype
,
{
THREE
.
PropertyBinding
.
create
=
function
(
root
,
path
,
parsedPath
)
{
// these are used to "bind" a nonexistent property
_getValue_unavailable
:
function
()
{},
_setValue_unavailable
:
function
()
{},
if
(
!
(
root
instanceof
THREE
.
AnimationObjectGroup
)
)
{
// initial state of these methods that calls 'bind'
_getValue_unbound
:
THREE
.
PropertyBinding
.
prototype
.
getValue
,
_setValue_unbound
:
THREE
.
PropertyBinding
.
prototype
.
setValue
return
new
THREE
.
PropertyBinding
(
root
,
path
,
parsedPath
);
}
);
}
else
{
return
new
THREE
.
PropertyBinding
.
Composite
(
root
,
path
,
parsedPath
);
}
};
THREE
.
PropertyBinding
.
parseTrackName
=
function
(
trackName
)
{
...
...
@@ -367,7 +492,7 @@ THREE.PropertyBinding.parseTrackName = function( trackName ) {
}
var
results
=
{
directoryName
:
matches
[
1
],
// directoryName: matches[1], // (tschw) currently unused
nodeName
:
matches
[
3
],
// allowed to be null, specified root node.
objectName
:
matches
[
5
],
objectIndex
:
matches
[
7
],
...
...
@@ -456,4 +581,5 @@ THREE.PropertyBinding.findNode = function( root, nodeName ) {
}
return
null
;
}
src/animation/PropertyMixer.js
浏览文件 @
c32f31a5
...
...
@@ -8,9 +8,9 @@
* @author tschw
*/
THREE
.
PropertyMixer
=
function
(
rootNode
,
path
,
typeName
,
valueSize
)
{
THREE
.
PropertyMixer
=
function
(
binding
,
typeName
,
valueSize
)
{
this
.
binding
=
new
THREE
.
PropertyBinding
(
rootNode
,
path
)
;
this
.
binding
=
binding
;
this
.
valueSize
=
valueSize
;
var
bufferType
=
Float64Array
,
...
...
@@ -45,6 +45,7 @@ THREE.PropertyMixer = function ( rootNode, path, typeName, valueSize ) {
this
.
cumulativeWeight
=
0
;
this
.
useCount
=
0
;
this
.
referenceCount
=
0
;
};
...
...
src/animation/tracks/BooleanKeyframeTrack.js
浏览文件 @
c32f31a5
...
...
@@ -14,7 +14,8 @@ THREE.BooleanKeyframeTrack = function ( name, times, values ) {
};
Object
.
assign
(
THREE
.
BooleanKeyframeTrack
.
prototype
,
THREE
.
KeyframeTrack
.
prototype
,
{
THREE
.
BooleanKeyframeTrack
.
prototype
=
Object
.
assign
(
Object
.
create
(
THREE
.
KeyframeTrack
.
prototype
),
{
constructor
:
THREE
.
BooleanKeyframeTrack
,
...
...
src/animation/tracks/ColorKeyframeTrack.js
浏览文件 @
c32f31a5
...
...
@@ -14,7 +14,8 @@ THREE.ColorKeyframeTrack = function ( name, times, values, interpolation ) {
};
Object
.
assign
(
THREE
.
ColorKeyframeTrack
.
prototype
,
THREE
.
KeyframeTrack
.
prototype
,
{
THREE
.
ColorKeyframeTrack
.
prototype
=
Object
.
assign
(
Object
.
create
(
THREE
.
KeyframeTrack
.
prototype
),
{
constructor
:
THREE
.
ColorKeyframeTrack
,
...
...
src/animation/tracks/NumberKeyframeTrack.js
浏览文件 @
c32f31a5
...
...
@@ -13,7 +13,8 @@ THREE.NumberKeyframeTrack = function ( name, times, values, interpolation ) {
};
Object
.
assign
(
THREE
.
NumberKeyframeTrack
.
prototype
,
THREE
.
KeyframeTrack
.
prototype
,
{
THREE
.
NumberKeyframeTrack
.
prototype
=
Object
.
assign
(
Object
.
create
(
THREE
.
KeyframeTrack
.
prototype
),
{
constructor
:
THREE
.
NumberKeyframeTrack
,
...
...
src/animation/tracks/QuaternionKeyframeTrack.js
浏览文件 @
c32f31a5
...
...
@@ -13,7 +13,8 @@ THREE.QuaternionKeyframeTrack = function ( name, times, values, interpolation )
};
Object
.
assign
(
THREE
.
QuaternionKeyframeTrack
.
prototype
,
THREE
.
KeyframeTrack
.
prototype
,
{
THREE
.
QuaternionKeyframeTrack
.
prototype
=
Object
.
assign
(
Object
.
create
(
THREE
.
KeyframeTrack
.
prototype
),
{
constructor
:
THREE
.
QuaternionKeyframeTrack
,
...
...
src/animation/tracks/StringKeyframeTrack.js
浏览文件 @
c32f31a5
...
...
@@ -14,7 +14,8 @@ THREE.StringKeyframeTrack = function ( name, times, values, interpolation ) {
};
Object
.
assign
(
THREE
.
StringKeyframeTrack
.
prototype
,
THREE
.
KeyframeTrack
.
prototype
,
{
THREE
.
StringKeyframeTrack
.
prototype
=
Object
.
assign
(
Object
.
create
(
THREE
.
KeyframeTrack
.
prototype
),
{
constructor
:
THREE
.
StringKeyframeTrack
,
...
...
src/animation/tracks/VectorKeyframeTrack.js
浏览文件 @
c32f31a5
...
...
@@ -14,7 +14,8 @@ THREE.VectorKeyframeTrack = function ( name, times, values, interpolation ) {
};
Object
.
assign
(
THREE
.
VectorKeyframeTrack
.
prototype
,
THREE
.
KeyframeTrack
.
prototype
,
{
THREE
.
VectorKeyframeTrack
.
prototype
=
Object
.
assign
(
Object
.
create
(
THREE
.
KeyframeTrack
.
prototype
),
{
constructor
:
THREE
.
VectorKeyframeTrack
,
...
...
test/unit/animation/AnimationObjectGroup.js
0 → 100644
浏览文件 @
c32f31a5
/**
* @author tschw
*/
module
(
"
AnimationObjectGroup
"
);
var
ObjectA
=
new
THREE
.
Object3D
(),
ObjectB
=
new
THREE
.
Object3D
(),
ObjectC
=
new
THREE
.
Object3D
(),
PathA
=
'
object.position
'
,
PathB
=
'
object.rotation
'
,
PathC
=
'
object.scale
'
,
ParsedPathA
=
THREE
.
PropertyBinding
.
parseTrackName
(
PathA
),
ParsedPathB
=
THREE
.
PropertyBinding
.
parseTrackName
(
PathB
),
ParsedPathC
=
THREE
.
PropertyBinding
.
parseTrackName
(
PathC
);
test
(
"
smoke test
"
,
function
()
{
var
expect
=
function
expect
(
testIndex
,
group
,
bindings
,
path
,
cached
,
roots
)
{
var
rootNodes
=
[],
pathsOk
=
true
,
nodesOk
=
true
;
for
(
var
i
=
group
.
nCachedObjects_
,
n
=
bindings
.
length
;
i
!==
n
;
++
i
)
{
if
(
bindings
[
i
].
path
!==
path
)
pathsOk
=
false
;
rootNodes
.
push
(
bindings
[
i
].
rootNode
);
}
for
(
var
i
=
0
,
n
=
roots
.
length
;
i
!==
n
;
++
i
)
{
if
(
rootNodes
.
indexOf
(
roots
[
i
]
)
===
-
1
)
nodesOk
=
false
;
}
ok
(
pathsOk
,
testIndex
+
"
paths
"
);
ok
(
nodesOk
,
testIndex
+
"
nodes
"
);
ok
(
group
.
nCachedObjects_
===
cached
,
testIndex
+
"
cache size
"
);
ok
(
bindings
.
length
-
group
.
nCachedObjects_
===
roots
.
length
,
testIndex
+
"
object count
"
);
};
// initial state
var
groupA
=
new
THREE
.
AnimationObjectGroup
();
ok
(
groupA
instanceof
THREE
.
AnimationObjectGroup
,
"
constructor (w/o args)
"
);
var
bindingsAA
=
groupA
.
subscribe_
(
PathA
,
ParsedPathA
);
expect
(
0
,
groupA
,
bindingsAA
,
PathA
,
0
,
[]
);
var
groupB
=
new
THREE
.
AnimationObjectGroup
(
ObjectA
,
ObjectB
);
ok
(
groupB
instanceof
THREE
.
AnimationObjectGroup
,
"
constructor (with args)
"
);
var
bindingsBB
=
groupB
.
subscribe_
(
PathB
,
ParsedPathB
);
expect
(
1
,
groupB
,
bindingsBB
,
PathB
,
0
,
[
ObjectA
,
ObjectB
]
);
// add
groupA
.
add
(
ObjectA
,
ObjectB
);
expect
(
2
,
groupA
,
bindingsAA
,
PathA
,
0
,
[
ObjectA
,
ObjectB
]
);
groupB
.
add
(
ObjectC
);
expect
(
3
,
groupB
,
bindingsBB
,
PathB
,
0
,
[
ObjectA
,
ObjectB
,
ObjectC
]
);
// remove
groupA
.
remove
(
ObjectA
,
ObjectC
);
expect
(
4
,
groupA
,
bindingsAA
,
PathA
,
1
,
[
ObjectB
]
);
groupB
.
remove
(
ObjectA
,
ObjectB
,
ObjectC
);
expect
(
5
,
groupB
,
bindingsBB
,
PathB
,
3
,
[]
);
// subscribe after re-add
groupA
.
add
(
ObjectC
);
expect
(
6
,
groupA
,
bindingsAA
,
PathA
,
1
,
[
ObjectB
,
ObjectC
]
);
var
bindingsAC
=
groupA
.
subscribe_
(
PathC
,
ParsedPathC
);
expect
(
7
,
groupA
,
bindingsAC
,
PathC
,
1
,
[
ObjectB
,
ObjectC
]
);
// re-add after subscribe
var
bindingsBC
=
groupB
.
subscribe_
(
PathC
,
ParsedPathC
);
groupB
.
add
(
ObjectA
,
ObjectB
);
expect
(
8
,
groupB
,
bindingsBB
,
PathB
,
1
,
[
ObjectA
,
ObjectB
]
);
// unsubscribe
var
copyOfBindingsBC
=
bindingsBC
.
slice
();
groupB
.
unsubscribe_
(
PathC
);
groupB
.
add
(
ObjectC
);
deepEqual
(
bindingsBC
,
copyOfBindingsBC
,
"
no more update after unsubscribe
"
);
// uncache active
groupB
.
uncache
(
ObjectA
);
expect
(
9
,
groupB
,
bindingsBB
,
PathB
,
0
,
[
ObjectB
,
ObjectC
]
);
// uncache cached
groupA
.
uncache
(
ObjectA
);
expect
(
10
,
groupA
,
bindingsAC
,
PathC
,
0
,
[
ObjectB
,
ObjectC
]
);
}
);
test/unit/unittests_three.html
浏览文件 @
c32f31a5
...
...
@@ -47,13 +47,16 @@
<script
src=
"math/Frustum.js"
></script>
<script
src=
"math/Interpolant.js"
></script>
<script
src=
"
geometry/EdgesGeometry
.js"
></script>
<script
src=
"extras/ImageUtils.test.js"
></script>
<script
src=
"
animation/AnimationObjectGroup
.js"
></script>
<script
src=
"lights/AmbientLight.tests.js"
></script>
<script
src=
"lights/DirectionalLight.tests.js"
></script>
<script
src=
"lights/HemisphereLight.tests.js"
></script>
<script
src=
"lights/PointLight.tests.js"
></script>
<script
src=
"lights/SpotLight.tests.js"
></script>
<script
src=
"geometry/EdgesGeometry.js"
></script>
<script
src=
"extras/ImageUtils.test.js"
></script>
<script
src=
"extras/geometries/BoxGeometry.tests.js"
></script>
<script
src=
"extras/geometries/CircleBufferGeometry.tests.js"
></script>
...
...
utils/build/includes/common.json
浏览文件 @
c32f31a5
...
...
@@ -39,9 +39,9 @@
"src/core/DirectGeometry.js"
,
"src/core/BufferGeometry.js"
,
"src/core/InstancedBufferGeometry.js"
,
"src/animation/AnimationAction.js"
,
"src/animation/AnimationClip.js"
,
"src/animation/AnimationMixer.js"
,
"src/animation/AnimationObjectGroup.js"
,
"src/animation/AnimationUtils.js"
,
"src/animation/KeyframeTrack.js"
,
"src/animation/PropertyBinding.js"
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录