forked from natuka/web.puabadge.com
修改:优化手机端的点云效果
This commit is contained in:
1 parent
5892c47a6b
commit
704f6a30e0
4 files changed
+46
-18
No files matched your search
@@ -313,7 +313,8 @@ function init() {
|
||||
onSwitchToSubject: () => {
|
||||
const src = props.imageUrl
|
||||
const entry = renderer.textures.getSubject(src) || renderer.textures.get(src)
|
||||
if (entry && entry.subjectCloudBuffer) {
|
||||
// 缓冲无效则不切,避免切到空点云后整页变黑
|
||||
if (entry && entry.subjectCloudBuffer && entry.subjectCloudBuffer.buffer) {
|
||||
renderer.transitionToCloud({
|
||||
pointCloudBuffer: entry.subjectCloudBuffer,
|
||||
aspect: entry.aspect,
|
||||
|
||||
@@ -78,8 +78,11 @@ function createStateMachine(hooks) {
|
||||
subjectReady = false
|
||||
}
|
||||
|
||||
let resultReadyAt = 0
|
||||
|
||||
function setResultPreloadStatus(s) {
|
||||
resultPreloadStatus = s
|
||||
if (s === 'ready' && !resultReadyAt) resultReadyAt = Date.now()
|
||||
}
|
||||
|
||||
function getUniforms() {
|
||||
@@ -104,11 +107,15 @@ function createStateMachine(hooks) {
|
||||
|
||||
function tryEnterSubject() {
|
||||
if (subjectEntered || subjectFailed || !subjectReady) return false
|
||||
if (phase !== PHASE.IMAGE_COLOR_POINT_CLOUD) return false
|
||||
if (phase !== PHASE.IMAGE_COLOR_POINT_CLOUD && phase !== PHASE.RESULT_PRELOADING) {
|
||||
return false
|
||||
}
|
||||
// 等效果图点云采样完成后再进 mask 人物段,避免真机提前切空缓冲黑屏
|
||||
if (resultPreloadStatus !== 'ready') return false
|
||||
// 原图彩色点云需先完整展示
|
||||
if (Date.now() - phaseStartedAt < TIMING.IMAGE_COLOR_MS) return false
|
||||
// 结果已好则优先进结果,跳过人物段
|
||||
if (resultPreloadStatus === 'ready') return false
|
||||
if (Date.now() - phaseStartedAt < TIMING.IMAGE_COLOR_MS && phase === PHASE.IMAGE_COLOR_POINT_CLOUD) {
|
||||
return false
|
||||
}
|
||||
subjectEntered = true
|
||||
if (hooks && hooks.onSwitchToSubject) hooks.onSwitchToSubject()
|
||||
beginMorph()
|
||||
@@ -232,16 +239,22 @@ function createStateMachine(hooks) {
|
||||
) {
|
||||
// 彩色原图已展示够再标预加载;人物段优先于 RESULT_PRELOADING 文案
|
||||
}
|
||||
if (!tryStartResultTransition() && phase === PHASE.IMAGE_COLOR_POINT_CLOUD) {
|
||||
tryEnterSubject()
|
||||
}
|
||||
// 人物未就绪且结果仍在加载:原图彩色展示满后再进预加载相位
|
||||
if (
|
||||
!subjectEntered &&
|
||||
!subjectReady &&
|
||||
resultPreloadStatus === 'loading' &&
|
||||
// 效果图点云就绪后再进 mask 人物段;识别失败或超时则直接切效果图点云
|
||||
if (resultPreloadStatus === 'ready') {
|
||||
const entered = tryEnterSubject()
|
||||
const subjectWaitedOut =
|
||||
!subjectReady &&
|
||||
!subjectFailed &&
|
||||
resultReadyAt &&
|
||||
Date.now() - resultReadyAt > 12000
|
||||
if (!entered && (subjectFailed || subjectWaitedOut)) {
|
||||
if (subjectWaitedOut) subjectFailed = true
|
||||
tryStartResultTransition()
|
||||
}
|
||||
} else if (
|
||||
phase === PHASE.IMAGE_COLOR_POINT_CLOUD &&
|
||||
Date.now() - phaseStartedAt >= TIMING.IMAGE_COLOR_MS
|
||||
Date.now() - phaseStartedAt >= TIMING.IMAGE_COLOR_MS &&
|
||||
(resultPreloadStatus === 'loading' || resultPreloadStatus === 'idle')
|
||||
) {
|
||||
enter(PHASE.RESULT_PRELOADING)
|
||||
}
|
||||
|
||||
@@ -201,16 +201,20 @@ function createRenderer(canvas, cssW, cssH, dpr, scaleCanvas) {
|
||||
cloudA = entry.pointCloudBuffer
|
||||
cloudB = entry.pointCloudBuffer
|
||||
contentAspect = entry.aspect || cloudA.aspect || 1
|
||||
// count 是整段缓冲长度。点按从上到下写入,只画 liveCount 会把下半身裁掉
|
||||
pointCount = cloudA.count || maxPoints
|
||||
}
|
||||
|
||||
/** Promote current target to A, set B = new target (particle morph) */
|
||||
function transitionToCloud(entry) {
|
||||
if (!entry || !entry.pointCloudBuffer) return
|
||||
if (!entry || !entry.pointCloudBuffer || !entry.pointCloudBuffer.buffer) return
|
||||
cloudA = cloudB
|
||||
cloudB = entry.pointCloudBuffer
|
||||
contentAspect = entry.aspect || cloudB.aspect || contentAspect
|
||||
pointCount = Math.max(cloudA.count || 0, cloudB.count || 0, maxPoints)
|
||||
const countA = cloudA.count || 0
|
||||
const countB = cloudB.count || 0
|
||||
// 取两边缓冲容量的较小值,避免越界;不要用有效点数,否则下半身被截掉
|
||||
pointCount = Math.max(1, Math.min(countA || countB, countB || countA))
|
||||
}
|
||||
|
||||
function setResultTexture(entry) {
|
||||
|
||||
@@ -44,7 +44,17 @@ function createTextureManager(gl, canvas, scaleCanvas, viewportW, viewportH) {
|
||||
try {
|
||||
const dpr = (typeof window !== 'undefined' && window.devicePixelRatio) || 1
|
||||
const cores = (typeof navigator !== 'undefined' && navigator.hardwareConcurrency) || 4
|
||||
if (dpr >= 2.5 && cores >= 8) {
|
||||
const ua = (typeof navigator !== 'undefined' && navigator.userAgent) || ''
|
||||
const mobile = /Android|iPhone|iPad|iPod|Mobile/i.test(ua)
|
||||
// 真机内存紧,高点数上传容易丢 WebGL 上下文,之后整页黑屏
|
||||
if (mobile) {
|
||||
maxPoints = POINT_CLOUD.LOW
|
||||
sampleSide = POINT_CLOUD.SAMPLE_LOW
|
||||
maxTexSize = VISUAL.LOW_TEX_SIZE
|
||||
maskSide = POINT_CLOUD.MASK_LOW
|
||||
subjectPoints = POINT_CLOUD.SUBJECT_LOW
|
||||
quality = 'low'
|
||||
} else if (dpr >= 2.5 && cores >= 8) {
|
||||
maxPoints = POINT_CLOUD.HIGH
|
||||
sampleSide = POINT_CLOUD.SAMPLE_HIGH
|
||||
maxTexSize = VISUAL.MAX_TEX_SIZE
|
||||
@@ -475,7 +485,7 @@ function createTextureManager(gl, canvas, scaleCanvas, viewportW, viewportH) {
|
||||
const mask = maskProcessor.decodeMaskImage(
|
||||
maskRes.image,
|
||||
scaleCtx,
|
||||
scaleCanvas,
|
||||
sampleCanvas,
|
||||
aligned.width,
|
||||
aligned.height
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user