MaterialXMaterials 0.0.1
Utilities for retrieving materials from remote servers
Loading...
Searching...
No Matches
JsAmbientCGLoader.js
1const axios = require('axios');
2const fs = require('fs');
3const { Writable } = require('stream');
4const { createGunzip } = require('zlib');
5const { parse } = require('csv-parse/sync');
6
14 constructor(mxModule, mxStdlib = null) {
15 this.logger = console;
16 this.database = {};
17 this.assets = {};
18 this.materials = null;
19 this.materialNames = [];
20 this.csvMaterials = null;
21 this.downloadMaterial = null;
22 this.downloadMaterialFileName = '';
23 this.mx = mxModule;
24 this.stdlib = mxStdlib;
25 this.supportOpenPBR = false;
26
27 if (!mxModule) {
28 this.logger.error('MaterialX module not specified.');
29 return;
30 }
31
32 // Check for OpenPBR support (placeholder logic)
33 const version = this.mx.getVersionIntegers();
34 this.logger.info(`Using MaterialX version: ${version.join('.')}`);
35 if (version[0] >= 1 && version[1] >= 39) || version[0] > 1) {
36 this.logger.debug('OpenPBR shading model supported');
37 this.supportOpenPBR = true;
38 }
39
40 // Load the MaterialX standard library if not provided
41 if (!this.stdlib) {
42 this.stdlib = this.mx.createDocument();
43 const libFiles = this.mx.loadLibraries(this.mx.getDefaultDataLibraryFolders(), this.mx.getDefaultDataSearchPath(), this.stdlib);
44 this.logger.debug(`Loaded standard library: ${libFiles}`);
45 }
46 }
47
48 setDebugging(debug = true) {
53 this.logger.level = debug ? 'debug' : 'info';
54 }
55
56 getMaterialNames(key = 'assetId') {
62 this.materialNames = [];
63 const uniqueNames = new Set();
64 if (this.materials) {
65 this.materials.forEach(item => uniqueNames.add(item[key]));
66 }
67 this.materialNames = Array.from(uniqueNames).sort();
68 return this.materialNames;
69 }
70
71 writeMaterialList(materialList, filename) {
77 this.logger.info(`Writing material list to file: ${filename}`);
78 fs.writeFileSync(filename, JSON.stringify(materialList, null, 4));
79 }
80
81 buildDownloadAttribute(imageFormat = 'PNG', imageResolution = '1') {
88 return `${imageResolution}K-${imageFormat}`;
89 }
90
96 return {
97 filename: this.downloadMaterialFileName,
98 content: this.downloadMaterial
99 };
100 }
101
106 if (this.downloadMaterial) {
107 this.downloadMaterial = null;
108 }
109 this.downloadMaterialFileName = '';
110 }
111
117 const haveDownload = this.downloadMaterialFileName && this.downloadMaterial;
118 if (!haveDownload) {
119 this.logger.warning('No current material downloaded');
120 return;
121 }
122
123 const filename = `${path}/${this.downloadMaterialFileName}`;
124 fs.writeFileSync(filename, this.downloadMaterial);
125 this.logger.info(`Saved downloaded material to: ${filename}`);
126 }
127
128 async downloadMaterialAsset(assetId, imageFormat = 'PNG', imageResolution = '1', downloadAttributeKey = 'downloadAttribute', downloadLinkKey = 'downloadLink') {
139
140 const items = this.findMaterial(assetId);
141 const target = this.buildDownloadAttribute(imageFormat, imageResolution);
142 let url = '';
143 let downloadAttribute = '';
144
145 items.forEach(item => {
146 downloadAttribute = item[downloadAttributeKey];
147 if (downloadAttribute === target) {
148 url = item[downloadLinkKey];
149 this.logger.info(`Found Asset: ${assetId}. Download Attribute: ${downloadAttribute} -> ${url}`);
150 }
151 });
152
153 if (!url) {
154 this.logger.error(`No download link found for asset: ${assetId}, attribute: ${target}`);
155 return '';
156 }
157
158 this.downloadMaterialFileName = url.split('file=')[1];
159
160 try {
161 const response = await axios.get(url, { responseType: 'arraybuffer' });
162 this.downloadMaterial = Buffer.from(response.data, 'binary');
163 this.logger.info(`Material file downloaded: ${this.downloadMaterialFileName}`);
164 } catch (error) {
165 this.downloadMaterialFileName = '';
166 this.logger.error(`Error occurred while downloading the file: ${error}`);
167 }
168
169 return this.downloadMaterialFileName;
170 }
171
172 findMaterial(assetId, key = 'assetId') {
179 if (this.materials) {
180 return this.materials.filter(item => item[key] === assetId);
181 }
182 return [];
183 }
184
191 this.materials = JSON.parse(fs.readFileSync(fileName, 'utf8'));
192 this.logger.info(`Loaded materials list from: ${fileName}`);
193 return this.materials;
194 }
195
201 const url = 'https://ambientCG.com/api/v2/downloads_csv';
202 const headers = { Accept: 'application/csv' };
203 const params = {
204 method: 'PBRPhotogrammetry',
205 type: 'Material',
206 sort: 'Alphabet',
207 };
208
209 this.logger.info('Downloading materials CSV list...');
210 try {
211 const response = await axios.get(url, { headers, params });
212 if (response.status === 200) {
213 const csvContent = response.data;
214 this.csvMaterials = csvContent;
215 //this.materials = parse(csvContent, { columns: true });
216 this.logger.info('Downloaded CSV material list as JSON.');
217 } else {
218 this.materials = null;
219 this.logger.warning(`Failed to fetch the CSV material content. HTTP status code: ${response.status}`);
220 }
221 } catch (error) {
222 this.materials = null;
223 this.logger.error(`Error downloading materials list: ${error}`);
224 }
225
226 return this.materials;
227 }
228
234 return this.database;
235 }
236
242 return this.assets;
243 }
244
250 this.database = {};
251 this.assets = null;
252
253 const url = 'https://ambientcg.com/api/v2/full_json';
254 const headers = { Accept: 'application/json' };
255 const params = {
256 method: 'PBRPhotogrammetry',
257 type: 'Material',
258 sort: 'Alphabet',
259 };
260
261 try {
262 const response = await axios.get(url, { headers, params });
263 if (response.status === 200) {
264 this.database = response.data;
265 this.assets = this.database.foundAssets;
266 } else {
267 this.logger.error(`Status: ${response.status}, ${response.data}`);
268 }
269 } catch (error) {
270 this.logger.error(`Error downloading asset database: ${error}`);
271 }
272
273 return this.database;
274 }
275
282 if (!this.database) {
283 this.logger.warning('No database to write');
284 return false;
285 }
286
287 fs.writeFileSync(filename, JSON.stringify(this.database, null, 4));
288 return true;
289 }
290
297 if (!this.mx) {
298 this.logger.error('MaterialX module is required');
299 return [false, ''];
300 }
301
302 if (!doc) {
303 this.logger.warning('MaterialX document is required');
304 return [false, ''];
305 }
306
307 const valid = doc.validate();
308 return [valid, valid ? '' : 'Validation failed'];
309 }
310
311 addComment(doc, commentString) {
317 const comment = doc.addChildOfCategory('comment');
318 comment.setDocString(commentString);
319 }
320
327 if (!this.mx) {
328 this.logger.error('MaterialX module is required');
329 return;
330 }
331
332 const writeOptions = this.mx.XmlWriteOptions();
333 writeOptions.writeXIncludeEnable = false;
334 writeOptions.elementPredicate = this.skipLibraryElement;
335 return this.mx.writeToXmlString(doc, writeOptions);
336 }
337}
338
339module.exports = AmbientCGLoader;
buildDownloadAttribute(imageFormat='PNG', imageResolution='1')
setDebugging(debug=true)
async downloadMaterialAsset(assetId, imageFormat='PNG', imageResolution='1', downloadAttributeKey='downloadAttribute', downloadLinkKey='downloadLink')
writeDownloadedMaterialToFile(path='')
addComment(doc, commentString)
constructor(mxModule, mxStdlib=null)
Class to load materials from the AmbientCG site.
findMaterial(assetId, key='assetId')
getMaterialNames(key='assetId')
writeDatabaseToFile(filename)
writeMaterialList(materialList, filename)