Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
fyge_for_tb
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
王剑峰
fyge_for_tb
Commits
01a093d8
Commit
01a093d8
authored
Oct 05, 2020
by
wjf
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
l
parent
0cc8f760
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1745 additions
and
206 deletions
+1745
-206
Container.ts
src/2d/display/Container.ts
+7
-0
Rectangle.ts
src/2d/math/Rectangle.ts
+2
-2
BezierEaser.ts
src/2d/ui/forLottie/BezierEaser.ts
+154
-0
Lottie.ts
src/2d/ui/forLottie/Lottie.ts
+1070
-0
buildBezierProps.ts
src/2d/ui/forLottie/buildBezierProps.ts
+99
-0
Geometry.ts
src/3D/Geometry.ts
+2
-2
GLTFCubicSplineInterpolant.ts
src/3D/gltf/GLTFCubicSplineInterpolant.ts
+71
-0
GLTFLoader.ts
src/3D/gltf/GLTFLoader.ts
+120
-202
Interpolant.ts
src/3D/gltf/Interpolant.ts
+220
-0
No files found.
src/2d/display/Container.ts
View file @
01a093d8
...
...
@@ -271,6 +271,13 @@ export default class Container extends DisplayObject {
children
.
forEach
((
child
:
T
)
=>
{
this
.
removeChild
(
child
);
})
return
children
}
/**
* 移除所有子级
* @returns 返回移除的子级的数组
*/
removeAllChildren
<
T
extends
DisplayObject
>
():
T
[]
{
return
this
.
removeChildren
()
}
/**
* 通过索引批量移除child
* @param {number} [beginIndex=0]
...
...
src/2d/math/Rectangle.ts
View file @
01a093d8
...
...
@@ -190,10 +190,10 @@ export class Rectangle extends HashObject {
hy1
=
y
+
h
;
wx2
=
arg
[
i
].
x
+
arg
[
i
].
width
;
hy2
=
arg
[
i
].
y
+
arg
[
i
].
height
;
if
(
x
>
arg
[
i
].
x
||
wx1
==
0
)
{
if
(
x
>
arg
[
i
].
x
/*|| wx1 == 0*/
)
{
x
=
arg
[
i
].
x
;
}
if
(
y
>
arg
[
i
].
y
||
hy1
==
0
)
{
if
(
y
>
arg
[
i
].
y
/*|| hy1 == 0*/
)
{
y
=
arg
[
i
].
y
;
}
if
(
wx1
<
wx2
)
{
...
...
src/2d/ui/forLottie/BezierEaser.ts
0 → 100644
View file @
01a093d8
export
const
getBezierEasing
=
(
function
()
{
/**
* BezierEasing - use bezier curve for transition easing function
* by Gaëtan Renaudeau 2014 - 2015 – MIT License
*
* Credits: is based on Firefox's nsSMILKeySpline.cpp
* Usage:
* var spline = BezierEasing([ 0.25, 0.1, 0.25, 1.0 ])
* spline.get(x) => returns the easing value | x must be in [0, 1] range
*
*/
var
beziers
=
{};
function
getBezierEasing
(
a
,
b
,
c
,
d
,
nm
?)
{
var
str
=
nm
||
(
'bez_'
+
a
+
'_'
+
b
+
'_'
+
c
+
'_'
+
d
).
replace
(
/
\.
/g
,
'p'
);
if
(
beziers
[
str
])
{
return
beziers
[
str
];
}
var
bezEasing
=
new
BezierEasing
([
a
,
b
,
c
,
d
]);
beziers
[
str
]
=
bezEasing
;
return
bezEasing
;
}
// These values are established by empiricism with tests (tradeoff: performance VS precision)
var
NEWTON_ITERATIONS
=
4
;
var
NEWTON_MIN_SLOPE
=
0.001
;
var
SUBDIVISION_PRECISION
=
0.0000001
;
var
SUBDIVISION_MAX_ITERATIONS
=
10
;
var
kSplineTableSize
=
11
;
var
kSampleStepSize
=
1.0
/
(
kSplineTableSize
-
1.0
);
var
float32ArraySupported
=
typeof
Float32Array
===
"function"
;
function
A
(
aA1
,
aA2
)
{
return
1.0
-
3.0
*
aA2
+
3.0
*
aA1
;
}
function
B
(
aA1
,
aA2
)
{
return
3.0
*
aA2
-
6.0
*
aA1
;
}
function
C
(
aA1
)
{
return
3.0
*
aA1
;
}
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
function
calcBezier
(
aT
,
aA1
,
aA2
)
{
return
((
A
(
aA1
,
aA2
)
*
aT
+
B
(
aA1
,
aA2
))
*
aT
+
C
(
aA1
))
*
aT
;
}
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
function
getSlope
(
aT
,
aA1
,
aA2
)
{
return
3.0
*
A
(
aA1
,
aA2
)
*
aT
*
aT
+
2.0
*
B
(
aA1
,
aA2
)
*
aT
+
C
(
aA1
);
}
function
binarySubdivide
(
aX
,
aA
,
aB
,
mX1
,
mX2
)
{
var
currentX
,
currentT
,
i
=
0
;
do
{
currentT
=
aA
+
(
aB
-
aA
)
/
2.0
;
currentX
=
calcBezier
(
currentT
,
mX1
,
mX2
)
-
aX
;
if
(
currentX
>
0.0
)
{
aB
=
currentT
;
}
else
{
aA
=
currentT
;
}
}
while
(
Math
.
abs
(
currentX
)
>
SUBDIVISION_PRECISION
&&
++
i
<
SUBDIVISION_MAX_ITERATIONS
);
return
currentT
;
}
function
newtonRaphsonIterate
(
aX
,
aGuessT
,
mX1
,
mX2
)
{
for
(
var
i
=
0
;
i
<
NEWTON_ITERATIONS
;
++
i
)
{
var
currentSlope
=
getSlope
(
aGuessT
,
mX1
,
mX2
);
if
(
currentSlope
===
0.0
)
return
aGuessT
;
var
currentX
=
calcBezier
(
aGuessT
,
mX1
,
mX2
)
-
aX
;
aGuessT
-=
currentX
/
currentSlope
;
}
return
aGuessT
;
}
/**
* points is an array of [ mX1, mY1, mX2, mY2 ]
*/
function
BezierEasing
(
points
)
{
this
.
_p
=
points
;
this
.
_mSampleValues
=
float32ArraySupported
?
new
Float32Array
(
kSplineTableSize
)
:
new
Array
(
kSplineTableSize
);
this
.
_precomputed
=
false
;
this
.
get
=
this
.
get
.
bind
(
this
);
}
BezierEasing
.
prototype
=
{
get
:
function
(
x
)
{
var
mX1
=
this
.
_p
[
0
],
mY1
=
this
.
_p
[
1
],
mX2
=
this
.
_p
[
2
],
mY2
=
this
.
_p
[
3
];
if
(
!
this
.
_precomputed
)
this
.
_precompute
();
if
(
mX1
===
mY1
&&
mX2
===
mY2
)
return
x
;
// linear
// Because JavaScript number are imprecise, we should guarantee the extremes are right.
if
(
x
===
0
)
return
0
;
if
(
x
===
1
)
return
1
;
return
calcBezier
(
this
.
_getTForX
(
x
),
mY1
,
mY2
);
},
// Private part
_precompute
:
function
()
{
var
mX1
=
this
.
_p
[
0
],
mY1
=
this
.
_p
[
1
],
mX2
=
this
.
_p
[
2
],
mY2
=
this
.
_p
[
3
];
this
.
_precomputed
=
true
;
if
(
mX1
!==
mY1
||
mX2
!==
mY2
)
this
.
_calcSampleValues
();
},
_calcSampleValues
:
function
()
{
var
mX1
=
this
.
_p
[
0
],
mX2
=
this
.
_p
[
2
];
for
(
var
i
=
0
;
i
<
kSplineTableSize
;
++
i
)
{
this
.
_mSampleValues
[
i
]
=
calcBezier
(
i
*
kSampleStepSize
,
mX1
,
mX2
);
}
},
/**
* getTForX chose the fastest heuristic to determine the percentage value precisely from a given X projection.
*/
_getTForX
:
function
(
aX
)
{
var
mX1
=
this
.
_p
[
0
],
mX2
=
this
.
_p
[
2
],
mSampleValues
=
this
.
_mSampleValues
;
var
intervalStart
=
0.0
;
var
currentSample
=
1
;
var
lastSample
=
kSplineTableSize
-
1
;
for
(;
currentSample
!==
lastSample
&&
mSampleValues
[
currentSample
]
<=
aX
;
++
currentSample
)
{
intervalStart
+=
kSampleStepSize
;
}
--
currentSample
;
// Interpolate to provide an initial guess for t
var
dist
=
(
aX
-
mSampleValues
[
currentSample
])
/
(
mSampleValues
[
currentSample
+
1
]
-
mSampleValues
[
currentSample
]);
var
guessForT
=
intervalStart
+
dist
*
kSampleStepSize
;
var
initialSlope
=
getSlope
(
guessForT
,
mX1
,
mX2
);
if
(
initialSlope
>=
NEWTON_MIN_SLOPE
)
{
return
newtonRaphsonIterate
(
aX
,
guessForT
,
mX1
,
mX2
);
}
else
if
(
initialSlope
===
0.0
)
{
return
guessForT
;
}
else
{
return
binarySubdivide
(
aX
,
intervalStart
,
intervalStart
+
kSampleStepSize
,
mX1
,
mX2
);
}
}
};
return
getBezierEasing
;
}());
\ No newline at end of file
src/2d/ui/forLottie/Lottie.ts
0 → 100644
View file @
01a093d8
import
{
TextureCache
,
getCreateImage
}
from
"../../utils"
;
import
{
Tween
}
from
"../../../tween"
;
import
{
Texture
,
BaseTexture
}
from
"../../texture"
;
import
{
Container
,
Sprite
,
DisplayObject
}
from
"../../display"
;
import
{
buildBezierProps
}
from
"./buildBezierProps"
;
import
{
getBezierEasing
}
from
"./BezierEaser"
;
interface
LottieData
{
"fr"
:
number
,
//珍露 30 60等
"ip"
:
number
,
//开始帧
"op"
:
number
,
//结束帧
"w"
:
number
,
//宽度
"h"
:
number
,
//高度
"nm"
:
string
,
//名字
"layers"
:
LayerData
[],
"assets"
?:
{
"id"
:
string
,
//图片id,与layers里的refId对应
"w"
:
number
,
"h"
:
number
,
"p"
:
string
,
//base64数据
}[],
"textures"
?:
{
[
key
:
string
]:
Texture
}
//缓存的贴图,为了上面的assets里的图片数据,不进全局缓存,
svgaData
?:
any
//数据生成后存入
}
interface
LayerData
{
"ind"
:
number
,
//id唯一
"ty"
:
number
,
//类型,暂时只有2
"nm"
:
string
//"owl_sleep.png",//暂时就是图片
"refId"
:
string
,
"parent"
?:
number
,
//父级id
"ks"
:
KsData
;
"ip"
:
number
,
//开始帧
"op"
:
number
,
//结束帧
transformDatas
?:
TansformData
[];
}
interface
KsData
{
o
:
KeyData
//透明度
r
:
KeyData
//旋转
p
:
KeyData
//位置
a
:
KeyData
//锚点
s
:
KeyData
//缩放
}
interface
KeyData
{
a
:
number
,
k
:
KeyAniData
[]
|
number
[]
|
number
,
x
:
string
,
//可能有表达式
frames
?:
KeyFrameInt
[],
//注意根据表达式还要添加
props
?:
number
[][],
//记录所有的属性,每一帧的
}
interface
KeyAniData
{
t
:
number
,
s
:
number
[],
i
:
{
x
:
number
|
number
[],
y
:
number
|
number
[]
},
o
:
{
x
:
number
|
number
[],
y
:
number
|
number
[]
},
to
:
number
[],
ti
:
number
[],
}
/**
* 记录的Tween数据
*/
interface
TweenData
{
/**
* 属性对象
*/
obj
:
any
,
deltaTime
:
number
,
deltaT
:
number
,
isSet
?:
boolean
,
/**
* 原始帧数据,算pingpong的时间差值用
*/
timeOri
?:
number
,
}
/**
* 每一个属性在总帧数上每个关键点的数据
* 挂在每个层级的的ks的各个属性上,到时直接计算出所有的x,y,sx,sy,r,alpha, ax和ay固定,注意xy都得减axy
* 第一步只处理ks里面的数据
*/
interface
KeyFrameInt
{
/**
* 数值
*/
value
:
number
[],
/**
* 第几帧
*/
frame
:
number
,
// type: "stay" | "tween",//stay停留不变,到下一个状态时硬切 ,
/**
* 为了计算贝塞尔补间数据 ,有io或toti才有缓动
*/
i
?:
{
x
:
number
|
number
[],
y
:
number
|
number
[]
};
o
?:
{
x
:
number
|
number
[],
y
:
number
|
number
[]
};
/**
* 为了计算贝塞尔补间数据
*/
to
?:
number
[],
ti
?:
number
[],
}
interface
TansformData
{
alpha
:
number
;
transform
:
{
a
:
number
,
b
:
number
,
c
:
number
,
d
:
number
,
tx
:
number
,
ty
:
number
,
};
}
//动画总ip必须为0,否则修改
let
totalOp
:
number
=
0
;
export
function
handleLottieData
(
data
:
LottieData
)
{
//存一下,全局用
totalOp
=
data
.
op
;
//最后一帧估计不算
//是否需要深拷贝
// data = JSON.parse(JSON.stringify(data))
//最终返回的数据
var
videoEntity
:
any
=
{};
//一些简单的先设置了
videoEntity
.
videoSize
=
{
width
:
data
.
w
,
height
:
data
.
h
}
videoEntity
.
FPS
=
data
.
fr
;
videoEntity
.
frames
=
data
.
op
-
data
.
ip
;
//图片还在的时
if
(
data
.
assets
)
{
//注意这时不能把素材干进全局。单独存在自己的数据中
videoEntity
.
images
=
{};
data
.
assets
.
forEach
((
a
)
=>
{
videoEntity
.
images
[
a
.
id
]
=
a
.
p
.
replace
(
"data:image/png;base64,"
,
""
)
//去掉相同的前缀
})
}
for
(
var
i
=
0
;
i
<
data
.
layers
.
length
;
i
++
)
{
var
layerData
=
data
.
layers
[
i
];
var
ks
=
layerData
.
ks
;
//锚点是不变的,先写
var
ad
:
[
number
,
number
]
=
typeof
layerData
.
ks
.
a
.
k
[
0
]
==
"number"
?
layerData
.
ks
.
a
.
k
:
layerData
.
ks
.
a
.
k
[
0
].
s
;
// ks.a.frames = [{ value: ad, frame: 0 }];
//@ts-ignore
ks
.
a
.
props
=
fillUp
(
ad
);
addFrames
(
layerData
);
}
//开始计算每帧属性,循环每个层级
//开始计算每帧矩阵,注意父级,循环每帧
//sprites最重要的东西,里面有imageKey和frames,TODO
videoEntity
.
sprites
=
[];
for
(
var
i
=
0
;
i
<
data
.
layers
.
length
;
i
++
)
{
var
layerData
=
data
.
layers
[
i
];
videoEntity
.
sprites
.
push
({
imageKey
:
layerData
.
refId
,
frames
:
layerData
.
transformDatas
})
}
return
videoEntity
}
function
addFrames
(
layerData
:
LayerData
)
{
var
ks
=
layerData
.
ks
;
var
ip
=
layerData
.
ip
;
var
op
=
layerData
.
op
;
//@ts-ignore透明度
if
(
ks
.
o
.
k
.
length
)
{
addFrame
(
layerData
,
"o"
);
}
else
{
//没有直接取首诊数据,且根据ip op处理显隐 具体怎么处理好点
//@ts-ignore 透明度决定显隐,最后根据ip和op来重新修正alpha 注意ip有可能小于0,op可能大于totalOp,所以注意判断 TODO
var
alpha
=
ks
.
o
.
k
/
100
;
// ks.o.frames = [{ value: alpha, frame: 0 }]
//@ts-ignore
ks
.
o
.
props
=
fillUp
(
alpha
);
}
//@ts-ignore 旋转
if
(
data
.
ks
.
r
.
k
.
length
)
{
addFrame
(
layerData
,
"r"
);
}
else
{
//@ts-ignore
// ks.r.frames = [{ value: ks.r.k, frame: 0 }]
//@ts-ignore
ks
.
r
.
props
=
fillUp
(
ks
.
r
.
k
);
}
//位置,得是对象
if
(
typeof
ks
.
p
.
k
[
0
]
!=
"number"
)
{
addFrame
(
layerData
,
"p"
);
}
else
{
var
anchor
:
[
number
,
number
]
=
typeof
ks
.
a
.
k
[
0
]
==
"number"
?
ks
.
a
.
k
:
ks
.
a
.
k
[
0
].
s
;
//@ts-ignore
var
p
=
ks
.
p
.
k
[
0
].
s
;
// ks.p.frames = [{ value: [p[0] - anchor[0], p[1] - anchor[1]], frame: 0 }]
//@ts-ignore
ks
.
p
.
props
=
fillUp
([
p
[
0
]
-
anchor
[
0
],
p
[
1
]
-
anchor
[
1
]]);
}
//缩放
if
(
typeof
ks
.
s
.
k
[
0
]
!=
"number"
)
{
addFrame
(
layerData
,
"s"
);
}
else
{
//@ts-ignore
var
s
=
ks
.
s
.
k
[
0
].
s
;
// ks.s.frames = [{ value: [s[0] / 100, s[1] / 100], frame: 0 }]
//@ts-ignore
ks
.
s
.
props
=
fillUp
([
s
[
0
]
/
100
,
s
[
1
]
/
100
]);
}
}
function
addFrame
(
layerData
:
LayerData
,
type
:
"o"
|
"r"
|
"p"
|
"s"
)
{
//@ts-ignore
var
data
:
KeyAniData
[]
=
layerData
.
ks
[
type
].
k
;
var
ip
=
layerData
.
ip
;
//有小于0的情况
var
op
=
layerData
.
op
;
//有大于totalOp的情况
var
ks
=
layerData
.
ks
;
var
anchor
:
[
number
,
number
]
=
typeof
ks
.
a
.
k
[
0
]
==
"number"
?
ks
.
a
.
k
:
ks
.
a
.
k
[
0
].
s
;
var
frames
:
KeyFrameInt
[]
=
[];
var
props
:
number
[][]
=
ks
[
type
].
props
=
[];
for
(
let
i
=
0
;
i
<
data
.
length
;
i
++
)
{
let
d
=
data
[
i
];
frames
.
push
({
i
:
d
.
i
,
o
:
d
.
o
,
ti
:
d
.
ti
,
to
:
d
.
to
,
value
:
getValue
(
d
.
s
,
type
,
anchor
),
frame
:
d
.
t
})
}
//有表达式的
if
(
ks
[
type
].
x
)
{
var
xs
=
ks
[
type
].
x
;
//取数字
var
rr
=
+
xs
.
replace
(
/
[^
0-9
]
/ig
,
""
);
}
//没表达式的,前后有空的,用前后数据补,小于0的不用,超过totalOp的不用
else
{
for
(
var
i
=
0
;
i
<
frames
.
length
-
1
;
i
++
)
{
//最后一个数据不用
let
f
=
frames
[
i
],
nextF
=
frames
[
i
+
1
];
if
(
f
.
to
)
{
//把函数也传进去吧,用来处理
var
fnc
=
getBezierEasing
(
f
.
o
.
x
,
f
.
o
.
y
,
f
.
i
.
x
,
f
.
i
.
y
).
get
;
buildBezierProps
(
f
.
value
,
nextF
.
value
,
f
.
to
,
f
.
ti
,
f
.
frame
,
nextF
.
frame
,
props
,
fnc
,
totalOp
);
}
}
}
}
/**
* 默认数据
* @param type
*/
function
createDefaultFrame
(
type
:
"o"
|
"r"
|
"p"
|
"s"
)
{
if
(
type
==
"p"
)
{
return
{
value
:
[
0
,
0
],
frame
:
0
}
}
if
(
type
==
"s"
)
{
return
{
value
:
[
1
,
1
],
frame
:
0
}
}
return
{
value
:
0
,
frame
:
0
}
}
function
getValue
(
s
:
number
[],
type
:
"r"
|
"o"
|
"s"
|
"p"
,
anchor
?:
[
number
,
number
])
{
let
value
;
switch
(
type
)
{
case
"r"
:
value
=
[
s
[
0
]];
break
;
case
"o"
:
value
=
[
s
[
0
]
/
100
];
break
;
case
"s"
:
value
=
[
s
[
0
]
/
100
,
s
[
1
]
/
100
]
break
;
case
"p"
:
value
=
[
s
[
0
]
-
anchor
[
0
],
s
[
1
]
-
anchor
[
1
]]
break
;
}
return
value
;
}
function
fillUp
(
value
:
number
|
[
number
,
number
])
{
return
Array
(...
Array
(
totalOp
)).
map
((
a
,
i
)
=>
value
);
}
/**
* 用Tween拼,后续计算帧数据记录
* 临时写的,真尼玛乱得很,以后再说
*/
export
class
Lottie
extends
Container
{
/**
* 原始数据,尽量只获取,不修改
*/
private
rawData
:
LottieData
;
/**
* 总帧数
*/
get
totalFrames
():
number
{
return
this
.
rawData
&&
(
this
.
rawData
.
op
-
this
.
rawData
.
ip
);
};
/**
* 锁步的时间间隔,按fps定,毫秒
*/
private
timeInterval
;
/**
* 按帧率计算,60为1,30为2,
*/
private
deltaFrame
:
number
=
1
;
get
videoWidth
():
number
{
return
this
.
rawData
&&
this
.
rawData
.
w
;
};
get
videoHeight
():
number
{
return
this
.
rawData
&&
this
.
rawData
.
h
;
};
/**
* 供循环用
*/
private
loops
:
number
private
callback
:
()
=>
void
constructor
(
data
)
{
super
()
this
.
_instanceType
=
"Lottie"
;
//初始化
if
(
data
)
{
this
.
init
(
data
);
}
// else {
// this.totalFrames = 0;
// }
}
/**
* 暂时不考虑重复init
* @param data
*/
init
(
data
:
LottieData
)
{
if
(
!
data
)
return
this
.
rawData
=
data
;
this
.
timeInterval
=
1000
/
data
.
fr
;
// this.totalFrames = data.op - data.ip
//间隔帧数,
this
.
deltaFrame
=
60
/
data
.
fr
;
this
.
name
=
data
.
nm
;
//初始化图片 有assets但无textures
if
(
data
.
assets
&&
!
data
.
textures
)
{
//带图片数据的待测试
data
.
textures
=
{};
data
.
assets
.
forEach
((
a
)
=>
{
let
imgTag
=
getCreateImage
()();
imgTag
.
src
=
a
.
p
;
data
.
textures
[
a
.
id
]
=
new
Texture
(
new
BaseTexture
(
imgTag
));
})
}
this
.
initChildren
();
}
private
initChildren
()
{
//初始化内容吧,假设所有资源已经加载好额
var
layers
=
this
.
rawData
.
layers
.
slice
();
//先筛选出所有不带parents,说明是顶级容器
for
(
var
i
=
layers
.
length
-
1
;
i
>=
0
;
i
--
)
{
let
layer
=
layers
[
i
];
// if (!layer.refId) console.log(layer)
let
c
=
this
.
addChild
(
new
Sprite
(
// RES.getRes(layer.nm) ||
layer
.
refId
?
this
.
rawData
.
textures
?
this
.
rawData
.
textures
[
layer
.
refId
]
:
TextureCache
[
layer
.
refId
]
||
TextureCache
[
layer
.
refId
+
".png"
]
:
null
));
//记录一下数据
c
[
"layerData"
]
=
layer
;
}
this
.
initState
()
}
private
initState
(
con
=
this
.
children
)
{
for
(
var
i
=
0
;
i
<
con
.
length
;
i
++
)
{
var
c
:
Sprite
=
con
[
i
];
if
(
c
[
"layerData"
])
{
//取第一个数据
let
data
:
LayerData
=
c
[
"layerData"
];
//@ts-ignore 透明度
c
.
alpha
=
data
.
ks
.
o
.
k
[
0
]
?
data
.
ks
.
o
.
k
[
0
].
s
[
0
]
/
100
:
data
.
ks
.
o
.
k
/
100
;
// c.alpha = c.alpha === 0.01 ? 1 : c.alpha;
//@ts-ignore 选转
c
.
rotation
=
data
.
ks
.
r
.
k
[
0
]
?
data
.
ks
.
r
.
k
[
0
].
s
[
0
]
:
data
.
ks
.
r
.
k
;
//锚点,用贴图锚点
var
ad
=
typeof
data
.
ks
.
a
.
k
[
0
]
==
"number"
?
data
.
ks
.
a
.
k
:
data
.
ks
.
a
.
k
[
0
].
s
;
c
.
anchor
.
set
(
ad
[
0
],
ad
[
1
])
//位置
var
ad
=
typeof
data
.
ks
.
p
.
k
[
0
]
==
"number"
?
data
.
ks
.
p
.
k
:
data
.
ks
.
p
.
k
[
0
].
s
;
c
.
position
.
set
(
ad
[
0
]
-
c
.
anchorX
,
ad
[
1
]
-
c
.
anchorY
)
//缩放
var
ad
=
typeof
data
.
ks
.
s
.
k
[
0
]
==
"number"
?
data
.
ks
.
s
.
k
:
data
.
ks
.
s
.
k
[
0
].
s
;
c
.
scale
.
set
(
ad
[
0
]
/
100
,
ad
[
1
]
/
100
)
//如果入场不在的
c
.
visible
=
data
.
ip
<=
0
// if (data.ip > 0) {
// c.visible = false
// } else {
// c.visible = true
// }
}
if
(
c
.
children
.
length
)
this
.
initState
(
c
.
children
)
}
}
/**
* 为了那啥 修改 loop默认0
*/
play
(
loop
:
number
=
0
,
callback
?:
()
=>
void
)
{
// this.initState();
this
.
stop
(
true
);
//需要回到初始状态再开始
this
.
loops
=
loop
;
this
.
callback
=
callback
;
this
.
addTweens
();
}
/**
* 移除所有的Tween,临时方法
* @param isReset 是否回到初始状态,默认否
*/
stop
(
isReset
:
boolean
=
false
)
{
//tween要去掉
Tween
.
removeTweens
(
this
)
this
.
children
.
forEach
((
c
)
=>
{
Tween
.
removeTweens
(
c
)
})
isReset
&&
this
.
initState
();
}
private
addTweens
(
con
=
this
.
children
)
{
for
(
var
i
=
0
;
i
<
con
.
length
;
i
++
)
{
let
c
:
Sprite
=
con
[
i
];
if
(
c
[
"layerData"
])
{
//取第一个数据
let
data
:
LayerData
=
c
[
"layerData"
];
//@ts-ignore 透明度,如果k是数组,肯定有帧数据
if
(
data
.
ks
.
o
.
k
.
length
)
this
.
addTween
(
c
,
"o"
);
//@ts-ignore 旋转
if
(
data
.
ks
.
r
.
k
.
length
)
this
.
addTween
(
c
,
"r"
);
//位置,得是对象
if
(
typeof
data
.
ks
.
p
.
k
[
0
]
!=
"number"
)
this
.
addTween
(
c
,
"p"
);
//缩放
if
(
typeof
data
.
ks
.
s
.
k
[
0
]
!=
"number"
)
this
.
addTween
(
c
,
"s"
);
//显示隐藏统一这里处理,还有个循环的,如何计算显示隐藏再说
var
t
=
Tween
.
get
(
c
,
{
loop
:
true
})
if
(
data
.
ip
>
0
||
data
.
op
<
this
.
rawData
.
op
)
{
var
aa
=
data
.
ip
<
0
?
0
:
data
.
ip
;
var
bb
=
data
.
op
>
this
.
rawData
.
op
?
this
.
rawData
.
op
:
data
.
op
t
.
wait
(
aa
*
this
.
timeInterval
)
.
call
(()
=>
{
c
.
visible
=
true
;
})
.
wait
((
bb
-
aa
)
*
this
.
timeInterval
)
.
call
(()
=>
{
c
.
visible
=
false
;
})
.
wait
((
this
.
rawData
.
op
-
bb
)
*
this
.
timeInterval
)
}
}
//其实不会有
if
(
c
.
children
.
length
)
this
.
addTweens
(
c
.
children
)
}
//考虑回调
Tween
.
get
(
this
,
{
loop
:
true
})
.
wait
((
this
.
rawData
.
op
-
this
.
rawData
.
ip
)
*
this
.
timeInterval
)
.
call
(()
=>
{
if
(
--
this
.
loops
==
0
)
{
this
.
stop
();
this
.
callback
&&
this
.
callback
();
}
})
}
/**
* 来吧重写,,。专干loopOut和loopIn
* @param dis
* @param type
*/
private
addTween
(
dis
:
DisplayObject
,
type
:
"r"
|
"o"
|
"s"
|
"p"
)
{
const
data
:
{
"t"
:
number
,
"s"
:
number
[]
}[]
=
dis
[
"layerData"
].
ks
[
type
].
k
let
tween
=
Tween
.
get
(
dis
,
{
loop
:
true
})
let
countTime
=
0
;
//有表达式的,先随便写,到时整理
if
(
dis
[
"layerData"
].
ks
[
type
].
x
)
{
var
xs
=
dis
[
"layerData"
].
ks
[
type
].
x
;
//取数字
var
rr
=
+
xs
.
replace
(
/
[^
0-9
]
/ig
,
""
);
//loopOut后续循环,补齐从最后一个数据的t到dis["layerData"].op的间隔,不足一个的情况需要单独计算
if
(
xs
.
indexOf
(
"loopOut"
)
>=
0
)
{
//先走完一次整的,反正补后面的
let
objArr
:
{
obj
:
any
,
deltaTime
:
number
,
deltaT
:
number
,
isSet
?:
boolean
}[]
=
[];
let
curT
=
0
;
for
(
let
i
=
0
;
i
<
data
.
length
;
i
++
)
{
let
d
=
data
[
i
];
//如果超过op的
if
(
d
.
t
>
dis
[
"layerData"
].
op
)
break
;
let
deltaT
=
d
.
t
-
curT
;
let
deltaTime
=
deltaT
*
this
.
timeInterval
;
let
obj
=
getTweenObj
(
d
);
//如果第一帧不是0,需要等待
if
(
i
==
0
&&
d
.
t
>
0
)
{
tween
.
wait
(
deltaTime
)
countTime
+=
deltaTime
// console.log("asdffff",countALL,d.t)
//需加set,但是时间0,暂时别加吧,tween会自行记录初始值
// objArr.push({ obj, deltaT:0, deltaTime:0, isSet: true })
}
//从0开始,但是t为0,用set
else
if
(
i
==
0
&&
d
.
t
==
0
)
{
//考虑下是否需要,deltaTime也是0
tween
.
set
(
obj
);
objArr
.
push
({
obj
,
deltaT
,
deltaTime
,
isSet
:
true
})
}
else
{
//一帧当作set
if
(
d
.
t
-
curT
==
1
)
{
tween
.
wait
(
deltaTime
)
.
set
(
obj
);
objArr
.
push
({
obj
,
deltaT
,
deltaTime
,
isSet
:
true
})
countTime
+=
deltaTime
// console.log("asdff",countALL)
}
else
{
tween
.
to
(
obj
,
deltaTime
);
objArr
.
push
({
obj
,
deltaT
,
deltaTime
})
countTime
+=
deltaTime
// console.log("asdff",countALL)
}
}
//赋值
curT
=
d
.
t
;
}
// if (dis["layerData"].ind == "1") console.log(45445456, objArr)
// console.log("asdf",countALL)
//pingpong先不考虑次数,还没遇到
if
(
xs
.
indexOf
(
"pingpong"
)
>=
0
&&
data
[
data
.
length
-
1
].
t
<
dis
[
"layerData"
].
op
)
{
// Math.floor((dis["layerData"].op - data[0].t))
var
round
=
Math
.
round
(
(
dis
[
"layerData"
].
op
-
data
[
data
.
length
-
1
].
t
)
/
(
data
[
data
.
length
-
1
].
t
-
data
[
0
].
t
)
//不一定所有
)
curT
+=
round
*
(
data
[
data
.
length
-
1
].
t
-
data
[
0
].
t
)
//不一定所有
var
dir
=
false
;
while
(
--
round
)
{
if
(
dir
)
{
for
(
var
o
=
0
;
o
<
objArr
.
length
;
o
++
)
{
tween
.
to
(
objArr
[
o
].
obj
,
objArr
[
o
].
deltaTime
);
countTime
+=
objArr
[
o
].
deltaTime
;
}
}
else
{
for
(
var
o
=
objArr
.
length
-
1
;
o
>=
1
;
o
--
)
{
tween
.
to
(
objArr
[
o
-
1
].
obj
,
objArr
[
o
].
deltaTime
);
countTime
+=
objArr
[
o
].
deltaTime
;
}
}
dir
=
!
dir
;
}
}
//循环,先floor,多余的重走一次,估计不能用dis["layerData"].op,得用this.rawData.op,loopOut到时也得单独计算
else
if
(
xs
.
indexOf
(
"cycle"
)
>=
0
&&
data
[
data
.
length
-
1
].
t
<
dis
[
"layerData"
].
op
)
{
var
lastIndex
=
data
.
length
-
1
;
var
num
=
Math
.
floor
(
(
dis
[
"layerData"
].
op
-
data
[
lastIndex
].
t
)
/
(
data
[
lastIndex
].
t
-
data
[
lastIndex
-
(
rr
||
lastIndex
)].
t
)
);
// console.log("asd",num,data[lastIndex].t - data[lastIndex - (rr || lastIndex)].t)
//取一部分
let
objArrC
=
objArr
.
slice
(
-
rr
);
while
(
num
)
{
num
--
;
//补满
for
(
var
o
=
0
;
o
<
objArrC
.
length
;
o
++
)
{
if
(
objArrC
[
o
].
isSet
)
{
tween
.
wait
(
objArrC
[
o
].
deltaTime
)
.
set
(
objArrC
[
o
].
obj
);
}
else
{
tween
.
to
(
objArrC
[
o
].
obj
,
objArrC
[
o
].
deltaTime
);
}
countTime
+=
objArrC
[
o
].
deltaTime
}
}
// console.log("asd",countALL)
//补剩下的,跑一部分
var
left
=
(
dis
[
"layerData"
].
op
-
data
[
lastIndex
].
t
)
%
(
data
[
lastIndex
].
t
-
data
[
lastIndex
-
(
rr
||
lastIndex
)].
t
);
// if(dis["layerData"].ind=="1") console.log(45445456,left)
for
(
var
o
=
0
;
o
<
objArrC
.
length
;
o
++
)
{
if
(
objArrC
[
o
].
deltaT
<=
left
)
{
if
(
objArrC
[
o
].
isSet
)
{
tween
.
wait
(
objArrC
[
o
].
deltaTime
)
.
set
(
objArrC
[
o
].
obj
);
}
else
{
tween
.
to
(
objArrC
[
o
].
obj
,
objArrC
[
o
].
deltaTime
);
}
left
-=
objArrC
[
o
].
deltaT
countTime
+=
objArrC
[
o
].
deltaTime
}
else
{
if
(
left
>
0
)
{
//这种情况不会是set,再调吧,这样算补间有问题
// console.log(o,left, objArrC.length)
// if(o == 0)console.log(left, objArrC[o].deltaT)
var
ooo
=
o
==
0
?
calculateInterpolation
(
/*objArrC[0].obj,*/
copyProps
(
objArrC
[
o
].
obj
,
tween
[
"_initQueueProps"
]),
//初始值用tween记录的
objArrC
[
o
].
obj
,
left
/
objArrC
[
o
].
deltaT
)
:
calculateInterpolation
(
objArrC
[
o
-
1
].
obj
,
objArrC
[
o
].
obj
,
left
/
objArrC
[
o
].
deltaT
)
tween
.
to
(
ooo
,
left
*
this
.
timeInterval
);
countTime
+=
left
*
this
.
timeInterval
// console.log(countALL)
}
break
;
}
}
}
}
//前面循环,先取所有的tween序列,初始状态要改
else
if
(
xs
.
indexOf
(
"loopIn"
)
>=
0
)
{
let
objArr
:
TweenData
[]
=
[];
let
curT
=
0
;
for
(
let
i
=
0
;
i
<
data
.
length
;
i
++
)
{
let
d
=
data
[
i
];
//不能去掉,有可能需要用到
// if (d.t > dis["layerData"].op) break;
let
deltaT
=
d
.
t
-
curT
;
let
deltaTime
=
deltaT
*
this
.
timeInterval
;
let
obj
=
getTweenObj
(
d
);
//一帧当作set
if
(
d
.
t
-
curT
==
1
)
{
objArr
.
push
({
obj
,
deltaT
,
deltaTime
,
isSet
:
true
,
timeOri
:
d
.
t
})
}
else
{
objArr
.
push
({
obj
,
deltaT
,
deltaTime
,
timeOri
:
d
.
t
})
}
//赋值
curT
=
d
.
t
;
}
//pingpong再loopIn暂时没有,用到时再写,还真尼玛下个就是
if
(
xs
.
indexOf
(
"pingpong"
)
>=
0
&&
data
[
0
].
t
>
0
)
{
objArr
=
getLoopInPingpongTween
(
objArr
,
rr
,
dis
[
"layerData"
].
op
)
// if (dis["layerData"].ind == 8) console.log("asdf", objArr);
for
(
var
o
=
0
;
o
<
objArr
.
length
;
o
++
)
{
// if (dis["layerData"].ind == 8) console.log("asdf", objArrC[o]);
if
(
objArr
[
o
].
isSet
)
{
tween
.
wait
(
objArr
[
o
].
deltaTime
)
.
set
(
objArr
[
o
].
obj
);
}
else
{
tween
.
to
(
objArr
[
o
].
obj
,
objArr
[
o
].
deltaTime
);
}
countTime
+=
objArr
[
o
].
deltaTime
}
}
//循环,其实应该用dis["layerData"].ip判断
else
if
(
xs
.
indexOf
(
"cycle"
)
>=
0
&&
data
[
0
].
t
>
0
)
{
//不考虑不整的,直接从0开始,算出整的,然后自然过度到最后一个
//可能入场的时间不能算
// if (dis["layerData"].ip > 0) tween.wait(dis["layerData"].ip * this.timeInterval)
objArr
=
getLoopInCycleTween
(
objArr
,
rr
,
dis
[
"layerData"
].
op
,
dis
[
"layerData"
].
ip
);
if
(
dis
[
"layerData"
].
ip
)
{
// console.log(5464,dis["layerData"].ip,countTime)
tween
.
wait
(
dis
[
"layerData"
].
ip
*
this
.
timeInterval
)
//以后改
countTime
+=
dis
[
"layerData"
].
ip
*
this
.
timeInterval
}
for
(
var
o
=
0
;
o
<
objArr
.
length
;
o
++
)
{
if
(
objArr
[
o
].
isSet
)
{
tween
.
wait
(
objArr
[
o
].
deltaTime
)
.
set
(
objArr
[
o
].
obj
);
}
else
{
tween
.
to
(
objArr
[
o
].
obj
,
objArr
[
o
].
deltaTime
);
}
countTime
+=
objArr
[
o
].
deltaTime
}
}
// if (dis["layerData"].ind == 1) console.log("asd", countTime);
//多余的时间
var
op
=
Math
.
min
(
dis
[
"layerData"
].
op
,
this
.
rawData
.
op
)
if
(
countTime
<
op
*
this
.
timeInterval
)
{
var
dd
=
op
*
this
.
timeInterval
-
countTime
;
tween
.
wait
(
dd
)
countTime
+=
dd
}
// console.log(countTime)
// if (dis["layerData"].ind == 1) console.log("asde", countTime);
}
//还有一部分 dis["layerData"].op 到 this.rawData.op
if
(
dis
[
"layerData"
].
op
<
this
.
rawData
.
op
)
{
tween
.
wait
((
this
.
rawData
.
op
-
dis
[
"layerData"
].
op
)
*
this
.
timeInterval
)
countTime
+=
(
this
.
rawData
.
op
-
dis
[
"layerData"
].
op
)
*
this
.
timeInterval
}
//查看所有时间
// console.log(countTime)
}
//没表达式的,用wait补满前面的和后面的
else
{
let
curT
=
0
;
for
(
let
i
=
0
;
i
<
data
.
length
;
i
++
)
{
let
d
=
data
[
i
],
obj
=
getTweenObj
(
d
),
deltaTime
;
//判断是否小于0,小于0需要和下一帧算补间
if
(
d
.
t
<
0
)
{
//下一帧不存在或也小于0
if
(
!
data
[
i
+
1
]
||
data
[
i
+
1
].
t
<
0
)
break
;
obj
=
calculateInterpolation
(
obj
,
getTweenObj
(
data
[
i
+
1
]),
-
d
.
t
/
(
data
[
i
+
1
].
t
-
d
.
t
)
);
// if (d.t == -35) console.log(123)
tween
.
set
(
obj
);
curT
=
0
;
}
//如果超过op的,和上一帧算补间
else
if
(
d
.
t
>
this
.
rawData
.
op
)
{
if
(
!
data
[
i
-
1
]
||
data
[
i
-
1
].
t
>
this
.
rawData
.
op
)
break
;
let
dt
=
this
.
rawData
.
op
-
data
[
i
-
1
].
t
;
deltaTime
=
dt
*
this
.
timeInterval
;
obj
=
calculateInterpolation
(
getTweenObj
(
data
[
i
-
1
]),
obj
,
dt
/
(
d
.
t
-
data
[
i
-
1
].
t
)
);
// if (dis["layerData"].ind == 7) console.log(999, d.t, data[i - 1].t, getTweenObj(data[i - 1]), obj)
tween
.
to
(
obj
,
deltaTime
);
//累计时间
countTime
+=
deltaTime
;
//没必要记了。最后一帧了
curT
=
this
.
rawData
.
op
;
}
else
{
deltaTime
=
(
d
.
t
-
curT
)
*
this
.
timeInterval
//如果第一帧不是0,需要等待
if
(
i
==
0
&&
d
.
t
>
0
)
{
tween
.
wait
(
deltaTime
)
}
//从0开始,但是t为0,用set
else
if
(
i
==
0
&&
d
.
t
==
0
)
{
tween
.
set
(
obj
);
}
else
{
tween
.
to
(
obj
,
deltaTime
);
}
countTime
+=
deltaTime
//赋值
curT
=
d
.
t
;
}
}
//考虑还有部分时间,等待
if
(
this
.
rawData
.
op
>
curT
)
{
tween
.
wait
((
this
.
rawData
.
op
-
curT
)
*
this
.
timeInterval
)
}
}
// console.log(countTime)
//结束的操作
// tween.call(() => {
// if (--this.loops == 0) {
// this.stop();
// this.callback && this.callback();
// }
// })
/**
* type和dis主参数里取
* @param d 循环里取
*/
function
getTweenObj
(
d
:
{
"t"
:
number
;
"s"
:
number
[]
})
{
let
obj
;
switch
(
type
)
{
case
"r"
:
obj
=
{
rotation
:
d
.
s
[
0
]
}
break
;
case
"o"
:
obj
=
{
alpha
:
d
.
s
[
0
]
/
100
}
break
;
case
"s"
:
obj
=
{
scaleX
:
d
.
s
[
0
]
/
100
,
scaleY
:
d
.
s
[
1
]
/
100
}
break
;
case
"p"
:
obj
=
{
x
:
d
.
s
[
0
]
-
dis
.
anchorX
,
y
:
d
.
s
[
1
]
-
dis
.
anchorY
}
break
;
}
return
obj
;
}
}
/**
* 对所有的进行刷新,,根据cParent进行迭代刷新
* 层级有问题,只能平铺,手动计算矩阵
* 因为要平铺,所以记录cParent和ind 从1开始,也许只需要+1就行,还是用ind记录查找吧
* 遍历找
*/
updateTransform
()
{
//super不行,到时查
this
.
displayObjectUpdateTransform
();
this
.
children
.
forEach
((
c
)
=>
{
this
.
_recursivePostUpdateTransformAA
(
c
);
})
this
.
children
.
forEach
((
c
)
=>
{
c
.
mark
=
false
;
})
}
private
findChildByInd
(
ind
:
number
)
{
for
(
var
i
=
0
;
i
<
this
.
children
.
length
;
i
++
)
{
if
(
this
.
children
[
i
].
layerData
&&
this
.
children
[
i
].
layerData
.
ind
===
ind
)
return
this
.
children
[
i
]
}
return
null
}
private
_recursivePostUpdateTransformAA
(
c
)
{
if
(
c
.
layerData
&&
c
.
layerData
.
parent
)
{
//ind从1开始,所以不用考虑0,且不应该存在 p没有的情况
var
p
=
this
.
findChildByInd
(
c
.
layerData
.
parent
)
this
.
_recursivePostUpdateTransformAA
(
p
);
if
(
!
c
.
mark
)
{
c
.
mark
=
true
;
c
.
transform
.
updateWorldMatrix
(
p
.
transform
);
//透明度单独计算,不跟cParent保持
c
.
_worldAlpha
=
c
.
alpha
*
c
.
parent
.
_worldAlpha
;
}
}
//直接进行tans
else
if
(
!
c
.
mark
)
{
c
.
updateTransform
();
//alpha跟父级有关
c
.
mark
=
true
}
}
/**
* 加个方法,前两个参数都没用,为了一头牛
* @param beginFrame
* @param endFrame
* @param loops
* @param callback
*/
public
startAniRange
(
beginFrame
:
number
=
1
,
endFrame
:
number
=
this
.
totalFrames
,
loops
:
number
=
1
,
callback
?:
()
=>
void
)
{
this
.
play
(
loops
,
callback
)
}
destroy
()
{
//tween要去掉
this
.
children
.
forEach
((
c
)
=>
{
Tween
.
removeTweens
(
c
)
})
super
.
destroy
();
}
}
function
calculateInterpolation
(
d1
:
any
,
d2
:
any
,
scale
:
number
//时间比例 t/(t2-t1)
)
{
let
obj
=
{};
// for (let key in d1) obj[key] = Math.abs(d1[key] - d2[key]) * scale + d1[key]
//之前为何要加绝对值
for
(
let
key
in
d1
)
obj
[
key
]
=
(
d2
[
key
]
-
d1
[
key
])
*
scale
+
d1
[
key
]
return
obj
}
/**
* 返回一个带obj里所有的key的对象,但是key值为sObj里的
* @param obj 取里面的key
* @param sObj 取里面的key值
*/
function
copyProps
(
obj
,
sObj
)
{
var
o
=
{};
if
(
!
obj
)
return
o
;
for
(
let
key
in
obj
)
o
[
key
]
=
sObj
[
key
];
return
o
;
}
/**
* 以后可能还会改,以后整理吧,以后可能要计算补间,现在先不管
* @param objArr
* @param time 第一帧的时间间隔
* @param round 循环索引
*/
function
getLoopInCycleTween
(
objArr
:
TweenData
[],
round
:
number
,
op
:
number
,
ip
:
number
=
0
)
{
var
time
=
objArr
[
0
].
deltaT
-
ip
;
//以后算插值时再说
//这样是否合理,也可能是objArrC的length下标,超出一个
if
(
round
>=
objArr
.
length
)
round
=
0
;
var
objArrC
=
objArr
.
slice
(
0
,
round
?
round
+
1
:
objArr
.
length
)
// var lastDeltaT = objArrC[objArrC.length - 1].deltaT;
// if (objArrC.length > 2) {//如果长度大于2,首帧和尾帧是一致的,默认,所以不取最后一帧
// //去掉最后一帧
// objArrC.pop();
// }
// console.log(objArrC.length, objArr.length)
var
tweenArr
:
TweenData
[]
=
[];
var
curIndex
=
0
;
while
(
time
>
0
)
{
curIndex
--
;
//超出就是最后一帧
if
(
curIndex
<
0
)
curIndex
=
objArrC
.
length
-
1
;
//第0帧是set
if
(
!
curIndex
)
{
tweenArr
.
unshift
({
obj
:
objArrC
[
0
].
obj
,
deltaT
:
0
,
deltaTime
:
0
,
timeOri
:
objArrC
[
0
].
timeOri
,
isSet
:
true
})
}
//其他的都是终点
else
{
tweenArr
.
unshift
(
objArrC
[
curIndex
])
time
-=
objArrC
[
curIndex
].
deltaT
}
}
//第一帧加上
tweenArr
.
unshift
({
obj
:
objArrC
[
0
].
obj
,
deltaT
:
0
,
deltaTime
:
0
,
timeOri
:
objArrC
[
0
].
timeOri
,
isSet
:
true
})
//把剩下的,第一项要变成set,再加后面的所有
tweenArr
.
push
({
obj
:
objArrC
[
0
].
obj
,
deltaT
:
0
,
deltaTime
:
0
,
isSet
:
true
})
for
(
var
i
=
1
;
i
<
objArr
.
length
;
i
++
)
{
if
(
objArr
[
i
].
timeOri
>
op
)
break
;
tweenArr
.
push
(
objArr
[
i
]);
}
// console.log(tweenArr)
return
tweenArr
}
function
getLoopInCycleTween11
(
objArr
:
TweenData
[],
time
:
number
,
round
:
number
)
{
//这样是否合理,也可能是objArrC的length下标,超出一个
if
(
round
>=
objArr
.
length
)
round
=
0
;
var
lastDeltaT
=
objArr
[
round
||
objArr
.
length
-
1
].
deltaT
;
var
lastDeltaTime
=
objArr
[
round
||
objArr
.
length
-
1
].
deltaTime
;
objArr
[
0
].
deltaT
=
lastDeltaT
;
objArr
[
0
].
deltaTime
=
lastDeltaTime
;
var
objArrC
=
objArr
.
slice
(
0
,
round
||
objArr
.
length
)
var
tweenArr
:
TweenData
[]
=
[];
var
curT
=
0
;
//从0开始,一般就是初始未知,不做任何处理,不考虑插值
for
(
var
i
=
1
;
i
<
objArrC
.
length
;
i
++
)
{
tweenArr
.
push
(
objArrC
[
i
]);
//不做拷贝应该也没事
curT
+=
objArrC
[
i
].
deltaT
;
}
time
-=
curT
;
while
(
time
>
lastDeltaT
)
{
for
(
var
i
=
0
;
i
<
objArrC
.
length
;
i
++
)
{
tweenArr
.
push
(
objArrC
[
i
]);
//不做拷贝应该也没事
time
-=
objArrC
[
i
].
deltaT
}
}
//接上最后一组
tweenArr
=
tweenArr
.
concat
(
objArr
)
return
tweenArr
}
/**
* pingpong的,取首尾相接的循环
* @param objArr
* @param time
* @param round
*/
function
getLoopInPingpongTween
(
objArr
:
TweenData
[],
round
:
number
,
op
:
number
)
{
var
time
=
objArr
[
0
].
deltaT
;
if
(
round
>=
objArr
.
length
)
round
=
0
;
var
objArrC
=
objArr
.
slice
(
0
,
round
?
round
+
1
:
objArr
.
length
)
var
timeInterval
=
objArr
[
0
].
deltaTime
/
objArr
[
0
].
deltaT
;
// var allTime = 0;
// objArrC.forEach((o, i) => { if (i != 0) allTime += o.deltaT })
var
tweenArr
:
TweenData
[]
=
[];
var
dir
:
boolean
=
true
// = (time / allTime) % 2 == 0;
var
curIndex
=
0
;
var
lastIndex
=
0
;
while
(
time
>
0
)
{
dir
?
curIndex
++
:
curIndex
--
;
//如果超了,就反向
if
(
curIndex
>
objArrC
.
length
-
1
)
{
dir
=
false
;
curIndex
-=
2
}
else
if
(
curIndex
<
0
)
{
dir
=
true
;
curIndex
+=
2
}
var
deltaT
=
Math
.
abs
(
objArrC
[
lastIndex
].
timeOri
-
objArrC
[
curIndex
].
timeOri
);
tweenArr
.
unshift
({
obj
:
objArrC
[
lastIndex
].
obj
,
deltaT
,
deltaTime
:
deltaT
*
timeInterval
,
timeOri
:
objArrC
[
lastIndex
].
timeOri
,
isSet
:
objArrC
[
lastIndex
].
isSet
})
lastIndex
=
curIndex
;
time
-=
deltaT
}
//塞入
tweenArr
.
unshift
({
obj
:
objArrC
[
lastIndex
].
obj
,
deltaT
:
0
,
deltaTime
:
0
,
timeOri
:
objArrC
[
lastIndex
].
timeOri
,
isSet
:
true
})
//把剩下的,除了第一项不要
//得考虑超出的op
for
(
var
i
=
1
;
i
<
objArr
.
length
;
i
++
)
{
if
(
objArr
[
i
].
timeOri
>
op
)
break
;
tweenArr
.
push
(
objArr
[
i
]);
}
// objArr.forEach((o, i) => {
// if (i) tweenArr.push(o)
// })
return
tweenArr
}
\ No newline at end of file
src/2d/ui/forLottie/buildBezierProps.ts
0 → 100644
View file @
01a093d8
export
function
buildBezierProps
(
pt1
,
pt2
,
pt3
,
pt4
,
startIndex
,
endIndex
,
points
,
fnc
,
limit
?:
number
)
{
var
bezierData
=
buildBezierData
(
pt1
,
pt2
,
pt3
,
pt4
);
//处理完所有的点
for
(
var
i
=
startIndex
;
i
<
endIndex
;
i
++
)
{
if
(
limit
)
{
//小于0的不算了,浪费时间
if
(
i
<
0
)
continue
;
//超出的也不要了
if
(
i
>=
limit
)
break
;
//遇到那种
}
var
perc
=
fnc
((
i
-
startIndex
)
/
(
endIndex
-
startIndex
));
var
distanceInLine
=
bezierData
.
segmentLength
*
perc
;
if
(
perc
==
0
)
{
points
[
i
]
=
bezierData
.
points
[
0
].
point
;
continue
;
}
//找最近的点
points
[
i
]
=
findNearest
(
distanceInLine
,
bezierData
.
points
);
}
}
function
findNearest
(
distanceInLine
:
number
,
bezierDataPoints
:
PointData
[])
{
for
(
var
i
=
0
;
i
<
bezierDataPoints
.
length
;
i
++
)
{
var
preLength
=
bezierDataPoints
[
i
].
preLength
;
if
(
distanceInLine
<
preLength
)
{
//前一帧后当前帧做补间,且i肯定不会为0,因为distanceInLine不会小于0;
var
segmentPerc
=
(
distanceInLine
-
bezierDataPoints
[
i
-
1
].
preLength
)
/
bezierDataPoints
[
i
].
partialLength
;
var
kLen
=
bezierDataPoints
[
i
-
1
].
point
.
length
;
var
newValue
=
[];
for
(
var
k
=
0
;
k
<
kLen
;
k
+=
1
)
{
newValue
[
k
]
=
bezierDataPoints
[
i
-
1
].
point
[
k
]
+
(
bezierDataPoints
[
i
].
point
[
k
]
-
bezierDataPoints
[
i
-
1
].
point
[
k
])
*
segmentPerc
;
}
return
newValue
;
//取补间
}
}
//没有返回最后一个
return
bezierDataPoints
[
bezierDataPoints
.
length
-
1
].
point
;
}
var
storedData
=
{};
function
buildBezierData
(
pt1
,
pt2
,
pt3
,
pt4
):
BezierData
{
var
bezierName
=
(
pt1
[
0
]
+
'_'
+
pt1
[
1
]
+
'_'
+
pt2
[
0
]
+
'_'
+
pt2
[
1
]
+
'_'
+
pt3
[
0
]
+
'_'
+
pt3
[
1
]
+
'_'
+
pt4
[
0
]
+
'_'
+
pt4
[
1
]).
replace
(
/
\.
/g
,
'p'
);
if
(
!
storedData
[
bezierName
])
{
var
curveSegments
=
150
//defaultCurveSegments;
var
k
,
i
,
len
;
var
ptCoord
,
perc
,
addedLength
=
0
;
var
ptDistance
;
var
point
,
lastPoint
=
null
;
if
(
pt1
.
length
===
2
&&
(
pt1
[
0
]
!=
pt2
[
0
]
||
pt1
[
1
]
!=
pt2
[
1
])
&&
pointOnLine2D
(
pt1
[
0
],
pt1
[
1
],
pt2
[
0
],
pt2
[
1
],
pt1
[
0
]
+
pt3
[
0
],
pt1
[
1
]
+
pt3
[
1
])
&&
pointOnLine2D
(
pt1
[
0
],
pt1
[
1
],
pt2
[
0
],
pt2
[
1
],
pt2
[
0
]
+
pt4
[
0
],
pt2
[
1
]
+
pt4
[
1
]))
{
curveSegments
=
2
;
//这种情况只会生成两个点
}
var
bezierData
=
{
segmentLength
:
0
,
points
:
new
Array
(
curveSegments
)
}
len
=
pt3
.
length
;
for
(
k
=
0
;
k
<
curveSegments
;
k
+=
1
)
{
point
=
new
Array
(
len
);
perc
=
k
/
(
curveSegments
-
1
);
ptDistance
=
0
;
for
(
i
=
0
;
i
<
len
;
i
+=
1
)
{
ptCoord
=
Math
.
pow
(
1
-
perc
,
3
)
*
pt1
[
i
]
+
3
*
Math
.
pow
(
1
-
perc
,
2
)
*
perc
*
(
pt1
[
i
]
+
pt3
[
i
])
+
3
*
(
1
-
perc
)
*
Math
.
pow
(
perc
,
2
)
*
(
pt2
[
i
]
+
pt4
[
i
])
+
Math
.
pow
(
perc
,
3
)
*
pt2
[
i
];
point
[
i
]
=
ptCoord
;
if
(
lastPoint
!==
null
)
{
ptDistance
+=
Math
.
pow
(
point
[
i
]
-
lastPoint
[
i
],
2
);
}
}
ptDistance
=
Math
.
sqrt
(
ptDistance
);
addedLength
+=
ptDistance
;
bezierData
.
points
[
k
]
=
{
partialLength
:
ptDistance
,
preLength
:
addedLength
,
//记录一下前面所有的总长
point
}
lastPoint
=
point
;
}
bezierData
.
segmentLength
=
addedLength
;
storedData
[
bezierName
]
=
bezierData
;
}
return
storedData
[
bezierName
];
}
interface
PointData
{
point
:
number
[],
partialLength
:
number
,
preLength
:
number
,
}
interface
BezierData
{
segmentLength
:
number
,
points
:
PointData
[]
}
function
pointOnLine2D
(
x1
,
y1
,
x2
,
y2
,
x3
,
y3
)
{
var
det1
=
(
x1
*
y2
)
+
(
y1
*
x3
)
+
(
x2
*
y3
)
-
(
x3
*
y2
)
-
(
y3
*
x1
)
-
(
x2
*
y1
);
return
det1
>
-
0.001
&&
det1
<
0.001
;
}
\ No newline at end of file
src/3D/Geometry.ts
View file @
01a093d8
...
...
@@ -243,10 +243,10 @@ function createNineTextures(imageUrl: string): Promise<FYGE.Texture[]> {
"y"
:
~~
(
i
/
3
)
*
h
,
w
,
h
,
sw
:
w
,
sh
:
h
,
ox
:
0
,
oy
:
0
,
ro
:
false
};
FYGE
.
createTextureSheet
(
new
FYGE
.
BaseTexture
(
image
),
obj
);
var
textures
=
FYGE
.
createTextureSheet
(
new
FYGE
.
BaseTexture
(
image
),
obj
);
//取TextureCache里的
var
arr
=
[];
for
(
var
i
=
0
;
i
<
9
;
i
++
)
arr
.
push
(
FYGE
.
TextureCache
[
name
+
i
])
for
(
var
i
=
0
;
i
<
9
;
i
++
)
arr
.
push
(
textures
[
name
+
i
])
resolve
(
arr
)
}
image
.
onerror
=
function
()
{
...
...
src/3D/gltf/GLTFCubicSplineInterpolant.ts
0 → 100644
View file @
01a093d8
import
{
InterInterpolant
}
from
"./Interpolant"
;
// Spline Interpolation
// Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation
export
class
GLTFCubicSplineInterpolant
extends
InterInterpolant
{
copySampleValue_
(
index
:
number
)
{
// Copies a sample value to the result buffer. See description of glTF
// CUBICSPLINE values layout in interpolate_() function below.
var
result
=
this
.
resultBuffer
,
values
=
this
.
sampleValues
,
valueSize
=
this
.
valueSize
,
offset
=
index
*
valueSize
*
3
+
valueSize
;
for
(
var
i
=
0
;
i
!==
valueSize
;
i
++
)
{
result
[
i
]
=
values
[
offset
+
i
];
}
return
result
;
}
beforeStart_
=
this
.
copySampleValue_
;
afterEnd_
=
this
.
copySampleValue_
;
interpolate_
(
i1
:
number
,
t0
:
number
,
t
:
number
,
t1
:
number
)
{
var
result
=
this
.
resultBuffer
;
var
values
=
this
.
sampleValues
;
var
stride
=
this
.
valueSize
;
var
stride2
=
stride
*
2
;
var
stride3
=
stride
*
3
;
var
td
=
t1
-
t0
;
var
p
=
(
t
-
t0
)
/
td
;
var
pp
=
p
*
p
;
var
ppp
=
pp
*
p
;
var
offset1
=
i1
*
stride3
;
var
offset0
=
offset1
-
stride3
;
var
s0
=
2
*
ppp
-
3
*
pp
+
1
;
var
s1
=
ppp
-
2
*
pp
+
p
;
var
s2
=
-
2
*
ppp
+
3
*
pp
;
var
s3
=
ppp
-
pp
;
// Layout of keyframe output values for CUBICSPLINE animations:
// [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ]
for
(
var
i
=
0
;
i
!==
stride
;
i
++
)
{
var
p0
=
values
[
offset0
+
i
+
stride
];
// splineVertex_k
var
m0
=
values
[
offset0
+
i
+
stride2
]
*
td
;
// outTangent_k * (t_k+1 - t_k)
var
p1
=
values
[
offset1
+
i
+
stride
];
// splineVertex_k+1
var
m1
=
values
[
offset1
+
i
]
*
td
;
// inTangent_k+1 * (t_k+1 - t_k)
result
[
i
]
=
s0
*
p0
+
s1
*
m0
+
s2
*
p1
+
s3
*
m1
;
}
return
result
;
};
}
src/3D/GLTFLoader.ts
→
src/3D/
gltf/
GLTFLoader.ts
View file @
01a093d8
import
{
EventDispatcher
}
from
"../2d/events"
;
import
{
GlobalLoader
}
from
"../2d/loader"
;
import
{
rgb2hex
}
from
"../2d/utils"
;
import
{
DirectionalLight
,
PointLight
,
LightMaterial
}
from
"."
;
import
{
EventDispatcher
}
from
"../../2d/events"
;
import
{
GlobalLoader
}
from
"../../2d/loader"
;
import
{
rgb2hex
,
getEnv
}
from
"../../2d/utils"
;
import
{
LightMaterial
}
from
"../materials/LightMaterial"
;
import
{
GLTFCubicSplineInterpolant
}
from
"./GLTFCubicSplineInterpolant"
;
var
THREE
:
any
var
THREE
:
any
/* BINARY EXTENSION */
var
BINARY_EXTENSION_BUFFER_NAME
=
'binary_glTF'
;
...
...
@@ -94,7 +95,7 @@ var PATH_PROPERTIES = {
translation
:
'position'
,
rotation
:
'quaternion'
,
weights
:
'morphTargetInfluences'
,
position
:
"position"
position
:
"position"
};
var
INTERPOLATION
=
{
...
...
@@ -130,8 +131,7 @@ class GLTFLoader extends EventDispatcher {
onError
&&
onError
(
res
)
}
}
//@ts-ignore
if
(
my
)
{
if
(
getEnv
()
==
"tb"
)
{
GlobalLoader
.
tbLoad
(
callback
,
url
,
"ArrayBuffer"
)
}
else
{
GlobalLoader
.
loadRawWeb
(
callback
,
url
,
"arraybuffer"
)
...
...
@@ -168,7 +168,7 @@ class GLTFLoader extends EventDispatcher {
}
var
parser
=
//
new GLTFParser(json, extensions);
var
parser
//=
new GLTFParser(json, extensions);
parser
.
parse
(
function
(
scene
,
scenes
,
cameras
,
animations
,
json
)
{
...
...
@@ -191,235 +191,177 @@ class GLTFLoader extends EventDispatcher {
}
}
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material
*/
function
createDefaultMaterial
()
{
// return new THREE.MeshStandardMaterial({
// color: 0xFFFFFF,
// emissive: 0x000000,
// metalness: 1,
// roughness: 1,
// transparent: false,
// depthTest: true,
// side: THREE.FrontSide
// });
return
new
LightMaterial
({
color
:
0xFFFFFF
,
side
:
0
})
}
THREE
.
GLTFLoader
=
(
function
()
{
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
*
* @param {THREE.BufferGeometry} geometry
* @param {Array<GLTF.Target>} targets
* @param {Array<THREE.BufferAttribute>} accessors
*/
function
addMorphTargets
(
geometry
,
targets
,
accessors
)
{
var
hasMorphPosition
=
false
;
var
hasMorphNormal
=
false
;
for
(
var
i
=
0
,
il
=
targets
.
length
;
i
<
il
;
i
++
)
{
/*********************************/
/********** INTERPOLATION ********/
/*********************************/
var
target
=
targets
[
i
];
// Spline Interpolation
// Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation
function
GLTFCubicSplineInterpolant
(
parameterPositions
,
sampleValues
,
sampleSize
,
resultBuffer
)
{
if
(
target
.
POSITION
!==
undefined
)
hasMorphPosition
=
true
;
if
(
target
.
NORMAL
!==
undefined
)
hasMorphNormal
=
true
;
THREE
.
Interpolant
.
call
(
this
,
parameterPositions
,
sampleValues
,
sampleSize
,
resultBuffer
)
;
if
(
hasMorphPosition
&&
hasMorphNormal
)
break
;
}
GLTFCubicSplineInterpolant
.
prototype
=
Object
.
create
(
THREE
.
Interpolant
.
prototype
);
GLTFCubicSplineInterpolant
.
prototype
.
constructor
=
GLTFCubicSplineInterpolant
;
if
(
!
hasMorphPosition
&&
!
hasMorphNormal
)
return
;
GLTFCubicSplineInterpolant
.
prototype
.
copySampleValue_
=
function
(
index
)
{
var
morphPositions
=
[];
var
morphNormals
=
[];
// Copies a sample value to the result buffer. See description of glTF
// CUBICSPLINE values layout in interpolate_() function below.
for
(
var
i
=
0
,
il
=
targets
.
length
;
i
<
il
;
i
++
)
{
var
result
=
this
.
resultBuffer
,
values
=
this
.
sampleValues
,
valueSize
=
this
.
valueSize
,
offset
=
index
*
valueSize
*
3
+
valueSize
;
var
target
=
targets
[
i
];
var
attributeName
=
'morphTarget'
+
i
;
for
(
var
i
=
0
;
i
!==
valueSize
;
i
++
)
{
if
(
hasMorphPosition
)
{
result
[
i
]
=
values
[
offset
+
i
];
// Three.js morph position is absolute value. The formula is
// basePosition
// + weight0 * ( morphPosition0 - basePosition )
// + weight1 * ( morphPosition1 - basePosition )
// ...
// while the glTF one is relative
// basePosition
// + weight0 * glTFmorphPosition0
// + weight1 * glTFmorphPosition1
// ...
// then we need to convert from relative to absolute here.
}
return
result
;
};
if
(
target
.
POSITION
!==
undefined
)
{
GLTFCubicSplineInterpolant
.
prototype
.
beforeStart_
=
GLTFCubicSplineInterpolant
.
prototype
.
copySampleValue_
;
// Cloning not to pollute original accessor
var
positionAttribute
=
cloneBufferAttribute
(
accessors
[
target
.
POSITION
]);
positionAttribute
.
name
=
attributeName
;
GLTFCubicSplineInterpolant
.
prototype
.
afterEnd_
=
GLTFCubicSplineInterpolant
.
prototype
.
copySampleValue_
;
var
position
=
geometry
.
attributes
.
position
;
GLTFCubicSplineInterpolant
.
prototype
.
interpolate_
=
function
(
i1
,
t0
,
t
,
t1
)
{
for
(
var
j
=
0
,
jl
=
positionAttribute
.
count
;
j
<
jl
;
j
++
)
{
var
result
=
this
.
resultBuffer
;
var
values
=
this
.
sampleValues
;
var
stride
=
this
.
valueSize
;
positionAttribute
.
setXYZ
(
j
,
positionAttribute
.
getX
(
j
)
+
position
.
getX
(
j
),
positionAttribute
.
getY
(
j
)
+
position
.
getY
(
j
),
positionAttribute
.
getZ
(
j
)
+
position
.
getZ
(
j
)
);
var
stride2
=
stride
*
2
;
var
stride3
=
stride
*
3
;
var
td
=
t1
-
t0
;
var
p
=
(
t
-
t0
)
/
td
;
var
pp
=
p
*
p
;
var
ppp
=
pp
*
p
;
var
offset1
=
i1
*
stride3
;
var
offset0
=
offset1
-
stride3
;
}
var
s0
=
2
*
ppp
-
3
*
pp
+
1
;
var
s1
=
ppp
-
2
*
pp
+
p
;
var
s2
=
-
2
*
ppp
+
3
*
pp
;
var
s3
=
ppp
-
pp
;
}
else
{
// Layout of keyframe output values for CUBICSPLINE animations:
// [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ]
for
(
var
i
=
0
;
i
!==
stride
;
i
++
)
{
positionAttribute
=
geometry
.
attributes
.
position
;
var
p0
=
values
[
offset0
+
i
+
stride
];
// splineVertex_k
var
m0
=
values
[
offset0
+
i
+
stride2
]
*
td
;
// outTangent_k * (t_k+1 - t_k)
var
p1
=
values
[
offset1
+
i
+
stride
];
// splineVertex_k+1
var
m1
=
values
[
offset1
+
i
]
*
td
;
// inTangent_k+1 * (t_k+1 - t_k)
}
result
[
i
]
=
s0
*
p0
+
s1
*
m0
+
s2
*
p1
+
s3
*
m1
;
morphPositions
.
push
(
positionAttribute
)
;
}
return
result
;
};
if
(
hasMorphNormal
)
{
// see target.POSITION's comment
var
normalAttribute
;
if
(
target
.
NORMAL
!==
undefined
)
{
var
normalAttribute
=
cloneBufferAttribute
(
accessors
[
target
.
NORMAL
]);
normalAttribute
.
name
=
attributeName
;
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material
*/
function
createDefaultMaterial
()
{
// return new THREE.MeshStandardMaterial({
// color: 0xFFFFFF,
// emissive: 0x000000,
// metalness: 1,
// roughness: 1,
// transparent: false,
// depthTest: true,
// side: THREE.FrontSide
// });
return
new
LightMaterial
({
color
:
0xFFFFFF
,
side
:
0
})
var
normal
=
geometry
.
attributes
.
normal
;
}
for
(
var
j
=
0
,
jl
=
normalAttribute
.
count
;
j
<
jl
;
j
++
)
{
/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
*
* @param {THREE.BufferGeometry} geometry
* @param {Array<GLTF.Target>} targets
* @param {Array<THREE.BufferAttribute>} accessors
*/
function
addMorphTargets
(
geometry
,
targets
,
accessors
)
{
normalAttribute
.
setXYZ
(
j
,
normalAttribute
.
getX
(
j
)
+
normal
.
getX
(
j
),
normalAttribute
.
getY
(
j
)
+
normal
.
getY
(
j
),
normalAttribute
.
getZ
(
j
)
+
normal
.
getZ
(
j
)
);
var
hasMorphPosition
=
false
;
var
hasMorphNormal
=
false
;
}
for
(
var
i
=
0
,
il
=
targets
.
length
;
i
<
il
;
i
++
)
{
}
else
{
var
target
=
targets
[
i
]
;
normalAttribute
=
geometry
.
attributes
.
normal
;
if
(
target
.
POSITION
!==
undefined
)
hasMorphPosition
=
true
;
if
(
target
.
NORMAL
!==
undefined
)
hasMorphNormal
=
true
;
}
if
(
hasMorphPosition
&&
hasMorphNormal
)
break
;
morphNormals
.
push
(
normalAttribute
)
;
}
if
(
!
hasMorphPosition
&&
!
hasMorphNormal
)
return
;
var
morphPositions
=
[];
var
morphNormals
=
[];
for
(
var
i
=
0
,
il
=
targets
.
length
;
i
<
il
;
i
++
)
{
var
target
=
targets
[
i
];
var
attributeName
=
'morphTarget'
+
i
;
if
(
hasMorphPosition
)
{
// Three.js morph position is absolute value. The formula is
// basePosition
// + weight0 * ( morphPosition0 - basePosition )
// + weight1 * ( morphPosition1 - basePosition )
// ...
// while the glTF one is relative
// basePosition
// + weight0 * glTFmorphPosition0
// + weight1 * glTFmorphPosition1
// ...
// then we need to convert from relative to absolute here.
if
(
target
.
POSITION
!==
undefined
)
{
// Cloning not to pollute original accessor
var
positionAttribute
=
cloneBufferAttribute
(
accessors
[
target
.
POSITION
]);
positionAttribute
.
name
=
attributeName
;
}
var
position
=
geometry
.
attributes
.
position
;
if
(
hasMorphPosition
)
geometry
.
morphAttributes
.
position
=
morphPositions
;
if
(
hasMorphNormal
)
geometry
.
morphAttributes
.
normal
=
morphNormals
;
for
(
var
j
=
0
,
jl
=
positionAttribute
.
count
;
j
<
jl
;
j
++
)
{
}
positionAttribute
.
setXYZ
(
j
,
positionAttribute
.
getX
(
j
)
+
position
.
getX
(
j
),
positionAttribute
.
getY
(
j
)
+
position
.
getY
(
j
),
positionAttribute
.
getZ
(
j
)
+
position
.
getZ
(
j
)
);
}
function
cloneBufferAttribute
(
attribute
)
{
}
else
{
if
(
attribute
.
isInterleavedBufferAttribute
)
{
positionAttribute
=
geometry
.
attributes
.
position
;
var
count
=
attribute
.
count
;
var
itemSize
=
attribute
.
itemSize
;
var
array
=
attribute
.
array
.
slice
(
0
,
count
*
itemSize
);
}
for
(
var
i
=
0
;
i
<
count
;
++
i
)
{
morphPositions
.
push
(
positionAttribute
);
array
[
i
]
=
attribute
.
getX
(
i
);
if
(
itemSize
>=
2
)
array
[
i
+
1
]
=
attribute
.
getY
(
i
);
if
(
itemSize
>=
3
)
array
[
i
+
2
]
=
attribute
.
getZ
(
i
);
if
(
itemSize
>=
4
)
array
[
i
+
3
]
=
attribute
.
getW
(
i
);
}
if
(
hasMorphNormal
)
{
// see target.POSITION's comment
}
var
normalAttribute
;
return
new
THREE
.
BufferAttribute
(
array
,
itemSize
,
attribute
.
normalized
)
;
if
(
target
.
NORMAL
!==
undefined
)
{
}
var
normalAttribute
=
cloneBufferAttribute
(
accessors
[
target
.
NORMAL
]);
normalAttribute
.
name
=
attributeName
;
return
attribute
.
clone
();
var
normal
=
geometry
.
attributes
.
normal
;
}
for
(
var
j
=
0
,
jl
=
normalAttribute
.
count
;
j
<
jl
;
j
++
)
{
THREE
.
GLTFLoader
=
(
function
(
)
{
normalAttribute
.
setXYZ
(
j
,
normalAttribute
.
getX
(
j
)
+
normal
.
getX
(
j
),
normalAttribute
.
getY
(
j
)
+
normal
.
getY
(
j
),
normalAttribute
.
getZ
(
j
)
+
normal
.
getZ
(
j
)
);
}
}
else
{
normalAttribute
=
geometry
.
attributes
.
normal
;
}
morphNormals
.
push
(
normalAttribute
);
}
}
if
(
hasMorphPosition
)
geometry
.
morphAttributes
.
position
=
morphPositions
;
if
(
hasMorphNormal
)
geometry
.
morphAttributes
.
normal
=
morphNormals
;
}
/**
* @param {THREE.Mesh} mesh
...
...
@@ -546,30 +488,6 @@ THREE.GLTFLoader = (function () {
}
function
cloneBufferAttribute
(
attribute
)
{
if
(
attribute
.
isInterleavedBufferAttribute
)
{
var
count
=
attribute
.
count
;
var
itemSize
=
attribute
.
itemSize
;
var
array
=
attribute
.
array
.
slice
(
0
,
count
*
itemSize
);
for
(
var
i
=
0
;
i
<
count
;
++
i
)
{
array
[
i
]
=
attribute
.
getX
(
i
);
if
(
itemSize
>=
2
)
array
[
i
+
1
]
=
attribute
.
getY
(
i
);
if
(
itemSize
>=
3
)
array
[
i
+
2
]
=
attribute
.
getZ
(
i
);
if
(
itemSize
>=
4
)
array
[
i
+
3
]
=
attribute
.
getW
(
i
);
}
return
new
THREE
.
BufferAttribute
(
array
,
itemSize
,
attribute
.
normalized
);
}
return
attribute
.
clone
();
}
/**
* Checks if we can build a single Mesh with MultiMaterial from multiple primitives.
...
...
@@ -1122,7 +1040,7 @@ THREE.GLTFLoader = (function () {
});
}).
then
(
function
(
texture
:
any
)
{
}).
then
(
function
(
texture
:
any
)
{
// Clean up resources and configure Texture.
...
...
@@ -1187,7 +1105,7 @@ THREE.GLTFLoader = (function () {
var
materialDef
=
json
.
materials
[
materialIndex
];
var
materialType
;
var
materialParams
:
any
=
{};
var
materialParams
:
any
=
{};
var
materialExtensions
=
materialDef
.
extensions
||
{};
var
pending
=
[];
...
...
@@ -1455,7 +1373,7 @@ THREE.GLTFLoader = (function () {
addPrimitiveAttributes
(
geometry
,
primitive
,
accessors
);
var
geometryPromise
:
any
=
Promise
.
resolve
(
geometry
);
var
geometryPromise
:
any
=
Promise
.
resolve
(
geometry
);
// Cache this geometry
cache
.
push
({
primitive
:
primitive
,
promise
:
geometryPromise
});
...
...
@@ -1832,7 +1750,7 @@ THREE.GLTFLoader = (function () {
var
skinDef
=
this
.
json
.
skins
[
skinIndex
];
var
skinEntry
:
any
=
{
joints
:
skinDef
.
joints
};
var
skinEntry
:
any
=
{
joints
:
skinDef
.
joints
};
if
(
skinDef
.
inverseBindMatrices
===
undefined
)
{
...
...
src/3D/gltf/Interpolant.ts
0 → 100644
View file @
01a093d8
export
class
InterInterpolant
{
parameterPositions
:
any
;
_cachedIndex
:
number
;
resultBuffer
:
any
;
sampleValues
:
any
;
valueSize
:
any
;
constructor
(
parameterPositions
,
sampleValues
,
sampleSize
,
resultBuffer
)
{
this
.
parameterPositions
=
parameterPositions
;
this
.
_cachedIndex
=
0
;
this
.
resultBuffer
=
resultBuffer
!==
undefined
?
resultBuffer
:
new
sampleValues
.
constructor
(
sampleSize
);
this
.
sampleValues
=
sampleValues
;
this
.
valueSize
=
sampleSize
;
}
evaluate
(
t
)
{
var
pp
=
this
.
parameterPositions
,
i1
=
this
.
_cachedIndex
,
t1
=
pp
[
i1
],
t0
=
pp
[
i1
-
1
];
validate_interval
:
{
seek
:
{
var
right
;
linear_scan
:
{
//- See http://jsperf.com/comparison-to-undefined/3
//- slower code:
//-
//- if ( t >= t1 || t1 === undefined ) {
forward_scan
:
if
(
!
(
t
<
t1
))
{
for
(
var
giveUpAt
=
i1
+
2
;
;)
{
if
(
t1
===
undefined
)
{
if
(
t
<
t0
)
break
forward_scan
;
// after end
i1
=
pp
.
length
;
this
.
_cachedIndex
=
i1
;
return
this
.
afterEnd_
(
i1
-
1
/*, t, t0*/
);
}
if
(
i1
===
giveUpAt
)
break
;
// this loop
t0
=
t1
;
t1
=
pp
[
++
i1
];
if
(
t
<
t1
)
{
// we have arrived at the sought interval
break
seek
;
}
}
// prepare binary search on the right side of the index
right
=
pp
.
length
;
break
linear_scan
;
}
//- slower code:
//- if ( t < t0 || t0 === undefined ) {
if
(
!
(
t
>=
t0
))
{
// looping?
var
t1global
=
pp
[
1
];
if
(
t
<
t1global
)
{
i1
=
2
;
// + 1, using the scan for the details
t0
=
t1global
;
}
// linear reverse scan
for
(
var
giveUpAt
=
i1
-
2
;
;)
{
if
(
t0
===
undefined
)
{
// before start
this
.
_cachedIndex
=
0
;
return
this
.
beforeStart_
(
0
/*, t, t1*/
);
}
if
(
i1
===
giveUpAt
)
break
;
// this loop
t1
=
t0
;
t0
=
pp
[
--
i1
-
1
];
if
(
t
>=
t0
)
{
// we have arrived at the sought interval
break
seek
;
}
}
// prepare binary search on the left side of the index
right
=
i1
;
i1
=
0
;
break
linear_scan
;
}
// the interval is valid
break
validate_interval
;
}
// linear scan
// binary search
while
(
i1
<
right
)
{
var
mid
=
(
i1
+
right
)
>>>
1
;
if
(
t
<
pp
[
mid
])
{
right
=
mid
;
}
else
{
i1
=
mid
+
1
;
}
}
t1
=
pp
[
i1
];
t0
=
pp
[
i1
-
1
];
// check boundary cases, again
if
(
t0
===
undefined
)
{
this
.
_cachedIndex
=
0
;
return
this
.
beforeStart_
(
0
/*, t, t1*/
);
}
if
(
t1
===
undefined
)
{
i1
=
pp
.
length
;
this
.
_cachedIndex
=
i1
;
return
this
.
afterEnd_
(
i1
-
1
/*, t0, t*/
);
}
}
// seek
this
.
_cachedIndex
=
i1
;
this
.
intervalChanged_
(
i1
,
t0
,
t1
);
}
// validate_interval
return
this
.
interpolate_
(
i1
,
t0
,
t
,
t1
);
}
settings
=
null
;
DefaultSettings_
=
{};
getSettings_
()
{
return
this
.
settings
||
this
.
DefaultSettings_
;
};
copySampleValue_
(
index
)
{
// copies a sample value to the result buffer
var
result
=
this
.
resultBuffer
,
values
=
this
.
sampleValues
,
stride
=
this
.
valueSize
,
offset
=
index
*
stride
;
for
(
var
i
=
0
;
i
!==
stride
;
++
i
)
{
result
[
i
]
=
values
[
offset
+
i
];
}
return
result
;
};
// Template methods for derived classes:
interpolate_
(
i1
,
t0
,
t
,
t1
)
{
throw
new
Error
(
'call to abstract method'
);
// implementations shall return this.resultBuffer
};
intervalChanged_
(
i1
,
t0
,
t1
)
{
// empty
}
beforeStart_
=
this
.
copySampleValue_
;
//( N-1, tN-1, t ), returns this.resultBuffer
afterEnd_
=
this
.
copySampleValue_
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment