var lerp = { vector: function(e, t, f) {//xzw change, add f var i = e.clone(); return t = t.clone(), function(n) { e.set(i.x * (1 - n) + t.x * n, i.y * (1 - n) + t.y * n, i.z * (1 - n) + t.z * n) f && f(e,n); } }, quaternion: function(e, t, f) {//xzw change, add f var i = e.clone(); return function(n) { e.copy(i).slerp(t, n); f && f(e,n); } }, property: function(e, t, i, n) { var r = e[t]; return function(o) { e[t] = r * (1 - o) + i * o, n && n(e[t]) } }, uniform: function(e, t, i) { var n = e.material.uniforms[t].value; return function(r) { try{ e.material.uniforms[t] && (e.material.uniforms[t].value = n * (1 - r) + i * r) }catch(e){ console.log(1) } } }, matrix4: function(e, t) { var i = e.clone(); return function(n) { for (var r = e.elements, o = i.elements, a = t.elements, s = 0; s < 16; s++) r[s] = o[s] * (1 - n) + a[s] * n } }, allUniforms: function(e, t, i) { var n = e.map(function(e) { return this.uniform(e, t, i) } .bind(this)); return function(e) { n.forEach(function(t) { t(e) }) } } }; ////// var easing = {}; //渐变曲线函数,反应加速度的变化 easing.linearTween = function(e, t, i, n) { return i * e / n + t } , easing.easeInQuad = function(e, t, i, n) { return e /= n, i * e * e + t } , easing.easeOutQuad = function(e, t, i, n) { return e /= n, -i * e * (e - 2) + t } , easing.easeInOutQuad = function(e, t, i, n) { return e /= n / 2, e < 1 ? i / 2 * e * e + t : (e--, -i / 2 * (e * (e - 2) - 1) + t) } , easing.easeInCubic = function(e, t, i, n) { return e /= n, i * e * e * e + t } , easing.easeOutCubic = function(e, t, i, n) { return e /= n, e--, i * (e * e * e + 1) + t } , easing.easeInOutCubic = function(e, t, i, n) { return e /= n / 2, e < 1 ? i / 2 * e * e * e + t : (e -= 2, i / 2 * (e * e * e + 2) + t) } , easing.easeInQuart = function(e, t, i, n) { return e /= n, i * e * e * e * e + t } , easing.easeOutQuart = function(e, t, i, n) { return e /= n, e--, -i * (e * e * e * e - 1) + t } , easing.easeInOutQuart = function(e, t, i, n) { return e /= n / 2, e < 1 ? i / 2 * e * e * e * e + t : (e -= 2, -i / 2 * (e * e * e * e - 2) + t) } , easing.easeInQuint = function(e, t, i, n) { return e /= n, i * e * e * e * e * e + t } , easing.easeOutQuint = function(e, t, i, n) { return e /= n, e--, i * (e * e * e * e * e + 1) + t } , easing.easeInOutQuint = function(e, t, i, n) { return e /= n / 2, e < 1 ? i / 2 * e * e * e * e * e + t : (e -= 2, i / 2 * (e * e * e * e * e + 2) + t) } , easing.easeInSine = function(e, t, i, n) { return -i * Math.cos(e / n * (Math.PI / 2)) + i + t } , easing.easeOutSine = function(e, t, i, n) { return i * Math.sin(e / n * (Math.PI / 2)) + t } , easing.easeInOutSine = function(e, t, i, n) { return -i / 2 * (Math.cos(Math.PI * e / n) - 1) + t } , easing.easeInExpo = function(e, t, i, n) { return i * Math.pow(2, 10 * (e / n - 1)) + t } , easing.easeOutExpo = function(e, t, i, n) { return i * (-Math.pow(2, -10 * e / n) + 1) + t } , easing.easeInOutExpo = function(e, t, i, n) { return e /= n / 2, e < 1 ? i / 2 * Math.pow(2, 10 * (e - 1)) + t : (e--, i / 2 * (-Math.pow(2, -10 * e) + 2) + t) } , easing.easeInCirc = function(e, t, i, n) { return e /= n, -i * (Math.sqrt(1 - e * e) - 1) + t } , easing.easeOutCirc = function(e, t, i, n) { return e /= n, e--, i * Math.sqrt(1 - e * e) + t } , easing.easeInOutCirc = function(e, t, i, n) { return e /= n / 2, e < 1 ? -i / 2 * (Math.sqrt(1 - e * e) - 1) + t : (e -= 2, i / 2 * (Math.sqrt(1 - e * e) + 1) + t) } , easing.easeInElastic = function(e, t, i, n) { var r = 1.70158 , o = 0 , a = i; return 0 === e ? t : 1 === (e /= n) ? t + i : (o || (o = .3 * n), a < Math.abs(i) ? (a = i, r = o / 4) : r = o / (2 * Math.PI) * Math.asin(i / a), -(a * Math.pow(2, 10 * (e -= 1)) * Math.sin((e * n - r) * (2 * Math.PI) / o)) + t) } , easing.easeOutElastic = function(e, t, i, n) { var r = 1.70158 , o = 0 , a = i; return 0 === e ? t : 1 === (e /= n) ? t + i : (o || (o = .3 * n), a < Math.abs(i) ? (a = i, r = o / 4) : r = o / (2 * Math.PI) * Math.asin(i / a), a * Math.pow(2, -10 * e) * Math.sin((e * n - r) * (2 * Math.PI) / o) + i + t) } , easing.easeInOutElastic = function(e, t, i, n) { var r = 1.70158 , o = 0 , a = i; return 0 === e ? t : 2 === (e /= n / 2) ? t + i : (o || (o = n * (.3 * 1.5)), a < Math.abs(i) ? (a = i, r = o / 4) : r = o / (2 * Math.PI) * Math.asin(i / a), e < 1 ? -.5 * (a * Math.pow(2, 10 * (e -= 1)) * Math.sin((e * n - r) * (2 * Math.PI) / o)) + t : a * Math.pow(2, -10 * (e -= 1)) * Math.sin((e * n - r) * (2 * Math.PI) / o) * .5 + i + t) } , easing.easeInBack = function(e, t, i, n, r) { return void 0 === r && (r = 1.70158), i * (e /= n) * e * ((r + 1) * e - r) + t } , easing.easeOutBack = function(e, t, i, n, r) { return void 0 === r && (r = 1.70158), i * ((e = e / n - 1) * e * ((r + 1) * e + r) + 1) + t } , easing.easeInOutBack = function(e, t, i, n, r) { return void 0 === r && (r = 1.70158), (e /= n / 2) < 1 ? i / 2 * (e * e * (((r *= 1.525) + 1) * e - r)) + t : i / 2 * ((e -= 2) * e * (((r *= 1.525) + 1) * e + r) + 2) + t } , easing.easeOutBounce = function(e, t, i, n) { return (e /= n) < 1 / 2.75 ? i * (7.5625 * e * e) + t : e < 2 / 2.75 ? i * (7.5625 * (e -= 1.5 / 2.75) * e + .75) + t : e < 2.5 / 2.75 ? i * (7.5625 * (e -= 2.25 / 2.75) * e + .9375) + t : i * (7.5625 * (e -= 2.625 / 2.75) * e + .984375) + t } , easing.easeInBounce = function(e, t, i, r) { return i - easing.easeOutBounce(r - e, 0, i, r) + t } , easing.easeInOutBounce = function(e, t, i, r) { return e < r / 2 ? .5 * easing.easeInBounce(2 * e, 0, i, r) + t : .5 * easing.easeOutBounce(x, 2 * e - r, 0, i, r) + .5 * i + t } /* 渐变 */ var transitions = { globalDone: null, funcs: [], counter: 0, uniqueID: 0, start: function(e, t, i, r, o, a, s, cancelFun) { r = r || 0 let info = { func: e, current: -r * Math.abs(t), //当前时间 duration: (1 - Math.max(r, 0)) * Math.abs(t), //总时长 done: i, easing: o || easing.linearTween, //渐变曲线 cycling: t < 0, running: !0, debug: r < 0, name: a || "T" + this.counter, id: void 0 === s ? this.counter : s, paused: !1, cancelFun : cancelFun, //取消时执行的函数 } this.funcs.push(info), e(0, 16), this.counter += 1 return info }, trigger: function(e) { var t = void 0 === e.delayRatio ? 0 : e.delayRatio , i = e.func || function() {} , r = void 0 === e.duration ? 0 : e.duration; void 0 !== e.cycling && e.cycling && (r = -Math.abs(r)); var o = e.done || null , a = e.easing || easing.linearTween , s = e.name || "R" + this.counter , l = void 0 === e.id ? this.counter : e.id; return this.start(i, r, o, t, a, s, l) }, setTimeout: function(e, t, i) { var n = void 0 === i ? this.counter : i; return this.trigger({ done: e, duration: void 0 === t ? 0 : t, name: "O" + this.counter, id: n }) }, pause: function() { this.paused = !0 }, resume: function() { this.paused = !1 }, update: function(e) { this.funcs.forEach(function(t) { if (!(t.paused || (t.current += 1e3 * e, t.current < 0))){ if (t.current >= t.duration && !t.cycling) { var i = t.easing(1, 0, 1, 1); t.func(i, 1e3 * e), t.done && t.done(), t.running = !1 } else { var n = t.easing(t.current % t.duration / t.duration, 0, 1, 1) , r = t.func(n, 1e3 * e) || !1; r && (t.done && t.done(), t.running = !1) } } }); var t = this.funcs.length; this.funcs = this.funcs.filter(function(e) { return e.running }); var i = this.funcs.length; if (t > 0 && 0 === i && this.globalDone) { var n = this.globalDone; this.globalDone = null, n() } }, adjustSpeed: function(e, t) { for (var i = this.getById(e), n = 0; n < i.length; n++) { var r = i[n]; r.duration /= t, r.current /= t } }, getById: function(e) { return this.funcs.filter(function(t) { return e === t.id }) }, get: function(e) { for (var t = 0; t < this.funcs.length; t += 1) if (this.funcs[t].func === e) return this.funcs[t]; return null }, isRunning: function(e) { var t = this.get(e); return null !== t && t.running }, countActive: function() { for (var e = 0, t = 0; t < this.funcs.length; t += 1) e += this.funcs[t].running; return e }, listActive: function() { for (var e = [], t = 0; t < this.funcs.length; t += 1) this.funcs[t].running && e.push(this.funcs[t].name); return e }, done: function(e) { this.globalDone = e }, cancelById: function(e, dealCancelFun) { //xzw add dealDone var t = void 0 === e ? 0 : e; this.funcs = this.funcs.filter(function(e) { var is = e.id == t; if(is && dealCancelFun){ e.cancelFun && e.cancelFun() } return !is }) }, cancel: function(e) { this.funcs = this.funcs.filter(function(t) { return t.func !== e }) }, getUniqueId: function() { return this.uniqueID -= 1, this.uniqueID } }; let convertTool = { getPos2d : function(point, camera, dom){//获取一个三维坐标对应屏幕中的二维坐标 if(!camera)return var pos = point.clone().project(camera) //比之前hotspot的计算方式写得简单 project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera); var x,y; x = (pos.x + 1) / 2 * dom.clientWidth; y = (1 - (pos.y + 1) / 2) * dom.clientHeight; var inSight = x <= dom.clientWidth && x >= 0 //是否在屏幕中 && y <= dom.clientHeight && y >= 0 return { pos: new THREE.Vector2(x,y), // 屏幕像素坐标 vector: pos, //(范围 -1 ~ 1) trueSide : pos.z<1, //trueSide为false时,即使在屏幕范围内可见,也是反方向的另一个不可以被渲染的点 参见Tag.update inSight : inSight //在屏幕范围内可见 }; }, ifShelter: function (pos3d, pos2d, camera, colliders, margin=0 ) { //检测某点在视线中是否被mesh遮挡 if (!pos2d) pos2d = convertTool.getPos2d(pos3d ) camera = camera || player.camera var ori = new THREE.Vector3(pos2d.x, pos2d.y, -1).unproject(camera) //找到视线原点 var dir = pos3d.clone().sub(ori).normalize() var ray = new THREE.Raycaster(ori, dir); //由外向里 因为模型从内侧是可见的所以从外侧 var o = ray.intersectObjects(colliders); var len = pos3d.distanceTo(ori); if (o && o.length) { for(var i=0;i0代表不可见 if(!object.visibleReasons) object.visibleReasons = []; //在同级时,优先可见 var update = function(){ //先按从高到低的level排列 object.unvisibleReasons = object.unvisibleReasons.sort((a,b)=>b.level-a.level) object.visibleReasons = object.visibleReasons.sort((a,b)=>b.level-a.level) var maxVisiLevel = object.visibleReasons[0] ? object.visibleReasons[0].level : -1 var maxunVisiLevel = object.unvisibleReasons[0] ? object.unvisibleReasons[0].level : -1 var shouldVisi = maxVisiLevel >= maxunVisiLevel var visiBefore = object.visible if(visiBefore != shouldVisi){ object.visible = shouldVisi object.dispatchEvent({ type: 'isVisible', visible: shouldVisi, reason, }) } } if(ifShow){ var index = object.unvisibleReasons.findIndex(e=>e.reason == reason) if(index > -1){ type = 'cancel' object.unvisibleReasons.splice(index, 1); } if(type == 'add' ){ if(!object.visibleReasons.some(e=>e.reason == reason)){ object.visibleReasons.push({reason,level}) } } }else{ var index = object.visibleReasons.findIndex(e=>e.reason == reason) if(index > -1){ type = 'cancel' object.visibleReasons.splice(index, 1); } if(type != 'cancel' ){ if(!object.unvisibleReasons.some(e=>e.reason == reason)){ object.unvisibleReasons.push({reason,level}) } } } update() }, toPrecision: function (e, t) {//xzw change 保留小数 var f = function (e, t) { var i = Math.pow(10, t); return Math.round(e * i) / i } if (e instanceof Array) { for (var s = 0; s < e.length; s++) { e[s] = f(e[s], t); } return e; } else if (e instanceof Object) { for (var s in e) { e[s] = f(e[s], t); } return e; } else return f(e, t) }, intervalTool:{ //延时update,防止卡顿 list:[], isWaiting:function(name, func, delayTime){ if(!this.list.includes(name)){ //如果没有该项, 则开始判断 var needWait = func(); //触发了改变,则等待一段时间后再自动判断 if(needWait){ this.list.push(name); setTimeout(()=>{ var a = this.list.indexOf(name); this.list.splice(a,1); this.isWaiting(name, func, delayTime) //循环 },delayTime) } } }, } , } let math = { closeTo : function(a,b, precision=1e-6){ let f = (a,b)=>{ return Math.abs(a-b) < precision; }; if(typeof (a) == 'number'){ return f(a, b); }else { let judge = (name)=>{ if(a[name] == void 0)return true //有值就判断,没值就不判断 else return f(a[name],b[name]) }; return judge('x') && judge('y') && judge('z') && judge('w') } }, linearClamp(value, xArr , yArr){ //xArr需要按顺序从小到大,yArr对应xArr中的值 let len = xArr.length; if(value <= xArr[0]) return yArr[0] if(value >= xArr[len - 1]) return yArr[len - 1] let i = 0; while(++i < len ){ if(value < xArr[i]){ let x1 = xArr[i-1], x2 = xArr[i], y1 = yArr[i-1], y2 = yArr[i]; value = y1 + ( y2 - y1) * (value - x1) / (x2 - x1); break } } return value } } var cameraLight = { clampVFOV: function(currentFov, maxHFov, width, height) {//限制currentFov, 使之造成的横向fov不大于指定值maxHFov var r = cameraLight.getHFOVFromVFOV(currentFov, width, height); return r > maxHFov ? cameraLight.getVFOVFromHFOV(maxHFov, width, height) : currentFov }, getHFOVForCamera: function(camera, getRad) { return cameraLight.getHFOVByScreenPrecent(camera.fov, camera.aspect, getRad) }, //add getHFOVByScreenPrecent: function(fov, percent, getRad) { //当fov为占比百分百时,percent代表在屏幕上从中心到边缘的占比 let rad = 2 * Math.atan(percent * Math.tan(THREE.Math.degToRad(fov * 2))); if(getRad)return rad else return rad * MathLight.DEGREES_PER_RADIAN; } }; let texLoader = new THREE.TextureLoader; let texs = new Map let common = { urlHasValue(key, isGetValue) { let querys = window.location.search.substr(1).split('?') if (isGetValue) { for (let i = 0; i < querys.length; i++) { let keypair = querys[i].split('=') if (keypair.length === 2 && keypair[0] === key) { return keypair[1] } } return '' } else { //return window.location.search.match("&" + key + "|\\?" + key) != null 有bug for (let i = 0; i < querys.length; i++) { let keypair = querys[i].split('=') if(keypair[0] == key){ return true } } return false } }, dataURLtoBlob(dataurl) {//将base64转换blob var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); }, loadTexture(src,done){ let o = texs.get(src) if(o){ if(o.tex.image) done && done(o.tex)//加载完毕 else{ o.callbacks.push(done)//等待加载 } return } let callbacks = [] let tex = texLoader.load(src,(tex)=>{ callbacks.forEach(done=>done(tex)) }) done && callbacks.push(done) texs.set(src,{tex,callbacks}) return tex } }