Skip to content

Commit 4d60d9d

Browse files
authored
Polyhaven Web Patches for EXR (#33)
* Start patching 3d and content preview to get PNG vs EXR. Still need to patch bad MTLX references based on downloaded images... * Preview of content okay now. - Download is using original mtlx. * Fix 3d preview. * Cleanup. Restore cache usage. * Places image before doc in content preview. Add few snapshots. * Add Mac preview snap.
1 parent f3ca87f commit 4d60d9d

5 files changed

Lines changed: 98 additions & 13 deletions

File tree

870 KB
Loading
737 KB
Loading
348 KB
Loading

javascript/JsPolyHaven/jsPolyHavenLoader.js

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ class JsPolyHavenAPILoader {
9292
throw new Error(`Failed to fetch MaterialX data for ${materialId}`);
9393
}
9494

95-
return await response.json();
95+
const result = await response.json();
96+
console.log(`Fetched MaterialX files for ${materialId}:`, result);
97+
return result;
9698
} catch (error) {
9799
console.error(`Error fetching material files for ${materialId}:`, error);
98100
throw error;
@@ -114,7 +116,9 @@ class JsPolyHavenAPILoader {
114116
throw new Error('Failed to download MaterialX file');
115117
}
116118

117-
return await response.text();
119+
const result = await response.text();
120+
// Find
121+
return result;
118122
} catch (error) {
119123
console.error('Error downloading MaterialX content:', error);
120124
throw error;
@@ -135,6 +139,9 @@ class JsPolyHavenAPILoader {
135139
if (!response.ok) {
136140
throw new Error(`Failed to download texture from ${url}`);
137141
}
142+
else {
143+
console.log(`> Successfully downloaded texture from ${url}`);
144+
}
138145

139146
return await response.blob();
140147
} catch (error) {
@@ -176,6 +183,7 @@ class JsPolyHavenAPILoader {
176183
// Fetch MaterialX files data
177184
const filesData = await this.fetchMaterialFiles(material.id);
178185
const mtlxData = filesData.mtlx?.[resolution]?.mtlx;
186+
console.log('> createMaterialXPackage - fetched MaterialX data:', mtlxData);
179187

180188
if (!mtlxData) {
181189
throw new Error(`No MaterialX files found for ${resolution} resolution`);
@@ -185,14 +193,36 @@ class JsPolyHavenAPILoader {
185193
const zip = new JSZip();
186194

187195
// 1. Download and add the main MaterialX file
188-
const mtlxContent = await this.downloadMaterialXContent(mtlxData.url);
189-
zip.file(`${material.id}.mtlx`, mtlxContent);
190-
console.log(`Added MaterialX file to ZIP: ${material.id}.mtlx, ${mtlxContent}`);
196+
let mtlxContent = await this.downloadMaterialXContent(mtlxData.url);
191197

192198
// 2. Download and add all included texture files
193199
const textureFiles = mtlxData.include || {};
200+
let texturePaths = [];
201+
194202
const texturePromises = Object.entries(textureFiles).map(async ([path, fileData]) => {
195203
try {
204+
console.log(`Processing texture: ${path} from URL: ${fileData.url}`);
205+
206+
let isEXR = path.toLowerCase().endsWith('.exr')
207+
// Try changing extension to .png.
208+
if (isEXR) {
209+
const prevPath = path;
210+
path = path.replace(/\.exr$/i, '.png');
211+
// Replace /exr/ with /png/
212+
fileData.url = fileData.url.replace(/\/exr\//i, '/png/');
213+
// Replace .exr with .png extension
214+
fileData.url = fileData.url.replace('.exr', '.png');
215+
// Replace .exr with .png in mtlxContent if present
216+
const previousMtlxContent = mtlxContent;
217+
mtlxContent = previousMtlxContent.replace(prevPath, path);
218+
219+
console.log(`EXR file detected. Path: ${prevPath} -> ${path}, URL: ${fileData.url}`);
220+
if (previousMtlxContent !== mtlxContent) {
221+
console.log(`Updated MaterialX content to replace .exr with .png for texture: ${path}`);
222+
}
223+
224+
}
225+
196226
const textureBlob = await this.downloadTexture(fileData.url);
197227

198228
// Maintain the folder structure from the include paths
@@ -211,15 +241,20 @@ class JsPolyHavenAPILoader {
211241
console.warn(`EXR file present which may not be supported by MaterialX texture loader: ${path}`);
212242
}
213243
else {
214-
console.log(`Added texture to ZIP: ${path}`);
244+
console.log(`Added texture ${path} to ZIP from URL: ${fileData.url}`);
245+
zip.file(path, textureBlob);
215246
}
247+
248+
texturePaths.push(path);
249+
216250
} catch (error) {
217251
console.error(`Error downloading texture ${path}:`, error);
218252
// Add placeholder file if download fails
219253
zip.file(path, `Failed to download: ${fileData.url}`);
220254
}
221255
});
222256

257+
223258
// 3. Download and add thumbnail
224259
if (material.thumb_url) {
225260
try {
@@ -236,15 +271,30 @@ class JsPolyHavenAPILoader {
236271
// Wait for all downloads to complete
237272
await Promise.all(texturePromises);
238273

239-
// Add README file
274+
for (const textureName of texturePaths) {
275+
// Patch bad MTLX references in original file
276+
const extenson = textureName.split('.').pop();
277+
const exrName = textureName.replace(`.${extenson}`, `.exr`);
278+
if (mtlxContent.includes(exrName)) {
279+
console.log(`Replace ${exrName} with ${textureName} in MaterialX content for preview`);
280+
mtlxContent = mtlxContent.replace(exrName, textureName);
281+
}
282+
}
283+
284+
// Add Materialx document to ZIP.
285+
// This must be done after texture processing which may
286+
// modify the MTLX image references.
287+
zip.file(`${material.id}.mtlx`, mtlxContent);
288+
console.log(`Added MaterialX file to ZIP: ${material.id}.mtlx`); //, ${mtlxContent}`);
289+
290+
// Add README file, and thumbnail to root of ZIP
240291
zip.file("README.txt",
241292
`Material: ${material.name}\n` +
242293
`Resolution: ${resolution}\n` +
243294
`Source: https://polyhaven.com/a/${material.id}\n` +
244295
`Downloaded: ${new Date().toISOString()}\n\n` +
245296
`Contains the following files:\n` +
246297
`- ${material.id}.mtlx\n` +
247-
Object.keys(textureFiles).map(path => `- ${path}`).join('\n') +
248298
(material.thumb_url ? `\n- ${material.id}_thumbnail.png` : '')
249299
);
250300

javascript/JsPolyHaven/main.js

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ document.addEventListener('DOMContentLoaded', function () {
105105
async function downloadMaterial() {
106106
if (!currentSelectedMaterial || !polyHavenAPI) return;
107107

108+
console.log(`Preparing download for material: ${currentSelectedMaterial.name} (ID: ${currentSelectedMaterial.id})`);
109+
108110
const resolution = document.getElementById('materialResolution').value;
109111
const materialName = currentSelectedMaterial.name.replace(/[^a-z0-9]/gi, '_').toLowerCase();
110112

@@ -343,14 +345,15 @@ async function loadMaterialContent(materialId) {
343345

344346
// Create preview content
345347
const previewContainer = document.getElementById('contentPreview');
348+
let mtlxContent = contentData.mtlxContent || '';
346349
previewContainer.innerHTML = `
347350
<div class="mt-4">
348-
<b>MaterialX Document</b>
349-
<textarea id="mtlxEditor">${contentData.mtlxContent}</textarea>
351+
<b>Content</b>
350352
<div class="mt-2">
351353
<b>Textures</b>
352354
<div id="textureGallery" class="row g-2"></div>
353355
</div>
356+
<textarea id="mtlxEditor">${mtlxContent}</textarea>
354357
</div>
355358
`;
356359

@@ -373,11 +376,26 @@ async function loadMaterialContent(materialId) {
373376
const textureFiles = contentData.textureFiles;
374377
const galleryContainer = document.getElementById('textureGallery');
375378
galleryContainer.innerHTML = '';
379+
380+
let textureNames = [];
376381

377-
const createTextureCard = (textureName, textureUrl) => {
382+
const createTextureCard = (textureName, textureUrl) =>
383+
{
378384
const card = document.createElement('div');
379385
card.className = 'col-6 col-md-4 col-lg-3 mb-3';
380386

387+
// If textureURL ends with exr replace with png for preview
388+
if (textureUrl.toLowerCase().endsWith('.exr')) {
389+
console.log(`> EXR file detected for preview, attempting to use PNG version: ${textureUrl}`);
390+
textureUrl = textureUrl.replace(/\.exr$/i, '.png').replace(/\/exr\//i, '/png/');
391+
let textureName_before = textureName;
392+
textureName = textureName_before.replace(/\.exr$/i, '.png');
393+
console.log(`Replace ${textureName_before} with ${textureName} in MaterialX content for preview`);
394+
mtlxContent = mtlxContent.replace(textureName_before, textureName);
395+
}
396+
397+
textureNames.push(textureName);
398+
381399
card.innerHTML = `
382400
<div class="card h-100">
383401
<div class="ratio ratio-1x1 bg-light">
@@ -395,13 +413,30 @@ async function loadMaterialContent(materialId) {
395413
return card;
396414
};
397415

416+
398417
// Create gallery items
399418
for (const [path, fileData] of Object.entries(textureFiles)) {
400-
const textureName = path.split('/').pop();
401-
const card = createTextureCard(textureName, fileData.url);
419+
const textureURI = path.split('/').pop();
420+
let card = createTextureCard(textureURI, fileData.url);
402421
galleryContainer.appendChild(card);
403422
}
404423

424+
// Set mtlxContent to editor
425+
if (codeMirrorEditor) {
426+
// Patch bad MTLX references in original file
427+
for (const textureName of textureNames) {
428+
extenson = textureName.split('.').pop();
429+
exrName = textureName.replace(`.${extenson}`, `.exr`);
430+
if (mtlxContent.includes(exrName)) {
431+
console.log(`Replace ${exrName} with ${textureName} in MaterialX content for preview`);
432+
mtlxContent = mtlxContent.replace(exrName, textureName);
433+
}
434+
}
435+
436+
console.log('Setting MaterialX content in CodeMirror editor:', mtlxContent);
437+
codeMirrorEditor.setValue(mtlxContent);
438+
}
439+
405440
} catch (error) {
406441
console.error('Error loading content:', error);
407442
document.getElementById('contentPreview').innerHTML += `

0 commit comments

Comments
 (0)