123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- """
- Copyright (c) Contributors to the Open 3D Engine Project.
- For complete copyright and license terms please see the LICENSE at the root of this distribution.
- SPDX-License-Identifier: Apache-2.0 OR MIT
- """
- from PySide2 import QtWidgets
- import azlmbr.asset as asset
- import azlmbr.atom
- import azlmbr.bus
- import azlmbr.math as math
- import azlmbr.name
- import azlmbr.paths
- import azlmbr.shader
- import azlmbr.shadermanagementconsole
- import json
- import os
- # Make a copy of shaderVariants, update target option value and return copy, accumulate stableId
- def updateOptionValue(shaderVariants, targetOptionName, targetValue, stableId):
- tempShaderVariants = []
-
- for variantInfo in shaderVariants:
- tempVariantInfo = azlmbr.shader.ShaderVariantInfo()
- options = {}
- for optionName in variantInfo.options:
- if targetOptionName == optionName:
- options[optionName] = targetValue
- else:
- options[optionName] = variantInfo.options[optionName]
- tempVariantInfo.options = options
- tempVariantInfo.stableId = stableId
- tempShaderVariants.append(tempVariantInfo)
- stableId += 1
- return tempShaderVariants, stableId
- # alters the option group passed in argument by clearing internal options if predicate passes
- def clearOptions(optionGroup, predicateTakingOptionName_clearIfYes):
- descriptors = optionGroup.GetShaderOptionDescriptors()
- for optDesc in descriptors:
- optionName = optDesc.GetName()
- if predicateTakingOptionName_clearIfYes(optionName):
- optionGroup.ClearValue(optionName)
- # Input is one .shader
- def create_shadervariantlist_for_shader(filename):
- print(f"Creating shader variant list for {filename}")
- # Get info such as relative path of the file and asset id
- shaderAssetInfo = azlmbr.shadermanagementconsole.ShaderManagementConsoleRequestBus(
- azlmbr.bus.Broadcast,
- 'GetSourceAssetInfo',
- filename
- )
- # retrieves a list of all material source files that use the shader. Note that materials inherit from materialtype files, which are actual files that refer to shader files.
- materialAssetIds = azlmbr.shadermanagementconsole.ShaderManagementConsoleRequestBus(
- azlmbr.bus.Broadcast,
- 'FindMaterialAssetsUsingShader',
- shaderAssetInfo.relativePath
- )
- print(f"Found {len(materialAssetIds)} material assets referencing shader")
- shaderVariantList = azlmbr.shader.ShaderVariantListSourceData()
- shaderVariantList.shaderFilePath = shaderAssetInfo.relativePath
- if len(materialAssetIds) == 0:
- # No material is using this shader, so we can't get ShaderOptionDescriptor in the script
- # Return early and handle user assigned system option after shaderAsset is loaded
- return shaderVariantList
-
- # This loop collects all uniquely-identified shader items used by the materials based on its shader variant id.
- shader_file = os.path.basename(filename)
- shaderVariantIds = []
- shaderOptionGroups = []
- progressDialog = QtWidgets.QProgressDialog(f"Generating .shadervariantlist file for:\n{shader_file}", "Cancel", 0, len(materialAssetIds))
- progressDialog.setMaximumWidth(400)
- progressDialog.setMaximumHeight(100)
- progressDialog.setModal(True)
- progressDialog.setWindowTitle("Generating Shader Variant List")
- for i, materialAssetId in enumerate(materialAssetIds):
- materialInstanceShaderItems = azlmbr.shadermanagementconsole.ShaderManagementConsoleRequestBus(azlmbr.bus.Broadcast, 'GetMaterialInstanceShaderItems', materialAssetId)
- for shaderItem in materialInstanceShaderItems:
- shaderAssetId = shaderItem.GetShaderAsset().get_id()
- if shaderAssetInfo.assetId == shaderAssetId:
- shaderVariantId = shaderItem.GetShaderVariantId()
- if not shaderVariantId.IsEmpty():
- # Check for repeat shader variant ids. We are using a list here
- # instead of a set to check for duplicates on shaderVariantIds because
- # shaderVariantId is not hashed by the ID like it is in the C++ side.
- has_repeat = False
- for variantId in shaderVariantIds:
- if shaderVariantId == variantId:
- has_repeat = True
- break
- if has_repeat:
- continue
- shaderVariantIds.append(shaderVariantId)
- optionGroup = shaderItem.GetShaderOptionGroup()
- # clear the group from spuriously defaulted options by reducing it to a lean set:
- clearOptions(optionGroup, lambda optName_Query: not shaderItem.MaterialOwnsShaderOption(optName_Query))
- shaderOptionGroups.append(optionGroup)
- progressDialog.setValue(i)
- # processing events to update UI after progress bar changes
- QtWidgets.QApplication.processEvents()
- # Allowing the application to process idle events for one frame to update systems and garbage collect graphics resources
- azlmbr.atomtools.general.idle_wait_frames(1)
- if progressDialog.wasCanceled():
- return
- progressDialog.close()
- # Read from shaderPath.systemoptions to get user assigned system option value
- pre, ext = os.path.splitext(filename)
- systemOptionFilePath = f'{pre}.systemoptions'
- systemOptionFilePath = systemOptionFilePath.replace("\\", "/")
- systemOptionDict = {}
- if os.path.isfile(systemOptionFilePath):
- with open(systemOptionFilePath, "r") as systemOptionFile:
- systemOptionDict = json.load(systemOptionFile)
- # Generate the shader variant list data by collecting shader option name-value pairs.
- shaderVariants = []
- systemOptionDescriptor = {}
- stableId = 1
- for shaderOptionGroup in shaderOptionGroups:
- variantInfo = azlmbr.shader.ShaderVariantInfo()
- variantInfo.stableId = stableId
- options = {}
- shaderOptionDescriptors = shaderOptionGroup.GetShaderOptionDescriptors()
- for shaderOptionDescriptor in shaderOptionDescriptors:
- optionName = shaderOptionDescriptor.GetName()
- optionValue = shaderOptionGroup.GetValueByOptionName(optionName)
- if not optionValue.IsValid():
- continue
- valueName = shaderOptionDescriptor.GetValueName(optionValue)
- options[optionName] = valueName
- # Check user assigned value
- optionNameString = optionName.ToString()
- if optionNameString in systemOptionDict:
- if systemOptionDict[optionNameString] != "":
- options[optionName] = azlmbr.name.Name(systemOptionDict[optionNameString])
- else:
- # Value is unset, expansion handling later
- systemOptionDescriptor[optionName] = shaderOptionDescriptor
- if len(options) != 0:
- variantInfo.options = options
- shaderVariants.append(variantInfo)
- stableId += 1
- shaderVariantList.materialOptionsHint = set(options.keys()) - set(systemOptionDict.keys())
- # Expand the unset system option
- for systemOptionName in systemOptionDescriptor:
- optionDescriptor = systemOptionDescriptor[systemOptionName]
- defaultValue = optionDescriptor.GetDefaultValue()
-
- valueMin = optionDescriptor.GetMinValue()
- valueMax = optionDescriptor.GetMaxValue()
- totalShaderVariants = []
-
- for index in range(valueMin.GetIndex(), valueMax.GetIndex() + 1):
- optionValue = optionDescriptor.GetValueNameByIndex(index)
- if optionValue != defaultValue:
- tempShaderVariants, stableId = updateOptionValue(shaderVariants, systemOptionName, optionValue, stableId)
- totalShaderVariants.extend(tempShaderVariants)
-
- shaderVariants.extend(totalShaderVariants)
- shaderVariantList.shaderVariants = shaderVariants
- return shaderVariantList
|