Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

First openMaya release with first renderer appleseed.

The compiled plugins do not work at the moment, I will fix it asap.

Signed-off-by: haggi <git@haggi.de>
  • Loading branch information...
commit 955e5195a8b0ea381088740e79a4fa8497a8b51f 1 parent c628e54
haggi authored
Showing with 11,141 additions and 1 deletion.
  1. +3 −0  .gitignore
  2. +8 −1 README.md
  3. +71 −0 src/common/cpp/mayaObject.cpp
  4. +59 −0 src/common/cpp/mayaObject.h
  5. +903 −0 src/common/cpp/mayaScene.cpp
  6. +64 −0 src/common/cpp/mayaScene.h
  7. +130 −0 src/common/cpp/mayarendernodes/renderGlobalsNode.cpp
  8. +60 −0 src/common/cpp/mayarendernodes/renderGlobalsNode.h
  9. +27 −0 src/common/cpp/mayarendernodes/rendercmd.cpp
  10. +26 −0 src/common/cpp/mayarendernodes/rendercmd.h
  11. +17 −0 src/common/cpp/memory/memoryInfo.cpp
  12. +12 −0 src/common/cpp/memory/memoryInfo.h
  13. +230 −0 src/common/cpp/renderGlobals.cpp
  14. +158 −0 src/common/cpp/renderGlobals.h
  15. +339 −0 src/common/cpp/shadingtools/material.cpp
  16. +80 −0 src/common/cpp/shadingtools/material.h
  17. +308 −0 src/common/cpp/shadingtools/readShaderDefs.cpp
  18. +14 −0 src/common/cpp/shadingtools/readShaderDefs.h
  19. +124 −0 src/common/cpp/shadingtools/shadingNode.cpp
  20. +101 −0 src/common/cpp/shadingtools/shadingNode.h
  21. +10 −0 src/common/cpp/threads/queue.cpp
  22. +86 −0 src/common/cpp/threads/queue.h
  23. +46 −0 src/common/cpp/threads/threads.cpp
  24. +19 −0 src/common/cpp/threads/threads.h
  25. +84 −0 src/common/cpp/translators/meshTranslator.cpp
  26. +52 −0 src/common/cpp/translators/meshTranslator.h
  27. +269 −0 src/common/cpp/utilities/attrTools.cpp
  28. +41 −0 src/common/cpp/utilities/attrTools.h
  29. +54 −0 src/common/cpp/utilities/logging.cpp
  30. +29 −0 src/common/cpp/utilities/logging.h
  31. +1,057 −0 src/common/cpp/utilities/pystring.cpp
  32. +291 −0 src/common/cpp/utilities/pystring.h
  33. +383 −0 src/common/cpp/utilities/tools.cpp
  34. +74 −0 src/common/cpp/utilities/tools.h
  35. +192 −0 src/common/python/Renderer/__init__.py
  36. BIN  src/mayaToAppleseed/deployment/mayaToAppleseed/bin/appleseed.dll
  37. BIN  src/mayaToAppleseed/deployment/mayaToAppleseed/bin/appleseed.shared.dll
  38. +6 −0 src/mayaToAppleseed/deployment/mayaToAppleseed/mayaToAppleseed.mod
  39. BIN  src/mayaToAppleseed/deployment/mayaToAppleseed/plug-ins/mayatoappleseed.mll
  40. +91 −0 src/mayaToAppleseed/deployment/mayaToAppleseed/ressources/appleseedRenderer.xml
  41. +17 −0 src/mayaToAppleseed/deployment/mayaToAppleseed/scripts/.project
  42. +11 −0 src/mayaToAppleseed/deployment/mayaToAppleseed/scripts/.pydevproject
  43. +35 −0 src/mayaToAppleseed/deployment/mayaToAppleseed/scripts/AETemplates/AEappleSeedNodeTemplate.py
  44. +62 −0 src/mayaToAppleseed/deployment/mayaToAppleseed/scripts/AETemplates/AEappleseedSurfaceShaderTemplate.py
  45. 0  src/mayaToAppleseed/deployment/mayaToAppleseed/scripts/AETemplates/__init__.py
  46. +192 −0 src/mayaToAppleseed/deployment/mayaToAppleseed/scripts/Renderer/__init__.py
  47. 0  src/mayaToAppleseed/deployment/mayaToAppleseed/scripts/__init__.py
  48. +16 −0 src/mayaToAppleseed/deployment/mayaToAppleseed/scripts/asutils.py
  49. +200 −0 src/mayaToAppleseed/deployment/mayaToAppleseed/scripts/mtap_initialize.py
  50. +16 −0 src/mayaToAppleseed/devkit/.gitignore
  51. +19 −0 src/mayaToAppleseed/devkit/appleseed_devkit_win64/.gitignore
  52. BIN  src/mayaToAppleseed/mtap_devmodule/bin/appleseed.dll
  53. BIN  src/mayaToAppleseed/mtap_devmodule/bin/appleseed.shared.dll
  54. +6 −0 src/mayaToAppleseed/mtap_devmodule/mayaToAppleseed.mod
  55. BIN  src/mayaToAppleseed/mtap_devmodule/plug-ins/mayatoappleseed.mll
  56. +91 −0 src/mayaToAppleseed/mtap_devmodule/ressources/appleseedRenderer.xml
  57. +17 −0 src/mayaToAppleseed/mtap_devmodule/scripts/.project
  58. +11 −0 src/mayaToAppleseed/mtap_devmodule/scripts/.pydevproject
  59. +35 −0 src/mayaToAppleseed/mtap_devmodule/scripts/AETemplates/AEappleseedNodeTemplate.py
  60. +62 −0 src/mayaToAppleseed/mtap_devmodule/scripts/AETemplates/AEappleseedSurfaceShaderTemplate.py
  61. 0  src/mayaToAppleseed/mtap_devmodule/scripts/AETemplates/__init__.py
  62. 0  src/mayaToAppleseed/mtap_devmodule/scripts/__init__.py
  63. +16 −0 src/mayaToAppleseed/mtap_devmodule/scripts/asutils.py
  64. +200 −0 src/mayaToAppleseed/mtap_devmodule/scripts/mtap_initialize.py
  65. +1,983 −0 src/mayaToAppleseed/src/appleseed.cpp
  66. +107 −0 src/mayaToAppleseed/src/appleseed.h
  67. +57 −0 src/mayaToAppleseed/src/mayatoappleseed.cpp
  68. +22 −0 src/mayaToAppleseed/src/mayatoappleseed.h
  69. +22 −0 src/mayaToAppleseed/src/mtap_MayaObject.h
  70. +19 −0 src/mayaToAppleseed/src/mtap_mayaObject.cpp
  71. +114 −0 src/mayaToAppleseed/src/mtap_mayaScene.cpp
  72. +36 −0 src/mayaToAppleseed/src/mtap_mayaScene.h
  73. +189 −0 src/mayaToAppleseed/src/mtap_renderGlobals.cpp
  74. +47 −0 src/mayaToAppleseed/src/mtap_renderGlobals.h
  75. +142 −0 src/mayaToAppleseed/src/mtap_renderGlobalsNode.cpp
  76. +47 −0 src/mayaToAppleseed/src/mtap_renderGlobalsNode.h
  77. +44 −0 src/mayaToAppleseed/src/mtap_rendererController.cpp
  78. +39 −0 src/mayaToAppleseed/src/mtap_rendererController.h
  79. +817 −0 src/mayaToAppleseed/src/mtap_surfaceShader.cpp
  80. +188 −0 src/mayaToAppleseed/src/mtap_surfaceShader.h
  81. +146 −0 src/mayaToAppleseed/src/mtap_tileCallback.cpp
  82. +42 −0 src/mayaToAppleseed/src/mtap_tileCallback.h
  83. +100 −0 src/mayaToAppleseed/src/pluginMain.cpp
  84. +19 −0 src/mayaToAppleseed/vs2010/.gitignore
  85. +26 −0 src/mayaToAppleseed/vs2010/mayaToAppleseed.sln
  86. BIN  src/mayaToAppleseed/vs2010/mayaToAppleseed.suo
  87. +206 −0 src/mayaToAppleseed/vs2010/mayaToAppleseed.vcxproj
  88. +195 −0 src/mayaToAppleseed/vs2010/mayaToAppleseed.vcxproj.filters
  89. +10 −0 src/mayaToAppleseed/vs2010/mayaToAppleseed.vcxproj.user
