2@brief Utilities to extract materials from the ambientCG material database.
4See: https://docs.ambientcg.com/api/ for information on available API calls.
8from http
import HTTPStatus
19from typing
import Optional
23 @brief Class to load materials from the AmbientCG site.
24 The class can convert the materials to MaterialX format for given target shading models.
26 def __init__(self, mx_module, mx_stdlib : Optional[mx.Document] =
None):
28 @brief Constructor for the AmbientCGLoader class.
29 Will initialize shader mappings and load the MaterialX standard library
30 if it is not passed in as an argument.
31 @param mx_module The MaterialX module. Required.
32 @param mx_stdlib The MaterialX standard library. Optional.
36 self.
logger = lg.getLogger(
'ACGLoader')
37 lg.basicConfig(level=lg.INFO)
66 self.
logger.critical(f
'> {self._getMethodName()}: MaterialX module not specified.')
70 version_major, version_minor, version_patch = self.
mx.getVersionIntegers()
71 self.
logger.info(f
'Using MaterialX version: {version_major}.{version_minor}.{version_patch}')
72 if (version_major >=1
and version_minor >= 39)
or version_major > 1:
73 self.
logger.debug(
'> OpenPBR shading model supported')
78 self.
stdlib = self.
mx.createDocument()
79 libFiles = self.
mx.loadLibraries(mx.getDefaultDataLibraryFolders(), mx.getDefaultDataSearchPath(), self.
stdlib)
80 self.
logger.debug(f
'> Loaded standard library: {libFiles}')
84 @brief Set the debugging level for the logger.
85 @param debug True to set the logger to debug level, otherwise False.
89 self.
logger.setLevel(lg.DEBUG)
91 self.
logger.setLevel(lg.INFO)
95 Get the list of material names.
96 @param key The key to use for the material name. Default is 'assetId' based
97 on the version 2 ambientCG API.
98 @return The list of material names
104 unique_names.add(item.get(key) )
110 @brief Write the material list in JSON format to a file
111 @param materialList The list of materials to write
112 @param filename The file path to write the list to
115 self.
logger.info(f
'Writing material list to file: {filename}')
116 with open(filename, mode=
'w', encoding=
'utf-8')
as json_file:
117 json.dump(materialList, json_file, indent=4)
121 @brief Build the download attribute string for a given image format and resolution
122 Note: This is a hard-coded string format used by ambientCG. If this changes then this
124 @param imageFormat The image format to download
125 @param imageResolution The image resolution to download
126 @return The download attribute string
128 target = f
"{imageResolution}K-{imageFormat}"
133 @brief Get the current downloaded material information
140 @brief Clear any cached current material asset
150 @brief Write the currently downloaded file to file
151 @param path The output path for the material. Default is empty.
155 self.
logger.warning(
'No current material downloaded')
160 filename = os.path.join(path, filename)
165 with open(filename,
"wb")
as file:
174 self.
logger.info(f
"Saved downloaded material to: {filename}")
177 downloadAttributeKey = 'downloadAttribute', downloadLinkKey = 'downloadLink'):
179 @brief Download a material with a given id and format + resolution for images.
180 Default is to look for a 1K PNG variant.
181 @param assetId The string id of the material
182 @param imageFormat The image format to download. Default is PNG.
183 @param imageResolution The image resolution to download. Default is 1.
184 @param downloadAttributeKey The download attribute key. Default is 'downloadAttribute' based on the V2 ambientCG API.
185 @param downloadLinkKey The download link key. Default is 'downloadLink' based on the V2 ambientCG API.
186 @return File name of downloaded content
193 downloadAttribute =
''
197 downloadAttribute = item[downloadAttributeKey]
198 if downloadAttribute == target:
199 url = item[downloadLinkKey]
200 self.
logger.info(f
'Found Asset: {assetId}. Download Attribute: {downloadAttribute} -> {url}')
203 self.
logger.error(f
'No download link found for asset: {assetId}, attribute: {target}')
211 response = requests.get(url, stream=
True)
212 response.raise_for_status()
219 for chunk
in response.iter_content(chunk_size=CHUNK_SIZE):
222 self.
logger.info(f
"Material file downloaded: {self.downloadMaterialFileName}")
224 except requests.exceptions.RequestException
as e:
227 self.
logger.info(f
"Error occurred while downloading the file: {e}")
233 @brief Get the list of materials matching a material identifier
234 @param assetId Material string identifier
235 @param key The key to lookup asset identifiers. Default is 'assetId' based on the version 2 ambientCG API.
236 @return List of materials, or None if not found
239 materialList = [item
for item
in self.
materials if item.get(key) == assetId]
245 @brief Load in the list of downloadable materials from file.
246 @param fileName Name of JSON containing list
247 @return Materials list
249 with open(fileName,
'r')
as json_file:
251 self.
logger.info(f
'Loaded materials list from: {fileName}')
256 @brief Download the list of materials from the ambientCG site: "ttps://ambientCG.com/api/v2/downloads_csv"
257 Takes the origina CSV file and remaps this into JSON for runtime.
258 @return Materials list
261 url =
"https://ambientCG.com/api/v2/downloads_csv"
263 'Accept':
'application/csv'
266 'method':
'PBRPhotogrammetry',
271 self.
logger.info(
'Downloading materials CSV list...')
272 response = requests.get(url, headers=headers, params=parameters)
275 if response.status_code == HTTPStatus.OK:
284 self.
materials = [row
for row
in csv_reader]
286 self.
logger.info(
"Downloaded CSV material list as JSON.")
289 self.
logger.warning(
"Failed to parse the CSV material content")
293 self.
logger.warning(f
"Failed to fetch the CSV material content. HTTP status code: {response.status_code}")
299 @brief Get asset database
300 @return Asset database
306 @brief Get asset database material list
307 @return Material list
313 @brief Download the asset database for materials from the ambientCG site.
319 url =
'https://ambientcg.com/api/v2/full_json'
321 'Accept':
'application/json'
324 'method':
'PBRPhotogrammetry',
329 response = requests.get(url, headers=headers, params=parameters)
331 if response.status_code == HTTPStatus.OK:
335 self.
logger.error(f
'> Status: {response.status_code}, {response.text}')
339 @brief Write the database file
340 @param filename The filename to write the JSON file to
341 @return True if the file was written successfully, otherwise False
344 self.
logger.warning(
'No database to write')
347 with open(filename,
'w')
as json_file:
348 json.dump(self.
database, json_file, indent=4)
356 @brief Validate the MaterialX document
357 @param doc The MaterialX document to validate
358 @return A tuple of (valid, errors) where valid is True if the document is valid, and errors is a list of errors if the document is invalid.
361 self.
logger.critical(f
'> {self._getMethodName()}: MaterialX module is required')
365 self.
logger.warning(f
'> {self._getMethodName()}: MaterialX document is required')
368 valid, errors = doc.validate()
374 @brief Add a comment to the MaterialX document
375 @param doc The MaterialX document to add the comment to
376 @param commentString The comment string to add
379 comment = doc.addChildOfCategory(
'comment')
380 comment.setDocString(commentString)
385 @brief Convert the MaterialX document to a string
386 @return The MaterialX document as a string
389 self.
logger.critical(f
'> {self._getMethodName()}: MaterialX module is required')
392 writeOptions = self.
mx.XmlWriteOptions()
393 writeOptions.writeXIncludeEnable =
False
394 writeOptions.elementPredicate = self.skipLibraryElement
395 mtlx = self.
mx.writeToXmlString(doc, writeOptions)
Class to load materials from the AmbientCG site.
logger
logger is the logging object for the class
validateMaterialXDocument(self, doc)
Validate the MaterialX document.
getMaterialXString(self, doc)
Convert the MaterialX document to a string.
getDownloadedMaterialInformation(self)
Get the current downloaded material information.
downloadMaterialAsset(self, assetId, imageFormat='PNG', imageResolution='1', downloadAttributeKey='downloadAttribute', downloadLinkKey='downloadLink')
Download a material with a given id and format + resolution for images.
getDataBase(self)
Get asset database.
bool support_openpbr
Flag to indicate OpenPBR shader support.
dict database
Database of asset information.
list materials
List of materials in JSON format.
findMaterial(self, assetId, key='assetId')
Get the list of materials matching a material identifier.
csv_materials
List of materials in CSV format.
addComment(self, doc, commentString)
Add a comment to the MaterialX document.
dict downloadAssetDatabase(self)
Download the asset database for materials from the ambientCG site.
downloadMaterialsList(self)
Download the list of materials from the ambientCG site: "ttps://ambientCG.com/api/v2/downloads_csv" T...
writeDatabaseToFile(self, filename)
Write the database file.
buildDownLoadAttribute(self, imageFormat='PNG', imageResolution='1')
Build the download attribute string for a given image format and resolution Note: This is a hard-code...
__init__(self, mx_module, Optional[mx.Document] mx_stdlib=None)
Constructor for the AmbientCGLoader class.
clearDownloadMaterial(self)
Clear any cached current material asset.
list materialNames
List of material names.
stdlib
MaterialX standard library.
downloadMaterial
Current downloaded material.
writeDownloadedMaterialToFile(self, path='')
Write the currently downloaded file to file.
str downloadMaterialFileName
Current downlaoded material file name.
setDebugging(self, Optional[bool] debug=True)
Set the debugging level for the logger.
writeMaterialList(self, materialList, filename)
Write the material list in JSON format to a file.
list getMaterialNames(self, key='assetId')
Get the list of material names.
getDataBaseMaterialList(self)
Get asset database material list.
dict assets
Reference to database found assets.
loadMaterialsList(self, fileName)
Load in the list of downloadable materials from file.