This loads image files via backend asset links (with auth when available), applies them as Three.js textures on plane meshes, and falls back to primitive placeholders if texture loading fails. Made-with: Cursor
This commit is contained in:
@@ -39,6 +39,7 @@ let threeCamera;
|
|||||||
const featureMeshes = new Map();
|
const featureMeshes = new Map();
|
||||||
const modelTemplateCache = new Map();
|
const modelTemplateCache = new Map();
|
||||||
const gltfLoader = new GLTFLoader();
|
const gltfLoader = new GLTFLoader();
|
||||||
|
const textureLoader = new THREE.TextureLoader();
|
||||||
const ownFeatureMarkers = new Map();
|
const ownFeatureMarkers = new Map();
|
||||||
const ownFeatureCoords = new Map();
|
const ownFeatureCoords = new Map();
|
||||||
let renderCycle = 0;
|
let renderCycle = 0;
|
||||||
@@ -143,6 +144,13 @@ function is3DAsset(asset) {
|
|||||||
return kind === "3d" && ext === "glb";
|
return kind === "3d" && ext === "glb";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isImageAsset(asset) {
|
||||||
|
if (!asset) return false;
|
||||||
|
const kind = String(asset.kind || "").toLowerCase();
|
||||||
|
const ext = normalizeExt(asset.ext) || extFromLink(asset.link);
|
||||||
|
return kind === "image" && ["jpg", "jpeg", "png", "webp"].includes(ext);
|
||||||
|
}
|
||||||
|
|
||||||
async function renderSharedAssetFromQuery() {
|
async function renderSharedAssetFromQuery() {
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
if (params.get("shared") !== "1") return;
|
if (params.get("shared") !== "1") return;
|
||||||
@@ -283,6 +291,42 @@ function addFallbackMesh(featureId, lng, lat, isPublic, kind) {
|
|||||||
map.triggerRepaint();
|
map.triggerRepaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadTextureFromAssetLink(assetLink) {
|
||||||
|
const assetURL = client.resolveRelativeLink(assetLink);
|
||||||
|
const headers = accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined;
|
||||||
|
const response = await fetch(assetURL, { headers });
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to load image asset: HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
const blob = await response.blob();
|
||||||
|
const objectURL = URL.createObjectURL(blob);
|
||||||
|
try {
|
||||||
|
const texture = await new Promise((resolve, reject) => {
|
||||||
|
textureLoader.load(objectURL, resolve, undefined, reject);
|
||||||
|
});
|
||||||
|
texture.colorSpace = THREE.SRGBColorSpace;
|
||||||
|
texture.needsUpdate = true;
|
||||||
|
return texture;
|
||||||
|
} finally {
|
||||||
|
URL.revokeObjectURL(objectURL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addImagePlaneMesh(featureId, lng, lat, asset) {
|
||||||
|
const texture = await loadTextureFromAssetLink(asset.link);
|
||||||
|
const geometry = new THREE.PlaneGeometry(1.8, 1.8);
|
||||||
|
const material = new THREE.MeshBasicMaterial({
|
||||||
|
map: texture,
|
||||||
|
transparent: true,
|
||||||
|
side: THREE.DoubleSide,
|
||||||
|
});
|
||||||
|
const mesh = new THREE.Mesh(geometry, material);
|
||||||
|
positionObjectOnMap(mesh, lng, lat, 20);
|
||||||
|
threeScene.add(mesh);
|
||||||
|
featureMeshes.set(featureId, mesh);
|
||||||
|
map.triggerRepaint();
|
||||||
|
}
|
||||||
|
|
||||||
function prepareModelRoot(modelRoot) {
|
function prepareModelRoot(modelRoot) {
|
||||||
const box = new THREE.Box3().setFromObject(modelRoot);
|
const box = new THREE.Box3().setFromObject(modelRoot);
|
||||||
if (box.isEmpty()) return;
|
if (box.isEmpty()) return;
|
||||||
@@ -344,6 +388,14 @@ async function addObjectMeshFromAsset(featureId, lng, lat, asset, cycleID) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!is3DAsset(asset) || !asset.link) {
|
if (!is3DAsset(asset) || !asset.link) {
|
||||||
|
if (isImageAsset(asset) && asset.link) {
|
||||||
|
try {
|
||||||
|
await addImagePlaneMesh(featureId, lng, lat, asset);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Failed to load image texture for feature ${featureId}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
const ext = normalizeExt(asset.ext) || extFromLink(asset.link);
|
const ext = normalizeExt(asset.ext) || extFromLink(asset.link);
|
||||||
if (String(asset.kind || "").toLowerCase() === "3d" && ext === "gltf") {
|
if (String(asset.kind || "").toLowerCase() === "3d" && ext === "gltf") {
|
||||||
console.warn(
|
console.warn(
|
||||||
|
|||||||
Reference in New Issue
Block a user