View
3  .gitignore
@@ -10,3 +10,6 @@
*.lai
*.la
*.a
+
+# Compiled Python scripts
+*.pyc
View
9 README.md
@@ -7,4 +7,11 @@ There are connections for mantra (mayaToMantra) Appleseed (mayaToAppleseed) and
The idea is to develop a renderer framework to be able to implement a new renderer without reimplementing the
same procedures again and again.
-A description of all renderers is/will be available on http://www.openmaya.net.
+A description of all renderers is/will be available on http://www.openmaya.net.
+
+At the moment it's all VisualStudio project. Just starting to lear cmake, simply to be able to compile some OpenSource projects.
+
+Because these are my first steps releasing code, I'll have to learn a lot how to do it the right way. So please let me know how
+I can improve this project, or do it yourself.
+
+haggi
View
71 src/common/cpp/mayaObject.cpp
@@ -0,0 +1,71 @@
+#include <maya/MFnDagNode.h>
+#include <maya/MFnDependencyNode.h>
+
+#include "mayaObject.h"
+#include "utilities/logging.h"
+#include "utilities/tools.h"
+#include "utilities/attrTools.h"
+
+static Logging logger;
+
+bool MayaObject::geometryShapeSupported()
+{
+ return true;
+}
+
+bool MayaObject::shadowMapCastingLight()
+{
+ if(!this->mobject.hasFn(MFn::kLight))
+ return false;
+
+ MFnDependencyNode lightFn(this->mobject);
+
+ bool useDepthMapShadows = false;
+ if(!getBool(MString("useDepthMapShadows"), lightFn, useDepthMapShadows))
+ return false;
+
+ if(!useDepthMapShadows)
+ return false;
+
+ return true;
+}
+
+MayaObject::MayaObject(MObject& mobject)
+{
+ this->isInstancerObject = false;
+ this->origObject = NULL;
+ this->mobject = mobject;
+ this->supported = false;
+ this->shortName = getObjectName(mobject);
+ logger.debug(MString("Getting dagNode from: ") + getObjectName(mobject));
+ MFnDagNode dagNode(mobject);
+ dagNode.getPath(this->dagPath);
+ MString fullPath = dagNode.fullPathName();
+ logger.debug(MString("fullpath: ") + fullPath);
+ this->fullName = fullPath;
+ this->transformMatrices.push_back(this->dagPath.inclusiveMatrix());
+ this->instanceNumber = 0;
+ // check for light connection. If the geo is connected to a areaLight it is not supposed to be rendered
+ // but used as light geometry.
+ //checkLightConnection();
+
+ //getObjectShadingGroups(this->dagPath);
+ MFnDependencyNode depFn(mobject);
+ this->motionBlurred = true;
+ this->geometryMotionblur = false;
+
+ bool mb = true;
+ if( getBool(MString("motionBlur"), depFn, mb) )
+ this->motionBlurred = mb;
+
+ this->perObjectMbSteps = 1;
+ this->index = -1;
+ this->scenePtr = NULL;
+ this->lightExcludeList = true; // In most cases only a few lights are ignored, so the list is shorter with excluded lights
+ this->shadowExcludeList = true; // in most cases only a few objects ignore shadows, so the list is shorter with ignoring objects
+
+}
+
+
+MayaObject::~MayaObject()
+{}
View
59 src/common/cpp/mayaObject.h
@@ -0,0 +1,59 @@
+#ifndef MAYA_OBJECT_H
+#define MAYA_OBJECT_H
+
+#include <maya/MObject.h>
+#include <maya/MDagPath.h>
+#include <maya/MBoundingBox.h>
+#include <maya/MString.h>
+#include <maya/MMatrix.h>
+#include <vector>
+#include "shadingtools/material.h"
+
+//typedef void (*functionPointer)(void *, void *);
+
+class MayaScene;
+
+class MayaObject : public MBoundingBox
+{
+public:
+ MObject mobject;
+ MString shortName;
+ MString fullName;
+ int index;
+ MDagPath dagPath;
+ MayaScene *scenePtr;
+ std::vector<MDagPath> linkedLights; // for objects - light linking
+ bool lightExcludeList; // if true the linkedLights list contains excluded lights, else included lights
+ std::vector<MDagPath> shadowObjects; // for lights - shadow linking
+ bool shadowExcludeList; // if true the shadowObjects contains objects which ignores shadows from the current light
+ std::vector<MDagPath> castNoShadowObjects; // for lights - shadow linking
+
+
+ std::vector<MString> exportFileNames; // for every mb step complete filename for every exported shape file
+ std::vector<MString> hierarchyNames; // for every geo mb step I have one name, /obj/cube0, /obj/cube1...
+ std::vector<MMatrix> transformMatrices; // for every xmb step I have one matrix
+ std::vector<MString> shadowMapFiles; // file paths for a shadow map creating light
+
+ Material material;
+ // instancer node attributes
+ MMatrix instancerMatrix; // matrix of instancer node and paricle node
+ bool isInstancerObject; // is this an instancer object
+ int instancerParticleId;
+ MObject instancerMObj;
+
+ bool supported;
+ bool shapeConnected; // if shape connected, it can be used to determine if it has to be exported for every frame or not
+ bool visible; // important for instances: orig object can be invisible but must be exported
+ int instanceNumber;
+ int perObjectMbSteps; // default 1 can be overridden vor some renderers
+ bool motionBlurred; // possibility to turn off motionblur for this object
+ bool geometryMotionblur; // if object has vertex velocity informations, there is no need for real deformation blur
+ bool shadowMapCastingLight(); // to know if I have to add a light to render passes
+ virtual bool geometryShapeSupported() = 0;
+
+ MayaObject *origObject; // this is necessary for instanced objects that have to access the original objects data
+ MayaObject(MObject& mobject);
+ ~MayaObject();
+};
+
+#endif
View
903 src/common/cpp/mayaScene.cpp
@@ -0,0 +1,903 @@
+#include <maya/MDagPath.h>
+#include <maya/MItDag.h>
+#include <maya/MFnDagNode.h>
+#include <maya/MDagPathArray.h>
+#include <maya/MFnCamera.h>
+#include <maya/MFnDependencyNode.h>
+#include <maya/MFnInstancer.h>
+#include <maya/MMatrixArray.h>
+#include <maya/MIntArray.h>
+#include <maya/MLightLinks.h>
+#include <maya/MSelectionList.h>
+#include <maya/MGlobal.h>
+#include <maya/M3dView.h>
+#include <maya/MRenderView.h>
+
+#include "mayaScene.h"
+#include "utilities/logging.h"
+#include "utilities/tools.h"
+#include "utilities/attrTools.h"
+
+static Logging logger;
+
+MayaScene::MayaScene()
+{
+ this->good = true;
+}
+
+MayaScene::~MayaScene()
+{}
+
+// Here is checked if the linklist is complete, what means that we do not have to do any
+// complicated light linking, but default procedures. If excludedLights is > 0 then we found
+// any excluded Lights.
+bool MayaScene::listContainsAllLights(MDagPathArray& linkedLights, MDagPathArray& excludedLights)
+{
+ excludedLights.clear();
+ for( uint lId = 0; lId < this->lightList.size(); lId++)
+ {
+ MDagPath path = this->lightList[lId]->dagPath;
+ bool found = false;
+ for( uint liId = 0; liId < linkedLights.length(); liId++)
+ {
+ MDagPath linkedPath = linkedLights[liId];
+ if( linkedPath == path )
+ {
+ found = true;
+ break;
+ }
+ }
+ if( found )
+ continue;
+ else
+ excludedLights.append(path);
+ }
+
+ if( excludedLights.length() > 0)
+ return false;
+
+ return true;
+}
+
+// there are two types of linking, light linking and shadow linking.
+// Light linking will be done in the object attributes, whereas shadow linking is an attribute of a light
+void MayaScene::getLightLinking()
+{
+ //logger.debug(MString("----------- MayaScene::getLightLinking ---------------"));
+ MLightLinks lightLink;
+ bool parseStatus;
+ //parseStatus = lightLink.parseLinks(MObject::kNullObj, useIgnore = true);
+ parseStatus = lightLink.parseLinks(MObject::kNullObj);
+ MDagPathArray lightArray, excludeLights;
+ MObject nullObj;
+ std::vector<MayaObject *> castNoShadowObjects;
+
+ for( int oId = 0; oId < this->objectList.size(); oId++)
+ {
+ MayaObject *mo = this->objectList[oId];
+ MDagPath path = mo->dagPath;
+ // the ignored list is more useful because if we have no ignored lights the list is empty
+ // at the moment this does not work for lights with "illuminates by default" turned off, so
+ // I use the linkedLights which works and search for excluded ones
+ mo->linkedLights.clear();
+ //lightLink.getIgnoredLights(path, nullObj, lightArray);
+ //for( int ll = 0; ll < lightArray.length(); ll++)
+ //{
+ // MDagPath lpath = lightArray[ll];
+ // logger.debug(lpath.partialPathName() + " is ignored by " + path.partialPathName());
+ // mo->linkedLights.push_back(lpath);
+ //}
+
+ lightLink.getLinkedLights(path, nullObj, lightArray);
+ this->listContainsAllLights(lightArray, excludeLights);
+ //logger.debug(MString("Exclude list contains: ") + excludeLights.length() + " lights");
+ for( uint ll = 0; ll < excludeLights.length(); ll++)
+ {
+ MDagPath lpath = excludeLights[ll];
+ //logger.debug(lpath.partialPathName() + " is ignored by " + path.partialPathName());
+ mo->linkedLights.push_back(lpath);
+ }
+
+ bool castsShadows = true;
+ MFnDependencyNode dn(mo->mobject);
+ if( getBool(MString("castsShadows"), dn, castsShadows))
+ {
+ if( !castsShadows )
+ castNoShadowObjects.push_back(mo);
+ }
+ // leave for later implementation: Compare include and exclude list and create the shorter one if necessary
+ // not sure if this is useful at all...
+ //if( !this->listContainsAllLights(lightArray, excludeLights) )
+ //{
+ // for( int ll = 0; ll < lightArray.length(); ll++)
+ // {
+ // this->objectList[oId]->linkedLights.push_back(lightArray[ll]);
+ // }
+ //}else{
+ // logger.debug(path.partialPathName() + " is connected to all lights.");
+ //}
+ }
+
+ // shadow linking. Get objects which ignores shadows from a specific light
+ MSelectionList selectionList;
+ for( uint lId = 0; lId < this->lightList.size(); lId++)
+ {
+ if( castNoShadowObjects.size() > 0)
+ {
+ for( uint oId = 0; oId < castNoShadowObjects.size(); oId++)
+ {
+ this->lightList[lId]->castNoShadowObjects.push_back(castNoShadowObjects[oId]->dagPath);
+ }
+ }
+ //MayaObject *mo = this->lightList[lId];
+ //MDagPath path = mo->dagPath;
+ //selectionList.clear();
+ //lightLink.getShadowIgnoredObjects(path, selectionList);
+ //int numObj = selectionList.length();
+ //for( int oId = 0; oId < numObj; oId++)
+ //{
+ // MDagPath obDag;
+ // selectionList.getDagPath(oId, obDag);
+ // logger.debug(MString("Object ") + obDag.partialPathName() + " ignores shadows from " + path.partialPathName());
+ // mo->shadowObjects.push_back(obDag);
+ //}
+ }
+
+ // search for shadow ignoring objects
+ for( uint lId = 0; lId < this->lightList.size(); lId++)
+ {
+ MayaObject *mo = this->lightList[lId];
+ MDagPath path = mo->dagPath;
+ selectionList.clear();
+ lightLink.getShadowIgnoredObjects(path, selectionList);
+ int numObj = selectionList.length();
+ for( int oId = 0; oId < numObj; oId++)
+ {
+ MDagPath obDag;
+ selectionList.getDagPath(oId, obDag);
+ //logger.debug(MString("Object ") + obDag.partialPathName() + " ignores shadows from " + path.partialPathName());
+ mo->shadowObjects.push_back(obDag);
+ }
+ }
+}
+
+//bool MayaScene::translateShaders()
+//{
+// return true;
+//}
+//
+//bool MayaScene::translateShapes()
+//{
+// return true;
+//}
+
+bool MayaScene::parseScene()
+{
+ logger.debug(MString("parseScene"));
+
+ instancerDagPathList.clear();
+
+ MItDag dagIterator(MItDag::kDepthFirst, MFn::kInvalid);
+ MDagPath dagPath;
+
+ for (dagIterator.reset(); (!dagIterator.isDone()); dagIterator.next())
+ {
+ if (!dagIterator.getPath(dagPath))
+ {
+ logger.error(MString("parseScene ERROR: Could not get path for DAG iterator."));
+ return false;
+ }
+ logger.debug(MString("Parse Object: ") + getObjectName(dagPath.node()));
+
+ MFnDagNode node(dagPath.node());
+ MObject obj = node.object();
+
+ // here only base objects, instances will be exported later directly
+ int instanceNumber = dagPath.instanceNumber();
+
+ if( instanceNumber > 0 )
+ continue;
+
+ if (dagPath.apiType() == MFn::kWorld)
+ continue;
+
+ if (obj.hasFn(MFn::kCamera))
+ {
+ MFnCamera cam(obj);
+ bool renderable = false;
+
+ // ignore all cameras that are not renderable
+ if(!getBool(MString("renderable"), cam, renderable))
+ continue;
+
+ if( renderable )
+ {
+ MayaObject *mo = this->mayaObjectCreator(obj);
+ mo->visible = true;
+ mo->scenePtr = this;
+ mo->instanceNumber = 0;
+ this->camList.push_back(mo);
+ mo->index = (int)(this->camList.size() - 1);
+ continue;
+ }
+ }
+
+ if (obj.hasFn(MFn::kLight))
+ {
+
+ if (!IsVisible(node) || IsTemplated(node) || !IsInRenderLayer(dagPath) || !IsPathVisible(dagPath))
+ continue;
+ else{
+ MayaObject *mo = this->mayaObjectCreator(obj);
+ mo->visible = true;
+ mo->instanceNumber = 0;
+ mo->scenePtr = this;
+ //mo->findObject = &this->getObject;
+ this->lightList.push_back(mo);
+ mo->index = (int)(this->lightList.size() - 1);
+ continue;
+ }
+ }
+
+ if (dagPath.apiType() == MFn::kInstancer)
+ {
+ this->instancerDagPathList.push_back(dagPath);
+ }
+
+ MFnDependencyNode depFn(obj);
+ uint nodeId = depFn.typeId().id();
+ for( uint lId = 0; lId < this->lightIdentifier.size(); lId++)
+ {
+ bool nodeFound = false;
+ if( nodeId == this->lightIdentifier[lId])
+ {
+ nodeFound = true;
+ logger.debug("Found external light node.");
+ if (!IsVisible(node) || IsTemplated(node) || !IsInRenderLayer(dagPath) || !IsPathVisible(dagPath))
+ {
+ continue;
+ }else{
+ MayaObject *mo = this->mayaObjectCreator(obj);
+ mo->visible = true;
+ mo->instanceNumber = 0;
+ mo->scenePtr = this;
+ //mo->findObject = &this->getObject;
+ this->lightList.push_back(mo);
+ mo->index = (int)(this->lightList.size() - 1);
+ continue;
+ }
+ }
+ if( nodeFound )
+ continue;
+ }
+
+ bool visible = true;
+ if (!IsVisible(node) || IsTemplated(node) || !IsInRenderLayer(dagPath) || !IsPathVisible(dagPath))
+ {
+ int numi = dagIterator.instanceCount(true);
+ if( numi > 1 )
+ {
+ logger.info(MString("Object ") + node.name() + " has instances but is not visible. Set it to invisble but export geo");
+
+ // okay I am an original object of an instance, now check if any of my instanced objects is visible
+ MDagPathArray instPathArray;
+ dagIterator.getAllPaths(instPathArray);
+ bool visibleInstFound = false;
+ for( uint iId = 0; iId < instPathArray.length(); iId++)
+ {
+ MFnDagNode inode(instPathArray[iId].node());
+ if (IsVisible(inode) || !IsTemplated(inode) || IsInRenderLayer(instPathArray[iId]) || IsPathVisible(instPathArray[iId]))
+ {
+ logger.info(MString("Found a visible instance for object: ") + inode.name());
+ visibleInstFound = true;
+ break;
+ }
+ }
+ if( !visibleInstFound)
+ continue;
+ visible = false;
+ }else{
+ continue;
+ }
+ }
+
+ MayaObject *mo = this->mayaObjectCreator(node.object());
+ mo->scenePtr = this;
+ //mo->findObject = &this->getObject;
+ mo->visible = visible;
+ mo->instanceNumber = instanceNumber;
+ this->objectList.push_back(mo);
+ mo->index = (int)(this->objectList.size() - 1);
+ }
+
+ int numobjects = (int)this->objectList.size();
+ if( numobjects == 0)
+ {
+ logger.error(MString("Scene parse: No renderable object found"));
+ this->good = false;
+ return false;
+ }
+
+ // get instances
+ // the idea is, simply to copy the original object and set the necessary values only.
+ // I have to access the original MayaObject to be able to get the HierarchyNameList for mb data.
+
+ int numObjects = (int)this->objectList.size();
+ for( int objId = 0; objId < numobjects; objId++)
+ {
+ MDagPathArray instArray;
+ MayaObject *mo = this->objectList[objId];
+ mo->dagPath.getAllPathsTo(mo->mobject, instArray);
+ int numPaths = instArray.length();
+ if( numPaths > 1)
+ {
+ logger.debug( MString("Found ") + (numPaths - 1) + " instances for " + mo->shortName);
+ for( uint iId = 1; iId < instArray.length(); iId++)
+ {
+ MFnDagNode node(instArray[iId].node());
+ MDagPath dagPath = instArray[iId];
+ //logger.debug(MString("Inst node: ") + node.name());
+ //logger.debug(MString("Full path name: ") + instArray[iId].fullPathName());
+ MMatrix m0 = instArray[iId].inclusiveMatrix();
+
+ if (!IsVisible(node) || IsTemplated(node) || !IsInRenderLayer(instArray[iId]) || !IsPathVisible(instArray[iId]))
+ continue;
+ MayaObject *newObj = this->mayaObjectCreator(node.object());
+ *newObj = *mo;
+ //logger.debug(MString("new Object Full path name: ") + newObj->dagPath.fullPathName());
+ //logger.debug(MString("new instArray[iId] path name: ") + dagPath.fullPathName());
+ newObj->dagPath = dagPath;
+ newObj->visible = true;
+ newObj->supported = true;
+ newObj->origObject = mo;
+ newObj->instanceNumber = iId;
+ newObj->transformMatrices.clear();
+ //MMatrix m = newObj->dagPath.inclusiveMatrix();
+ newObj->transformMatrices.push_back(newObj->dagPath.inclusiveMatrix());
+ //MObject parent = node.parent(0);
+ //MFnDagNode pNode(parent);
+ //logger.debug(MString("Full parent path name: ") + pNode.fullPathName());
+ //newObj->transformMatrices.push_back(pNode.dagPath().inclusiveMatrix());
+ //MMatrix m1 = pNode.dagPath().inclusiveMatrix();
+
+ this->objectList.push_back(newObj);
+ newObj->index = (int)(this->objectList.size() - 1);
+ }
+ }
+ }
+
+ this->parseInstancer();
+
+ this->getLightLinking();
+
+ if( MGlobal::mayaState() != MGlobal::kBatch )
+ {
+ // clear cameras and use only the active one
+ this->clearObjList(this->camList);
+ // if we are in UI rendering state, try to get the current camera
+ M3dView curView = M3dView::active3dView();
+ MDagPath camDagPath;
+ curView.getCamera( camDagPath );
+ MayaObject *mo = this->mayaObjectCreator(camDagPath.node());
+ mo->visible = true;
+ mo->scenePtr = this;
+ mo->instanceNumber = 0;
+ this->camList.push_back(mo);
+ mo->index = (int)(this->camList.size() - 1);
+ }
+
+ this->good = true;
+ return true;
+
+}
+
+
+bool MayaScene::updateScene()
+{
+
+ if(this->renderGlobals->currentMbElement.elementType == MbElement::XForm )
+ logger.debug(MString("MayaScene::updateScene for XForm step"));
+ if(this->renderGlobals->currentMbElement.elementType == MbElement::Geo )
+ logger.debug(MString("MayaScene::updateScene for Deform step"));
+ if(this->renderGlobals->currentMbElement.elementType == MbElement::Both )
+ logger.debug(MString("MayaScene::updateScene for Deform and XForm step"));
+
+ int numElements = (int)this->objectList.size();
+ for( int objId = 0; objId < numElements; objId++)
+ {
+ MayaObject *obj = (MayaObject *)this->objectList[objId];
+
+ // check if the geometry shape is supported
+ if( !obj->geometryShapeSupported() )
+ continue;
+
+ // if this is not the very first time step of a rendering
+ // we must be in a motionblur step
+ // isMbStartStep will be always true in an animation without motionblur
+ if( !this->renderGlobals->isMbStartStep )
+ {
+ if( !obj->motionBlurred )
+ {
+ continue;
+ }
+ }
+
+ // clear transformation matrices if we are at very first mb step
+ // we can have xform and deform steps for the same timeframe
+ // currentMbStep is only 0 for the very first step
+ if( this->renderGlobals->isMbStartStep && this->renderGlobals->isTransformStep())
+ {
+ obj->transformMatrices.clear();
+ }
+
+ if( this->renderGlobals->isTransformStep() )
+ {
+ obj->transformMatrices.push_back(obj->dagPath.inclusiveMatrix());
+ this->transformUpdateCallback(*obj);
+ continue;
+ }
+
+ // if we are here at the very first motionBlur step, then remove export filesNames, export filenames will be automatically filled by the exporter
+ // at start frame, always clear
+ // not at start frame only clear if shapedeformation is detected
+ if( this->renderGlobals->isMbStartStep )
+ {
+ if( this->renderGlobals->currentFrameNumber != this->renderGlobals->startFrame )
+ {
+ if( obj->shapeConnected && this->renderGlobals->detectShapeDeform)
+ {
+ obj->exportFileNames.clear();
+ }
+ }else{
+ obj->exportFileNames.clear();
+ }
+ }
+
+ if( this->renderGlobals->isMbStartStep )
+ {
+ if(this->renderGlobals->isTransformStep())
+ {
+ }
+ if(this->renderGlobals->isDeformStep())
+ {
+ if( (!obj->isInstancerObject) &&
+ ( obj->instanceNumber == 0))
+ {
+ if( obj->exportFileNames.size() == 0)
+ {
+ this->deformUpdateCallback(*obj);
+ }
+ }
+ }
+ }else{
+ // only export if shape has deformation, of course only for original shapes
+ if(obj->shapeConnected && this->renderGlobals->detectShapeDeform && (!obj->isInstancerObject) && (obj->instanceNumber == 0))
+ {
+ // during motion step
+ if( this->renderGlobals->isDeformStep() )
+ {
+ // in case of geometryMotionblur, we need only the first export filename, no additional steps
+ if(obj->geometryMotionblur )
+ continue;
+ logger.debug(MString("Deforming object not at start frame -> exporting ") + obj->shortName);
+ this->deformUpdateCallback(*obj);
+ }
+ }
+ }
+ }
+
+ numElements = (int)this->camList.size();
+ for( int objId = 0; objId < numElements; objId++)
+ {
+ MayaObject *obj = (MayaObject *)this->camList[objId];
+ if( this->renderGlobals->currentMbStep == 0)
+ obj->transformMatrices.clear();
+
+ if( this->renderGlobals->isTransformStep() )
+ {
+ logger.debug(MString("Adding cam transform at time ") + this->renderGlobals->currentFrameNumber);
+ obj->transformMatrices.push_back(obj->dagPath.inclusiveMatrix());
+ this->transformUpdateCallback(*obj);
+ }
+ if( obj->transformMatrices.size() > 1)
+ {
+ MMatrix m1 = obj->transformMatrices[0];
+ MMatrix m2 = obj->transformMatrices[1];
+ logger.debug(MString("CamMatrix1: t: ") + m1[3][0] + " " + m1[3][1] + " " + m1[3][2]);
+ logger.debug(MString("CamMatrix2: t: ") + m2[3][0] + " " + m2[3][1] + " " + m2[3][2]);
+ }
+ }
+
+ numElements = (int)this->lightList.size();
+ for( int objId = 0; objId < numElements; objId++)
+ {
+ MayaObject *obj = (MayaObject *)this->lightList[objId];
+ if( this->renderGlobals->currentMbStep == 0 )
+ obj->transformMatrices.clear();
+
+ if( this->renderGlobals->isTransformStep() )
+ {
+ obj->transformMatrices.push_back(obj->dagPath.inclusiveMatrix());
+ this->transformUpdateCallback(*obj);
+ }
+ }
+
+ // Recreate the instancer array for every frame. If we are in a motion blur step, update it.
+ // With no motionblur, clear the array and re-parse the instancers. This is necessary because the contents of the instancer
+ // can vary from frame to frame e.g. if instances disappear with the death of a particle
+ if( !this->renderGlobals->doMb )
+ {
+ this->clearInstancerNodeList();
+ this->parseInstancer();
+ }else{
+ this->updateInstancer();
+ }
+
+ return true;
+}
+
+void MayaScene::clearObjList(std::vector<MayaObject *>& objList)
+{
+ size_t numElements = objList.size();
+ for( size_t i = 0; i < numElements; i++)
+ this->mayaObjectDeleter(objList[i]);
+ objList.clear();
+}
+
+void MayaScene::clearInstancerNodeList()
+{
+ size_t numElements = this->instancerNodeElements.size();
+ for( size_t i = 0; i < numElements; i++)
+ this->mayaObjectDeleter(this->instancerNodeElements[i]);
+
+ this->instancerNodeElements.clear();
+}
+
+bool MayaScene::updateInstancer()
+{
+ size_t numElements = this->instancerNodeElements.size();
+ for( size_t i = 0; i < numElements; i++)
+ {
+ MayaObject *obj = this->instancerNodeElements[i];
+ MFnInstancer instFn(obj->instancerMObj);
+ MDagPathArray dagPathArray;
+ MMatrix matrix;
+ instFn.instancesForParticle(obj->instancerParticleId, dagPathArray, matrix);
+ // get matrix from current path?
+ obj->transformMatrices.push_back(matrix);
+ }
+ return true;
+}
+
+std::vector<MayaObject *> InstDoneList;
+// parsing all particle instancer nodes in the scene
+// here I put all nodes created by an instancer node into a array of its own.
+// The reason why I don't simply add it to the main list is that I have to recreate them
+// during sceneUpdate() for every frame because the list can change with the birth or death
+// of a particle
+bool MayaScene::parseInstancer()
+{
+ bool result = true;
+
+ InstDoneList.clear();
+
+ MDagPath dagPath;
+ int numInstancers = (int)instancerDagPathList.size();
+ int numobjects = (int)this->objectList.size();
+
+ for(int iId = 0; iId < numInstancers; iId++)
+ {
+ MDagPath instPath = instancerDagPathList[iId];
+ MObject instancerMObject = instPath.node();
+ MString path = instPath.fullPathName();
+ MFnInstancer instFn(instPath);
+ int numParticles = instFn.particleCount();
+ logger.debug(MString("Detected instancer. instPath: ") + path + " it has " + numParticles + " particle instances");
+ MDagPathArray allPaths;
+ MMatrixArray allMatrices;
+ MIntArray pathIndices;
+ MIntArray pathStartIndices;
+
+ // give me all instances in this instancer
+ instFn.allInstances( allPaths, allMatrices, pathStartIndices, pathIndices );
+
+ for( int p = 0; p < numParticles; p++ )
+ {
+ MMatrix particleMatrix = allMatrices[p];
+
+ // the number of paths instanced under a particle is computed by
+ // taking the difference between the starting path index for this
+ // particle and that of the next particle. The size of the start
+ // index array is always one larger than the number of particles.
+ //
+ int numPaths = pathStartIndices[p+1]-pathStartIndices[p];
+
+ // the values pathIndices[pathStart...pathStart+numPaths] give the
+ // indices in the allPaths array of the paths instanced under this
+ // particular particle. Remember, different paths can be instanced
+ // under each particle.
+ //
+ int pathStart = pathStartIndices[p];
+
+ // loop through the instanced paths for this particle
+ //
+ MayaObject *mo = NULL;
+ MayaObject *origObj = NULL;
+ for( int i = pathStart; i < pathStart+numPaths; i++ )
+ {
+ int curPathIndex = pathIndices[i];
+ MDagPath curPath = allPaths[curPathIndex];
+
+ // search for the correct orig MayaObject element
+ // first search the already done list, this could be faster
+ int numObj = (int)InstDoneList.size();
+ bool found = false;
+ MDagPath dp = curPath;
+ MObject thisObject = curPath.node();
+ MObject foundObject = MObject::kNullObj;
+ for( int oId = 0; oId < numObj; oId++)
+ {
+ MObject doneObj = InstDoneList[oId]->mobject;
+ if( doneObj == thisObject)
+ {
+ logger.debug("Found mobject in instancer done list");
+ origObj = InstDoneList[oId];
+ found = true;
+ break;
+ }
+ }
+ // well it is not in the done list, so search the whole obj list for instances
+ if( !found)
+ {
+ int foundId = -1;
+ for( int oId = 0; oId < numobjects; oId++)
+ {
+ mo = this->objectList[oId];
+ MObject doneObj = mo->mobject;
+ if( doneObj == thisObject)
+ {
+ logger.debug("Found mobject in all list");
+ found = true;
+ origObj = mo;
+ InstDoneList.push_back(mo);
+ break;
+ }
+ }
+ }
+ // TODO: visibiliy check - necessary?
+ MMatrix instancedPathMatrix = curPath.inclusiveMatrix();
+ MMatrix finalMatrixForPath = instancedPathMatrix * particleMatrix;
+ MPoint finalPoint = MPoint::origin * finalMatrixForPath;
+ MDagPath cp = curPath;
+ MayaObject *newObj = this->mayaObjectCreator(thisObject);
+ *newObj = *origObj;
+ newObj->dagPath = cp;
+ newObj->origObject = origObj;
+ newObj->isInstancerObject = true;
+ newObj->instancerMatrix = finalMatrixForPath;
+ newObj->transformMatrices.clear();
+ newObj->transformMatrices.push_back(finalMatrixForPath);
+ newObj->supported = true;
+ newObj->visible = true;
+ newObj->instancerParticleId = p;
+ newObj->instanceNumber = p;
+ newObj->instancerMObj = instancerMObject;
+ newObj->fullName = origObj->fullName + MString("_i_") + p;
+ newObj->shortName = origObj->shortName + MString("_i_") + p;
+ this->instancerNodeElements.push_back(newObj);
+ //this->objectList.push_back(newObj);
+ newObj->index = (int)(this->instancerNodeElements.size() - 1);
+
+ MString instancedPathName = curPath.fullPathName();
+ //logger.info(instancedPathName + " pos " + finalPoint.x + " " + finalPoint.y + " " + finalPoint.z);
+
+ }
+ }
+ }
+ return true;
+}
+
+bool MayaScene::getShadingGroups()
+{
+ size_t numobjects = this->objectList.size();
+ for( size_t objId = 0; objId < numobjects; objId++)
+ {
+ MayaObject *mo = this->objectList[objId];
+ MObject sg;
+ if(getObjectShadingGroups(mo->dagPath, sg))
+ mo->material = Material(sg);
+ }
+ numobjects = this->instancerNodeElements.size();
+ for( uint objId = 0; objId < numobjects; objId++)
+ {
+ MayaObject *mo = this->instancerNodeElements[objId];
+ MObject sg;
+ if(getObjectShadingGroups(mo->dagPath, sg))
+ mo->material = Material(sg);
+ }
+ numobjects = this->lightList.size();
+ for( uint objId = 0; objId < numobjects; objId++)
+ {
+ MayaObject *mo = this->lightList[objId];
+ MObject sg = mo->mobject;
+ mo->material = Material(sg);
+ }
+ return true;
+}
+
+void MayaScene::getPasses()
+{
+ // clear
+ for( size_t renderPassId = 0; renderPassId < this->renderGlobals->renderPasses.size(); renderPassId++)
+ delete this->renderGlobals->renderPasses[renderPassId];
+ this->renderGlobals->renderPasses.clear();
+
+ // add pass for lights for shadow maps
+
+ // add pass for lights with photon maps
+
+ // finally do the normal beauty passes
+ RenderPass *rp = new RenderPass();
+ rp->evalFrequency = RenderPass::OncePerFrame;
+ rp->passType = RenderPass::Beauty;
+
+ int numcams = (int)this->camList.size();
+ for( int objId = 0; objId < numcams; objId++)
+ {
+ MayaObject *obj = this->camList[objId];
+ rp->objectList.push_back(obj);
+ }
+
+ this->renderGlobals->renderPasses.push_back(rp);
+}
+
+
+bool MayaScene::doFrameJobs()
+{
+ logger.debug("MayaScene::doFrameJobs()");
+ logger.progress(MString("\n========== Start rendering of frame ") + this->currentFrame + " ==============\n");
+
+ size_t numPasses = this->renderGlobals->renderPasses.size();
+ for( size_t passId = 0; passId < numPasses; passId++)
+ {
+ // Get the objects from the currentPass object list.
+ // In case of a shadow map generation it is a light,
+ // in case of a beauty its a camera.
+ this->renderGlobals->currentRenderPass = this->renderGlobals->renderPasses[passId];
+ size_t numPassElements = this->renderGlobals->currentRenderPass->objectList.size();
+ for( size_t passElementId = 0; passElementId < numPassElements; passElementId++)
+ {
+
+ this->renderGlobals->currentRenderPassElementId = passElementId;
+ if( this->renderGlobals->currentRenderPass->passType == RenderPass::Beauty)
+ {
+ MayaObject *camera = (MayaObject *)this->renderGlobals->currentRenderPass->objectList[passElementId];
+ this->renderGlobals->getMbSteps(camera->mobject);
+ }
+
+ if(this->renderGlobals->mbElementList.size() == 0)
+ {
+ logger.error(MString("no mb steps, somethings wrong."));
+ return false;
+ }
+
+ int numMbSteps = (int)this->renderGlobals->mbElementList.size();
+ logger.debug(MString("mbSteps: ") + numMbSteps);
+ this->renderGlobals->currentMbStep = 0;
+
+ for( int mbStepId = 0; mbStepId < numMbSteps; mbStepId++)
+ {
+ this->renderGlobals->isMbStartStep = this->renderGlobals->mbElementList[mbStepId].time == this->renderGlobals->mbElementList[0].time;
+ this->renderGlobals->currentMbElement = this->renderGlobals->mbElementList[mbStepId];
+ this->renderGlobals->currentFrameNumber = (float)(this->renderGlobals->currentFrame + this->renderGlobals->mbElementList[mbStepId].time);
+ bool needView = true;
+ if( mbStepId > 0)
+ {
+ if( this->renderGlobals->mbElementList[mbStepId].time != this->renderGlobals->mbElementList[mbStepId-1].time)
+ {
+ needView = true;
+ }else{
+ needView = false;
+ }
+ }
+ if( needView )
+ {
+ MayaObject *camera = (MayaObject *)this->renderGlobals->currentRenderPass->objectList[passElementId];
+ logger.debug(MString("doFrameJobs() viewFrame: ") + this->renderGlobals->currentFrameNumber);
+ if( MGlobal::mayaState() != MGlobal::kBatch )
+ {
+ if( MRenderView::setCurrentCamera( camera->dagPath ) != MS::kSuccess )
+ {
+ logger.error("renderViewRender: error occurred in setCurrentCamera." );
+ return false;
+ }
+ }
+ MGlobal::viewFrame(this->renderGlobals->currentFrameNumber);
+ }
+
+ // TODO: runup necessary?
+
+ this->updateScene();
+ logger.info(MString("update scene done"));
+ this->renderGlobals->currentMbStep++;
+ }
+ this->renderImage();
+ }
+ }
+
+ // if we render from UI jump back to full frame after rendering
+ if( MGlobal::mayaState() != MGlobal::kBatch )
+ MGlobal::viewFrame(this->renderGlobals->currentFrame);
+
+ return true;
+}
+
+
+bool MayaScene::renderScene()
+{
+ logger.info("MayaScene::renderScene()");
+ this->getPasses();
+
+ if(!this->doPreRenderJobs())
+ {
+ logger.error("doPreRenderJobs failed.");
+ return false;
+ }
+
+ int numFrames = (int)this->renderGlobals->frameList.size();
+ for( int frameNr = 0; frameNr < numFrames; frameNr++)
+ {
+ this->currentFrame = this->renderGlobals->frameList[frameNr];
+ this->renderGlobals->currentFrame = this->currentFrame;
+ if(!this->doPreFrameJobs())
+ {
+ logger.error("doPreFrameJobs failed.");
+ return false;
+ }
+ if(!this->doFrameJobs())
+ {
+ logger.error("doFrameJobs failed.");
+ return false;
+ }
+
+ if(!this->doPostFrameJobs())
+ {
+ logger.error("doPostFrameJobs failed.");
+ return false;
+ }
+ logger.progress(MString("\n========== Rendering of frame ") + this->currentFrame + " done ==============\n");
+ }
+
+ if(!this->doPostRenderJobs())
+ {
+ logger.error("doPostRenderJobs failed.");
+ return false;
+ }
+
+
+ return true;
+}
+
+MayaObject *MayaScene::getObject(MObject obj)
+{
+ MayaObject *mo = NULL;
+ size_t numobjects = this->objectList.size();
+ for( size_t objId = 0; objId < numobjects; objId++)
+ {
+ if( this->objectList[objId]->mobject == obj)
+ return this->objectList[objId];
+ }
+ return mo;
+}
+
+MayaObject *MayaScene::getObject(MDagPath dp)
+{
+ MayaObject *mo = NULL;
+ size_t numobjects = this->objectList.size();
+ for( size_t objId = 0; objId < numobjects; objId++)
+ {
+ if( this->objectList[objId]->dagPath == dp)
+ return this->objectList[objId];
+ }
+ return mo;
+}
View
64 src/common/cpp/mayaScene.h
@@ -0,0 +1,64 @@
+#ifndef MAYA_SCENE_H
+#define MAYA_SCENE_H
+
+#include <maya/MDagPath.h>
+#include <maya/MObject.h>
+#include <maya/MDagPathArray.h>
+#include <vector>
+
+#include "renderGlobals.h"
+#include "mayaObject.h"
+
+class MayaScene
+{
+public:
+ bool good;
+ std::vector<int> lightIdentifier; // plugids for detecting new lighttypes
+ std::vector<int> objectIdentifier; // plugids for detecting new objTypes
+
+ std::vector<MObject> mObjectList;
+ std::vector<MayaObject *> objectList;
+ std::vector<MayaObject *> camList;
+ std::vector<MayaObject *> lightList;
+ std::vector<MayaObject *> instancerNodeElements; // so its easier to update them
+
+ std::vector<MDagPath> instancerDagPathList;
+
+ float currentFrame;
+ RenderGlobals *renderGlobals;
+
+ bool parseScene(); // pase whole scene and save/analyze objects
+ bool parseInstancer(); // parse only particle instancer nodes, its a bit more complex
+ bool updateScene(); // update all necessary objects
+ virtual void transformUpdateCallback(MayaObject&) = 0;
+ virtual void deformUpdateCallback(MayaObject&) = 0;
+ bool updateInstancer(); // update all necessary objects
+ virtual bool translateShaders(int timeStep) = 0; // overwrite this in your definition
+ virtual bool translateShapes(int timeStep) = 0; // overwrite this in your definition
+ bool renderScene();
+ virtual bool doPreRenderJobs() = 0; // overwrite this in your definition
+ bool doFrameJobs(); // overwrite this in your definition
+ virtual bool renderImage() = 0; // the actual render job, overwrite
+ virtual bool doPreFrameJobs() = 0; // overwrite this in your definition
+ virtual bool doPostFrameJobs() = 0; // overwrite this in your definition
+ virtual bool doPostRenderJobs() = 0; // overwrite this in your definition
+ void clearInstancerNodeList();
+ void clearObjList(std::vector<MayaObject *>& objList);
+ bool getShadingGroups();
+ void getLightLinking();
+ bool listContainsAllLights(MDagPathArray& linkedLights, MDagPathArray& excludedLights);
+ virtual MayaObject* mayaObjectCreator(MObject&) = 0;
+ virtual void mayaObjectDeleter(MayaObject *) = 0;
+ virtual void getRenderGlobals() = 0;
+ void getPasses();
+
+
+ MayaObject *getObject(MObject obj);
+ MayaObject *getObject(MDagPath dp);
+ MayaScene();
+ ~MayaScene();
+};
+
+
+
+#endif
View
130 src/common/cpp/mayarendernodes/renderGlobalsNode.cpp
@@ -0,0 +1,130 @@
+#include <maya/MFnNumericAttribute.h>
+#include <maya/MFnTypedAttribute.h>
+#include <maya/MFnGenericAttribute.h>
+#include <maya/MFnEnumAttribute.h>
+
+#include <maya/MGlobal.h>
+#include <maya/MFnPluginData.h>
+#include "renderGlobalsNode.h"
+
+ // sampling adaptive
+MObject MayaRenderGlobalsNode::adaptiveSampling;
+
+MObject MayaRenderGlobalsNode::minSamples;
+MObject MayaRenderGlobalsNode::maxSamples;
+
+ // sampling raster based
+MObject MayaRenderGlobalsNode::samplesX;
+MObject MayaRenderGlobalsNode::samplesY;
+
+MObject MayaRenderGlobalsNode::doMotionBlur;
+MObject MayaRenderGlobalsNode::doDof;
+
+MObject MayaRenderGlobalsNode::threads;
+
+MObject MayaRenderGlobalsNode::translatorVerbosity;
+MObject MayaRenderGlobalsNode::rendererVerbosity;
+
+MObject MayaRenderGlobalsNode::detectShapeDeform;
+
+// pixel filtering
+MObject MayaRenderGlobalsNode::filtersize;
+MObject MayaRenderGlobalsNode::tilesize;
+MObject MayaRenderGlobalsNode::gamma;
+
+
+MObject MayaRenderGlobalsNode::imageName;
+MObject MayaRenderGlobalsNode::basePath;
+MObject MayaRenderGlobalsNode::imagePath;
+
+MObject MayaRenderGlobalsNode::maxTraceDepth;
+
+MayaRenderGlobalsNode::MayaRenderGlobalsNode()
+{
+}
+
+MayaRenderGlobalsNode::~MayaRenderGlobalsNode()
+{}
+
+void *MayaRenderGlobalsNode::creator()
+{
+ return new MayaRenderGlobalsNode();
+}
+
+MStatus MayaRenderGlobalsNode::initialize()
+{
+ MFnNumericAttribute nAttr;
+ MFnTypedAttribute tAttr;
+ MFnGenericAttribute gAttr;
+ MFnEnumAttribute eAttr;
+ MStatus stat = MStatus::kSuccess;
+
+ // sampling adaptive
+ minSamples = nAttr.create("minSamples", "minSamples", MFnNumericData::kInt, 1);
+ CHECK_MSTATUS(addAttribute( minSamples ));
+ maxSamples = nAttr.create("maxSamples", "maxSamples", MFnNumericData::kInt, 16);
+ CHECK_MSTATUS(addAttribute( maxSamples ));
+
+ // sampling raster based
+ samplesX = nAttr.create("samplesX", "samplesX", MFnNumericData::kInt, 3);
+ CHECK_MSTATUS(addAttribute( samplesX ));
+ samplesY = nAttr.create("samplesY", "samplesY", MFnNumericData::kInt, 3);
+ CHECK_MSTATUS(addAttribute( samplesY ));
+
+ doMotionBlur = nAttr.create("doMotionBlur", "doMotionBlur", MFnNumericData::kBoolean, false);
+ CHECK_MSTATUS(addAttribute( doMotionBlur ));
+ doDof = nAttr.create("doDof", "doDof", MFnNumericData::kBoolean, false);
+ CHECK_MSTATUS(addAttribute( doDof ));
+
+ MString numCpu = getenv("NUMBER_OF_PROCESSORS");
+ int numberOfProcessors = numCpu.asInt();
+ threads = nAttr.create("threads", "threads", MFnNumericData::kInt, numberOfProcessors);
+ CHECK_MSTATUS(addAttribute( threads ));
+
+ translatorVerbosity = eAttr.create("translatorVerbosity", "translatorVerbosity", 2, &stat);
+ stat = eAttr.addField( "Info", 0 );
+ stat = eAttr.addField( "Error", 1 );
+ stat = eAttr.addField( "Warning", 2 );
+ stat = eAttr.addField( "Progress", 3 );
+ stat = eAttr.addField( "Debug", 4 );
+ stat = eAttr.addField( "None", 5 );
+ CHECK_MSTATUS(addAttribute( translatorVerbosity ));
+
+ rendererVerbosity = nAttr.create("rendererVerbosity", "rendererVerbosity", MFnNumericData::kInt, 2);
+ CHECK_MSTATUS(addAttribute( rendererVerbosity ));
+
+ detectShapeDeform = nAttr.create("detectShapeDeform", "detectShapeDeform", MFnNumericData::kBoolean, true);
+ CHECK_MSTATUS(addAttribute( detectShapeDeform ));
+
+ filtersize = nAttr.create("filtersize", "filtersize", MFnNumericData::kInt, 3);
+ CHECK_MSTATUS(addAttribute( filtersize ));
+
+ tilesize = nAttr.create("tilesize", "tilesize", MFnNumericData::kInt, 32);
+ CHECK_MSTATUS(addAttribute( tilesize ));
+
+ basePath = tAttr.create("basePath", "basePath", MFnNumericData::kString);
+ CHECK_MSTATUS(addAttribute( basePath ));
+
+ imagePath = tAttr.create("imagePath", "imagePath", MFnNumericData::kString);
+ CHECK_MSTATUS(addAttribute( imagePath ));
+
+ imageName = tAttr.create("imageName", "imageName", MFnNumericData::kString);
+ CHECK_MSTATUS(addAttribute( imageName ));
+
+ gamma = nAttr.create("gamma", "gamma", MFnNumericData::kFloat, 1.0f);
+ CHECK_MSTATUS(addAttribute( gamma ));
+
+ maxTraceDepth = nAttr.create("maxTraceDepth", "maxTraceDepth", MFnNumericData::kInt, 4);
+ CHECK_MSTATUS(addAttribute( maxTraceDepth ));
+
+ adaptiveSampling = nAttr.create("adaptiveSampling", "adaptiveSampling", MFnNumericData::kBoolean, false);
+ CHECK_MSTATUS(addAttribute( adaptiveSampling ));
+
+ return MStatus::kSuccess;
+}
+
+MStatus MayaRenderGlobalsNode::compute( const MPlug& plug, MDataBlock& datablock )
+{
+ MStatus stat = MStatus::kSuccess;
+ return stat;
+}
View
60 src/common/cpp/mayarendernodes/renderGlobalsNode.h
@@ -0,0 +1,60 @@
+#ifndef MT_GLOBALS_H
+#define MT_GLOBALS_H
+
+#include <maya/MTypeId.h>
+#include <maya/MString.h>
+#include <maya/MPxNode.h>
+
+
+class MayaRenderGlobalsNode : public MPxNode
+{
+public:
+ MayaRenderGlobalsNode();
+ virtual ~MayaRenderGlobalsNode();
+
+ virtual MStatus compute( const MPlug& plug, MDataBlock& data );
+ static void* creator();
+ static MStatus initialize();
+
+ static MTypeId id;
+
+private:
+
+ static MObject adaptiveSampling;
+ // sampling adaptive
+ static MObject minSamples;
+ static MObject maxSamples;
+
+ // sampling raster based
+ static MObject samplesX;
+ static MObject samplesY;
+
+ static MObject doMotionBlur;
+ static MObject doDof;
+
+ //
+ static MObject threads;
+ static MObject translatorVerbosity;
+ static MObject rendererVerbosity;
+
+ static MObject detectShapeDeform;
+
+ // pixel filtering
+ // filtertype is renderer specific. It will be defined in subclass
+ static MObject filtersize;
+ static MObject tilesize;
+
+ static MObject gamma;
+
+
+ static MObject basePath;
+ static MObject imagePath;
+ static MObject imageName;
+
+ // raytracing
+ static MObject maxTraceDepth;
+
+
+};
+
+#endif
View
27 src/common/cpp/mayarendernodes/rendercmd.cpp
@@ -0,0 +1,27 @@
+#include <maya/MGlobal.h>
+#include <maya/MArgDatabase.h>
+#include "utilities/logging.h"
+#include "rendercmd.h"
+
+static Logging logger;
+
+void* MayaToRendererCmd::creator()
+{
+ return new MayaToRendererCmd();
+}
+
+MayaToRendererCmd::~MayaToRendererCmd() {}
+
+MSyntax MayaToRendererCmd::newSyntax()
+{
+ MSyntax syntax;
+
+ return syntax;
+}
+
+MStatus MayaToRendererCmd::doIt( const MArgList& args)
+{
+ MStatus stat = MStatus::kSuccess;
+
+ return MStatus::kSuccess;
+}
View
26 src/common/cpp/mayarendernodes/rendercmd.h
@@ -0,0 +1,26 @@
+#ifndef MT_CMD_H
+#define MT_CMD_H
+
+#include <string.h>
+#include <maya/MPxCommand.h>
+#include <maya/MSyntax.h>
+#include <maya/MString.h>
+
+class MayaToRendererCmd : public MPxCommand
+{
+public:
+ MayaToRendererCmd(){};
+ virtual ~MayaToRendererCmd();
+ static MSyntax newSyntax();
+
+ MStatus doIt( const MArgList& args );
+ static void* creator();
+
+private:
+ MString basePath;
+ MString imagePath;
+ MString fileName;
+};
+
+#endif
+
View
17 src/common/cpp/memory/memoryInfo.cpp
@@ -0,0 +1,17 @@
+#include "memoryInfo.h"
+
+
+#include "windows.h"
+#include "psapi.h"
+
+size_t getCurrentUsage()
+{
+ PROCESS_MEMORY_COUNTERS pmc;
+ GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
+ SIZE_T usedMB = pmc.WorkingSetSize / (1024 * 1024);
+ if( startUsage == 0)
+ startUsage = usedMB;
+
+ return (usedMB);
+}
+
View
12 src/common/cpp/memory/memoryInfo.h
@@ -0,0 +1,12 @@
+//
+// memory info - for windows only at the momen
+//
+
+#ifndef MEMINFO_H
+#define MEMINFO_H
+
+static size_t startUsage = 0;
+
+size_t getCurrentUsage();
+
+#endif
View
230 src/common/cpp/renderGlobals.cpp
@@ -0,0 +1,230 @@
+#include <maya/MSelectionList.h>
+#include <maya/MCommonRenderSettingsData.h>
+#include <maya/MRenderUtil.h>
+#include <maya/MFnDependencyNode.h>
+#include <maya/MFnRenderLayer.h>
+#include <maya/MAnimControl.h>
+#include <maya/MGlobal.h>
+#include <maya/MFnCamera.h>
+#include <list>
+
+#include "renderGlobals.h"
+#include "utilities/logging.h"
+#include "utilities/attrTools.h"
+#include "utilities/pystring.h"
+
+static Logging logger;
+
+// during creation, the renderGlobals class initializes itself with the
+// necessaray information from the defaultRenderGlobals node
+// All additional information should be done in a derived class
+RenderGlobals::RenderGlobals()
+{
+ logger.info("RenderGlobals::RenderGlobals()");
+ this->good = false;
+ this->getDefaultGlobals();
+ this->useShortNames = true;
+ this->currentRenderPass = NULL;
+ this->currentRenderPassElementId = 0;
+ this->isMbStartStep = false;
+ this->maxTraceDepth = 4;
+ this->isMbStartStep = true;
+ this->doMb = false;
+ this->doDof = false;
+ this->mbStartTime = 0.0f;
+ this->mbEndTime = 0.0f;
+ this->currentFrame = 0.0f;
+ this->currentFrameNumber = 0.0f;
+ this->mbtype = 1;
+ this->xftimesamples = 2;
+ this->geotimesamples = 2;
+ this->createDefaultLight = false;
+}
+
+RenderGlobals::~RenderGlobals()
+{}
+
+void RenderGlobals::getImageName()
+{
+ double fn = this->currentFrame;
+ MCommonRenderSettingsData data;
+ MRenderUtil::getCommonRenderSettings(data);
+ MObject renderLayer = MFnRenderLayer::currentLayer();
+ MString ext = this->getImageExt();
+ ext = pystring::lower(ext.asChar()).c_str();
+ this->imageOutputFile = data.getImageName(data.kFullPathImage, fn, this->imageName, MString(""), ext, renderLayer);
+}
+
+bool RenderGlobals::isDeformStep()
+{
+ return ((this->currentMbElement.elementType == MbElement::Geo) || (this->currentMbElement.elementType == MbElement::Both));
+}
+
+bool RenderGlobals::isTransformStep()
+{
+ return ((this->currentMbElement.elementType == MbElement::XForm) || (this->currentMbElement.elementType == MbElement::Both));
+}
+
+// If motionblur is turned on, I need to evaluate the instances/geometry serveral times.
+// To know at which point what type of export deform/transform is needed, I create a list of
+// times that will be added to the current render frame e.g. frame 101 + mbStep1 (.20) = 101.20
+bool RenderGlobals::getMbSteps( MObject& camera)
+{
+ this->mbElementList.clear();
+
+ // if shadowmap then ignore motionblur steps
+ if(this->currentRenderPass->passType == RenderPass::ShadowMap)
+ {
+ MbElement mbel;
+ mbel.elementType = MbElement::Both;
+ mbel.time = 0.0;
+ this->mbElementList.push_back(mbel);
+ return true;
+ }
+
+
+ // if no motionblur, I add 0.0 to the list as dummy
+ if( !this->doMb )
+ {
+ MbElement mbel;
+ mbel.elementType = MbElement::Both;
+ mbel.time = 0.0;
+ this->mbElementList.push_back(mbel);
+ return true;
+ }
+
+ // For the calculation of motionblur steps, I need the camera shutter angle and the number of mb steps
+ MFnCamera fnCam(camera);
+ double shutterAngle;
+ if( !getDouble(MString("shutterAngle"), fnCam, shutterAngle) )
+ {
+ logger.error("RenderGlobals::getMbSteps Unable to read shutter angle from cam " + fnCam.name());
+ return false;
+ }
+
+ //degrees * ( M_PI/ 180.0 );
+ //radians * (180.0/M_PI);
+
+ double shutterDist = shutterAngle / (2.0 * M_PI);
+ MString info;
+
+ double startStep = 0.0;
+
+ // get mb type
+ // 0 = leading blur --> blur ends at frame
+ if( this->mbtype == 0)
+ {
+ startStep = -shutterDist;
+ }
+ // 1 = centered blur --> blur starts at frame - (shutterDist/2.0)
+ if( this->mbtype == 1)
+ {
+ startStep = -shutterDist/2.0;
+ }
+ // 2 = trailing blur --> blur centered at frame
+ if( this->mbtype == 2)
+ {
+ startStep = 0.0;
+ }
+ double endStep = shutterDist - fabs(startStep);
+
+ this->mbStartTime = startStep;
+ this->mbEndTime = endStep;
+
+ // to get a correct listing of all xform and deform steps I put all into a list
+ // and sort this list later.
+ std::list<MbElement> sortList;
+ std::list<MbElement >::iterator sortListIt;
+
+ if( this->xftimesamples > 1)
+ {
+ float xfStepSize = (float)(shutterDist/(float)(this->xftimesamples - 1));
+ double mbStepValue = startStep;
+ for( int step = 0; step < this->xftimesamples; step++)
+ {
+ MbElement mbel;
+ mbel.elementType = MbElement::XForm;
+ mbel.time = mbStepValue;
+ mbStepValue += xfStepSize;
+ sortList.push_back(mbel);
+ }
+ }
+
+ if(this->geotimesamples > 1)
+ {
+ float geoStepSize = (float)(shutterDist/(float)(this->geotimesamples - 1));
+ double mbStepValue = startStep;
+ for( int step = 0; step < this->geotimesamples; step++)
+ {
+ MbElement mbel;
+ mbel.elementType = MbElement::Geo;
+ mbel.time = mbStepValue;
+ mbStepValue += geoStepSize;
+ sortList.push_back(mbel);
+ }
+ }
+ sortList.sort();
+ for( sortListIt = sortList.begin(); sortListIt != sortList.end(); sortListIt++)
+ {
+ this->mbElementList.push_back(*sortListIt);
+ }
+ return true;
+}
+
+bool RenderGlobals::getDefaultGlobals()
+{
+ MSelectionList defaultGlobals;
+ defaultGlobals.add("defaultRenderGlobals");
+
+ if( defaultGlobals.length() == 0 )
+ {
+ logger.debug("defaultRenderGlobals not found. Stopping.");
+ return false;
+ }
+ MCommonRenderSettingsData data;
+ MRenderUtil::getCommonRenderSettings(data);
+
+ MObject node;
+ defaultGlobals.getDependNode(0, node);
+ MFnDependencyNode fnRenderGlobals(node);
+
+ MTime tv = MAnimControl::currentTime();
+ this->currentFrameNumber = (float)(tv.value());
+ tv = data.frameStart;
+ this->startFrame = (float)(tv.value());
+ tv = data.frameEnd;
+ this->endFrame = (float)(tv.value());
+ tv = data.frameBy;
+ this->byFrame = (float)(tv.value());
+
+ // check if we are in a batch render mode or if we are rendering from UI
+ if( MGlobal::mayaState() == MGlobal::kBatch )
+ {
+ this->inBatch = true;
+ if( data.isAnimated() )
+ {
+ logger.debug(MString("animation on, rendering frame sequence from ") + this->startFrame + " to " + this->endFrame);
+ // these are the frames that are supposed to be rendered in batch mode
+ this->doAnimation = true;
+ for( double frame = this->startFrame; frame <= this->endFrame; frame += this->byFrame)
+ this->frameList.push_back((float)frame);
+ }else{
+ logger.debug(MString("animation off, rendering current frame"));
+ this->frameList.push_back(this->currentFrameNumber );
+ this->doAnimation = false;
+ }
+ }else{
+ // we are rendering from the UI so only render the current frame
+ this->inBatch = false;
+ this->frameList.push_back(this->currentFrameNumber );
+ this->doAnimation = false; // at the moment, if rendering comes from UI dont do animation
+ }
+ this->imgHeight = data.height;
+ this->imgWidth = data.width;
+ this->pixelAspect = data.pixelAspectRatio;
+
+ getBool(MString("enableDefaultLight"), fnRenderGlobals, this->createDefaultLight);
+
+ this->good = true;
+ return true;
+}
View
158 src/common/cpp/renderGlobals.h
@@ -0,0 +1,158 @@
+#ifndef MAYA_RENDERGLOBALS_H
+#define MAYA_RENDERGLOBALS_H
+
+#include <maya/MObject.h>
+#include <maya/MString.h>
+#include <vector>
+
+// Render pass definition goes into the global framework because most of the known passses are
+// the same in all renderers, like shadowmap, photonmap, caustics, bake...
+
+// A render pass contains a complete render procedure.
+// e.g. a ShadowMap Render pass will start a new rendering. Here all shadow casting lights will produce
+// shadow maps. They can be seen as a pendant to frames in a sequence.
+
+// During the render procedure the passes are collected in the render globals.
+// There are preSequence passes. e.g. for shadow maps that are created only once before the final rendering.
+// Then for every frame we have perFrame passes e.g. moving shadow maps or photon maps.
+
+class RenderPass
+{
+public:
+ enum RenderPassType{
+ PassNone,
+ PhotonGI,
+ PhotonCaustic,
+ ShadowMap,
+ Bake,
+ Beauty
+ };
+
+ enum EvalFrequency{
+ FrequencyNone,
+ OncePerFrame,
+ OncePerJob
+ };
+
+ RenderPassType passType;
+ EvalFrequency evalFrequency;
+
+ std::vector<void *> objectList; // void element pointer to camera, light or other things
+
+ RenderPass()
+ {
+ passType = PassNone;
+ evalFrequency = FrequencyNone;
+ };
+};
+
+// Some renderers offer different transform mb steps and geometry deformation steps (mantra)
+// So I create this as as global framework option
+class MbElement
+{
+public:
+
+ enum Type{
+ XForm,
+ Geo,
+ Both
+ };
+
+ MbElement::Type elementType;
+ double time;
+
+ // these are for sorting the mb steps
+ bool operator>(const MbElement& other) const
+ {
+ return ( time > other.time );
+ };
+ bool operator<(const MbElement& other) const
+ {
+ return( time < other.time );
+ };
+ MbElement(void){};
+};
+
+
+class RenderGlobals
+{
+public:
+
+ bool good;
+
+ bool doAnimation;
+ float currentFrameNumber; // current real frame (with mb steps)
+ float currentFrame; // current frame
+ float startFrame;
+ float endFrame;
+ float byFrame;
+ std::vector<float> frameList;
+
+ bool inBatch;
+ bool useShortNames;
+
+ int imgWidth;
+ int imgHeight;
+ float pixelAspect;
+
+ // sampling
+ int minSamples;
+ int maxSamples;
+ // regular sampling
+ int samplesX;
+ int samplesY;
+
+ // filtering
+ int filterSize;
+ int filterType;
+ MString filterTypeString;
+
+ float gamma;
+
+ bool doMb;
+ int mbtype; // leading = 0, centered = 1, trailing = 2
+ float mbStartTime; // frame relative start time e.g. -0.2
+ float mbEndTime; // frame relative end time e.g. 0.2
+ bool doDof;
+ int bitdepth; // 8, 16, 16halfFloat, 32float
+
+ int threads;
+ int tilesize;
+ int translatorVerbosity;
+ int rendererVerbosity;
+
+ // raytracing
+ int maxTraceDepth;
+ //static MObject detectShapeDeform;
+
+ int xftimesamples;
+ int geotimesamples;
+ std::vector<MbElement> mbElementList;
+ MbElement currentMbElement; // contains type and relative time
+ int currentMbStep; // currend mb step id 0 - x
+ bool isMbStartStep;
+
+ bool createDefaultLight;
+
+ MString basePath;
+ MString imagePath;
+ MString imageName;
+ MString imageOutputFile; // complete path to current image file
+
+ bool detectShapeDeform;
+
+ std::vector<RenderPass *> renderPasses;
+ RenderPass *currentRenderPass;
+ int currentRenderPassElementId;
+
+ RenderGlobals();
+ ~RenderGlobals();
+ bool getDefaultGlobals();
+ bool getMbSteps( MObject& camera);
+ bool isTransformStep();
+ bool isDeformStep();
+ void getImageName();
+ virtual MString getImageExt() = 0;
+};
+
+#endif
View
339 src/common/cpp/shadingtools/material.cpp
@@ -0,0 +1,339 @@
+#include <maya/MFnDependencyNode.h>
+#include <maya/MPlugArray.h>
+#include <maya/MFnParticleSystem.h>
+#include <maya/MFnNurbsSurface.h>
+#include <maya/MFnMesh.h>
+
+
+#include "material.h"
+#include "utilities/attrTools.h"
+#include "utilities/tools.h"
+#include "utilities/logging.h"
+#include "readShaderDefs.h"
+
+static Logging logger;
+
+// This procedure checks if a node from the parsed maya hypeshade is available in the shader
+// definitions list and sets all necessary data.
+void Material::checkNode(ShadingNode *sn)
+{
+ ShadingNode *sNode = findShaderNodeByTypeName(sn->typeName);
+ if( sNode != NULL)
+ {
+ //logger.debug(MString("Found node ") + sn->typeName + " in shader definitions");
+ ShadingNode sTmp = *sNode;
+ sTmp.mobject = sn->mobject;
+ sTmp.internalName = sn->internalName;
+ sTmp.typeName = sn->typeName;
+ sTmp.mayaName = sn->mayaName;
+ sTmp.outShadingNodes = sn->outShadingNodes;
+ *sn = sTmp;
+ sn->updateData();
+ }else{
+ sn->supported = false;
+ }
+}
+
+// here the nodes are checked if they are defined in the shaderDefinions file
+// They will receive their correct plugs and duble nodes will be removed
+void Material::checkNodeList(ShadingNetwork& network)
+{
+ for( int i = 0; i < (int)network.shaderList.size(); i++)
+ {
+ checkNode(network.shaderList[i]);
+
+ for( uint k = 0; k < network.shaderList[i]->geoPlugs.size(); k++)
+ {
+ ShadingPlug plug = network.shaderList[i]->geoPlugs[k];
+ bool found = false;
+ for( uint l = 0; l < network.geometryParamsList.size(); l++)
+ {
+ if( network.geometryParamsList[l].name == plug.name)
+ {
+ found = true;
+ }
+ }
+ if(!found)
+ network.geometryParamsList.push_back(plug);
+ }
+ }
+ // remove double nodes, serach from back
+ std::vector<ShadingNode *> cleanList;
+ int numShaders = (int)network.shaderList.size();
+ for( int i = (numShaders-1); i >= 0; i--)
+ {
+ ShadingNode *sn = network.shaderList[i];
+ bool found = false;
+ for( int k = 0; k < (int)cleanList.size(); k++)
+ {
+ if( sn->mayaName == cleanList[k]->mayaName)
+ {
+ found = true;
+ for( int osn = 0; osn < sn->outShadingNodes.size(); osn++)
+ {
+ cleanList[k]->outShadingNodes.push_back(sn->outShadingNodes[osn]);
+ }
+ break;
+ }
+ }
+ if(!found)
+ {
+ cleanList.push_back(sn);
+ }
+ }
+ numShaders = (int)cleanList.size();
+ network.shaderList.clear();
+ for( int i = (numShaders-1); i >= 0; i--)
+ {
+ network.shaderList.push_back(cleanList[i]);
+ }
+
+ numShaders = (int)network.shaderList.size();
+ for( uint i = 0; i < numShaders; i++)
+ {
+ std::vector<ShadingNode *> tmpOutList;
+ ShadingNode *sn = network.shaderList[i];
+ int outLen = (int)sn->outShadingNodes.size();
+ for( int k = 0; k < outLen; k++)
+ {
+ ShadingNode *outsn = sn->outShadingNodes[k];
+ bool found = false;
+ for( int l = 0; l < tmpOutList.size(); l++)
+ {
+ if( outsn->mayaName == tmpOutList[l]->mayaName)
+ {
+ found = true;
+ break;
+ }
+ }
+ if( !found)
+ tmpOutList.push_back(outsn);
+ }
+ sn->outShadingNodes = tmpOutList;
+ tmpOutList.clear();
+ }
+}
+
+bool Material::alreadyDefined(ShadingNode *sn, ShadingNetwork& network)
+{
+ for( int i = 0; i < (int)network.shaderList.size(); i++)
+ {
+ if( network.shaderList[i]->mobject == sn->mobject)
+ {
+ //logger.debug("shading node already defined");
+ return true;
+ }
+ }
+ return false;
+}
+
+// beginning with the start shaderNode the whole network is parsed and the nodes
+// are placed in the shadingNodeList. Sometimes it can be necessary to know how the nodes
+// are connected, e.g. in a rman/mantra environment with a projection node. For this reason
+// the network puts the new shading node in all conncted nodes outputs.
+// The ** pointer to a pointer is needed because I want to assign the pointer a pointer
+void Material::parseNetwork(MObject& shaderNode, ShadingNetwork& network, ShadingNode **sNode)
+{
+ (*sNode) = NULL;
+ ShadingNode *sn = new ShadingNode(shaderNode);
+
+ // modify this to detect cycles
+ //if( alreadyDefined(sn, network))
+ //{
+ // logger.debug("Node is already defined, stopping recoursion here...");
+ // delete sn;
+ // return;
+ //}
+
+ network.shaderList.push_back(sn);
+
+ // read incoming connections
+ MObjectArray connectedNodeList;
+ getConnectedNodes(shaderNode, connectedNodeList);
+
+ for(uint i = 0; i < connectedNodeList.length(); i++)
+ {
+ ShadingNode *upNode = NULL;
+ this->parseNetwork(connectedNodeList[i], network, &upNode);
+ //logger.info(MString("---->> parsed node ") + sn->mayaName);
+ if( upNode != NULL)
+ {
+ //logger.info(MString("---->> found up node ") + upNode->mayaName + " addr " + (int)upNode);
+ upNode->outShadingNodes.push_back(sn);
+ //logger.info(MString("Node: ") + upNode->mayaName + " has now " + upNode->outShadingNodes.size() + " outputs");
+ }
+ }
+ (*sNode) = sn;
+}
+
+void Material::printNodes(ShadingNetwork& network)
+{
+ int numNodes = (int)network.shaderList.size();
+ for(int i = numNodes - 1; i >= 0 ; i--)
+ {
+ ShadingNode *sn = network.shaderList[i];
+ logger.info(MString("Material::Node id ") + (double)i + " typename " + sn->typeName);
+ logger.info(MString("Material::Node id ") + (double)i + " mayaname " + sn->mayaName);
+ }
+}
+
+// Modify to use light materials as well
+Material::Material(MObject &shadingEngine)
+{
+ this->shadingEngineNode = shadingEngine;
+ this->materialName = getObjectName(this->shadingEngineNode);
+
+ MObject lightShaderNode = shadingEngine;
+
+ MObject surfaceShaderNode = getOtherSideNode(MString("surfaceShader"), this->shadingEngineNode);
+ MObject volumeShaderNode = getOtherSideNode(MString("volumeShader"), this->shadingEngineNode);
+ MObject displacementShaderNode = getOtherSideNode(MString("displacementShader"), this->shadingEngineNode);
+ MObject imageShaderNode = getOtherSideNode(MString("imageShader"), this->shadingEngineNode);
+
+ // if a mr material is connected, check it and use it instead of the normal shader connection
+ MObject miMaterialShaderNode = getOtherSideNode(MString("miMaterialShader"), this->shadingEngineNode);
+ MObject miShadowShaderNode = getOtherSideNode(MString("miShadowShader"), this->shadingEngineNode);
+ MObject miVolumeShaderNode = getOtherSideNode(MString("miVolumeShader"), this->shadingEngineNode);
+ MObject miDisplacementShaderNode = getOtherSideNode(MString("miDisplacementShader"), this->shadingEngineNode);
+
+ // read surface shader hierarchy
+ // if mr node is defined, use it, if not use the normal one
+ if( (miMaterialShaderNode != MObject::kNullObj) || (surfaceShaderNode != MObject::kNullObj) )
+ {
+ if(miMaterialShaderNode != MObject::kNullObj)
+ surfaceShaderNode = miMaterialShaderNode;
+
+ ShadingNode *sn = NULL;
+ this->parseNetwork(surfaceShaderNode, this->surfaceShaderNet, &sn);
+ this->checkNodeList(this->surfaceShaderNet);
+ }
+ // read volume shader hierarchy
+ // if mr node is defined, use it, if not use the normal one
+ if( (miVolumeShaderNode != MObject::kNullObj) || (volumeShaderNode != MObject::kNullObj) )
+ {
+ if(miVolumeShaderNode != MObject::kNullObj)
+ volumeShaderNode = miVolumeShaderNode;
+ ShadingNode *sn = NULL;
+ this->parseNetwork(miVolumeShaderNode, this->volumeShaderNet, &sn);
+ this->checkNodeList(this->volumeShaderNet);
+ }
+
+ // read displacement shader hierarchy
+ // if mr node is defined, use it, if not use the normal one
+ if( (miDisplacementShaderNode != MObject::kNullObj) || (displacementShaderNode != MObject::kNullObj) )
+ {
+ if(miDisplacementShaderNode != MObject::kNullObj)
+ displacementShaderNode = miDisplacementShaderNode;
+
+ ShadingNode *sn = NULL;
+ this->parseNetwork(displacementShaderNode, this->displacementShaderNet, &sn);
+ this->checkNodeList(this->displacementShaderNet);
+ }
+
+ // read light shader hierarchy, only for maya lights, not for mtm_envlight yet
+ if( (lightShaderNode != MObject::kNullObj) && (lightShaderNode.hasFn(MFn::kLight)) )
+ {
+ ShadingNode *sn = NULL;
+ this->parseNetwork(lightShaderNode, this->lightShaderNet, &sn);
+ this->checkNodeList(this->lightShaderNet);
+ }
+
+}
+
+Material::Material()
+{}
+
+Material::~Material()
+{}
+
+//// GLOBAL PROCS //////
+
+bool getObjectShadingGroups(MObject& geoObject, MObject& sGroup, int instId)
+{
+
+ MPlugArray connections;
+ MFnDependencyNode dependNode(geoObject);
+ //logger.debug(MString(" shading object ") + dependNode.name());
+ MPlug plug(geoObject, dependNode.attribute("instObjGroups"));
+ int numConnections = plug.numConnectedElements();
+
+ plug.elementByLogicalIndex(instId).connectedTo(connections, false, true);
+
+ if( connections.length() > 0)
+ {
+ MObject shadingGroup(connections[0].node());
+ if (shadingGroup.apiType() == MFn::kShadingEngine )
+ {
+ //logger.debug(MString("Found shading group for object ") + dependNode.name() + " == " + getObjectName(shadingGroup));
+ sGroup = shadingGroup;
+ return true;
+ }
+ }else{
+ logger.debug(MString("Object-instObjGroups has no connection to shading group."));
+ }
+ return false;
+}
+
+bool getObjectShadingGroups(MDagPath& shapeObjectDP, MObject& shadingGroup)
+{
+ // if obj is a light, simply return the mobject
+ if(shapeObjectDP.hasFn(MFn::kLight))
+ shadingGroup = shapeObjectDP.node();
+
+ if(shapeObjectDP.hasFn(MFn::kMesh))
+ {
+ // Find the Shading Engines Connected to the SourceNode
+ MFnMesh fnMesh(shapeObjectDP.node());
+
+ // A ShadingGroup will have a MFnSet
+ MObjectArray sets, comps;
+ fnMesh.getConnectedSetsAndMembers(shapeObjectDP.instanceNumber(), sets, comps, true);
+
+ // Each set is a Shading Group. Loop through them
+ //logger.debug(MString("Found ") + sets.length() + " shading groups for mesh object " + fnMesh.name());
+ for(unsigned int i = 0; i < sets.length(); ++i)
+ {
+ MFnDependencyNode fnDepSGNode(sets[i]);
+ //logger.debug(MString("SG: ") + fnDepSGNode.name());
+ shadingGroup = sets[i];
+ return true;
+ //cout << fnDepSGNode.name() << endl;
+ }
+ }
+
+ if(shapeObjectDP.hasFn(MFn::kNurbsSurface)||shapeObjectDP.hasFn(MFn::kParticle)||shapeObjectDP.hasFn(MFn::kNParticle))
+ {
+
+ MObject instObjGroupsAttr;
+ if( shapeObjectDP.hasFn(MFn::kNurbsSurface))
+ {
+ MFnNurbsSurface fnNurbs(shapeObjectDP.node());
+ instObjGroupsAttr = fnNurbs.attribute("instObjGroups");
+ }
+ if( shapeObjectDP.hasFn(MFn::kParticle)||shapeObjectDP.hasFn(MFn::kNParticle))
+ {
+ MFnParticleSystem fnPart(shapeObjectDP.node());
+ instObjGroupsAttr = fnPart.attribute("instObjGroups");
+ }
+ MPlug instPlug(shapeObjectDP.node(), instObjGroupsAttr);
+
+ // Get the instance that our node is referring to;
+ // In other words get the Plug for instObjGroups[intanceNumber];
+ MPlug instPlugElem = instPlug.elementByLogicalIndex(shapeObjectDP.instanceNumber());
+
+ // Find the ShadingGroup plugs that we are connected to as Source
+ MPlugArray SGPlugArray;
+ instPlugElem.connectedTo(SGPlugArray, false, true);
+
+ // Loop through each ShadingGroup Plug
+ for(unsigned int i=0; i < SGPlugArray.length(); ++i)
+ {
+ MFnDependencyNode fnDepSGNode(SGPlugArray[i].node());
+ //cout << fnDepSGNode.name() << endl;
+ shadingGroup = SGPlugArray[i].node();
+ return true;
+ }
+ }
+ return false;
+}
+
View
80 src/common/cpp/shadingtools/material.h
@@ -0,0 +1,80 @@
+#ifndef MT_SHADING_TOOLS_MATERIAL_H
+#define MT_SHADING_TOOLS_MATERIAL_H
+
+/*
+ A material collects all necessary object attributes for rendering a surface or volume.
+ The material node in maya is called shadingGroup (shadingEngine).
+ Here all shader types are connected. At the moment there are:
+ - surface shader
+ - displacement shader
+ - volume shader
+ - shadow shader
+ - ...
+ The main purpose of a material is the organisation and collection of shader nodes and
+ the possiblity to translate them in another form, may it be an text shader source file for
+ Renderman or for mantra or into a shading node network for an node based renderer.
+
+ In maya behind every shader type stands a whole shading network. There can be a lot of nodes
+ or simply none or e.g. only one node like a lambert shader. These nodes are collected in a list
+ of shadings nodes.
+
+ As soon as a Material node is defined, it parses the connected shaders based on the maya shading group connections.
+
+ Every Shader could need some external attributes. An external attribute comes from an connection to a non supported
+ node type. e.g. if the color is connected to a non supported animcurve, this attribute is placed in the shader parameter list
+ and can be updated every time the shader is exported. The rest does not need to be exported for every frame.
+
+ Every shader can use some geometric attributes. e.g. the "uv" coordinates. If a shading node has an geoinput attribute, this will
+ be placed in the geometryParamsList so it can be exposed in the shader definition. Same with perParticle attributes like rgbPP or
+ opacityPP. These are defined in the particle geometry. If the parameter is connected in the particleSampler, the attribute will be exposed.
+*/
+
+#include <maya/MDagPath.h>
+#include <maya/MObject.h>
+
+#include <vector>
+#include "shadingNode.h"
+
+#define SNODE_LIST std::vector<ShadingNode *>
+
+class Material;
+static std::vector<Material *> ShadingGroups;
+
+
+class ShadingNetwork
+{
+public:
+ SNODE_LIST shaderList;
+ SPLUG_LIST externalPlugList;
+ SPLUG_LIST geometryParamsList;
+};
+
+class Material
+{
+public:
+ // here we save all nodes for a certain shader type connection
+ ShadingNetwork surfaceShaderNet;
+ ShadingNetwork volumeShaderNet;
+ ShadingNetwork displacementShaderNet;
+ ShadingNetwork shadowShaderNet;
+ ShadingNetwork lightShaderNet;
+ MObject shadingEngineNode;
+
+ MString materialName;
+ void printNodes(ShadingNetwork& network);
+ bool isLight(MObject& obj);
+ Material();
+ Material(MObject& shadingEngine);
+ ~Material();
+
+private:
+
+ void parseNetwork(MObject& shaderNode, ShadingNetwork& network, ShadingNode **sn);
+ bool alreadyDefined(ShadingNode *sn, ShadingNetwork& network);
+ void checkNode(ShadingNode *sn);
+ void checkNodeList(ShadingNetwork& network);
+};
+
+bool getObjectShadingGroups(MObject& geoObject, MObject& sGroup, int instId);
+bool getObjectShadingGroups(MDagPath& shapeObjectDP, MObject& sGroup);
+#endif
View
308 src/common/cpp/shadingtools/readShaderDefs.cpp
@@ -0,0 +1,308 @@
+
+/*
+Here all supported shaders are read from a text file called shaderDefinitions.txt
+
+The shaderDefinition file has a simple structure:
+
+Comments start with a '#'.
+Spaces and empty lines are ignored, spaces in names are not allowed.
+
+A new shader starts with the symbol "shader_start" followed by the name of the shader in one line,
+all seperated by a ":". The name is the original maya internal shader name.
+
+shader_start:kBlendColors
+
+Then most shaders have input and output attributes that are defined this way:
+
+attype:datatype
+e.g.
+inatt:colorGain:color
+
+A shader is finished with the "shader_end" symbol.
+If geometry defined attributes are needed like uv coordinates they are defined like this:
+
+inattgeo:uv:float2
+
+It it possible to define often used attributes in a seperate node and inherit these attributes.
+To do so you only need to add the parent node behind the node name
+
+shader_start:common
+ inatt:abc:float
+shader_end
+
+shader_start:kBlendColors:common
+...
+shader_end
+
+Here a complete example.
+
+# this is a comment
+shader_start:kBlendColors
+ inatt:color1:color
+ inatt:color2:color
+ inatt:blender:float
+ outatt:output:color
+shader_end
+
+Allowed dataTypes are:
+float
+int
+string
+color
+vector
+float2
+int2
+floatArray
+intArray
+colorArray
+vectorArray
+floatRamp
+colorRamp
+
+*/
+#include <fstream>
+#include "readShaderDefs.h"
+#include "shadingNode.h"
+#include "utilities/pystring.h"
+#include "utilities/logging.h"
+#include "maya/MGlobal.h"
+static Logging logger;
+
+#define String std::string
+#define StringArray std::vector<std::string>
+
+bool readShaderDefs()
+{
+ std::string homeDir = getenv("MTM_HOME");
+ homeDir += std::string("/ressources/shaderDefinitions.txt");
+ String shaderDefFile = homeDir;
+ //TODO: shader definition relativ
+ //String shaderDefFile = "C:/Users/haggi/coding/Renderer/mayaTo/mayaToMantra/mtm_devmodule/ressources/shaderDefinitions.txt";
+
+ logger.debug(MString("ReadShaderDefs from ") + MString(shaderDefFile.c_str()));
+ std::ifstream shaderFile(shaderDefFile.c_str());
+ if( !shaderFile.good())
+ {
+ logger.error(MString("Unable to open shaderInfoFile ") + MString(shaderDefFile.c_str()));
+ shaderFile.close();
+ return false;
+ }
+
+ String line;
+ StringArray stringArray;
+ ShadingNode currentNode;
+ int lineNumber = -1;
+
+ logger.debug("START read of shader def file:");
+ do{
+ std::getline(shaderFile, line);
+ lineNumber++;
+ logger.debug(line.c_str());
+ if( line.length() > 0 )
+ {
+ // get rid of any spaces and newlines
+ line = pystring::strip(line);
+
+ if( line.length() == 0)
+ continue;
+ line = pystring::replace(line, " ", "");
+
+ // filtering comments
+ if(pystring::startswith(line, "#"))
+ continue;
+
+ if( pystring::count(line, ":") > 0)
+ {
+ pystring::split(line, stringArray, ":");
+ }
+ int numElements = (int)stringArray.size();
+
+
+ // shader_start:name:kBlendColors:common
+ if(pystring::startswith(line, "shader_start"))
+ {
+ if( numElements < 2 )
+ {
+ logger.debug(MString("Malformed shader definition line: ") + line.c_str());
+ continue;
+ }
+ ShadingNode sNode;
+ if( numElements > 2)
+ {
+ String parentName = stringArray[2];
+ logger.debug(MString("Searching for parent node ") + parentName.c_str());