perf: ảnh mờ blur-up (LQIP) khi tải cảnh

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
tuyenio
2026-06-24 16:14:49 +07:00
parent 5cc3c7b636
commit e4eb4a81b2
+32
View File
@@ -27,6 +27,7 @@ import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import Lottie, { type LottieRefCurrentProps } from "lottie-react";
import letterAnimation from "@/letter.json";
import { chuaThaiLacTour } from "@/app/tours/chua-thai-lac";
import { lqip } from "@/app/tours/chua-thai-lac.lqip";
type SceneId = string;
@@ -193,6 +194,23 @@ const defaultTourConfig = chuaThaiLacTourConfig;
const getTourConfig = (tourId?: string) => toursById[tourId ?? ""] ?? defaultTourConfig;
// Texture ảnh mờ (blur-up) tạo từ data-URI base64 — hiện gần như tức thì khi cảnh đang tải.
const lqipTextureCache = new Map<string, THREE.Texture>();
function loadLqipTexture(image: string) {
const data = lqip[image];
if (!data) {
return null;
}
const cached = lqipTextureCache.get(image);
if (cached) {
return cached;
}
const texture = new THREE.TextureLoader().load(data);
texture.colorSpace = THREE.SRGBColorSpace;
lqipTextureCache.set(image, texture);
return texture;
}
const panoramaTextureCache = new Map<string, THREE.Texture>();
const panoramaTexturePromises = new Map<string, Promise<THREE.Texture>>();
const panoramaTextureProgress = new Map<string, number>();
@@ -1635,6 +1653,11 @@ function TourExperience({
if (cachedTexture) {
prepareTransitionTexture(cachedTexture);
} else {
const lqipTexture = loadLqipTexture(scene.image);
if (lqipTexture) {
transitionMaterial.map = lqipTexture;
transitionMaterial.needsUpdate = true;
}
loadPanoramaTexture(scene.image, (progress) => {
if (transitionTokenRef.current === token) {
setLoadProgress(progress);
@@ -1747,6 +1770,15 @@ function TourExperience({
setIsLoading(!initialCachedTexture);
setLoadProgress(initialCachedTexture ? 100 : 0);
if (!initialCachedTexture) {
const lqipTexture = loadLqipTexture(scene.image);
if (lqipTexture) {
material.map = lqipTexture;
material.opacity = 1;
material.needsUpdate = true;
needsRenderRef.current = true;
}
}
loadTexture
.then((texture) => {
if (transitionTokenRef.current !== token) return;