├── .gitattributes ├── MayaKrakatoa.exp ├── NOTICE.txt ├── icons ├── krakatoa16_magma_icon.png ├── krakatoa16_modifier_icon.png ├── krakatoa16_prtsaver_icon.png ├── krakatoa16_prtloader_icon.png ├── krakatoa16_prtsurface_icon.png ├── krakatoa16_prtvolume_icon.png └── krakatoa16_prtfractals_icon.png ├── .gitignore ├── stdafx.cpp ├── MayaKrakatoa.map ├── scripts ├── KrakatoaDeinit.mel ├── KrakatoaNoticesDialog.py ├── AEPRTMayaParticleTemplate.mel ├── AEPRTMagmaTemplate.mel ├── KrakatoaInit.mel ├── MayaKrakatoa.py └── AEPRTModifierTemplate.mel ├── include ├── PRTLoaderIconMesh.hpp ├── PRTSurfaceIconMesh.hpp ├── PRTVolumeIconMesh.hpp ├── PRTFractalsIconMesh.hpp ├── PRTSaver.hpp ├── KrakatoaVersionCommand.hpp ├── KrakatoaSettings.hpp ├── PRTIconMesh.hpp ├── PRTExporter.hpp ├── GenerateStickyChannelsCommand.hpp ├── KrakatoaPluginDirectory.hpp ├── maya_frame_buffer_interface.hpp ├── KrakatoaParticleJitter.hpp ├── maya_progress_bar_interface.hpp ├── KrakatoaRender.hpp ├── PRTObjectUI.hpp ├── maya_render_save_interface.hpp ├── PRTModifiers.hpp ├── PRTObject.hpp ├── KrakatoaRenderSettingsNode.hpp ├── PRTSurface.hpp ├── PRTFractal.hpp ├── maya_ksr.hpp ├── PRTObjectUIGeometryOverride.hpp ├── PRTLoader.hpp └── PRTVolume.hpp ├── CODE_OF_CONDUCT.md ├── .clang-format ├── src ├── PRTSaver.cpp ├── KrakatoaSettings.cpp ├── KrakatoaVersionCommand.cpp ├── KrakatoaPluginDirectory.cpp ├── maya_frame_buffer_interface.cpp ├── maya_progress_bar_interface.cpp ├── PRTObject.cpp ├── GenerateStickyChannelsCommand.cpp ├── KrakatoaParticleJitter.cpp ├── PRTVolumeIconMesh.cpp ├── maya_render_save_interface.cpp └── PRTExporter.cpp ├── version_gen.py ├── stdafx.h ├── README.md ├── CMakeLists.txt ├── conanfile.py ├── CONTRIBUTING.md └── LICENSE.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /MayaKrakatoa.exp: -------------------------------------------------------------------------------- 1 | *initializePlugin* 2 | *uninitializePlugin* 3 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | KrakatoaMY 2 | Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /icons/krakatoa16_magma_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/thinkbox-krakatoa-my/HEAD/icons/krakatoa16_magma_icon.png -------------------------------------------------------------------------------- /icons/krakatoa16_modifier_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/thinkbox-krakatoa-my/HEAD/icons/krakatoa16_modifier_icon.png -------------------------------------------------------------------------------- /icons/krakatoa16_prtsaver_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/thinkbox-krakatoa-my/HEAD/icons/krakatoa16_prtsaver_icon.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | BitRockInstaller/MayaKrakatoa_*.xml 2 | build 3 | __pycache__ 4 | KrakatoaVersion.h 5 | third_party_licenses.txt 6 | -------------------------------------------------------------------------------- /icons/krakatoa16_prtloader_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/thinkbox-krakatoa-my/HEAD/icons/krakatoa16_prtloader_icon.png -------------------------------------------------------------------------------- /icons/krakatoa16_prtsurface_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/thinkbox-krakatoa-my/HEAD/icons/krakatoa16_prtsurface_icon.png -------------------------------------------------------------------------------- /icons/krakatoa16_prtvolume_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/thinkbox-krakatoa-my/HEAD/icons/krakatoa16_prtvolume_icon.png -------------------------------------------------------------------------------- /icons/krakatoa16_prtfractals_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/thinkbox-krakatoa-my/HEAD/icons/krakatoa16_prtfractals_icon.png -------------------------------------------------------------------------------- /stdafx.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | -------------------------------------------------------------------------------- /MayaKrakatoa.map: -------------------------------------------------------------------------------- 1 | { 2 | global: 3 | extern "C++" { 4 | initializePlugin*; 5 | uninitializePlugin*; 6 | }; 7 | local: 8 | *; 9 | }; 10 | 11 | -------------------------------------------------------------------------------- /scripts/KrakatoaDeinit.mel: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | // I believe this is all that is needed to kill a renderer 4 | 5 | renderer -unregisterRenderer MayaKrakatoa; 6 | -------------------------------------------------------------------------------- /include/PRTLoaderIconMesh.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | 7 | const frantic::geometry::trimesh3& get_prt_loader_icon_mesh(); 8 | -------------------------------------------------------------------------------- /include/PRTSurfaceIconMesh.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | 7 | const frantic::geometry::trimesh3& get_prt_surface_icon_mesh(); 8 | -------------------------------------------------------------------------------- /include/PRTVolumeIconMesh.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | 7 | const frantic::geometry::trimesh3& get_prt_volume_icon_mesh(); 8 | -------------------------------------------------------------------------------- /include/PRTFractalsIconMesh.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | 7 | const frantic::geometry::trimesh3& get_prt_fractals_icon_mesh(); 8 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | Standard: c++17 3 | UseTab: Never 4 | ColumnLimit: 120 5 | IndentWidth: 4 6 | BreakBeforeBraces: Attach 7 | NamespaceIndentation: None 8 | AlwaysBreakTemplateDeclarations: true 9 | SpacesInParentheses: true 10 | SpaceBeforeParens: Never 11 | BreakConstructorInitializersBeforeComma: true 12 | PointerAlignment: Left 13 | -------------------------------------------------------------------------------- /include/PRTSaver.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | #include 5 | class PRTSaver : public MPxNode { 6 | public: 7 | static void* creator(); 8 | static MStatus initialize(); 9 | static MTypeId typeId; 10 | static MString typeName; 11 | 12 | PRTSaver( void ); 13 | ~PRTSaver( void ); 14 | }; 15 | -------------------------------------------------------------------------------- /include/KrakatoaVersionCommand.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | 7 | class KrakatoaVersionCommand : public MPxCommand { 8 | public: 9 | static const MString commandName; 10 | KrakatoaVersionCommand(); 11 | virtual ~KrakatoaVersionCommand(); 12 | static void* creator(); 13 | virtual MStatus doIt( const MArgList& args ); 14 | }; 15 | -------------------------------------------------------------------------------- /src/PRTSaver.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | 5 | #include "PRTSaver.hpp" 6 | 7 | MTypeId PRTSaver::typeId( 0x00117499 ); 8 | MString PRTSaver::typeName = "ksr_exporter_ui_settings_node"; 9 | 10 | PRTSaver::PRTSaver( void ) {} 11 | 12 | PRTSaver::~PRTSaver( void ) {} 13 | 14 | void* PRTSaver::creator() { return new PRTSaver; } 15 | MStatus PRTSaver::initialize() { return MStatus::kSuccess; } 16 | -------------------------------------------------------------------------------- /include/KrakatoaSettings.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | class KrakatoaSettingsNodeName : public MPxCommand { 10 | public: 11 | static const MString commandName; 12 | static const MString nodeName; 13 | static void* creator(); 14 | 15 | public: 16 | MStatus doIt( const MArgList& args ); 17 | }; 18 | -------------------------------------------------------------------------------- /src/KrakatoaSettings.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | 5 | #include "KrakatoaSettings.hpp" 6 | 7 | const MString KrakatoaSettingsNodeName::commandName = "KrakatoaSettingsNodeName"; 8 | const MString KrakatoaSettingsNodeName::nodeName = "MayaKrakatoaRenderSettings"; 9 | void* KrakatoaSettingsNodeName::creator() { return NULL; } 10 | 11 | MStatus KrakatoaSettingsNodeName::doIt( const MArgList& args ) { return MStatus::kFailure; } 12 | -------------------------------------------------------------------------------- /include/PRTIconMesh.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | void build_icon_mesh( const float* vertices, size_t numVertices, const int* faces, size_t numFaces, 9 | frantic::geometry::trimesh3& outMesh ); 10 | 11 | const frantic::geometry::trimesh3& get_default_icon_mesh(); 12 | 13 | void gl_draw_trimesh( const frantic::geometry::trimesh3& mesh ); 14 | -------------------------------------------------------------------------------- /include/PRTExporter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | /** 10 | * Maya Plugin class for the KrakatoaSR exporter command 11 | */ 12 | class prt_exporter : public MPxCommand { 13 | public: 14 | static const MString commandName; 15 | static void* creator(); 16 | 17 | public: 18 | prt_exporter(); 19 | ~prt_exporter(); 20 | MStatus doIt( const MArgList& Args ); 21 | }; 22 | -------------------------------------------------------------------------------- /include/GenerateStickyChannelsCommand.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | /** 10 | * Maya Plugin class for the GenerateStickyChannels command 11 | */ 12 | class GenerateStickyChannels : public MPxCommand { 13 | public: 14 | static const MString commandName; 15 | static void* creator(); 16 | 17 | public: 18 | GenerateStickyChannels(); 19 | ~GenerateStickyChannels(); 20 | MStatus doIt( const MArgList& args ); 21 | }; 22 | -------------------------------------------------------------------------------- /include/KrakatoaPluginDirectory.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | class KrakatoaPluginDirectory : public MPxCommand { 10 | public: 11 | static const MString commandName; 12 | static void* creator(); 13 | 14 | static void setPluginPath( const MString& path ); 15 | static const MString getPluginPath(); 16 | 17 | private: 18 | static MString s_pluginPath; 19 | 20 | public: 21 | MStatus doIt( const MArgList& args ); 22 | }; 23 | -------------------------------------------------------------------------------- /src/KrakatoaVersionCommand.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | 5 | #include "KrakatoaVersionCommand.hpp" 6 | 7 | #include "../KrakatoaVersion.h" 8 | 9 | const MString KrakatoaVersionCommand::commandName = "krakatoaGetVersion"; 10 | 11 | KrakatoaVersionCommand::KrakatoaVersionCommand() {} 12 | 13 | KrakatoaVersionCommand::~KrakatoaVersionCommand() {} 14 | 15 | void* KrakatoaVersionCommand::creator() { return new KrakatoaVersionCommand(); } 16 | 17 | MStatus KrakatoaVersionCommand::doIt( const MArgList& args ) { 18 | MString result = FRANTIC_VERSION; 19 | 20 | setResult( result ); 21 | 22 | return MStatus::kSuccess; 23 | } -------------------------------------------------------------------------------- /include/maya_frame_buffer_interface.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | #include 7 | /** 8 | * Krakatoa SR frame buffer callback for maya 9 | */ 10 | class maya_frame_buffer_interface : public krakatoasr::frame_buffer_interface { 11 | private: 12 | frantic::strings::tstring m_cameraName; 13 | 14 | public: 15 | maya_frame_buffer_interface(); 16 | ~maya_frame_buffer_interface(); 17 | void set_camera_name( frantic::strings::tstring cameraName ); 18 | 19 | virtual void set_frame_buffer( int width, int height, const krakatoasr::frame_buffer_pixel_data* data ); 20 | }; 21 | -------------------------------------------------------------------------------- /include/KrakatoaParticleJitter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include 4 | #include 5 | #include 6 | 7 | class krakatoaParticleJitter : public MPxCommand { 8 | public: 9 | static const MString commandName; 10 | static void* creator(); 11 | static void setPluginPath( const MString& path ); 12 | static const MString getPluginPath(); 13 | static MSyntax newSyntax(); 14 | 15 | /*static const char *randomFlag; 16 | static const char *randomLongFlag; 17 | static const char *radiusFlag; 18 | static const char *radiusLongFlag; 19 | static const char *nodeFlag; 20 | static const char *nodeLongFlag;*/ 21 | 22 | private: 23 | static MString s_pluginPath; 24 | 25 | public: 26 | MStatus doIt( const MArgList& args ); 27 | }; 28 | -------------------------------------------------------------------------------- /src/KrakatoaPluginDirectory.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | 5 | #include "KrakatoaPluginDirectory.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | const MString KrakatoaPluginDirectory::commandName = "KrakatoaPluginDirectory"; 15 | MString KrakatoaPluginDirectory::s_pluginPath; 16 | 17 | void* KrakatoaPluginDirectory::creator() { return new KrakatoaPluginDirectory; } 18 | 19 | void KrakatoaPluginDirectory::setPluginPath( const MString& path ) { s_pluginPath = path; } 20 | 21 | const MString KrakatoaPluginDirectory::getPluginPath() { return s_pluginPath; } 22 | 23 | MStatus KrakatoaPluginDirectory::doIt( const MArgList& args ) { 24 | setResult( s_pluginPath ); 25 | return MStatus::kSuccess; 26 | } 27 | -------------------------------------------------------------------------------- /version_gen.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | import argparse 4 | 5 | def write_version_file(version: str, filename: str='KrakatoaVersion.h') -> None: 6 | major, minor, patch = version.split('.') 7 | with open(filename, 'w') as version_header: 8 | version_header.write('#pragma once\n') 9 | version_header.write('/////////////////////////////////////////////////////\n') 10 | version_header.write('// AWS Thinkbox auto generated version include file.\n') 11 | version_header.write(f'#define FRANTIC_VERSION\t\t\t\t"{version}"\n') 12 | version_header.write(f'#define FRANTIC_MAJOR_VERSION\t\t"{major}"\n') 13 | version_header.write(f'#define FRANTIC_MINOR_VERSION\t\t"{minor}"\n') 14 | version_header.write(f'#define FRANTIC_PATCH_NUMBER\t\t"{patch}"\n') 15 | version_header.write(f'#define FRANTIC_DESCRIPTION\t\t\t"Thinkbox Krakatoa for Maya"\n') 16 | 17 | 18 | if __name__ == '__main__': 19 | parser = argparse.ArgumentParser() 20 | parser.add_argument(dest='version', required=True, help='The version number to use.') 21 | args = parser.parse_args() 22 | write_version_file(args.version) 23 | -------------------------------------------------------------------------------- /include/maya_progress_bar_interface.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | 7 | #include 8 | 9 | /** 10 | * Krakatoa SR progress bar callback for maya 11 | * Unfortunately, this is actually 90% calls to mel's 'progressBar' procedure, since there 12 | * seems to be no C++ api for the maya progress bar. Someone please correct me if I'm wrong. 13 | */ 14 | class maya_progress_bar_interface : public krakatoasr::progress_logger_interface, 15 | public krakatoasr::cancel_render_interface { 16 | public: 17 | maya_progress_bar_interface(); 18 | ~maya_progress_bar_interface(); 19 | 20 | virtual bool is_cancelled(); 21 | 22 | virtual void set_title( const char* title ); 23 | virtual void set_progress( float progress ); 24 | 25 | void set_num_frames( int numFrames ); 26 | void set_current_frame( int currentFrame ); 27 | 28 | void begin_display(); 29 | void end_display(); 30 | 31 | void reset_state(); 32 | 33 | private: 34 | void set_progress_min_max(); 35 | 36 | int m_numFrames; 37 | int m_currentFrame; 38 | frantic::tstring m_title; 39 | bool m_displayStarted; 40 | }; 41 | -------------------------------------------------------------------------------- /scripts/KrakatoaNoticesDialog.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | import maya.cmds as cmds 4 | import os 5 | 6 | kmyNoticesWindowId = 'kmyNoticesDlg' 7 | kmyNoticesText = None 8 | kmyNoticesError = "Could not read third_party_licenses.txt" 9 | 10 | def open_kmy_notices_dialog(): 11 | global kmyNoticesWindowId 12 | global kmyNoticesText 13 | global kmyNoticesError 14 | 15 | if cmds.window( kmyNoticesWindowId, exists=True ): 16 | cmds.deleteUI( kmyNoticesWindowId ) 17 | 18 | if kmyNoticesText == None or kmyNoticesText == kmyNoticesError : 19 | noticesPath = os.path.join( os.path.dirname( __file__ ), '..', '..', 'Legal', 'third_party_licenses.txt' ) 20 | try: 21 | with open( noticesPath, 'r' ) as theFile: 22 | kmyNoticesText = theFile.read() 23 | except IOError: 24 | kmyNoticesText = kmyNoticesError 25 | 26 | cmds.window( kmyNoticesWindowId, title="Krakatoa MY Notices", width=516 ) 27 | 28 | cmds.formLayout( "resizeForm" ) 29 | 30 | sf = cmds.scrollField( wordWrap=True, text=kmyNoticesText, editable=False ) 31 | 32 | cmds.formLayout( "resizeForm", edit=True, attachForm=[( sf, 'top', 0 ), ( sf, 'right', 0 ), ( sf, 'left', 0 ), ( sf, 'bottom', 0 )] ) 33 | 34 | cmds.setParent( '..' ) 35 | 36 | cmds.showWindow() -------------------------------------------------------------------------------- /include/KrakatoaRender.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | class KrakatoaRender : public MPxCommand { 10 | public: 11 | static const MString commandName; 12 | static void* creator(); 13 | 14 | public: 15 | MStatus doIt( const MArgList& args ); 16 | }; 17 | 18 | class KrakatoaBatchRender : public MPxCommand { 19 | public: 20 | static const MString commandName; 21 | static void* creator(); 22 | 23 | public: 24 | MStatus doIt( const MArgList& args ); 25 | }; 26 | 27 | class KrakatoaLocalBatchRenderOptionsString : public MPxCommand { 28 | public: 29 | static const MString commandName; 30 | static void* creator(); 31 | 32 | public: 33 | MStatus doIt( const MArgList& args ); 34 | }; 35 | 36 | class KrakatoaLocalBatchRender : public MPxCommand { 37 | public: 38 | static const MString commandName; 39 | static void* creator(); 40 | static bool isLocalBatchRender(); 41 | 42 | public: 43 | MStatus doIt( const MArgList& args ); 44 | 45 | private: 46 | static bool s_flaggedAsLocalBatchRender; 47 | }; 48 | 49 | class RenderCommandListener : public MPxCommand { 50 | public: 51 | static const MString commandName; 52 | static void* creator(); 53 | 54 | public: 55 | MStatus doIt( const MArgList& args ); 56 | }; 57 | -------------------------------------------------------------------------------- /scripts/AEPRTMayaParticleTemplate.mel: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //////////////////////////////////// 4 | // Attribute Editor Template for the Maya Particles Wrapper Node 5 | // 6 | // Written By: Matthew Yu 7 | // Thinkbox Software Inc. 8 | // 2013 9 | /////////////////////////////////// 10 | 11 | global proc AEPRTMayaParticleTemplate( string $nodeName ) { 12 | 13 | editorTemplate -beginScrollLayout; 14 | 15 | editorTemplate -beginLayout "Particles" -collapse false; 16 | gridLayout -nc 2; 17 | editorTemplate -callCustom "KrakatoaPRTMayaParticleSelectButton" "KrakatoaPRTMayaParticleUpdateButton" "inParticles"; 18 | setParent ..; 19 | editorTemplate -endLayout; 20 | 21 | // To Suppress 22 | string $toSuppress[] = { /*"caching", "nodeState"*/ }; 23 | 24 | // manually supress each such item 25 | for ($value in $toSuppress) 26 | editorTemplate -suppress $value; 27 | 28 | editorTemplate -addExtraControls; 29 | 30 | editorTemplate -endScrollLayout; 31 | } 32 | 33 | global proc KrakatoaPRTMayaParticleSelectButton ( string $node ) 34 | { 35 | button -label "Select Particle System" SelectParticleButton; 36 | KrakatoaPRTMayaParticleUpdateButton $node; 37 | } 38 | 39 | global proc KrakatoaPRTMayaParticleUpdateButton (string $node ) 40 | { 41 | string $buffer[]; 42 | tokenize $node "." $buffer; 43 | string $command = 44 | "string $prtnode = \"" + $buffer[0] + "\";\n" + 45 | "string $mayaprt = `KMY_getMayaParticleFromPRTMayaParticle $prtnode`;\n" + 46 | "select -r $mayaprt;\n"; 47 | button -e -c $command SelectParticleButton; 48 | } 49 | -------------------------------------------------------------------------------- /scripts/AEPRTMagmaTemplate.mel: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //////////////////////////////////// 4 | // Attribute Editor Template for the Magma Node 5 | // 6 | // Written By: Matthew Yu 7 | // Thinkbox Software Inc. 8 | // 2013 9 | /////////////////////////////////// 10 | 11 | global proc AEPRTMagmaTemplate( string $nodeName ) { 12 | 13 | editorTemplate -beginScrollLayout; 14 | 15 | editorTemplate -beginLayout "Magma" -collapse false; 16 | editorTemplate -label "Enabled" -addControl "inEnabled"; 17 | 18 | //Magma Editor is supported for MAYA_VERSION > 2011 19 | float $version = `getApplicationVersionAsFloat`; 20 | if( $version > 2011 ) 21 | { 22 | gridLayout -nc 2; 23 | editorTemplate -callCustom "KrakatoaPRTMagmaMakeMagmaFluxButton" "KrakatoaPRTMagmaUpdateMagmaFluxButton" "magmaflux"; 24 | setParent ..; 25 | } 26 | editorTemplate -endLayout; 27 | 28 | // To Suppress 29 | string $toSuppress[] = { /*"caching", "nodeState",*/ "inMayaMagma" }; 30 | 31 | // manually supress each such item 32 | for ($value in $toSuppress) 33 | editorTemplate -suppress $value; 34 | 35 | editorTemplate -addExtraControls; 36 | 37 | editorTemplate -endScrollLayout; 38 | } 39 | 40 | global proc KrakatoaPRTMagmaMakeMagmaFluxButton ( string $node ) 41 | { 42 | button -label "Open Magma Editor..." LoadMagmaFLUXButton; 43 | 44 | KrakatoaPRTMagmaUpdateMagmaFluxButton $node; 45 | } 46 | 47 | global proc KrakatoaPRTMagmaUpdateMagmaFluxButton (string $node ) 48 | { 49 | string $buffer[]; 50 | tokenize $node "." $buffer; 51 | button -e -c ("OpenMagmaFLUXDialog " + $buffer[0]) LoadMagmaFLUXButton; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /stdafx.h: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | // stdafx.h : include file for standard system include files, 4 | // or project specific include files that are used frequently, but 5 | // are changed infrequently 6 | // 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | #ifdef WIN32 13 | 14 | // Including SDKDDKVer.h defines the highest available Windows platform. 15 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 16 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 17 | //#include 18 | // Specify a requirement for Win2K. See http://msdn.microsoft.com/en-us/library/aa383745(VS.85).aspx 19 | #define _WIN32_WINNT 0x0501 20 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 21 | #ifndef NOMINMAX 22 | #define NOMINMAX 23 | #endif 24 | 25 | // Windows Header Files: 26 | #include 27 | 28 | #endif 29 | 30 | // Common Maya headers 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | -------------------------------------------------------------------------------- /include/PRTObjectUI.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | class PRTObject; 16 | 17 | /** 18 | * User-Interface class to the PRTLoader, responsible for drawing and selection methods 19 | */ 20 | class PRTObjectUI : public MPxSurfaceShapeUI { 21 | public: 22 | static const MString drawClassification; 23 | 24 | static void* creator(); 25 | 26 | public: 27 | PRTObjectUI(); 28 | virtual ~PRTObjectUI(); 29 | 30 | virtual void getDrawRequests( const MDrawInfo& drawInfo, bool objectAndActiveOnly, MDrawRequestQueue& requests ); 31 | virtual void draw( const MDrawRequest& request, M3dView& view ) const; 32 | virtual bool select( MSelectInfo& selectInfo, MSelectionList& selectionList, 33 | MPointArray& worldSpaceSelectPts ) const; 34 | 35 | private: 36 | static const float s_smallPointSize; 37 | static const float s_largePointSize; 38 | 39 | private: 40 | void drawBoundingBox( const MDrawRequest& request, M3dView& view ) const; 41 | 42 | void drawParticles( const frantic::particles::particle_array& particles, bool useColorChannel, 43 | M3dView& view ) const; 44 | void drawPoints( const frantic::particles::particle_array& particles, float pointSize, M3dView& view ) const; 45 | void drawLines( const frantic::particles::particle_array& particles, 46 | const frantic::channels::channel_cvt_accessor& deltaAccessor, 47 | float scale, M3dView& view ) const; 48 | void drawRootGeometry( M3dView& view ) const; 49 | 50 | void enterMatrixTransform() const; 51 | void exitMatrixTransform() const; 52 | 53 | PRTObject* getPRTObject() const; 54 | }; 55 | -------------------------------------------------------------------------------- /include/maya_render_save_interface.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | class maya_render_save_interface : public krakatoasr::render_save_interface { 15 | public: 16 | maya_render_save_interface( const MFnDependencyNode& krakatoaSettingsNode, 17 | const MDGContext& currentContext = MDGContext::fsNormal, 18 | const frantic::tstring& cameraName = _T("") ); 19 | virtual ~maya_render_save_interface(); 20 | 21 | virtual void save_render_data( int width, int height, int imageCount, const krakatoasr::output_type_t* listOfTypes, 22 | const krakatoasr::frame_buffer_pixel_data* const* listOfImages ); 23 | 24 | void set_current_context( const MDGContext& currentContext ); 25 | void set_camera_name( const frantic::tstring& cameraName ); 26 | 27 | frantic::tstring get_output_image_name( const frantic::tstring& appendName = _T("") ); 28 | frantic::tstring get_output_image_extension(); 29 | 30 | krakatoasr::exr_compression_t get_exr_compression_type() const; 31 | krakatoasr::exr_bit_depth_t get_exr_bit_depth( const std::string& bitDepthName ) const; 32 | 33 | private: 34 | void save_velocity_image_data( int width, int height, const krakatoasr::frame_buffer_pixel_data* imageData ); 35 | void save_rgba_image_data( int width, int height, const krakatoasr::frame_buffer_pixel_data* imageData ); 36 | void save_depth_image_data( int width, int height, const krakatoasr::frame_buffer_pixel_data* imageData ); 37 | void save_normal_image_data( int width, int height, const krakatoasr::frame_buffer_pixel_data* imageData ); 38 | void save_occluded_image_data( int width, int height, const krakatoasr::frame_buffer_pixel_data* imageData ); 39 | 40 | MDGContext m_currentContext; 41 | frantic::tstring m_cameraName; 42 | MFnDependencyNode m_krakatoaSettings; 43 | }; 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KrakatoaMY 2 | 3 | ## Overview 4 | 5 | KrakatoaMY is a Maya plugin that enables using the Krakatoa renderer in Autodesk Maya. 6 | 7 | The official documentation for the plugin can be found [here](https://docs.thinkboxsoftware.com/products/krakatoa/2.12/1_Documentation/manual/kmy/index.html). 8 | 9 | ## Table of Contents 10 | 11 | - [Reporting Bugs/Feature Requests](#reporting-bugs/feature-requests) 12 | - [Security issue notifications](#security-issue-notifications) 13 | - [Contributing](#contributing) 14 | - [Code of Conduct](#code-of-conduct) 15 | - [Licensing](#licensing) 16 | 17 | ## Reporting Bugs/Feature Requests 18 | 19 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 20 | 21 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 22 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 23 | 24 | - A reproducible test case or series of steps 25 | - The version of our code being used 26 | - Any modifications you've made relevant to the bug 27 | - Anything unusual about your environment or deployment 28 | 29 | ## Security issue notifications 30 | 31 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 32 | 33 | ## Contributing 34 | 35 | Contributions to KrakatoaMY are encouraged. If you want to fix a problem, or want to enhance the library in any way, then 36 | we are happy to accept your contribution. Information on contributing to KrakatoaMY can be found 37 | [in CONTRIBUTING.md](CONTRIBUTING.md). 38 | 39 | ## Code of Conduct 40 | 41 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 42 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 43 | opensource-codeofconduct@amazon.com with any additional questions or comments. 44 | 45 | ## Licensing 46 | 47 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 48 | 49 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 50 | -------------------------------------------------------------------------------- /src/maya_frame_buffer_interface.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | 5 | #include "maya_frame_buffer_interface.hpp" 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace krakatoasr; 18 | 19 | maya_frame_buffer_interface::maya_frame_buffer_interface() { m_cameraName = _T(""); } 20 | 21 | maya_frame_buffer_interface::~maya_frame_buffer_interface() {} 22 | void maya_frame_buffer_interface::set_camera_name( frantic::strings::tstring cameraName ) { m_cameraName = cameraName; } 23 | 24 | void maya_frame_buffer_interface::set_frame_buffer( int width, int height, const frame_buffer_pixel_data* data ) { 25 | MStatus status; 26 | bool output = false; 27 | if( MRenderView::doesRenderEditorExist() ) { 28 | if( m_cameraName.empty() ) { 29 | M3dView curView = M3dView::active3dView(); 30 | MDagPath camDagPath; 31 | curView.getCamera( camDagPath ); 32 | MRenderView::setCurrentCamera( camDagPath ); 33 | } else { 34 | MSelectionList list; 35 | MGlobal::getSelectionListByName( MString( m_cameraName.c_str() ), list ); 36 | MDagPath camDagPath; 37 | list.getDagPath( 0, camDagPath ); 38 | MRenderView::setCurrentCamera( camDagPath ); 39 | } 40 | 41 | // copy our entire buffer into a Maya buffer 42 | // we can do it pixel-by-pixel calls to "updatePixels" to save memory too, but updating as one big block seems 43 | // to be a tiny bit faster. 44 | std::vector pixelBlock( width * height ); 45 | for( int i = 0; i < width * height; ++i ) { 46 | const frame_buffer_pixel_data& srcPixel = data[i]; 47 | RV_PIXEL& destPixel = pixelBlock[i]; 48 | destPixel.r = srcPixel.r; 49 | destPixel.g = srcPixel.g; 50 | destPixel.b = srcPixel.b; 51 | destPixel.a = ( ( srcPixel.r_alpha + srcPixel.g_alpha + srcPixel.b_alpha ) / 3.0f ); 52 | } 53 | 54 | // give the frame buffer memory to maya. 55 | MRenderView::startRender( width, height, true, false ); 56 | MRenderView::updatePixels( 0, width - 1, 0, height - 1, &pixelBlock[0], true ); 57 | MRenderView::endRender(); 58 | 59 | } else { 60 | FF_LOG( stats ) << "Krakatoa MY: Unable to create maya render viewer." << std::endl; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /include/PRTModifiers.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | class PRTModifiers : public MPxNode, public frantic::maya::PRTObjectBase { 14 | public: 15 | // Maya rtti and object creation information 16 | static void* creator(); 17 | static MStatus initialize(); 18 | 19 | static const MTypeId id; 20 | static const MString typeName; 21 | 22 | private: 23 | // Input particles to be modified 24 | static MObject inParticleStream; 25 | 26 | // Output particles 27 | static MObject outParticleStream; 28 | 29 | // Enabled 30 | static MObject inEnabled; 31 | 32 | // Params 33 | static MObject inModifiersMethod; 34 | 35 | static MObject inModifiersName; 36 | 37 | // Set Channel Vec3, Set Channel, Scale Channel, Copy Channel 38 | // static MObject inChannelDestination; 39 | // static MObject inChannelSource; 40 | // static MObject inChannelValue; 41 | // static MObject inChannelValueVec3; 42 | 43 | // Copy Channel 44 | static MObject inCopyFull; 45 | 46 | // Repopulate 47 | 48 | // Texture 49 | 50 | public: 51 | PRTModifiers(); 52 | virtual ~PRTModifiers(); 53 | virtual void postConstructor(); 54 | virtual MStatus compute( const MPlug& plug, MDataBlock& block ); 55 | 56 | // inherited from base 57 | frantic::maya::PRTObjectBase::particle_istream_ptr 58 | getParticleStream( const frantic::graphics::transform4f& objectSpace, const MDGContext& context, 59 | bool isViewport ) const; 60 | 61 | virtual frantic::maya::PRTObjectBase::particle_istream_ptr 62 | getRenderParticleStream( const frantic::graphics::transform4f& objectSpace, const MDGContext& context ) const { 63 | return getParticleStream( objectSpace, context, false ); 64 | } 65 | 66 | virtual frantic::maya::PRTObjectBase::particle_istream_ptr 67 | getViewportParticleStream( const frantic::graphics::transform4f& objectSpace, const MDGContext& context ) const { 68 | return getParticleStream( objectSpace, context, true ); 69 | } 70 | 71 | bool isEnabled( const MDGContext& context = MDGContext::fsNormal ) const; 72 | 73 | int getModifierMethod( MString& outName, const MDGContext& context = MDGContext::fsNormal ) const; 74 | 75 | private: 76 | frantic::particles::streams::particle_istream_ptr 77 | apply_channel_modifiers( const MDGContext& context, bool inViewport, 78 | frantic::particles::streams::particle_istream_ptr inputParticles ) const; 79 | }; 80 | -------------------------------------------------------------------------------- /scripts/KrakatoaInit.mel: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //////////////////////////////////// 4 | // Maya Krakatoa Renderer Creation Script 5 | // 6 | // Written By: Conrad Wiebe, Stephen Kiazyk 7 | // Thinkbox Software Inc. 8 | // 2013 9 | /////////////////////////////////// 10 | 11 | source "KrakatoaRenderer.mel"; 12 | source "KMY2PRT_Saver.mel"; 13 | source "KrakatoaModifiers.mel"; 14 | source "KrakatoaModEditor.mel"; 15 | source "KrakatoaMagma.mel"; 16 | 17 | global proc RunKrakatoaRender(int $width, int $height, int $doShadow, int $doGlow, string $camera, string $options) 18 | { 19 | // ensure that the krakatoa render settings node exists before trying to render 20 | CreateKrakatoaSettingsNode(); 21 | int $results = `KrakatoaRender -cam $camera`; 22 | } 23 | 24 | global proc RunKrakatoaBatchRender(string $options) 25 | { 26 | // ensure krakatoa is loaded before trying to run the batch render 27 | if (!`pluginInfo -q -l "MayaKrakatoa"`) 28 | { 29 | loadPlugin "MayaKrakatoa"; 30 | } 31 | 32 | CreateKrakatoaSettingsNode(); 33 | KrakatoaBatchRender(); 34 | } 35 | 36 | global proc RunKrakatoaBatchRenderOptions() 37 | { 38 | window -title "Batch Render Frame" batchRenderWindow; 39 | rowLayout 40 | -numberOfColumns 3 41 | -columnWidth3 120 120 120 42 | -columnAlign3 "center" "center" "center"; 43 | 44 | button -label "Batch render and close" -width 120 -command "mayaBatchRender; deleteUI batchRenderWindow"; 45 | button -label "Batch render" -width 120 -command "mayaBatchRender"; 46 | button -label "Close" -width 120 -command "deleteUI batchRenderWindow"; 47 | showWindow batchRenderWindow; 48 | } 49 | 50 | global proc createKrakatoaRenderSettingsTab() 51 | { 52 | string $parent = `setParent -query`; 53 | string $child = `createKrakatoaRenderSettingsUI`; 54 | formLayout -edit -af $child "top" 5 -af $child "bottom" 0 -af $child "left" 0 -af $child "right" 0 $parent; 55 | } 56 | 57 | global proc updateKrakatoaRenderSettingsTab() 58 | { 59 | print "This is actually never ever called, so it doesn't matter what you put in here\n"; 60 | } 61 | 62 | // ENTRY POINT 63 | // This is where we actually register the krakatoa renderer to Maya 64 | 65 | renderer -rendererUIName "Krakatoa" 66 | -renderProcedure RunKrakatoaRender 67 | -batchRenderProcedure RunKrakatoaBatchRender 68 | -batchRenderOptionsProcedure RunKrakatoaBatchRenderOptions 69 | -commandRenderProcedure RunKrakatoaBatchRender 70 | -batchRenderOptionsStringProcedure KrakatoaLocalBatchRenderOptionsString 71 | -cancelBatchRenderProcedure "batchRender" //This calls maya softwares default cancel call which kills the process o the batch render 72 | MayaKrakatoa; 73 | 74 | // This is a hack to get around Maya not loading a function that it expects to call every time the 75 | // renderer tab is changed, whether we're using it or not 76 | if (!`exists "updateMayaImageFormatControl"`) 77 | { 78 | source "others/createMayaSoftwareCommonGlobalsTab.mel"; 79 | } 80 | 81 | renderer -edit -addGlobalsTab "Common" createMayaSoftwareCommonGlobalsTab updateMayaSoftwareCommonGlobalsTab MayaKrakatoa; 82 | renderer -edit -addGlobalsTab "Krakatoa Settings" createKrakatoaRenderSettingsTab updateKrakatoaRenderSettingsTab MayaKrakatoa; 83 | 84 | // Add a "Open scene" callback. this will provide attribute update callbacks for our modifier system. 85 | scriptJob -e "SceneOpened" "KMYMOD_addModifierCallbackForAllSceneItems()"; 86 | -------------------------------------------------------------------------------- /include/PRTObject.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class PRTObject : public MPxSurfaceShape, public frantic::maya::PRTObjectBase { 14 | public: 15 | enum display_mode_t { 16 | DISPLAYMODE_DOT1 = 1, 17 | DISPLAYMODE_DOT2, 18 | DISPLAYMODE_VELOCITY, 19 | DISPLAYMODE_NORMAL, 20 | DISPLAYMODE_TANGENT 21 | }; 22 | 23 | public: 24 | virtual ~PRTObject(); 25 | 26 | // inherited from MPxNode 27 | virtual void postConstructor(); 28 | 29 | /** 30 | * Gets a transform for this PRTObject. 31 | * This is used for viewport caching purposes only. Use the one that takes in a MDagPath to get the proper 32 | * transform 33 | */ 34 | virtual frantic::graphics::transform4f getTransform( const MDGContext& context ) const; 35 | 36 | /** 37 | * Returns a cached particle_array of the particle set suitable for displaying in the viewport. 38 | * This will only be re-computed if the current scene context changes. 39 | */ 40 | virtual frantic::particles::particle_array* getCachedViewportParticles() = 0; 41 | 42 | /** 43 | * Specifies the display mode to use when drawing the particles in the viewport. Ensure that the appropriately 44 | * named channel exists corresponding to the returned display mode. 45 | */ 46 | virtual display_mode_t getViewportDisplayMode() = 0; 47 | 48 | /** 49 | * Returns the root display mesh to show under this object in the scene 50 | * @return a const reference to the root display trimesh 51 | */ 52 | virtual const frantic::geometry::trimesh3& getRootMesh() const; 53 | 54 | #if MAYA_API_VERSION >= 201600 55 | /** 56 | * Returns a selection mask for Viewport 2.0 Selection 57 | */ 58 | virtual MSelectionMask getShapeSelectionMask() const; 59 | #endif 60 | 61 | /** 62 | * For Viewport 2.0, this registers an attribute that will require the viewport to redraw. For Viewport 1.0, this 63 | * will set the attribute so that it will affect the affected object(ie an update to attribute will cause and update 64 | * to affected). 65 | */ 66 | static void register_viewport_dependency( boost::unordered_set& registry, MObject& attr, 67 | MObject& affected ); 68 | 69 | /** 70 | * Viewport 2.0 code, which checks if an element requires the viewport to be redrawn. 71 | */ 72 | static void check_dependents_dirty( boost::unordered_set& registry, const MPlug& attr, 73 | MObject& toUpdates ); 74 | 75 | /** 76 | * TOTAL HACK FOR BECAUSE FOR VIEWPORT 2.0 UPDATING ON OS X 77 | * On OS X, the function "setDependentsDirty" never seems to be called, therefore, the neccessary 78 | * "MHWRender::MRenderer::setGeometryDrawDirty" function is not called to alert viewport 2.0 that it needs to 79 | * update. So instead, we're registering a scriptJob each time to run this Mel script command to force it to update. 80 | * We should think of removing this if it is fixed, or the problem source is found. Check again if it's still a 81 | * problem in Maya 2016+. 82 | */ 83 | static void 84 | register_osx_viewport20_update_hack( MString objName, 85 | const boost::unordered_set& viewportInputDependencies ); 86 | }; 87 | -------------------------------------------------------------------------------- /src/maya_progress_bar_interface.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | 5 | #include "maya_progress_bar_interface.hpp" 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace { 14 | std::string escape_mel_string( const std::string& inString ) { 15 | std::string resultString( inString ); 16 | size_t currentPos = 0; 17 | 18 | while( currentPos < resultString.length() ) { 19 | currentPos = resultString.find_first_of( '\"', currentPos ); 20 | 21 | if( currentPos == std::string::npos ) { 22 | break; 23 | } else { 24 | resultString.replace( currentPos, 1, "\\\"" ); 25 | currentPos += 2; 26 | } 27 | } 28 | 29 | return "\"" + resultString + "\""; 30 | } 31 | } // namespace 32 | 33 | maya_progress_bar_interface::maya_progress_bar_interface() { reset_state(); } 34 | 35 | maya_progress_bar_interface::~maya_progress_bar_interface() { 36 | if( m_displayStarted ) { 37 | end_display(); 38 | } 39 | } 40 | 41 | bool maya_progress_bar_interface::is_cancelled() { 42 | if( m_displayStarted ) { 43 | std::ostringstream os; 44 | os << "progressBar -query -isCancelled $gMainProgressBar;"; 45 | int result; 46 | MGlobal::executeCommand( os.str().c_str(), result ); 47 | return result ? true : false; 48 | } 49 | 50 | return false; 51 | } 52 | 53 | void maya_progress_bar_interface::reset_state() { 54 | m_numFrames = 1; 55 | m_currentFrame = 0; 56 | m_displayStarted = false; 57 | } 58 | 59 | void maya_progress_bar_interface::set_title( const char* title ) { 60 | if( m_displayStarted ) { 61 | std::ostringstream os; 62 | os << "progressBar -edit -status " << escape_mel_string( title ) << " $gMainProgressBar;"; 63 | MGlobal::executeCommand( os.str().c_str() ); 64 | } 65 | } 66 | 67 | void maya_progress_bar_interface::set_progress( float progress ) { 68 | if( m_displayStarted ) { 69 | std::ostringstream os; 70 | os << "progressBar -edit -progress " << int( ( m_currentFrame + progress ) * 100.0f ) << " $gMainProgressBar;"; 71 | MGlobal::executeCommand( os.str().c_str() ); 72 | } 73 | } 74 | 75 | void maya_progress_bar_interface::set_num_frames( int numFrames ) { 76 | if( numFrames > 0 && numFrames != m_numFrames ) { 77 | m_numFrames = numFrames; 78 | set_progress_min_max(); 79 | 80 | if( m_currentFrame >= m_numFrames ) { 81 | set_current_frame( m_numFrames - 1 ); 82 | } 83 | } 84 | } 85 | 86 | void maya_progress_bar_interface::set_current_frame( int currentFrame ) { 87 | if( currentFrame >= 0 && currentFrame < m_numFrames && currentFrame != m_currentFrame ) { 88 | m_currentFrame = currentFrame; 89 | // I'm assuming that when setting the current frame, you also want to set the progress to the start of that 90 | // frame 91 | set_progress( 0.0f ); 92 | } 93 | } 94 | 95 | void maya_progress_bar_interface::begin_display() { 96 | if( !m_displayStarted ) { 97 | std::ostringstream os; 98 | os << "progressBar -edit -isInterruptable true -beginProgress $gMainProgressBar;"; 99 | MGlobal::executeCommand( os.str().c_str() ); 100 | m_displayStarted = true; 101 | set_progress( 0.0f ); 102 | } 103 | } 104 | 105 | void maya_progress_bar_interface::end_display() { 106 | if( m_displayStarted ) { 107 | std::ostringstream os; 108 | os << "progressBar -edit -endProgress $gMainProgressBar;"; 109 | MGlobal::executeCommand( os.str().c_str() ); 110 | set_progress_min_max(); 111 | m_displayStarted = false; 112 | } 113 | } 114 | 115 | void maya_progress_bar_interface::set_progress_min_max() { 116 | std::ostringstream os; 117 | os << "progressBar -edit -minValue " << 0 << " -maxValue " << m_numFrames * 100 << " $gMainProgressBar;"; 118 | MGlobal::executeCommand( os.str().c_str() ); 119 | } 120 | -------------------------------------------------------------------------------- /src/PRTObject.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | 5 | #include "PRTIconMesh.hpp" 6 | #include "PRTObject.hpp" 7 | 8 | #include 9 | #if MAYA_API_VERSION >= 201400 10 | #include 11 | #include 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include 23 | 24 | using namespace frantic::maya; 25 | 26 | frantic::graphics::transform4f PRTObject::getTransform( const MDGContext& context ) const { 27 | MStatus stat; 28 | 29 | MFnDagNode dagNode( this->thisMObject(), &stat ); 30 | if( stat == MS::kSuccess ) { 31 | MDagPathArray dagNodePathArray; 32 | dagNode.getAllPaths( dagNodePathArray ); 33 | 34 | // iterate through all the paths get the transform from the first path that has it 35 | frantic::graphics::transform4f result; 36 | for( unsigned int i = 0; i < dagNodePathArray.length(); i++ ) { 37 | if( maya_util::get_object_world_matrix( dagNodePathArray[i], context, result ) ) 38 | return result; 39 | } 40 | } 41 | 42 | frantic::graphics::transform4f emptyTrans; 43 | return emptyTrans; 44 | } 45 | 46 | const frantic::geometry::trimesh3& PRTObject::getRootMesh() const { return get_default_icon_mesh(); } 47 | 48 | #if MAYA_API_VERSION >= 201600 49 | MSelectionMask PRTObject::getShapeSelectionMask() const { 50 | MSelectionMask::SelectionType selType = MSelectionMask::kSelectObjectsMask; 51 | return MSelectionMask( selType ); 52 | } 53 | #endif 54 | 55 | void render_end_callback( MHWRender::MDrawContext& context, void* clientData ) { 56 | MHWRender::MRenderer::disableChangeManagementUntilNextRefresh(); 57 | } 58 | 59 | void PRTObject::postConstructor() { 60 | MPxSurfaceShape::postConstructor(); 61 | 62 | // Setup Viewport 2.0 rendering callback 63 | MHWRender::MRenderer* renderer = MHWRender::MRenderer::theRenderer( false ); 64 | if( renderer && renderer->drawAPI() != MHWRender::kNone ) { 65 | renderer->addNotification( &render_end_callback, "PRTObjectRenderEndCallback", 66 | MHWRender::MPassContext::kEndRenderSemantic, NULL ); 67 | } 68 | } 69 | 70 | PRTObject::~PRTObject() {} 71 | 72 | void PRTObject::register_viewport_dependency( boost::unordered_set& registry, MObject& attr, 73 | MObject& affected ) { 74 | attributeAffects( attr, affected ); 75 | registry.insert( std::string( MFnAttribute( attr ).name().asChar() ) ); 76 | } 77 | 78 | void PRTObject::check_dependents_dirty( boost::unordered_set& registry, const MPlug& attr, 79 | MObject& toUpdate ) { 80 | // for viewport 2.0. calling the "setGeometryDrawDirty" function. 81 | #if MAYA_API_VERSION >= 201400 82 | boost::unordered_set::const_iterator elemIter = 83 | registry.find( std::string( MFnAttribute( attr ).name().asChar() ) ); 84 | 85 | if( elemIter != registry.end() ) { 86 | MHWRender::MRenderer::setGeometryDrawDirty( toUpdate ); 87 | } 88 | #endif 89 | } 90 | 91 | void PRTObject::register_osx_viewport20_update_hack( 92 | MString objName, const boost::unordered_set& viewportInputDependencies ) { 93 | #ifdef __APPLE__ 94 | #if MAYA_API_VERSION >= 201400 95 | // Viewport 2.0 Hack for OS X. See comment in PRTObjectUIGeometryOverride.hpp. 96 | // For some reason I can't do this in "postConstructor" because this->name() returns an empty string at that point. 97 | std::string objNameStr = objName.asChar(); 98 | boost::unordered_set::const_iterator iter, iterEnd = viewportInputDependencies.end(); 99 | for( iter = viewportInputDependencies.begin(); iter != iterEnd; ++iter ) { 100 | std::string attrName = *iter; 101 | if( !attrName.empty() ) { 102 | // The MEL script we execute looks something like this: 103 | // scriptJob -kws -ac "PRTFractal1.inFractalRandomSeed" "ForceViewport20Update \"PRTFractal1\""; 104 | // What this does is calls our own "ForceViewport20Update" function whenever the attribute specified 105 | // changes. What our "ForceViewport20Update" function does is manually call 106 | // "MHWRender::MRenderer::setGeometryDrawDirty" on our node. I wish there was a way to do this without the 107 | // MEL intermediate. However, our proper "setDependentsDirty" function doesn't appear to ever be called 108 | // under OS X. 109 | std::string melCommand = "scriptJob -kws -ac \"" + objNameStr + "." + attrName + 110 | "\" \"ForceViewport20Update \\\"" + objNameStr + "\\\"\";"; 111 | MGlobal::executeCommand( melCommand.c_str() ); 112 | } 113 | } 114 | #endif 115 | #endif 116 | } 117 | -------------------------------------------------------------------------------- /src/GenerateStickyChannelsCommand.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | 5 | #include "GenerateStickyChannelsCommand.hpp" 6 | 7 | #include 8 | 9 | const MString GenerateStickyChannels::commandName = "GenerateStickyChannels"; 10 | 11 | void* GenerateStickyChannels::creator() { return new GenerateStickyChannels; } 12 | 13 | GenerateStickyChannels::GenerateStickyChannels() {} 14 | 15 | GenerateStickyChannels::~GenerateStickyChannels() {} 16 | 17 | MStatus GenerateStickyChannels::doIt( const MArgList& args ) { 18 | try { 19 | // error check the input 20 | const int numExpectedArgs = 9; 21 | if( args.length() < numExpectedArgs ) { 22 | MGlobal::displayError( 23 | "Birth Channel Generator takes nine arguments. " 24 | "Argument one is the path to the input .prt file. " 25 | "Argument two is the path to the output .prt file. " 26 | "Argument 3 is the input channel. " 27 | "Argument 4 is the output channel. " 28 | "Argument 5 is the ID channel. " 29 | "Argument 6 is the startframe. " 30 | "Argument 7 is IgnoreError (bool). Set it as true to ignore per-frame errors and continue to next " 31 | "frame. " 32 | "Argument 8 is OverwriteChannel (bool). If true then existing birth channels will always be " 33 | "overwritten. If false then existing birth channels will never be overwritten. " 34 | "Argument 9 is OverwriteFile (bool). If true then any exsting PRT files will always be overwritten. If " 35 | "false then existing files will never be overwritten." ); 36 | return MStatus::kFailure; 37 | } 38 | 39 | // get the parameters 40 | MStatus status; 41 | birth_channel_gen::options opts; 42 | 43 | MString inSequence( args.asString( 0, &status ) ); 44 | if( status != MStatus::kSuccess ) { 45 | MGlobal::displayError( "First input must be a string" ); 46 | return MStatus::kFailure; 47 | } 48 | MString outSequence( args.asString( 1, &status ) ); 49 | if( status != MStatus::kSuccess ) { 50 | MGlobal::displayError( "Second input must be a string" ); 51 | return MStatus::kFailure; 52 | } 53 | MString inChannel( args.asString( 2, &status ) ); 54 | if( status != MStatus::kSuccess ) { 55 | MGlobal::displayError( "Third input must be a string" ); 56 | return MStatus::kFailure; 57 | } 58 | MString outChannel( args.asString( 3, &status ) ); 59 | if( status != MStatus::kSuccess ) { 60 | MGlobal::displayError( "Fourth input must be a string" ); 61 | return MStatus::kFailure; 62 | } 63 | MString idChannel( args.asString( 4, &status ) ); 64 | if( status != MStatus::kSuccess ) { 65 | MGlobal::displayError( "Fifth input must be a string" ); 66 | return MStatus::kFailure; 67 | } 68 | double startFrame = args.asDouble( 5, &status ); 69 | if( status != MStatus::kSuccess ) { 70 | MGlobal::displayError( "Sixth input must be a double" ); 71 | return MStatus::kFailure; 72 | } 73 | bool ignoreError = args.asBool( 6, &status ); 74 | if( status != MStatus::kSuccess ) { 75 | MGlobal::displayError( "Seventh input must be a bool" ); 76 | return MStatus::kFailure; 77 | } 78 | bool overwriteChannel = args.asBool( 7, &status ); 79 | if( status != MStatus::kSuccess ) { 80 | MGlobal::displayError( "Eighth input must be a bool" ); 81 | return MStatus::kFailure; 82 | } 83 | bool overwriteFile = args.asBool( 8, &status ); 84 | if( status != MStatus::kSuccess ) { 85 | MGlobal::displayError( "Ninth input must be a bool" ); 86 | return MStatus::kFailure; 87 | } 88 | 89 | opts.m_inSequence = frantic::strings::to_tstring( inSequence.asChar() ); 90 | opts.m_outSequence = frantic::strings::to_tstring( outSequence.asChar() ); 91 | opts.m_inChannel = frantic::strings::to_tstring( inChannel.asChar() ); 92 | opts.m_outChannel = frantic::strings::to_tstring( outChannel.asChar() ); 93 | opts.m_idChannel = frantic::strings::to_tstring( idChannel.asChar() ); 94 | opts.m_startFrame = startFrame; 95 | opts.m_ignoreError = ignoreError; 96 | if( overwriteChannel ) { 97 | opts.m_overwriteChannel = birth_channel_gen::scope_answer::yes_all; 98 | } else { 99 | opts.m_overwriteChannel = birth_channel_gen::scope_answer::no_all; 100 | } 101 | if( overwriteFile ) { 102 | opts.m_overwriteFile = birth_channel_gen::scope_answer::yes_all; 103 | } else { 104 | opts.m_overwriteFile = birth_channel_gen::scope_answer::no_all; 105 | } 106 | 107 | birth_channel_gen::generate_sticky_channels( opts ); 108 | } catch( const std::exception& e ) { 109 | MGlobal::displayError( e.what() ); 110 | return MStatus::kFailure; 111 | } 112 | 113 | return MStatus(); 114 | } 115 | -------------------------------------------------------------------------------- /include/KrakatoaRenderSettingsNode.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | #include 5 | class KrakatoaRenderSettingsNode : public MPxNode { 6 | public: 7 | static void* creator(); 8 | static MStatus initialize(); 9 | static MTypeId typeId; 10 | static MString typeName; 11 | 12 | KrakatoaRenderSettingsNode( void ); 13 | ~KrakatoaRenderSettingsNode( void ); 14 | 15 | private: 16 | static MObject inForceEXROutput; 17 | static MObject inEXRCompressionType; 18 | static MObject inEXRRgbaBitDepth; 19 | static MObject inEXRNormalBitDepth; 20 | static MObject inEXRVelocityBitDepth; 21 | static MObject inEXRZBitDepth; 22 | static MObject inEXROccludedBitDepth; 23 | 24 | static MObject inExportMayaParticles; 25 | static MObject inExportMayaHair; 26 | static MObject inExportPRTLoaders; 27 | static MObject inExportPRTVolumes; 28 | static MObject inExportPRTSurfaces; 29 | static MObject inExportPRTFractals; 30 | 31 | static MObject inOverrideBG; 32 | static MObject inBackgroundColor; 33 | static MObject inOverrideColor; 34 | static MObject inColorChannelOverride; 35 | static MObject inOverrideEmission; 36 | static MObject inEmissionChannelOverride; 37 | static MObject inOverrideAbsorption; 38 | static MObject inAbsorptionChannelOverride; 39 | static MObject inOverrideDensity; 40 | static MObject inDensityChannelOverride; 41 | 42 | static MObject inCopyChannel[]; 43 | static MObject inCopyChannelFrom[]; 44 | static MObject inCopyChannelTo[]; 45 | 46 | static MObject inSaveNormalPass; 47 | static MObject inSaveVelocityPass; 48 | static MObject inSaveZDepthPass; 49 | static MObject inSaveOccludedPass; 50 | 51 | static MObject inPhongSpecularPower; 52 | static MObject inPhongSpecularLevel; 53 | static MObject inUsePhongSpecularPower; 54 | static MObject inUsePhongSpecularLevel; 55 | 56 | static MObject inHgEccentricity; 57 | static MObject inUseHgEccentricity; 58 | 59 | static MObject inSchlickEccentricity; 60 | static MObject inUseSchlickEccentricity; 61 | 62 | static MObject inKkSpecularPower; 63 | static MObject inKkSpecularLevel; 64 | static MObject inUseKkSpecularPower; 65 | static MObject inUseKkSpecularLevel; 66 | 67 | static MObject inMarschnerSpecularLevel; 68 | static MObject inMarschnerSpecular2Level; 69 | static MObject inMarschnerSpecularGlossiness; 70 | static MObject inMarschnerSpecular2Glossiness; 71 | static MObject inMarschnerSpecularShift; 72 | static MObject inMarschnerSpecular2Shift; 73 | static MObject inMarschnerGlintLevel; 74 | static MObject inMarschnerGlintSize; 75 | static MObject inMarschnerGlintGlossiness; 76 | static MObject inMarschnerDiffuseLevel; 77 | static MObject inUseMarschnerSpecularLevel; 78 | static MObject inUseMarschnerSpecular2Level; 79 | static MObject inUseMarschnerSpecularGlossiness; 80 | static MObject inUseMarschnerSpecular2Glossiness; 81 | static MObject inUseMarschnerSpecularShift; 82 | static MObject inUseMarschnerSpecular2Shift; 83 | static MObject inUseMarschnerGlintLevel; 84 | static MObject inUseMarschnerGlintSize; 85 | static MObject inUseMarschnerGlintGlossiness; 86 | static MObject inUseMarschnerDiffuseLevel; 87 | 88 | static MObject inShadingMode; 89 | static MObject inRenderingMethod; 90 | static MObject inIgnoreSceneLights; 91 | static MObject inVoxelSize; 92 | static MObject inVoxelFilterRadius; 93 | static MObject inUseEmission; 94 | static MObject inUseAbsorption; 95 | static MObject inForceAdditiveMode; 96 | static MObject inLoadPercentage; 97 | 98 | static MObject inSelfShadowFilter; 99 | static MObject inDrawPointFilter; 100 | static MObject inLightingPassFilterSize; 101 | static MObject inFinalPassFilterSize; 102 | static MObject inLightingPassDensity; 103 | static MObject inFinalPassDensity; 104 | static MObject inLightingPassDensityExponent; 105 | static MObject inFinalPassDensityExponent; 106 | static MObject inUseLightingPassDensity; 107 | static MObject inEmissionStrength; 108 | static MObject inUseEmissionStrength; 109 | static MObject inEmissionStrengthExponent; 110 | 111 | static MObject inEnableMotionBlur; 112 | static MObject inMotionBlurParticleSegments; 113 | static MObject inJitteredMotionBlur; 114 | static MObject inShutterAngle; 115 | static MObject inEnableDOF; 116 | static MObject inSampleRateDOF; 117 | static MObject inDisableCameraBlur; 118 | static MObject inMotionBlurBias; 119 | 120 | static MObject inEnableAdaptiveMotionBlur; 121 | static MObject inAdaptiveMotionBlurMinSamples; 122 | static MObject inAdaptiveMotionBlurMaxSamples; 123 | static MObject inAdaptiveMotionBlurSmoothness; 124 | static MObject inAdaptiveMotionBlurExpoenent; 125 | 126 | static MObject inEnableBokehShapeMap; 127 | static MObject inBokehShapeMap; 128 | static MObject inEnableBokehBlendMap; 129 | static MObject inBokehBlendMap; 130 | static MObject inBokehBlendInfluence; 131 | static MObject inBokehEnableAnamorphicSqueeze; 132 | static MObject inBokehAnamorphicSqueeze; 133 | static MObject inBokehBlendMipmapScale; 134 | static MObject inAllocateBokehBlendInfluence; 135 | 136 | static MObject inEnableMatteObjects; 137 | static MObject inMatteSuperSampling; 138 | 139 | static MObject inLogLevel; 140 | static MObject inThreadCount; 141 | static MObject inFrameBufferAvailableMemoryFraction; 142 | }; 143 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | cmake_minimum_required( VERSION 3.20 FATAL_ERROR ) 4 | 5 | project( KrakatoaMY ) 6 | 7 | find_package( thinkboxcmlibrary REQUIRED ) 8 | include( PrecompiledHeader) 9 | include( ThinkboxCMLibrary) 10 | 11 | set( SUPPORTED_MAYA_VERSIONS 2022 2023 ) 12 | 13 | option( MAYA_VERSION "The version of Maya SDK to build the library against." 2022 ) 14 | 15 | if( NOT MAYA_VERSION IN_LIST SUPPORTED_MAYA_VERSIONS ) 16 | message( FATAL_ERROR "ERROR: Cannot build for unsupported Maya version ${MAYA_VERSION}" ) 17 | endif() 18 | 19 | add_library( krakatoamy SHARED ) 20 | 21 | set_target_properties( krakatoamy PROPERTIES OUTPUT_NAME "MayaKrakatoa" ) 22 | set_target_properties( krakatoamy PROPERTIES PREFIX "" ) 23 | 24 | target_include_directories( krakatoamy PUBLIC 25 | $ 26 | $ ) 27 | target_include_directories( krakatoamy PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) 28 | 29 | if( WIN32 ) 30 | set_target_properties( krakatoamy PROPERTIES SUFFIX ".mll" ) 31 | elseif( APPLE ) 32 | set_target_properties( krakatoamy PROPERTIES SUFFIX ".bundle" ) 33 | elseif( UNIX ) 34 | set_target_properties( krakatoamy PROPERTIES SUFFIX ".so" ) 35 | endif() 36 | 37 | file( GLOB_RECURSE H_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/*.h" "include/*.hpp" ) 38 | file( GLOB_RECURSE CXX_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp" ) 39 | 40 | target_sources( krakatoamy PRIVATE 41 | "KrakatoaVersion.h" 42 | "stdafx.h" 43 | "stdafx.cpp" 44 | ${H_FILES} 45 | ${CXX_FILES} 46 | ) 47 | 48 | # The Conan version of Boost was built with this, and it changes the library names. 49 | # As a result, we need to set this to tell Boost to look for the right libraries to 50 | # link against. 51 | target_compile_definitions( krakatoamy PUBLIC BOOST_AUTO_LINK_SYSTEM ) 52 | target_compile_definitions( krakatoamy PUBLIC KSR_STATIC ) 53 | 54 | find_package( mayasdk REQUIRED ) 55 | find_package( thinkboxlibrary REQUIRED ) 56 | find_package( thinkboxmylibrary REQUIRED ) 57 | find_package( krakatoa REQUIRED ) 58 | find_package( krakatoasr REQUIRED ) 59 | find_package( magma REQUIRED ) 60 | find_package( magmamy REQUIRED ) 61 | find_package( nodeview REQUIRED ) 62 | find_package( Boost REQUIRED ) 63 | find_package( OpenEXR REQUIRED ) 64 | find_package( ZLIB REQUIRED ) 65 | find_package( TBB REQUIRED ) 66 | find_package( xxHash REQUIRED ) 67 | 68 | target_include_directories( krakatoamy PUBLIC ${mayasdk_INCLUDE_DIRS} ) 69 | target_include_directories( krakatoamy PUBLIC ${thinkboxlibrary_INCLUDE_DIRS} ) 70 | target_include_directories( krakatoamy PUBLIC ${thinkboxmylibrary_INCLUDE_DIRS} ) 71 | target_include_directories( krakatoamy PUBLIC ${krakatoa_INCLUDE_DIRS} ) 72 | target_include_directories( krakatoamy PUBLIC ${krakatoasr_INCLUDE_DIRS} ) 73 | target_include_directories( krakatoamy PUBLIC ${magma_INCLUDE_DIRS} ) 74 | target_include_directories( krakatoamy PUBLIC ${magmamy_INCLUDE_DIRS} ) 75 | target_include_directories( krakatoamy PUBLIC ${nodeview_INCLUDE_DIRS} ) 76 | target_include_directories( krakatoamy PUBLIC ${Boost_INCLUDE_DIRS} ) 77 | target_include_directories( krakatoamy PUBLIC ${OpenEXR_INCLUDE_DIRS} ) 78 | target_include_directories( krakatoamy PUBLIC ${ZLIB_INCLUDE_DIRS} ) 79 | target_include_directories( krakatoamy PUBLIC ${TBB_INCLUDE_DIRS} ) 80 | target_include_directories( krakatoamy PUBLIC ${xxHash_INCLUDE_DIRS} ) 81 | 82 | target_link_libraries( krakatoamy PUBLIC mayasdk::mayasdk ) 83 | target_link_libraries( krakatoamy PUBLIC thinkboxlibrary::thinkboxlibrary ) 84 | target_link_libraries( krakatoamy PUBLIC thinkboxmylibrary::thinkboxmylibrary ) 85 | target_link_libraries( krakatoamy PUBLIC krakatoa::krakatoa ) 86 | target_link_libraries( krakatoamy PUBLIC krakatoasr::krakatoasr ) 87 | target_link_libraries( krakatoamy PUBLIC magma::magma ) 88 | target_link_libraries( krakatoamy PUBLIC magmamy::magmamy ) 89 | target_link_libraries( krakatoamy PUBLIC nodeview::nodeview ) 90 | target_link_libraries( krakatoamy PUBLIC Boost::Boost ) 91 | target_link_libraries( krakatoamy PUBLIC OpenEXR::OpenEXR ) 92 | target_link_libraries( krakatoamy PUBLIC ZLIB::ZLIB ) 93 | target_link_libraries( krakatoamy PUBLIC TBB::tbb ) 94 | target_link_libraries( krakatoamy PUBLIC xxHash::xxHash ) 95 | 96 | find_package( OpenGL REQUIRED ) 97 | include_directories( ${OPENGL_INCLUDE_DIRS} ) 98 | target_link_libraries( krakatoamy PUBLIC ${OPENGL_LIBRARIES} ) 99 | 100 | frantic_common_platform_setup( krakatoamy ) 101 | frantic_default_source_groups( krakatoamy HEADERDIR include SOURCEDIR src ) 102 | 103 | if( APPLE ) 104 | set_property( TARGET krakatoamy APPEND_STRING PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/MayaKrakatoa.exp" ) 105 | # These are required when including certain Maya SDK headers. 106 | target_link_libraries( krakatoamy PUBLIC "-framework CoreServices") 107 | target_link_libraries( krakatoamy PUBLIC "-framework CoreFoundation") 108 | target_link_libraries( krakatoamy PUBLIC "-framework IOKit") 109 | elseif( UNIX ) 110 | set_property( TARGET krakatoamy APPEND_STRING PROPERTY LINK_FLAGS "-Wl,--no-undefined -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/MayaKrakatoa.map -ldl" ) 111 | endif() 112 | 113 | frantic_common_platform_setup( krakatoamy ) 114 | frantic_default_source_groups( krakatoamy HEADERDIR include SOURCEDIR src ) 115 | 116 | # Disable optimization for the RelWithDebInfo configuration on Windows. 117 | # This allows breakpoints to be hit reliably when debugging in Visual Studio. 118 | if( WIN32 ) 119 | target_compile_options( krakatoamy PRIVATE "$<$:/O2>$<$:/Od>" ) 120 | endif() 121 | 122 | install( TARGETS krakatoamy 123 | RUNTIME DESTINATION bin 124 | LIBRARY DESTINATION lib 125 | ARCHIVE DESTINATION lib 126 | ) 127 | -------------------------------------------------------------------------------- /scripts/MayaKrakatoa.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | # MayaKrakatoa.py 5 | # 6 | # This is a utility file that should house any common script code required by MayaKrakatoa, since 7 | # its much easier to share code as a python module than as a mel source file. Eventually, we should 8 | # try migrating more of our code over to python to avoid MEL's awkwardness 9 | # 10 | from __future__ import print_function 11 | 12 | import maya.cmds 13 | import maya.mel 14 | import re 15 | 16 | MAYA_KRAKATOA_NAME = 'MayaKrakatoa' 17 | 18 | # Useful internal method to loaded the plugin 19 | def _LoadMayaKrakatoa(app_name): 20 | if not maya.cmds.pluginInfo(app_name, query=True, loaded=True ): 21 | results = maya.cmds.loadPlugin(app_name) 22 | print('_LoadMayaKrakatoa %s' % results) 23 | if results != None and len(results) == 0: 24 | raise Exception('Could not load %s, cannot proceed.' % app_name) 25 | 26 | def _AutoLoadMayaKrakatoa(): 27 | if not maya.cmds.pluginInfo( MAYA_KRAKATOA_NAME, query=True, loaded=True ): 28 | result = maya.cmds.confirmDialog(title='Warning', 29 | message='MayaKrakatoa plugin is not loaded. Please go to Window -> Setting/Preferences -> Plug-in Manager to load MayaKrakatoa', 30 | button=['Ok'], defaultButton='Ok', cancelButton='Ok', dismissString='Ok') 31 | # 32 | # Methods related to handling partition files 33 | # 34 | _currentPartitionFileGroup = 'current' 35 | _totalPartitionFileGroup = 'total' 36 | _partitionFileRegex = "_part(?P<" + _currentPartitionFileGroup + ">[0-9]+)of(?P<" + _totalPartitionFileGroup + ">[0-9]+)_" 37 | 38 | def IsPartitionFile( fileName ): 39 | if re.search( _partitionFileRegex, fileName ): 40 | return True 41 | else: 42 | return False 43 | 44 | def GetPartitionFileInfo( fileName ): 45 | m = re.search( _partitionFileRegex, fileName ) 46 | if m: 47 | return ( int(m.group(_currentPartitionFileGroup)), int(m.group(_totalPartitionFileGroup)) ) 48 | else: 49 | return () 50 | 51 | def ReplacePartitionNumber(fileName, paritionIdx): 52 | current, total = GetPartitionFileInfo(fileName) 53 | numDigits = len(str(total)) 54 | return re.sub( _partitionFileRegex, '_part' + str(paritionIdx).zfill(numDigits) + 'of' + str(total) + '_', fileName ) 55 | 56 | def WildCardPartitionNumber(fileName): 57 | current, total = GetPartitionFileInfo(fileName) 58 | return re.sub( _partitionFileRegex, '_part*of' + str(total) + '_', fileName ) 59 | 60 | # 61 | # Methods related to creating Maya Krakatoa nodes 62 | # Eventually, we may want to use UI contexts to allow the user to place them in the scene using the mouse 63 | # 64 | def _CreateRelatedTransform(baseName): 65 | transformNode = maya.cmds.createNode( 'transform', name=baseName+'Transform#' ) 66 | matches = re.search( '[0-9]+$', transformNode ) 67 | idx = int(matches.group( 0 )) 68 | return ( transformNode, idx ) 69 | 70 | def CreatePRTVolumeNode(): 71 | _AutoLoadMayaKrakatoa() 72 | if maya.cmds.pluginInfo( MAYA_KRAKATOA_NAME, query=True, loaded=True ): 73 | sel = maya.cmds.ls(sl=True) 74 | transformNode, idx = _CreateRelatedTransform( 'PRTVolume' ) 75 | prtVolumeNode = maya.cmds.createNode( 'PRTVolume', name='PRTVolume'+str(idx), parent=transformNode ) 76 | maya.cmds.connectAttr( prtVolumeNode + '.worldMatrix' , prtVolumeNode + '.currXForm' ) 77 | for node in sel: 78 | typ = maya.cmds.nodeType( node ) 79 | if typ == 'mesh' or typ == 'transform': 80 | mystr = ('PRTVolumeAutoAttachSelectedMesh("'+ node + '","' + prtVolumeNode + '");') 81 | maya.mel.eval(mystr) 82 | break 83 | return prtVolumeNode 84 | return None 85 | 86 | def CreatePRTSurfaceNode(): 87 | _AutoLoadMayaKrakatoa() 88 | if maya.cmds.pluginInfo( MAYA_KRAKATOA_NAME, query=True, loaded=True ): 89 | sel = maya.cmds.ls(sl=True) 90 | transformNode, idx = _CreateRelatedTransform( 'PRTSurface' ) 91 | prtSurfaceNode = maya.cmds.createNode( 'PRTSurface', name='PRTSurface'+str(idx), parent=transformNode ) 92 | maya.cmds.connectAttr( prtSurfaceNode + '.worldMatrix' , prtSurfaceNode + '.currXForm' ) 93 | for node in sel: 94 | typ = maya.cmds.nodeType( node ) 95 | if typ == 'mesh' or typ == 'transform': 96 | mystr = ('PRTSurfaceAutoAttachSelectedMesh("'+ node + '","' + prtSurfaceNode + '");') 97 | maya.mel.eval(mystr) 98 | break 99 | return prtSurfaceNode 100 | return None 101 | 102 | def CreatePRTLoaderNode(): 103 | _AutoLoadMayaKrakatoa() 104 | if maya.cmds.pluginInfo( MAYA_KRAKATOA_NAME, query=True, loaded=True ): 105 | transformNode, idx = _CreateRelatedTransform( 'PRTLoader' ) 106 | prtLoaderNode = maya.cmds.createNode( 'PRTLoader', name='PRTLoader'+str(idx), parent=transformNode ) 107 | maya.cmds.connectAttr( 'time1.outTime', prtLoaderNode + '.inTime' ) 108 | return prtLoaderNode 109 | return None 110 | 111 | def CreatePRTFractalNode(): 112 | _AutoLoadMayaKrakatoa() 113 | if maya.cmds.pluginInfo( MAYA_KRAKATOA_NAME, query=True, loaded=True ): 114 | transformNode, idx = _CreateRelatedTransform( 'PRTFractal' ) 115 | prtFractalNode = maya.cmds.createNode( 'PRTFractal', name='PRTFractal'+str(idx), parent=transformNode ) 116 | return prtFractalNode 117 | return None 118 | 119 | def OpenPRTSaver(): 120 | _AutoLoadMayaKrakatoa() 121 | if maya.cmds.pluginInfo( MAYA_KRAKATOA_NAME, query=True, loaded=True ): 122 | maya.mel.eval('displayPRTExporterDialog()') 123 | return () 124 | return None 125 | 126 | def OpenModifierDialog(): 127 | _AutoLoadMayaKrakatoa() 128 | if maya.cmds.pluginInfo( MAYA_KRAKATOA_NAME, query=True, loaded=True ): 129 | maya.mel.eval('KMYMODED_displayKMYModEditorDialog()') 130 | return () 131 | return None 132 | 133 | def OpenMagmaDialog(): 134 | _AutoLoadMayaKrakatoa() 135 | if maya.cmds.pluginInfo( MAYA_KRAKATOA_NAME, query=True, loaded=True ): 136 | maya.mel.eval('OpenKrakatoaMagmaEditor()') 137 | return () 138 | return None 139 | 140 | def LoadMayaKrakatoa(): 141 | _AutoLoadMayaKrakatoa() 142 | if maya.cmds.pluginInfo( MAYA_KRAKATOA_NAME, query=True, loaded=True ): 143 | return () 144 | return None 145 | -------------------------------------------------------------------------------- /include/PRTSurface.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include "PRTObject.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | /** 24 | * Maya Plugin shape object that can be used to represent a cloud of particles generated from the surface of a mesh 25 | * Base code was copied and modified from PRTVolume 26 | */ 27 | class PRTSurface : public PRTObject { 28 | 29 | public: 30 | // Maya rtti and object creation information 31 | static void* creator(); 32 | static MStatus initialize(); 33 | static MTypeId typeId; 34 | static MString typeName; 35 | static const MString drawRegistrantId; 36 | 37 | public: 38 | PRTSurface(); 39 | virtual ~PRTSurface(); 40 | 41 | virtual void postConstructor(); 42 | 43 | // inherited from MPxSurfaceShape 44 | virtual MBoundingBox boundingBox() const; 45 | virtual bool isBounded() const; 46 | 47 | // inherited from MPxNode 48 | virtual MStatus compute( const MPlug& plug, MDataBlock& block ); 49 | virtual MStatus setDependentsDirty( const MPlug& plug, MPlugArray& plugArray ); 50 | 51 | // inherited from PRTObject 52 | virtual PRTObject::particle_istream_ptr getRenderParticleStream( const frantic::graphics::transform4f& tm, 53 | const MDGContext& currentContext ) const; 54 | virtual PRTObject::particle_istream_ptr getViewportParticleStream( const frantic::graphics::transform4f& tm, 55 | const MDGContext& currentContext ) const; 56 | 57 | virtual frantic::particles::particle_array* getCachedViewportParticles(); 58 | virtual PRTObject::display_mode_t getViewportDisplayMode(); 59 | 60 | virtual const frantic::geometry::trimesh3& getRootMesh() const; 61 | 62 | private: 63 | // The mesh from which the particle surface is calculated 64 | static MObject inMesh; 65 | 66 | // The 'worldMatrix' of the mesh used by the source object 67 | static MObject inMeshTransform; 68 | 69 | // The 'worldMatrix' of this object (For some reason, MFnAttribute::setWorldSpace does not work so this is used as a 70 | // work around) 71 | static MObject inCurrentTransform; 72 | 73 | // boolean that states if the surface should be rendered in object or world-space 74 | static MObject inUseWorldSpace; 75 | 76 | // This integer defines the seed for the random jitter. 77 | static MObject inRandomSeed; 78 | 79 | // This integer defines the total number of particles to generate. 80 | static MObject inParticleCount; 81 | 82 | // Enable/Disable override to use spacing. 83 | static MObject inUseParticleSpacing; 84 | 85 | // This double defines the spacing of the particles to generate. 86 | static MObject inParticleSpacing; 87 | 88 | // use density compensation 89 | static MObject inUseDensityCompensation; 90 | 91 | // whether to show the surface particles in the viewport at all 92 | static MObject inEnableInViewport; 93 | 94 | // Percentage of the total number of particles to display in the viewport 95 | static MObject inViewportParticlePercent; 96 | 97 | // Enable/disable the control over viewport load limit 98 | static MObject inEnableViewportParticleLimit; 99 | 100 | // Maximum number of particles to display in the viewport 101 | static MObject inViewportParticleLimit; 102 | 103 | // The rendering method to use when displaying the particles in the viewport 104 | static MObject inViewportDisplayMode; 105 | 106 | // a dummy output parameter that forces read-through of the input attributes 107 | // This can be thought of as the proxy for the cached particle array on this object 108 | static MObject outViewportParticleCacheProxy; 109 | 110 | // output particle stream 111 | static MObject outParticleStream; 112 | 113 | static boost::unordered_set viewportInputDependencies; 114 | 115 | private: 116 | void touchSentinelOutput( MObject sentinelAttribute ) const; 117 | void cacheViewportParticles(); 118 | PRTObject::particle_istream_ptr buildParticleStream( bool viewportMode ) const; 119 | void cacheBoundingBox(); 120 | 121 | double getViewportSpacing() const; 122 | double getRenderSpacing() const; 123 | 124 | double getViewportParticleFraction() const; 125 | boost::int64_t getViewportParticleLimit() const; 126 | 127 | bool inWorldSpace() const; 128 | frantic::graphics::transform4f getWorldSpaceTransform( const MDGContext& context, bool* isOK = NULL ) const; 129 | MMatrix getMayaWorldSpaceTransform( const MDGContext& context, bool* isOK = NULL ) const; 130 | int getRandomSeed() const; 131 | int getParticleCount() const; 132 | double getParticleSpacing() const; 133 | bool isUseParticleSpacing() const; 134 | bool useDensityCompensation() const; 135 | 136 | int getIntAttribute( MObject attribute, MDGContext& context = MDGContext::fsNormal, 137 | MStatus* outStatus = NULL ) const; 138 | double getDoubleAttribute( MObject attribute, MDGContext& context = MDGContext::fsNormal, 139 | MStatus* outStatus = NULL ) const; 140 | bool getBooleanAttribute( MObject attribute, MDGContext& context = MDGContext::fsNormal, 141 | MStatus* outStatus = NULL ) const; 142 | 143 | // return channel map for displaying viewport based on the channel map of inputStream 144 | // "Position", "Velocity", "Normal", "Color" will be returned if inputStream have these channels 145 | frantic::channels::channel_map 146 | get_viewport_channel_map( boost::shared_ptr inputStream ) const; 147 | 148 | private: 149 | frantic::particles::particle_array m_cachedParticles; 150 | MBoundingBox m_boundingBox; 151 | bool lastWorldSpaceState; 152 | bool m_osxViewport20HackInitialized; 153 | }; 154 | -------------------------------------------------------------------------------- /include/PRTFractal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include "PRTObject.hpp" 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | // setkeys and RandomizeFractals 28 | #include 29 | #include 30 | #include 31 | 32 | #if !( __APPLE__ && MAYA_API_VERSION >= 201800 ) 33 | class MIntArray; 34 | class MVectorArray; 35 | class MFnArrayAttrsData; 36 | #endif 37 | 38 | /** 39 | * Maya Plugin shape object that can be used to represent a set of PRT file sequences in the scene. 40 | */ 41 | class PRTFractal : public PRTObject { 42 | public: 43 | // Maya rtti and object creation information 44 | static void* creator(); 45 | static MStatus initialize(); 46 | static MTypeId typeId; 47 | static MString typeName; 48 | static const MString drawRegistrantId; 49 | static const MString drawClassification; 50 | 51 | public: 52 | PRTFractal(); 53 | virtual ~PRTFractal(); 54 | 55 | virtual void postConstructor(); 56 | 57 | // inherited from MPxSurfaceShape 58 | virtual MBoundingBox boundingBox() const; 59 | virtual bool isBounded() const; 60 | 61 | // inherited from MPxNode 62 | virtual MStatus compute( const MPlug& plug, MDataBlock& block ); 63 | virtual MStatus setDependentsDirty( const MPlug& plug, MPlugArray& plugArray ); 64 | 65 | // inherited from PRTObject 66 | virtual PRTObject::particle_istream_ptr 67 | getRenderParticleStream( const frantic::graphics::transform4f& tm, 68 | const MDGContext& currentContext = MDGContext::fsNormal ) const; 69 | virtual PRTObject::particle_istream_ptr 70 | getViewportParticleStream( const frantic::graphics::transform4f& tm, 71 | const MDGContext& currentContext = MDGContext::fsNormal ) const; 72 | 73 | virtual frantic::particles::particle_array* getCachedViewportParticles(); 74 | virtual PRTObject::display_mode_t getViewportDisplayMode(); 75 | 76 | virtual const frantic::geometry::trimesh3& getRootMesh() const; 77 | 78 | private: 79 | // current time, as received from the global time node 80 | static MObject inTime; 81 | 82 | // test 83 | // static MObject inInputFiles; 84 | static MObject inAffineTransformationCount; 85 | 86 | // viewport particle loading mode 87 | static MObject inViewportLoadMode; 88 | 89 | // How to represent each particle (dot, velocity, etc..) 90 | static MObject inViewportDisplayMode; 91 | 92 | // a dummy output parameter that forces read-through of the input attributes 93 | static MObject outSentinel; 94 | 95 | static MObject inPosX[]; 96 | static MObject inPosY[]; 97 | static MObject inPosZ[]; 98 | static MObject inRotX[]; 99 | static MObject inRotY[]; 100 | static MObject inRotZ[]; 101 | static MObject inRotW[]; 102 | static MObject inScaleX[]; 103 | static MObject inScaleY[]; 104 | static MObject inScaleZ[]; 105 | static MObject inSkewX[]; 106 | static MObject inSkewY[]; 107 | static MObject inSkewZ[]; 108 | static MObject inSkewW[]; 109 | static MObject inSkewA[]; 110 | static MObject inWeight[]; 111 | static MObject inStartColor; 112 | static MObject inEndColor; 113 | 114 | static MObject inRenderParticleCount; 115 | static MObject inViewportParticleCount; 116 | 117 | static MObject inFractalRandomSeed; 118 | 119 | // output particle stream 120 | static MObject outParticleStream; 121 | 122 | static boost::unordered_set viewportInputDependencies; 123 | 124 | private: 125 | particle_istream_ptr getParticleStream( const MDGContext& currentContext, 126 | krakatoa::enabled_mode::enabled_mode_enum mode ) const; 127 | 128 | void touchSentinelOutput() const; 129 | void cacheParticlesAt( MTime time ); 130 | void cacheBoundingBox(); 131 | 132 | MStatus getCurrentTime( MDataBlock& block, MTime& outTime ) const; 133 | static void addDependencies( MObject obj ); 134 | 135 | krakatoa::viewport::RENDER_LOAD_PARTICLE_MODE getViewportLoadMode() const; 136 | 137 | frantic::graphics::vector3f getVector3fAttribute( MObject attribute, 138 | const MDGContext& context = MDGContext::fsNormal, 139 | MStatus* outStatus = NULL ) const; 140 | int getIntAttribute( MObject attribute, const MDGContext& context = MDGContext::fsNormal, 141 | MStatus* outStatus = NULL ) const; 142 | double getDoubleAttribute( MObject attribute, const MDGContext& context = MDGContext::fsNormal, 143 | MStatus* outStatus = NULL ) const; 144 | bool getBooleanAttribute( MObject attribute, const MDGContext& context = MDGContext::fsNormal, 145 | MStatus* outStatus = NULL ) const; 146 | MTime getTimeAttribute( MObject attribute, const MDGContext& context = MDGContext::fsNormal, 147 | MStatus* outStatus = NULL ) const; 148 | 149 | // return channel map for displaying viewport based on the channel map of inputStream 150 | // "Position", "Color" will be returned if inputStream have these channels 151 | frantic::channels::channel_map 152 | get_viewport_channel_map( boost::shared_ptr inputStream ) const; 153 | 154 | private: 155 | frantic::particles::particle_array m_cachedParticles; 156 | MBoundingBox m_boundingBox; 157 | bool m_osxViewport20HackInitialized; 158 | }; 159 | 160 | class AddFractalTransformKeyframes : public MPxCommand { 161 | public: 162 | static const MString commandName; 163 | static void* creator(); 164 | 165 | static void setPluginPath( const MString& path ); 166 | static const MString getPluginPath(); 167 | 168 | private: 169 | static MString s_pluginPath; 170 | 171 | public: 172 | MStatus doIt( const MArgList& args ); 173 | }; 174 | 175 | class RandomizeFractals : public MPxCommand { 176 | public: 177 | static const MString commandName; 178 | static void* creator(); 179 | 180 | static void setPluginPath( const MString& path ); 181 | static const MString getPluginPath(); 182 | 183 | private: 184 | static MString s_pluginPath; 185 | 186 | public: 187 | MStatus doIt( const MArgList& args ); 188 | }; 189 | -------------------------------------------------------------------------------- /conanfile.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | from typing import Any 4 | from conans import ConanFile, CMake 5 | 6 | import os 7 | import posixpath 8 | import shutil 9 | 10 | import version_gen 11 | 12 | 13 | VALID_MAYA_CONFIGS: dict[tuple[str, str], set[str]] = { 14 | ('Visual Studio', '16'): { '2022', '2023' }, 15 | ('gcc', '7'): { '2022', '2023' }, 16 | ('gcc', '9'): { '2022', '2023' }, 17 | ('apple-clang', '10.0'): { '2022', '2023' } 18 | } 19 | 20 | SETTINGS: dict[str, Any] = { 21 | 'os': ['Windows', 'Linux', 'Macos'], 22 | 'compiler': { 23 | 'Visual Studio': {'version': ['16']}, 24 | 'gcc': {'version': ['7', '9']}, 25 | 'apple-clang': {'version': ['10.0']} 26 | }, 27 | 'build_type': None, 28 | 'arch': 'x86_64' 29 | } 30 | 31 | TOOL_REQUIRES: list[str] = [ 32 | 'cmake/3.24.1', 33 | 'thinkboxcmlibrary/1.0.0' 34 | ] 35 | 36 | REQUIRES: list[str] = [ 37 | 'mayasdk/1.0.0', 38 | 'thinkboxlibrary/1.0.0', 39 | 'thinkboxmylibrary/1.0.0', 40 | 'krakatoa/1.0.0', 41 | 'krakatoasr/1.0.0', 42 | 'nodeview/1.0.0', 43 | 'magma/1.0.0', 44 | 'magmamy/1.0.0', 45 | ] 46 | 47 | NO_LICENSE_ALLOWLIST: set[str] = { 48 | # ThinkboxCMLibrary is not distributed with this package 49 | 'thinkboxcmlibrary', 50 | # The Maya SDK is not open source and we do not distribute it 51 | 'mayasdk', 52 | # We do not distribute Qt, 53 | 'qt', 54 | # We do not distribute OpenGL 55 | 'opengl', 56 | # We do not distribute CMake 57 | 'cmake', 58 | # We do not distribute xorg 59 | 'xorg', 60 | # We do not distribute xkeyboard-config 61 | 'xkeyboard-config' 62 | } 63 | 64 | UNUSED_LICENSE_DENYLIST: set[str] = { 65 | # Parts of Eigen are licensed under GPL or LGPL 66 | # Eigen provides an option to disable these parts such 67 | # that a compiler error will be generated if they are used. 68 | # We do not use these parts, and enable this option. 69 | 'licenses/eigen/licenses/COPYING.GPL', 70 | 'licenses/eigen/licenses/COPYING.LGPL', 71 | # Freetype is dual licensed under it's own BSD style license, FTL 72 | # as well as GPLv2. We are licensing it under FTL so we will not 73 | # include GPLv2 in our attributions document. 74 | 'licenses/freetype/licenses/GPLv2.txt' 75 | } 76 | 77 | 78 | class KrakatoaMYConan(ConanFile): 79 | name: str = 'krakatoamy' 80 | version: str = '2.12.4' 81 | license: str = 'Apache-2.0' 82 | description: str = 'The Krakatoa Plugin for Maya' 83 | settings: dict[str, Any] = SETTINGS 84 | requires: list[str] = REQUIRES 85 | tool_requires: list[str] = TOOL_REQUIRES 86 | generators: str | list[str] = 'cmake_find_package' 87 | options: dict[str, Any] = { 88 | 'maya_version': ['2022', '2023'] 89 | } 90 | 91 | def configure(self) -> None: 92 | if self.options.maya_version == None: 93 | self.options.maya_version = '2022' 94 | self.options['magmamy'].maya_version = self.options.maya_version 95 | self.options['nodeview'].maya_version = self.options.maya_version 96 | self.options['thinkboxmylibrary'].maya_version = self.options.maya_version 97 | self.options['mayasdk'].maya_version = self.options.maya_version 98 | self.default_options = { 99 | 'krakatoasr:shared': False 100 | } 101 | 102 | def validate(self) -> None: 103 | if self.options.maya_version != self.options['mayasdk'].maya_version: 104 | raise Exception('Option \'maya_version\' must be the same as mayasdk') 105 | if self.options.maya_version != self.options['thinkboxmylibrary'].maya_version: 106 | raise Exception('Option \'maya_version\' must be the same as thinkboxmylibrary') 107 | compiler = str(self.settings.compiler) 108 | compiler_version = str(self.settings.compiler.version) 109 | compiler_tuple = (compiler, compiler_version) 110 | maya_version = str(self.options.maya_version) 111 | if maya_version not in VALID_MAYA_CONFIGS[compiler_tuple]: 112 | raise Exception(f'{str(compiler_tuple)} is not a valid configuration for Maya {maya_version}') 113 | 114 | def imports(self) -> None: 115 | self.copy("license*", dst="licenses", folder=True, ignore_case=True) 116 | self.generate_attributions_doc() 117 | 118 | def build(self) -> None: 119 | version_gen.write_version_file(self.version, os.path.join(self.source_folder, 'KrakatoaVersion.h')) 120 | shutil.copyfile('attributions.txt', os.path.join(self.source_folder, 'third_party_licenses.txt')) 121 | 122 | cmake = CMake(self) 123 | cmake.configure(defs={ 124 | 'MAYA_VERSION': self.options.maya_version 125 | }) 126 | cmake.build() 127 | 128 | def export_sources(self) -> None: 129 | self.copy('**.h', src='', dst='') 130 | self.copy('**.hpp', src='', dst='') 131 | self.copy('**.cpp', src='', dst='') 132 | self.copy('CMakeLists.txt', src='', dst='') 133 | self.copy('version_gen.py', src='', dst='') 134 | self.copy('MayaKrakatoa.exp', src='', dst='') 135 | self.copy('MayaKrakatoa.map', src='', dst='') 136 | self.copy('*', dst='icons', src='icons') 137 | self.copy('*', dst='scripts', src='scripts') 138 | 139 | def package(self) -> None: 140 | cmake = CMake(self) 141 | cmake.install() 142 | self.copy('*', dst='icons', src='icons') 143 | self.copy('*', dst='scripts', src='scripts') 144 | self.copy('third_party_licenses.txt', dst='Legal', src='') 145 | 146 | def deploy(self) -> None: 147 | self.copy('*', dst='bin', src='bin') 148 | self.copy('*', dst='lib', src='lib') 149 | self.copy('*', dst='include', src='include') 150 | self.copy('*', dst='icons', src='icons') 151 | self.copy('*', dst='scripts', src='scripts') 152 | self.copy('*', dst='Legal', src='Legal') 153 | 154 | def generate_attributions_doc(self) -> None: 155 | dependencies = [str(dependency[0].ref).split('/') for dependency in self.dependencies.items()] 156 | print('Building Attributions Doc') 157 | with open('attributions.txt', 'w') as attributions_doc: 158 | for name, version in dependencies: 159 | if name not in NO_LICENSE_ALLOWLIST: 160 | print(f'Including {name} {version} in attributions doc.') 161 | attributions_doc.write(f'######## {name} {version} ########\n\n') 162 | licensedir = posixpath.join('licenses', name, 'licenses') 163 | if not os.path.exists(licensedir): 164 | raise Exception(f'Could not find license files for package {name} {version}.') 165 | for licensefile in os.listdir(licensedir): 166 | licensefilepath = posixpath.join(licensedir, licensefile) 167 | if licensefilepath not in UNUSED_LICENSE_DENYLIST: 168 | print(f' Including license file: {licensefile}.') 169 | with open(licensefilepath, 'r', encoding='utf8') as license: 170 | attributions_doc.writelines(license.readlines()) 171 | attributions_doc.write('\n') 172 | -------------------------------------------------------------------------------- /include/maya_ksr.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | namespace maya_ksr { 24 | 25 | // unfortunately, its neccessary to hang onto meshes that are created, as the renderer does not take explicit ownership 26 | // of the meshes This class is just a primitive example of how to maintain this context It is designed such that in the 27 | // future, it might be possible to associate meshes with a specific named attribute in the scene that outputs a mesh to 28 | // more than one scene node, in order to support that kind of instancing 29 | class mesh_context { 30 | private: 31 | typedef std::map mesh_container; 32 | mesh_container m_meshes; 33 | 34 | public: 35 | mesh_context(); 36 | ~mesh_context(); 37 | 38 | /** 39 | * First checks if a mesh was already registered with the specified name, otherwise returns a new instance 40 | */ 41 | krakatoasr::triangle_mesh* get_shared_instance( const frantic::tstring& name ); 42 | }; 43 | 44 | struct bokeh_map_ptrs { 45 | boost::shared_array shapeMapPtr; 46 | boost::shared_array blendMapPtr; 47 | }; 48 | 49 | // not including the camera 50 | void apply_scene_to_renderer( const MFnDependencyNode& krakatoaSettingsNode, const MDGContext& currentContext, 51 | krakatoasr::krakatoa_renderer& krakRenderer, mesh_context& sharedMeshContext ); 52 | 53 | void apply_global_resolution_node_to_renderer( const MDGContext& currentContext, 54 | krakatoasr::krakatoa_renderer& krakRenderer ); 55 | 56 | void apply_shader_to_renderer( const MFnDependencyNode& krakatoaSettingsNode, const MDGContext& currentContext, 57 | krakatoasr::krakatoa_renderer& krakRenderer ); 58 | 59 | void apply_render_method_to_renderer( const MFnDependencyNode& krakatoaSettingsNode, const MDGContext& currentContext, 60 | krakatoasr::krakatoa_renderer& krakRenderer ); 61 | 62 | void apply_general_settings_to_renderer( const MFnDependencyNode& krakatoaSettingsNode, 63 | const MDGContext& currentContext, 64 | krakatoasr::krakatoa_renderer& krakRenderer ); 65 | 66 | void apply_current_camera_to_renderer( const MFnDependencyNode& krakatoaSettingsNode, const MDGContext& currentContext, 67 | krakatoasr::krakatoa_renderer& krakRenderer ); 68 | 69 | void apply_chosen_camera_to_renderer( const MFnDependencyNode& krakatoaSettingsNode, const MDGContext& currentContext, 70 | krakatoasr::krakatoa_renderer& krakRenderer, MString camera ); 71 | 72 | void apply_camera_to_renderer( const MFnCamera& mayaCamera, const MFnDependencyNode& krakatoaSettingsNode, 73 | const MDGContext& currentContext, krakatoasr::krakatoa_renderer& krakRenderer ); 74 | 75 | void apply_light_to_renderer( const MFnLight& mayaLight, const MFnDependencyNode& krakatoaSettingsNode, 76 | const MDGContext& currentContext, krakatoasr::krakatoa_renderer& krakRenderer ); 77 | 78 | void apply_load_percentage_to_renderer( const MFnDagNode& fnNode, const MFnDependencyNode& krakatoaSettingsNode, 79 | const MDGContext& currentContext, krakatoasr::krakatoa_renderer& krakRenderer ); 80 | 81 | void apply_prt_object_to_renderer( const MFnDagNode& fnPath, const MFnDependencyNode& prtNode, 82 | const MFnDependencyNode& krakatoaSettingsNode, const MDGContext& currentContext, 83 | krakatoasr::krakatoa_renderer& krakRenderer ); 84 | 85 | void apply_maya_mesh_to_renderer( const MDagPath& fnNode, const MFnDependencyNode& krakatoaSettingsNode, 86 | const MDGContext& currentContext, krakatoasr::krakatoa_renderer& krakRenderer, 87 | mesh_context& sharedMeshContext ); 88 | 89 | void apply_common_operations_to_stream( const MFnDependencyNode& krakatoaSettingsNode, const MDGContext& currentContext, 90 | krakatoasr::particle_stream& particleStream ); 91 | 92 | bool has_krakatoa_matte_tag( const MFnDependencyNode& fnNode, const MDGContext& currentContext ); 93 | 94 | bool has_krakatoa_matte_shadows_tag( const MFnDependencyNode& fnNode, const MDGContext& currentContext ); 95 | 96 | void build_motion_transform( const MDagPath& dagNodePath, const MDGContext& currentContext, float shutterBeginOffset, 97 | float shutterEndOffset, int numSamples, krakatoasr::animated_transform& outTForm ); 98 | 99 | void build_static_transform( const MDagPath& dagNodePath, const MDGContext& currentContext, 100 | krakatoasr::animated_transform& outTForm ); 101 | 102 | void build_scene_transform( const MDagPath& dagNodePath, const MFnDependencyNode& krakatoaSettingsNode, 103 | const MDGContext& currentContext, krakatoasr::animated_transform& outTForm ); 104 | 105 | int get_render_layer_setting( const std::string& settingName, const MDGContext& currentContext ); 106 | 107 | bokeh_map_ptrs apply_bokeh_settings_to_renderer_with_current_camera( const MFnDependencyNode& krakatoaSettingsNode, 108 | const MDGContext& currentContext, 109 | krakatoasr::krakatoa_renderer& krakRenderer ); 110 | 111 | bokeh_map_ptrs apply_bokeh_settings_to_renderer_with_chosen_camera( const MFnDependencyNode& krakatoaSettingsNode, 112 | const MDGContext& currentContext, 113 | krakatoasr::krakatoa_renderer& krakRenderer, 114 | MString camera ); 115 | 116 | /** 117 | * This is a utility function to set up a particle stream to match what the render would do. 118 | * This function is not called at render time. It is for those who need a stream to look exactly like it would look if 119 | * the render had proccessed it. This includes: Adding all the global color overrides, fractional streams, all object 120 | * modifiers, etc. It is used for: Viewport caching of streams, PRTExporter (partitioning), or anyone else that needs a 121 | * stream from a PRT object, and wants all the fanciness on it. It skips the global settings Krakatoa Settings node 122 | * doesn't exist, but it still processes modifiers. 123 | */ 124 | boost::shared_ptr 125 | get_renderer_stream_modifications( boost::shared_ptr inStream, 126 | const MDGContext& currentContext ); 127 | 128 | } // namespace maya_ksr 129 | -------------------------------------------------------------------------------- /include/PRTObjectUIGeometryOverride.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include 6 | 7 | // for viewport 2.0 only. 8 | #if MAYA_API_VERSION >= 201400 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "PRTFractal.hpp" 19 | #include "PRTLoader.hpp" 20 | #include "PRTObject.hpp" 21 | 22 | #include 23 | 24 | class PRTObjectUIGeometryOverride : public MHWRender::MPxGeometryOverride { 25 | public: 26 | static MHWRender::MPxGeometryOverride* create( const MObject& obj ); 27 | 28 | PRTObjectUIGeometryOverride( const MObject& obj ); 29 | ~PRTObjectUIGeometryOverride( void ){}; 30 | 31 | void updateDG(); 32 | 33 | void updateRenderItems( const MDagPath& path, MHWRender::MRenderItemList& list ); 34 | 35 | #if MAYA_API_VERSION >= 201300 36 | void populateGeometry( const MHWRender::MGeometryRequirements& requirements, 37 | const MHWRender::MRenderItemList& renderItems, MHWRender::MGeometry& data ); 38 | #else 39 | void populateGeometry( const MHWRender::MGeometryRequirements& requirements, 40 | MHWRender::MRenderItemList& renderItems, MHWRender::MGeometry& data ); 41 | #endif 42 | 43 | #if MAYA_API_VERSION >= 201600 44 | MHWRender::DrawAPI supportedDrawAPIs() const; 45 | #endif 46 | 47 | void cleanUp(); 48 | 49 | private: 50 | MObject m_obj; 51 | PRTObject* m_cachedObj; 52 | PRTObject::display_mode_t m_cachedDisplayMode; 53 | frantic::particles::particle_array* m_cachedParticleArray; 54 | frantic::channels::channel_map m_cachedChannelMap; 55 | MHWRender::MVertexBuffer* m_vertexBuffer; 56 | MHWRender::MVertexBuffer* m_colorBuffer; 57 | float m_cachedFPS; 58 | // The following are needed because they are part of many if statement conditions 59 | bool m_lineBasedDisplayMode, m_pointBasedDisplayMode; 60 | bool m_validDisplayMode; 61 | bool m_isParticleEnabledInViewport; 62 | bool m_positiveChannelStructureSize; 63 | MColor m_cachedColor; 64 | 65 | void cache_wireframe_color( const MFnDagNode& dagNodeFunctionSet ); 66 | 67 | /** 68 | * Sets up a render item of a specified name 69 | */ 70 | void setup_render_item( const MString& renderItemName, const MHWRender::MGeometry::Primitive geometryType, 71 | MHWRender::MRenderItemList& renderItemList, 72 | const MHWRender::MShaderManager& shaderManager ); 73 | 74 | /** 75 | * Creates a new render item object 76 | */ 77 | MHWRender::MRenderItem* create_render_item( const MString& renderItemName, 78 | const MHWRender::MGeometry::Primitive geometryType, 79 | MHWRender::MRenderItemList& renderItemList ); 80 | 81 | /** 82 | * Attaches a shader to the render item 83 | */ 84 | void attach_shader( const MHWRender::MShaderManager& shaderManager, MHWRender::MRenderItem& renderItem ); 85 | 86 | /** 87 | * Creates a solid color shader item for vertex render items 88 | */ 89 | MHWRender::MShaderInstance* create_vertex_item_shader( const MHWRender::MShaderManager& shaderManager ); 90 | 91 | /** 92 | * Sets up the shaders for coloring the render items 93 | */ 94 | void set_shader_color( MHWRender::MShaderInstance& shader ); 95 | 96 | /** 97 | * Sets the color of the shader of the particles 98 | */ 99 | void populate_particle_color_buffer(); 100 | 101 | /* Creates the vertex buffer using the requirements 102 | * 103 | * Buffer is organized as follows: 104 | * m vertices - particle positions 105 | * n vertices - icon mesh vertices 106 | * 8 vertices - icon mesh bounding box vertices 107 | */ 108 | void create_vertex_buffer( const MHWRender::MVertexBufferDescriptorList& vertexRequirements, 109 | MHWRender::MGeometry& data ); 110 | 111 | /** 112 | * Populates the vertex buffer with the positions of the icon mesh's bounding square 113 | */ 114 | void populate_vertex_buffer( const frantic::geometry::trimesh3& iconMesh, size_t numIconVertices ); 115 | 116 | /** 117 | * Create aquire vertex buffer. Implemented as a function to reduce code necessary for backwards compatability 118 | */ 119 | float* acquire_vertex_buffer( MHWRender::MVertexBuffer* buffer, const size_t size, const bool write ); 120 | 121 | /** 122 | * Populates the particle positions vertex buffer with the positions of the particles in m_cachedParticleArray 123 | */ 124 | void populate_particle_positions( float* bufferPositions ); 125 | 126 | /** 127 | * Get a vector channel accessor fromt the channel map. 128 | */ 129 | frantic::channels::channel_cvt_accessor get_vector_channel_accessor(); 130 | 131 | /** 132 | * Populates the particle colors vertex buffer with the colors of the particles in m_cachedParticleArray 133 | */ 134 | void populate_particle_colors( size_t numIconVertices ); 135 | 136 | /** 137 | * Populates a single particle's color in the vertex buffer for display in a line based display mode. 138 | */ 139 | void populate_particle_line_color( float* colorBuffer, const int offset, const frantic::graphics::color3f& color ); 140 | 141 | /** 142 | * Populates a single particle's color in the vertex buffer for display in a point based display mode 143 | */ 144 | void populate_particle_color( float* colorBuffer, const int offset, const frantic::graphics::color3f& color ); 145 | 146 | /** 147 | * Populates the bounding square of the vertexBuffer 148 | */ 149 | void populate_icon_bounding_square_vertices( const frantic::geometry::trimesh3& iconMesh, float* bufferPositions ); 150 | 151 | /** 152 | * Populates the middle of the vertexBuffer with the verices of the icon mesh 153 | */ 154 | void populate_icon_mesh_vertices( const frantic::geometry::trimesh3& iconMesh, float* bufferPositions ); 155 | 156 | /** 157 | * Creates and populates an index buffer for the bounding quare of the icon mesh 158 | */ 159 | void populate_icon_mesh_bounding_square_indices( MHWRender::MGeometry& geometryData, 160 | const MHWRender::MRenderItem& renderItem, 161 | const unsigned int vertexOffset ); 162 | 163 | /** 164 | * Creates and populates an index buffer for the icon mesh 165 | */ 166 | void populate_icon_mesh_indices( const frantic::geometry::trimesh3& iconMesh, MHWRender::MGeometry& geometryData, 167 | const MHWRender::MRenderItem& renderItem, const unsigned int vertexOffset ); 168 | 169 | /** 170 | * Create and populates an index buffer for the particle array 171 | */ 172 | void populate_viewport_particle_indices( MHWRender::MGeometry& geometryData, 173 | const MHWRender::MRenderItem& renderItem ); 174 | }; 175 | 176 | // TOTAL HACK FOR BECAUSE FOR VIEWPORT 2.0 UPDATING ON OS X 177 | class ForceViewport20Update : public MPxCommand { 178 | public: 179 | static const MString commandName; 180 | static void* creator(); 181 | 182 | static void setPluginPath( const MString& path ); 183 | static const MString getPluginPath(); 184 | 185 | private: 186 | static MString s_pluginPath; 187 | 188 | public: 189 | MStatus doIt( const MArgList& args ); 190 | }; 191 | 192 | #endif 193 | -------------------------------------------------------------------------------- /src/KrakatoaParticleJitter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | 5 | #include "KrakatoaParticleJitter.hpp" 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | using namespace frantic; 22 | using namespace frantic::channels; 23 | using namespace frantic::graphics; 24 | using namespace frantic::particles; 25 | using namespace frantic::particles::streams; 26 | 27 | const MString krakatoaParticleJitter::commandName = "KrakatoaParticleJitter"; 28 | MString krakatoaParticleJitter::s_pluginPath; 29 | 30 | const char* radiusFlag = "-r"; 31 | const char* radiusLongFlag = "-radius"; 32 | const char* nodeFlag = "-n"; 33 | const char* nodeLongFlag = "-node"; 34 | const char* randomSeedFlag = "-s"; 35 | const char* randomSeedLongFlag = "-seed"; 36 | const char* minIdFlag = "-mId"; 37 | const char* minIdLongFlag = "-minId"; 38 | const char* channelFlag = "-c"; 39 | const char* channelLongFlag = "-channel"; 40 | 41 | void* krakatoaParticleJitter::creator() { return new krakatoaParticleJitter; } 42 | 43 | void krakatoaParticleJitter::setPluginPath( const MString& path ) { s_pluginPath = path; } 44 | 45 | const MString krakatoaParticleJitter::getPluginPath() { return s_pluginPath; } 46 | 47 | // a streamlined way of setting flags 48 | MSyntax krakatoaParticleJitter::newSyntax() { 49 | MSyntax syntax; 50 | syntax.addFlag( randomSeedFlag, randomSeedLongFlag, MSyntax::kLong ); 51 | syntax.addFlag( nodeFlag, nodeLongFlag, MSyntax::kString ); 52 | syntax.addFlag( radiusFlag, radiusLongFlag, MSyntax::kDouble ); 53 | syntax.addFlag( minIdFlag, minIdLongFlag, MSyntax::kLong ); 54 | syntax.addFlag( channelFlag, channelLongFlag, MSyntax::kString ); 55 | return syntax; 56 | } 57 | 58 | MStatus krakatoaParticleJitter::doIt( const MArgList& args ) { 59 | // create and set Default values 60 | MSelectionList selected; 61 | MString node; 62 | int randomSeed = 100; 63 | double radius = 5; 64 | int minId = -1; 65 | MString channel = "position"; 66 | 67 | MArgDatabase argData( syntax(), args ); 68 | // get all the data from the arguments fail if we are not given a node 69 | // we could change node from a flag 70 | if( argData.isFlagSet( nodeFlag ) ) { 71 | argData.getFlagArgument( nodeFlag, 0, node ); 72 | } else { 73 | FF_LOG( warning ) << "Error: No particle node given" << std::endl; 74 | return MStatus::kFailure; 75 | } 76 | 77 | if( argData.isFlagSet( randomSeedFlag ) ) { 78 | argData.getFlagArgument( randomSeedFlag, 0, randomSeed ); 79 | } 80 | 81 | if( argData.isFlagSet( radiusFlag ) ) { 82 | argData.getFlagArgument( radiusFlag, 0, radius ); 83 | } 84 | 85 | if( argData.isFlagSet( minIdFlag ) ) { 86 | argData.getFlagArgument( minIdFlag, 0, minId ); 87 | } 88 | if( argData.isFlagSet( channelFlag ) ) { 89 | argData.getFlagArgument( channelFlag, 0, channel ); 90 | } 91 | // add the node by name to a custom selection list without actually selecting it 92 | selected.add( node ); 93 | 94 | if( selected.length() == 0 ) { 95 | FF_LOG( warning ) << "No nodes found" << std::endl; 96 | return MStatus::kFailure; 97 | } else if( selected.length() > 1 ) { 98 | FF_LOG( warning ) << "Multiple nodes were found, please refine search to only include a single node." 99 | << std::endl; 100 | return MStatus::kFailure; 101 | } 102 | int maxid = minId; 103 | // currently set up so that only a single node can be passed to this point 104 | // however I am leaving it so that it can be modified to allow multiple later on 105 | for( unsigned int i = 0; i < selected.length(); ++i ) { 106 | MStatus stat; 107 | MObject obj; 108 | selected.getDependNode( i, obj ); 109 | MFnParticleSystem particlesTest( obj, &stat ); 110 | // try casting the mobject to a particle system 111 | if( stat != MS::kSuccess || !particlesTest.isValid() ) { 112 | // let the user know that this particlular node failed 113 | MFnDependencyNode depNode( obj ); 114 | FF_LOG( error ) << _T( "Node: " ) << frantic::strings::to_tstring( depNode.name().asChar() ) 115 | << " is not a valid particle node" << std::endl; 116 | return MStatus::kFailure; 117 | } 118 | 119 | // Positions/Velocities in the deformed shape appear to be readonly so lets alter the original shape 120 | MObject sourceObject = obj; 121 | if( particlesTest.isDeformedParticleShape( &stat ) ) { 122 | // WARNING: Maya crashes when it tries to read the particleIDs for deformers for some reason... 123 | sourceObject = particlesTest.originalParticleShape( &stat ); 124 | if( stat != MS::kSuccess || sourceObject == MObject::kNullObj ) 125 | sourceObject = obj; 126 | } 127 | MFnParticleSystem particles( sourceObject, &stat ); 128 | 129 | MVectorArray attribute; 130 | // creat random number generator 131 | boost::mt19937 gen( randomSeed ); 132 | boost::uniform_01 range; 133 | boost::variate_generator> rng( gen, range ); 134 | // get the data from the channel we are looking for 135 | if( channel == "position" ) { 136 | particles.position( attribute ); 137 | } else if( channel == "velocity" ) { 138 | particles.velocity( attribute ); 139 | } else if( channel == "acceleration" ) { 140 | particles.acceleration( attribute ); 141 | } else { 142 | FF_LOG( warning ) << "The channel specified is not supported. Currently supported channels are: position, " 143 | "velocity, and acceleration" 144 | << std::endl; 145 | return MStatus::kFailure; 146 | } 147 | 148 | MIntArray ids; 149 | particles.particleIds( ids ); 150 | // FF_LOG(error)<<"Particle Count: "< minId ) { 155 | // get the random adjustment and modify the attribute 156 | adjustment = frantic::graphics::vector3f::from_random_in_sphere( rng, (float)radius ); 157 | attribute[k].x += adjustment.x; 158 | attribute[k].y += adjustment.y; 159 | attribute[k].z += adjustment.z; 160 | 161 | // store the largest id we have found 162 | if( ids[k] > maxid ) { 163 | maxid = ids[k]; 164 | } 165 | } 166 | } 167 | 168 | // Maya seems to assume positions are in object space when you set the position. Need to transform it back. 169 | if( channel == "position" ) { 170 | MTime currentTime = MAnimControl::currentTime(); 171 | MDGContext currentContext( currentTime ); 172 | MDagPath particlesPath; 173 | particles.getPath( particlesPath ); 174 | frantic::graphics::transform4f objectSpace; 175 | frantic::maya::maya_util::get_object_world_matrix( particlesPath, currentContext, objectSpace ); 176 | objectSpace = objectSpace.to_inverse(); 177 | for( unsigned int k = 0; k < attribute.length(); k++ ) { 178 | frantic::graphics::vector3f fixedValue( (float)attribute[k].x, (float)attribute[k].y, 179 | (float)attribute[k].z ); 180 | fixedValue = objectSpace * fixedValue; 181 | attribute[k].x = fixedValue.x; 182 | attribute[k].y = fixedValue.y; 183 | attribute[k].z = fixedValue.z; 184 | } 185 | } 186 | 187 | // set the data 188 | particles.setPerParticleAttribute( channel, attribute, &stat ); 189 | if( stat != MS::kSuccess ) { 190 | // let the user know we failed on this node 191 | FF_LOG( error ) << "Failed to set attribute for node " 192 | << frantic::strings::to_tstring( particles.name().asChar() ) << std::endl; 193 | return MStatus::kFailure; 194 | } 195 | } 196 | // return the maximum id we found 197 | krakatoaParticleJitter::setResult( maxid ); 198 | return MStatus::kSuccess; 199 | } 200 | -------------------------------------------------------------------------------- /include/PRTLoader.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include "PRTObject.hpp" 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #if !( __APPLE__ && MAYA_API_VERSION >= 201800 ) 29 | class MIntArray; 30 | class MVectorArray; 31 | class MFnArrayAttrsData; 32 | #endif 33 | 34 | struct input_file_info { 35 | frantic::tstring baseName; 36 | bool singleFileOnly; 37 | bool inViewport; 38 | bool inRender; 39 | }; 40 | 41 | /** 42 | * Maya Plugin shape object that can be used to represent a set of PRT file sequences in the scene. 43 | */ 44 | class PRTLoader : public PRTObject { 45 | public: 46 | // Maya rtti and object creation information 47 | static void* creator(); 48 | static MStatus initialize(); 49 | static MTypeId typeId; 50 | static MString typeName; 51 | static const MString drawRegistrantId; 52 | 53 | public: 54 | PRTLoader(); 55 | virtual ~PRTLoader(); 56 | 57 | virtual void postConstructor(); 58 | 59 | // inherited from MPxSurfaceShape 60 | virtual MBoundingBox boundingBox() const; 61 | virtual bool isBounded() const; 62 | 63 | // inherited from MPxNode 64 | virtual MStatus compute( const MPlug& plug, MDataBlock& block ); 65 | virtual MStringArray getFilesToArchive( bool shortName = false, bool unresolvedName = false, 66 | bool markCouldBeImageSequence = false ) const; 67 | virtual MStatus setDependentsDirty( const MPlug& plug, MPlugArray& plugArray ); 68 | 69 | bool isSingleSimpleRenderFile( MTime currentTime, frantic::tstring& outFileName ) const; 70 | 71 | // inherited from PRTObject 72 | virtual PRTObject::particle_istream_ptr 73 | getRenderParticleStream( const frantic::graphics::transform4f& tm, 74 | const MDGContext& currentContext = MDGContext::fsNormal ) const; 75 | virtual PRTObject::particle_istream_ptr 76 | getViewportParticleStream( const frantic::graphics::transform4f& tm, 77 | const MDGContext& currentContext = MDGContext::fsNormal ) const; 78 | 79 | virtual frantic::particles::particle_array* getCachedViewportParticles(); 80 | virtual PRTObject::display_mode_t getViewportDisplayMode(); 81 | 82 | virtual const frantic::geometry::trimesh3& getRootMesh() const; 83 | 84 | private: 85 | // current time, as received from the global time node 86 | static MObject inTime; 87 | 88 | // the set of PRT files to be attached to this node 89 | static MObject inPRTFile; 90 | 91 | // boolean specifying if a given file is part of the viewport view or not 92 | static MObject inUseFileInViewport; 93 | 94 | // boolean specifying if a given file is part of the render or not 95 | static MObject inUseFileInRender; 96 | 97 | // boolean specifying if a given file is meant to be just a single loaded file, or part of a file sequence 98 | static MObject inSingleFileOnly; 99 | 100 | // test 101 | static MObject inInputFiles; 102 | 103 | // if 'single frame only' is selected, then by default the velocity channel will not be preserved 104 | static MObject inKeepVelocityChannel; 105 | 106 | // select if more complex sub-frame interpolation should be performed 107 | static MObject inInterpolateSubFrames; 108 | 109 | // playback time re-mapping graph 110 | static MObject inPlaybackGraph; 111 | 112 | // use custom playback graph 113 | static MObject inEnablePlaybackGraph; 114 | 115 | // set a global frame offset for loading from the particle sequences 116 | static MObject inFrameOffset; 117 | 118 | // set whether to limit playback to a specific range of frames 119 | static MObject inUseCustomRange; 120 | 121 | // set the low end of the custom range 122 | static MObject inCustomRangeStart; 123 | 124 | // set the high end of the custom range 125 | static MObject inCustomRangeEnd; 126 | 127 | // set how to handle frames before the start of the custom range 128 | static MObject inCustomRangeStartClampMode; 129 | 130 | // set how to handle frames after the end of the custom range 131 | static MObject inCustomRangeEndClampMode; 132 | 133 | // viewport particle loading mode 134 | static MObject inViewportLoadMode; 135 | 136 | // viewport particle hard limit (this value, x1000) 137 | static MObject inViewportParticleLimit; 138 | 139 | // enable particle hard limit in viewport 140 | static MObject inEnableViewportParticleLimit; 141 | 142 | // percent of total number of particles to load in viewport 143 | static MObject inViewportParticlePercent; 144 | 145 | // How to represent each particle (dot, velocity, etc..) 146 | static MObject inViewportDisplayMode; 147 | 148 | // render particle loading mode 149 | static MObject inRenderLoadMode; 150 | 151 | // render particle hard limit (this value, x1000) 152 | static MObject inRenderParticleLimit; 153 | 154 | // enable particle hard limit in render 155 | static MObject inEnableRenderParticleLimit; 156 | 157 | // percent of total number of particles to load in render 158 | static MObject inRenderParticlePercent; 159 | 160 | // a dummy output parameter that forces read-through of the input attributes 161 | static MObject outSentinel; 162 | 163 | // the total number of particles in all referenced files 164 | static MObject outNumParticlesOnDisk; 165 | 166 | // the total number of particles that will be included in the render 167 | static MObject outNumParticlesInRender; 168 | 169 | // the total number of particles that will be displayed in the viewport 170 | static MObject outNumParticlesInViewport; 171 | 172 | // a hidden output parameter that can be used when optimizing render output 173 | // A non-empty string value indicates that the entire output render can be 174 | // represented by that filename. 175 | static MObject outSingleSimpleRenderFile; 176 | 177 | // output particle stream 178 | static MObject outParticleStream; 179 | 180 | static boost::unordered_set viewportInputDependencies; 181 | 182 | private: 183 | particle_istream_ptr getParticleStream( const MDGContext& currentContext, 184 | krakatoa::enabled_mode::enabled_mode_enum mode ) const; 185 | 186 | void touchSentinelOutput() const; 187 | void cacheParticlesAt( MTime time ); 188 | void cacheBoundingBox(); 189 | 190 | MStatus getCurrentTime( MDataBlock& block, MTime& outTime ) const; 191 | 192 | MStatus getInputFiles( std::vector& outFiles ) const; 193 | 194 | int getFrameOffset() const; 195 | bool interpolateSubFrames() const; 196 | bool useCustomRange() const; 197 | bool keepVelocityChannel() const; 198 | 199 | int getRangeStart() const; 200 | int getRangeEnd() const; 201 | krakatoa::clamp_mode::clamp_mode_enum getRangeStartClampMode() const; 202 | krakatoa::clamp_mode::clamp_mode_enum getRangeEndClampMode() const; 203 | 204 | MTime getEffectivePlaybackTime( MTime atTime ) const; 205 | 206 | krakatoa::viewport::RENDER_LOAD_PARTICLE_MODE getViewportLoadMode() const; 207 | double getViewportParticleFraction( const MDGContext& context = MDGContext::fsNormal ) const; 208 | boost::int64_t getViewportParticleLimit() const; 209 | 210 | // This calls take into account possibly using the render mode for the viewport mode 211 | krakatoa::render::RENDER_LOAD_PARTICLE_MODE getEffectiveViewportLoadMode() const; 212 | 213 | krakatoa::render::RENDER_LOAD_PARTICLE_MODE getRenderLoadMode() const; 214 | double getRenderParticleFraction( const MDGContext& context = MDGContext::fsNormal ) const; 215 | boost::int64_t getRenderParticleLimit() const; 216 | 217 | int getIntAttribute( MObject attribute, const MDGContext& context = MDGContext::fsNormal, 218 | MStatus* outStatus = NULL ) const; 219 | double getDoubleAttribute( MObject attribute, const MDGContext& context = MDGContext::fsNormal, 220 | MStatus* outStatus = NULL ) const; 221 | bool getBooleanAttribute( MObject attribute, const MDGContext& context = MDGContext::fsNormal, 222 | MStatus* outStatus = NULL ) const; 223 | MTime getTimeAttribute( MObject attribute, const MDGContext& context = MDGContext::fsNormal, 224 | MStatus* outStatus = NULL ) const; 225 | 226 | // return channel map for displaying viewport based on the channel map of inputStream 227 | // "Position", "Velocity", "Normal", "Color", "Tangent" will be returned if inputStream have these channels 228 | frantic::channels::channel_map 229 | get_viewport_channel_map( boost::shared_ptr inputStream ) const; 230 | 231 | private: 232 | frantic::particles::particle_array m_cachedParticles; 233 | MBoundingBox m_boundingBox; 234 | bool m_osxViewport20HackInitialized; 235 | }; 236 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to KrakatoaMY 2 | 3 | Thanks for your interest in contributing to KrakatoaMY! ❤️ 4 | 5 | This document describes how to set up a development environment and submit your contributions. Please read it carefully 6 | and let us know if it's not up-to-date (even better, submit a PR with your corrections ;-)). 7 | 8 | - [Prerequisites](#prerequisites) 9 | - [Building](#building) 10 | - [Testing](#testing) 11 | - [Publishing to Local Conan Cache](#publishing-to-local-conan-cache) 12 | - [Building Multiple Configurations](#building-multiple-configurations) 13 | - [Pull Requests](#pull-requests) 14 | - [Pull Request Checklist](#pull-request-checklist) 15 | - [Step 1: Open Issue](#step-1-open-issue) 16 | - [Step 2: Design (optional)](#step-2-design-optional) 17 | - [Step 3: Work your Magic](#step-3-work-your-magic) 18 | - [Step 4: Commit](#step-4-commit) 19 | - [Step 5: Pull Request](#step-5-pull-request) 20 | - [Step 6: Merge](#step-6-merge) 21 | 22 | ## Prerequisites 23 | 24 | You will need Python 3.10 or later and the C++ compiler for your platform installed before you are able to build KrakatoaMY. The compilers used for each platform are as follows: 25 | 26 | * Windows: Visual C++ 14.1 (Visual Studio 2017) or later 27 | * macOS: Clang 10.0 or later 28 | * Linux: GCC 7 or later 29 | 30 | You will then need to install Conan. You can do this by running: 31 | 32 | ```bash 33 | pip install conan conan_package_tools 34 | ``` 35 | 36 | Conan is a C++ package manager that is used to install the 3rd party dependencies. 37 | 38 | KrakatoaMY uses the C++17 standard. 39 | 40 | ## Dependencies 41 | 42 | You will need to build the following dependencies to your local Conan cache: 43 | 44 | * https://github.com/aws/thinkbox-cm-library 45 | * https://github.com/aws/thinkbox-library 46 | * https://github.com/aws/thinkbox-node-view 47 | * https://github.com/aws/thinkbox-my-library 48 | * https://github.com/aws/thinkbox-magma (Both MagmaCore and MagmaMY) 49 | * https://github.com/aws/thinkbox-krakatoa (Both Krakatoa and KrakatoaSR) 50 | 51 | Please see the instructions in the linked repositories for detailed instructions for building these packages. 52 | 53 | ## Building 54 | 55 | From the project root directory run the following commands to install the dependencies and build KrakatoaMY: 56 | 57 | ```bash 58 | conan install . --install-folder build 59 | conan build . --build-folder build 60 | ``` 61 | 62 | If you wish to generate a development environment without building the package immediately, you can add `--configure` to the `conan build` command. 63 | 64 | If you are using Windows, once run, you can open `build/KrakatoaMY.sln` in Visual Studio to use Visual Studio for development and debugging. 65 | 66 | ### Publishing to Local Conan Cache 67 | 68 | If you need to publish build artifacts to your local Conan cache manually, after completing the [building](#building) steps, you can run the following commands to package KrakatoaMY and publish it to your local Conan cache: 69 | 70 | ```bash 71 | conan package . --install-folder build --build-folder build --package-folder build/package 72 | conan export-pkg . --package-folder build/package 73 | ``` 74 | 75 | ### Building Multiple Configurations 76 | 77 | To quickly build all supported configurations on the current platform you can run: 78 | 79 | ``` 80 | python build.py 81 | ``` 82 | 83 | This will build the configurations and publish them to your local conan cache. You can add the `--dry-run` flag to preview the configurations that will be built without building them. 84 | 85 | ## Installation 86 | 87 | In order to run the KrakatoaMY plugin that you built, you will need to run perform the following setup on you machine. We will assume that you already 88 | have the correct version of Maya installed for the plugin you have built. 89 | 90 | __Warning__: The code in these files and directories will be executed when the plugin is run. As such it is crucial that the permissions of these files are set such that they cannot be written to without elevated privlidges. 91 | 92 | Create the following directory structure somewhere on your system: 93 | 94 | ``` 95 | Installation Root/ 96 | ├─ Maya####_x64/ 97 | │ ├─ icons/ 98 | │ ├─ plug-ins/ 99 | │ │ ├─ MayaKrakatoa.mll 100 | │ ├─ scripts/ 101 | ├─ renderDesc/ 102 | │ ├─ kmyRenderer.xml 103 | ├─ Legal/ 104 | │ ├─ third_party_licenses.txt 105 | ``` 106 | 107 | * The `####` in `Maya####_x64/` should be substituted for the Maya version you built the plugin for 108 | * `MayaKrakatoa.mll` can be found in `build/Release` after it has been built using the above instructions 109 | * On Linux, the `.mll` extension will be replaced with `.so` and on macOS it will be replaced with `.bundle` 110 | * `kmyRenderer.xml` can be found in the project root directory 111 | * `third_party_licenses.txt` can be found in the project root directory after the plugin as been built 112 | * Copy the contents of the `icons/` directory in the project root directory to the `icons/` directory in the installation directory 113 | * Copy the contents of the `scripts/` directory in the project root directory to the `scripts/` directory in the installation directory 114 | 115 | Finally, in the `modules/` directory within your Maya installation, create a file called `KrakatoaForMaya.module` with the following contents: 116 | 117 | ``` 118 | + MayaKrakatoa 1.0 /path/to/Maya####_x64 119 | ``` 120 | 121 | Where the path is substituted for the absolute path to the `Maya####_x64/` directory you created earlier. 122 | 123 | Once this is complete, you should be able to load KrakatoaMY as a plugin in Maya. You will need to repeat this process for any additional versions of Maya that you wish to use the plugin for. 124 | 125 | ### Pull Requests 126 | 127 | #### Pull Request Checklist 128 | 129 | - Testing 130 | - Unit test added (prefer not to modify an existing test, otherwise, it's probably a breaking change) 131 | - Title and Description 132 | - __Change type__: title prefixed with **fix**, **feat** and module name in parens, which will appear in changelog 133 | - __Title__: use lower-case and doesn't end with a period 134 | - __Breaking?__: last paragraph: "BREAKING CHANGE: " 135 | - __Issues__: Indicate issues fixed via: "**Fixes #xxx**" or "**Closes #xxx**" 136 | 137 | #### Step 1: Open Issue 138 | 139 | If there isn't one already, open an issue describing what you intend to contribute. It's useful to communicate in 140 | advance, because sometimes, someone is already working in this space, so maybe it's worth collaborating with them 141 | instead of duplicating the efforts. 142 | 143 | #### Step 2: Design (optional) 144 | 145 | In some cases, it is useful to seek for feedback by iterating on a design document. This is useful 146 | when you plan a big change or feature, or you want advice on what would be the best path forward. 147 | 148 | Sometimes, the GitHub issue is sufficient for such discussions, and can be sufficient to get 149 | clarity on what you plan to do. Sometimes, a design document would work better, so people can provide 150 | iterative feedback. 151 | 152 | In such cases, use the GitHub issue description to collect **requirements** and 153 | **use cases** for your feature. 154 | 155 | #### Step 3: Work your Magic 156 | 157 | Work your magic. Here are some guidelines: 158 | 159 | - Coding style: 160 | - Code should conform to the style defined in .clang-format 161 | - Every change requires a unit test 162 | - Try to maintain a single feature/bugfix per pull request. It's okay to introduce a little bit of housekeeping 163 | changes along the way, but try to avoid conflating multiple features. Eventually all these are going to go into a 164 | single commit, so you can use that to frame your scope. 165 | 166 | #### Step 4: Commit 167 | 168 | Create a commit with the proposed changes: 169 | 170 | - Commit title and message (and PR title and description) must adhere to [conventionalcommits](https://www.conventionalcommits.org). 171 | - The title must begin with `feat: title`, `fix: title`, `refactor: title` or 172 | `chore: title`. 173 | - Title should be lowercase. 174 | - No period at the end of the title. 175 | 176 | - Commit message should describe _motivation_. Think about your code reviewers and what information they need in 177 | order to understand what you did. If it's a big commit (hopefully not), try to provide some good entry points so 178 | it will be easier to follow. 179 | 180 | - Commit message should indicate which issues are fixed: `fixes #` or `closes #`. 181 | 182 | - Shout out to collaborators. 183 | 184 | - If not obvious (i.e. from unit tests), describe how you verified that your change works. 185 | 186 | - If this commit includes breaking changes, they must be listed at the end in the following format (notice how multiple breaking changes should be formatted): 187 | 188 | ``` 189 | BREAKING CHANGE: Description of what broke and how to achieve this behavior now 190 | - **module-name:** Another breaking change 191 | - **module-name:** Yet another breaking change 192 | ``` 193 | 194 | #### Step 5: Pull Request 195 | 196 | - Push to a personal GitHub fork. 197 | - Submit a Pull Request on GitHub. A reviewer will later be assigned by the maintainers. 198 | - Please follow the PR checklist written above. We trust our contributors to self-check, and this helps that process! 199 | - Discuss review comments and iterate until you get at least one "Approve". When iterating, push new commits to the 200 | same branch. Usually all these are going to be squashed when you merge to master. The commit messages should be hints 201 | for you when you finalize your merge commit message. 202 | - Make sure to update the PR title/description if things change. The PR title/description are going to be used as the 203 | commit title/message and will appear in the CHANGELOG, so maintain them all the way throughout the process. 204 | 205 | #### Step 6: Merge 206 | 207 | - Make sure your PR builds successfully 208 | - Once approved and tested, a maintainer will squash-merge to master and will use your PR title/description as the 209 | commit message. 210 | -------------------------------------------------------------------------------- /include/PRTVolume.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #pragma once 4 | 5 | #include "PRTObject.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #if !( __APPLE__ && MAYA_API_VERSION >= 201800 ) 32 | class MIntArray; 33 | class MVectorArray; 34 | class MFnArrayAttrsData; 35 | #endif 36 | 37 | /** 38 | * Maya Plugin shape object that can be used to represent a cloud of particles generated from the internal volume of a 39 | * mesh 40 | */ 41 | class PRTVolume : public PRTObject { 42 | public: 43 | typedef boost::shared_ptr level_set_ptr; 44 | typedef boost::shared_ptr level_set_sampler_ptr; 45 | 46 | public: 47 | // Maya rtti and object creation information 48 | static void* creator(); 49 | static MStatus initialize(); 50 | static MTypeId typeId; 51 | static MString typeName; 52 | static const MString drawRegistrantId; 53 | 54 | public: 55 | PRTVolume(); 56 | virtual ~PRTVolume(); 57 | 58 | virtual void postConstructor(); 59 | 60 | // inherited from MPxSurfaceShape 61 | virtual MBoundingBox boundingBox() const; 62 | virtual bool isBounded() const; 63 | 64 | // inherited from MPxNode 65 | virtual MStatus compute( const MPlug& plug, MDataBlock& block ); 66 | virtual MStatus setDependentsDirty( const MPlug& plug, MPlugArray& plugArray ); 67 | 68 | // inherited from PRTObject 69 | virtual PRTObject::particle_istream_ptr getRenderParticleStream( const frantic::graphics::transform4f& tm, 70 | const MDGContext& currentContext ) const; 71 | virtual PRTObject::particle_istream_ptr getViewportParticleStream( const frantic::graphics::transform4f& tm, 72 | const MDGContext& currentContext ) const; 73 | 74 | virtual frantic::particles::particle_array* getCachedViewportParticles(); 75 | virtual PRTObject::display_mode_t getViewportDisplayMode(); 76 | 77 | virtual const frantic::geometry::trimesh3& getRootMesh() const; 78 | 79 | private: 80 | // The mesh from which the particle volume is calculated 81 | static MObject inMesh; 82 | 83 | // The 'worldMatrix' of the mesh used by the source object 84 | static MObject inMeshTransform; 85 | 86 | // The 'worldMatrix' of this object (For some reason, MFnAttribute::setWorldSpace does not work so this is used as a 87 | // work around) 88 | static MObject inCurrentTransform; 89 | 90 | // boolean that states if the volume should be rendered in object or world-space 91 | static MObject inUseWorldSpace; 92 | 93 | // The sampling spacing between particles to use in the render 94 | static MObject inRenderSpacing; 95 | 96 | // Specify whether to use the custom spacing in the viewport, or just use the default render spacing 97 | static MObject inUseCustomViewportSpacing; 98 | 99 | // the spacing spacing between particles to use in the viewport 100 | // typically this is set to a higher value in order to retain the shape of the object while reducing viewport render 101 | // load 102 | static MObject inViewportSpacing; 103 | 104 | // Define whether to use multiple subdivisions 105 | static MObject inSubdivideVoxel; 106 | 107 | // Number of subdivisions to use if enabled 108 | static MObject inNumSubdivisions; 109 | 110 | // Specify whether the particles should be affected by random jitter, or distributed uniformly 111 | static MObject inRandomJitter; 112 | 113 | // If random jitter is enabled, this helps ensure that the volume is well-filled (lessens possible gaps and such) 114 | static MObject inJitterWellDistributed; 115 | 116 | // I have no idea what this is supposed to do 117 | static MObject inJitterMultiplePerVoxel; 118 | 119 | // I have no idea what this is supposed to do 120 | static MObject inJitterCountPerVoxel; 121 | 122 | // This integer defines the seed for the random jitter. 123 | static MObject inRandomSeed; 124 | 125 | // I gather this is how many times the random generator is called with the given seed when generating the volume 126 | static MObject inNumDistinctRandomValues; 127 | 128 | // use density compensation 129 | static MObject inUseDensityCompensation; 130 | 131 | // whether to show the volume particles in the viewport at all 132 | static MObject inEnableInViewport; 133 | 134 | // Disable subdivisions in the viewport 135 | static MObject inViewportDisableSubdivision; 136 | 137 | // Percentage of the total number of particles to display in the viewport 138 | static MObject inViewportParticlePercent; 139 | 140 | // Enable/disable the control over viewport load limit 141 | static MObject inEnableViewportParticleLimit; 142 | 143 | // Maximum number of particles to display in the viewport 144 | static MObject inViewportParticleLimit; 145 | 146 | // Whether or not to use a 'surface shell', rather than just fill the entire volume 147 | static MObject inUseSurfaceShell; 148 | 149 | // The distance from the object surface at which to start emitting particles 150 | static MObject inSurfaceShellStart; 151 | 152 | // The thickness of the surface 153 | static MObject inSurfaceShellThickness; 154 | 155 | // The rendering method to use when displaying the particles in the viewport 156 | static MObject inViewportDisplayMode; 157 | 158 | // This acts as a proxy to determine if the level-set needs to be recomputed, based on whether 159 | // the input mesh attribute has changed 160 | static MObject outViewportMeshLevelSetProxy; 161 | 162 | // This acts as a proxy to determine if the level-set needs to be recomputed 163 | static MObject outViewportLevelSetSamplerProxy; 164 | 165 | // This acts as a proxy to determine if the subdivisions for the level set sampler need to be recomputed 166 | static MObject outViewportLevelSetSamplerSubdivisionsProxy; 167 | 168 | // a dummy output parameter that forces read-through of the input attributes 169 | // This can be thought of as the proxy for the cached particle array on this object 170 | static MObject outViewportParticleCacheProxy; 171 | 172 | static MObject outRenderMeshLevelSetProxy; 173 | static MObject outRenderLevelSetSamplerProxy; 174 | static MObject outRenderLevelSetSamplerSubdivisionsProxy; 175 | 176 | // output particle stream 177 | static MObject outParticleStream; 178 | 179 | static boost::unordered_set viewportInputDependencies; 180 | 181 | private: 182 | void touchSentinelOutput( MObject sentinelAttribute ) const; 183 | void cacheViewportParticles(); 184 | PRTObject::particle_istream_ptr buildParticleStream( level_set_ptr levelSet, level_set_sampler_ptr sampler ) const; 185 | level_set_ptr buildLevelSet( MDataBlock& inputDataBlock, bool viewportMode ) const; 186 | level_set_sampler_ptr buildLevelSetSampler( bool viewportMode ) const; 187 | void cacheBoundingBox(); 188 | 189 | double getViewportSpacing() const; 190 | double getRenderSpacing() const; 191 | 192 | double getViewportParticleFraction() const; 193 | boost::int64_t getViewportParticleLimit() const; 194 | 195 | bool inWorldSpace() const; 196 | frantic::graphics::transform4f getWorldSpaceTransform( const MDGContext& context, bool* isOK = NULL ) const; 197 | int getViewportSubdivisionCount() const; 198 | int getRenderSubdivisionCount() const; 199 | bool isJitterEnabled() const; 200 | int getViewportJitterPerVoxelCount() const; 201 | int getRenderJitterPerVoxelCount() const; 202 | bool isMultipleJitterEnabled() const; 203 | int getRandomSeed() const; 204 | int getRandomCount() const; 205 | bool isJitterWellDistributed() const; 206 | bool useDensityCompensation() const; 207 | 208 | double getShellStart() const; 209 | double getShellThickness() const; 210 | 211 | level_set_ptr getCachedViewportLevelSet(); 212 | level_set_sampler_ptr getCachedViewportLevelSetSampler(); 213 | 214 | int getIntAttribute( MObject attribute, MDGContext& context = MDGContext::fsNormal, 215 | MStatus* outStatus = NULL ) const; 216 | double getDoubleAttribute( MObject attribute, MDGContext& context = MDGContext::fsNormal, 217 | MStatus* outStatus = NULL ) const; 218 | bool getBooleanAttribute( MObject attribute, MDGContext& context = MDGContext::fsNormal, 219 | MStatus* outStatus = NULL ) const; 220 | 221 | // return channel map for displaying viewport based on the channel map of inputStream 222 | // "Position", "Velocity", "Normal", "Color" will be returned if inputStream have these channels 223 | frantic::channels::channel_map 224 | get_viewport_channel_map( boost::shared_ptr inputStream ) const; 225 | 226 | private: 227 | frantic::particles::particle_array m_cachedParticles; 228 | MBoundingBox m_boundingBox; 229 | bool lastWorldSpaceState; 230 | level_set_ptr m_cachedMeshLevelSet; 231 | level_set_sampler_ptr m_cachedLevelSetSampler; 232 | level_set_ptr m_cachedRenderMeshLevelSet; 233 | level_set_sampler_ptr m_cachedRenderLevelSetSampler; 234 | bool m_osxViewport20HackInitialized; 235 | }; 236 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/PRTVolumeIconMesh.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | 5 | #include "PRTIconMesh.hpp" 6 | #include "PRTVolumeIconMesh.hpp" 7 | 8 | namespace { 9 | 10 | float vertices[] = { 11 | -0.382369f, 0.0f, 0.368268f, -0.384947f, 0.0f, 0.360952f, -0.389152f, 0.0f, 0.354901f, 12 | -0.394895f, 0.0f, 0.350044f, -0.400727f, 0.0f, 0.346946f, -0.407375f, 0.0f, 0.344732f, 13 | -0.415235f, 0.0f, 0.343405f, -0.424704f, 0.0f, 0.342962f, -0.47043f, 0.0f, 0.342962f, 14 | -0.47043f, 0.0f, 0.450602f, -0.44271f, 0.0f, 0.450602f, -0.44271f, 0.0f, 0.415502f, 15 | -0.425399f, 0.0f, 0.415502f, -0.414563f, 0.0f, 0.414689f, -0.405664f, 0.0f, 0.412251f, 16 | -0.398104f, 0.0f, 0.408223f, -0.391286f, 0.0f, 0.40264f, -0.387123f, 0.0f, 0.397395f, 17 | -0.384045f, 0.0f, 0.391046f, -0.382144f, 0.0f, 0.384064f, -0.38151f, 0.0f, 0.37692f, 18 | -0.410608f, 0.0f, 0.381884f, -0.411504f, 0.0f, 0.385411f, -0.413068f, 0.0f, 0.388366f, 19 | -0.415372f, 0.0f, 0.390876f, -0.418853f, 0.0f, 0.393018f, -0.423074f, 0.0f, 0.394304f, 20 | -0.42829f, 0.0f, 0.394948f, -0.434753f, 0.0f, 0.395162f, -0.44271f, 0.0f, 0.395162f, 21 | -0.44271f, 0.0f, 0.363302f, -0.437937f, 0.0f, 0.363302f, -0.426944f, 0.0f, 0.363481f, 22 | -0.422768f, 0.0f, 0.364043f, -0.418483f, 0.0f, 0.365375f, -0.415428f, 0.0f, 0.367151f, 23 | -0.412769f, 0.0f, 0.36991f, -0.410925f, 0.0f, 0.373472f, -0.41031f, 0.0f, 0.37766f, 24 | -0.306744f, 0.0f, 0.3799f, -0.307747f, 0.0f, 0.383051f, -0.309474f, 0.0f, 0.385628f, 25 | -0.311979f, 0.0f, 0.38797f, -0.315378f, 0.0f, 0.389855f, -0.319499f, 0.0f, 0.390915f, 26 | -0.324525f, 0.0f, 0.3914f, -0.330637f, 0.0f, 0.391562f, -0.33917f, 0.0f, 0.391562f, 27 | -0.33917f, 0.0f, 0.362762f, -0.329118f, 0.0f, 0.362762f, -0.320368f, 0.0f, 0.363014f, 28 | -0.316843f, 0.0f, 0.363489f, -0.313787f, 0.0f, 0.364413f, -0.310334f, 0.0f, 0.366371f, 29 | -0.308074f, 0.0f, 0.36894f, -0.306826f, 0.0f, 0.3721f, -0.30641f, 0.0f, 0.375834f, 30 | -0.299027f, 0.0f, 0.404528f, -0.289906f, 0.0f, 0.398903f, -0.283163f, 0.0f, 0.392012f, 31 | -0.278998f, 0.0f, 0.383385f, -0.27761f, 0.0f, 0.372552f, -0.278507f, 0.0f, 0.364603f, 32 | -0.281197f, 0.0f, 0.358119f, -0.285409f, 0.0f, 0.352901f, -0.290871f, 0.0f, 0.34875f, 33 | -0.297104f, 0.0f, 0.345766f, -0.30377f, 0.0f, 0.344048f, -0.311325f, 0.0f, 0.343233f, 34 | -0.320222f, 0.0f, 0.342962f, -0.36689f, 0.0f, 0.342962f, -0.36689f, 0.0f, 0.450602f, 35 | -0.33917f, 0.0f, 0.450602f, -0.33917f, 0.0f, 0.411182f, -0.32639f, 0.0f, 0.411182f, 36 | -0.297064f, 0.0f, 0.450602f, -0.26303f, 0.0f, 0.450602f, -0.17173f, 0.0f, 0.342962f, 37 | -0.26677f, 0.0f, 0.342962f, -0.26677f, 0.0f, 0.363842f, -0.23311f, 0.0f, 0.363842f, 38 | -0.23311f, 0.0f, 0.450602f, -0.20539f, 0.0f, 0.450602f, -0.20539f, 0.0f, 0.363842f, 39 | -0.17173f, 0.0f, 0.363842f, -0.0416084f, 0.0f, 0.342962f, -0.0676774f, 0.0f, 0.418652f, 40 | -0.0937465f, 0.0f, 0.342962f, -0.12287f, 0.0f, 0.342962f, -0.0836074f, 0.0f, 0.450602f, 41 | -0.0525124f, 0.0f, 0.450602f, -0.0132499f, 0.0f, 0.342962f, 0.0760434f, 0.0f, 0.392143f, 42 | 0.0673232f, 0.0f, 0.378466f, 0.053279f, 0.0f, 0.369793f, 0.0344f, 0.0f, 0.366902f, 43 | 0.0157022f, 0.0f, 0.369775f, 0.00162179f, 0.0f, 0.378394f, -0.007207f, 0.0f, 0.392053f, 44 | -0.0101499f, 0.0f, 0.410049f, -0.00722527f, 0.0f, 0.427945f, 0.00154868f, 0.0f, 0.441595f, 45 | 0.0156108f, 0.0f, 0.45024f, 0.0344f, 0.0f, 0.453122f, 0.0531893f, 0.0f, 0.45024f, 46 | 0.0672515f, 0.0f, 0.441595f, 0.0760254f, 0.0f, 0.427945f, 0.0789501f, 0.0f, 0.410049f, 47 | 0.0443813f, 0.0f, 0.432154f, 0.041399f, 0.0f, 0.433751f, 0.0380897f, 0.0f, 0.434644f, 48 | 0.0346167f, 0.0f, 0.434942f, 0.0307111f, 0.0f, 0.434617f, 0.0272577f, 0.0f, 0.433643f, 49 | 0.0242572f, 0.0f, 0.431965f, 0.0217101f, 0.0f, 0.429531f, 0.0196067f, 0.0f, 0.426094f, 50 | 0.0180833f, 0.0f, 0.421701f, 0.0171584f, 0.0f, 0.416388f, 0.0168501f, 0.0f, 0.410192f, 51 | 0.0172037f, 0.0f, 0.403392f, 0.0182648f, 0.0f, 0.397854f, 0.0199241f, 0.0f, 0.39347f, 52 | 0.0220729f, 0.0f, 0.390133f, 0.0248193f, 0.0f, 0.387607f, 0.0276923f, 0.0f, 0.386092f, 53 | 0.0308373f, 0.0f, 0.385334f, 0.0344f, 0.0f, 0.385082f, 0.0380444f, 0.0f, 0.385389f, 54 | 0.0414341f, 0.0f, 0.386308f, 0.0444618f, 0.0f, 0.387968f, 0.0470198f, 0.0f, 0.390493f, 55 | 0.0490862f, 0.0f, 0.393866f, 0.0506451f, 0.0f, 0.398214f, 0.0516238f, 0.0f, 0.403626f, 56 | 0.0519501f, 0.0f, 0.410192f, 0.051633f, 0.0f, 0.417074f, 0.0506817f, 0.0f, 0.422279f, 57 | 0.0490954f, 0.0f, 0.426329f, 0.0468735f, 0.0f, 0.429747f, 0.11859f, 0.0f, 0.338102f, 58 | 0.0924901f, 0.0f, 0.338102f, 0.0924901f, 0.0f, 0.450602f, 0.11859f, 0.0f, 0.450602f, 59 | 0.21907f, 0.0f, 0.369422f, 0.19297f, 0.0f, 0.369422f, 0.19297f, 0.0f, 0.426867f, 60 | 0.18914f, 0.0f, 0.428961f, 0.185165f, 0.0f, 0.430476f, 0.181299f, 0.0f, 0.431395f, 61 | 0.177794f, 0.0f, 0.431702f, 0.173359f, 0.0f, 0.431395f, 0.170026f, 0.0f, 0.430476f, 62 | 0.167596f, 0.0f, 0.428888f, 0.165872f, 0.0f, 0.426578f, 0.164688f, 0.0f, 0.423556f, 63 | 0.164028f, 0.0f, 0.41983f, 0.16373f, 0.0f, 0.415238f, 0.16363f, 0.0f, 0.409618f, 64 | 0.16363f, 0.0f, 0.369422f, 0.13753f, 0.0f, 0.369422f, 0.13753f, 0.0f, 0.422213f, 65 | 0.139344f, 0.0f, 0.435466f, 0.144785f, 0.0f, 0.445035f, 0.153583f, 0.0f, 0.45083f, 66 | 0.165467f, 0.0f, 0.452762f, 0.173191f, 0.0f, 0.452049f, 0.17976f, 0.0f, 0.449909f, 67 | 0.186058f, 0.0f, 0.446397f, 0.19297f, 0.0f, 0.441568f, 0.19297f, 0.0f, 0.450602f, 68 | 0.21907f, 0.0f, 0.450602f, 0.322069f, 0.0f, 0.390757f, 0.325521f, 0.0f, 0.389264f, 69 | 0.328665f, 0.0f, 0.388423f, 0.331883f, 0.0f, 0.388142f, 0.336184f, 0.0f, 0.38844f, 70 | 0.339401f, 0.0f, 0.389336f, 0.341713f, 0.0f, 0.390883f, 0.343302f, 0.0f, 0.393137f, 71 | 0.344342f, 0.0f, 0.396122f, 0.344857f, 0.0f, 0.399867f, 0.34511f, 0.0f, 0.410001f, 72 | 0.34511f, 0.0f, 0.450602f, 0.37121f, 0.0f, 0.450602f, 0.37121f, 0.0f, 0.397696f, 73 | 0.369505f, 0.0f, 0.384597f, 0.364388f, 0.0f, 0.374971f, 0.355988f, 0.0f, 0.369054f, 74 | 0.34443f, 0.0f, 0.367082f, 0.337282f, 0.0f, 0.368023f, 0.32999f, 0.0f, 0.370845f, 75 | 0.322519f, 0.0f, 0.375314f, 0.314831f, 0.0f, 0.381195f, 0.310698f, 0.0f, 0.375089f, 76 | 0.305229f, 0.0f, 0.370665f, 0.298622f, 0.0f, 0.367978f, 0.291076f, 0.0f, 0.367082f, 77 | 0.283965f, 0.0f, 0.367824f, 0.277502f, 0.0f, 0.370049f, 0.27122f, 0.0f, 0.373596f, 78 | 0.26465f, 0.0f, 0.378301f, 0.26465f, 0.0f, 0.369422f, 0.23855f, 0.0f, 0.369422f, 79 | 0.23855f, 0.0f, 0.450602f, 0.26465f, 0.0f, 0.450602f, 0.26465f, 0.0f, 0.392991f, 80 | 0.267722f, 0.0f, 0.3913f, 0.271155f, 0.0f, 0.389699f, 0.274824f, 0.0f, 0.388531f, 81 | 0.278603f, 0.0f, 0.388142f, 0.28284f, 0.0f, 0.38844f, 0.286011f, 0.0f, 0.389336f, 82 | 0.288315f, 0.0f, 0.390883f, 0.289951f, 0.0f, 0.393137f, 0.290998f, 0.0f, 0.396131f, 83 | 0.29154f, 0.0f, 0.399902f, 0.291758f, 0.0f, 0.404508f, 0.29183f, 0.0f, 0.410001f, 84 | 0.29183f, 0.0f, 0.450602f, 0.31793f, 0.0f, 0.450602f, 0.31793f, 0.0f, 0.392991f, 85 | 0.47043f, 0.0f, 0.405684f, 0.467932f, 0.0f, 0.389101f, 0.460436f, 0.0f, 0.376905f, 86 | 0.447979f, 0.0f, 0.369403f, 0.430597f, 0.0f, 0.366902f, 0.411377f, 0.0f, 0.369838f, 87 | 0.396738f, 0.0f, 0.378647f, 0.387477f, 0.0f, 0.392478f, 0.38439f, 0.0f, 0.410482f, 88 | 0.387652f, 0.0f, 0.42846f, 0.397439f, 0.0f, 0.441776f, 0.413351f, 0.0f, 0.450016f, 89 | 0.43499f, 0.0f, 0.452762f, 0.44407f, 0.0f, 0.452363f, 0.452316f, 0.0f, 0.451166f, 90 | 0.460399f, 0.0f, 0.44908f, 0.46899f, 0.0f, 0.446015f, 0.46899f, 0.0f, 0.425042f, 91 | 0.466076f, 0.0f, 0.425042f, 0.46074f, 0.0f, 0.428407f, 0.453765f, 0.0f, 0.43155f, 92 | 0.445842f, 0.0f, 0.433824f, 0.437665f, 0.0f, 0.434582f, 0.426144f, 0.0f, 0.433308f, 93 | 0.417811f, 0.0f, 0.429486f, 0.412611f, 0.0f, 0.423262f, 0.41049f, 0.0f, 0.414782f, 94 | 0.47043f, 0.0f, 0.414782f, 0.410417f, 0.0f, 0.399482f, 0.41207f, 0.0f, 0.392068f, 95 | 0.415863f, 0.0f, 0.386999f, 0.4214f, 0.0f, 0.384076f, 0.428282f, 0.0f, 0.383102f, 96 | 0.435345f, 0.0f, 0.38413f, 0.440265f, 0.0f, 0.387215f, 0.443206f, 0.0f, 0.392339f, 97 | 0.44433f, 0.0f, 0.399482f, 98 | }; 99 | 100 | int faces[] = { 101 | 21, 22, 1, 38, 21, 1, 37, 38, 1, 0, 1, 22, 20, 0, 22, 19, 20, 22, 18, 19, 22, 17, 18, 102 | 22, 16, 17, 22, 16, 22, 23, 15, 16, 23, 15, 23, 24, 14, 15, 24, 13, 14, 24, 13, 24, 25, 37, 103 | 1, 2, 36, 37, 2, 36, 2, 3, 36, 3, 4, 35, 36, 4, 35, 4, 5, 34, 35, 5, 34, 5, 6, 104 | 33, 34, 6, 33, 6, 7, 32, 33, 7, 12, 13, 25, 12, 25, 26, 12, 26, 27, 11, 12, 27, 11, 27, 105 | 28, 11, 28, 29, 32, 7, 8, 31, 32, 8, 30, 31, 8, 30, 8, 9, 29, 30, 9, 11, 29, 9, 10, 106 | 11, 9, 75, 76, 57, 74, 75, 57, 57, 40, 41, 74, 57, 41, 74, 41, 42, 74, 42, 43, 74, 43, 44, 107 | 74, 44, 45, 40, 57, 58, 74, 45, 46, 73, 74, 46, 73, 46, 47, 71, 72, 73, 70, 71, 73, 70, 73, 108 | 47, 70, 47, 48, 69, 70, 48, 69, 48, 49, 69, 49, 50, 68, 69, 50, 68, 50, 51, 68, 51, 52, 67, 109 | 68, 52, 40, 58, 59, 39, 40, 59, 39, 59, 60, 39, 60, 61, 56, 39, 61, 55, 56, 61, 55, 61, 62, 110 | 55, 62, 63, 55, 63, 64, 54, 55, 64, 54, 64, 65, 54, 65, 66, 53, 54, 66, 53, 66, 67, 53, 67, 111 | 52, 83, 84, 77, 83, 77, 78, 81, 82, 83, 80, 81, 83, 80, 83, 78, 79, 80, 78, 90, 91, 85, 90, 112 | 85, 86, 89, 90, 86, 88, 89, 86, 88, 86, 87, 93, 127, 128, 93, 128, 129, 127, 93, 94, 93, 129, 130, 113 | 127, 94, 95, 93, 130, 131, 127, 95, 96, 126, 127, 96, 125, 126, 96, 124, 125, 96, 124, 96, 97, 123, 124, 114 | 97, 122, 123, 97, 122, 97, 98, 121, 122, 98, 121, 98, 99, 120, 121, 99, 119, 120, 99, 119, 99, 100, 118, 115 | 119, 100, 117, 118, 100, 117, 100, 101, 116, 117, 101, 116, 101, 102, 115, 116, 102, 114, 115, 102, 114, 102, 103, 116 | 113, 114, 103, 112, 113, 103, 111, 112, 103, 111, 103, 104, 110, 111, 104, 109, 110, 104, 108, 109, 104, 108, 104, 117 | 105, 139, 108, 105, 138, 139, 105, 138, 105, 106, 137, 138, 106, 137, 106, 107, 136, 137, 107, 135, 136, 107, 135, 118 | 107, 92, 134, 135, 92, 133, 134, 92, 133, 92, 93, 132, 133, 93, 132, 93, 131, 142, 143, 140, 141, 142, 140, 119 | 170, 171, 144, 169, 170, 144, 159, 160, 161, 158, 159, 161, 157, 158, 161, 156, 157, 161, 156, 161, 162, 155, 156, 120 | 162, 155, 162, 163, 154, 155, 163, 154, 163, 164, 153, 154, 164, 153, 164, 165, 152, 153, 165, 152, 165, 166, 151, 121 | 152, 166, 151, 166, 167, 150, 151, 167, 150, 167, 168, 149, 150, 168, 149, 168, 169, 148, 149, 169, 147, 148, 169, 122 | 144, 145, 146, 169, 144, 146, 147, 169, 146, 219, 220, 221, 218, 219, 221, 217, 218, 221, 216, 217, 221, 215, 216, 123 | 221, 204, 205, 206, 203, 204, 206, 201, 202, 203, 201, 203, 206, 201, 206, 207, 201, 207, 208, 183, 184, 185, 182, 124 | 183, 185, 181, 182, 185, 181, 185, 186, 180, 181, 186, 179, 180, 186, 179, 186, 187, 179, 187, 188, 178, 179, 188, 125 | 178, 188, 189, 177, 178, 189, 177, 189, 190, 176, 177, 190, 176, 190, 191, 175, 176, 191, 175, 191, 192, 174, 175, 126 | 192, 174, 192, 193, 173, 174, 193, 172, 173, 193, 221, 172, 193, 215, 221, 193, 214, 215, 193, 214, 193, 194, 214, 127 | 194, 195, 213, 214, 195, 213, 195, 196, 213, 196, 197, 212, 213, 197, 212, 197, 198, 211, 212, 198, 211, 198, 199, 128 | 210, 211, 199, 210, 199, 200, 209, 210, 200, 209, 200, 201, 209, 201, 208, 258, 250, 222, 258, 222, 223, 257, 258, 129 | 223, 257, 223, 224, 257, 224, 225, 256, 257, 225, 256, 225, 226, 255, 256, 226, 254, 255, 226, 254, 226, 227, 253, 130 | 254, 227, 252, 253, 227, 252, 227, 228, 251, 252, 228, 251, 228, 229, 250, 251, 229, 250, 229, 230, 248, 249, 222, 131 | 248, 222, 250, 248, 250, 230, 248, 230, 231, 247, 248, 231, 247, 231, 232, 247, 232, 233, 246, 247, 233, 245, 246, 132 | 233, 245, 233, 234, 244, 245, 234, 244, 234, 235, 243, 244, 235, 243, 235, 236, 242, 243, 236, 242, 236, 237, 238, 133 | 239, 240, 238, 240, 241, 237, 238, 241, 242, 237, 241, 134 | }; 135 | 136 | frantic::geometry::trimesh3 g_prtVolumeIconMesh; 137 | bool g_isPRTVolumeIconMeshBuilt = false; 138 | } // namespace 139 | 140 | const frantic::geometry::trimesh3& get_prt_volume_icon_mesh() { 141 | if( !g_isPRTVolumeIconMeshBuilt ) { 142 | build_icon_mesh( vertices, sizeof( vertices ) / ( sizeof( float ) * 3 ), faces, 143 | sizeof( faces ) / ( sizeof( int ) * 3 ), g_prtVolumeIconMesh ); 144 | g_isPRTVolumeIconMeshBuilt = true; 145 | } 146 | 147 | return g_prtVolumeIconMesh; 148 | } 149 | -------------------------------------------------------------------------------- /src/maya_render_save_interface.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "maya_render_save_interface.hpp" 4 | #include "stdafx.h" 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace frantic::files; 16 | using namespace frantic::maya; 17 | 18 | maya_render_save_interface::maya_render_save_interface( const MFnDependencyNode& krakatoaSettingsNode, 19 | const MDGContext& currentContext, 20 | const frantic::tstring& cameraName ) { 21 | 22 | m_krakatoaSettings.setObject( krakatoaSettingsNode.object() ); 23 | m_currentContext = currentContext; 24 | m_cameraName = cameraName; 25 | } 26 | 27 | maya_render_save_interface::~maya_render_save_interface() {} 28 | 29 | void maya_render_save_interface::save_render_data( int width, int height, int imageCount, 30 | const krakatoasr::output_type_t* listOfTypes, 31 | const krakatoasr::frame_buffer_pixel_data* const* listOfImages ) { 32 | frantic::tstring extension = get_output_image_extension(); 33 | 34 | // special case handling for exr files, since we have a better system than maya 35 | if( extension == _T("exr") ) { 36 | krakatoasr::multi_channel_exr_file_saver exrSaver( 37 | frantic::strings::to_string( get_output_image_name() ).c_str() ); 38 | 39 | // get exr compression type 40 | krakatoasr::exr_compression_t exr_compression_type = get_exr_compression_type(); 41 | exrSaver.set_exr_compression_type( exr_compression_type ); 42 | 43 | // get rgba bit depth setting 44 | krakatoasr::exr_bit_depth_t rgbaD = get_exr_bit_depth( "exrRgbaBitDepth" ); 45 | exrSaver.set_channel_name_rgba( "R", "G", "B", "A", rgbaD ); 46 | 47 | // get normal bit depth setting 48 | krakatoasr::exr_bit_depth_t normalD = get_exr_bit_depth( "exrNormalBitDepth" ); 49 | exrSaver.set_channel_name_normal( "normal.X", "normal.Y", "normal.Z", normalD ); 50 | 51 | // get velocity bit depth setting 52 | krakatoasr::exr_bit_depth_t velocityD = get_exr_bit_depth( "exrVelocityBitDepth" ); 53 | exrSaver.set_channel_name_velocity( "velocity.X", "velocity.Y", "velocity.Z", velocityD ); 54 | 55 | // get z bit depth setting 56 | krakatoasr::exr_bit_depth_t zD = get_exr_bit_depth( "exrZBitDepth" ); 57 | exrSaver.set_channel_name_z( "Z", zD ); 58 | 59 | // get occluded bit depth setting 60 | krakatoasr::exr_bit_depth_t occludedD = get_exr_bit_depth( "exrOccludedBitDepth" ); 61 | exrSaver.set_channel_name_rgba_occluded( "occluded.R", "occluded.G", "occluded.B", "occluded.A", occludedD ); 62 | 63 | // save the data 64 | exrSaver.save_render_data( width, height, imageCount, listOfTypes, listOfImages ); 65 | } else { 66 | for( int i = 0; i < imageCount; ++i ) { 67 | switch( listOfTypes[i] ) { 68 | case krakatoasr::OUTPUT_RGBA: 69 | save_rgba_image_data( width, height, listOfImages[i] ); 70 | break; 71 | case krakatoasr::OUTPUT_Z: 72 | save_depth_image_data( width, height, listOfImages[i] ); 73 | break; 74 | case krakatoasr::OUTPUT_NORMAL: 75 | save_normal_image_data( width, height, listOfImages[i] ); 76 | break; 77 | case krakatoasr::OUTPUT_RGBA_OCCLUDED: 78 | save_occluded_image_data( width, height, listOfImages[i] ); 79 | break; 80 | case krakatoasr::OUTPUT_VELOCITY: 81 | save_velocity_image_data( width, height, listOfImages[i] ); 82 | break; 83 | default: 84 | FF_LOG( debug ) << "Krakatoa MY: Unknown image output type " << listOfTypes[i] << ", omitting." 85 | << std::endl; 86 | } 87 | } 88 | } 89 | } 90 | 91 | boost::uint8_t to_uint8( float f ) { 92 | return static_cast( frantic::math::clamp( f * 255, 0, 255 ) ); 93 | } 94 | 95 | void maya_render_save_interface::save_rgba_image_data( int width, int height, 96 | const krakatoasr::frame_buffer_pixel_data* imageData ) { 97 | MImage mayaImage; 98 | mayaImage.create( width, height, 4, MImage::kByte ); 99 | 100 | const size_t imageSize = width * height; 101 | 102 | for( size_t i = 0; i < imageSize; ++i ) { 103 | mayaImage.pixels()[i * 4 + 0] = to_uint8( imageData[i].r ); 104 | mayaImage.pixels()[i * 4 + 1] = to_uint8( imageData[i].g ); 105 | mayaImage.pixels()[i * 4 + 2] = to_uint8( imageData[i].b ); 106 | mayaImage.pixels()[i * 4 + 3] = 107 | to_uint8( ( imageData[i].r_alpha + imageData[i].g_alpha + imageData[i].b_alpha ) / 3.0f ); 108 | } 109 | 110 | mayaImage.writeToFile( MString( get_output_image_name().c_str() ), 111 | MString( get_output_image_extension().c_str() ) ); 112 | } 113 | 114 | void maya_render_save_interface::save_depth_image_data( int width, int height, 115 | const krakatoasr::frame_buffer_pixel_data* imageData ) { 116 | MImage mayaImage; 117 | mayaImage.create( width, height, 4, MImage::kByte ); 118 | 119 | const size_t imageSize = width * height; 120 | 121 | for( size_t i = 0; i < imageSize; ++i ) { 122 | mayaImage.pixels()[i * 4 + 0] = to_uint8( imageData[i].r ); 123 | mayaImage.pixels()[i * 4 + 1] = to_uint8( imageData[i].r ); 124 | mayaImage.pixels()[i * 4 + 2] = to_uint8( imageData[i].r ); 125 | mayaImage.pixels()[i * 4 + 3] = to_uint8( imageData[i].r_alpha ); 126 | } 127 | 128 | mayaImage.writeToFile( MString( get_output_image_name( _T( "ZDepth" ) ).c_str() ), 129 | MString( get_output_image_extension().c_str() ) ); 130 | } 131 | 132 | void maya_render_save_interface::save_normal_image_data( int width, int height, 133 | const krakatoasr::frame_buffer_pixel_data* imageData ) { 134 | MImage mayaImage; 135 | mayaImage.create( width, height, 4, MImage::kByte ); 136 | 137 | const size_t imageSize = width * height; 138 | 139 | for( size_t i = 0; i < imageSize; ++i ) { 140 | mayaImage.pixels()[i * 4 + 0] = to_uint8( imageData[i].r ); 141 | mayaImage.pixels()[i * 4 + 1] = to_uint8( imageData[i].g ); 142 | mayaImage.pixels()[i * 4 + 2] = to_uint8( imageData[i].b ); 143 | mayaImage.pixels()[i * 4 + 3] = 144 | to_uint8( ( imageData[i].r_alpha + imageData[i].g_alpha + imageData[i].b_alpha ) / 3.0f ); 145 | } 146 | 147 | mayaImage.writeToFile( MString( get_output_image_name( _T( "Normal" ) ).c_str() ), 148 | MString( get_output_image_extension().c_str() ) ); 149 | } 150 | 151 | void maya_render_save_interface::save_velocity_image_data( int width, int height, 152 | const krakatoasr::frame_buffer_pixel_data* imageData ) { 153 | MImage mayaImage; 154 | mayaImage.create( width, height, 4, MImage::kByte ); 155 | 156 | const size_t imageSize = width * height; 157 | 158 | for( size_t i = 0; i < imageSize; ++i ) { 159 | mayaImage.pixels()[i * 4 + 0] = to_uint8( imageData[i].r ); 160 | mayaImage.pixels()[i * 4 + 1] = to_uint8( imageData[i].g ); 161 | mayaImage.pixels()[i * 4 + 2] = to_uint8( imageData[i].b ); 162 | mayaImage.pixels()[i * 4 + 3] = 163 | to_uint8( ( imageData[i].r_alpha + imageData[i].g_alpha + imageData[i].b_alpha ) / 3.0f ); 164 | } 165 | 166 | mayaImage.writeToFile( MString( get_output_image_name( _T( "Velocity" ) ).c_str() ), 167 | MString( get_output_image_extension().c_str() ) ); 168 | } 169 | 170 | void maya_render_save_interface::save_occluded_image_data( int width, int height, 171 | const krakatoasr::frame_buffer_pixel_data* imageData ) { 172 | MImage mayaImage; 173 | mayaImage.create( width, height, 4, MImage::kByte ); 174 | 175 | const size_t imageSize = width * height; 176 | 177 | for( size_t i = 0; i < imageSize; ++i ) { 178 | mayaImage.pixels()[i * 4 + 0] = to_uint8( imageData[i].r ); 179 | mayaImage.pixels()[i * 4 + 1] = to_uint8( imageData[i].g ); 180 | mayaImage.pixels()[i * 4 + 2] = to_uint8( imageData[i].b ); 181 | mayaImage.pixels()[i * 4 + 3] = 182 | to_uint8( ( imageData[i].r_alpha + imageData[i].g_alpha + imageData[i].b_alpha ) / 3.0f ); 183 | } 184 | 185 | mayaImage.writeToFile( MString( get_output_image_name( _T( "Occluded" ) ).c_str() ), 186 | MString( get_output_image_extension().c_str() ) ); 187 | } 188 | 189 | void maya_render_save_interface::set_current_context( const MDGContext& currentContext ) { 190 | m_currentContext = currentContext; 191 | } 192 | 193 | void maya_render_save_interface::set_camera_name( const frantic::tstring& cameraName ) { m_cameraName = cameraName; } 194 | 195 | frantic::tstring maya_render_save_interface::get_output_image_name( const frantic::tstring& appendName ) { 196 | frantic::tstring result = 197 | maya_util::get_render_filename( m_currentContext, m_cameraName, appendName, get_output_image_extension() ); 198 | 199 | // if (get_output_image_extension() == _T("exr")) 200 | //{ 201 | // result = replace_extension(result, _T(".exr")); 202 | // } 203 | 204 | return result; 205 | } 206 | 207 | frantic::tstring maya_render_save_interface::get_output_image_extension() { 208 | frantic::tstring output; 209 | int renderImageFormat = maya_util::get_current_render_image_format(); 210 | if( frantic::maya::get_boolean_attribute( m_krakatoaSettings, _T( "forceEXROutput" ) ) ) { 211 | return _T("exr"); 212 | } else if( maya_util::get_image_format_extension( renderImageFormat, output ) ) { 213 | return output; 214 | } else { 215 | FF_LOG( stats ) << "Image format " << renderImageFormat << " not recognized, using default (iff)" << std::endl; 216 | return _T("iff"); 217 | } 218 | } 219 | 220 | krakatoasr::exr_compression_t maya_render_save_interface::get_exr_compression_type() const { 221 | krakatoasr::exr_compression_t retval = krakatoasr::COMPRESSION_NONE; 222 | MString exrCompressionType = frantic::maya::get_enum_attribute( m_krakatoaSettings, "exrCompressionType" ); 223 | 224 | if( exrCompressionType == "No Compression" ) 225 | retval = krakatoasr::COMPRESSION_NONE; 226 | else if( exrCompressionType == "Run Length Encoding" ) 227 | retval = krakatoasr::COMPRESSION_RLE; 228 | else if( exrCompressionType == "Zlib Compression (one scan line at a time)" ) 229 | retval = krakatoasr::COMPRESSION_ZIPS; 230 | else if( exrCompressionType == "Zlib Compression (in blocks of 16 scan lines)" ) 231 | retval = krakatoasr::COMPRESSION_ZIP; 232 | else if( exrCompressionType == "Piz-Based Wavelet Compression" ) 233 | retval = krakatoasr::COMPRESSION_PIZ; 234 | else if( exrCompressionType == "Lossy 24-bit Float Compression" ) 235 | retval = krakatoasr::COMPRESSION_PXR24; 236 | else if( exrCompressionType == "Lossy 4-by-4 Pixel Block Compression (fixed compression rate)" ) 237 | retval = krakatoasr::COMPRESSION_B44; 238 | else if( exrCompressionType == "Lossy 4-by-4 Pixel Block Compression (flat fields are compressed more)" ) 239 | retval = krakatoasr::COMPRESSION_B44A; 240 | else { 241 | // shouldn't happen given our code 242 | throw std::runtime_error( "Unknown EXRDataCompression Type " ); 243 | } 244 | FF_LOG( debug ) << "EXRCompression Type: " << frantic::strings::to_tstring( exrCompressionType.asChar() ) 245 | << std::endl; 246 | return retval; 247 | } 248 | 249 | krakatoasr::exr_bit_depth_t maya_render_save_interface::get_exr_bit_depth( const std::string& bitDepthName ) const { 250 | krakatoasr::exr_bit_depth_t retval = krakatoasr::BIT_DEPTH_FLOAT; 251 | MString exrBitDepth = frantic::maya::get_enum_attribute( m_krakatoaSettings, MString( bitDepthName.c_str() ) ); 252 | 253 | if( exrBitDepth == "UInt" ) 254 | retval = krakatoasr::BIT_DEPTH_UINT; 255 | else if( exrBitDepth == "Half" ) 256 | retval = krakatoasr::BIT_DEPTH_HALF; 257 | else if( exrBitDepth == "Float" ) 258 | retval = krakatoasr::BIT_DEPTH_FLOAT; 259 | else { 260 | // shouldn't happen given our code 261 | throw std::runtime_error( "Unknown bit depth for " + bitDepthName ); 262 | } 263 | FF_LOG( debug ) << "EXR Bit Depth for " << frantic::strings::to_tstring( bitDepthName ) << ": " 264 | << frantic::strings::to_tstring( exrBitDepth.asChar() ) << std::endl; 265 | return retval; 266 | } 267 | -------------------------------------------------------------------------------- /scripts/AEPRTModifierTemplate.mel: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //////////////////////////////////// 4 | // Attribute Editor Template for the Modifiers Node 5 | // 6 | // Written By: Matthew Yu 7 | // Thinkbox Software Inc. 8 | // 2013 9 | /////////////////////////////////// 10 | 11 | global proc AEPRTModifierTemplate( string $nodeName ) { 12 | 13 | global int $PRTModifiersSourceChannelChangedJobID = -1; 14 | global int $PRTModifiersDestinationChannelChangedJobID = -1; 15 | global int $PRTModifiersChannelChangedJobID = -1; 16 | global int $PRTModifiersUVWChannelChangedJobID = -1; 17 | 18 | editorTemplate -beginScrollLayout; 19 | 20 | editorTemplate -beginLayout "Modifier" -collapse false; 21 | editorTemplate -label "Enabled" -addControl "inEnabled"; 22 | editorTemplate -label "Name" -addControl "inModifiersName"; 23 | editorTemplate -label "Type" -addControl "inModifiersMethod"; 24 | editorTemplate -callCustom "PRTModifiers_settingsLabel" "PRTModifiers_settingsLabelUpdate" "inModifiersMethod"; 25 | editorTemplate -endLayout; 26 | 27 | editorTemplate -beginLayout "Settings" -collapse false; 28 | editorTemplate -label "Evaluate In Viewport" -addControl "KMod_Evaluate_In_Viewport"; 29 | 30 | editorTemplate -callCustom "PRTModifiers_Channel" "PRTModifiers_ChannelUpdate" "KMod_Channel_Name"; 31 | editorTemplate -label "Channel Value" -addControl "KMod_Channel_Value"; 32 | editorTemplate -label "Channel Scale" -addControl "KMod_Channel_Scale"; 33 | 34 | editorTemplate -callCustom "PRTModifiers_SourceChannel" "PRTModifiers_SourceChannelUpdate" "KMod_Source_Channel"; 35 | editorTemplate -callCustom "PRTModifiers_DestinationChannel" "PRTModifiers_DestinationChannelUpdate" "KMod_Destination_Channel"; 36 | editorTemplate -label "Copy as Vector Length" -addControl "KMod_Copy_as_Vector_Length"; 37 | 38 | editorTemplate -label "Fill Radius" -addControl "KMod_Fill_Radius"; 39 | editorTemplate -label "Fill Radius Subdivs" -addControl "KMod_Fill_Radius_Subdivs"; 40 | editorTemplate -label "Particles Per Subdiv" -addControl "KMod_Particles_Per_Subdiv"; 41 | editorTemplate -label "Density Falloff" -addControl "KMod_Density_Falloff"; 42 | editorTemplate -label "Random Seed" -addControl "KMod_Random_Seed"; 43 | 44 | editorTemplate -callCustom "PRTModifiers_UVWChannel" "PRTModifiers_UVWChannelUpdate" "KMod_UVW_Channel_Name"; 45 | editorTemplate -label "Texture" -addControl "KMod_Texture"; 46 | 47 | editorTemplate -endLayout; 48 | 49 | // To Suppress 50 | string $toSuppress[] = { "caching", "nodeState", "inModifiersMethod", 51 | 52 | "KMod_Evaluate_In_Viewport", 53 | "KMod_Channel_Name", "KMod_Channel_Value", "KMod_Channel_Scale", 54 | "KMod_Source_Channel", "KMod_Destination_Channel", "KMod_Copy_as_Vector_Length", "KMod_Copy_as_Vector_Length", 55 | "KMod_Fill_Radius", "KMod_Fill_Radius_Subdivs", "KMod_Particles_Per_Subdiv", "KMod_Density_Falloff", "KMod_Random_Seed", "KMod_Texture", 56 | "KMod_Texture", "KMod_UVW_Channel_Name" 57 | }; 58 | 59 | // manually supress each such item 60 | for ($value in $toSuppress) 61 | editorTemplate -suppress $value; 62 | 63 | editorTemplate -addExtraControls; 64 | 65 | editorTemplate -endScrollLayout; 66 | } 67 | 68 | global proc PRTModifiers_settingsLabel( string $nodeAttr ) { 69 | PRTModifiers_settingsLabelUpdate $nodeAttr; 70 | } 71 | 72 | global proc PRTModifiers_settingsLabelUpdate( string $nodeAttr ) { 73 | setAttr -lock on $nodeAttr; 74 | } 75 | 76 | global proc PRTModifiers_SourceChannel( string $nodeAttr ) { 77 | PRTModifiers_SourceChannelUpdate $nodeAttr; 78 | } 79 | 80 | global proc PRTModifiers_SourceChannelUpdate( string $nodeAttr ) { 81 | global int $PRTModifiersSourceChannelChangedJobID; 82 | if ( `scriptJob -ex $PRTModifiersSourceChannelChangedJobID` ) 83 | scriptJob -kill $PRTModifiersSourceChannelChangedJobID; 84 | 85 | string $spinner = "PRTModifiers_SourceChannel_Spinner"; 86 | string $layoutName = ($spinner + "_layout"); 87 | string $fieldName = ($spinner + "_textfield"); 88 | int $hasAttr = `objExists $nodeAttr`; 89 | int $hasGui = `layout -exists $layoutName`; 90 | 91 | string $buffer[]; 92 | tokenize $nodeAttr "." $buffer; 93 | 94 | string $choices[]; 95 | $choices = `MagmaFLUX_getChannelTypes`; 96 | 97 | $PRTModifiersSourceChannelChangedJobID = `PRTModifiers_UpdateChannelSelectionGUI $buffer[0] $buffer[1] $layoutName $spinner $fieldName "Source Selection" "Source Name" $choices`; 98 | } 99 | 100 | global proc PRTModifiers_DestinationChannel( string $nodeAttr ) { 101 | PRTModifiers_DestinationChannelUpdate $nodeAttr; 102 | } 103 | 104 | global proc PRTModifiers_DestinationChannelUpdate( string $nodeAttr ) { 105 | global int $PRTModifiersDestinationChannelChangedJobID; 106 | if ( `scriptJob -ex $PRTModifiersDestinationChannelChangedJobID` ) 107 | scriptJob -kill $PRTModifiersDestinationChannelChangedJobID; 108 | 109 | string $spinner = "PRTModifiers_DestinationChannel_Spinner"; 110 | string $layoutName = ($spinner + "_layout"); 111 | string $fieldName = ($spinner + "_textfield"); 112 | int $hasAttr = `objExists $nodeAttr`; 113 | int $hasGui = `layout -exists $layoutName`; 114 | 115 | string $buffer[]; 116 | tokenize $nodeAttr "." $buffer; 117 | 118 | string $choices[]; 119 | $choices = `MagmaFLUX_getChannelTypes`; 120 | 121 | $PRTModifiersDestinationChannelChangedJobID = `PRTModifiers_UpdateChannelSelectionGUI $buffer[0] $buffer[1] $layoutName $spinner $fieldName "Destination Selection" "Destination Name" $choices`; 122 | } 123 | 124 | global proc PRTModifiers_Channel( string $nodeAttr ) { 125 | PRTModifiers_ChannelUpdate $nodeAttr; 126 | } 127 | 128 | global proc PRTModifiers_ChannelUpdate( string $nodeAttr ) { 129 | global int $PRTModifiersChannelChangedJobID; 130 | if ( `scriptJob -ex $PRTModifiersChannelChangedJobID` ) 131 | scriptJob -kill $PRTModifiersChannelChangedJobID; 132 | 133 | string $spinner = "PRTModifiers_Channel_Spinner"; 134 | string $layoutName = ($spinner + "_layout"); 135 | string $fieldName = ($spinner + "_textfield"); 136 | 137 | string $buffer[]; 138 | tokenize $nodeAttr "." $buffer; 139 | 140 | string $modType = `getAttr ($buffer[0] + ".inModifiersMethod")`; 141 | string $choices[]; 142 | if ( $modType == "Set Vector Channel" || $modType == "Apply Texture" ) { 143 | $choices = `PRTModifiers_getChannelsByDataType "Vec3"`; 144 | } else if ( $modType == "Set Float Channel" ) { 145 | $choices = `PRTModifiers_getChannelsByDataType "Float"`; 146 | } else { 147 | $choices = `MagmaFLUX_getChannelTypes`; 148 | } 149 | 150 | $PRTModifiersChannelChangedJobID = `PRTModifiers_UpdateChannelSelectionGUI $buffer[0] $buffer[1] $layoutName $spinner $fieldName "Channel Selection" "Channel Name" $choices`; 151 | } 152 | 153 | global proc PRTModifiers_UVWChannel( string $nodeAttr ) { 154 | PRTModifiers_UVWChannelUpdate $nodeAttr; 155 | } 156 | 157 | global proc PRTModifiers_UVWChannelUpdate( string $nodeAttr ) { 158 | global int $PRTModifiersUVWChannelChangedJobID; 159 | if ( `scriptJob -ex $PRTModifiersUVWChannelChangedJobID` ) 160 | scriptJob -kill $PRTModifiersUVWChannelChangedJobID; 161 | 162 | string $spinner = "PRTModifiers_UVWChannel_Spinner"; 163 | string $layoutName = ($spinner + "_layout"); 164 | string $fieldName = ($spinner + "_textfield"); 165 | 166 | string $buffer[]; 167 | tokenize $nodeAttr "." $buffer; 168 | 169 | string $choices[]; 170 | $choices = `PRTModifiers_getChannelsByDataType "Vec3"`; 171 | 172 | $PRTModifiersUVWChannelChangedJobID = `PRTModifiers_UpdateChannelSelectionGUI $buffer[0] $buffer[1] $layoutName $spinner $fieldName "UVW Selection" "UVW Name" $choices`; 173 | } 174 | 175 | global proc int PRTModifiers_UpdateChannelSelectionGUI( string $node, string $attr, string $layoutName, string $spinner, string $fieldName, string $selectLabel, string $inputLabel, string $choices[] ) 176 | { 177 | int $hasAttr = `objExists ($node + "." + $attr)`; 178 | int $hasGui = `layout -exists $layoutName`; 179 | int $updateScript = -1; 180 | 181 | if ( $hasAttr ) { 182 | if ( $hasGui ) { 183 | // Update the scripts and selection choices 184 | $updateScript = `PRTModifiers_setupStringEnumAttributeOption $node $attr $spinner $fieldName $choices`; 185 | } else /*if (!$hasGui )*/ { 186 | // Rebuild the gui 187 | $updateScript = `PRTModifiers_addStringEnumAttributeOption $node $attr $layoutName $spinner $fieldName $selectLabel $inputLabel $choices`; 188 | } 189 | } else { 190 | if ($hasGui ) { 191 | // Remove the gui 192 | deleteUI -layout $layoutName; 193 | } else /*if (!$hasGui )*/ { 194 | // Nothing needs to be done 195 | } 196 | $updateScript = -1; 197 | } 198 | 199 | return $updateScript; 200 | } 201 | 202 | global proc string[] PRTModifiers_getChannelsByDataType( string $type ) { 203 | string $attributeChoices[] = `MagmaFLUX_getChannelTypes`; 204 | string $finalChoices[]; 205 | int $index = 0; 206 | int $finalCount = 0; 207 | for ( $item in $attributeChoices ) { 208 | if ( $finalCount == 0 ) { 209 | // Assumes first choice is always 210 | $finalChoices[$finalCount] = $item; 211 | $finalCount++; 212 | } else { 213 | string $checkType = `MagmaFLUX_getChannelTypesDataType $index`; 214 | if ( $type == $checkType ) { 215 | $finalChoices[$finalCount] = $item; 216 | $finalCount++; 217 | } 218 | } 219 | $index++; 220 | } 221 | 222 | return $finalChoices; 223 | } 224 | 225 | global proc int PRTModifiers_setupStringEnumAttributeOption( string $node, string $attr, string $spinner, string $fieldName, string $choices[] ) 226 | { 227 | PRTModifiers_setStringEnumAttributeOption $node $attr $spinner $choices; 228 | 229 | if ( `objExists ($node + "." + $attr)` ) { 230 | string $enumCommand = ("setAttr \"" + $node + "." + $attr + "\" -type \"string\" \"#1\";\n"); 231 | 232 | optionMenu -e -cc $enumCommand $spinner; 233 | 234 | string $jobstring = ( 235 | "int $itemIndex = 1;\n" + 236 | "string $spinner = \"" + $spinner + "\";\n" + 237 | "string $currentChoice = `getAttr " + ($node + "." + $attr) + "`;\n" + 238 | 239 | "optionMenu -e -select 1 $spinner;\n" + 240 | "for( $item in `optionMenu -q -ils $spinner` )\n" + 241 | "{\n" + 242 | "$itemName = `menuItem -q -label $item $spinner`;\n" + 243 | "if ( $itemName == $currentChoice )\n" + 244 | "{\n" + 245 | "if( `optionMenu -q -select $spinner` != $itemIndex ) {\n" + 246 | "optionMenu -e -select $itemIndex $spinner;\n" + 247 | "break;\n" + 248 | "}\n" + 249 | "}\n" + 250 | "$itemIndex++;\n" + 251 | "}\n" 252 | ); 253 | 254 | connectControl $fieldName ($node + "." + $attr); 255 | 256 | int $updateScriptID = `scriptJob -kws -parent $spinner -attributeChange ($node + "." + $attr) ( $jobstring )`; 257 | eval $jobstring; 258 | return $updateScriptID; 259 | } else { 260 | optionMenu -e -cc ";" $spinner; 261 | return -1; 262 | } 263 | } 264 | 265 | global proc PRTModifiers_setStringEnumAttributeOption( string $node, string $attr, string $spinner, string $attributeChoices[] ) 266 | { 267 | // Clear the old list 268 | string $oldItems[] = `optionMenu -q -ill $spinner`; 269 | deleteUI -menuItem $oldItems; 270 | 271 | // Get the current selection 272 | string $currentChoice; 273 | if ( `objExists ($node + "." + $attr)` ) { 274 | $currentChoice = `getAttr ($node + "." + $attr)`; 275 | } else { 276 | $currentChoice = $attributeChoices[0]; 277 | } 278 | int $currentChoiceInList = 1; 279 | 280 | // Set up the list 281 | int $itemIndex = 1; 282 | for( $item in $attributeChoices ) 283 | { 284 | menuItem -label $item -data $itemIndex -p $spinner; 285 | if( $item == $currentChoice ) 286 | $currentChoiceInList = $itemIndex; 287 | $itemIndex++; 288 | } 289 | optionMenu -e -select $currentChoiceInList $spinner; 290 | } 291 | 292 | global proc int PRTModifiers_addStringEnumAttributeOption( string $node, string $attr, string $layoutName, string $spinner, string $fieldName, string $selectLabel, string $inputLabel, string $attributeChoices[] ) 293 | { 294 | // Add a combo box for string attribute 295 | // Based on MagmaFLUX_addStringEnumAttributeOption 296 | string $currentChoice; 297 | if ( `objExists ($node + "." + $attr)` ) { 298 | $currentChoice = `getAttr ($node + "." + $attr)`; 299 | } else { 300 | $currentChoice = $attributeChoices[0]; 301 | } 302 | int $currentChoiceInList = 1; 303 | 304 | //Set up the enum choices and combo box 305 | columnLayout $layoutName; 306 | rowLayout -nc 2 ($layoutName + "_1"); 307 | text -label $selectLabel ($spinner + "_label_1"); 308 | 309 | optionMenu -label "" $spinner; 310 | int $itemIndex = 1; 311 | for( $item in $attributeChoices ) 312 | { 313 | menuItem -label $item -data $itemIndex; 314 | if( $item == $currentChoice ) 315 | $currentChoiceInList = $itemIndex; 316 | $itemIndex++; 317 | } 318 | optionMenu -e -select $currentChoiceInList $spinner; 319 | setParent ..; 320 | 321 | rowLayout -nc 2 ($layoutName + "_2"); 322 | text -label $inputLabel ($spinner + "_label_2"); 323 | textField -text "" $fieldName; 324 | setParent ..; 325 | 326 | setParent ..; 327 | 328 | int $updateScriptID = `PRTModifiers_setupStringEnumAttributeOption $node $attr $spinner $fieldName $attributeChoices`; 329 | return $updateScriptID; 330 | } 331 | -------------------------------------------------------------------------------- /src/PRTExporter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #include "stdafx.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | #include "PRTExporter.hpp" 39 | #include "PRTFractal.hpp" 40 | #include "PRTLoader.hpp" 41 | #include "PRTSurface.hpp" 42 | #include "PRTVolume.hpp" 43 | #include "maya_ksr.hpp" 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | using namespace frantic; 50 | using namespace frantic::graphics; 51 | using namespace frantic::channels; 52 | using namespace frantic::logging; 53 | using namespace frantic::particles; 54 | using namespace frantic::particles::streams; 55 | using namespace frantic::maya; 56 | 57 | namespace { 58 | 59 | typedef std::pair channel_type; 60 | 61 | bool is_vector_channel_type( channel_type type ) { 62 | return is_channel_data_type_float( type.first ) && type.second == 3; 63 | } 64 | 65 | bool is_float_channel_type( channel_type type ) { return is_channel_data_type_float( type.first ) && type.second == 1; } 66 | 67 | bool is_int_channel_type( channel_type type ) { return is_channel_data_type_signed( type.first ); } 68 | 69 | channel_type parse_channel_type( const char* channelTypeString ) { 70 | channel_type result = channel_data_type_and_arity_from_string( frantic::strings::to_tstring( channelTypeString ) ); 71 | 72 | if( is_vector_channel_type( result ) || is_float_channel_type( result ) || is_int_channel_type( result ) ) { 73 | return result; 74 | } else { 75 | return std::make_pair( data_type_invalid, 0 ); 76 | } 77 | } 78 | 79 | /** 80 | * Select the default set of channels to read into the PRT file if no channels 81 | * are explicitly selected. 82 | */ 83 | void initialize_default_prt_channels( channel_map& selectedChannels ) { 84 | selectedChannels.define_channel( frantic::maya::particles::PRTPositionChannelName, 3, data_type_float32 ); 85 | selectedChannels.define_channel( frantic::maya::particles::PRTVelocityChannelName, 3, data_type_float16 ); 86 | selectedChannels.define_channel( frantic::maya::particles::PRTColorChannelName, 3, data_type_float16 ); 87 | selectedChannels.define_channel( frantic::maya::particles::PRTParticleIdChannelName, 1, data_type_int64 ); 88 | selectedChannels.define_channel( frantic::maya::particles::PRTDensityChannelName, 1, data_type_float32 ); 89 | } 90 | 91 | } // anonymous namespace 92 | 93 | const MString prt_exporter::commandName = "PRTExporter"; 94 | 95 | void* prt_exporter::creator() { return new prt_exporter; } 96 | 97 | prt_exporter::prt_exporter() {} 98 | 99 | prt_exporter::~prt_exporter() {} 100 | 101 | MStatus prt_exporter::doIt( const MArgList& args ) { 102 | try { 103 | // error check the input 104 | if( args.length() < 2 ) { 105 | MGlobal::displayError( 106 | "PRT Exporter takes three string arguments. Argument one is the path to the .prt output file. Agument " 107 | "two is the name of the Particle or NParticle source object. (optional) Argument 3 is an array of the " 108 | "form { \"channelName\", \"channelType\", ... }, where names and types of each channel must be " 109 | "specified as interleaved pairs." ); 110 | return MStatus::kFailure; 111 | } 112 | 113 | // get the parameters 114 | MStatus status; 115 | unsigned int val = 1; 116 | MString filename( args.asString( 0, &status ) ); 117 | MStringArray inputObjects; 118 | inputObjects = args.asStringArray( val, &status ); 119 | if( status != MStatus::kSuccess ) { 120 | MGlobal::displayError( "Second input must be a string or string array" ); 121 | return MStatus::kFailure; 122 | } 123 | // holds which channels the caller requested be exported 124 | // export_channel_info_map selectedChannels; 125 | channel_map selectedChannels; 126 | frantic::particles::particle_file_stream_factory_object streamFactory; 127 | 128 | // Check if specific channels were requested in the PRT export 129 | if( args.length() > 2 ) { 130 | // the argument location for an array must be passed by reference 131 | unsigned int arrayLocation = 2; 132 | MStringArray dataChannels( args.asStringArray( arrayLocation ) ); 133 | 134 | if( dataChannels.length() % 2 != 0 ) { 135 | MGlobal::displayError( 136 | "Channel name and type information must form interleaved pairs in the input array" ); 137 | return MStatus::kFailure; 138 | } 139 | 140 | // cycle through each interleaved pair of channel name and type, and enter it into the table 141 | for( unsigned int i = 0; i < dataChannels.length(); i += 2 ) { 142 | MString channelNameInput = dataChannels[i]; 143 | MString channelTypeInput = dataChannels[i + 1]; 144 | frantic::tstring mayaChannelName = frantic::strings::to_tstring( channelNameInput.asChar() ); 145 | frantic::tstring prtChannelName; 146 | frantic::maya::particles::get_prt_channel_name_default( mayaChannelName, prtChannelName ); 147 | 148 | // error if the same channel is specified twice (or is this an error?) 149 | if( selectedChannels.has_channel( prtChannelName ) ) { 150 | std::ostringstream errorText; 151 | errorText << "Channel \'" << mayaChannelName.c_str() << "\' was selected more than once"; 152 | MGlobal::displayError( errorText.str().c_str() ); 153 | return MStatus::kFailure; 154 | } 155 | 156 | channel_type type = parse_channel_type( channelTypeInput.asChar() ); 157 | 158 | if( type.first == data_type_invalid ) { 159 | std::ostringstream errorText; 160 | errorText << "Invalid channel data type : \"" << channelTypeInput.asChar() 161 | << "\", must be in the form [arity]"; 162 | MGlobal::displayError( errorText.str().c_str() ); 163 | return MStatus::kFailure; 164 | } 165 | 166 | selectedChannels.define_channel( prtChannelName, type.second, type.first ); 167 | } 168 | } 169 | 170 | // if no channel selections were made, use a default set of channels to output 171 | if( selectedChannels.channel_count() == 0 ) { 172 | initialize_default_prt_channels( selectedChannels ); 173 | } 174 | 175 | selectedChannels.end_channel_definition(); 176 | // get the object from the name by iterating through the scene graph 177 | MDagPath exportObjectPath; 178 | MObject exportObject; 179 | 180 | particle_file_stream_factory_object factoryObject; 181 | factoryObject.set_coordinate_system( frantic::maya::get_coordinate_system() ); 182 | factoryObject.set_length_unit_in_meters( frantic::maya::get_scale_to_meters() ); 183 | factoryObject.set_frame_rate( (unsigned)frantic::maya::get_fps(), 1 ); 184 | boost::shared_ptr outputStream = factoryObject.create_ostream( 185 | frantic::strings::to_tstring( filename.asChar() ), selectedChannels, selectedChannels ); 186 | 187 | MSelectionList list; 188 | MStatus stat; 189 | for( unsigned int i = 0; i < inputObjects.length(); i++ ) { 190 | // create a custom Selection list independent of the active selection list 191 | // merging the new file names with those already included in the list 192 | stat = list.add( inputObjects[i], true ); 193 | if( stat != MStatus::kSuccess ) { 194 | MGlobal::displayError( MString( "The object \"" ) + inputObjects[i] + "\" was not found." ); 195 | return MStatus::kFailure; 196 | } 197 | } 198 | const MTime currentTime = maya_util::get_current_time(); 199 | size_t pSize = outputStream->get_channel_map().structure_size(); 200 | std::vector defaultParticle( pSize, 0 ); 201 | if( outputStream->get_channel_map().has_channel( _T( "Density" ) ) ) 202 | outputStream->get_channel_map().get_cvt_accessor( _T( "Density" ) ).set( &defaultParticle[0], 1.0f ); 203 | if( outputStream->get_channel_map().has_channel( _T( "Color" ) ) ) 204 | outputStream->get_channel_map() 205 | .get_cvt_accessor( _T( "Color" ) ) 206 | .set( &defaultParticle[0], vector3f( 1.0f ) ); 207 | for( unsigned int i = 0; i < list.length(); i++ ) { 208 | list.getDagPath( i, exportObjectPath ); 209 | list.getDependNode( i, exportObject ); 210 | 211 | MObject exportObjectSource; 212 | if( exportObject.apiType() == MFn::kParticle || exportObject.apiType() == MFn::kNParticle ) { 213 | MStatus status; 214 | MFnParticleSystem mayaParticleStream( exportObject ); 215 | exportObjectSource = 216 | frantic::maya::PRTMayaParticle::getPRTMayaParticleFromMayaParticleStreamCheckDeformed( 217 | mayaParticleStream, &status ); 218 | 219 | // May Particles no longer supported 220 | if( status != MS::kSuccess || exportObjectSource == MObject::kNullObj ) { 221 | MGlobal::displayError( MString( "Maya Particles no longer supported for \"" ) + inputObjects[i] + 222 | "\". Please wrap with PRTMayaParticle" ); 223 | return MStatus::kFailure; 224 | } 225 | } else { 226 | exportObjectSource = exportObject; 227 | } 228 | 229 | MFnDependencyNode fnNode( exportObjectSource ); 230 | if( PRTObjectBase::hasParticleStreamMPxData( fnNode ) ) { 231 | MObject endOfChain = PRTObjectBase::getEndOfStreamChain( fnNode ); 232 | MFnDependencyNode depNode( endOfChain ); 233 | 234 | frantic::graphics::transform4f transform; 235 | bool ok = frantic::maya::maya_util::get_object_world_matrix( exportObjectPath, currentTime, transform ); 236 | 237 | boost::shared_ptr inputStream = 238 | PRTObjectBase::getParticleStreamFromMPxData( depNode, transform, currentTime, false ); 239 | inputStream = maya_ksr::get_renderer_stream_modifications( 240 | inputStream, currentTime ); // calls apply_common_operations_to_stream 241 | 242 | // transform the the particle stream into world-space co-ordinates 243 | transform4f objectPosition; 244 | maya_util::get_object_world_matrix( exportObjectPath, currentTime, objectPosition ); 245 | inputStream = boost::shared_ptr( 246 | new transformed_particle_istream( inputStream, objectPosition ) ); 247 | 248 | inputStream->set_channel_map( outputStream->get_channel_map() ); 249 | inputStream->set_default_particle( &defaultParticle[0] ); 250 | 251 | std::vector particleBuffer( inputStream->get_channel_map().structure_size() ); 252 | while( inputStream->get_particle( &particleBuffer[0] ) ) 253 | outputStream->put_particle( &particleBuffer[0] ); 254 | } else { 255 | // can't process this object 256 | MGlobal::displayError( MString( "The object \"" ) + fnNode.name() + 257 | "\" was not a Particle, NParticle, or Thinkbox PRT object. No output particle " 258 | "stream attribute found." ); 259 | return MStatus::kFailure; 260 | } 261 | } 262 | outputStream->close(); 263 | } catch( const std::exception& e ) { 264 | MGlobal::displayError( e.what() ); 265 | return MStatus::kFailure; 266 | } 267 | 268 | return MStatus::kSuccess; 269 | } 270 | --------------------------------------------------------------------------------