Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,55 @@
{
"description": "",
"materialType": "Materials/Types/StandardPBR.materialtype",
"parentMaterial": "",
"propertyLayoutVersion": 3,
"properties": {
"ambientOcclusion": {
"factor": 1.0,
"useTexture": true,
"textureMap": "EngineAssets/TextureMsg/DefaultNoUVs.tif"
},
"baseColor": {
"color": [ 1.0, 1.0, 1.0 ],
"factor": 1.0,
"useTexture": true,
"textureMap": "EngineAssets/TextureMsg/DefaultNoUVs.tif"
},
"emissive": {
"color": [ 1.0, 1.0, 1.0 ],
"intensity": 1.0,
"useTexture": false,
"textureMap": "EngineAssets/TextureMsg/DefaultNoUVs.tif"
},
"metallic": {
"factor": 0.0,
"useTexture": false,
"textureMap": ""
},
"roughness": {
"factor": 1.0,
"useTexture": true,
"textureMap": "EngineAssets/TextureMsg/DefaultNoUVs_spec.tif"
},
"specularF0": {
"factor": 0.5,
"useTexture": false,
"textureMap": ""
},
"normal": {
"factor": 1.0,
"useTexture": true,
"textureMap": "EngineAssets/TextureMsg/DefaultNoUVs_ddn.tif"
},
"opacity": {
"doubleSided": false,
"factor": 1.0,
"cutoutAlpha": false,
"cutoutThreshold": 0.5,
"useBaseColorTextureAlpha": false,
"useTexture": false,
"textureMap": ""
}
}
}
@@ -0,0 +1,14 @@
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
__all__ = ['atom_mat',
'fbx_to_atom',
'stingraypbs_converter',
'stingraypbs_converter_maya']
@@ -0,0 +1,66 @@
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
#
# -- This line is 75 characters -------------------------------------------
"""
Module Documentation: To Do
"""
# -------------------------------------------------------------------------
# built-ins
import json
# 3rdParty
from box import Box
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
class AtomMaterial:
def __init__(self, material_file):
'''To Do: document'''
# loading .material Files
self.material_file = material_file
self.input_data = open(self.material_file, "r")
self.material = json.load(self.input_data)
self.mat_box = Box(self.material)
self.input_data.close()
# Texture map dictionary:
self.texture_map = {'ambientOcclusion': 'ambientOcclusion',
'baseColor': 'baseColor',
'emissive': 'emissive',
'metallic': 'metallic',
'roughness': 'roughness',
'specularF0': 'specular',
'normal': 'normal',
'opacity': 'opacity'
}
def load(self, material_file):
input_data = open(material_file, "r")
self.material = json.load(input_data)
self.mat_box = Box(self.material)
input_data.close()
def getBaseMaterial(self):
return self.mat_box.material.baseMaterial
def getMap(self, tex_slot):
return self.mat_box.properties[tex_slot].textureMap
def setMap(self, tex_slot, tex_map):
self.mat_box.properties[tex_slot].textureMap = tex_map
self.mat_box.properties[tex_slot].useTexture = True
self.mat_box.properties[tex_slot].factor = 1.0
def write(self, material_out):
output_data = open(material_out, "w+")
output_data.write(json.dumps(self.mat_box, indent=4))
output_data.close()
# -------------------------------------------------------------------------
@@ -0,0 +1,67 @@
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
#
# -- This line is 75 characters -------------------------------------------
import simplejson as json
from box import Box
from atom_mat import AtomMaterial as atomMat
"""
The idea behind this script is to convert FBX to glTF in order to take advantage of glTF format
FBX2glTF CLT:
https://github.com/facebookincubator/FBX2glTF
ToDo:
Add FBX2glTF subprocess to the script.
"""
atom_material = atomMat("C:\\atom\\dev\\AtomTest\\Editor\\Scripts\\atom\\maya\\StandardPBR_AllProperties.material")
""" All these path could be in configure file or bootstrapped """
fbx_root = 'C:\\atom\\dev\\Gems\\AtomContent\\AtomDemoContent\\Assets\\Objects\\Peccy\\'
rel_root = "C:\\atom\\dev\\Gems\\AtomContent\\AtomDemoContent\\Assets\\"
texture_root = 'Objects\\Peccy\\'
# -------------------------------------------------------------------------
class FBX:
def __init__(self, fbx_file):
self.fbx_file = fbx_file
self.glTF_file = self.fbx_file.replace("fbx", "gltf")
self.input_data = open(self.glTF_file, "r")
self.glTF_properties = json.load(self.input_data)
self.glTF_box = Box(self.glTF_properties)
self.input_data.close()
def get_material_names(self):
return self.glTF_box.materials
def get_textures(self, index):
return self.glTF_box.images[index]
def create_atom_material(self):
for mat_index in range(len(fbx01.get_material_names())):
baseColorTexture_index = self.get_material_names()[mat_index].pbrMetallicRoughness.baseColorTexture.index
atom_material.setMap(atom_material.texture_map['baseColor'], texture_root +
self.get_textures(baseColorTexture_index).uri)
normalTexture_index = self.get_material_names()[mat_index].normalTexture.index
atom_material.setMap(atom_material.texture_map['normal'], texture_root +
self.get_textures(normalTexture_index).uri)
roughnessTexture_index = self.get_material_names()[mat_index].\
pbrMetallicRoughness.metallicRoughnessTexture.index
atom_material.setMap(atom_material.texture_map['roughness'], texture_root +
self.get_textures(roughnessTexture_index).uri)
atom_material.write(rel_root + "\\Materials\\" + fbx01.get_material_names()[mat_index].name + ".material")
# -------------------------------------------------------------------------
if __name__ == "__main__":
fbx01 = FBX(fbx_root + 'peccy_01.fbx')
fbx01.create_atom_material()
@@ -0,0 +1,121 @@
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
import os
import site
from unipath import Path
import click
import glob
# -------------------------------------------------------------------------
def returnStubDir(stub):
_DIRtoLastFile = None
'''Take a file name (stub) and returns the directory of the file (stub)'''
if _DIRtoLastFile is None:
path = os.path.abspath(__file__)
while 1:
path, tail = os.path.split(path)
if (os.path.isfile(os.path.join(path, stub))):
break
if (len(tail) == 0):
path = ""
if _G_DEBUG:
print('~ Debug Message: I was not able to find the '
'path to that file (stub) in a walk-up from currnet path')
break
_DIRtoLastFile = path
return _DIRtoLastFile
# --------------------------------------------------------------------------
# Paths for the quick tests. These could throw a UI or a configuration on it.
_DEV_ROOT = Path(returnStubDir('engineroot.txt')).resolve() #hopefully safe
_REL_ROOT = Path(_DEV_ROOT, 'AtomTest').resolve()
_MAYA_SCRIPTS = Path(_REL_ROOT, 'Editor/Scripts/atom/maya').resolve()
site.addsitedir(_MAYA_SCRIPTS)
from atom_mat import AtomMaterial as atomMAT
_ATOM_MAT_TEMPLATE = atomMAT(Path(_MAYA_SCRIPTS,
'StandardPBR_AllProperties.material').resolve())
_model_asset_dir = Path(_REL_ROOT, 'Objects/Characters/Peccy').resolve()
_atom_mat_path = Path(_REL_ROOT, 'Objects/Characters/Peccy').resolve()
import pymel.core as pm
def converter(_model_asset_dir, _atom_mat_path):
_maya_file = glob.glob(_model_asset_dir + '*.ma')
print(_maya_file)
for maya in range(len(_maya_file)):
pm.openFile(_maya_file[maya], f=True, prompt=False)
set_stingray_properties()
# This is ugly but work.
# To to: remove all of duplications.
def set_stingray_properties():
nodes = pm.ls(dag=1, o=1, s=1)
shade_eng = pm.listConnections(nodes, type=pm.nt.ShadingEngine)
materials = pm.ls(pm.listConnections(shade_eng), materials=1)
mat = []
for i in materials:
if i not in mat:
mat.append(i)
print(mat)
for j in range(len(mat)):
file_node_baseColor = pm.listConnections(mat[j].TEX_color_map)
if (file_node_baseColor and pm.objectType(file_node_baseColor[0]) == 'file'
and pm.getAttr(mat[j].use_color_map)):
tex_baseColor = Path(pm.getAttr(file_node_baseColor[0].fileTextureName)).norm().replace(_REL_ROOT, "")
_ATOM_MAT_TEMPLATE.setMap(_ATOM_MAT_TEMPLATE.texture_map['baseColor'], tex_baseColor)
# else:
# _baseColor = pm.getAttr(mat[j].base_color)
# _ATOM_MAT_TEMPLATE.setColor(_ATOM_MAT_TEMPLATE.texture_map['baseColor'], _baseColor)
# print(mat[j])
# print(baseColor)
file_node_normal = pm.listConnections(mat[j].TEX_normal_map)
if (file_node_normal and pm.objectType(file_node_normal[0]) == 'file'
and pm.getAttr(mat[j].use_normal_map)):
tex_normal = Path(pm.getAttr(file_node_normal[0].fileTextureName)).norm().replace(_REL_ROOT, "")
_ATOM_MAT_TEMPLATE.setMap(_ATOM_MAT_TEMPLATE.texture_map['normal'], tex_normal)
file_node_metallic = pm.listConnections(mat[j].TEX_metallic_map)
if (file_node_metallic and pm.objectType(file_node_metallic[0]) == 'file'
and pm.getAttr(mat[j].use_metallic_map)):
tex_metallic = Path(pm.getAttr(file_node_metallic[0].fileTextureName)).norm().replace(_REL_ROOT, "")
_ATOM_MAT_TEMPLATE.setMap(_ATOM_MAT_TEMPLATE.texture_map['metallic'], tex_metallic)
file_node_roughness = pm.listConnections(mat[j].TEX_roughness_map)
if (file_node_roughness and pm.objectType(file_node_roughness[0]) == 'file'
and pm.getAttr(mat[j].use_roughness_map)):
file_node_roughness = pm.listConnections(mat[j].TEX_roughness_map)
tex_roughness = Path(pm.getAttr(file_node_roughness[0].fileTextureName)).norm().replace(_REL_ROOT, "")
_ATOM_MAT_TEMPLATE.setMap(_ATOM_MAT_TEMPLATE.texture_map['roughness'], tex_roughness)
file_node_ao = pm.listConnections(mat[j].TEX_ao_map)
if (file_node_ao and pm.objectType(file_node_ao[0]) == 'file'
and pm.getAttr(mat[j].use_ao_map)):
tex_ao = Path(pm.getAttr(file_node_ao[0].fileTextureName)).norm().replace(_REL_ROOT, "")
_ATOM_MAT_TEMPLATE.setMap(_ATOM_MAT_TEMPLATE.texture_map['ambientOcclusion'], tex_ao)
_ATOM_MAT_TEMPLATE.write(_REL_ROOT + "\\Materials\\" + str(mat[j])+".material")
@click.command()
@click.option('--maya', default=_model_asset_dir, help='Maya file folder')
@click.option('--output', default=_atom_mat_path, help='Atom Material output path')
def stingrayPBS_converter(maya, output):
click.echo(converter(maya, output))
if __name__ == '__main__':
stingrayPBS_converter()
@@ -0,0 +1,117 @@
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
#
# -- This line is 75 characters -------------------------------------------
import os
import site
from unipath import Path
import maya.cmds as cmds
# -------------------------------------------------------------------------
def returnStubDir(stub, start_path):
_DIRtoLastFile = None
'''Take a file name (stub) and returns the directory of the file (stub)'''
if _DIRtoLastFile is None:
path = os.path.abspath(start_path)
while 1:
path, tail = os.path.split(path)
if (os.path.isfile(os.path.join(path, stub))):
break
if (len(tail) == 0):
path = ""
if _G_DEBUG:
print('~ Debug Message: I was not able to find the '
'path to that file (stub) in a walk-up from currnet path')
break
_DIRtoLastFile = path
return _DIRtoLastFile
# --------------------------------------------------------------------------
# Paths for the quick tests. These could throw a UI or a configuration on it.
_ASSET_PATH = Path(cmds.file(q=True, sn=True)).parent.resolve()
_DEV_ROOT = Path(returnStubDir('engineroot.txt', _ASSET_PATH)).resolve() # hopefully safe
_REL_ROOT = Path(_DEV_ROOT, 'AtomTest').resolve()
_MAYA_SCRIPTS = Path(_REL_ROOT, 'Editor/Scripts/atom/maya').resolve()
site.addsitedir(_MAYA_SCRIPTS)
from atom_mat import AtomMaterial as atomMAT
_ATOM_MAT_TEMPLATE = atomMAT(Path(_MAYA_SCRIPTS,
'StandardPBR_AllProperties.material').resolve())
import pymel.core as pm
class StingrayPBS(object):
def __init__(self):
# Append material from selected object(S)
nodes = pm.ls(dag=1, o=1, s=1, sl=1)
shade_eng = pm.listConnections(nodes, type=pm.nt.ShadingEngine)
material = pm.ls(pm.listConnections(shade_eng), materials=1)
self.mat = []
for i in material:
if i not in self.mat:
self.mat.append(i)
# Make a StringrayPBS instance
strpbs = StingrayPBS()
# This is ugly but work.
# To to: remove all of duplications.
for i in range(len(strpbs.mat)):
file_node_baseColor = pm.listConnections(strpbs.mat[i].TEX_color_map)
if (file_node_baseColor and pm.objectType(file_node_baseColor[0]) == 'file'
and pm.getAttr(strpbs.mat[i].use_color_map)):
tex_baseColor = Path(pm.getAttr(file_node_baseColor[0].fileTextureName)).resolve()
tex_baseColor = _REL_ROOT.rel_path_to(tex_baseColor)
tex_baseColor = tex_baseColor.replace('\\', '/')
_ATOM_MAT_TEMPLATE.setMap(_ATOM_MAT_TEMPLATE.texture_map['baseColor'], tex_baseColor)
# else:
# _baseColor = pm.getAttr(strpbs.mat[i].base_color)
# _ATOM_MAT_TEMPLATE.setColor(_ATOM_MAT_TEMPLATE.texture_map['baseColor'], _baseColor)
# print(strpbs.mat[i])
# print(baseColor)
file_node_normal = pm.listConnections(strpbs.mat[i].TEX_normal_map)
if (file_node_normal and pm.objectType(file_node_normal[0]) == 'file'
and pm.getAttr(strpbs.mat[i].use_normal_map)):
tex_normal = Path(pm.getAttr(file_node_normal[0].fileTextureName)).resolve()
tex_normal = _REL_ROOT.rel_path_to(tex_normal)
tex_normal = tex_normal.replace('\\', '/')
_ATOM_MAT_TEMPLATE.setMap(_ATOM_MAT_TEMPLATE.texture_map['normal'], tex_normal)
file_node_metallic = pm.listConnections(strpbs.mat[i].TEX_metallic_map)
if (file_node_metallic and pm.objectType(file_node_metallic[0]) == 'file'
and pm.getAttr(strpbs.mat[i].use_metallic_map)):
tex_metallic = Path(pm.getAttr(file_node_metallic[0].fileTextureName)).resolve()
tex_metallic = _REL_ROOT.rel_path_to(tex_metallic)
tex_metallic = tex_metallic.replace('\\', '/')
_ATOM_MAT_TEMPLATE.setMap(_ATOM_MAT_TEMPLATE.texture_map['metallic'], tex_metallic)
file_node_roughness = pm.listConnections(strpbs.mat[i].TEX_roughness_map)
if (file_node_roughness and pm.objectType(file_node_roughness[0]) == 'file'
and pm.getAttr(strpbs.mat[i].use_roughness_map)):
file_node_roughness = pm.listConnections(strpbs.mat[i].TEX_roughness_map)
tex_roughness = Path(pm.getAttr(file_node_roughness[0].fileTextureName)).resolve()
tex_roughness = _REL_ROOT.rel_path_to(tex_roughness)
tex_roughness = tex_roughness.replace('\\', '/')
_ATOM_MAT_TEMPLATE.setMap(_ATOM_MAT_TEMPLATE.texture_map['roughness'], tex_roughness)
file_node_ao = pm.listConnections(strpbs.mat[i].TEX_ao_map)
if (file_node_ao and pm.objectType(file_node_ao[0]) == 'file'
and pm.getAttr(strpbs.mat[i].use_ao_map)):
tex_ao = Path(pm.getAttr(file_node_ao[0].fileTextureName)).resolve()
tex_ao = _REL_ROOT.rel_path_to(tex_ao)
tex_ao = tex_ao.replace('\\', '/')
_ATOM_MAT_TEMPLATE.setMap(_ATOM_MAT_TEMPLATE.texture_map['ambientOcclusion'], tex_ao)
_ATOM_MAT_TEMPLATE.write(Path(_ASSET_PATH, "{}.material".format(str(strpbs.mat[i]))).resolve())
@@ -0,0 +1,35 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -- This line is 75 characters -------------------------------------------
"""
Module Documentation:
DccScriptingInterface:: SDK//maya//scripts//constants.py
This module is mainly a bunch of commony used constants, and default strings
So we can make an update here once that is used elsewhere
"""
# -------------------------------------------------------------------------
# built-ins
# none
# -- External Python modules
# -- DCCsi Extension Modules
#import azpy
# -- maya imports
# none
# -------------------------------------------------------------------------
OBJ_DCCSI_MAINMENU = 'LyDCCsiMainMenu'
TAG_DCCSI_MAINMENU = 'DCCsi (LY:Atom)'
@@ -0,0 +1,204 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -- This line is 75 characters -------------------------------------------
"""
Module Documentation:
DccScriptingInterface:: SDK//maya//scripts//set_callbacks.py
This module manages a set of predefined callbacks for maya
"""
# -------------------------------------------------------------------------
# -- Standard Python modules
import os
import sys
import logging as _logging
# -- External Python modules
from box import Box
# maya imports
import maya.cmds as mc
import maya.api.OpenMaya as om
# -- DCCsi Extension Modules
from azpy.constants import *
import azpy.maya
azpy.maya.init() # <-- should have already run?
import azpy.maya.callbacks.event_callback_handler as azEvCbH
import azpy.maya.callbacks.node_message_callback_handler as azNdMsH
# Node Message Callback Setup
import azpy.maya.callbacks.on_shader_rename as oSR
from set_defaults import set_defaults
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
from azpy.env_bool import env_bool
from azpy.constants import ENVAR_DCCSI_GDEBUG
from azpy.constants import ENVAR_DCCSI_DEV_MODE
# global space
_G_DEBUG = env_bool(ENVAR_DCCSI_GDEBUG, True)
_DCCSI_DEV_MODE = env_bool(ENVAR_DCCSI_DEV_MODE, True)
_MODULENAME = r'DCCsi.SDK.Maya.Scripts.set_callbacks'
_LOGGER = azpy.initialize_logger(_MODULENAME, default_log_level=int(20))
_LOGGER.debug('Invoking:: {0}.'.format({_MODULENAME}))
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# global scope callbacks, set up set and initialize all to None
# To Do: should callback initialization use data-driven settings?
# To Do: should we move callback initialization to a sub-module?
# To Do: move the callback key like 'NewSceneOpened' here (instead of None)
# ^ this would provide ability to loop through and replace key with CB object
_G_callbacks = Box(box_dots=True) # global scope container
_G_masterkey = 'DCCsi_callbacks'
_G_callbacks[_G_masterkey] = True # required master key
# -------------------------------------------------------------------------
def init_callbacks(_callbacks=_G_callbacks):
# store as a dict (Box is a fancy dict)
_callbacks[_G_masterkey] = True # required master key
# signature dict['callback key'] = ('CallBack'(type), func, callbackObj)
_callbacks['on_new_file'] = ['NewSceneOpened', set_defaults, None]
_callbacks['new_scene_fix_paths'] = ['NewSceneOpened', install_fix_paths, None]
_callbacks['post_scene_fix_paths'] = ['PostSceneRead', install_fix_paths, None]
_callbacks['workspace_changed'] = ['workspaceChanged', update_workspace, None]
_callbacks['quit_app'] = ['quitApplication', uninstall_callbacks, None]
# nodeMessage style callbacks
# fire a function
_func_00 = oSR.on_shader_rename_rename_shading_group
# using a nodeMessage callback trigger
_cb_00 = om.MNodeMessage.addNameChangedCallback
# all nodeMessage type callbacks can use 'nodeMessageType' key
_callbacks['shader_rename'] = ['nodeMessageType', (_func_00, _cb_00), None]
return _callbacks
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
def uninstall_callbacks():
"""Bulk uninstalls hte globally defined set of callbacks:
_G_callbacks"""
global _G_callbacks
_LOGGER.debug('uninstall_callbacks() fired')
for key, value in _G_callbacks:
if value[2] is not None: # have a cb
value[2].uninstall() # so uninstall it
else:
_LOGGER.warning('No callback in: key {0}, value:{1}'
''.format(key, value))
_G_callbacks = None
_LOGGER.info('DCCSI CALLBACKS UNINSTALLED ... EXITING')
return _G_callbacks
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
def install_callbacks(_callbacks=_G_callbacks):
"""Bulk installs the globally defined set of callbacks:
_G_callbacks"""
_LOGGER.debug('install_callback_set() fired')
_callbacks = init_callbacks(_callbacks)
# we initialized the box with this so pop it
if 'box_dots' in _callbacks:
_callbacks.pop('box_dots')
# don't pass anything but carefully considered dict
if _G_masterkey in _callbacks:
_masterkey = _callbacks.pop(_G_masterkey)
else:
_LOGGER.error('No master key, use a correct dictionary')
#To Do: implement error handling and return codes
return _callbacks[None]
for key, value in _G_callbacks.items():
# we popped the master key should the rest should be safe
if value[0] != 'nodeMessageType':
# set callback up
_cb = azEvCbH.EventCallbackHandler(value[0],
value[1])
# ^ installs by default
# stash it back into managed dict
value[2] = _cb
# value[2].install()
else:
# set up callback, value[1] should be tupple(func, trigger)
_cb = azNdMsH.NodeMessageCallbackHandler(value[1][0],
value[1][1])
# ^ installs by default
# stash it back into managed dict
value[2] = _cb
# value[2].install()
return _callbacks
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
def install_fix_paths(foo=None):
"""Installs and triggers a fix paths module.
This can repair broken reference paths in shaders"""
global _fix_paths
_fix_paths = None
_LOGGER.debug('install_fix_paths() fired')
# if we don't have it already, this function is potentially triggered
# by a callback, so we don't need to keep importing it.
try:
_fix_paths
reload(_fix_paths)
except Exception as e:
try:
import fixPaths as _fix_paths
except Exception as e:
# To Do: not implemented yet
_LOGGER.warning('NOT IMPLEMENTED: {0}'.format(e))
# if we have it, use it
if _fix_paths:
return _fix_paths.main()
else:
# To Do: implement error handling and return codes
return 1
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
def update_workspace(foo=None):
"""Forces and update of the workspace (workspace.mel)"""
_LOGGER.debug('update_workspace() fired')
result = mc.workspace(update=True)
return result
# -------------------------------------------------------------------------
# install and init callbacks on an import obj
_G_callbacks = install_callbacks(_G_callbacks)
# ==========================================================================
# Module Tests
#==========================================================================
if __name__ == '__main__':
_G_callbacks = install_callbacks(_G_callbacks)
@@ -0,0 +1,96 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -- This line is 75 characters -------------------------------------------
"""
Module Documentation:
DccScriptingInterface:: SDK//maya//scripts//set_pref_defaults.py
This module manages a predefined set of prefs for maya
"""
# -------------------------------------------------------------------------
# -- Standard Python modules
import os
import sys
# -- External Python modules
# -- DCCsi Extension Modules
import azpy
from azpy.constants import *
# -- maya imports
import maya.cmds as mc
import maya.mel as mm
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
from azpy.env_bool import env_bool
from azpy.constants import ENVAR_DCCSI_GDEBUG
from azpy.constants import ENVAR_DCCSI_DEV_MODE
# global space
_G_DEBUG = env_bool(ENVAR_DCCSI_GDEBUG, False)
_DCCSI_DEV_MODE = env_bool(ENVAR_DCCSI_DEV_MODE, False)
_MODULENAME = r'DCCsi.SDK.Maya.Scripts.set_defaults'
_LOGGER = azpy.initialize_logger(_MODULENAME, default_log_level=int(20))
_LOGGER.debug('Invoking:: {0}.'.format({_MODULENAME}))
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
def set_defaults(units='meter'):
"""This method will make defined settings changes to Maya prefs,
to better configure maya to work with Lumberyard"""
# To Do: make this data-driven env/settings, game teams should be able
# to opt out and/or set their prefered configuration.
_LOGGER.debug('set_defaults_lumberyard() fired')
# set up default units ... this should be moved to bootstrap config
_LOGGER.info('Default, 1 Linear Game Unit in Lumberyard == 1 Meter'
' in Maya content. Setting default linear units to Meters'
' (user can change to other units in the preferences)')
result = mc.currentUnit(linear=units)
# set up grid defaults
_LOGGER.info('Setting Grid defaults, to match default unit scale.'
'(user can change grid config manually')
try:
mc.grid(size=32, spacing=1, divisions=10)
except Exception as e:
_LOGGER.warning('{0}'.format(e))
# viewFit
_LOGGER.info('Changing default mc.viewFit')
try:
mc.viewFit()
except Exception as e:
_LOGGER.warning('{0}'.format(e))
# some mel commands
_LOGGER.info('Changing sersp camera clipping planes')
try:
mm.eval(str(r'setAttr "perspShape.nearClipPlane" 0.01;'))
mm.eval(str(r'setAttr "perspShape.farClipPlane" 1000;'))
except Exception as e:
_LOGGER.warning('{0}'.format(e))
# set up fixPaths
_LOGGER.info('~ Setting up fixPaths in default scene')
return 0
# -------------------------------------------------------------------------
@@ -0,0 +1,91 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -- This line is 75 characters -------------------------------------------
"""
Module Documentation:
DccScriptingInterface:: SDK//maya//scripts//set_menu.py
This module creates and manages a DCCsi mainmenu
"""
# -------------------------------------------------------------------------
# -- Standard Python modules
# none
# -- External Python modules
# none
# -- DCCsi Extension Modules
import azpy
from constants import OBJ_DCCSI_MAINMENU
from constants import TAG_DCCSI_MAINMENU
# -- maya imports
import pymel.core as pm
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
from azpy.env_bool import env_bool
from azpy.constants import ENVAR_DCCSI_GDEBUG
from azpy.constants import ENVAR_DCCSI_DEV_MODE
# global space
_G_DEBUG = env_bool(ENVAR_DCCSI_GDEBUG, False)
_DCCSI_DEV_MODE = env_bool(ENVAR_DCCSI_DEV_MODE, False)
_MODULENAME = r'DCCsi.SDK.Maya.Scripts.set_menu'
_LOGGER = azpy.initialize_logger(_MODULENAME, default_log_level=int(20))
_LOGGER.debug('Invoking:: {0}.'.format({_MODULENAME}))
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
def menu_cmd_test():
_LOGGER.info('test_func(), is TESTING main menu')
return
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
def set_main_menu(obj_name=OBJ_DCCSI_MAINMENU, label=TAG_DCCSI_MAINMENU):
_main_window = pm.language.melGlobals['gMainWindow']
_menu_obj = obj_name
_menu_label = label
# check if it already exists and remove (so we don't duplicate)
if pm.menu(_menu_obj, label=_menu_label, exists=True, parent=_main_window):
pm.deleteUI(pm.menu(_menu_obj, e=True, deleteAllItems=True))
# create the main menu object
_custom_tools_menu = pm.menu(_menu_obj,
label=_menu_label,
parent=_main_window,
tearOff=True)
# make a dummpy sub-menu
pm.menuItem(label='Menu Item Stub',
subMenu=True,
parent=_custom_tools_menu,
tearOff=True)
# make a dummy menu item to test
pm.menuItem(label='Test', command=pm.Callback(menu_cmd_test))
return _custom_tools_menu
# ==========================================================================
# Run as LICENSE
#==========================================================================
if __name__ == '__main__':
_custom_menu = set_main_menu()
@@ -0,0 +1,326 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -- This line is 75 characters -------------------------------------------
from __future__ import unicode_literals
"""
This module fullfils the maya bootstrap pattern as described in their docs
https://tinyurl.com/y2aoz8es
Pattern is similar to Lumberyard Editor\\Scripts\\bootstrap.py
For now the proper way to initiate Maya boostrapping the DCCsi, is to use
the provided env and launcher bat files.
If you are developing for the DCCsi you can use this launcher to start Maya:
DccScriptingInterface\Launchers\Windows\Launch_Maya_2020.bat"
To Do: https://jira.agscollab.com/browse/ATOM-5861
"""
__project__ = 'DccScriptingInterface'
# it is really hard to debug userSetup bootstrapping
# this enables some rudimentary logging for debugging
_BOOT_INFO = True
# -------------------------------------------------------------------------
# built in's
import os
import sys
import site
import inspect
import traceback
import logging as _logging
# -- DCCsi Extension Modules
import azpy
from azpy.constants import *
from azpy.env_base import _BASE_ENVVAR_DICT
# -- maya imports
import maya.cmds as cmds
import maya.mel as mel
#from pymel.all import *
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
from azpy import env_bool
from azpy.constants import ENVAR_DCCSI_GDEBUG
from azpy.constants import ENVAR_DCCSI_DEV_MODE
# global space
_G_DEBUG = env_bool(ENVAR_DCCSI_GDEBUG, False)
_DCCSI_DEV_MODE = env_bool(ENVAR_DCCSI_DEV_MODE, False)
#_DCCSI_DEV_MODE = True # force true for debugger testing
_ORG_TAG = r'Amazon::Lumberyard'
_APP_TAG = r'DCCsi'
_TOOL_TAG = r'SDK.Maya.Scripts.userSetup'
_TYPE_TAG = r'entrypoint' # bootstrap
_MODULENAME = str('{0}.{1}'.format(_APP_TAG, _TOOL_TAG))
_LOGGER = azpy.initialize_logger(_MODULENAME, default_log_level=int(20))
_LOGGER.info('Initializing: {0}.'.format({_MODULENAME}))
_LOGGER.info('DCCSI_GDEBUG: {0}.'.format({_G_DEBUG}))
_LOGGER.info('DCCSI_DEV_MODE: {0}.'.format({_DCCSI_DEV_MODE}))
# flag to turn off setting up callbacks, until they are fully implemented
# To Do: consider making it a settings option to define and enable/disable
_G_LOAD_CALLBACKS = True # couple bugs, couple NOT IMPLEMENTED
_LOGGER.info('DCCSI_MAYA_SET_CALLBACKS: {0}.'.format({_G_LOAD_CALLBACKS}))
# early attach WingIDE debugger (can refactor to include other IDEs later)
if _DCCSI_DEV_MODE:
from azpy.test.entry_test import connect_wing
foo = connect_wing()
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# To Do REMOVE this block and replace with dev module
# debug prints, To Do: this should be moved to bootstrap config
#_G_DEBUGGER = os.getenv(ENVAR_DCCSI_GDEBUGGER, "WING")
#if _DCCSI_DEV_MODE:
#if _G_DEBUGGER == "WING":
#_LOGGER.info('{0}'.format('-' * 74))
#_LOGGER.info('Developer Debug Mode: {0}, Basic debugger: {1}'.format(_G_DEBUG, _G_DEBUGGER))
#try:
#_LOGGER.info('Attempting to start basic WING debugger')
#import azpy.lmbr.test
#_LOGGER.info('Package Imported: azpy.test')
#ouput = azpy.entry_test.main(verbose=False,
#connectDebugger=True,
#returnOuput=_G_DEBUG)
#_LOGGER.info(ouput)
#pass
#except Exception as e:
#_LOGGER.info("Error: azpy.test, entry_test (didn't perform)")
#_LOGGER.info("Exception: {0}".format(e))
#pass
#elif _G_DEBUGGER == "PYCHARM":
## https://github.com/juggernate/PyCharm-Maya-Debugging
#_LOGGER.info('{0}'.format('-' * 74))
#_LOGGER.info('Developer Debug Mode: {0}, Basic debugger: {1}'.format(_G_DEBUG, _G_DEBUGGER))
#sys.path.append('C:\Program Files\JetBrains\PyCharm 2019.1.3\debug-eggs\pydevd-pycharm.egg')
#try:
#_LOGGER.info('Attempting to start basic PYCHARM debugger')
## Inside Maya Python Console (Tip: add to a shelf button for quick access)
#import pydevd
#_LOGGER.info('Package Imported: pydevd')
#pydevd.settrace('localhost', port=7720, suspend=False)
#_LOGGER.info('PYCHARM Debugger Attach Success!!!')
## To disconnect run:
## pydevd.stoptrace()
#pass
#except Exception as e:
#_LOGGER.info("Error: pydevd.settrace (didn't perform)")
#_LOGGER.info("Exception: {0}".format(e))
#pass
#else:
#pass
## -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# validate access to the DCCsi and it's Lib site-packages
# bootstrap site-packages by version
from azpy.constants import PATH_DCCSI_PYTHON_LIB_PATH
try:
os.path.exists(PATH_DCCSI_PYTHON_LIB_PATH)
site.addsitedir(PATH_DCCSI_PYTHON_LIB_PATH)
_LOGGER.info('azpy 3rdPary site-packages: is: {0}'.format(PATH_DCCSI_PYTHON_LIB_PATH))
except Exception as e:
_LOGGER.error('ERROR: {0}, {1}'.format(e, PATH_DCCSI_PYTHON_LIB_PATH))
raise e
# 3rdparty
from unipath import Path
from box import Box
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# Maya is frozen
#_MODULE_PATH = Path(__file__)
# https://tinyurl.com/y49t3zzn
# module path when frozen
_MODULE_FILEPATH = os.path.abspath(inspect.getfile(inspect.currentframe()))
_MODULE_PATH = os.path.dirname(_MODULE_FILEPATH)
if _BOOT_INFO:
_LOGGER.debug('Boot: CWD: {}'.format(os.getcwd()))
_LOGGER.debug('Frozen: _MODULE_FILEPATH: {}'.format(_MODULE_FILEPATH))
_LOGGER.debug('Frozen: _MODULE_PATH: {}'.format(_MODULE_PATH))
_LOGGER.debug('Module __name__: {}'.format(__name__))
# root: INFO: Module __name__: __main__
_LOGGER.info('_MODULENAME: {}'.format(_MODULENAME))
# -------------------------------------------------------------------------
# check some env var tags (fail if no, likely means no proper code access)
_STR_ERROR_ENVAR = "Envar 'key' does not exist in base_env: {0}"
_DCCSI_SDK_PATH = None
try:
_DCCSI_SDK_PATH = _BASE_ENVVAR_DICT[ENVAR_DCCSI_SDK_PATH]
except Exception as e:
_LOGGER.critical(_STR_ERROR_ENVAR.format(_BASE_ENVVAR_DICT[ENVAR_DCCSI_SDK_PATH]))
_LY_PROJECT_PATH = None
try:
_LY_PROJECT_PATH = _BASE_ENVVAR_DICT[ENVAR_LY_PROJECT_PATH]
except Exception as e:
_LOGGER.critical(_STR_ERROR_ENVAR.format(_BASE_ENVVAR_DICT[ENVAR_LY_PROJECT_PATH]))
# check some env var tags (fail if no, likely means no proper code access)
_LY_DEV = _BASE_ENVVAR_DICT[ENVAR_LY_DEV]
_LY_DCCSIG_PATH = _BASE_ENVVAR_DICT[ENVAR_DCCSIG_PATH]
_LY_DCCSI_LOG_PATH = _BASE_ENVVAR_DICT[ENVAR_DCCSI_LOG_PATH]
_LY_AZPY_PATH = _BASE_ENVVAR_DICT[ENVAR_DCCSI_AZPY_PATH]
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# To Do: implement data driven config
# Currently not used, but will be where we store the ordered dict
# which is parsed from the project bootstrapping config files.
_G_app_config = {}
# global scope maya callbacks container
_G_callbacks = Box(box_dots=True) # global scope container
# used to store fixPaths in the global scope
_fix_paths = None
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# add appropriate common tools paths to the maya environment variables
def startup():
"""Early starup execution before mayautils.executeDeferred().
Some things like UI and plugins should be defered to avoid failure"""
_LOGGER.info('startup() fired')
# get known paths
_KNOWN_PATHS = site._init_pathinfo()
if os.path.isdir(_DCCSI_SDK_PATH):
site.addsitedir(_DCCSI_SDK_PATH, _KNOWN_PATHS)
try:
import azpy.test
_LOGGER.info('SUCCESS, import azpy.test')
except Exception as e:
_LOGGER.warning('startup(), could not import azpy.test')
_LOGGER.info('startup(), COMPLETE')
return 0
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# verify Shared\Python exists and add it as a site dir. Begin imports and config.
def post_startup():
"""Allows for a defered execution startup sequence"""
_LOGGER.info('post_startup() fired')
# plugins, To Do: these should be moved to bootstrapping config
try:
maya.cmds.loadPlugin("dx11Shader")
except Exception as e:
_LOGGER.error(e) # not a hard failure
# Lumberyard DCCsi environment ready or error out.
try:
import azpy.maya
_LOGGER.info('Python module imported: azpy.maya')
except Exception as e:
_LOGGER.error(e)
_LOGGER.error(traceback.print_exc())
return 1
# Dccsi azpy maya ready or error out.
try:
azpy.maya.init()
_LOGGER.info('SUCCESS, azpy.maya.init(), code accessible.')
except Exception as e:
_LOGGER.error(e)
_LOGGER.error(traceback.print_exc())
return 1
# callbacks, To Do: these should also be moved to the bootstrapping config
# Defered startup after the Ui is running.
_G_callbacks = Box(box_dots=True) # this just ensures a global scope container
if _G_LOAD_CALLBACKS:
from set_callbacks import _G_callbacks
# ^ need to hold on to this as the install repopulate set
# this ensures the fixPaths callback is loaded
# even when the other global callbacks are disabled
from set_callbacks import install_fix_paths
install_fix_paths()
# set the project workspace
#_LY_PROJECT_PATH = _BASE_ENVVAR_DICT[ENVAR_LY_PROJECT_PATH]
_project_workspace = os.path.join(_LY_PROJECT_PATH, TAG_MAYA_WORKSPACE)
if os.path.isfile(_project_workspace):
try:
# load workspace
maya.cmds.workspace(_LY_PROJECT_PATH, openWorkspace=True)
_LOGGER.info('Loaded workspace file: {0}'.format(_project_workspace))
maya.cmds.workspace(_LY_PROJECT_PATH, update=True)
except Exception as e:
_LOGGER.error(e)
else:
_LOGGER.warning('Workspace file not found: {1}'.format(_LY_PROJECT_PATH))
# Set up Lumberyard, maya default setting
from set_defaults import set_defaults
set_defaults()
# Setup UI tools
if not maya.cmds.about(batch=True):
_LOGGER.info('Add UI dependent tools')
# wrap in a try, because we haven't implmented it yet
try:
mel.eval(str(r'source "{}"'.format(TAG_LY_DCC_MAYA_MEL)))
except Exception as e:
_LOGGER.error(e)
# manage custom menu in a sub-module
from set_menu import set_main_menu
set_main_menu()
# To Do: manage custom shelf in a sub-module
_LOGGER.info('post_startup(), COMPLETE')
_LOGGER.info('DCCsi Bootstrap, COMPLETE')
return 0
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
if __name__ == '__main__':
try:
# Early startup config.
startup()
# This allows defered action post boot (atfer UI is active)
from maya.utils import executeDeferred
post = executeDeferred(post_startup)
except Exception as e:
traceback.print_exc()