Integrating github/staging through commit ab87ed9
This commit is contained in:
@@ -128,7 +128,6 @@ void FlyCameraInputComponent::Reflect(AZ::ReflectContext* reflection)
|
||||
if (behaviorContext)
|
||||
{
|
||||
behaviorContext->EBus<FlyCameraInputBus>("FlyCameraInputBus")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview)
|
||||
->Event("SetIsEnabled", &FlyCameraInputBus::Events::SetIsEnabled)
|
||||
->Event("GetIsEnabled", &FlyCameraInputBus::Events::GetIsEnabled);
|
||||
}
|
||||
|
||||
@@ -296,8 +296,6 @@ void AZ::FFont::DrawStringUInternal(float x, float y, float z, const char* str,
|
||||
|
||||
const bool orthoMode = ctx.m_overrideViewProjMatrices;
|
||||
|
||||
int baseState = ctx.m_baseState;
|
||||
|
||||
const RHI::Viewport& viewport = m_windowContext->GetViewport();
|
||||
const float viewX = viewport.m_minX;
|
||||
const float viewY = viewport.m_minY;
|
||||
@@ -322,7 +320,6 @@ void AZ::FFont::DrawStringUInternal(float x, float y, float z, const char* str,
|
||||
}
|
||||
|
||||
size_t startingVertexCount = m_vertexCount;
|
||||
size_t startingIndexCount = m_indexCount;
|
||||
|
||||
// Local function that is passed into CreateQuadsForText as the AddQuad function
|
||||
AddFunction AddQuad = [this, startingVertexCount]
|
||||
|
||||
@@ -309,7 +309,7 @@ Vec2 AZ::FontRenderer::GetKerning(uint32_t leftGlyph, uint32_t rightGlyph)
|
||||
const FT_UInt leftGlyphIndex = FT_Get_Char_Index(m_face, leftGlyph);
|
||||
const FT_UInt rightGlyphIndex = FT_Get_Char_Index(m_face, rightGlyph);
|
||||
|
||||
FT_Error ftError = FT_Get_Kerning(m_face, leftGlyphIndex, rightGlyphIndex, FT_KERNING_DEFAULT, &kerningOffsets);
|
||||
[[maybe_unused]] FT_Error ftError = FT_Get_Kerning(m_face, leftGlyphIndex, rightGlyphIndex, FT_KERNING_DEFAULT, &kerningOffsets);
|
||||
|
||||
#if !defined(_RELEASE)
|
||||
if (0 != ftError)
|
||||
|
||||
@@ -261,8 +261,9 @@ int AZ::FontTexture::PreCacheString(const char* string, int* updated, float size
|
||||
int updateCount = 0;
|
||||
|
||||
uint32_t character;
|
||||
for (Unicode::CIterator<const char*, false> it(string); character = *it; ++it)
|
||||
for (Unicode::CIterator<const char*, false> it(string); *it; ++it)
|
||||
{
|
||||
character = *it;
|
||||
TextureSlot* slot = GetCharSlot(character, clampedGlyphSize);
|
||||
|
||||
if (!slot)
|
||||
|
||||
+30
-3
@@ -88,19 +88,46 @@ namespace AtomImGuiTools
|
||||
{
|
||||
m_imguiGpuProfiler.Draw(m_showGpuProfiler, AZ::RPI::PassSystemInterface::Get()->GetRootPass().get());
|
||||
}
|
||||
if (m_showCpuProfiler)
|
||||
{
|
||||
const AZ::RHI::CpuTimingStatistics* stats = AZ::RHI::RHISystemInterface::Get()->GetCpuTimingStatistics();
|
||||
if (stats)
|
||||
{
|
||||
m_imguiCpuProfiler.Draw(m_showCpuProfiler, *stats);
|
||||
}
|
||||
}
|
||||
if (m_showTransientAttachmentProfiler)
|
||||
{
|
||||
auto* transientStats = AZ::RHI::RHISystemInterface::Get()->GetTransientAttachmentStatistics();
|
||||
if (transientStats)
|
||||
{
|
||||
m_showTransientAttachmentProfiler = m_imguiTransientAttachmentProfiler.Draw(*transientStats);
|
||||
}
|
||||
}
|
||||
if (m_showShaderMetrics)
|
||||
{
|
||||
m_imguiShaderMetrics.Draw(m_showShaderMetrics, AZ::RPI::ShaderMetricsSystemInterface::Get()->GetMetrics());
|
||||
}
|
||||
}
|
||||
|
||||
void AtomImGuiToolsSystemComponent::OnImGuiMainMenuUpdate()
|
||||
{
|
||||
if (ImGui::BeginMenu("Atom Tools"))
|
||||
{
|
||||
if (ImGui::MenuItem("Pass Viewer", "", &m_showPassTree))
|
||||
ImGui::MenuItem("Pass Viewer", "", &m_showPassTree);
|
||||
ImGui::MenuItem("Gpu Profiler", "", &m_showGpuProfiler);
|
||||
if (ImGui::MenuItem("Cpu Profiler", "", &m_showCpuProfiler))
|
||||
{
|
||||
AZ::RHI::RHISystemInterface::Get()->ModifyFrameSchedulerStatisticsFlags(
|
||||
AZ::RHI::FrameSchedulerStatisticsFlags::GatherCpuTimingStatistics, m_showCpuProfiler);
|
||||
AZ::RHI::CpuProfiler::Get()->SetProfilerEnabled(m_showCpuProfiler);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Gpu Profiler", "", &m_showGpuProfiler))
|
||||
if (ImGui::MenuItem("Transient Attachment Profiler", "", &m_showTransientAttachmentProfiler))
|
||||
{
|
||||
AZ::RHI::RHISystemInterface::Get()->ModifyFrameSchedulerStatisticsFlags(
|
||||
AZ::RHI::FrameSchedulerStatisticsFlags::GatherTransientAttachmentStatistics, m_showTransientAttachmentProfiler);
|
||||
}
|
||||
ImGui::MenuItem("Shader Metrics", "", &m_showShaderMetrics);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@
|
||||
#if defined(IMGUI_ENABLED)
|
||||
#include <ImGuiBus.h>
|
||||
#include <imgui/imgui.h>
|
||||
#include <Atom/Utils/ImGuiCpuProfiler.h>
|
||||
#include <Atom/Utils/ImGuiGpuProfiler.h>
|
||||
#include <Atom/Utils/ImGuiPassTree.h>
|
||||
#include <Atom/Utils/ImGuiShaderMetrics.h>
|
||||
#include <Atom/Utils/ImGuiTransientAttachmentProfiler.h>
|
||||
#endif
|
||||
|
||||
namespace AtomImGuiTools
|
||||
@@ -63,6 +66,15 @@ namespace AtomImGuiTools
|
||||
|
||||
AZ::Render::ImGuiGpuProfiler m_imguiGpuProfiler;
|
||||
bool m_showGpuProfiler = false;
|
||||
|
||||
AZ::Render::ImGuiCpuProfiler m_imguiCpuProfiler;
|
||||
bool m_showCpuProfiler = false;
|
||||
|
||||
AZ::Render::ImGuiTransientAttachmentProfiler m_imguiTransientAttachmentProfiler;
|
||||
bool m_showTransientAttachmentProfiler = false;
|
||||
|
||||
AZ::Render::ImGuiShaderMetrics m_imguiShaderMetrics;
|
||||
bool m_showShaderMetrics = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
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.
|
||||
|
||||
|
||||
|
||||
Lumberyard Actor Component to Actor+Material Component Conversion Script
|
||||
"""
|
||||
from LegacyConversionHelpers import *
|
||||
from LegacyMaterialComponentConverter import *
|
||||
|
||||
class Actor_Component_Converter(Component_Converter):
|
||||
"""
|
||||
Converts point lights
|
||||
"""
|
||||
def __init__(self, assetCatalogHelper, statsCollector, normalizedProjectDir):
|
||||
Component_Converter.__init__(self, assetCatalogHelper, statsCollector)
|
||||
# These are constant for every component in the file
|
||||
self.materialComponentConverter = Material_Component_Converter(assetCatalogHelper)
|
||||
self.normalizedProjectDir = normalizedProjectDir
|
||||
# These need to be reset between each component
|
||||
self.oldMaterialRelativePath = ""
|
||||
self.oldFbxRelativePathWithoutExtension = ""
|
||||
|
||||
def is_this_the_component_im_looking_for(self, xmlElement, parent):
|
||||
if "name" in xmlElement.keys() and xmlElement.get("name") == "EditorActorComponent":
|
||||
for sibling in list(parent):
|
||||
if "name" in sibling.keys() and sibling.get("name") == "EditorMaterialComponent":
|
||||
# There is already a material component on this actor, so we don't need to convert it again
|
||||
return False
|
||||
# Found an actor that doesn't have a material component
|
||||
return True
|
||||
# Not an actor
|
||||
return False
|
||||
|
||||
def gather_info_for_conversion(self, xmlElement, parent):
|
||||
# We don't need to modify the actor component, but we do need to add a material component
|
||||
for possibleActorAssetComponent in xmlElement.getchildren():
|
||||
if "field" in possibleActorAssetComponent.keys() and possibleActorAssetComponent.get("field") == "ActorAsset" and "value" in possibleActorAssetComponent.keys():
|
||||
assetId = possibleActorAssetComponent.get("value")
|
||||
|
||||
actorPathStartIndex = assetId.find("hint={")
|
||||
actorPathStartIndex += len("hint={")
|
||||
actorPathEndIndex = assetId.find(".actor")
|
||||
self.oldFbxRelativePathWithoutExtension = assetId[actorPathStartIndex: actorPathEndIndex]
|
||||
elif "field" in possibleActorAssetComponent.keys() and possibleActorAssetComponent.get("field") == "MaterialPerActor":
|
||||
# TODO - support the actor component's "MaterialPerLOD"
|
||||
for simpleAssetReferenceChild in possibleActorAssetComponent:
|
||||
if "name" in simpleAssetReferenceChild.keys() and simpleAssetReferenceChild.get("name") == "SimpleAssetReferenceBase":
|
||||
for simpleAssetReferenceBaseChild in simpleAssetReferenceChild:
|
||||
if "field" in simpleAssetReferenceBaseChild.keys() and simpleAssetReferenceBaseChild.get("field") == "AssetPath" and "value" in simpleAssetReferenceBaseChild.keys():
|
||||
# We've found the material override
|
||||
self.oldMaterialRelativePath = simpleAssetReferenceBaseChild.get("value")
|
||||
|
||||
def convert(self, xmlElement, parent):
|
||||
"""
|
||||
Adds a sibling material component
|
||||
"""
|
||||
|
||||
|
||||
if len(self.oldMaterialRelativePath) == 0 or self.oldMaterialRelativePath[0:self.oldMaterialRelativePath.find(".mtl")] == self.oldFbxRelativePathWithoutExtension:
|
||||
# There was no material override
|
||||
self.statsCollector.noMaterialOverrideCount += 1
|
||||
else:
|
||||
# There was a material override
|
||||
print("Material Override: fbx {0} override {1}".format(self.oldFbxRelativePathWithoutExtension, self.oldMaterialRelativePath))
|
||||
self.statsCollector.materialOverrideCount += 1
|
||||
|
||||
# We don't modify the xmlElement here because we do not want to replace the old ActorComponet, we just want to add a material component
|
||||
atomMaterialInDefaultSlot = self.materialComponentConverter.convert_legacy_mtl_relative_path_to_atom_material_assetid(self.normalizedProjectDir, self.oldMaterialRelativePath, self.oldFbxRelativePathWithoutExtension)
|
||||
isActor = True
|
||||
atomMaterialList = self.materialComponentConverter.convert_legacy_mtl_relative_path_to_atom_material_list(self.normalizedProjectDir, self.oldMaterialRelativePath, self.oldFbxRelativePathWithoutExtension, isActor)
|
||||
parent.append(self.materialComponentConverter.create_material_component_with_material_assignments(atomMaterialInDefaultSlot, atomMaterialList))
|
||||
# TODO - protect against running this more than once on an actor? Kind of handled by the 'already converted' log file. Not a problem with meshes because the legacy mesh component gets stripped, but it is an issue with actors since they don't get removed
|
||||
|
||||
def reset(self):
|
||||
self.oldMaterialRelativePath = ""
|
||||
self.oldFbxRelativePathWithoutExtension = ""
|
||||
+365
@@ -0,0 +1,365 @@
|
||||
"""
|
||||
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.
|
||||
|
||||
|
||||
|
||||
Lumberyard Legacy Renderer to Atom Component Conversion Script
|
||||
|
||||
|
||||
What does this script do?
|
||||
================================================
|
||||
This script walks through all the .slice, .layer, .ly, and .cry files in a
|
||||
project and attempts to convert the following components into something
|
||||
reasonably similar that renders in Atom:
|
||||
Mesh
|
||||
Actor
|
||||
|
||||
|
||||
Do materials get carried over?
|
||||
================================================
|
||||
For the mesh component, this script will attempt to create an atom mesh component
|
||||
that uses the same material, pre-supposing that you have already run the
|
||||
LegacyMaterialConverter.py script sto generate Atom .material files out of legacy .mtl files
|
||||
For meshes that only have one sub-mesh, this is straightforward as the mesh will only
|
||||
have one material to apply, and this script will look for a material with the same
|
||||
name but a .material extension.
|
||||
|
||||
For mult-materials, this is a little tricky since Atom does not follow the same
|
||||
ordered sub-material convention used by the legacy renderer. However, legacy .mtl
|
||||
files that were generated when adding a .fbx to a project use a naming convention
|
||||
that can be used by this script to match with the default materials that come from Atom.
|
||||
So as long as you were using the initial .mtl generated by Lumberyard and have not
|
||||
re-named the submaterials, it should find a match. This applies to both the
|
||||
ActorComponent and the MeshComponent
|
||||
|
||||
How do I run this script from a command line?
|
||||
================================================
|
||||
1) Check out any .slice, .layer, .ly, and .cry files you want to convert from source control
|
||||
- This script will remove the legacy components entirely, so make sure you have your files
|
||||
backed up before you run this script in case you want to run it again
|
||||
<<<<<<< HEAD
|
||||
2) From the dev folder, run LegacyComponentConverter.py project=<ProjectName> --include_gems
|
||||
=======
|
||||
2) From the Lumberyard root folder, run LegacyComponentConverter.py project=<ProjectName> --include_gems
|
||||
>>>>>>> main
|
||||
- --include_gems is optional
|
||||
- if you include Gems, it will run all all Gems, not just the ones enabled by your project
|
||||
|
||||
|
||||
What are the artifacts of this script?
|
||||
================================================
|
||||
The .slice, .layer, .ly, and .cry files will be converted in-place. No new files will be created
|
||||
|
||||
|
||||
Is this script destructive?
|
||||
================================================
|
||||
Yes! This is a one-way conversion that will clear the old data once converted. You should back up
|
||||
your files before running this conversion in case you want to modify the script and re-run it on
|
||||
your original level.
|
||||
"""
|
||||
CONVERTED_LOG_NAME = "ComponentConversion_ConvertedLegacyFiles.log"
|
||||
UNCONVERTED_LOG_NAME = "ComponentConversion_UnsupportedLegacyFiles.log"
|
||||
STATS_LOG_NAME = "ComponentConversion_LegacyComponentStats.log"
|
||||
BUILD_PATH = None
|
||||
GEMS_PATH = None
|
||||
|
||||
# Normal imports
|
||||
import sys
|
||||
import xml.etree.ElementTree
|
||||
import time
|
||||
from zipfile import ZipFile
|
||||
import tempfile
|
||||
import subprocess
|
||||
|
||||
# Local python files
|
||||
from LegacyConversionHelpers import *
|
||||
from LegacyMeshComponentConverter import *
|
||||
from LegacyMaterialComponentConverter import *
|
||||
from LegacyActorComponentConverter import *
|
||||
from LegacyPointLightComponentConverter import *
|
||||
|
||||
BUILD_PATH = "./"
|
||||
GEMS_PATH = os.path.join(BUILD_PATH, "Gems")
|
||||
|
||||
class Component_File(object):
|
||||
"""
|
||||
Class to perform any read, write or conversion operations on material (*.mtl) files.
|
||||
"""
|
||||
def __init__(self, filename, projectDir, assetCatalogHelper, statsCollector):
|
||||
self.filename = filename
|
||||
self.normalizedProjectDir = os.path.normpath(projectDir)
|
||||
self.needsConversion = False
|
||||
self.hadException = False
|
||||
self.assetCatalogHelper = assetCatalogHelper
|
||||
self.materialComponentConverter = Material_Component_Converter(assetCatalogHelper)#TODO - I'm pretty sure this is dead code
|
||||
self.xml = None
|
||||
self.statsCollector = statsCollector
|
||||
|
||||
self.parse_xml()
|
||||
|
||||
def is_valid_xml(self):
|
||||
"""
|
||||
Performs a simple check to determine if the XML of the mtl is valid.
|
||||
This is to prevent an assert on a material conversion operation and
|
||||
preventing the script from finishing.
|
||||
|
||||
It's possible for a material's xml to be malformed, which is why this check is needed.
|
||||
"""
|
||||
return True
|
||||
try:
|
||||
if isinstance(self.xml.getroot(), xml.etree.ElementTree.Element):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def parse_xml(self):
|
||||
"""
|
||||
Open and parse the file's xml, storing it for access later.
|
||||
For .ly and .cry files, it will get the xml out of the .zip
|
||||
"""
|
||||
if self.filename.endswith(".cry") or self.filename.endswith(".ly"):
|
||||
zipRead = ZipFile(self.filename, 'r')
|
||||
|
||||
contents = zipRead.read("levelentities.editor_xml")
|
||||
|
||||
zipRead.close()
|
||||
|
||||
# write the contents to a temporary file so we can parse it with ElementTree
|
||||
tmpFile = tempfile.NamedTemporaryFile(delete=False)
|
||||
tmpFile.write(contents)
|
||||
tmpFile.close()
|
||||
|
||||
self.xml = xml.etree.ElementTree.parse(tmpFile.name)
|
||||
self.gather_elements()
|
||||
|
||||
os.unlink(tmpFile.name)
|
||||
os.path.exists(tmpFile.name)
|
||||
elif os.path.exists(self.filename):
|
||||
#try:
|
||||
# TODO try-except is supposed to make it so one bad xml doesn't crash the lot
|
||||
# need to clean up stuff so the logging/conversion later doesn't crash
|
||||
# for now, better to crash here so we see where the exception is being thrown
|
||||
self.xml = xml.etree.ElementTree.parse(self.filename)
|
||||
self.gather_elements()
|
||||
#except OSError as err:
|
||||
# print("OS error: {0}".format(err))
|
||||
# self.xml = None
|
||||
# self.needsConversion = False
|
||||
# self.hadException = True
|
||||
#except ValueError:
|
||||
# print("Could not convert data to an integer.")
|
||||
# self.xml = None
|
||||
# self.needsConversion = False
|
||||
# self.hadException = True
|
||||
#except:
|
||||
# print("Unexpected error:", sys.exc_info()[0])
|
||||
# self.xml = None
|
||||
# self.needsConversion = False
|
||||
# self.hadException = True
|
||||
|
||||
def gather_elements(self):
|
||||
"""
|
||||
Once the xml has been parsed, mine through it to find all of the
|
||||
neccessary elements that need to be modified.
|
||||
"""
|
||||
print("starting to parse {0}".format(self.filename))
|
||||
|
||||
componentConverters = []
|
||||
componentConverters.append(Mesh_Component_Converter(self.assetCatalogHelper, self.statsCollector, self.normalizedProjectDir))
|
||||
componentConverters.append(Actor_Component_Converter(self.assetCatalogHelper, self.statsCollector, self.normalizedProjectDir))
|
||||
componentConverters.append(Point_Light_Component_Converter(self.assetCatalogHelper, self.statsCollector, self.normalizedProjectDir))
|
||||
|
||||
if self.is_valid_xml():
|
||||
root = self.xml.getroot()
|
||||
if root.tag == "ObjectStream" or True:
|
||||
# First, get a dictionary of child->parent mapping for later use inserting sibling elements
|
||||
self.parent_map = {c:p for p in root.iter('Class') for c in p}
|
||||
|
||||
# Now go through and look for mesh components
|
||||
for child in root.iter('Class'):
|
||||
# If we run into one of the components we just added, skip it. It doesn't need to be converted,
|
||||
# and it doesn't exist in the pre-built parent_map so it would throw an exception if we tried to access it
|
||||
if child in self.parent_map:
|
||||
parent = self.parent_map[child]
|
||||
for componentConverter in componentConverters:
|
||||
componentConverter.reset()
|
||||
if componentConverter.is_this_the_component_im_looking_for(child, parent):
|
||||
self.needsConversion = True
|
||||
componentConverter.gather_info_for_conversion(child, parent)
|
||||
# TODO - we're about to change the tree structure while iterating, which is apparently undefined but appears to work. Might be better to just build up a list of things that need to be modified, then do a second pass to replace the legacy component
|
||||
# Seems to be okay since we only change or add elements, never remove entirely
|
||||
componentConverter.convert(child, parent)
|
||||
self.xml._setroot(root)
|
||||
print("finished parsing {0}".format(self.filename))
|
||||
|
||||
def can_be_converted(self):
|
||||
"""
|
||||
Determines if this material file can be converted by checking if
|
||||
it is using the Illum Shader
|
||||
"""
|
||||
return self.needsConversion
|
||||
|
||||
def can_write(self):
|
||||
"""
|
||||
Checks to make sure the mtl file is writable.
|
||||
This is to prevent the script from asserting during a
|
||||
save attempt and preventing the script from finishing.
|
||||
"""
|
||||
fullFilePath = self.get_atom_file_path()
|
||||
if os.path.exists(fullFilePath):
|
||||
if os.access(fullFilePath, os.W_OK):
|
||||
return True
|
||||
else:
|
||||
with open(fullFilePath,"a+") as f:
|
||||
f.close()
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_atom_file_path(self):
|
||||
# This is just a way to optionally create a new file for comparing with the original
|
||||
# TODO: control this via command line
|
||||
atomFileName = self.filename
|
||||
return atomFileName#.replace('.slice', '_atom.slice')
|
||||
|
||||
def convert(self):
|
||||
"""
|
||||
Creates the new level/slice file
|
||||
"""
|
||||
# TODO - will not work if .slice is part of the path instead of the extension
|
||||
if self.needsConversion:
|
||||
if self.filename.endswith(".cry") or self.filename.endswith(".ly"):
|
||||
# We can't just update the .cry file, we need to rebuild all the contents
|
||||
|
||||
#Make a temporary file
|
||||
tmpFile, tmpFileName = tempfile.mkstemp(dir=os.path.dirname(self.filename))
|
||||
os.close(tmpFile)
|
||||
|
||||
#Create a temporary copy of the .cry file
|
||||
with ZipFile(self.filename, 'r') as zin:
|
||||
with ZipFile(tmpFileName, 'w') as zout:
|
||||
#Loop through the file list and write out every file but level.editor_xml with no modifications
|
||||
#when we hit the level data we want to edit, write it out with the new contents
|
||||
for item in zin.infolist():
|
||||
if item.filename == "levelentities.editor_xml":
|
||||
xmlString = xml.etree.ElementTree.tostring(self.xml.getroot())
|
||||
zout.writestr(item, xmlString)
|
||||
else:
|
||||
zout.writestr(item, zin.read(item.filename))
|
||||
|
||||
#Remove old cry file and rename the temp file
|
||||
os.remove(self.filename)
|
||||
os.rename(tmpFileName, self.filename)
|
||||
else:
|
||||
self.xml.write(self.get_atom_file_path())
|
||||
|
||||
return False
|
||||
|
||||
def getUpdatedStatsCollector(self):
|
||||
"""
|
||||
Returns the stats collector that was passed in intially, with any modifications that were made
|
||||
"""
|
||||
return self.statsCollector
|
||||
|
||||
###############################################################################
|
||||
def main():
|
||||
'''sys.__name__ wrapper function'''
|
||||
|
||||
msgStr = "This tool will scan all of your project's level/layer/slice files\n\
|
||||
convert any compatible legacy components into the equivalent Atom components\n\
|
||||
This script will overwrite the original files, and will remove the legacy components\n\
|
||||
upon conversion, decimating the previous contents of those components.\n"
|
||||
|
||||
commandLineOptions = Common_Command_Line_Options(sys.argv[0], sys.argv[1])
|
||||
if commandLineOptions.isHelp:
|
||||
print (commandLineOptions.helpString)
|
||||
return
|
||||
|
||||
start_time = time.time()
|
||||
total_converted = 0
|
||||
|
||||
extensionList = [".slice", ".layer", ".ly", ".cry"]
|
||||
fileList = get_file_list(commandLineOptions.projectName, commandLineOptions.includeGems, extensionList, BUILD_PATH, GEMS_PATH)
|
||||
|
||||
assetCatalogDictionaries = get_asset_catalog_dictionaries(BUILD_PATH, commandLineOptions.projectName)
|
||||
|
||||
# Create a log file to store converted component file filenames
|
||||
# and to check to see if the component file has already been converted.
|
||||
convertedLogFile = Log_File(filename="{0}\\{1}".format(BUILD_PATH, CONVERTED_LOG_NAME))
|
||||
|
||||
# Create a log file to store component file filenames that need conversion
|
||||
# but cannot becuase they are read only.
|
||||
unconvertedLogFile = Log_File(filename="{0}\\{1}".format(BUILD_PATH, UNCONVERTED_LOG_NAME), include_previous = False)
|
||||
|
||||
statsLogFile = Log_File(filename="{0}\\{1}".format(BUILD_PATH, STATS_LOG_NAME), include_previous = False)
|
||||
statsCollector = Stats_Collector()
|
||||
|
||||
# Go through each component file to perform the conversion on it
|
||||
print("==============================")
|
||||
componentFileIndex = -1
|
||||
for componentFileInfo in fileList:
|
||||
componentFileIndex += 1
|
||||
componentFileName = componentFileInfo.filename
|
||||
copmonentFileProjectDir = componentFileInfo.normalizedProjectDir
|
||||
print(componentFileName)
|
||||
|
||||
|
||||
#if convertedLogFile.has_line(componentFileName.lstrip(BUILD_PATH)): # Use this to only convert files that haven't already been converted
|
||||
# print("--> Previously converted, not doing")
|
||||
# continue
|
||||
if commandLineOptions.endsWithStr == "" or componentFileName.lower().endswith(commandLineOptions.endsWithStr.lower()):
|
||||
componentFile = Component_File(componentFileName, copmonentFileProjectDir, assetCatalogDictionaries, statsCollector)
|
||||
if componentFile.can_be_converted():
|
||||
if commandLineOptions.useP4:
|
||||
subprocess.check_call(['p4', 'edit', componentFileName])
|
||||
if componentFile.can_write():
|
||||
componentFile.convert()
|
||||
convertedLogFile.add_line_no_duplicates(componentFile.get_atom_file_path())
|
||||
print("--> Converted")
|
||||
total_converted += 1
|
||||
else:
|
||||
unconvertedLogFile.add_line_no_duplicates("{0} - cannot access file (read-only)".format(componentFile.get_atom_file_path()))
|
||||
print("--> Could not write to destination component file (read-only). Not converted.")
|
||||
else:
|
||||
print("--> did not need conversion.")
|
||||
statsCollector = componentFile.getUpdatedStatsCollector()
|
||||
print("\n")
|
||||
|
||||
# Fill out the stats log
|
||||
statsLogFile.add_line("Mesh/Actor Components without a material overrride: {0}".format(statsCollector.noMaterialOverrideCount))
|
||||
statsLogFile.add_line("Mesh/Actor Components with a material overrride: {0}".format(statsCollector.materialOverrideCount))
|
||||
statsLogFile.add_line("Total Mesh/Actor Components: {0}".format(statsCollector.noMaterialOverrideCount + statsCollector.materialOverrideCount))
|
||||
|
||||
# Finally, save the log files to disk
|
||||
convertedLogFile.save()
|
||||
unconvertedLogFile.save()
|
||||
statsLogFile.save()
|
||||
|
||||
total_time = time.time() - start_time
|
||||
|
||||
log_str = "You can view a list of converted component files in this log file:\n{0}\\{1}".format(BUILD_PATH, CONVERTED_LOG_NAME)
|
||||
unconverted_log_str = "You can view a list of component files that were not converted in this log file:\n{0}\\{1}".format(BUILD_PATH, UNCONVERTED_LOG_NAME)
|
||||
stats_log_str = "You can view a list of component files stats, such as feature and shader usage, in this log file:\n{0}\\{1}".format(BUILD_PATH, STATS_LOG_NAME)
|
||||
|
||||
print("==============================\n")
|
||||
print("Conversion completed in {0} seconds.\n".format(total_time))
|
||||
print("Converted {0} component file(s)".format(total_converted))
|
||||
|
||||
# Inform the user about the log files
|
||||
print("{0}".format(log_str))
|
||||
print("{0}".format(unconverted_log_str))
|
||||
print("{0}".format(stats_log_str))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# GLOBAL NOTE:
|
||||
# - All python scripts should execute through a main() function.
|
||||
main()
|
||||
+303
@@ -0,0 +1,303 @@
|
||||
"""
|
||||
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.
|
||||
|
||||
Helper classes for legacy conversion scripts
|
||||
"""
|
||||
|
||||
import os
|
||||
import xml.etree.ElementTree
|
||||
|
||||
class Stats_Collector(object):
|
||||
"""
|
||||
Stuff any extra info you want to keep track of during conversion into this object
|
||||
"""
|
||||
def __init__(self):
|
||||
self.materialOverrideCount = 0
|
||||
self.noMaterialOverrideCount = 0
|
||||
|
||||
|
||||
class File_Info(object):
|
||||
"""
|
||||
Keep track of both the filename and the directory of the project
|
||||
(not the directory the file is in, but the LY project itself)
|
||||
"""
|
||||
def __init__(self, filename, projectDir):
|
||||
self.filename = filename
|
||||
self.normalizedProjectDir = os.path.normpath(projectDir)
|
||||
|
||||
|
||||
class Log_File(object):
|
||||
"""
|
||||
Simple class to create, open & save a log file.
|
||||
"""
|
||||
def __init__(self, filename, include_previous = True):
|
||||
self.filename = filename
|
||||
self.logFile = None
|
||||
self.include_previous = include_previous
|
||||
self.lines = []
|
||||
self.create_log_file()
|
||||
|
||||
def create_log_file(self):
|
||||
"""
|
||||
Will either generate a new log file or open the existing log file and read its contents
|
||||
"""
|
||||
if os.path.exists(self.filename):
|
||||
self.logFile = open(self.filename, 'r+')
|
||||
if self.include_previous:
|
||||
for line in self.logFile.readlines():
|
||||
self.add_line(line)
|
||||
else:
|
||||
self.logFile = open(self.filename, 'w')
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
Saves the log file back to disk.
|
||||
|
||||
To ensure that filenames are not added twice, this method first saves an empty
|
||||
log to disc. Then saves it again with the list of filenames (self.lines)
|
||||
stored in this class.
|
||||
"""
|
||||
# First clear the log file's contents so they can be written back in
|
||||
self.logFile.close()
|
||||
open(self.filename, 'w').close()
|
||||
self.logFile = open(self.filename, 'w')
|
||||
|
||||
for line in self.lines:
|
||||
self.logFile.write("{0}\n".format(line))
|
||||
|
||||
self.logFile.close()
|
||||
|
||||
def get_lines(self):
|
||||
return self.lines
|
||||
|
||||
def add_line(self, line):
|
||||
self.lines.append(line)
|
||||
|
||||
def add_line_no_duplicates(self, line):
|
||||
"""
|
||||
Adds a line to the log, and prevents adding duplicates
|
||||
Useful for keeping track of files that have already been converted
|
||||
The line will be all lowercase for simplicity
|
||||
"""
|
||||
# rstrip with no arguments will remove trailing whitespace
|
||||
lowercase = line.lower().rstrip()
|
||||
if not lowercase in self.lines:
|
||||
self.lines.append(lowercase)
|
||||
|
||||
def has_line(self, line):
|
||||
"""
|
||||
Checks to see if a specific line already exists in the log
|
||||
"""
|
||||
# rstrip with no arguments will remove trailing whitespace
|
||||
lowercase = line.lower().rstrip()
|
||||
if lowercase in self.lines:
|
||||
return True
|
||||
return False
|
||||
|
||||
class Common_Command_Line_Options(object):
|
||||
"""
|
||||
Some common options/parsing
|
||||
"""
|
||||
def __init__(self, argv0, argv1):
|
||||
arguments = argv1.split('-')
|
||||
|
||||
self.projectName = ""
|
||||
self.includeGems = False
|
||||
self.useP4 = False
|
||||
self.endsWithStr = ""
|
||||
self.isHelp = False
|
||||
self.helpString = "usage: {0} -project=<project name> -include_gems -ends_with=<filter> -use_p4\n\
|
||||
E.g.:\n\
|
||||
{1} -project=StarterGame -include_gems\n\
|
||||
-project is required.\n\
|
||||
-include_gems is optional, and by default gems will not be included.\n\
|
||||
-ends_with is optional. It could be used to filter for a specific file (--ends_with=default.mtl)\n\
|
||||
-use_p4 is optional. It will use the p4 command line to check out files that are edited in your default changelist".format(argv0, argv0)
|
||||
|
||||
for argument in arguments:
|
||||
argument = argument.rstrip(" ")
|
||||
if argument == "h" or argument == "help" or argv1 == "?":
|
||||
self.isHelp = True
|
||||
elif argument.startswith("project"):
|
||||
projectArgs = argument.split("=")
|
||||
if len(projectArgs) > 1:
|
||||
self.projectName = projectArgs[1]
|
||||
elif argument == "include_gems":
|
||||
self.includeGems = True
|
||||
elif argument == "use_p4":
|
||||
self.useP4 = True
|
||||
elif argument.startswith("ends_with"):
|
||||
endsWithArgs = argument.split("=")
|
||||
if len(endsWithArgs) > 1:
|
||||
self.endsWithStr = endsWithArgs[1]
|
||||
|
||||
|
||||
|
||||
def get_file_list(projectName, includeGems, extensionList, buildPath, gemsPath):
|
||||
"""
|
||||
The main difference between this and any other way to walk a directory
|
||||
looking for files is that it keeps track of the lumberyard project
|
||||
or gems folder the file is in, which can later be used to figure out
|
||||
the relative path that is used by the engine for the file
|
||||
"""
|
||||
|
||||
print("Gathering Files...")
|
||||
# Lower the project name for easier matching
|
||||
projectName = projectName.lower()
|
||||
|
||||
# First, gather a list of all project folders in the dev root.
|
||||
# This will help to reduce the amount of files that the script
|
||||
# has to walk through when searching for files.
|
||||
projectFolders = []
|
||||
for root, dirs, files in os.walk(buildPath):
|
||||
if root != buildPath:
|
||||
break
|
||||
for d in dirs:
|
||||
projectFile = "{0}\\{1}\\project.json".format(root, d)
|
||||
if os.path.exists(projectFile) and d.lower() == projectName:
|
||||
projectFolders.append(os.path.join(root, d))
|
||||
|
||||
# Add all gems to the list of project folders.
|
||||
if includeGems:
|
||||
for root, dirs, files in os.walk(gemsPath):
|
||||
if root != gemsPath:
|
||||
break
|
||||
while len(dirs) >= 1:
|
||||
d = dirs[0]
|
||||
gemsFile = "{0}\\{1}\\gem.json".format(root, d)
|
||||
if os.path.exists(gemsFile):
|
||||
projectFolders.append(os.path.join(os.path.join(root, d), "Assets"))
|
||||
for subroot, subdirs, subfiles in os.walk(os.path.join(gemsPath, d)):
|
||||
if subroot != os.path.join(gemsPath, d):
|
||||
break
|
||||
for subd in subdirs:
|
||||
dirs.append(os.path.join(d, subd))
|
||||
dirs.remove(d)
|
||||
|
||||
fileInfoList = []
|
||||
for projPath in projectFolders:
|
||||
for root, dirs, files in os.walk(projPath):
|
||||
if 'Cache' in root.split(os.sep):
|
||||
continue
|
||||
|
||||
for f in files:
|
||||
for extension in extensionList:
|
||||
if f.endswith(extension):
|
||||
fileInfoList.append(File_Info("{0}\\{1}".format(root, f), projPath))
|
||||
return fileInfoList
|
||||
|
||||
class Asset_Catalog_Dictionaries(object):
|
||||
"""
|
||||
Some dictionaries from the asset catalog
|
||||
"""
|
||||
def __init__(self, relativePathToAssetIdDict, assetIdToRelativePathDict, assetUuidToAssetIdsDict):
|
||||
self.relativePathToAssetIdDict = relativePathToAssetIdDict
|
||||
self.assetIdToRelativePathDict = assetIdToRelativePathDict
|
||||
self.assetUuidToAssetIdsDict = assetUuidToAssetIdsDict
|
||||
|
||||
def get_asset_id_from_relative_path(self, relativePath):
|
||||
# parse the asset catalog and find the assetId
|
||||
if relativePath in self.relativePathToAssetIdDict:
|
||||
return self.relativePathToAssetIdDict[relativePath]
|
||||
return ""
|
||||
|
||||
def get_asset_catalog_dictionaries(buildPath, projectName):
|
||||
"""
|
||||
This function pre-supposes that you have modified AssetCatalog::SaveRegistry_Impl
|
||||
in Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp
|
||||
to use AZ::ObjectStream::ST_XML instead of AZ::ObjectStream::ST_BINARY
|
||||
and subsequently deleted Cache/<project name>/pc/<project name>/assetcatalog.xml
|
||||
and let it re-build so that it is a parseable xml file
|
||||
"""
|
||||
|
||||
print("Parsing Asset Catalog...")
|
||||
relativePathToAssetIdDict = {}
|
||||
relativePathToAssetIdDict[""] = "{00000000-0000-0000-0000-000000000000}:0"
|
||||
assetIdToRelativePathDict = {}
|
||||
assetUuidToAssetIdsDict = {}
|
||||
assetCatalogPath = os.path.join(projectName, "Cache", "pc", "assetcatalog.xml")
|
||||
assetCatalogXml = xml.etree.ElementTree.parse(assetCatalogPath)
|
||||
for possibleAssetInfo in assetCatalogXml.getroot().iter('Class'):
|
||||
if "name" in possibleAssetInfo.keys() and possibleAssetInfo.get("name") == "AssetInfo":
|
||||
# We found some AssetInfo
|
||||
relativePath = ""
|
||||
assetId = ""
|
||||
for child in possibleAssetInfo:
|
||||
if "field" in child.keys() and child.get("field") == "relativePath" and "value" in child.keys():
|
||||
relativePath = child.get("value")
|
||||
if "name" in child.keys() and child.get("name") == "AssetId":
|
||||
guid = ""
|
||||
subId = ""
|
||||
for assetIdPart in child:
|
||||
if "field" in assetIdPart.keys() and assetIdPart.get("field") == "guid" and "value" in assetIdPart.keys():
|
||||
guid = assetIdPart.get("value")
|
||||
if "field" in assetIdPart.keys() and assetIdPart.get("field") == "subId" and "value" in assetIdPart.keys():
|
||||
subId = assetIdPart.get("value")
|
||||
assetId = "".join((guid, ":", subId))
|
||||
relativePathToAssetIdDict[relativePath] = assetId
|
||||
assetIdToRelativePathDict[assetId] = relativePath
|
||||
if not guid in assetUuidToAssetIdsDict:
|
||||
assetUuidToAssetIdsDict[guid] = []
|
||||
assetUuidToAssetIdsDict[guid].append(assetId)
|
||||
return Asset_Catalog_Dictionaries(relativePathToAssetIdDict, assetIdToRelativePathDict, assetUuidToAssetIdsDict)
|
||||
|
||||
def create_xml_element_from_string(xmlString):
|
||||
# copy paste a line from a .slice or other serialization file from lumberyard, add a \ before the " marks, and this function will turn it into an xml element
|
||||
# e.g. <Class name=\"EditorMaterialComponent\" field=\"element\" version=\"3\" type=\"{02B60E9D-470B-447D-A6EE-7D635B154183}\">
|
||||
# does not protect against malformed strings.
|
||||
# relies heavily on things like starting with <, no space between < and the tag, etc.
|
||||
# but works in a pinch
|
||||
rawXmlList = xmlString.split()
|
||||
# strip the < from the first element to get the tag
|
||||
element = xml.etree.ElementTree.Element(rawXmlList[0].lstrip("<"))
|
||||
for itemIndex in range(len(rawXmlList)):
|
||||
item = rawXmlList[itemIndex]
|
||||
if itemIndex == 0:
|
||||
# ignore the tag because we've already handled it
|
||||
continue
|
||||
elif itemIndex == (len(rawXmlList) - 1):
|
||||
# strip the end tag if it exists
|
||||
item = item.rstrip('>')
|
||||
item = item.rstrip('/')
|
||||
|
||||
#parse the item
|
||||
itemList = item.split('=')
|
||||
attribute = itemList[0]
|
||||
value = itemList[1].lstrip('\"').rstrip('\"')
|
||||
element.set(attribute, value)
|
||||
return element
|
||||
|
||||
def get_uuid_from_assetId(assetId):
|
||||
separatorIndex = assetId.find(":")
|
||||
return assetId[:separatorIndex]
|
||||
|
||||
def get_subid_from_assetId(assetId):
|
||||
separatorIndex = assetId.find(":") + 1
|
||||
return assetId[separatorIndex:]
|
||||
|
||||
class Component_Converter(object):
|
||||
"""
|
||||
Converter base class
|
||||
"""
|
||||
def __init__(self, assetCatalogHelper, statsCollector):
|
||||
self.assetCatalogHelper = assetCatalogHelper
|
||||
self.statsCollector = statsCollector
|
||||
|
||||
def is_this_the_component_im_looking_for(self, xmlElement, parent):
|
||||
pass
|
||||
|
||||
def gather_info_for_conversion(self, xmlElement, parent):
|
||||
pass
|
||||
|
||||
def convert(self, xmlElement, parent):
|
||||
pass
|
||||
|
||||
def reset(self):
|
||||
pass
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
"""
|
||||
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.
|
||||
|
||||
|
||||
|
||||
Lumberyard Legacy Mesh Component to Atom Mesh Component Conversion Script
|
||||
"""
|
||||
from LegacyConversionHelpers import *
|
||||
|
||||
class Material_Assignment_Info(object):
|
||||
def __init__(self, slotAssetId, assignmentAssetId):
|
||||
self.slotAssetId = slotAssetId
|
||||
self.assignmentAssetId = assignmentAssetId
|
||||
|
||||
class Material_Component_Converter(object):
|
||||
"""
|
||||
Some material related functions. Since there is no material component in legacy, this doesn't inherit from Component_Converter like other similar classes
|
||||
"""
|
||||
def __init__(self, assetCatalogHelper):
|
||||
self.assetCatalogHelper = assetCatalogHelper
|
||||
|
||||
def create_material_map_entry(self, slotAssetId, materialAssetId):
|
||||
# <Class name="AZStd::pair" field="element" type="{F652A87A-0FDF-527C-B0ED-340C074A4874}">
|
||||
# <Class name="AZ::Render::MaterialAssignmentId" field="value1" version="1" type="{EB603581-4654-4C17-B6DE-AE61E79EDA97}">
|
||||
# <Class name="AZ::u64" field="lodIndex" value="18446744073709551615" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
|
||||
# <Class name="AssetId" field="materialAssetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
|
||||
# <Class name="AZ::Uuid" field="guid" value="{2A4E7DCF-F5D5-55B3-8D41-A4F89398D53C}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
# <Class name="unsigned int" field="subId" value="31953" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# <Class name="AZ::Render::MaterialAssignment" field="value2" version="1" type="{C66E5214-A24B-4722-B7F0-5991E6F8F163}">
|
||||
# <Class name="Asset" field="MaterialAsset" value="id={0BFD18DD-3A64-5240-A272-600301CE821C}:0,type={522C7BE0-501D-463E-92C6-15184A2B7AD8},hint={valena/valenaactor_jumpsuitmat.azmaterial}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
|
||||
# <Class name="AZStd::unordered_map" field="PropertyOverrides" type="{6E6962E1-04C9-56F9-89C4-361031CC1384}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
pair = create_xml_element_from_string("<Class name=\"AZStd::pair\" field=\"element\" type=\"{F652A87A-0FDF-527C-B0ED-340C074A4874}\">")
|
||||
isMapAssignment = True
|
||||
pair.append(self.create_material_assignment_id(slotAssetId, isMapAssignment))
|
||||
pair.append(self.create_material_assignment(materialAssetId))
|
||||
return pair
|
||||
|
||||
def create_material_asset_string_from_assetid(self, assetId):
|
||||
hint_path = ""
|
||||
if assetId != "{00000000-0000-0000-0000-000000000000}:0":
|
||||
hint_path = self.assetCatalogHelper.assetIdToRelativePathDict[assetId]
|
||||
return "".join(("id=", assetId, ",type={522C7BE0-501D-463E-92C6-15184A2B7AD8},hint={", hint_path, "},loadBehavior=1"))
|
||||
|
||||
def create_material_assignment_id(self, slotAssetId, isMapAssignment):
|
||||
# Material assignment ids are serialized differently for the map vs the EditorMaterialComponentSlot
|
||||
field = ""
|
||||
if isMapAssignment:
|
||||
field = "value1"
|
||||
else:
|
||||
field = "id"
|
||||
|
||||
# <Class name="AZ::Render::MaterialAssignmentId" field="id" version="1" type="{EB603581-4654-4C17-B6DE-AE61E79EDA97}">
|
||||
# <Class name="AZ::u64" field="lodIndex" value="18446744073709551615" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
|
||||
# <Class name="AssetId" field="materialAssetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
|
||||
# <Class name="AZ::Uuid" field="guid" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
# <Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
materialAssignmentId = create_xml_element_from_string("".join(("<Class name=\"AZ::Render::MaterialAssignmentId\" field=\"", field, "\" version=\"1\" type=\"{EB603581-4654-4C17-B6DE-AE61E79EDA97}\">")))
|
||||
# TODO - for now, always using the default lod index 18446744073709551615, which applies to all lods that don't have a specific override
|
||||
materialAssignmentId_lodIndex = create_xml_element_from_string("<Class name=\"AZ::u64\" field=\"lodIndex\" value=\"18446744073709551615\" type=\"{D6597933-47CD-4FC8-B911-63F3E2B0993A}\"/>")
|
||||
materialAssignmentId_AssetId = create_xml_element_from_string("<Class name=\"AssetId\" field=\"materialAssetId\" version=\"1\" type=\"{652ED536-3402-439B-AEBE-4A5DBC554085}\">")
|
||||
uuid = get_uuid_from_assetId(slotAssetId)
|
||||
materialAssignmentId_AssetId_Uuid = create_xml_element_from_string("".join(("<Class name=\"AZ::Uuid\" field=\"guid\" value=\"", uuid, "\" type=\"{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}\"/>")))
|
||||
subId = get_subid_from_assetId(slotAssetId)
|
||||
materialAssignmentId_AssetId_subid = xml.etree.ElementTree.Element("Class", {'name' : "unsigned int", 'field' : "subId", 'value' : subId, 'type' : "{43DA906B-7DEF-4CA8-9790-854106D3F983}"})
|
||||
|
||||
materialAssignmentId_AssetId.append(materialAssignmentId_AssetId_Uuid)
|
||||
materialAssignmentId_AssetId.append(materialAssignmentId_AssetId_subid)
|
||||
|
||||
materialAssignmentId.append(materialAssignmentId_lodIndex)
|
||||
materialAssignmentId.append(materialAssignmentId_AssetId)
|
||||
return materialAssignmentId
|
||||
|
||||
def create_editor_material_assignment_slot(self, slotAssetId, materialAssetId, isDefaultSlot):
|
||||
field = ""
|
||||
if isDefaultSlot:
|
||||
field = "defaultMaterialSlot"
|
||||
else:
|
||||
field = "element"
|
||||
# <Class name="EditorMaterialComponentSlot" field="defaultMaterialSlot" version="2" type="{344066EB-7C3D-4E92-B53D-3C9EBD546488}">
|
||||
# <Class name="AZ::Render::MaterialAssignmentId" ...
|
||||
# <Class name="Asset" field="materialAsset" value="id={00000000-0000-0000-0000-000000000000}:0,type={522C7BE0-501D-463E-92C6-15184A2B7AD8},hint={}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
|
||||
# <Class name="AZStd::unordered_map" field="propertyOverrides" type="{6E6962E1-04C9-56F9-89C4-361031CC1384}"/>
|
||||
# </Class>
|
||||
materialComponentSlot = create_xml_element_from_string("".join(("<Class name=\"EditorMaterialComponentSlot\" field=\"", field, "\" version=\"4\" type=\"{344066EB-7C3D-4E92-B53D-3C9EBD546488}\">")))
|
||||
isMapAssignment = False
|
||||
materialAssignmentId = self.create_material_assignment_id(slotAssetId, isMapAssignment)
|
||||
materialAsset = self.create_material_asset(materialAssetId)
|
||||
defaultPropertyOverrides = self.create_material_property_overrides()
|
||||
materialComponentSlot.append(materialAssignmentId)
|
||||
materialComponentSlot.append(materialAsset)
|
||||
materialComponentSlot.append(defaultPropertyOverrides)
|
||||
return materialComponentSlot
|
||||
|
||||
def create_material_assignment(self, materialAssetId):
|
||||
# <Class name="AZ::Render::MaterialAssignment" field="value2" version="1" type="{C66E5214-A24B-4722-B7F0-5991E6F8F163}">
|
||||
# <Class name="Asset" field="MaterialAsset" value="id={B175B5BF-E97C-52BD-9DC8-60A9CE05CCC8}:0,type={522C7BE0-501D-463E-92C6-15184A2B7AD8},hint={valena/valenaactor_glovesbootsmat.azmaterial}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
|
||||
# <Class name="AZStd::unordered_map" field="PropertyOverrides" type="{6E6962E1-04C9-56F9-89C4-361031CC1384}"/>
|
||||
# </Class>
|
||||
materialAssignment = create_xml_element_from_string("<Class name=\"AZ::Render::MaterialAssignment\" field=\"value2\" version=\"1\" type=\"{C66E5214-A24B-4722-B7F0-5991E6F8F163}\">")
|
||||
materialAssignment.append(self.create_material_asset(materialAssetId))
|
||||
materialAssignment.append(self.create_material_property_overrides())
|
||||
return materialAssignment
|
||||
|
||||
def create_material_asset(self, materialAssetId):
|
||||
materialAssetString = self.create_material_asset_string_from_assetid(materialAssetId)
|
||||
materialAsset = xml.etree.ElementTree.Element("Class", {'name' : "Asset", 'field' : "materialAsset", 'value' : materialAssetString, 'version' : "2", 'type' : "{77A19D40-8731-4D3C-9041-1B43047366A4}"})
|
||||
return materialAsset
|
||||
|
||||
def create_material_property_overrides(self):
|
||||
return create_xml_element_from_string("<Class name=\"AZStd::unordered_map\" field=\"propertyOverrides\" type=\"{6E6962E1-04C9-56F9-89C4-361031CC1384}\"/>")
|
||||
|
||||
def create_material_component_with_material_assignments(self, atomMaterialInDefaultSlotAssetId, materialAssignmentList):
|
||||
# TODO - the relative path might not be in the same project/gem folder as the .slice
|
||||
|
||||
#<Class name="EditorMaterialComponent" field="element" version="3" type="{02B60E9D-470B-447D-A6EE-7D635B154183}">
|
||||
# <Class name="EditorRenderComponentAdapter<MaterialComponentController MaterialComponent MaterialComponentConfig >" field="BaseClass1" type="{DF046B40-536D-5D59-96EF-7A40DA6191B2}">
|
||||
# <Class name="EditorComponentAdapter<MaterialComponentController MaterialComponent MaterialComponentConfig >" field="BaseClass1" version="1" type="{6C4D4557-3728-56F8-A0FF-A309C3AAB853}">
|
||||
# <Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
|
||||
# <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
|
||||
# <Class name="AZ::u64" field="Id" value="6456931760107146363" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# <Class name="MaterialComponentController" field="Controller" version="1" type="{34AD7ED0-9866-44CD-93B6-E86840214B91}">
|
||||
# <Class name="MaterialComponentConfig" field="Configuration" version="3" type="{3366C279-32AE-48F6-839B-7700AE117A54}">
|
||||
# <Class name="ComponentConfig" field="BaseClass1" version="1" type="{0A7929DF-2932-40EA-B2B3-79BC1C3490D0}"/>
|
||||
# <Class name="AZStd::unordered_map" field="materials" type="{50F6716F-698B-5A6C-AACD-940597FDEC24}">
|
||||
# ... (map entries)
|
||||
# </Class>
|
||||
# </Class>
|
||||
# </Class>
|
||||
editorMaterialComponent = create_xml_element_from_string("<Class name=\"EditorMaterialComponent\" field=\"element\" version=\"5\" type=\"{02B60E9D-470B-447D-A6EE-7D635B154183}\">")
|
||||
# can't use create_xml_element_from_string here because of the spaces in the class name
|
||||
editorRenderComponentAdapter = xml.etree.ElementTree.Element("Class", {'name' : "EditorRenderComponentAdapter<MaterialComponentController MaterialComponent MaterialComponentConfig >", 'field' : "BaseClass1", 'type' : "{DF046B40-536D-5D59-96EF-7A40DA6191B2}"})
|
||||
editorComponentAdapter = xml.etree.ElementTree.Element("Class", {'name' : "EditorComponentAdapter<MaterialComponentController MaterialComponent MaterialComponentConfig >", 'field' : "BaseClass1", 'version' : "1", 'type' : "{6C4D4557-3728-56F8-A0FF-A309C3AAB853}"})
|
||||
editorComponentBase = create_xml_element_from_string("<Class name=\"EditorComponentBase\" field=\"BaseClass1\" version=\"1\" type=\"{D5346BD4-7F20-444E-B370-327ACD03D4A0}\">")
|
||||
component = create_xml_element_from_string("<Class name=\"AZ::Component\" field=\"BaseClass1\" type=\"{EDFCB2CF-F75D-43BE-B26B-F35821B29247}\">")
|
||||
u64 = create_xml_element_from_string("<Class name=\"AZ::u64\" field=\"Id\" value=\"6456931760107146363\" type=\"{D6597933-47CD-4FC8-B911-63F3E2B0993A}\"/>")
|
||||
component.append(u64)
|
||||
editorComponentBase.append(component)
|
||||
editorComponentAdapter.append(editorComponentBase)
|
||||
|
||||
materialComponentController = create_xml_element_from_string("<Class name=\"MaterialComponentController\" field=\"Controller\" version=\"1\" type=\"{34AD7ED0-9866-44CD-93B6-E86840214B91}\">")
|
||||
materialComponentConfig = create_xml_element_from_string("<Class name=\"MaterialComponentConfig\" field=\"Configuration\" version=\"3\" type=\"{3366C279-32AE-48F6-839B-7700AE117A54}\">")
|
||||
componentConfig = create_xml_element_from_string("<Class name=\"ComponentConfig\" field=\"BaseClass1\" version=\"1\" type=\"{0A7929DF-2932-40EA-B2B3-79BC1C3490D0}\"/>")
|
||||
materialMap = create_xml_element_from_string("<Class name=\"AZStd::unordered_map\" field=\"materials\" type=\"{50F6716F-698B-5A6C-AACD-940597FDEC24}\">")
|
||||
|
||||
# {00000000-0000-0000-0000-000000000000}:0 is the default slot
|
||||
defaultMaterialAssignmentMapEntry = self.create_material_map_entry("{00000000-0000-0000-0000-000000000000}:0", atomMaterialInDefaultSlotAssetId)
|
||||
materialMap.append(defaultMaterialAssignmentMapEntry)
|
||||
|
||||
for atomMaterial in materialAssignmentList:
|
||||
if atomMaterial.assignmentAssetId:
|
||||
materialMapElement = self.create_material_map_entry(atomMaterial.slotAssetId, atomMaterial.assignmentAssetId)
|
||||
materialMap.append(materialMapElement)
|
||||
|
||||
materialComponentConfig.append(componentConfig)
|
||||
materialComponentConfig.append(materialMap)
|
||||
materialComponentController.append(materialComponentConfig)
|
||||
editorComponentAdapter.append(materialComponentController)
|
||||
editorRenderComponentAdapter.append(editorComponentAdapter)
|
||||
|
||||
isDefaultSlot = True
|
||||
defaultMaterialComponentSlot = self.create_editor_material_assignment_slot("{00000000-0000-0000-0000-000000000000}:0", atomMaterialInDefaultSlotAssetId, isDefaultSlot)
|
||||
|
||||
# <Class name="AZStd::vector" field="materialSlots" type="{7FDDDE36-46C8-5DBC-8566-E792AA358BD9}">
|
||||
# ... (slots)
|
||||
isDefaultSlot = False
|
||||
materialsSlots = create_xml_element_from_string("Class name=\"AZStd::vector\" field=\"materialSlots\" type=\"{7FDDDE36-46C8-5DBC-8566-E792AA358BD9}\"")
|
||||
for atomMaterial in materialAssignmentList:
|
||||
if atomMaterial.assignmentAssetId:
|
||||
materialSlotElement = self.create_editor_material_assignment_slot(atomMaterial.slotAssetId, atomMaterial.assignmentAssetId, isDefaultSlot)
|
||||
materialsSlots.append(materialSlotElement)
|
||||
else:
|
||||
# Use the default material if none was specified
|
||||
materialSlotElement = self.create_editor_material_assignment_slot(atomMaterial.slotAssetId, self.get_default_material_assetid(), isDefaultSlot)
|
||||
materialsSlots.append(materialSlotElement)
|
||||
|
||||
# <Class name="AZStd::vector" field="materialSlotsByLod" type="{22E4F3CF-29C1-54AC-89DD-6FD47A657229}">
|
||||
# <Class name="AZStd::vector" field="element" type="{7FDDDE36-46C8-5DBC-8566-E792AA358BD9}">
|
||||
|
||||
|
||||
editorMaterialComponent.append(editorRenderComponentAdapter)
|
||||
editorMaterialComponent.append(defaultMaterialComponentSlot)
|
||||
return editorMaterialComponent
|
||||
|
||||
def convert_legacy_mtl_relative_path_to_atom_material_assetid(self, normalizedProjectDir, oldMaterialRelativePath, oldFbxRelativePathWithoutExtension):
|
||||
if len(oldMaterialRelativePath) == 0:
|
||||
# if no material was used, try to find one that matches the name of the fbx (in the event the fbx only has a single material)
|
||||
cacheMaterialRelativePath = "".join((oldFbxRelativePathWithoutExtension, ".azmaterial"))
|
||||
if cacheMaterialRelativePath in self.assetCatalogHelper.relativePathToAssetIdDict:
|
||||
assetId = self.assetCatalogHelper.relativePathToAssetIdDict[cacheMaterialRelativePath]
|
||||
return assetId
|
||||
else:
|
||||
return self.get_default_material_assetid()
|
||||
|
||||
# TODO - doesn't work if .mtl is in the path
|
||||
atomRelativePath = oldMaterialRelativePath.replace('.mtl', '.azmaterial')
|
||||
assetId = self.assetCatalogHelper.get_asset_id_from_relative_path(atomRelativePath)
|
||||
if assetId:
|
||||
return assetId
|
||||
|
||||
return self.get_default_material_assetid()
|
||||
|
||||
def get_default_material_assetid(self):
|
||||
return "{00000000-0000-0000-0000-000000000000}:0"
|
||||
#return "{2A83451E-0FE6-508E-BAA2-6142AAA53C42}:0" # AtomStarterGame\Materials\Magenta.material" - makes it obvious we couldn't find a material
|
||||
|
||||
def convert_legacy_mtl_relative_path_to_atom_material_list(self, normalizedProjectDir, oldMaterialRelativePath, oldFbxRelativePathWithoutExtension, isActor):
|
||||
materialList = []
|
||||
|
||||
# Find all the materials produced by the fbx
|
||||
cacheFbxPath = ""
|
||||
if isActor:
|
||||
cacheFbxPath = "".join((oldFbxRelativePathWithoutExtension, ".actor"))
|
||||
else:
|
||||
cacheFbxPath = "".join((oldFbxRelativePathWithoutExtension, ".azmodel"))
|
||||
|
||||
if cacheFbxPath in self.assetCatalogHelper.relativePathToAssetIdDict:
|
||||
fbxAssetId = self.assetCatalogHelper.relativePathToAssetIdDict[cacheFbxPath]
|
||||
# get the guid portion of the id
|
||||
subIdSeparatorIndex = fbxAssetId.find(":")
|
||||
fbxGuid = fbxAssetId[:subIdSeparatorIndex]
|
||||
fbxProductList = self.assetCatalogHelper.assetUuidToAssetIdsDict[fbxGuid]
|
||||
for productAssetId in fbxProductList:
|
||||
relativePath = self.assetCatalogHelper.assetIdToRelativePathDict[productAssetId]
|
||||
if relativePath.endswith(".azmaterial"):
|
||||
# we found a product material.
|
||||
slot = productAssetId
|
||||
assignment = ""
|
||||
|
||||
# strip the _#### from it
|
||||
extraCharactersIndex = relativePath.rfind("_")
|
||||
convertedRelativePath = "".join((relativePath[:extraCharactersIndex], ".azmaterial"))
|
||||
|
||||
if convertedRelativePath in self.assetCatalogHelper.relativePathToAssetIdDict:
|
||||
# try to find an atom material with the same name
|
||||
assignment = self.assetCatalogHelper.relativePathToAssetIdDict[convertedRelativePath]
|
||||
elif cacheFbxPath.replace(".azmodel", ".azmaterial") in self.assetCatalogHelper.relativePathToAssetIdDict:
|
||||
# An fbx with only 1 submesh is going to produce an azmaterial that is fbxname_materialname
|
||||
# even though this is often redundant like rivervista_01_RiverVista01MAT.azmaterial.
|
||||
# Legacy .mtl files like this would end up with a rivervista_01.mtl that was a multi-material
|
||||
# but only had a single sub-material called RiverVista01MAT.
|
||||
# The legacy material converter treats this case as a single material, and instead of
|
||||
# naming the file rivervista_01_RiverVista01MAT.material, it just calls it rivervista_01.material.
|
||||
# However, the atom model builder still follows the fbxname_materialname convention, so in this case
|
||||
# we should look and see if the material converter created an rivervist_01.material
|
||||
assignment = self.assetCatalogHelper.relativePathToAssetIdDict[cacheFbxPath.replace(".azmodel", ".azmaterial")]
|
||||
else:
|
||||
assignment = self.get_default_material_assetid()
|
||||
print("Could not match {0} to a corresponding source atom material".format(convertedRelativePath))
|
||||
|
||||
materialList.append(Material_Assignment_Info(slot, assignment))
|
||||
|
||||
return materialList
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
"""
|
||||
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.
|
||||
|
||||
|
||||
|
||||
Lumberyard Legacy Mesh Component to Atom Mesh Component Conversion Script
|
||||
"""
|
||||
from LegacyConversionHelpers import *
|
||||
from LegacyMaterialComponentConverter import *
|
||||
|
||||
|
||||
class Mesh_Component_Converter(Component_Converter):
|
||||
"""
|
||||
Converts point lights
|
||||
"""
|
||||
def __init__(self, assetCatalogHelper, statsCollector, normalizedProjectDir):
|
||||
Component_Converter.__init__(self, assetCatalogHelper, statsCollector)
|
||||
# These are constant for every component in the file
|
||||
self.materialComponentConverter = Material_Component_Converter(assetCatalogHelper)
|
||||
self.normalizedProjectDir = normalizedProjectDir
|
||||
# These need to be reset between each component
|
||||
self.newAssetId = ""
|
||||
self.oldMaterialRelativePath = ""
|
||||
self.oldFbxRelativePathWithoutExtension = ""
|
||||
|
||||
def is_this_the_component_im_looking_for(self, xmlElement, parent):
|
||||
if "name" in xmlElement.keys() and xmlElement.get("name") == "EditorMeshComponent":
|
||||
return True
|
||||
return False
|
||||
|
||||
def gather_info_for_conversion(self, xmlElement, parent):
|
||||
# First, get the data that we need
|
||||
#<Class name="EditorMeshComponent" field="element" version="1" type="{FC315B86-3280-4D03-B4F0-5553D7D08432}">
|
||||
# <Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
|
||||
# <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
|
||||
# <Class name="AZ::u64" field="Id" value="17006471516512517700" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# <Class name="MeshComponentRenderNode" field="Static Mesh Render Node" version="1" type="{46FF2BC4-BEF9-4CC4-9456-36C127C310D7}">
|
||||
# <Class name="bool" field="Visible" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
|
||||
# <Class name="Asset" field="Static Mesh" value="id={BCD2BB63-338F-53BE-98E1-BF847138B78E}:3250cdc0,type={C2869E3B-DDA0-4E01-8FE3-6770D788866B},hint={objects/airship/airship_pod_outerwalls.cgf}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
|
||||
# <Class name="AzFramework::SimpleAssetReference<LmbrCentral::MaterialAsset>" field="Material Override" version="1" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}">
|
||||
# <Class name="SimpleAssetReferenceBase" field="BaseClass1" version="1" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}">
|
||||
# <Class name="AZStd::string" field="AssetPath" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
|
||||
for editorMeshComponentChild in xmlElement:
|
||||
if "name" in editorMeshComponentChild.keys() and editorMeshComponentChild.get("name") == "MeshComponentRenderNode":
|
||||
for meshComponentRenderNodeChild in editorMeshComponentChild:
|
||||
if "name" in meshComponentRenderNodeChild.keys() and meshComponentRenderNodeChild.get("name") == "Asset":
|
||||
# We've found the mesh asset, now extract the assetId and hit
|
||||
assetId = meshComponentRenderNodeChild.get("value")
|
||||
|
||||
# Legacy assetId looks like this "id={BCD2BB63-338F-53BE-98E1-BF847138B78E}:3250cdc0,type={C2869E3B-DDA0-4E01-8FE3-6770D788866B},hint={objects/airship/airship_pod_outerwalls.cgf}
|
||||
# atomAssetId looks like this "{BCD2BB63-338F-53BE-98E1-BF847138B78E}:########,
|
||||
# newAssetId should look like "id={BCD2BB63-338F-53BE-98E1-BF847138B78E}:########,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/airship/airship_pod_outerwalls.azmodel}"
|
||||
#value"id={E01FB8B5-D2B3-52D8-BC36-644FC0E3B5F4}:268435463,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/props/barrel_01.azmodel}"
|
||||
# get the relative path to the mesh
|
||||
meshPathStartIndex = assetId.find("hint={")
|
||||
meshPathStartIndex += len("hint={")
|
||||
meshPathEndIndex = assetId.find(".cgf")
|
||||
self.oldFbxRelativePathWithoutExtension = assetId[meshPathStartIndex: meshPathEndIndex]
|
||||
|
||||
# swap the sub-id for the atom model sub-id
|
||||
atomModelRelativePath = "{0}.azmodel".format(self.oldFbxRelativePathWithoutExtension)
|
||||
if atomModelRelativePath in self.assetCatalogHelper.relativePathToAssetIdDict:
|
||||
atomAssetId = self.assetCatalogHelper.relativePathToAssetIdDict[atomModelRelativePath]
|
||||
atomSubId = atomAssetId[atomAssetId.find(":") + 1:]
|
||||
# go from string->int->hex->string to get the hex number as a string
|
||||
hexSubId = str(hex(int(atomSubId)))
|
||||
# remove the leading characters to get plain hex
|
||||
hexString = hexSubId[hexSubId.find("x") + 1:]
|
||||
|
||||
subIdStartIndex = assetId.find(":")
|
||||
subIdStartIndex += 1
|
||||
subIdEndIndex = assetId.find(",")
|
||||
subIdReplacement = hexString
|
||||
|
||||
# swap the type for the atom model type
|
||||
typeStartIndex = assetId.find("type={")
|
||||
typeStartIndex += len("type={")
|
||||
typeEndIndex = assetId.find("},hint")
|
||||
typeReplacement = "2C7477B6-69C5-45BE-8163-BCD6A275B6D8"
|
||||
|
||||
# swap the hint for the atom model extension
|
||||
extensionStartIndex = assetId.find(".cgf")
|
||||
extensionEndIndex = extensionStartIndex + len(".cgf")
|
||||
extensionReplacement = ".azmodel"
|
||||
|
||||
self.newAssetId = "".join((assetId[:subIdStartIndex], subIdReplacement, assetId[subIdEndIndex:typeStartIndex], typeReplacement, assetId[typeEndIndex:extensionStartIndex], extensionReplacement, assetId[extensionEndIndex:]))
|
||||
else:
|
||||
# we couldn't find the atom model (it was probably a .cgf instead of a .fbx in source)
|
||||
self.newAssetId = "id={00000000-0000-0000-0000-000000000000}:00000000,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={}"
|
||||
print("Could not find {0} in the asset catalog. Make sure the corresponding source file ends in .fbx not .cgf, and that the asset has finished processing with no errors.".format(atomModelRelativePath))
|
||||
elif "field" in meshComponentRenderNodeChild.keys() and meshComponentRenderNodeChild.get("field") == "Material Override":
|
||||
for simpleAssetReferenceChild in meshComponentRenderNodeChild:
|
||||
if "name" in simpleAssetReferenceChild.keys() and simpleAssetReferenceChild.get("name") == "SimpleAssetReferenceBase":
|
||||
for simpleAssetReferenceBaseChild in simpleAssetReferenceChild:
|
||||
if "field" in simpleAssetReferenceBaseChild.keys() and simpleAssetReferenceBaseChild.get("field") == "AssetPath" and "value" in simpleAssetReferenceBaseChild.keys():
|
||||
# We've found the material override
|
||||
self.oldMaterialRelativePath = simpleAssetReferenceBaseChild.get("value")
|
||||
|
||||
def create_adapter_with_new_model_assetId(self, assetIdValue):
|
||||
# <Class name="EditorComponentAdapter<AZ::Render::MeshComponentController AZ::Render::MeshComponent AZ::Render::MeshComponentConfig >" field="BaseClass1" version="1" type="{52DFE044-18C1-5861-BA2A-EDB61107FEE9}">
|
||||
# <Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
|
||||
# <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
|
||||
# <Class name="AZ::u64" field="Id" value="4528867579411318958" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# <Class name="AZ::Render::MeshComponentController" field="Controller" type="{D0F35FAC-4194-4C89-9487-D000DDB8B272}">
|
||||
# <Class name="AZ::Render::MeshComponentConfig" field="Configuration" type="{63737345-51B1-472B-9355-98F99993909B}">
|
||||
# <Class name="Asset" field="ModelAsset" value="id={509D78D3-2196-50C2-808C-FEDC3C31380D}:10000007,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/suzanne.azmodel}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
|
||||
# <Class name="bool" field="ExcludeFromReflectionCubeMaps" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# </Class>
|
||||
|
||||
#<Class name="AZ::Render::EditorMeshComponent" field="element" version="1" type="{DCE68F6E-2E16-4CB4-A834-B6C2F900A7E9}">
|
||||
# <Class name="EditorRenderComponentAdapter<AZ::Render::MeshComponentController AZ::Render::MeshComponent AZ::Render::MeshComponentConfig >" field="BaseClass1" type="{3D614286-9164-53B5-833B-4F98D2820BA7}">
|
||||
# <Class name="EditorComponentAdapter<AZ::Render::MeshComponentController AZ::Render::MeshComponent AZ::Render::MeshComponentConfig >" field="BaseClass1" version="1" type="{52DFE044-18C1-5861-BA2A-EDB61107FEE9}">
|
||||
# <Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
|
||||
# <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
|
||||
# <Class name="AZ::u64" field="Id" value="4528867579411318958" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# <Class name="AZ::Render::MeshComponentController" field="Controller" type="{D0F35FAC-4194-4C89-9487-D000DDB8B272}">
|
||||
# <Class name="AZ::Render::MeshComponentConfig" field="Configuration" type="{63737345-51B1-472B-9355-98F99993909B}">
|
||||
# <Class name="Asset" field="ModelAsset" value="id={509D78D3-2196-50C2-808C-FEDC3C31380D}:10000007,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/suzanne.azmodel}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
|
||||
# <Class name="bool" field="ExcludeFromReflectionCubeMaps" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# </Class>
|
||||
#</Class>
|
||||
|
||||
editorRenderComponentAdapter = xml.etree.ElementTree.Element("Class", {'name': "EditorRenderComponentAdapter<AZ::Render::MeshComponentController AZ::Render::MeshComponent AZ::Render::MeshComponentConfig >", 'field': "BaseClass1", 'type': "{3D614286-9164-53B5-833B-4F98D2820BA7}"})
|
||||
|
||||
editorComponentAdapter = xml.etree.ElementTree.Element("Class", {'name': "EditorComponentAdapter<AZ::Render::MeshComponentController AZ::Render::MeshComponent AZ::Render::MeshComponentConfig >", 'field': "BaseClass1", 'version': "1", 'type': "{52DFE044-18C1-5861-BA2A-EDB61107FEE9}"})
|
||||
|
||||
editorComponentBase = xml.etree.ElementTree.Element("Class", {'name': "EditorComponentBase", 'field': "BaseClass1", 'version': "1", 'type': "{D5346BD4-7F20-444E-B370-327ACD03D4A0}"})
|
||||
component = xml.etree.ElementTree.Element("Class", {'name': "AZ::Component", 'field': "BaseClass1", 'type': "{EDFCB2CF-F75D-43BE-B26B-F35821B29247}"})
|
||||
u64 = xml.etree.ElementTree.Element("Class", {'name': "AZ::u64", 'field': "Id", 'value': "4528867579411318958", 'type': "{D6597933-47CD-4FC8-B911-63F3E2B0993A}"})
|
||||
component.append(u64)
|
||||
editorComponentBase.append(component)
|
||||
|
||||
meshComponentController = create_xml_element_from_string("<Class name=\"AZ::Render::MeshComponentController\" field=\"Controller\" type=\"{D0F35FAC-4194-4C89-9487-D000DDB8B272}\">")
|
||||
|
||||
meshComponentConfig = xml.etree.ElementTree.Element("Class", {'name': "AZ::Render::MeshComponentConfig", 'field': "Configuration", 'type': "{63737345-51B1-472B-9355-98F99993909B}"})
|
||||
modelAsset = xml.etree.ElementTree.Element("Class", {'name': "Asset", 'field': "ModelAsset", 'value': assetIdValue, 'version': "1", 'type': "{77A19D40-8731-4D3C-9041-1B43047366A4}"})
|
||||
excludeFromReflectionCubeMaps = xml.etree.ElementTree.Element("Class", {'name': "bool", 'field': "ExcludeFromReflectionCubeMaps", 'value': "false", 'type': "{A0CA880C-AFE4-43CB-926C-59AC48496112}"})
|
||||
meshComponentConfig.append(modelAsset)
|
||||
meshComponentConfig.append(excludeFromReflectionCubeMaps)
|
||||
|
||||
meshComponentController.append(meshComponentConfig)
|
||||
|
||||
editorComponentAdapter.append(editorComponentBase)
|
||||
editorComponentAdapter.append(meshComponentController)
|
||||
|
||||
editorRenderComponentAdapter.append(editorComponentAdapter)
|
||||
|
||||
return editorRenderComponentAdapter
|
||||
|
||||
def convert(self, xmlElement, parent):
|
||||
"""
|
||||
Returns a list of xml elements (siblings)
|
||||
"""
|
||||
# Now clear the legacy mesh component
|
||||
xmlElement.clear()
|
||||
|
||||
# And replace the content with an Atom mesh component
|
||||
xmlElement.set("name", "AZ::Render::EditorMeshComponent")
|
||||
xmlElement.set("field", "element")
|
||||
xmlElement.set("version", "1")
|
||||
xmlElement.set("type", "{DCE68F6E-2E16-4CB4-A834-B6C2F900A7E9}")
|
||||
|
||||
xmlElement.append(self.create_adapter_with_new_model_assetId(self.newAssetId))
|
||||
|
||||
if len(self.oldMaterialRelativePath) == 0 or self.oldMaterialRelativePath[0:self.oldMaterialRelativePath.find(".mtl")] == self.oldFbxRelativePathWithoutExtension:
|
||||
# There was no material override
|
||||
self.statsCollector.noMaterialOverrideCount += 1
|
||||
else:
|
||||
# There was a material override
|
||||
self.statsCollector.materialOverrideCount += 1
|
||||
|
||||
# Now that we have an Atom MeshComponent, we need an Atom MaterialComponent as a neighbor to 'child' (the new mesh component)
|
||||
atomMaterialInDefaultSlot = self.materialComponentConverter.convert_legacy_mtl_relative_path_to_atom_material_assetid(self.normalizedProjectDir, self.oldMaterialRelativePath, self.oldFbxRelativePathWithoutExtension)
|
||||
isActor = False
|
||||
atomMaterialList = self.materialComponentConverter.convert_legacy_mtl_relative_path_to_atom_material_list(self.normalizedProjectDir, self.oldMaterialRelativePath, self.oldFbxRelativePathWithoutExtension, isActor)
|
||||
|
||||
parent.append(self.materialComponentConverter.create_material_component_with_material_assignments(atomMaterialInDefaultSlot, atomMaterialList))
|
||||
|
||||
def reset(self):
|
||||
self.newAssetId = ""
|
||||
self.oldMaterialRelativePath = ""
|
||||
self.oldFbxRelativePathWithoutExtension = ""
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
"""
|
||||
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.
|
||||
|
||||
|
||||
|
||||
Lumberyard Legacy Point Light Component to Atom Point Light Component Conversion Script
|
||||
"""
|
||||
from LegacyConversionHelpers import *
|
||||
from LegacyMaterialComponentConverter import *
|
||||
|
||||
class Point_Light_Component_Converter(Component_Converter):
|
||||
"""
|
||||
Converts point lights
|
||||
"""
|
||||
def __init__(self, assetCatalogHelper, statsCollector, _):
|
||||
Component_Converter.__init__(self, assetCatalogHelper, statsCollector)
|
||||
|
||||
self.color = ""
|
||||
self.diffuse_multiplier = ""
|
||||
self.point_max_distance = ""
|
||||
|
||||
def convert_legacy_light_intensity_to_atom_intensity(self, diffuse_multiplier: str) -> str:
|
||||
return str(float(diffuse_multiplier) * 100)
|
||||
|
||||
def is_this_the_component_im_looking_for(self, xmlElement, parent):
|
||||
if "name" in xmlElement.keys() and xmlElement.get("name") == "EditorPointLightComponent":
|
||||
return True
|
||||
return False
|
||||
|
||||
def gather_info_for_conversion(self, xmlElement, _):
|
||||
# First, get the data that we need
|
||||
# <Class name="EditorPointLightComponent" field="element" version="1" type="{00818135-138D-42AD-8657-FF3FD38D9E7A}">
|
||||
# <Class name="EditorLightComponent" field="BaseClass1" version="2" type="{7C18B273-5BA3-4E0F-857D-1F30BD6B0733}">
|
||||
# <Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
|
||||
# <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
|
||||
# <Class name="AZ::u64" field="Id" value="14732701159327458740" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# <Class name="EditorLightConfiguration" field="EditorLightConfiguration" version="1" type="{1D3B114F-8FB2-47BD-9C21-E089F4F37861}">
|
||||
# <Class name="LightConfiguration" field="BaseClass1" version="8" type="{F4CC7BB4-C541-480C-88FC-C5A8F37CC67F}">
|
||||
# <Class name="unsigned int" field="LightType" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
# <Class name="bool" field="Visible" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
|
||||
# <Class name="bool" field="OnInitially" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
|
||||
# <Class name="Color" field="Color" value="1.0000000 1.0000000 1.0000000 1.0000000" type="{7894072A-9050-4F0F-901B-34B1A0D29417}"/>
|
||||
# <Class name="float" field="DiffuseMultiplier" value="50000.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="float" field="SpecMultiplier" value="1.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="bool" field="Ambient" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
|
||||
# <Class name="float" field="PointMaxDistance" value="500.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="float" field="PointAttenuationBulbSize" value="0.0500000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="float" field="AreaWidth" value="5.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="float" field="AreaHeight" value="5.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="float" field="AreaMaxDistance" value="2.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="float" field="AreaFOV" value="45.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="float" field="ProjectorDistance" value="5.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="float" field="ProjectorAttenuationBulbSize" value="0.0500000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="float" field="ProjectorFOV" value="90.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="float" field="ProjectorNearPlane" value="0.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# ...
|
||||
for editorPointLightComponentChild in xmlElement:
|
||||
#print("Editor Point Light Component Config")
|
||||
for editorLightComponentChild in editorPointLightComponentChild:
|
||||
#print("Editor Light Component Config")
|
||||
#print(f"Name: {editorLightComponentChild.get('name')}, Field: {editorLightComponentChild.get('field')}")
|
||||
if "name" in editorLightComponentChild.keys() and editorLightComponentChild.get("name") == "EditorLightConfiguration":
|
||||
#print(f"Editor Light Config. {editorLightComponentChild.get('name')}, {editorLightComponentChild.get('field')}")
|
||||
for editorLightConfigurationChild in editorLightComponentChild:
|
||||
for lightConfigurationChild in editorLightConfigurationChild:
|
||||
#print(f"Name: {lightConfigurationChild.get('name')}, Field: {lightConfigurationChild.get('field')}")
|
||||
if "field" in lightConfigurationChild.keys() and lightConfigurationChild.get("field") == "Color":
|
||||
self.color = lightConfigurationChild.get("value")
|
||||
elif "field" in lightConfigurationChild.keys() and lightConfigurationChild.get("field") == "DiffuseMultiplier":
|
||||
self.diffuse_multiplier = lightConfigurationChild.get("value")
|
||||
elif "field" in lightConfigurationChild.keys() and lightConfigurationChild.get("field") == "PointMaxDistance":
|
||||
self.point_max_distance = lightConfigurationChild.get("value")
|
||||
|
||||
#print(f"Color: {self.color}")
|
||||
#print(f"Diffuse: {self.diffuse_multiplier}")
|
||||
#print(f"Attenuation Dist.: {self.point_max_distance}")
|
||||
print('Editor Light Component was touched!')
|
||||
|
||||
def __create_adapter_xml(self, color, intensity, attenuationRadius):
|
||||
# <Class name="AZ::Render::EditorPointLightComponent" field="element" version="1" type="{C4D354BE-5247-41FD-9A8D-550C6772EE5B}">
|
||||
# <Class name="EditorRenderComponentAdapter<AZ::Render::PointLightComponentController AZ::Render::PointLightComponent PointLightComponentConfi" field="BaseClass1" type="{B09B7A31-789F-5996-AD50-EF71942A5271}">
|
||||
# <Class name="EditorComponentAdapter<AZ::Render::PointLightComponentController AZ::Render::PointLightComponent PointLightComponentConfig >" field="BaseClass1" version="1" type="{DC9066D5-4557-52C7-B901-4B5626C4F35A}">
|
||||
# <Class name="EditorComponentBase" field="BaseClass1" version="1" type="{D5346BD4-7F20-444E-B370-327ACD03D4A0}">
|
||||
# <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
|
||||
# <Class name="AZ::u64" field="Id" value="12988262800448744331" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# <Class name="AZ::Render::PointLightComponentController" field="Controller" version="1" type="{23F82E30-2E1F-45FE-A9A7-B15632ED9EBD}">
|
||||
# <Class name="PointLightComponentConfig" field="Configuration" version="2" type="{B6FC35BA-D22F-4C20-BFFC-3FE7A48858FA}">
|
||||
# <Class name="ComponentConfig" field="BaseClass1" version="1" type="{0A7929DF-2932-40EA-B2B3-79BC1C3490D0}"/>
|
||||
# <Class name="Color" field="Color" value="1.0000000 1.0000000 1.0000000 1.0000000" type="{7894072A-9050-4F0F-901B-34B1A0D29417}"/>
|
||||
# <Class name="char" field="ColorIntensityMode" value="0" type="{3AB0037F-AF8D-48CE-BCA0-A170D18B2C03}"/>
|
||||
# <Class name="float" field="Intensity" value="800.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="unsigned char" field="AttenuationRadiusMode" value="1" type="{72B9409A-7D1A-4831-9CFE-FCB3FADD3426}"/>
|
||||
# <Class name="float" field="AttenuationRadius" value="89.4427185" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# <Class name="float" field="BulbRadius" value="0.0500000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# </Class>
|
||||
# </Class>
|
||||
editorRenderComponentAdapter = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "EditorRenderComponentAdapter<AZ::Render::PointLightComponentController AZ::Render::PointLightComponent PointLightComponentConfig >",
|
||||
'field': "BaseClass1", 'type': "{B09B7A31-789F-5996-AD50-EF71942A5271}"
|
||||
})
|
||||
editorComponentAdapter = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "EditorComponentAdapter<AZ::Render::PointLightComponentController AZ::Render::PointLightComponent PointLightComponentConfig >",
|
||||
'field': "BaseClass1", 'version': "1", 'type': "{DC9066D5-4557-52C7-B901-4B5626C4F35A}"
|
||||
})
|
||||
editorComponentBase = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "EditorComponentBase",
|
||||
'field': "BaseClass1",
|
||||
'version': "1",
|
||||
'type': "{D5346BD4-7F20-444E-B370-327ACD03D4A0}"
|
||||
})
|
||||
component = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "AZ::Component",
|
||||
'field': "BaseClass1",
|
||||
'type': "{EDFCB2CF-F75D-43BE-B26B-F35821B29247}"
|
||||
})
|
||||
u64 = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "AZ::u64",
|
||||
'field': "Id",
|
||||
'value': "12988262800448744331",
|
||||
'type': "{D6597933-47CD-4FC8-B911-63F3E2B0993A}"
|
||||
})
|
||||
component.append(u64)
|
||||
editorComponentBase.append(component)
|
||||
|
||||
pointLightComponentController = create_xml_element_from_string(
|
||||
"<Class name=\"AZ::Render::PointLightComponentController\" field=\"Controller\" version=\"1\" type=\"{23F82E30-2E1F-45FE-A9A7-B15632ED9EBD}\">"
|
||||
)
|
||||
pointLightComponentConfig = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "PointLightComponentConfig",
|
||||
'field': "Configuration",
|
||||
'version': "2",
|
||||
'type': "{B6FC35BA-D22F-4C20-BFFC-3FE7A48858FA}"
|
||||
})
|
||||
componentConfig = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "ComponentConfig",
|
||||
'field': "BaseClass1",
|
||||
'version': "1",
|
||||
'type': "{0A7929DF-2932-40EA-B2B3-79BC1C3490D0}"
|
||||
})
|
||||
colorConfig = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "Color",
|
||||
'field': "Color",
|
||||
'value': color,
|
||||
'type': "{7894072A-9050-4F0F-901B-34B1A0D29417}"
|
||||
})
|
||||
colorIntesntiyModeConfig = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "char",
|
||||
'field': "ColorIntensityMode",
|
||||
'value': "0",
|
||||
'type': "{3AB0037F-AF8D-48CE-BCA0-A170D18B2C03}"
|
||||
})
|
||||
inensityConfig = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "float",
|
||||
'field': "Intensity",
|
||||
'value': intensity,
|
||||
'type': "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"
|
||||
})
|
||||
attenuationRadiusModeConfig = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "unsigned char",
|
||||
'field': "AttenuationRadiusMode",
|
||||
'value': "1",
|
||||
'type': "{72B9409A-7D1A-4831-9CFE-FCB3FADD3426}"
|
||||
})
|
||||
attenuationRadiusConfig = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "float",
|
||||
'field': "AttenuationRadius",
|
||||
'value': attenuationRadius,
|
||||
'type': "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"
|
||||
})
|
||||
bulbRadiusConfig = xml.etree.ElementTree.Element("Class", {
|
||||
'name': "float",
|
||||
'field': "BulbRadius",
|
||||
'value': "0.05",
|
||||
'type': "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"
|
||||
})
|
||||
pointLightComponentConfig.append(componentConfig)
|
||||
pointLightComponentConfig.append(colorConfig)
|
||||
pointLightComponentConfig.append(colorIntesntiyModeConfig)
|
||||
pointLightComponentConfig.append(inensityConfig)
|
||||
pointLightComponentConfig.append(attenuationRadiusModeConfig)
|
||||
pointLightComponentConfig.append(attenuationRadiusConfig)
|
||||
pointLightComponentConfig.append(bulbRadiusConfig)
|
||||
|
||||
pointLightComponentController.append(pointLightComponentConfig)
|
||||
|
||||
editorComponentAdapter.append(editorComponentBase)
|
||||
editorComponentAdapter.append(pointLightComponentController)
|
||||
|
||||
editorRenderComponentAdapter.append(editorComponentAdapter)
|
||||
|
||||
return editorRenderComponentAdapter
|
||||
|
||||
def convert(self, xmlElement, _):
|
||||
# Now clear the legacy component
|
||||
xmlElement.clear()
|
||||
|
||||
# And replace the content with an Atom point light component
|
||||
xmlElement.set("name", "AZ::Render::EditorPointLightComponent")
|
||||
xmlElement.set("field", "element")
|
||||
xmlElement.set("version", "1")
|
||||
xmlElement.set("type", "{C4D354BE-5247-41FD-9A8D-550C6772EE5B}")
|
||||
|
||||
xmlElement.append(self.__create_adapter_xml(
|
||||
self.color,
|
||||
self.convert_legacy_light_intensity_to_atom_intensity(self.diffuse_multiplier),
|
||||
self.point_max_distance
|
||||
))
|
||||
|
||||
def reset(self):
|
||||
self.color = ""
|
||||
self.diffuse_multiplier = ""
|
||||
self.point_max_distance = ""
|
||||
@@ -43,6 +43,7 @@ ly_add_target(
|
||||
Gem::AtomLyIntegration_CommonFeatures.Public
|
||||
Gem::LmbrCentral.Static
|
||||
Gem::GradientSignal.Static
|
||||
Gem::SurfaceData.Static
|
||||
Gem::Atom_Feature_Common.Static
|
||||
Gem::Atom_Bootstrap.Headers
|
||||
)
|
||||
|
||||
+27
-1
@@ -60,8 +60,34 @@ namespace AZ
|
||||
{
|
||||
public:
|
||||
virtual void OnModelReady(const Data::Asset<RPI::ModelAsset>& modelAsset, const Data::Instance<RPI::Model>& model) = 0;
|
||||
virtual void OnModelPreDestroy() {}
|
||||
|
||||
/**
|
||||
* When connecting to this bus if the asset is ready you will immediately get an OnModelReady event
|
||||
*/
|
||||
template<class Bus>
|
||||
struct ConnectionPolicy
|
||||
: public AZ::EBusConnectionPolicy<Bus>
|
||||
{
|
||||
static void Connect(
|
||||
typename Bus::BusPtr& busPtr,
|
||||
typename Bus::Context& context,
|
||||
typename Bus::HandlerNode& handler,
|
||||
typename Bus::Context::ConnectLockGuard& connectLock,
|
||||
const typename Bus::BusIdType& id = 0)
|
||||
{
|
||||
AZ::EBusConnectionPolicy<Bus>::Connect(busPtr, context, handler, connectLock, id);
|
||||
|
||||
Data::Instance<RPI::Model> model;
|
||||
MeshComponentRequestBus::EventResult(model, id, &MeshComponentRequestBus::Events::GetModel);
|
||||
if (model &&
|
||||
model->GetModelAsset().GetStatus() == AZ::Data::AssetData::AssetStatus::Ready)
|
||||
{
|
||||
handler->OnModelReady(model->GetModelAsset(), model);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
using MeshComponentNotificationBus = EBus<MeshComponentNotifications>;
|
||||
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+1
-5
@@ -98,10 +98,7 @@ namespace AZ
|
||||
->Attribute(AZ::Edit::Attributes::DefaultAsset, &EditorMaterialComponentSlot::GetDefaultAssetId)
|
||||
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &EditorMaterialComponentSlot::GetLabel)
|
||||
->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, true)
|
||||
->Attribute("ShowThumbnail", true)
|
||||
->Attribute("EditButton", ":/Cards/img/UI20/Cards/menu_ico.svg")
|
||||
->Attribute("EditDescription", "")
|
||||
->Attribute("EditCallback", &EditorMaterialComponentSlot::OpenPopupMenu)
|
||||
->Attribute("ThumbnailWithDropDown", &EditorMaterialComponentSlot::OpenPopupMenu)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -109,7 +106,6 @@ namespace AZ
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<EditorMaterialComponentSlot>("EditorMaterialComponentSlot")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview)
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "editor")
|
||||
|
||||
@@ -75,7 +75,6 @@ namespace AZ
|
||||
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<MaterialComponentConfig>("MaterialComponentConfig")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview)
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "render")
|
||||
->Attribute(AZ::Script::Attributes::Module, "render")
|
||||
|
||||
-1
@@ -33,7 +33,6 @@ namespace AZ
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->EBus<MaterialComponentRequestBus>("MaterialComponentRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview)
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "render")
|
||||
->Attribute(AZ::Script::Attributes::Module, "render")
|
||||
|
||||
@@ -137,7 +137,9 @@ namespace AZ
|
||||
AZ::Transform transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(transform, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
|
||||
|
||||
return m_controller.GetModel()->RayIntersection(transform, src, dir, distance);
|
||||
AZ::Vector3 ignoreNormal;
|
||||
|
||||
return m_controller.GetModel()->RayIntersection(transform, src, dir, distance, ignoreNormal);
|
||||
}
|
||||
|
||||
bool EditorMeshComponent::SupportsEditorRayIntersect()
|
||||
@@ -197,7 +199,6 @@ namespace AZ
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay,
|
||||
AzToolsFramework::Refresh_EntireTree);
|
||||
}
|
||||
|
||||
AZ::u32 EditorMeshComponent::OnConfigurationChanged()
|
||||
{
|
||||
// temp variable is needed to hold reference to m_modelAsset while it's being loaded.
|
||||
|
||||
@@ -87,6 +87,12 @@ namespace AZ
|
||||
return values;
|
||||
}
|
||||
|
||||
MeshComponentController::~MeshComponentController()
|
||||
{
|
||||
// Release memory, disconnect from buses in the right order and broadcast events so that other components are aware.
|
||||
Deactivate();
|
||||
}
|
||||
|
||||
void MeshComponentController::Reflect(ReflectContext* context)
|
||||
{
|
||||
MeshComponentConfig::Reflect(context);
|
||||
@@ -130,11 +136,13 @@ namespace AZ
|
||||
void MeshComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("MaterialReceiverService", 0x0d1a6a74));
|
||||
provided.push_back(AZ_CRC("MeshService", 0x71d8a455));
|
||||
}
|
||||
|
||||
void MeshComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("MaterialReceiverService", 0x0d1a6a74));
|
||||
incompatible.push_back(AZ_CRC("MeshService", 0x71d8a455));
|
||||
}
|
||||
|
||||
// [GFX TODO] [ATOM-13339] Remove the ModelAsset id fix up function in MeshComponentController
|
||||
@@ -157,7 +165,7 @@ namespace AZ
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Failed to find asset id for [%s] ", modelAsset.GetHint().c_str());
|
||||
AZ_Error("MeshComponentController", false, "Failed to find asset id for [%s] ", modelAsset.GetHint().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,14 +200,15 @@ namespace AZ
|
||||
|
||||
void MeshComponentController::Deactivate()
|
||||
{
|
||||
// Buses must be disconnected after unregistering the model, otherwise they can't deliver the events during the process.
|
||||
UnregisterModel();
|
||||
|
||||
AzFramework::BoundsRequestBus::Handler::BusDisconnect();
|
||||
MeshComponentRequestBus::Handler::BusDisconnect();
|
||||
TransformNotificationBus::Handler::BusDisconnect();
|
||||
MaterialReceiverRequestBus::Handler::BusDisconnect();
|
||||
MaterialComponentNotificationBus::Handler::BusDisconnect();
|
||||
|
||||
UnregisterModel();
|
||||
|
||||
m_meshFeatureProcessor = nullptr;
|
||||
m_transformInterface = nullptr;
|
||||
m_entityId = AZ::EntityId(AZ::EntityId::InvalidEntityId);
|
||||
@@ -283,6 +292,7 @@ namespace AZ
|
||||
{
|
||||
if (m_meshFeatureProcessor)
|
||||
{
|
||||
MeshComponentNotificationBus::Event(m_entityId, &MeshComponentNotificationBus::Events::OnModelPreDestroy);
|
||||
m_meshFeatureProcessor->ReleaseMesh(m_meshHandle);
|
||||
}
|
||||
}
|
||||
@@ -320,7 +330,7 @@ namespace AZ
|
||||
|
||||
const Data::Asset<RPI::ModelAsset>& MeshComponentController::GetModelAsset() const
|
||||
{
|
||||
return m_configuration.m_modelAsset;
|
||||
return GetModel() ? GetModel()->GetModelAsset() : m_configuration.m_modelAsset;
|
||||
}
|
||||
|
||||
Data::AssetId MeshComponentController::GetModelAssetId() const
|
||||
|
||||
@@ -66,6 +66,8 @@ namespace AZ
|
||||
AZ_CLASS_ALLOCATOR(MeshComponentController, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(AZ::Render::MeshComponentController, "{D0F35FAC-4194-4C89-9487-D000DDB8B272}");
|
||||
|
||||
~MeshComponentController();
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <SkyBox/HDRiSkyboxComponent.h>
|
||||
#include <SkyBox/PhysicalSkyComponent.h>
|
||||
#include <Scripting/EntityReferenceComponent.h>
|
||||
#include <SurfaceData/SurfaceDataMeshComponent.h>
|
||||
|
||||
#ifdef ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
|
||||
#include <EditorCommonFeaturesSystemComponent.h>
|
||||
@@ -71,6 +72,7 @@
|
||||
#include <SkyBox/EditorHDRiSkyboxComponent.h>
|
||||
#include <SkyBox/EditorPhysicalSkyComponent.h>
|
||||
#include <Scripting/EditorEntityReferenceComponent.h>
|
||||
#include <SurfaceData/EditorSurfaceDataMeshComponent.h>
|
||||
#endif
|
||||
|
||||
namespace AZ
|
||||
@@ -114,6 +116,7 @@ namespace AZ
|
||||
GradientWeightModifierComponent::CreateDescriptor(),
|
||||
DiffuseProbeGridComponent::CreateDescriptor(),
|
||||
DeferredFogComponent::CreateDescriptor(),
|
||||
SurfaceData::SurfaceDataMeshComponent::CreateDescriptor(),
|
||||
|
||||
#ifdef ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
|
||||
EditorAreaLightComponent::CreateDescriptor(),
|
||||
@@ -145,6 +148,7 @@ namespace AZ
|
||||
EditorGradientWeightModifierComponent::CreateDescriptor(),
|
||||
EditorDiffuseProbeGridComponent::CreateDescriptor(),
|
||||
EditorDeferredFogComponent::CreateDescriptor(),
|
||||
SurfaceData::EditorSurfaceDataMeshComponent::CreateDescriptor(),
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
#include <AzFramework/Components/ComponentAdapter.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/PostProcess/GradientWeightModifier/GradientWeightModifierComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/PostProcess/GradientWeightModifier/GradientWeightModifierComponentConfig.h>
|
||||
#include <PostProcess/GradientWeightModifier/GradientWeightModifierComponentController.h>
|
||||
#include <PostProcess/GradientWeightModifier/GradientWeightModifierController.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <PostProcess/GradientWeightModifier/GradientWeightModifierComponentController.h>
|
||||
#include <PostProcess/GradientWeightModifier/GradientWeightModifierController.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "EditorSurfaceDataMeshComponent.h"
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
|
||||
#include <LmbrCentral/Dependency/DependencyNotificationBus.h>
|
||||
|
||||
namespace SurfaceData
|
||||
{
|
||||
void EditorSurfaceDataMeshComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
BaseClassType::ReflectSubClass<EditorSurfaceDataMeshComponent, BaseClassType>(context, 2, &LmbrCentral::EditorWrappedComponentBaseVersionConverter<typename BaseClassType::WrappedComponentType, typename BaseClassType::WrappedConfigType,2>);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Module/Module.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
|
||||
#include <SurfaceData/SurfaceDataMeshComponent.h>
|
||||
#include <LmbrCentral/Component/EditorWrappedComponentBase.h>
|
||||
|
||||
namespace SurfaceData
|
||||
{
|
||||
class EditorSurfaceDataMeshComponent
|
||||
: public LmbrCentral::EditorWrappedComponentBase<SurfaceDataMeshComponent, SurfaceDataMeshConfig>
|
||||
{
|
||||
public:
|
||||
using BaseClassType = LmbrCentral::EditorWrappedComponentBase<SurfaceDataMeshComponent, SurfaceDataMeshConfig>;
|
||||
AZ_EDITOR_COMPONENT(EditorSurfaceDataMeshComponent, "{4D73E979-5463-4B75-AE46-70B1E52CBF43}", BaseClassType);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static constexpr const char* const s_categoryName = "Surface Data";
|
||||
static constexpr const char* const s_componentName = "Mesh Surface Tag Emitter";
|
||||
static constexpr const char* const s_componentDescription = "Enables a static mesh to emit surface tags";
|
||||
static constexpr const char* const s_icon = "Editor/Icons/Components/SurfaceData.svg";
|
||||
static constexpr const char* const s_viewportIcon = "Editor/Icons/Components/Viewport/SurfaceData.png";
|
||||
static constexpr const char* const s_helpUrl = "https://docs.aws.amazon.com/console/lumberyard/surfacedata/mesh-surface-tag-emitter";
|
||||
};
|
||||
}
|
||||
+288
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensor's.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "SurfaceDataMeshComponent.h"
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <LmbrCentral/Rendering/MeshAsset.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelAssetCreator.h>
|
||||
|
||||
#include <SurfaceData/SurfaceDataSystemRequestBus.h>
|
||||
#include <SurfaceData/Utility/SurfaceDataUtility.h>
|
||||
|
||||
#include <MathConversion.h>
|
||||
|
||||
namespace SurfaceData
|
||||
{
|
||||
void SurfaceDataMeshConfig::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<SurfaceDataMeshConfig, AZ::ComponentConfig>()
|
||||
->Version(0)
|
||||
->Field("SurfaceTags", &SurfaceDataMeshConfig::m_tags)
|
||||
;
|
||||
|
||||
AZ::EditContext* edit = serialize->GetEditContext();
|
||||
if (edit)
|
||||
{
|
||||
edit->Class<SurfaceDataMeshConfig>(
|
||||
"Mesh Surface Tag Emitter", "")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(0, &SurfaceDataMeshConfig::m_tags, "Generated Tags", "")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
{
|
||||
services.push_back(AZ_CRC("SurfaceDataProviderService", 0xfe9fb95e));
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
{
|
||||
services.push_back(AZ_CRC("SurfaceDataProviderService", 0xfe9fb95e));
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
{
|
||||
services.push_back(AZ_CRC("MeshService", 0x71d8a455));
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
SurfaceDataMeshConfig::Reflect(context);
|
||||
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<SurfaceDataMeshComponent, AZ::Component>()
|
||||
->Version(0)
|
||||
->Field("Configuration", &SurfaceDataMeshComponent::m_configuration)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
SurfaceDataMeshComponent::SurfaceDataMeshComponent(const SurfaceDataMeshConfig& configuration)
|
||||
: m_configuration(configuration)
|
||||
{
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::Activate()
|
||||
{
|
||||
AZ::TransformNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
|
||||
m_providerHandle = InvalidSurfaceDataRegistryHandle;
|
||||
m_refresh = false;
|
||||
|
||||
// Update the cached mesh data and bounds, then register the surface data provider
|
||||
UpdateMeshData();
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::Deactivate()
|
||||
{
|
||||
if (m_providerHandle != InvalidSurfaceDataRegistryHandle)
|
||||
{
|
||||
SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle);
|
||||
m_providerHandle = InvalidSurfaceDataRegistryHandle;
|
||||
}
|
||||
|
||||
SurfaceDataProviderRequestBus::Handler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AZ::TransformNotificationBus::Handler::BusDisconnect();
|
||||
AZ::Render::MeshComponentNotificationBus::Handler::BusDisconnect();
|
||||
m_refresh = false;
|
||||
|
||||
// Clear the cached mesh data
|
||||
{
|
||||
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
|
||||
m_meshAssetData = {};
|
||||
m_meshBounds = AZ::Aabb::CreateNull();
|
||||
m_meshWorldTM = AZ::Transform::CreateIdentity();
|
||||
m_meshWorldTMInverse = AZ::Transform::CreateIdentity();
|
||||
}
|
||||
}
|
||||
|
||||
bool SurfaceDataMeshComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
|
||||
{
|
||||
if (auto config = azrtti_cast<const SurfaceDataMeshConfig*>(baseConfig))
|
||||
{
|
||||
m_configuration = *config;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SurfaceDataMeshComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
|
||||
{
|
||||
if (auto config = azrtti_cast<SurfaceDataMeshConfig*>(outBaseConfig))
|
||||
{
|
||||
*config = m_configuration;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SurfaceDataMeshComponent::DoRayTrace(const AZ::Vector3& inPosition, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Entity);
|
||||
|
||||
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
|
||||
|
||||
// test AABB as first pass to claim the point
|
||||
const AZ::Vector3 testPosition = AZ::Vector3(
|
||||
inPosition.GetX(),
|
||||
inPosition.GetY(),
|
||||
(m_meshBounds.GetMax().GetZ() + m_meshBounds.GetMin().GetZ()) * 0.5f);
|
||||
|
||||
if (!m_meshBounds.Contains(testPosition))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::RPI::ModelAsset* mesh = m_meshAssetData.GetAs<AZ::RPI::ModelAsset>();
|
||||
if (!mesh)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const AZ::Vector3 rayOrigin = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMax().GetZ() + s_rayAABBHeightPadding);
|
||||
const AZ::Vector3 rayDirection = -AZ::Vector3::CreateAxisZ();
|
||||
return GetMeshRayIntersection(*mesh, m_meshWorldTM, m_meshWorldTMInverse, rayOrigin, rayDirection, outPosition, outNormal);
|
||||
}
|
||||
|
||||
|
||||
void SurfaceDataMeshComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
|
||||
{
|
||||
AZ::Vector3 hitPosition;
|
||||
AZ::Vector3 hitNormal;
|
||||
if (DoRayTrace(inPosition, hitPosition, hitNormal))
|
||||
{
|
||||
SurfacePoint point;
|
||||
point.m_entityId = GetEntityId();
|
||||
point.m_position = hitPosition;
|
||||
point.m_normal = hitNormal;
|
||||
AddMaxValueForMasks(point.m_masks, m_configuration.m_tags, 1.0f);
|
||||
surfacePointList.push_back(point);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Aabb SurfaceDataMeshComponent::GetSurfaceAabb() const
|
||||
{
|
||||
return m_meshBounds;
|
||||
}
|
||||
|
||||
SurfaceTagVector SurfaceDataMeshComponent::GetSurfaceTags() const
|
||||
{
|
||||
return m_configuration.m_tags;
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::OnCompositionChanged()
|
||||
{
|
||||
if (!m_refresh)
|
||||
{
|
||||
m_refresh = true;
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::OnModelReady([[maybe_unused]] const AZ::Data::Asset<AZ::RPI::ModelAsset>& modelAsset, [[maybe_unused]] const AZ::Data::Instance<AZ::RPI::Model>& model)
|
||||
{
|
||||
OnCompositionChanged();
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::OnTransformChanged(const AZ::Transform & local, const AZ::Transform & world)
|
||||
{
|
||||
(void)local;
|
||||
(void)world;
|
||||
OnCompositionChanged();
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
|
||||
{
|
||||
if (m_refresh)
|
||||
{
|
||||
UpdateMeshData();
|
||||
m_refresh = false;
|
||||
}
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::UpdateMeshData()
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Entity);
|
||||
|
||||
bool meshValidBeforeUpdate = false;
|
||||
bool meshValidAfterUpdate = false;
|
||||
|
||||
{
|
||||
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
|
||||
|
||||
meshValidBeforeUpdate = (m_meshAssetData.GetAs<AZ::RPI::ModelAsset>() != nullptr) && (m_meshBounds.IsValid());
|
||||
|
||||
m_meshAssetData = {};
|
||||
AZ::Render::MeshComponentRequestBus::EventResult(m_meshAssetData, GetEntityId(), &AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
|
||||
|
||||
m_meshBounds = AZ::Aabb::CreateNull();
|
||||
AZ::Render::MeshComponentRequestBus::EventResult(m_meshBounds, GetEntityId(), &AZ::Render::MeshComponentRequestBus::Events::GetWorldBounds);
|
||||
|
||||
m_meshWorldTM = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(m_meshWorldTM, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
|
||||
m_meshWorldTMInverse = m_meshWorldTM.GetInverse();
|
||||
|
||||
meshValidAfterUpdate = (m_meshAssetData.GetAs<AZ::RPI::ModelAsset>() != nullptr) && (m_meshBounds.IsValid());
|
||||
}
|
||||
|
||||
SurfaceDataRegistryEntry registryEntry;
|
||||
registryEntry.m_entityId = GetEntityId();
|
||||
registryEntry.m_bounds = GetSurfaceAabb();
|
||||
registryEntry.m_tags = GetSurfaceTags();
|
||||
|
||||
if (!meshValidBeforeUpdate && !meshValidAfterUpdate)
|
||||
{
|
||||
// We didn't have a valid mesh asset before or after running this, so do nothing.
|
||||
}
|
||||
else if (!meshValidBeforeUpdate && meshValidAfterUpdate)
|
||||
{
|
||||
// Our mesh has become valid, so register as a provider and save off the provider handle
|
||||
AZ_Assert((m_providerHandle == InvalidSurfaceDataRegistryHandle), "Surface data handle is initialized before our mesh became active");
|
||||
AZ_Assert(m_meshBounds.IsValid(), "Mesh Geometry isn't correctly initialized.");
|
||||
SurfaceDataSystemRequestBus::BroadcastResult(m_providerHandle, &SurfaceDataSystemRequestBus::Events::RegisterSurfaceDataProvider, registryEntry);
|
||||
|
||||
// Start listening for surface data events
|
||||
AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
|
||||
SurfaceDataProviderRequestBus::Handler::BusConnect(m_providerHandle);
|
||||
}
|
||||
else if (meshValidBeforeUpdate && !meshValidAfterUpdate)
|
||||
{
|
||||
// Our mesh has stopped being valid, so unregister and stop listening for surface data events
|
||||
AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
|
||||
SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle);
|
||||
m_providerHandle = InvalidSurfaceDataRegistryHandle;
|
||||
|
||||
SurfaceDataProviderRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
else if (meshValidBeforeUpdate && meshValidAfterUpdate)
|
||||
{
|
||||
// Our mesh was valid before and after, it just changed in some way, so update our registry entry.
|
||||
AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
|
||||
SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UpdateSurfaceDataProvider, m_providerHandle, registryEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
|
||||
#include <SurfaceData/SurfaceDataProviderRequestBus.h>
|
||||
#include <SurfaceData/SurfaceDataTypes.h>
|
||||
|
||||
namespace LmbrCentral
|
||||
{
|
||||
template<typename, typename>
|
||||
class EditorWrappedComponentBase;
|
||||
}
|
||||
|
||||
namespace SurfaceData
|
||||
{
|
||||
constexpr float s_rayAABBHeightPadding = 0.1f;
|
||||
|
||||
class SurfaceDataMeshConfig
|
||||
: public AZ::ComponentConfig
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(SurfaceDataMeshConfig, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(SurfaceDataMeshConfig, "{764C602E-7CA8-4BCC-AB2D-3E46623B3A20}", AZ::ComponentConfig);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
SurfaceTagVector m_tags;
|
||||
};
|
||||
|
||||
class SurfaceDataMeshComponent
|
||||
: public AZ::Component
|
||||
, public AZ::TickBus::Handler
|
||||
, public AZ::TransformNotificationBus::Handler
|
||||
, public AZ::Render::MeshComponentNotificationBus::Handler
|
||||
, public SurfaceDataProviderRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
template<typename, typename> friend class LmbrCentral::EditorWrappedComponentBase;
|
||||
AZ_COMPONENT(SurfaceDataMeshComponent, "{F8915F34-BE8B-40B4-B7E8-01EBF3DA1C95}");
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
SurfaceDataMeshComponent(const SurfaceDataMeshConfig& configuration);
|
||||
SurfaceDataMeshComponent() = default;
|
||||
~SurfaceDataMeshComponent() = default;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component interface implementation
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
|
||||
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MeshComponentNotificationBus
|
||||
void OnModelReady(const AZ::Data::Asset<AZ::RPI::ModelAsset>& modelAsset, const AZ::Data::Instance<AZ::RPI::Model>& model) override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TransformNotificationBus
|
||||
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// AZ::TickBus
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// SurfaceDataProviderRequestBus
|
||||
void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const override;
|
||||
|
||||
private:
|
||||
bool DoRayTrace(const AZ::Vector3& inPosition, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const;
|
||||
void UpdateMeshData();
|
||||
void OnCompositionChanged();
|
||||
|
||||
AZ::Aabb GetSurfaceAabb() const;
|
||||
SurfaceTagVector GetSurfaceTags() const;
|
||||
|
||||
SurfaceDataMeshConfig m_configuration;
|
||||
|
||||
SurfaceDataRegistryHandle m_providerHandle = InvalidSurfaceDataRegistryHandle;
|
||||
|
||||
// cached data
|
||||
AZStd::atomic_bool m_refresh{ false };
|
||||
mutable AZStd::recursive_mutex m_cacheMutex;
|
||||
AZ::Data::Asset<AZ::Data::AssetData> m_meshAssetData;
|
||||
AZ::Transform m_meshWorldTM = AZ::Transform::CreateIdentity();
|
||||
AZ::Transform m_meshWorldTMInverse = AZ::Transform::CreateIdentity();
|
||||
AZ::Aabb m_meshBounds = AZ::Aabb::CreateNull();
|
||||
};
|
||||
}
|
||||
+1
-1
@@ -35,7 +35,7 @@ namespace AZ
|
||||
//! ThumbnailRendererData encapsulates all data used by thumbnail renderer and caches assets
|
||||
struct ThumbnailRendererData final
|
||||
{
|
||||
static constexpr const char* LightingPresetPath = "lightingpresets/default.lightingpreset.azasset";
|
||||
static constexpr const char* LightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset";
|
||||
static constexpr const char* DefaultModelPath = "materialeditor/viewportmodels/quadsphere.azmodel";
|
||||
static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial";
|
||||
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ namespace AZ
|
||||
data->m_renderPipeline->SetDefaultView(data->m_view);
|
||||
|
||||
// Create lighting preset
|
||||
data->m_lightingPresetAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::AnyAsset>(LightingPresetPath);
|
||||
data->m_lightingPresetAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::AnyAsset>(ThumbnailRendererData::LightingPresetPath);
|
||||
if (data->m_lightingPresetAsset.IsReady())
|
||||
{
|
||||
auto preset = data->m_lightingPresetAsset->GetDataAs<Render::LightingPreset>();
|
||||
|
||||
-1
@@ -31,7 +31,6 @@ namespace AZ
|
||||
void Start() override;
|
||||
|
||||
private:
|
||||
static constexpr const char* LightingPresetPath = "lightingpresets/default.lightingpreset.azasset";
|
||||
static constexpr float AspectRatio = 1.0f;
|
||||
static constexpr float NearDist = 0.1f;
|
||||
static constexpr float FarDist = 100.0f;
|
||||
|
||||
+2
@@ -111,5 +111,7 @@ set(FILES
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h
|
||||
Source/Scripting/EditorEntityReferenceComponent.cpp
|
||||
Source/Scripting/EditorEntityReferenceComponent.h
|
||||
Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp
|
||||
Source/SurfaceData/EditorSurfaceDataMeshComponent.h
|
||||
Resources/AtomLyIntegrationResources.qrc
|
||||
)
|
||||
+4
-2
@@ -117,8 +117,8 @@ set(FILES
|
||||
Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponent.h
|
||||
Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponent.cpp
|
||||
Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponentConfig.cpp
|
||||
Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponentController.h
|
||||
Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponentController.cpp
|
||||
Source/PostProcess/GradientWeightModifier/GradientWeightModifierController.h
|
||||
Source/PostProcess/GradientWeightModifier/GradientWeightModifierController.cpp
|
||||
Source/ScreenSpace/DeferredFogComponentController.h
|
||||
Source/ScreenSpace/DeferredFogComponentController.cpp
|
||||
Source/ScreenSpace/DeferredFogComponent.h
|
||||
@@ -145,4 +145,6 @@ set(FILES
|
||||
Source/Scripting/EntityReferenceComponentConfig.cpp
|
||||
Source/Scripting/EntityReferenceComponentController.cpp
|
||||
Source/Scripting/EntityReferenceComponentController.h
|
||||
Source/SurfaceData/SurfaceDataMeshComponent.cpp
|
||||
Source/SurfaceData/SurfaceDataMeshComponent.h
|
||||
)
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
void CAtomShimRenderer::EF_Init()
|
||||
{
|
||||
bool nv = 0;
|
||||
|
||||
m_RP.m_MaxVerts = 600;
|
||||
m_RP.m_MaxTris = 300;
|
||||
|
||||
@@ -48,7 +46,7 @@ void CAtomShimRenderer::EF_Init()
|
||||
m_RP.m_ObjectsPool = (CRenderObject*)CryModuleMemalign(sizeof(CRenderObject) * (m_RP.m_nNumObjectsInPool * RT_COMMAND_BUF_COUNT), 16);
|
||||
for (int j = 0; j < (int)(m_RP.m_nNumObjectsInPool * RT_COMMAND_BUF_COUNT); j++)
|
||||
{
|
||||
CRenderObject* pRendObj = new(&m_RP.m_ObjectsPool[j])CRenderObject();
|
||||
new(&m_RP.m_ObjectsPool[j])CRenderObject();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -538,8 +538,6 @@ void CAtomShimRenderAuxGeom::DrawAABBs(const AABB* aabb, uint32 aabbCount, bool
|
||||
auto defaultScene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene();
|
||||
if (auto auxGeom = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(defaultScene))
|
||||
{
|
||||
AZ::RPI::AuxGeomDraw::DrawStyle drawStyle = LyDrawStyleToAZDrawStyle(bSolid, bbDrawStyle);
|
||||
|
||||
for (int i = 0; i < aabbCount; ++aabbCount)
|
||||
{
|
||||
auxGeom->DrawAabb(
|
||||
|
||||
@@ -207,8 +207,7 @@ void CAtomShimRenderer::BeginFrame()
|
||||
shaderOptionsWrap.push_back(AZ::RPI::ShaderOption(AZ::Name("o_clamp"), AZ::Name("false")));
|
||||
m_shaderVariantWrap = m_dynamicDraw->UseShaderVariant(shaderOptionsWrap);
|
||||
|
||||
AZ::Data::Instance<AZ::RPI::ShaderResourceGroup> drawSrg = m_dynamicDraw->NewDrawSrg();
|
||||
const AZ::RHI::ShaderResourceGroupLayout* layout = drawSrg->GetAsset()->GetLayout();
|
||||
m_dynamicDraw->NewDrawSrg();
|
||||
|
||||
m_isFinalInitializationDone = true;
|
||||
}
|
||||
@@ -377,11 +376,6 @@ void CAtomShimRenderer::DrawImage(float xpos, float ypos, float w, float h, int
|
||||
///////////////////////////////////////////
|
||||
void CAtomShimRenderer::DrawImageWithUV(float xpos, float ypos, float z, float w, float h, int texture_id, float s[4], float t[4], float r, float g, float b, float a, bool filtered)
|
||||
{
|
||||
float fx = xpos;
|
||||
float fy = ypos;
|
||||
float fw = w;
|
||||
float fh = h;
|
||||
|
||||
SetCullMode(R_CULL_DISABLE);
|
||||
EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
|
||||
EF_SetSrgbWrite(false);
|
||||
@@ -559,7 +553,6 @@ void CAtomShimRenderer::SetCamera(const CCamera& cam)
|
||||
mViewFinal.m31 = mView.m32;
|
||||
mViewFinal.m32 = -mView.m31;
|
||||
|
||||
Matrix44A* m = &m_RP.m_TI[nThreadID].m_matView;
|
||||
m_RP.m_TI[nThreadID].m_matView = mViewFinal;
|
||||
|
||||
mViewFinal.m30 = 0;
|
||||
|
||||
@@ -344,7 +344,6 @@ void AtomShimTexture::CreateFromImage(const AZ::Data::Instance<AZ::RPI::Image>&
|
||||
{
|
||||
AZ::RHI::Format rhiViewFormat = AZ::RHI::Format::Unknown;
|
||||
AZ::RHI::ImageViewDescriptor viewDesc = AZ::RHI::ImageViewDescriptor(rhiViewFormat);
|
||||
AZ::RHI::Factory& factory = AZ::RHI::Factory::Get();
|
||||
AZ::RHI::Image* rhiImage = image->GetRHIImage();
|
||||
|
||||
AZ::RHI::Ptr<AZ::RHI::ImageView> imageView = rhiImage->GetImageView(viewDesc);
|
||||
|
||||
@@ -81,7 +81,6 @@ namespace AZ
|
||||
lodIndexCount = 0;
|
||||
lodVertexCount = 0;
|
||||
|
||||
uint32_t subMeshIndexOffset = 0;
|
||||
const Data::Asset<RPI::ModelLodAsset>& lodAsset = actor->GetMeshAsset()->GetLodAssets()[lodIndex];
|
||||
const AZStd::array_view<RPI::ModelLodAsset::Mesh> modelMeshes = lodAsset->GetMeshes();
|
||||
for (const RPI::ModelLodAsset::Mesh& modelMesh : modelMeshes)
|
||||
@@ -395,7 +394,6 @@ namespace AZ
|
||||
uvBufferData.resize_no_construct(lodVertexCount);
|
||||
|
||||
// Now iterate over the actual data and populate the data for the per-actor buffers
|
||||
size_t lodVertexStart = 0;
|
||||
size_t indexBufferOffset = 0;
|
||||
size_t vertexBufferOffset = 0;
|
||||
size_t skinnedMeshSubmeshIndex = 0;
|
||||
@@ -410,7 +408,6 @@ namespace AZ
|
||||
// Each of these is one long buffer containing the data for all sub-meshes in the joint
|
||||
const AZ::Vector3* sourcePositions = static_cast<const AZ::Vector3*>(mesh->FindOriginalVertexData(EMotionFX::Mesh::ATTRIB_POSITIONS));
|
||||
const AZ::Vector3* sourceNormals = static_cast<const AZ::Vector3*>(mesh->FindOriginalVertexData(EMotionFX::Mesh::ATTRIB_NORMALS));
|
||||
const uint32_t* sourceOriginalVertex = static_cast<const uint32_t*>(mesh->FindOriginalVertexData(EMotionFX::Mesh::ATTRIB_ORGVTXNUMBERS));
|
||||
const AZ::Vector4* sourceTangents = static_cast<const AZ::Vector4*>(mesh->FindOriginalVertexData(EMotionFX::Mesh::ATTRIB_TANGENTS));
|
||||
const AZ::Vector3* sourceBitangents = static_cast<const AZ::Vector3*>(mesh->FindOriginalVertexData(EMotionFX::Mesh::ATTRIB_BITANGENTS));
|
||||
const AZ::Vector2* sourceUVs = static_cast<const AZ::Vector2*>(mesh->FindOriginalVertexData(EMotionFX::Mesh::ATTRIB_UVCOORDS, 0));
|
||||
|
||||
@@ -465,10 +465,15 @@ namespace AZ
|
||||
MaterialComponentNotificationBus::Handler::BusConnect(m_entityId);
|
||||
MeshComponentRequestBus::Handler::BusConnect(m_entityId);
|
||||
LmbrCentral::MeshComponentRequestBus::Handler::BusConnect(m_entityId);
|
||||
|
||||
const Data::Instance<RPI::Model> model = m_meshFeatureProcessor->GetModel(*m_meshHandle);
|
||||
MeshComponentNotificationBus::Event(m_entityId, &MeshComponentNotificationBus::Events::OnModelReady, model->GetModelAsset(), model);
|
||||
}
|
||||
|
||||
void AtomActorInstance::UnregisterActor()
|
||||
{
|
||||
MeshComponentNotificationBus::Event(m_entityId, &MeshComponentNotificationBus::Events::OnModelPreDestroy);
|
||||
|
||||
LmbrCentral::MeshComponentRequestBus::Handler::BusDisconnect();
|
||||
MeshComponentRequestBus::Handler::BusDisconnect();
|
||||
MaterialComponentNotificationBus::Handler::BusDisconnect();
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Input/Devices/Touch/InputDeviceTouch.h>
|
||||
#include <AzFramework/Input/Mappings/InputMappingAnd.h>
|
||||
#include <AzFramework/Input/Mappings/InputMappingOr.h>
|
||||
@@ -21,6 +22,9 @@
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
#include <Atom/Feature/ImGui/SystemBus.h>
|
||||
#include <ImGuiContextScope.h>
|
||||
#include <ImGui/ImGuiPass.h>
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
using namespace AzFramework;
|
||||
@@ -31,7 +35,7 @@ namespace AZ
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
constexpr const char* DebugConsoleInputContext = "DebugConsoleInputContext";
|
||||
const InputChannelId ToggleDebugConsoleInputChannelId("ToggleDebugConsole");
|
||||
const InputChannelId ThumbstickL3AndR3InputChannelId("BothGamepadTriggers");
|
||||
const InputChannelId ThumbstickL3AndR3InputChannelId("ThumbstickL3AndR3");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AZ::Color GetColorForLogLevel(const AZ::LogLevel& logLevel)
|
||||
@@ -79,6 +83,16 @@ namespace AZ
|
||||
, m_maxEntriesToDisplay(maxEntriesToDisplay)
|
||||
, m_maxInputHistorySize(maxInputHistorySize)
|
||||
{
|
||||
// The debug console is currently only supported when running the standalone launcher.
|
||||
// It does function correctly when running the editor if you remove this check, but it
|
||||
// conflicts with the legacy debug console that also shows at the bottom of the editor.
|
||||
AZ::ApplicationTypeQuery applicationType;
|
||||
AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::QueryApplicationType, applicationType);
|
||||
if (!applicationType.IsGame())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Create an input mapping so that the debug console can be toggled by 'L3+R3' on a gamepad.
|
||||
AZStd::shared_ptr<InputMappingAnd> inputMappingL3AndR3 = AZStd::make_shared<InputMappingAnd>(ThumbstickL3AndR3InputChannelId, m_inputContext);
|
||||
inputMappingL3AndR3->AddSourceInput(InputDeviceGamepad::Button::L3);
|
||||
@@ -112,33 +126,34 @@ namespace AZ
|
||||
// Bind our custom log handler.
|
||||
AZ::Interface<AZ::ILogger>::Get()->BindLogHandler(m_logHandler);
|
||||
|
||||
// Connect to receive tick events.
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
// Connect to receive render tick events.
|
||||
auto atomViewportRequests = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
|
||||
const AZ::Name contextName = atomViewportRequests->GetDefaultViewportContextName();
|
||||
AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect(contextName);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DebugConsole::~DebugConsole()
|
||||
{
|
||||
// Disconnect to stop receiving tick events.
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
// Disconnect to stop receiving render tick events.
|
||||
AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect();
|
||||
|
||||
// Disconnect our custom log handler.
|
||||
m_logHandler.Disconnect();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
int DebugConsole::GetTickOrder()
|
||||
void DebugConsole::OnRenderTick()
|
||||
{
|
||||
return AZ::ComponentTickBus::TICK_UI;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void DebugConsole::OnTick([[maybe_unused]]float deltaTime,
|
||||
[[maybe_unused]]AZ::ScriptTimePoint scriptTimePoint)
|
||||
{
|
||||
if (m_isShowing)
|
||||
if (!m_isShowing)
|
||||
{
|
||||
DrawDebugConsole();
|
||||
return;
|
||||
}
|
||||
|
||||
const bool continueShowing = DrawDebugConsole();
|
||||
if (!continueShowing)
|
||||
{
|
||||
ToggleIsShowing();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +163,7 @@ namespace AZ
|
||||
if (inputChannel.GetInputChannelId() == ToggleDebugConsoleInputChannelId &&
|
||||
inputChannel.IsStateBegan())
|
||||
{
|
||||
m_isShowing = !m_isShowing;
|
||||
ToggleIsShowing();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -292,14 +307,26 @@ namespace AZ
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void DebugConsole::DrawDebugConsole()
|
||||
bool DebugConsole::DrawDebugConsole()
|
||||
{
|
||||
// Get the default ImGui pass.
|
||||
AZ::Render::ImGuiPass* defaultImGuiPass = nullptr;
|
||||
AZ::Render::ImGuiSystemRequestBus::BroadcastResult(defaultImGuiPass, &AZ::Render::ImGuiSystemRequestBus::Events::GetDefaultImGuiPass);
|
||||
if (!defaultImGuiPass)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create an ImGui context scope using the default ImGui pass context.
|
||||
ImGui::ImGuiContextScope contextScope(defaultImGuiPass->GetContext());
|
||||
|
||||
// Draw the debug console in a closeable, moveable, and resizeable IMGUI window.
|
||||
bool continueShowing = true;
|
||||
ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver);
|
||||
if (!ImGui::Begin("Debug Console", &m_isShowing))
|
||||
if (!ImGui::Begin("Debug Console", &continueShowing))
|
||||
{
|
||||
ImGui::End();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Show a scrolling child region in which to display all debug log entires.
|
||||
@@ -375,5 +402,38 @@ namespace AZ
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
return continueShowing;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AzFramework::SystemCursorState GetDesiredSystemCursorState()
|
||||
{
|
||||
AZ::ApplicationTypeQuery applicationType;
|
||||
AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::QueryApplicationType, applicationType);
|
||||
return applicationType.IsEditor() ?
|
||||
AzFramework::SystemCursorState::ConstrainedAndVisible :
|
||||
AzFramework::SystemCursorState::UnconstrainedAndVisible;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void DebugConsole::ToggleIsShowing()
|
||||
{
|
||||
m_isShowing = !m_isShowing;
|
||||
if (m_isShowing)
|
||||
{
|
||||
AzFramework::InputSystemCursorRequestBus::EventResult(m_previousSystemCursorState,
|
||||
AzFramework::InputDeviceMouse::Id,
|
||||
&AzFramework::InputSystemCursorRequests::GetSystemCursorState);
|
||||
AzFramework::InputSystemCursorRequestBus::Event(AzFramework::InputDeviceMouse::Id,
|
||||
&AzFramework::InputSystemCursorRequests::SetSystemCursorState,
|
||||
GetDesiredSystemCursorState());
|
||||
}
|
||||
else
|
||||
{
|
||||
AzFramework::InputSystemCursorRequestBus::Event(AzFramework::InputDeviceMouse::Id,
|
||||
&AzFramework::InputSystemCursorRequests::SetSystemCursorState,
|
||||
m_previousSystemCursorState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/Input/Buses/Requests/InputSystemCursorRequestBus.h>
|
||||
#include <AzFramework/Input/Contexts/InputContext.h>
|
||||
#include <AzFramework/Input/Events/InputChannelEventFilter.h>
|
||||
#include <AzFramework/Input/Events/InputChannelEventListener.h>
|
||||
@@ -23,6 +24,8 @@
|
||||
#include <AzCore/std/containers/deque.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <Atom/RPI.Public/ViewportContextBus.h>
|
||||
|
||||
struct ImGuiInputTextCallbackData;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -43,8 +46,8 @@ namespace AZ
|
||||
//! - The '~' key on a keyboard.
|
||||
//! - Both the 'L3+R3' buttons on a gamepad.
|
||||
//! - The fourth finger press on a touch screen.
|
||||
class DebugConsole : public AZ::TickBus::Handler
|
||||
, public AzFramework::InputChannelEventListener
|
||||
class DebugConsole : public AzFramework::InputChannelEventListener
|
||||
, public AZ::RPI::ViewportContextNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -67,12 +70,8 @@ namespace AZ
|
||||
~DebugConsole() override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AZ::TickBus::Handler
|
||||
int GetTickOrder() override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! \ref AZ::TickEvents::OnTick
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint scriptTimePoint) override;
|
||||
//! \ref AZ::RPI::ViewportContextRequestsInterface
|
||||
void OnRenderTick() override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! \ref AzFramework::InputChannelEventListener::OnInputChannelEventFiltered
|
||||
@@ -105,7 +104,12 @@ namespace AZ
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! Draw the debug console.
|
||||
void DrawDebugConsole();
|
||||
//! \return True if we should continue showing the debug console, false otherwise.
|
||||
bool DrawDebugConsole();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! Toggle whether the debug console is showing or not.
|
||||
void ToggleIsShowing();
|
||||
|
||||
private:
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -115,6 +119,7 @@ namespace AZ
|
||||
AZ::ILogger::LogEvent::Handler m_logHandler; //!< Handler that receives log events to display.
|
||||
AzFramework::InputContext m_inputContext; //!< Input context used to open/close the console.
|
||||
char m_inputBuffer[1028] = {}; //!< The character buffer used to accept text input.
|
||||
AzFramework::SystemCursorState m_previousSystemCursorState; //! The last system cursor state.
|
||||
int m_currentHistoryIndex = -1; //!< The current index into the input history when browsing.
|
||||
int m_maxEntriesToDisplay = DefaultMaxEntriesToDisplay; //!< The maximum entries to display.
|
||||
int m_maxInputHistorySize = DefaultMaxInputHistorySize; //!< The maximum input history size.
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
#include <Atom/Feature/ImGui/ImGuiUtils.h>
|
||||
#include <Atom/Feature/ImGui/SystemBus.h>
|
||||
#include <Atom/RPI.Public/ViewportContext.h>
|
||||
|
||||
#if defined(IMGUI_ENABLED)
|
||||
#include <ImGuiBus.h>
|
||||
#endif
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -49,16 +54,28 @@ namespace AZ
|
||||
void ImguiAtomSystemComponent::Activate()
|
||||
{
|
||||
ImGui::OtherActiveImGuiRequestBus::Handler::BusConnect();
|
||||
|
||||
auto atomViewportRequests = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
|
||||
const AZ::Name contextName = atomViewportRequests->GetDefaultViewportContextName();
|
||||
AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect(contextName);
|
||||
}
|
||||
|
||||
void ImguiAtomSystemComponent::Deactivate()
|
||||
{
|
||||
ImGui::OtherActiveImGuiRequestBus::Handler::BusDisconnect();
|
||||
AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void ImguiAtomSystemComponent::RenderImGuiBuffers(const ImDrawData& drawData)
|
||||
{
|
||||
Render::ImGuiSystemRequestBus::Broadcast(&Render::ImGuiSystemRequests::RenderImGuiBuffersToDefaultPass, drawData);
|
||||
Render::ImGuiSystemRequestBus::Broadcast(&Render::ImGuiSystemRequests::RenderImGuiBuffersToCurrentViewport, drawData);
|
||||
}
|
||||
|
||||
void ImguiAtomSystemComponent::OnRenderTick()
|
||||
{
|
||||
#if defined(IMGUI_ENABLED)
|
||||
ImGui::ImGuiManagerListenerBus::Broadcast(&ImGui::IImGuiManagerListener::Render);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <OtherActiveImGuiBus.h>
|
||||
#include <DebugConsole.h>
|
||||
|
||||
#include <Atom/RPI.Public/ViewportContextBus.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LYIntegration
|
||||
@@ -28,6 +30,8 @@ namespace AZ
|
||||
class ImguiAtomSystemComponent final
|
||||
: public AZ::Component
|
||||
, public ImGui::OtherActiveImGuiRequestBus::Handler
|
||||
// The Imgui Gem's ImGuiManager can handle this directly when engine is fully switched to Atom Renderer
|
||||
, public AZ::RPI::ViewportContextNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(ImguiAtomSystemComponent, "{D423E075-D971-435A-A9C1-57C3B0623A9B}");
|
||||
@@ -43,10 +47,14 @@ namespace AZ
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
private:
|
||||
|
||||
// OtherActiveImGuiRequestBus overrides ...
|
||||
void RenderImGuiBuffers(const ImDrawData& drawData) override;
|
||||
|
||||
private:
|
||||
// ViewportContextNotificationBus overrides...
|
||||
void OnRenderTick() override;
|
||||
|
||||
DebugConsole m_debugConsole;
|
||||
};
|
||||
} // namespace LYIntegration
|
||||
|
||||
-1
@@ -363,4 +363,3 @@ base_directory = sys.argv[-3]
|
||||
destination_directory = sys.argv[-2]
|
||||
modify_naming = sys.argv[-1]
|
||||
CreateMayaFiles(file_list, base_directory, destination_directory, modify_naming)
|
||||
|
||||
|
||||
+1
@@ -103,6 +103,7 @@ _LOGGER.debug('Initializing: {0}.'.format({module_name}))
|
||||
|
||||
|
||||
class LegacyFilesConverter(QtWidgets.QDialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(LegacyFilesConverter, self).__init__(parent)
|
||||
|
||||
|
||||
@@ -158,9 +158,10 @@ def bootstrap_dccsi_py_libs(dccsi_dirpath=return_stub_dir()):
|
||||
"""Builds and adds local site dir libs based on py version"""
|
||||
|
||||
from azpy.constants import STR_DCCSI_PYTHON_LIB_PATH # a path string constructor
|
||||
_DCCSI_PYTHON_LIB_PATH = STR_DCCSI_PYTHON_LIB_PATH.format(dccsi_dirpath,
|
||||
sys.version_info[0],
|
||||
sys.version_info[1])
|
||||
_DCCSI_PYTHON_LIB_PATH = "E:\\P4\\jromnoa_spectra_atom_2\\dev\\Tools\\Python\\3.7.5\\windows\\Lib\\site-packages"
|
||||
# _DCCSI_PYTHON_LIB_PATH = STR_DCCSI_PYTHON_LIB_PATH.format(dccsi_dirpath,
|
||||
# sys.version_info[0],
|
||||
# sys.version_info[1])
|
||||
|
||||
if os.path.exists(_DCCSI_PYTHON_LIB_PATH):
|
||||
_LOGGER.debug('Performed site.addsitedir({})'.format(_DCCSI_PYTHON_LIB_PATH))
|
||||
|
||||
Reference in New Issue
Block a user