#include "CacheWriterAlembic.h"
#include "CacheAlembicUtil.h"
#include "gpuCacheStrings.h"
#include <maya/MString.h>
#include <maya/MTime.h>
#include <maya/MGlobal.h>
#include <Alembic/AbcCoreOgawa/ReadWrite.h>
#include <Alembic/AbcCoreAbstract/TimeSamplingType.h>
#include <Alembic/AbcGeom/ArchiveBounds.h>
#include <cassert>
using namespace CacheAlembicUtil;
namespace {
using namespace GPUCache;
class SubNodeWriterVisitor : public SubNodeVisitor
{
public:
SubNodeWriterVisitor(
Alembic::Abc::OObject parent,
double secondsPerSample,
double startTimeInSeconds
)
: fParent(parent),
fSecondsPerSample(secondsPerSample),
fStartTimeInSeconds(startTimeInSeconds),
fMaxNumSamples(0)
{}
void visit(const XformData& xform,
const SubNode& subNode) override
{
AlembicXformWriter xformWriter(
fParent, subNode.getName(), fSecondsPerSample, fStartTimeInSeconds);
fMaxNumSamples = 0;
XformData::SampleMap::const_iterator it =
xform.getSamples().begin();
XformData::SampleMap::const_iterator end =
xform.getSamples().end();
if (it != end) {
std::shared_ptr<const XformSample> sample = it->second;
double time = fStartTimeInSeconds + 0.5f * fSecondsPerSample;
xformWriter.write(sample);
++it;
time += fSecondsPerSample;
++fMaxNumSamples;
for (;it != end; ++it, time += fSecondsPerSample, ++fMaxNumSamples) {
const double nextTime = it->second->timeInSeconds();
while (time < nextTime) {
xformWriter.write(sample, sample);
time += fSecondsPerSample;
++fMaxNumSamples;
}
std::shared_ptr<const XformSample> prev = sample;
sample = it->second;
xformWriter.write(sample, prev);
}
}
SubNodeWriterVisitor visitor(xformWriter.object(),
fSecondsPerSample, fStartTimeInSeconds);
for(const SubNode::Ptr& child : subNode.getChildren()) {
child->accept(visitor);
fMaxNumSamples = std::max(fMaxNumSamples, visitor.maxNumSamples());
}
}
void visit(const ShapeData& shape,
const SubNode& subNode) override
{
AlembicMeshWriter meshWriter(
fParent, subNode.getName(), fSecondsPerSample, fStartTimeInSeconds);
fMaxNumSamples = 0;
ShapeData::SampleMap::const_iterator it =
shape.getSamples().begin();
ShapeData::SampleMap::const_iterator end =
shape.getSamples().end();
if (it != end) {
std::shared_ptr<const ShapeSample> sample = it->second;
double time = fStartTimeInSeconds + 0.5f * fSecondsPerSample;
meshWriter.write(sample);
++it;
time += fSecondsPerSample;
++fMaxNumSamples;
for (;it != end; ++it, time += fSecondsPerSample, ++fMaxNumSamples) {
const double nextTime = it->second->timeInSeconds();
while (time < nextTime) {
meshWriter.write(sample, sample);
time += fSecondsPerSample;
++fMaxNumSamples;
}
std::shared_ptr<const ShapeSample> prev = sample;
sample = it->second;
meshWriter.write(sample, prev);
}
}
assert(shape.getMaterials().size() <= 1);
if (!shape.getMaterials().empty() && shape.getMaterials()[0].length() > 0) {
MString material = shape.getMaterials()[0];
std::string materialAssignmentPath = "/";
materialAssignmentPath += kMaterialsObject;
materialAssignmentPath += "/";
materialAssignmentPath += material.
asChar();
Alembic::AbcMaterial::addMaterialAssignment(
meshWriter.object(),
materialAssignmentPath
);
}
}
unsigned int maxNumSamples() const
{
return fMaxNumSamples;
}
private:
Alembic::Abc::OObject fParent;
const double fSecondsPerSample;
const double fStartTimeInSeconds;
unsigned int fMaxNumSamples;
};
class ArchiveBoundsVisitor : public SubNodeVisitor
{
public:
ArchiveBoundsVisitor(
double timeInSeconds,
const MMatrix& matrix)
: fTimeInSeconds(timeInSeconds), fMatrix(matrix)
{}
void visit(const XformData& xform,
const SubNode& subNode) override
{
const std::shared_ptr<const XformSample>& sample =
xform.getSample(fTimeInSeconds);
if (!sample) return;
const MMatrix matrix = sample->xform() * fMatrix;
for(const SubNode::Ptr& child : subNode.getChildren()) {
ArchiveBoundsVisitor visitor(fTimeInSeconds, matrix);
child->accept(visitor);
fBoundingBox.expand(visitor.getBoundingBox());
}
}
void visit(const ShapeData& shape,
const SubNode& subNode) override
{
const std::shared_ptr<const ShapeSample>& sample =
shape.getSample(fTimeInSeconds);
if (!sample) return;
fBoundingBox = sample->boundingBox();
fBoundingBox.transformUsing(fMatrix);
}
{
return fBoundingBox;
}
static void computeArchiveBounds(const SubNode::Ptr& topNode,
Alembic::Abc::TimeSamplingPtr& timeSampling,
unsigned int maxNumSamples,
std::vector<MBoundingBox>& archiveBounds)
{
if (!topNode || !timeSampling || maxNumSamples == 0) return;
assert(maxNumSamples >= archiveBounds.size());
if (maxNumSamples > archiveBounds.size()) {
archiveBounds.resize(maxNumSamples,
!archiveBounds.empty() ? archiveBounds.back() :
MBoundingBox());
}
for (unsigned int i = 0; i < maxNumSamples; i++) {
double timeInSeconds = timeSampling->getSampleTime(i);
topNode->accept(visitor);
archiveBounds[i].expand(visitor.getBoundingBox());
}
}
private:
double fTimeInSeconds;
};
}
struct AlembicCacheWriter::MakeSharedEnabler: public AlembicCacheWriter{
MakeSharedEnabler(
const MFileObject& file,
char compressLevel)
:AlembicCacheWriter(file, compressLevel){}
};
std::shared_ptr<CacheWriter> AlembicCacheWriter::create(
char compressLevel)
{
return std::make_shared<MakeSharedEnabler>(file, compressLevel);
}
AlembicCacheWriter::AlembicCacheWriter(
const MFileObject& file,
char compressLevel)
: fFile(file),
fCompressLevel(compressLevel),
fMaxNumSamples(0)
{
try {
std::lock_guard<std::mutex> alembicLock(gsAlembicMutex);
fAbcArchive = Alembic::Abc::OArchive(
Alembic::AbcCoreOgawa::WriteArchive(),
Alembic::Abc::ErrorHandler::kThrowPolicy
);
if (fAbcArchive.valid()) {
fAbcArchive.setCompressionHint(fCompressLevel);
std::string realName = fAbcArchive.getName();
fFile.setRawFullName(realName.c_str());
}
}
catch (std::exception& ex) {
errorMsg.
format(msgFmt, fileName, ex.what());
}
}
AlembicCacheWriter::~AlembicCacheWriter()
{
try {
std::lock_guard<std::mutex> alembicLock(gsAlembicMutex);
if (fAbcTimeSampling && fMaxNumSamples != 0) {
unsigned int tsIndex = fAbcArchive.addTimeSampling(*fAbcTimeSampling);
if (tsIndex != 0) {
std::stringstream propName;
propName << tsIndex << ".samples";
Alembic::Abc::OUInt32Property samplesProp(
fAbcArchive.getTop().getProperties(), propName.str());
samplesProp.set(fMaxNumSamples);
}
Alembic::Abc::OBox3dProperty boxProp =
Alembic::AbcGeom::CreateOArchiveBounds(fAbcArchive, fAbcTimeSampling);
for (unsigned int i = 0; i < fMaxNumSamples; i++) {
const MPoint min = fArchiveBounds[i].min();
const MPoint max = fArchiveBounds[i].max();
boxProp.set(Alembic::Abc::Box3d(
Alembic::Abc::V3d(min.
x, min.
y, min.
z),
Alembic::Abc::V3d(max.
x, max.
y, max.
z)
));
}
}
fAbcArchive.reset();
}
catch (std::exception& ex) {
errorMsg.
format(msgFmt, fFile.resolvedFullName(), ex.what());
}
}
bool AlembicCacheWriter::valid() const
{
std::lock_guard<std::mutex> alembicLock(gsAlembicMutex);
return fAbcArchive.valid();
}
void AlembicCacheWriter::writeSubNodeHierarchy(
const SubNode::Ptr& topNode,
double secondsPerSample, double startTimeInSeconds)
{
try {
std::lock_guard<std::mutex> alembicLock(gsAlembicMutex);
SubNodeWriterVisitor visitor(
fAbcArchive.getTop(), secondsPerSample, startTimeInSeconds);
topNode->accept(visitor);
if (!fAbcTimeSampling) {
Alembic::Abc::TimeSamplingPtr ts = Alembic::Abc::TimeSamplingPtr(
new Alembic::Abc::TimeSampling(secondsPerSample, startTimeInSeconds));
unsigned int tsIndex = fAbcArchive.addTimeSampling(*ts);
fAbcTimeSampling = fAbcArchive.getTimeSampling(tsIndex);
}
else {
assert(fAbcTimeSampling->getNumStoredTimes() == 1);
assert(fAbcTimeSampling->getStoredTimes()[0] == startTimeInSeconds);
assert(fAbcTimeSampling->getTimeSamplingType().getTimePerCycle() == secondsPerSample);
}
fMaxNumSamples = std::max(fMaxNumSamples, visitor.maxNumSamples());
ArchiveBoundsVisitor::computeArchiveBounds(
topNode, fAbcTimeSampling, fMaxNumSamples, fArchiveBounds);
}
catch (std::exception& ex) {
errorMsg.
format(msgFmt, fFile.resolvedFullName(), ex.what());
}
}
void AlembicCacheWriter::writeMaterials(
const MaterialGraphMap::Ptr& materialGraphMap,
double secondsPerSample, double startTimeInSeconds)
{
try {
std::lock_guard<std::mutex> alembicLock(gsAlembicMutex);
Alembic::Abc::OObject materialsObject(fAbcArchive.getTop(), kMaterialsObject);
assert(materialGraphMap);
for(
const MaterialGraphMap::NamedMap::value_type& val :
materialGraphMap->getGraphs()) {
const MaterialGraph::Ptr& graph = val.second;
assert(graph);
MaterialGraphWriter writer(
materialsObject, secondsPerSample, startTimeInSeconds, graph);
writer.write();
}
}
catch (std::exception& ex) {
errorMsg.
format(msgFmt, fFile.resolvedFullName(), ex.what());
}
}
const MFileObject& AlembicCacheWriter::getFileObject()
const
{
return fFile;
}
AlembicXformWriter::AlembicXformWriter(
const Alembic::Abc::OObject& parent,
const MString& name,
double secondsPerSample, double startTimeInSeconds)
: fCachedWrite(0)
{
fTimeSampPtr = Alembic::Abc::TimeSamplingPtr(
new Alembic::Abc::TimeSampling(secondsPerSample, startTimeInSeconds));
Alembic::AbcGeom::OXform xformObject(parent, name.
asChar(), fTimeSampPtr);
fAbcXform = xformObject.getSchema();
}
Alembic::Abc::OObject AlembicXformWriter::object()
{
return fAbcXform.getObject();
}
void AlembicXformWriter::write(
const std::shared_ptr<const XformSample>& sample)
{
Alembic::AbcGeom::XformSample xformSample;
fillXform(xformSample, sample);
fAbcXform.set(xformSample);
if (!sample->visibility()) {
Alembic::Abc::OObject object = fAbcXform.getObject();
fVisibility = Alembic::AbcGeom::CreateVisibilityProperty(object, fTimeSampPtr);
fVisibility.set(char(Alembic::AbcGeom::kVisibilityHidden));
}
fCachedWrite++;
}
void AlembicXformWriter::write(
const std::shared_ptr<const XformSample>& sample,
const std::shared_ptr<const XformSample>& prev)
{
if (!sample->xform().isEquivalent(prev->xform()))
{
Alembic::AbcGeom::XformSample xformSample;
fillXform(xformSample, sample);
fAbcXform.set(xformSample);
}
else {
fAbcXform.setFromPrevious();
}
if (!sample->visibility() && !fVisibility) {
Alembic::Abc::OObject object = fAbcXform.getObject();
fVisibility = Alembic::AbcGeom::CreateVisibilityProperty(object, fTimeSampPtr);
for (size_t i = 0; i < fCachedWrite; i++) {
fVisibility.set(char(Alembic::AbcGeom::kVisibilityDeferred));
}
}
if (fVisibility) {
if (sample->visibility() == prev->visibility()) {
fVisibility.setFromPrevious();
}
else {
fVisibility.set(char(sample->visibility() ?
Alembic::AbcGeom::kVisibilityDeferred :
Alembic::AbcGeom::kVisibilityHidden));
}
}
fCachedWrite++;
}
void AlembicXformWriter::fillXform(
Alembic::AbcGeom::XformSample& xformSample,
const std::shared_ptr<const XformSample>& sample)
{
const Alembic::Abc::M44d abcWorldMatrix(sample->xform().matrix);
Alembic::AbcGeom::XformOp opMatrix(Alembic::AbcGeom::kMatrixOperation,
Alembic::AbcGeom::kMatrixHint);
opMatrix.setMatrix(abcWorldMatrix);
xformSample.addOp(opMatrix);
}
AlembicMeshWriter::AlembicMeshWriter(
const Alembic::Abc::OObject& parent,
const MString& name,
double secondsPerSample,
double startTimeInSeconds)
: fCachedWrite(0)
{
fTimeSampPtr = Alembic::Abc::TimeSamplingPtr(new Alembic::Abc::TimeSampling(secondsPerSample, startTimeInSeconds));
Alembic::AbcGeom::OPolyMesh meshObject(parent, name.
asChar(), fTimeSampPtr);
fAbcMesh = meshObject.getSchema();
fAbcCreator = Alembic::Abc::OStringProperty(
fAbcMesh.getPtr(), kCustomPropertyCreator, fTimeSampPtr);
fAbcVersion = Alembic::Abc::OStringProperty(
fAbcMesh.getPtr(), kCustomPropertyVersion, fTimeSampPtr);
fAbcWireIndices = Alembic::Abc::OInt32ArrayProperty(
fAbcMesh.getPtr(), kCustomPropertyWireIndices, fTimeSampPtr);
fAbcDiffuseColor = Alembic::Abc::OC4fProperty(
fAbcMesh.getPtr(), kCustomPropertyDiffuseColor, fTimeSampPtr);
}
Alembic::Abc::OObject AlembicMeshWriter::object()
{
return fAbcMesh.getObject();
}
void AlembicMeshWriter::write(
const std::shared_ptr<const ShapeSample>& sample)
{
Alembic::AbcGeom::OPolyMeshSchema::Sample meshSample;
Alembic::Abc::Int32ArraySample wireIndicesSample;
Alembic::Abc::Int32ArraySample groupSizesSample;
Alembic::Abc::C4f diffuseColorSample;
fillWireframeSample(wireIndicesSample, sample);
fillTriangleSample(meshSample, groupSizesSample, sample);
fillPositionSample(meshSample, sample);
fillNormalSample(meshSample, sample, false);
fillUVSample(meshSample, sample, false);
fillBoundingBoxSample(meshSample, sample);
fillDiffuseColorSample(diffuseColorSample, sample);
fAbcMesh.set(meshSample);
fAbcCreator.set(kCustomPropertyCreatorValue);
fAbcVersion.set(kCustomPropertyVersionValue);
fAbcWireIndices.set(wireIndicesSample);
if (groupSizesSample.size() > 1) {
fAbcGroupSizes = Alembic::Abc::OInt32ArrayProperty(
fAbcMesh.getPtr(), kCustomPropertyShadingGroupSizes, fTimeSampPtr);
fAbcGroupSizes.set(groupSizesSample);
}
fAbcDiffuseColor.set(diffuseColorSample);
if (!sample->visibility()) {
Alembic::Abc::OObject object = fAbcMesh.getObject();
fVisibility = Alembic::AbcGeom::CreateVisibilityProperty(object, fTimeSampPtr);
fVisibility.set(char(Alembic::AbcGeom::kVisibilityHidden));
}
fCachedWrite++;
}
void AlembicMeshWriter::write(
const std::shared_ptr<const ShapeSample>& sample,
const std::shared_ptr<const ShapeSample>& prev)
{
Alembic::AbcGeom::OPolyMeshSchema::Sample meshSample;
Alembic::Abc::Int32ArraySample wireIndicesSample;
Alembic::Abc::Int32ArraySample groupSizesSample;
Alembic::Abc::C4f diffuseColorSample;
if (sample->wireVertIndices() != prev->wireVertIndices()) {
fillWireframeSample(wireIndicesSample, sample);
}
assert(sample->numIndexGroups() == prev->numIndexGroups());
for(size_t i =0; i<sample->numIndexGroups() && i<prev->numIndexGroups(); ++i) {
if (sample->triangleVertIndices(i) != prev->triangleVertIndices(i)) {
fillTriangleSample(meshSample, groupSizesSample, sample);
break;
}
}
if (sample->positions() != prev->positions()) {
fillPositionSample(meshSample, sample);
}
if (sample->normals() != prev->normals()) {
fillNormalSample(meshSample, sample, prev->normals().get() != NULL);
}
if (sample->uvs() != prev->uvs()) {
fillUVSample(meshSample, sample, prev->uvs().get() != NULL);
}
fillBoundingBoxSample(meshSample, sample);
}
fAbcMesh.set(meshSample);
Alembic::AbcGeom::SetPropUsePrevIfNull(fAbcWireIndices, wireIndicesSample);
if (sample->diffuseColor() != prev->diffuseColor()) {
fillDiffuseColorSample(diffuseColorSample, sample);
fAbcDiffuseColor.set(diffuseColorSample);
}
if (!sample->visibility() && !fVisibility) {
Alembic::Abc::OObject object = fAbcMesh.getObject();
fVisibility = Alembic::AbcGeom::CreateVisibilityProperty(object, fTimeSampPtr);
for (size_t i = 0; i < fCachedWrite; i++) {
fVisibility.set(char(Alembic::AbcGeom::kVisibilityDeferred));
}
}
if (fVisibility) {
if (sample->visibility() == prev->visibility()) {
fVisibility.setFromPrevious();
}
else {
fVisibility.set(char(sample->visibility() ?
Alembic::AbcGeom::kVisibilityDeferred :
Alembic::AbcGeom::kVisibilityHidden));
}
}
fCachedWrite++;
}
void AlembicMeshWriter::fillWireframeSample(
Alembic::Abc::Int32ArraySample& wireIndicesSample,
const std::shared_ptr<const ShapeSample>& sample)
{
const int* wireIndexArray = NULL;
IndexBuffer::ReadableArrayPtr readable;
if (sample->wireVertIndices()) {
readable = sample->wireVertIndices()->array()->getReadableArray();
fIndexReadInterfaces.push_back(readable);
wireIndexArray = (const int*)readable->get();
}
size_t wireIndexCount = sample->numWires() * 2;
wireIndicesSample = Alembic::Abc::Int32ArraySample(wireIndexArray, wireIndexCount);
}
void AlembicMeshWriter::fillTriangleSample(
Alembic::AbcGeom::OPolyMeshSchema::Sample& meshSample,
Alembic::Abc::Int32ArraySample& groupSizesSample,
const std::shared_ptr<const ShapeSample>& sample)
{
size_t numTriangles = 0;
for(size_t i=0; i<sample->numIndexGroups(); ++i) {
numTriangles += sample->numTriangles(i);
fGroupSizes.push_back((int)sample->numTriangles(i));
}
groupSizesSample = Alembic::Abc::Int32ArraySample(fGroupSizes);
fPolygonCount.resize(numTriangles, 3);
meshSample.setFaceCounts(Alembic::Abc::Int32ArraySample(fPolygonCount));
std::vector<Alembic::Abc::int32_t> faceIndices(numTriangles*3);
int* faceIndicesCW = numTriangles>0 ? (int*)&(faceIndices[0]) : NULL;
for(size_t i=0; i<sample->numIndexGroups(); ++i) {
IndexBuffer::ReadableArrayPtr readable;
const int* faceIndicesCCW = NULL;
if (sample->triangleVertIndices(i)) {
readable = sample->triangleVertIndices(i)->array()->getReadableArray();
faceIndicesCCW = (const int* )readable->get();
}
size_t indicesCount = sample->numTriangles(i)*3;
for (size_t offset=0; offset<indicesCount; faceIndicesCW+=3, offset+=3) {
faceIndicesCW[0] = faceIndicesCCW[offset + 2];
faceIndicesCW[1] = faceIndicesCCW[offset + 1];
faceIndicesCW[2] = faceIndicesCCW[offset + 0];
}
}
fFaceIndices.swap(faceIndices);
meshSample.setFaceIndices(Alembic::Abc::Int32ArraySample(fFaceIndices));
}
void AlembicMeshWriter::fillPositionSample(
Alembic::AbcGeom::OPolyMeshSchema::Sample& meshSample,
const std::shared_ptr<const ShapeSample>& sample)
{
VertexBuffer::ReadableArrayPtr readable;
const Alembic::Abc::V3f* positionArray = NULL;
if (sample->positions()) {
readable = sample->positions()->array()->getReadableArray();
fVertexReadInterfaces.push_back(readable);
positionArray = (const Alembic::Abc::V3f*)readable->get();
}
size_t positionCount = sample->numVerts();
meshSample.setPositions(Alembic::Abc::P3fArraySample(positionArray, positionCount));
}
void AlembicMeshWriter::fillNormalSample(
Alembic::AbcGeom::OPolyMeshSchema::Sample& meshSample,
const std::shared_ptr<const ShapeSample>& sample,
bool forceWrite)
{
if (sample->normals()) {
Alembic::AbcGeom::ON3fGeomParam::Sample normalSample;
normalSample.setScope(Alembic::AbcGeom::kVertexScope);
VertexBuffer::ReadableArrayPtr readable = sample->normals()->array()->getReadableArray();
fVertexReadInterfaces.push_back(readable);
const Alembic::Abc::N3f* normalArray =
(const Alembic::Abc::N3f*)(readable->get());
size_t normalCount = sample->numVerts();
if (nullptr != normalArray || normalCount != 0)
{
normalSample.setVals(
Alembic::AbcGeom::N3fArraySample(normalArray, normalCount));
}
meshSample.setNormals(normalSample);
}
else if (forceWrite) {
Alembic::AbcGeom::ON3fGeomParam::Sample normalSample;
normalSample.setScope(Alembic::AbcGeom::kVertexScope);
normalSample.setVals(
Alembic::AbcGeom::N3fArraySample(NULL, 0));
meshSample.setNormals(normalSample);
}
}
void AlembicMeshWriter::fillUVSample(
Alembic::AbcGeom::OPolyMeshSchema::Sample& meshSample,
const std::shared_ptr<const ShapeSample>& sample,
bool forceWrite)
{
if (sample->uvs()) {
Alembic::AbcGeom::OV2fGeomParam::Sample uvSample;
uvSample.setScope(Alembic::AbcGeom::kVertexScope);
VertexBuffer::ReadableArrayPtr readable = sample->uvs()->array()->getReadableArray();
fVertexReadInterfaces.push_back(readable);
const Alembic::Abc::V2f* uvArray =
(const Alembic::Abc::V2f*)(readable->get());
size_t uvCount = sample->numVerts();
uvSample.setVals(Alembic::AbcGeom::V2fArraySample(uvArray, uvCount));
meshSample.setUVs(uvSample);
}
else if (forceWrite) {
Alembic::AbcGeom::OV2fGeomParam::Sample uvSample;
uvSample.setScope(Alembic::AbcGeom::kVertexScope);
uvSample.setVals(Alembic::AbcGeom::V2fArraySample(NULL, 0));
meshSample.setUVs(uvSample);
}
}
void AlembicMeshWriter::fillBoundingBoxSample(
Alembic::AbcGeom::OPolyMeshSchema::Sample& meshSample,
const std::shared_ptr<const ShapeSample>& sample)
{
Alembic::Abc::Box3d selfBounds(
Alembic::Abc::V3d(min.
x, min.
y, min.
z),
Alembic::Abc::V3d(max.
x, max.
y, max.
z));
meshSample.setSelfBounds(selfBounds);
}
void AlembicMeshWriter::fillDiffuseColorSample(
Alembic::AbcGeom::C4f& diffuseColorSample,
const std::shared_ptr<const ShapeSample>& sample)
{
const MColor diffuseColor = sample->diffuseColor();
diffuseColorSample.
r = diffuseColor.
r;
diffuseColorSample.g = diffuseColor.
g;
diffuseColorSample.b = diffuseColor.
b;
diffuseColorSample.a = diffuseColor.
a;
}
MaterialGraphWriter::MaterialGraphWriter(
Alembic::Abc::OObject parent,
double secondsPerSample,
double startTimeInSeconds,
const MaterialGraph::Ptr& graph
)
: fSecondsPerSample(secondsPerSample),
fStartTimeInSeconds(startTimeInSeconds),
fGraph(graph)
{
assert(fGraph);
fTimeSampPtr = Alembic::Abc::TimeSamplingPtr(
new Alembic::Abc::TimeSampling(secondsPerSample, startTimeInSeconds));
Alembic::AbcMaterial::OMaterial materialObject(
parent, graph->name().asChar(), fTimeSampPtr);
fAbcMaterial = materialObject.getSchema();
}
void MaterialGraphWriter::write()
{
for(const MaterialGraph::NamedMap::value_type& val : fGraph->getNodes()) {
std::string name = val.second->name().
asChar();
std::string type = val.second->type().asChar();
fAbcMaterial.addNetworkNode(name, kMaterialsGpuCacheTarget, type);
}
for(const MaterialGraph::NamedMap::value_type& val : fGraph->getNodes()) {
const MaterialNode::Ptr& node = val.second;
Alembic::Abc::OCompoundProperty abcCompoundProp =
fAbcMaterial.getNetworkNodeParameters(node->name().asChar());
assert(abcCompoundProp.valid());
for(
const MaterialNode::PropertyMap::value_type& val :
node->properties()) {
const MaterialProperty::Ptr& prop = val.second;
switch (prop->type()) {
case MaterialProperty::kBool:
writeMaterialProperty<Alembic::Abc::OBoolProperty>(abcCompoundProp, prop);
break;
case MaterialProperty::kInt32:
writeMaterialProperty<Alembic::Abc::OInt32Property>(abcCompoundProp, prop);
break;
case MaterialProperty::kFloat:
writeMaterialProperty<Alembic::Abc::OFloatProperty>(abcCompoundProp, prop);
break;
case MaterialProperty::kFloat2:
writeMaterialProperty<Alembic::Abc::OV2fProperty>(abcCompoundProp, prop);
break;
case MaterialProperty::kFloat3:
writeMaterialProperty<Alembic::Abc::OV3fProperty>(abcCompoundProp, prop);
break;
case MaterialProperty::kRGB:
writeMaterialProperty<Alembic::Abc::OC3fProperty>(abcCompoundProp, prop);
break;
case MaterialProperty::kString:
writeMaterialProperty<Alembic::Abc::OWstringProperty>(abcCompoundProp, prop);
break;
default:
assert(0);
break;
}
}
}
for(const MaterialGraph::NamedMap::value_type& val : fGraph->getNodes()) {
const MaterialNode::Ptr& node = val.second;
std::string nodeName = node->name().asChar();
for(
const MaterialNode::PropertyMap::value_type& val :
node->properties()) {
const MaterialProperty::Ptr& prop = val.second;
const MaterialNode::Ptr srcNode = prop->srcNode();
const MaterialProperty::Ptr srcProp = prop->srcProp();
if (srcNode && srcProp) {
std::string propName = prop->name().asChar();
std::string srcNodeName = srcNode->name().asChar();
std::string srcPropName = srcProp->name().asChar();
fAbcMaterial.setNetworkNodeConnection(
nodeName,
propName,
srcNodeName,
srcPropName
);
}
}
}
const MaterialNode::Ptr& rootNode = fGraph->rootNode();
if (rootNode) {
fAbcMaterial.setNetworkTerminal(
kMaterialsGpuCacheTarget,
kMaterialsGpuCacheType,
rootNode->name().asChar()
);
}
}