forked from natuka/web.puabadge.com
修改:优化手机上效果图点云显示
This commit is contained in:
1 parent
17908ab309
commit
605bd894c5
4 files changed
+87
-30
No files matched your search
@@ -64,8 +64,8 @@ let renderer: any = null
|
||||
let sm: any = null
|
||||
let raf = 0
|
||||
let lastTs = 0
|
||||
let cssW = 320
|
||||
let cssH = 320
|
||||
let cssW = 340
|
||||
let cssH = 340
|
||||
let logoFromCache = false
|
||||
let resultKey = ''
|
||||
|
||||
@@ -186,12 +186,23 @@ function preloadResult(url: string) {
|
||||
if (!url || !renderer || !sm) return
|
||||
resultKey = url
|
||||
sm.setResultPreloadStatus('loading')
|
||||
// 效果图保留完整画面做点云(去背景会在手机上采空,表现为「没有效果图点云」)
|
||||
renderer.textures
|
||||
.load(url, { removeBackground: true })
|
||||
.load(url, { removeBackground: false })
|
||||
.then((entry: any) => {
|
||||
if (destroyed || !sm) return
|
||||
if (!entry || !entry.pointCloudBuffer) {
|
||||
console.error('[ImagePointCloud] result cloud buffer missing')
|
||||
sm.setResultPreloadStatus('error')
|
||||
return
|
||||
}
|
||||
renderer.setResultTexture(entry)
|
||||
sm.setResultPreloadStatus('ready')
|
||||
// 若状态机已进入 RESULT_*(异步晚到),立刻切到效果图点云
|
||||
const phase = String(sm.getPhase?.() || '')
|
||||
if (phase.startsWith('RESULT')) {
|
||||
renderer.transitionToCloud(entry)
|
||||
}
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.error('[ImagePointCloud] result preload fail', err)
|
||||
@@ -310,11 +321,15 @@ function init() {
|
||||
}
|
||||
},
|
||||
onSwitchToResult: () => {
|
||||
const entry = renderer.textures.get(resultKey || props.resultUrl)
|
||||
const key = resultKey || props.resultUrl
|
||||
const entry = key ? renderer.textures.get(key) : null
|
||||
if (entry && entry.pointCloudBuffer) {
|
||||
renderer.transitionToCloud(entry)
|
||||
renderer.setResultTexture(entry)
|
||||
return
|
||||
}
|
||||
// 缓冲晚到时由 preloadResult 成功回调补切
|
||||
if (key) preloadResult(key)
|
||||
},
|
||||
onHandoff: () => emit('handoff'),
|
||||
})
|
||||
|
||||
@@ -124,6 +124,8 @@ function createStateMachine(hooks) {
|
||||
phase !== PHASE.RESULT_PRELOADING &&
|
||||
phase !== PHASE.SUBJECT_DETECTING &&
|
||||
phase !== PHASE.SUBJECT_OUTLINE &&
|
||||
phase !== PHASE.SUBJECT_CLOUD_GRAY &&
|
||||
phase !== PHASE.SUBJECT_CLOUD_COLORIZE &&
|
||||
phase !== PHASE.SUBJECT_CLOUD_COLOR &&
|
||||
phase !== PHASE.SUBJECT_POINT_CLOUD
|
||||
) {
|
||||
@@ -292,6 +294,7 @@ function createStateMachine(hooks) {
|
||||
if (!morphing) assembly = 1
|
||||
subjectProgress = 1
|
||||
outlineProgress = Math.max(0.35, 1 - Math.min(1, elapsed / 2400) * 0.55)
|
||||
if (tryStartResultTransition()) return getUniforms()
|
||||
if (!morphing && elapsed >= TIMING.SUBJECT_GRAY_MS) {
|
||||
enter(PHASE.SUBJECT_CLOUD_COLORIZE)
|
||||
}
|
||||
@@ -307,6 +310,7 @@ function createStateMachine(hooks) {
|
||||
if (!morphing) assembly = 1
|
||||
subjectProgress = 1
|
||||
outlineProgress = 0.35
|
||||
if (tryStartResultTransition()) return getUniforms()
|
||||
if (t >= 1) {
|
||||
colorProgress = 1
|
||||
enter(PHASE.SUBJECT_CLOUD_COLOR)
|
||||
|
||||
@@ -115,7 +115,8 @@ function createTextureManager(gl, canvas, scaleCanvas, viewportW, viewportH) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载图片并严格在 onload 之后再交给后续逻辑(避免 TMA 未定义行为告警)
|
||||
* 加载图片并严格在 onload 之后再交给后续逻辑。
|
||||
* http(s) 优先 fetch→blob,避免手机 WebView 跨域导致 getImageData 采点失败。
|
||||
*/
|
||||
function loadImage(src) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
@@ -123,38 +124,73 @@ function createTextureManager(gl, canvas, scaleCanvas, viewportW, viewportH) {
|
||||
reject(new Error('empty src'))
|
||||
return
|
||||
}
|
||||
let settled = false
|
||||
const img = new Image()
|
||||
// 跨域效果图需 CORS,否则无法 getImageData 采样
|
||||
if (/^https?:\/\//i.test(src)) {
|
||||
img.crossOrigin = 'anonymous'
|
||||
}
|
||||
|
||||
function finishOk() {
|
||||
if (settled) return
|
||||
setTimeout(function () {
|
||||
function bindImage(imgSrc, revokeUrl) {
|
||||
let settled = false
|
||||
const img = new Image()
|
||||
if (/^https?:\/\//i.test(imgSrc) && imgSrc.indexOf('blob:') !== 0) {
|
||||
img.crossOrigin = 'anonymous'
|
||||
}
|
||||
|
||||
function finishOk() {
|
||||
if (settled) return
|
||||
const w = img.width || 0
|
||||
const h = img.height || 0
|
||||
if (!w || !h) {
|
||||
setTimeout(function () {
|
||||
if (settled) return
|
||||
const w = img.width || 0
|
||||
const h = img.height || 0
|
||||
if (!w || !h) {
|
||||
settled = true
|
||||
if (revokeUrl) {
|
||||
try { URL.revokeObjectURL(revokeUrl) } catch (e) {}
|
||||
}
|
||||
reject(new Error('image empty after onload'))
|
||||
return
|
||||
}
|
||||
settled = true
|
||||
reject(new Error('image empty after onload'))
|
||||
return
|
||||
}
|
||||
resolve({
|
||||
image: img,
|
||||
path: src,
|
||||
width: w,
|
||||
height: h,
|
||||
revokeUrl: revokeUrl || '',
|
||||
})
|
||||
}, 0)
|
||||
}
|
||||
|
||||
function finishErr(err) {
|
||||
if (settled) return
|
||||
settled = true
|
||||
resolve({ image: img, path: src, width: w, height: h })
|
||||
}, 0)
|
||||
if (revokeUrl) {
|
||||
try { URL.revokeObjectURL(revokeUrl) } catch (e) {}
|
||||
}
|
||||
reject(err || new Error('image load fail'))
|
||||
}
|
||||
|
||||
img.onload = finishOk
|
||||
img.onerror = finishErr
|
||||
img.src = imgSrc
|
||||
}
|
||||
|
||||
function finishErr(err) {
|
||||
if (settled) return
|
||||
settled = true
|
||||
reject(err || new Error('image load fail'))
|
||||
// 远程图:先 blob 同源化,再采样(手机端效果图点云依赖此路径)
|
||||
if (/^https?:\/\//i.test(src) && typeof fetch === 'function') {
|
||||
fetch(src, { mode: 'cors', credentials: 'omit', cache: 'force-cache' })
|
||||
.then(function (res) {
|
||||
if (!res || !res.ok) throw new Error('fetch image http ' + (res && res.status))
|
||||
return res.blob()
|
||||
})
|
||||
.then(function (blob) {
|
||||
if (!blob || !blob.size) throw new Error('empty image blob')
|
||||
const objUrl = URL.createObjectURL(blob)
|
||||
bindImage(objUrl, objUrl)
|
||||
})
|
||||
.catch(function () {
|
||||
// CORS 拉流失败时退回 <img crossOrigin>
|
||||
bindImage(src, null)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
img.onload = finishOk
|
||||
img.onerror = finishErr
|
||||
img.src = src
|
||||
bindImage(src, null)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -333,10 +333,12 @@ function pollStatus() {
|
||||
imageId.value = parsed.imageId
|
||||
sessionStorage.setItem('douyin_image_id', parsed.imageId)
|
||||
}
|
||||
// 不再 10s 强切预览:会掐掉 RESULT_CLOUD_* 效果图点云段
|
||||
// 正常走点云状态机 handoff;仅作兜底(给足灰/彩点云播放时间)
|
||||
if (fadeTimer) clearTimeout(fadeTimer)
|
||||
fadeTimer = setTimeout(() => {
|
||||
if (!handoffDone) enterResultView()
|
||||
}, 10000)
|
||||
}, 60000)
|
||||
if (pollTimer) {
|
||||
clearInterval(pollTimer)
|
||||
pollTimer = null
|
||||
|
||||
Reference in new issue
Block a user