AnimationEditor.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. import * as THREE from "../../../../libs/three.js/build/three.module.js";
  2. import math from '../../utils/math.js'
  3. import Tween from '../../utils/Tween.js'
  4. import {easing, lerp} from '../../utils/transitions.js'
  5. //有的动画,如小狗,进来如果不play停在第一帧,mesh会错,爪子在前面;但如果都停在第一帧,动作有可能很奇怪
  6. const tweens = {}
  7. const maxClipFadeTime = Potree.settings.maxClipFadeTime//渐变时间 s
  8. /* const pathStates = new Map */
  9. //actions中可能包含没有动作的 如TPose
  10. //包括无动画的模型在内的各项属性的过渡
  11. const rot90Qua = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0),-Math.PI/2)
  12. export default class AnimationEditor extends THREE.EventDispatcher{
  13. constructor(){
  14. super()
  15. this.poseKeys = new Map //transform
  16. this.descKeys = new Map //字幕
  17. this.pathKeys = new Map //之前设置好的Path , 优先级高于pose
  18. this.clipKeys = new Map //glb animation actions
  19. this.duration = 0 //动画时长
  20. this.time = 0 //当前播放时间
  21. this.cursorTime = 0 //时间轴指针时间
  22. this.keepDistance = true //focus的物体和相机保持不变的距离
  23. this.poseTransition = false //pose缓动
  24. if(Potree.settings.isOfficial){
  25. viewer.modules.MergeEditor.bus.addEventListener('changeSelect',()=>{
  26. let targetObject = viewer.modules.MergeEditor.selected
  27. targetObject = this.ifContainsModel(targetObject) ? targetObject : null
  28. this.setCameraFollow(targetObject)
  29. })
  30. }
  31. }
  32. addKey(model, keyType, key ){
  33. let keys = this[keyType+'Keys'].get(model)
  34. if(!keys){
  35. keys = []
  36. }
  37. let index = keys.findIndex(e=>e.time>key.time)
  38. if(index == -1){
  39. index = keys.length
  40. }
  41. keys = [...keys.slice(0,index), key, ...keys.slice(index,keys.length)]
  42. this[keyType+'Keys'].set(model,keys)
  43. this.updateTimeRange()
  44. }
  45. removeKey(model, keyType, key ){
  46. let keys = this[keyType+'Keys'].get(model)
  47. if(!keys)return console.warn('removeKey没找到key')
  48. let index = keys.indexOf(key)
  49. if(index > -1){
  50. if(keyType == 'clip'){
  51. key.action.stop()
  52. }
  53. keys.splice(index,1)
  54. this.updateTimeRange()
  55. }
  56. }
  57. reOrderKey(model, keyType, key ){
  58. this.removeKey(model, keyType, key )
  59. this.addKey(model, keyType, key )
  60. }
  61. at(time, delta, force){
  62. this.dispatchEvent({type:'atTime', time}) //该时间可以大于本动画持续时间
  63. this.cursorTime = time
  64. /* if(time > this.duration + maxClipFadeTime/2){
  65. for(let [model, keys] of this.clipKeys){
  66. model.actions.forEach(a=>a.stop())
  67. }
  68. } */
  69. let maxTime = this.duration+maxClipFadeTime/2
  70. if(time >= maxTime) time = maxTime
  71. if(this.time == time && !force)return
  72. this.time = time //真实值
  73. let oldDisToCam = this.camFollowObject?.length == 1 && this.keepDistance && this.camFollowObject[0].boundCenter.distanceTo(viewer.mainViewport.view.position)
  74. let transitionRatio = 0.05 * delta * 60 //渐变系数,越小缓动程度越高,越平滑 //假设标准帧率为60fps,当帧率低时(delta大时) 降低缓动。速度快时缓动太高会偏移路径
  75. let transitionRatio2 = 0.8 * delta * 60
  76. let posePathModels = [];
  77. [this.poseKeys, this.pathKeys/* , this.clipKeys */].forEach((map)=>{
  78. Array.from(map.keys()).forEach(model=>{
  79. posePathModels.includes(model) || posePathModels.push(model)
  80. })
  81. })
  82. /*
  83. 路径>关键帧。但是如果每条路径开头和结尾以及过渡时没有关键帧,保持路径开头和结尾的姿态
  84. */
  85. posePathModels.forEach(model=>{
  86. let pathKeys = this.pathKeys.get(model) || []
  87. let poseKeys = this.poseKeys.get(model) || []
  88. let atPath //是否在path中 至多只有一个
  89. let lastPath
  90. let nextPath
  91. if(pathKeys.length){
  92. pathKeys.find(key=>{
  93. if(key.path.points.length < 2) return
  94. let startToFade = key.time - maxClipFadeTime/2
  95. let endFade = key.time + key.dur + maxClipFadeTime/2
  96. atPath = time >= key.time && time <= key.time + key.dur
  97. if(atPath){
  98. atPath = key //找到一个就退出
  99. return true
  100. }
  101. if(key.time + key.dur < time) lastPath = key
  102. else if(key.time > time && !nextPath) nextPath = key
  103. })
  104. }
  105. if(poseKeys.length){
  106. tweens.scale = new Tween(poseKeys.map(e=>e.time), poseKeys.map(e=>e.scale))
  107. model.scale.copy(tweens.scale.lerp(time))
  108. }else{
  109. /* if(pathKeys.length){
  110. model.quaternion.copy(model.defaultAniPose?.quaternion || new THREE.Quaternion()) //设置路径朝向前要先还原
  111. } */
  112. }
  113. if(atPath){//沿着curve行走,目视curve前方 (参照CameraAnimationCurve,搜quaFromCurveTan)
  114. let percent = THREE.Math.clamp((time - atPath.time) / atPath.dur, 0, 1)
  115. let {position , quaternion} = this.getPoseAtPathKey(atPath, percent, model) //模型文件先保证其center在脚底,如果要我手动将bound底部对齐路径高度再说
  116. model.position.copy(position);
  117. model.quaternion.copy(quaternion)
  118. model.atPath = atPath
  119. }else{
  120. model.atPath = null
  121. poseKeys = poseKeys.slice()
  122. let addPathToPoseKey = (pathKey, percent)=>{ //把当前前后的path姿态加入帧
  123. let {position , quaternion} = this.getPoseAtPathKey(pathKey, percent, model)
  124. let fakeKey = {
  125. isPath : true,
  126. time: pathKey.time + pathKey.dur * percent,
  127. pos:position , qua:quaternion
  128. }
  129. let index = poseKeys.findIndex(e=>e.time > fakeKey.time)
  130. if(index == -1){
  131. index = poseKeys.length
  132. }
  133. poseKeys = [...poseKeys.slice(0,index), fakeKey, ...poseKeys.slice(index,poseKeys.length)]
  134. }
  135. lastPath && addPathToPoseKey(lastPath, 1)
  136. nextPath && addPathToPoseKey(nextPath, 0)
  137. if(poseKeys.length){
  138. tweens.pos = new Tween(poseKeys.map(e=>e.time), poseKeys.map(e=>e.pos))
  139. model.position.copy(tweens.pos.lerp(time))
  140. tweens.qua = new Tween(poseKeys.map(e=>e.time), poseKeys.map(e=>e.qua))
  141. model.quaternion.copy(tweens.qua.lerp(time))
  142. /* let poseKeys2 = poseKeys.filter(e=>e.isPath)//妈呀为什么这么写我忘了
  143. if(poseKeys2.length ){
  144. tweens.qua = new Tween(poseKeys2.map(e=>e.time), poseKeys2.map(e=>e.qua))
  145. model.quaternion.copy(tweens.qua.lerp(time))
  146. } */
  147. }
  148. }
  149. if(poseKeys.length || pathKeys.length){
  150. model.dispatchEvent('position_changed')
  151. model.dispatchEvent('rotation_changed')
  152. }
  153. })
  154. for(let [model, keys] of this.clipKeys){
  155. if(keys.length == 0) continue
  156. let weights = keys.map((key,i)=>{ //计算每个动作权重(幅度)。
  157. /* if(delta == void 0){//无缓动 但会造成和缓动时动作time不同
  158. return time >= key.time && time <= key.time + key.dur ? 1 : 0
  159. } */
  160. key.index_ = i
  161. let fadeTimeStart = Math.min(maxClipFadeTime, key.dur, (keys[i-1]?.dur || maxClipFadeTime )) / 2 //过渡时间不超过当前和前一个的 half of dur
  162. let fadeTimeEnd = Math.min(maxClipFadeTime, key.dur, (keys[i+1]?.dur || maxClipFadeTime )) / 2 //过渡时间不超过当前和后一个的 half of dur
  163. let startTime1 = key.time - fadeTimeStart
  164. let endTime1 = key.time + key.dur + fadeTimeEnd
  165. let startTime2 = key.time + fadeTimeStart
  166. let endTime2 = key.time + key.dur - fadeTimeEnd
  167. key.action.tempSW_ = {scale:0,weight:0,time: null, sameLinks:[]},
  168. key.tempTime_ = THREE.Math.clamp(time - key.time, 0, key.dur) //time - startTime1 //当前动作时间
  169. key.startTime1 = startTime1
  170. key.endTime1 = endTime1
  171. if(i==0 && time<startTime2){//开始前维持第一个动作
  172. return 1
  173. }else if(i == keys.length-1 && time > endTime2){//所有动作播完后维持最后一个动作
  174. return 1
  175. }else{
  176. if(time < startTime1 || time > endTime1)return 0 //out bound
  177. if(time >= startTime2 && time <= endTime2 ) return 1
  178. if(time < startTime2 ){
  179. return Potree.math.linearClamp(time, [startTime1,startTime2],[0,1])
  180. }else{
  181. return Potree.math.linearClamp(time, [endTime2,endTime1],[1,0])
  182. }
  183. }
  184. })//最多有两个>0的,在过渡
  185. let animateActions = [] //在播的动作
  186. keys.forEach((key,i)=>{ weights[i]>0 && !animateActions.includes(key.action) && (key.action.tempSW_ = {scale:0,weight:0,time: null, sameLinks:[]}, animateActions.push(key.action) )})
  187. //万一前后是一个动作…… 所以用tempSW_计算总值
  188. keys.forEach((key,i)=>{ //要找到当前action之前所有不间断的所有key,他们之间要连续播放
  189. if(animateActions.includes(key.action)){
  190. if(key.startTime1 < time){//已播部分的key
  191. let last = key.action.tempSW_.sameLinks[key.action.tempSW_.sameLinks.length - 1]
  192. if(last){
  193. if( key.index_ == last.index_ + 1 && key.startTime1 <= last.endTime1 ){ //相连
  194. key.action.tempSW_.sameLinks.push(key)
  195. }else{
  196. key.action.tempSW_.sameLinks = [key] //clear
  197. }
  198. }else{
  199. key.action.tempSW_.sameLinks = [key]
  200. }
  201. }
  202. }
  203. })
  204. keys.forEach((key,i)=>{
  205. if(animateActions.includes(key.action)){
  206. let weight = weights[i] * key.weight //权重乘以自身幅度
  207. if(weight>0){//最多两个
  208. key.action.play()
  209. key.action.paused = true //停在某帧 //如果没有点击该动作块的话 不停
  210. key.action.tempSW_.weight += weight
  211. key.tempTime_ >= 0 && (key.action.tempSW_.scale = key.speed) //相同动作不允许叠加速度
  212. if(key.action.tempSW_.time == null){//如果两个动作相同 只需在第一个计算出总和
  213. let timeSum = 0
  214. key.action.tempSW_.sameLinks.forEach(key_ =>{
  215. timeSum += (key_.tempTime_ % (key_.action._clip.duration / key_.speed)) * key_.speed //相同动作可能速度不同,算出每个clip的时间
  216. })
  217. key.action.tempSW_.time = timeSum % key.action._clip.duration
  218. }
  219. //(老版本,过渡时播放时间会延长一点,有交集):
  220. //key.action.tempSW_.time == null && (key.action.tempSW_.time = key.tempTime_) //相同动作优先用前一个的时间
  221. //key.action.tempSW_.scale += key.speed // * weights[i] //乘以weight在开始和结束作为缓动效果好,但是不好计算实时time
  222. //speed time都没有交集,只有weight有,为了过渡
  223. }
  224. }else{
  225. key.action.stop() //不启动动画
  226. }
  227. })
  228. animateActions.forEach(action=>{
  229. action.setEffectiveTimeScale(action.tempSW_.scale) //speed 只有没paused时有效 这里都paused的所以没用
  230. action.setEffectiveWeight(action.tempSW_.weight );
  231. action.time = action.tempSW_.time //(action.tempSW_.time % (action._clip.duration / action.tempSW_.scale)) * action.tempSW_.scale //只有paused时有效
  232. //console.log('action', action._clip.name, action.time, action.weight, action.tempSW_.scale )
  233. })
  234. //model.mixer.timeScale = 1 ;
  235. }
  236. viewer.objs.children.forEach(obj=>{
  237. if(!obj.actions?.length)return
  238. let clipState = obj.actions.map(action=>{
  239. let played = action._mixer._isActiveAction( action );
  240. let paused = action.paused
  241. let time = action.time
  242. let weight = action.weight
  243. return {played,paused,time,weight}
  244. })
  245. clipState = JSON.stringify(clipState)
  246. if(obj.clipState != clipState){//动作是否改变
  247. obj.traverse(e=>e.isSkinnedMesh && (e.boundingSphere = null)) //动画会导致bound改变,清空,raycast时重新计算bound,否则hover不到模型
  248. obj.clipChanged = true
  249. }
  250. obj.clipState = clipState
  251. })
  252. {
  253. if(this.camFollowObject && !viewer.scene.monitors.some(e=>e.isWatching)){//in front of model
  254. if(this.camFollowObject.length == 1){
  255. let model = this.camFollowObject[0]
  256. if(viewer.images360.latestRequestMode == 'showPointCloud'){
  257. if(this.camFaceToObject){
  258. let dis = 4;
  259. let dir = new THREE.Vector3(0,0.1,1).normalize()//稍微朝上
  260. dir.multiplyScalar(dis).applyQuaternion(model.quaternion)
  261. let pos = new THREE.Vector3().addVectors(model.boundCenter, dir)
  262. viewer.mainViewport.view.position.copy(pos)
  263. viewer.mainViewport.view.lookAt(model.boundCenter)
  264. }else if(this.keepDistance){ //不改镜头方向 保持一定角度。如果要改镜头方向,把lookAt提前
  265. viewer.mainViewport.view.position.subVectors(model.boundCenter, viewer.mainViewport.view.direction.clone().multiplyScalar(oldDisToCam))
  266. viewer.mainViewport.view.radius = oldDisToCam
  267. }else{
  268. viewer.mainViewport.view.lookAt(model.boundCenter)
  269. }
  270. }else{
  271. viewer.mainViewport.view.lookAt(model.boundCenter)
  272. }
  273. }else{
  274. viewer.modules.MergeEditor.focusOn(this.camFollowObject, 0, true/* ,false,dirAve */)
  275. }
  276. }
  277. }
  278. viewer.dispatchEvent('content_changed')
  279. }
  280. getPoseAtPathKey(key, percent, model){
  281. let delta = 0.001
  282. let percent2 = percent + delta
  283. let curve = key.path.curve.clone()
  284. if(key.reverse) curve.points.reverse()
  285. let position = curve.getPointAt(percent);
  286. let pathQua, quaternion
  287. if(percent2 <= 1){
  288. let position2 = curve.getPointAt(percent2);
  289. pathQua = math.getQuaFromPosAim(position2, position)
  290. }else{
  291. percent2 = percent - delta
  292. let position2 = curve.getPointAt(percent2);
  293. pathQua = math.getQuaFromPosAim(position, position2)
  294. }
  295. pathQua.multiplyQuaternions( pathQua, rot90Qua ); //这是当模型导进来就旋转正确时的quaternion
  296. key.curQua_ = pathQua.clone() //记录下
  297. if(model.quaAtPath){
  298. quaternion = new THREE.Quaternion().multiplyQuaternions(pathQua, model.quaAtPath)
  299. }else{
  300. quaternion = pathQua.clone()
  301. }
  302. //model && quaternion.multiplyQuaternions( quaternion, model.quaternion ); //应用当前已有的quaternion
  303. //如果要将模型底部中心对准路径,需要先修改好模型scale ,然后boundingBox中心应用scale和qua, 加到position里
  304. //目前两个人物模型刚好模型pivot在脚底,如果是其他物体甚至直接用curve的朝向不太对,没有明确朝向。除非所有模型都保持上路径前的朝向
  305. //或者pos的z还用之前的
  306. //产品说位置偏移不管它,因为路径可以隐藏和修改。只要记录相对旋转即可。
  307. return {position, quaternion}
  308. }
  309. getModelQuaAtPath(model){ //当前时间在路径上时,旋转模型后立即执行该函数,获取相对旋转值
  310. if(!model.atPath)return
  311. let qua = new THREE.Quaternion().multiplyQuaternions(model.atPath.curQua_.clone().invert(), model.quaternion)
  312. //console.log('getModelQuaAtPath',qua)
  313. model.quaAtPath = qua //相对旋转
  314. return qua
  315. }
  316. play({ time = -maxClipFadeTime/2}={}){//动画时长比duration多一个maxClipFadeTime,为了给开始和结束动画过渡
  317. this.updateTimeRange()
  318. this.playing && this.pause()
  319. let maxTime = this.duration+maxClipFadeTime/2
  320. this.playing = true
  321. this.cursorTime = time
  322. this.onUpdate = (e)=>{
  323. this.cursorTime += e.delta
  324. if(!Potree.settings.isOfficial && time > maxTime) this.cursorTime = maxTime
  325. this.at(this.cursorTime, e.delta)
  326. if(!Potree.settings.isOfficial && time > maxTime) {
  327. this.dispatchEvent('stop')
  328. for(let [model, keys] of this.clipKeys){
  329. model.actions.forEach(a=>a.stop())
  330. }
  331. this.pause()
  332. }
  333. }
  334. viewer.addEventListener("update_start", this.onUpdate);
  335. }
  336. pause(){
  337. this.playing = false
  338. viewer.removeEventListener("update_start", this.onUpdate);
  339. /* for(let [model, keys] of this.clipKeys){
  340. model.actions.forEach(a=>a.stop())
  341. } */
  342. viewer.dispatchEvent('content_changed')
  343. }
  344. setCameraFollow(camFollowObject){//for test
  345. this.camFollowObject = camFollowObject
  346. if(!camFollowObject)return
  347. //Potree.settings.displayMode = 'showPointCloud'
  348. if(!(this.camFollowObject instanceof Array)){//支持相机跟随多个物体,对着bound的中心
  349. this.camFollowObject = [this.camFollowObject]
  350. }
  351. this.camFollowObject = this.camFollowObject.map(object=>{
  352. if(typeof object == 'string'){
  353. return viewer.objs.children.find(e=>e.name == object)
  354. }else{
  355. return object
  356. }
  357. })
  358. }
  359. updateTimeRange(){
  360. let maxTime = 0
  361. for(let [model, keys] of this.poseKeys){
  362. keys.length>0 && (maxTime = Math.max(maxTime, keys[keys.length - 1].time))
  363. }
  364. for(let [model, keys] of this.clipKeys){
  365. keys.length>0 && (maxTime = Math.max(maxTime, keys[keys.length - 1].time + keys[keys.length - 1].dur))
  366. }
  367. for(let [model, keys] of this.pathKeys){
  368. keys.length>0 && (maxTime = Math.max(maxTime, keys[keys.length - 1].time + keys[keys.length - 1].dur))
  369. }
  370. this.duration = maxTime //不算开始和结束动画的过渡时间的话
  371. /* for(let [model, keys] of this.clipKeys){
  372. max = Math.max(maxTime, keys[keys.length - 1].time + keys[keys.length - 1].dur)
  373. } */
  374. }
  375. /* removeModelCallback(model){
  376. this.poseKeys.get
  377. } */
  378. /////////////////////////////////
  379. addPoseKey({model,time,index }={}){
  380. /* if(replace){
  381. this.removeKey(model,'pose', index)
  382. } */
  383. let keys = this.poseKeys.get(model)
  384. if(!keys){
  385. keys = []
  386. }
  387. let key = {
  388. time,
  389. qua: model.quaternion.clone(),
  390. scale: model.scale.clone(),
  391. pos: model.position.clone()
  392. }
  393. if(index == void 0)index = keys.length
  394. keys = [...keys.slice(0,index), key, ...keys.slice(index,keys.length)]
  395. this.poseKeys.set(model,keys)
  396. return key
  397. }
  398. addClipKey({model, time, index, dur, actionIndex, weight=1, speed=1/* , replace */}={}){
  399. /* if(replace){
  400. this.removeKey(model,'clip',index)
  401. } */
  402. let keys = this.clipKeys.get(model)
  403. if(!keys){
  404. keys = []
  405. }
  406. let key = {
  407. time, //startTime
  408. dur,
  409. action: model.actions[actionIndex],
  410. speed, weight,
  411. }
  412. if(index == void 0)index = keys.length
  413. keys = [...keys.slice(0,index), key, ...keys.slice(index,keys.length)]
  414. this.clipKeys.set(model,keys)
  415. }
  416. addPathKey({model, time, index, dur, path/* , replace */ }={}){//what if path is deleted ?
  417. /* if(replace){
  418. this.removeKey(model,'path',index)
  419. } */
  420. let keys = this.pathKeys.get(model)
  421. if(!keys){
  422. keys = []
  423. }
  424. let key = {
  425. time, //startTime
  426. dur,
  427. path,
  428. }
  429. if(index == void 0)index = keys.length
  430. keys = [...keys.slice(0,index), key, ...keys.slice(index,keys.length)]
  431. this.pathKeys.set(model,keys)
  432. }
  433. addDescKey({model, time, index, dur, desc/* , replace */ }={}){
  434. /* if(replace){
  435. this.removeKey(model,'desc',index)
  436. } */
  437. let keys = this.descKeys.get(model)
  438. if(!keys){
  439. keys = []
  440. }
  441. let key = {
  442. time, //startTime
  443. dur,
  444. desc,
  445. }
  446. if(index == void 0)index = keys.length
  447. keys = [...keys.slice(0,index), key, ...keys.slice(index,keys.length)]
  448. this.descKeys.set(model,keys)
  449. }
  450. save(){//for test, 注意保证每个模型名字不同
  451. let data = {poseKeys:{}, clipKeys:{}}
  452. for(let [model, keys] of this.clipKeys){
  453. data.clipKeys[model.name] = keys.map(key=>{
  454. return {
  455. actionIndex: model.actions.indexOf(key.action),
  456. time: key.time, dur:key.dur, weight:key.weight, speed:key.speed
  457. }
  458. })
  459. }
  460. for(let [model, keys] of this.poseKeys){
  461. data.poseKeys[model.name] = keys.map(key=>{
  462. return {
  463. qua: key.qua.toArray(), pos: key.pos.toArray(), scale:key.scale.toArray(),
  464. time: key.time,
  465. }
  466. })
  467. }
  468. console.log(JSON.stringify(data))
  469. return data
  470. }
  471. buildFromData(data){
  472. if(typeof data == 'string'){
  473. data = JSON.parse(data)
  474. }
  475. for(let name in data.poseKeys){
  476. let model = viewer.objs.children.find(e=>e.name == name)
  477. if(!model){
  478. console.warn('没找到pose模型',name)
  479. continue
  480. }
  481. let keys = data.poseKeys[name].map(e=>{
  482. return {
  483. qua: new THREE.Quaternion().fromArray(e.qua),
  484. pos: new THREE.Vector3().fromArray(e.pos),
  485. scale: new THREE.Vector3().fromArray(e.scale),
  486. time: e.time
  487. }
  488. })
  489. this.poseKeys.set(model,keys)
  490. }
  491. for(let name in data.clipKeys){
  492. let model = viewer.objs.children.find(e=>e.name == name)
  493. if(!model){
  494. console.warn('没找到clip模型',name)
  495. continue
  496. }
  497. let keys = data.clipKeys[name].map(e=>{
  498. return {
  499. action: model.actions[e.actionIndex],
  500. time: e.time, dur: e.dur, weight:e.weight, speed:e.speed
  501. }
  502. })
  503. this.clipKeys.set(model,keys)
  504. }
  505. }
  506. ifContainsModel(model){//动画帧里是否包含它
  507. return [this.poseKeys, this.pathKeys, this.clipKeys].some((e)=>{
  508. return e.has(model)
  509. })
  510. }
  511. }
  512. /*
  513. function executeCrossFade( startAction, endAction, duration ) {
  514. // Not only the start action, but also the end action must get a weight of 1 before fading
  515. // (concerning the start action this is already guaranteed in this place)
  516. if ( endAction ) {
  517. setWeight( endAction, 1 );
  518. endAction.time = 0;
  519. if ( startAction ) {
  520. // Crossfade with warping
  521. startAction.crossFadeTo( endAction, duration, true );
  522. } else {
  523. // Fade in
  524. endAction.fadeIn( duration );
  525. }
  526. } else {
  527. // Fade out
  528. startAction.fadeOut( duration );
  529. }
  530. }
  531. function setWeight( action, weight ) {
  532. action.enabled = true;
  533. window.ani1 || action.setEffectiveTimeScale( 1 );
  534. action.setEffectiveWeight( weight );
  535. } */
  536. /* autoActionSpeed(action){ //要获取这段时间走过的路程很难,还是延期吧. 而且一段动作要对应多个速度不同的位移,是不可能的。
  537. return dis / dur
  538. } */
  539. /*
  540. 动作自动计算步伐 幅度(weight)或 速度
  541. timeScale * modelStepSizeRatio * weight = dis / dur
  542. 速度 每个模型的步长系数 幅度
  543. 如果人的bone attach 物品,物品就被add到人身上,需要click出物品
  544. //测试:为人加物体, 需要先选中物品
  545. let obj = viewer.modules.MergeEditor.selected
  546. viewer.objs.children.find(e=>e.name == 'Man.glb').skeletonHelper.bones[34].attach(obj); //左手骨和物品绑定
  547. //viewer.objs.children.find(e=>e.name == 'Soldier.glb').skeletonHelper.bones[9].attach(obj); //右手骨和物品绑定
  548. obj.updateMatrixWorld()
  549. obj.dispatchEvent({type:'position_changed',byControl:true })
  550. obj.dispatchEvent({type:'rotation_changed',byControl:true })
  551. 物体带动骨骼自动做动作 setAniIK
  552. */