#include "gpuCacheMaterialBakers.h"
#include "gpuCacheMaterialNodes.h"
#include "gpuCacheShapeNode.h"
#include "gpuCacheUtil.h"
#include <set>
#include <functional>
#include <maya/MFnDagNode.h>
#include <maya/MFnNumericData.h>
#include <maya/MPlugArray.h>
namespace GPUCache {
namespace MaterialBakers {
class BaseMaterialNodeBaker
{
public:
typedef std::shared_ptr<BaseMaterialNodeBaker> Ptr;
static BaseMaterialNodeBaker::Ptr create(
std::set<std::string>* traversedNodes);
BaseMaterialNodeBaker(
const MObject& node)
: fNode(node), fTraversedNodes(NULL)
{}
virtual ~BaseMaterialNodeBaker()
{}
BaseMaterialNodeBaker(const BaseMaterialNodeBaker&) = delete;
BaseMaterialNodeBaker& operator=(const BaseMaterialNodeBaker&) = delete;
void setupNetwork()
{
fBakedNode = createNode(fNode.name());
assert(fBakedNode);
collectPlugsAndProperties();
}
void sample(
const MTime& time)
{
assert(fBakedNode);
for(Channel& channel : fChannels) {
switch (channel.prop()->type()) {
case MaterialProperty::kBool:
sampleBoolPlug(time, channel.plug(), channel.prop());
break;
case MaterialProperty::kInt32:
sampleInt32Plug(time, channel.plug(), channel.prop());
break;
case MaterialProperty::kFloat:
sampleFloatPlug(time, channel.plug(), channel.prop());
break;
case MaterialProperty::kFloat2:
sampleFloat2Plug(time, channel.plug(), channel.prop());
break;
case MaterialProperty::kFloat3:
sampleFloat3Plug(time, channel.plug(), channel.prop());
break;
case MaterialProperty::kRGB:
sampleFloat3PlugAsColor(time, channel.plug(), channel.prop());
break;
case MaterialProperty::kString:
sampleStringPlug(time, channel.plug(), channel.prop());
break;
default:
assert(0);
break;
}
BaseMaterialNodeBaker::Ptr& srcBaker = channel.srcBaker();
if (srcBaker) {
srcBaker->sample(time);
}
}
}
void addToGraph(MaterialGraph::MPtr& graph)
{
assert(fBakedNode);
if (fBakedNode) {
graph->addNode(fBakedNode);
}
for(Channel& channel : fChannels) {
BaseMaterialNodeBaker::Ptr& srcBaker = channel.srcBaker();
if (srcBaker) {
srcBaker->addToGraph(graph);
}
}
}
void connect()
{
for(Channel& channel : fChannels) {
MaterialProperty::MPtr dstProp = channel.prop();
BaseMaterialNodeBaker::Ptr srcBaker = channel.srcBaker();
MaterialProperty::MPtr srcProp = channel.srcProp();
if (dstProp && srcBaker && srcProp) {
MaterialNode::Ptr srcNode = srcBaker->bakedNode();
if (srcNode) {
dstProp->connect(srcNode, srcProp);
}
}
}
}
MaterialNode::MPtr bakedNode()
{ assert(fBakedNode); return fBakedNode; }
protected:
virtual MaterialNode::MPtr createNode(
const MString& name) = 0;
virtual void collectPlugsAndProperties() = 0;
void sampleBoolPlug(
const MTime& time,
const MPlug& plug, MaterialProperty::MPtr& prop)
{
if (prop->isDefault() || prop->asBool(timeInSeconds) != value) {
prop->setBool(timeInSeconds, value);
}
}
void sampleInt32Plug(
const MTime& time,
const MPlug& plug, MaterialProperty::MPtr& prop)
{
int value = plug.
asInt();
if (prop->isDefault() || prop->asInt32(timeInSeconds) != value) {
prop->setInt32(timeInSeconds, value);
}
}
void sampleFloatPlug(
const MTime& time,
const MPlug& plug, MaterialProperty::MPtr& prop)
{
if (prop->isDefault() || prop->asFloat(timeInSeconds) != value) {
prop->setFloat(timeInSeconds, value);
}
}
void sampleFloat2Plug(
const MTime& time,
const MPlug& plug, MaterialProperty::MPtr& prop)
{
float value[2], prev[2];
prop->asFloat2(timeInSeconds, prev[0], prev[1]);
if (prop->isDefault() || value[0] != prev[0] || value[1] != prev[1]) {
prop->setFloat2(timeInSeconds, value[0], value[1]);
}
}
void sampleFloat3Plug(
const MTime& time,
const MPlug& plug, MaterialProperty::MPtr& prop)
{
float value[3], prev[3];
prop->asFloat3(timeInSeconds, prev[0], prev[1], prev[2]);
if (prop->isDefault() || value[0] != prev[0] || value[1] != prev[1] || value[2] != prev[2]) {
prop->setFloat3(timeInSeconds, value[0], value[1], value[2]);
}
}
void sampleFloat3PlugAsColor(
const MTime& time,
const MPlug& plug, MaterialProperty::MPtr prop)
{
if (prop->isDefault() || value != prop->asColor(timeInSeconds)) {
prop->setColor(timeInSeconds, value);
}
}
void sampleStringPlug(
const MTime& time,
const MPlug& plug, MaterialProperty::MPtr& prop)
{
if (prop->isDefault() || value != prop->asString(timeInSeconds)) {
prop->setString(timeInSeconds, value);
}
}
void sampleChannel(
const MString& name, MaterialProperty::MPtr& prop)
{
MPlug plug = fNode.findPlug(name,
false);
assert(prop);
BaseMaterialNodeBaker::Ptr srcBaker;
MaterialProperty::MPtr srcProp;
assert(plugArray.
length() == 1);
MPlug srcPlug = plugArray[0];
assert(!srcNode.isNull());
if (!isTraversed(srcNode)) {
srcBaker = BaseMaterialNodeBaker::create(srcNode, fTraversedNodes);
if (srcBaker) {
for(Channel& channel : srcBaker->fChannels) {
if (channel.plug() == srcPlug) {
srcProp = channel.prop();
break;
}
}
if (!srcProp) {
srcBaker.reset();
}
}
}
}
}
fChannels.push_back(Channel(plug, prop, srcBaker, srcProp));
}
}
void setTraversedNodes(std::set<std::string>* traversedNodes)
{
fTraversedNodes = traversedNodes;
}
bool isTraversed(
const MObject& node)
{
assert(!name.empty());
if (fTraversedNodes && (*fTraversedNodes).find(name) != (*fTraversedNodes).end()) {
return true;
}
return false;
}
void setTraversed(
const MObject& node)
{
assert(!name.empty());
if (fTraversedNodes) {
(*fTraversedNodes).insert(name);
}
}
private:
class Channel
{
public:
Channel(
const MPlug& plug,
MaterialProperty::MPtr& prop,
BaseMaterialNodeBaker::Ptr& srcBaker,
MaterialProperty::MPtr& srcProp)
: fPlug(plug),
fProp(prop),
fSrcBaker(srcBaker),
fSrcProp(srcProp)
{}
~Channel() {}
const MPlug& plug() {
return fPlug; }
MaterialProperty::MPtr& prop() { return fProp; }
BaseMaterialNodeBaker::Ptr& srcBaker() { return fSrcBaker; }
MaterialProperty::MPtr& srcProp() { return fSrcProp; }
private:
MaterialProperty::MPtr fProp;
BaseMaterialNodeBaker::Ptr fSrcBaker;
MaterialProperty::MPtr fSrcProp;
};
std::vector<Channel> fChannels;
private:
MaterialNode::MPtr fBakedNode;
std::set<std::string>* fTraversedNodes;
};
class SurfaceMaterialBaker : public BaseMaterialNodeBaker
{
public:
SurfaceMaterialBaker(
const MObject& node)
: BaseMaterialNodeBaker(node) {}
MaterialNode::MPtr createNode(
const MString& name)
override
{
return std::make_shared<SurfaceMaterial>(name);
}
void collectPlugsAndProperties() override
{
std::shared_ptr<SurfaceMaterial> surfaceMaterial =
std::dynamic_pointer_cast<SurfaceMaterial>(bakedNode());
sampleChannel("outColor", surfaceMaterial->OutColor);
sampleChannel("outTransparency", surfaceMaterial->OutTransparency);
}
};
class LambertBaker : public SurfaceMaterialBaker
{
public:
: SurfaceMaterialBaker(node) {}
MaterialNode::MPtr createNode(
const MString& name)
override
{
return std::make_shared<LambertMaterial>(name);
}
void collectPlugsAndProperties() override
{
SurfaceMaterialBaker::collectPlugsAndProperties();
std::shared_ptr<LambertMaterial> lambert =
std::dynamic_pointer_cast<LambertMaterial>(bakedNode());
sampleChannel("color", lambert->Color);
sampleChannel("transparency", lambert->Transparency);
sampleChannel("ambientColor", lambert->AmbientColor);
sampleChannel("incandescence", lambert->Incandescence);
sampleChannel("diffuse", lambert->Diffuse);
sampleChannel("translucence", lambert->Translucence);
sampleChannel("translucenceDepth", lambert->TranslucenceDepth);
sampleChannel("translucenceFocus", lambert->TranslucenceFocus);
sampleChannel("hideSource", lambert->HideSource);
sampleChannel("glowIntensity", lambert->GlowIntensity);
}
};
class PhongBaker : public LambertBaker
{
public:
: LambertBaker(node) {}
MaterialNode::MPtr createNode(
const MString& name)
override
{
return std::make_shared<PhongMaterial>(name);
}
void collectPlugsAndProperties() override
{
LambertBaker::collectPlugsAndProperties();
std::shared_ptr<PhongMaterial> phong =
std::dynamic_pointer_cast<PhongMaterial>(bakedNode());
sampleChannel("cosinePower", phong->CosinePower);
sampleChannel("specularColor", phong->SpecularColor);
sampleChannel("reflectivity", phong->Reflectivity);
sampleChannel("reflectedColor", phong->ReflectedColor);
}
};
class BlinnBaker : public LambertBaker
{
public:
: LambertBaker(node) {}
MaterialNode::MPtr createNode(
const MString& name)
override
{
return std::make_shared<BlinnMaterial>(name);
}
void collectPlugsAndProperties() override
{
LambertBaker::collectPlugsAndProperties();
std::shared_ptr<BlinnMaterial> phong =
std::dynamic_pointer_cast<BlinnMaterial>(bakedNode());
sampleChannel("eccentricity", phong->Eccentricity);
sampleChannel("specularRollOff",phong->SpecularRollOff);
sampleChannel("specularColor", phong->SpecularColor);
sampleChannel("reflectivity", phong->Reflectivity);
sampleChannel("reflectedColor", phong->ReflectedColor);
}
};
class Texture2dBaker : public BaseMaterialNodeBaker
{
public:
Texture2dBaker(
const MObject& node)
: BaseMaterialNodeBaker(node) {}
MaterialNode::MPtr createNode(
const MString& name)
override = 0;
void collectPlugsAndProperties() override
{
std::shared_ptr<Texture2d> texture2d =
std::dynamic_pointer_cast<Texture2d>(bakedNode());
sampleChannel("defaultColor", texture2d->DefaultColor);
sampleChannel("outColor", texture2d->OutColor);
sampleChannel("outAlpha", texture2d->OutAlpha);
}
};
class FileTextureBaker : public Texture2dBaker
{
public:
FileTextureBaker(
const MObject& node)
: Texture2dBaker(node)
{
}
MaterialNode::MPtr createNode(
const MString& name)
override
{
return std::make_shared<FileTexture>(name);
}
void collectPlugsAndProperties() override
{
Texture2dBaker::collectPlugsAndProperties();
std::shared_ptr<FileTexture> file =
std::dynamic_pointer_cast<FileTexture>(bakedNode());
sampleChannel("outTransparency", file->OutTransparency);
sampleChannel("fileTextureName", file->FileTextureName);
}
};
class UnknownTexture2dBaker : public Texture2dBaker
{
public:
UnknownTexture2dBaker(
const MObject& node)
: Texture2dBaker(node) {}
MaterialNode::MPtr createNode(
const MString& name)
override
{
return std::make_shared<UnknownTexture2d>(name);
}
void collectPlugsAndProperties() override
{
Texture2dBaker::collectPlugsAndProperties();
}
};
BaseMaterialNodeBaker::Ptr BaseMaterialNodeBaker::create(
std::set<std::string>* traversedNodes)
{
BaseMaterialNodeBaker::Ptr baker;
baker = std::make_shared<PhongBaker>(std::ref(node));
}
baker = std::make_shared<BlinnBaker>(std::ref(node));
}
baker = std::make_shared<LambertBaker>(std::ref(node));
}
baker = std::make_shared<FileTextureBaker>(std::ref(node));
}
baker = std::make_shared<UnknownTexture2dBaker>(std::ref(node));
}
if (baker) {
baker->setTraversedNodes(traversedNodes);
baker->setTraversed(node);
baker->setupNetwork();
}
return baker;
}
}
using namespace MaterialBakers;
class MaterialBaker::MaterialGraphBaker
{
public:
MaterialGraphBaker(
const MObject& node)
{
fRootBaker = BaseMaterialNodeBaker::create(node, &fTraversedNodes);
}
~MaterialGraphBaker() {}
MaterialGraphBaker(const MaterialGraphBaker&) = delete;
MaterialGraphBaker& operator=(const MaterialGraphBaker&) = delete;
void sample(
const MTime& time)
{
if (fRootBaker) {
fRootBaker->sample(time);
}
}
void buildGraph()
{
if (fRootBaker) {
MaterialNode::Ptr rootNode = fRootBaker->bakedNode();
if (rootNode) {
MaterialGraph::MPtr graph = std::make_shared<MaterialGraph>(rootNode->name());
fRootBaker->addToGraph(graph);
fRootBaker->connect();
graph->setRootNode(rootNode);
fGraph = graph;
}
fRootBaker.reset();
}
}
MaterialGraph::Ptr get() const
{
return fGraph;
}
private:
BaseMaterialNodeBaker::Ptr fRootBaker;
MaterialGraph::MPtr fGraph;
std::set<std::string> fTraversedNodes;
};
MaterialBaker::MaterialBaker()
{}
MaterialBaker::~MaterialBaker()
{}
{
return MS::kFailure;
}
if (dagNode.
typeId() == ShapeNode::id) {
const ShapeNode* node = (
const ShapeNode*)dagNode.
userNode();
if (node) {
const MaterialGraphMap::Ptr materials = node->getCachedMaterial();
if (materials) {
const MaterialGraphMap::NamedMap& graphs = materials->getGraphs();
if (!graphs.empty()) {
fExistingGraphs.insert(graphs.cbegin(), graphs.cend());
}
}
}
return MS::kSuccess;
}
InstanceMaterialLookup lookup(dagPath);
if (lookup.hasWholeObjectMaterial()) {
MObject surfaceMaterial = lookup.findWholeObjectSurfaceMaterial();
if (surfaceMaterial.
isNull()) {
return MS::kSuccess;
}
MaterialGraphBakers::iterator iter = fMaterialGraphBakers.find(name);
if (iter == fMaterialGraphBakers.end()) {
MaterialGraphBakerPtr baker =
std::make_shared<MaterialGraphBaker>(surfaceMaterial);
fMaterialGraphBakers.insert(std::make_pair(name, baker));
}
}
else if (lookup.hasComponentMaterials()) {
std::vector<MObject> surfaceMaterials;
lookup.findSurfaceMaterials(surfaceMaterials);
for(
const MObject& surfaceMaterial : surfaceMaterials) {
if (surfaceMaterial.isNull()) continue;
MaterialGraphBakers::iterator iter = fMaterialGraphBakers.find(name);
if (iter == fMaterialGraphBakers.end()) {
MaterialGraphBakerPtr baker =
std::make_shared<MaterialGraphBaker>(surfaceMaterial);
fMaterialGraphBakers.insert(std::make_pair(name, baker));
}
}
}
return MS::kSuccess;
}
{
for(MaterialGraphBakers::value_type& val : fMaterialGraphBakers) {
val.second->sample(time);
}
return MS::kSuccess;
}
MStatus MaterialBaker::buildGraph()
{
for(MaterialGraphBakers::value_type& val : fMaterialGraphBakers) {
val.second->buildGraph();
}
return MS::kSuccess;
}
MaterialGraphMap::Ptr MaterialBaker::get()
{
MaterialGraphMap::MPtr graphMap = std::make_shared<MaterialGraphMap>();
for(const MaterialGraphBakers::value_type& val : fMaterialGraphBakers) {
MaterialGraph::Ptr graph = val.second->get();
if (graph) {
graphMap->addMaterialGraph(graph);
}
}
for(const NamedMaterialGraphs::value_type& val : fExistingGraphs) {
if (val.second && !graphMap->find(val.first)) {
graphMap->addMaterialGraph(val.second);
}
}
return !graphMap->getGraphs().empty() ? graphMap : MaterialGraphMap::Ptr();
}
}