Commit 01a093d8 authored by wjf's avatar wjf

l

parent 0cc8f760
......@@ -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]
......
......@@ -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) {
......
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
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
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
......@@ -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 () {
......
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;
};
}
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) {
......
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_;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment