void AbcWriteJob::perFrameCallback(double iFrame) { MBoundingBox bbox; util::ShapeSet::iterator it = mArgs.dagPaths.begin(); const util::ShapeSet::iterator end = mArgs.dagPaths.end(); for (; it != end; it ++) { mCurDag = *it; MMatrix eMInvMat; if (mArgs.worldSpace) { eMInvMat.setToIdentity(); } else { eMInvMat = mCurDag.exclusiveMatrixInverse(); } bbox.expand(getBoundingBox(iFrame, eMInvMat)); } Alembic::Abc::V3d min(bbox.min().x, bbox.min().y, bbox.min().z); Alembic::Abc::V3d max(bbox.max().x, bbox.max().y, bbox.max().z); Alembic::Abc::Box3d b(min, max); mBoxProp.set(b); processCallback(mArgs.melPerFrameCallback, true, iFrame, bbox); processCallback(mArgs.pythonPerFrameCallback, false, iFrame, bbox); }
bool DX11ViewportRenderer::drawBounds( const MMatrix &matrix, const MBoundingBox &box, float color[3] ) { // Transform from object to world space // XMMATRIX mat = XMMATRIX ( (float)matrix.matrix[0][0], (float)matrix.matrix[0][1], (float)matrix.matrix[0][2], (float)matrix.matrix[0][3], (float)matrix.matrix[1][0], (float)matrix.matrix[1][1], (float)matrix.matrix[1][2], (float)matrix.matrix[1][3], (float)matrix.matrix[2][0], (float)matrix.matrix[2][1], (float)matrix.matrix[2][2], (float)matrix.matrix[2][3], (float)matrix.matrix[3][0], (float)matrix.matrix[3][1], (float)matrix.matrix[3][2], (float)matrix.matrix[3][3] ); // Adjust the unit cube to the bounds // MPoint minPt = box.min(); MPoint maxPt = box.max(); float minVal[3] = { (float)minPt.x, (float)minPt.y, (float)minPt.z }; float maxVal[3] = { (float)maxPt.x, (float)maxPt.y, (float)maxPt.z }; XMMATRIX bounds( 0.5f*(maxVal[0]-minVal[0]), 0.0f, 0.0f, 0.0f, 0.0f, 0.5f*(maxVal[1]-minVal[1]), 0.0f, 0.0f, 0.0f, 0.0f, 0.5f*(maxVal[2]-minVal[2]), 0.0f, 0.5f*(maxVal[0]+minVal[0]), 0.5f*(maxVal[1]+minVal[1]), 0.5f*(maxVal[2]+minVal[2]), 1.0f ); // Set vertex buffer UINT stride = sizeof( BoundsVertex ); UINT offset = 0; m_pD3DDeviceCtx->IASetVertexBuffers( 0, 1, &m_pBoundsVertexBuffer, &stride, &offset ); // Set index buffer m_pD3DDeviceCtx->IASetIndexBuffer( m_pBoundsIndexBuffer, DXGI_FORMAT_R16_UINT, 0 ); // Set constant buffer BoundsConstants cb; cb.fWVP = XMMatrixTranspose( bounds * mat * m_currentViewMatrix * m_currentProjectionMatrix ); cb.fDiffuseMaterial = XMFLOAT3( color[0], color[1], color[2] ); m_pD3DDeviceCtx->UpdateSubresource( m_pBoundsConstantBuffer, 0, NULL, &cb, 0, 0 ); // Set primitive topology m_pD3DDeviceCtx->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_LINELIST ); // get shader SurfaceEffectItemList::const_iterator it = m_resourceManager.getSurfaceEffectItemList().find( "Maya_unlit" ); if ( it == m_resourceManager.getSurfaceEffectItemList().end() ) return false; const SurfaceEffectItem* sei = it->second; // bind shaders m_pD3DDeviceCtx->VSSetShader( sei->fVertexShader, NULL, 0 ); m_pD3DDeviceCtx->VSSetConstantBuffers( 0, 1, &m_pBoundsConstantBuffer ); m_pD3DDeviceCtx->IASetInputLayout( sei->fInputLayout ); m_pD3DDeviceCtx->PSSetShader( sei->fPixelShader, NULL, 0 ); m_pD3DDeviceCtx->PSSetConstantBuffers( 0, 1, &m_pBoundsConstantBuffer ); // draw m_pD3DDeviceCtx->DrawIndexed( 24, 0, 0 ); return true; }
MTransformationMatrix ffdPlanar::getXyzToStuTransformation( MBoundingBox& boundingBox ) { MTransformationMatrix transform = MTransformationMatrix(); double scale[3] = { FFD_DIMENSIONS_S > 0 ? 1.f / boundingBox.width() : 1.f, FFD_DIMENSIONS_T > 0 ? 1.f / boundingBox.height() : 1.f, FFD_DIMENSIONS_U > 0 ? 1.f / boundingBox.depth() : 1.f }; transform.addScale( scale, MSpace::kObject ); MVector boundsMinOffset = MPoint::origin - boundingBox.min(); transform.addTranslation( boundsMinOffset, MSpace::kObject ); return transform; }
MBoundingBox ovalLocator::boundingbox (float multiplier /*=1.0f*/) { static MBoundingBox boundingbox ; if ( boundingbox.min () == boundingbox.max () ) { MPointArray vert =ovalLocator::vertices () ; for ( unsigned int i =0 ; i < vert.length () ; i++ ) boundingbox.expand (vert [i]) ; } MBoundingBox bbox (boundingbox) ; if ( multiplier != 1.0f ) { double factors [3] ={ multiplier, multiplier, multiplier } ; MTransformationMatrix mat ; mat.setScale (factors, MSpace::kWorld) ; bbox.transformUsing (mat.asScaleMatrix ()) ; } return (bbox) ; }
/* Some simple code to draw a wireframe bounding box in OpenGL */ void MCustomSceneDraw::drawBounds( const MDagPath &dagPath, const MBoundingBox &box) { MMatrix matrix = dagPath.inclusiveMatrix(); MPoint minPt = box.min(); MPoint maxPt = box.max(); double bottomLeftFront[3] = { minPt.x, minPt.y, minPt.z }; double topLeftFront[3] = { minPt.x, maxPt.y, minPt.z }; double bottomRightFront[3] = { maxPt.x, minPt.y, minPt.z }; double topRightFront[3] = { maxPt.x, maxPt.y, minPt.z }; double bottomLeftBack[3] = { minPt.x, minPt.y, maxPt.z }; double topLeftBack[3] = { minPt.x, maxPt.y, maxPt.z }; double bottomRightBack[3] = { maxPt.x, minPt.y, maxPt.z }; double topRightBack[3] = { maxPt.x, maxPt.y, maxPt.z }; gGLFT->glMatrixMode( MGL_MODELVIEW ); gGLFT->glPushMatrix(); gGLFT->glMultMatrixd( &(matrix.matrix[0][0]) ); gGLFT->glBegin(MGL_LINE_STRIP); gGLFT->glVertex3dv( bottomLeftFront ); gGLFT->glVertex3dv( bottomLeftBack ); gGLFT->glVertex3dv( topLeftBack ); gGLFT->glVertex3dv( topLeftFront ); gGLFT->glVertex3dv( bottomLeftFront ); gGLFT->glVertex3dv( bottomRightFront ); gGLFT->glVertex3dv( bottomRightBack); gGLFT->glVertex3dv( topRightBack ); gGLFT->glVertex3dv( topRightFront ); gGLFT->glVertex3dv( bottomRightFront ); gGLFT->glEnd(); gGLFT->glBegin(MGL_LINES); gGLFT->glVertex3dv(bottomLeftBack); gGLFT->glVertex3dv(bottomRightBack); gGLFT->glVertex3dv(topLeftBack); gGLFT->glVertex3dv(topRightBack); gGLFT->glVertex3dv(topLeftFront); gGLFT->glVertex3dv(topRightFront); gGLFT->glEnd(); gGLFT->glPopMatrix(); }
void SpatialGrid::getVoxelRange( const MBoundingBox& box, gridPoint3<int>& minIndices, gridPoint3<int>& maxIndices ) const // // Description: // // Given a bounding box, compute the min and max voxel // indices (in x, y, z) of the cells that intersect the box. // { // get bbox corners // const MPoint& minPt = box.min(); const MPoint& maxPt = box.max(); // return indices for min/max corners // getVoxelCoords( minPt, minIndices, NULL ); getVoxelCoords( maxPt, maxIndices, NULL ); }
Imath::Box3d convert( const MBoundingBox &from ) { return Imath::Box3d( convert<V3d>( from.min() ), convert<V3d>( from.max() ) ); }
void simpleFluidEmitter::volumeFluidEmitter( MFnFluid& fluid, const MMatrix& fluidWorldMatrix, int plugIndex, MDataBlock& block, double dt, double conversion, double dropoff ) //============================================================================== // // Method: // // simpleFluidEmitter::volumeFluidEmitter // // Description: // // Emits fluid from points distributed over the surface of the // emitter's owner object. // // Parameters: // // fluid: fluid into which we are emitting // fluidWorldMatrix: object->world matrix for the fluid // plugIndex: identifies which fluid connected to the emitter // we are emitting into // block: datablock for the emitter, to retrieve attribute // values // dt: time delta for this frame // conversion: mapping from UI emission rates to internal units // dropoff: specifies how much emission rate drops off as // we move away from the local y-axis of the // volume emitter shape. // //============================================================================== { // get emitter position and relevant matrices // MPoint emitterPos = getWorldPosition(); MMatrix emitterWorldMatrix = getWorldMatrix(); MMatrix fluidInverseWorldMatrix = fluidWorldMatrix.inverse(); // get emission rates for density, fuel, heat, and emission color // double densityEmit = fluidDensityEmission( block ); double fuelEmit = fluidFuelEmission( block ); double heatEmit = fluidHeatEmission( block ); bool doEmitColor = fluidEmitColor( block ); MColor emitColor = fluidColor( block ); // rate modulation based on frame time, user value conversion factor, and // standard emitter "rate" value (not actually exposed in most fluid // emitters, but there anyway). // double theRate = getRate(block) * dt * conversion; // get voxel dimensions and sizes (object space) // double size[3]; unsigned int res[3]; fluid.getDimensions( size[0], size[1], size[2] ); fluid.getResolution( res[0], res[1], res[2] ); // voxel sizes double dx = size[0] / res[0]; double dy = size[1] / res[1]; double dz = size[2] / res[2]; // voxel centers double Ox = -size[0]/2; double Oy = -size[1]/2; double Oz = -size[2]/2; // find the voxels that intersect the bounding box of the volume // primitive associated with the emitter // MBoundingBox bbox; if( !volumePrimitiveBoundingBox( bbox ) ) { // shouldn't happen // return; } // transform volume primitive into fluid space // bbox.transformUsing( emitterWorldMatrix ); bbox.transformUsing( fluidInverseWorldMatrix ); MPoint lowCorner = bbox.min(); MPoint highCorner = bbox.max(); // get fluid voxel coord range of bounding box // ::int3 lowCoords; ::int3 highCoords; fluid.toGridIndex( lowCorner, lowCoords ); fluid.toGridIndex( highCorner, highCoords ); int i; for ( i = 0; i < 3; i++ ) { if ( lowCoords[i] < 0 ) { lowCoords[i] = 0; } else if ( lowCoords[i] > ((int)res[i])-1 ) { lowCoords[i] = ((int)res[i])-1; } if ( highCoords[i] < 0 ) { highCoords[i] = 0; } else if ( highCoords[i] > ((int)res[i])-1 ) { highCoords[i] = ((int)res[i])-1; } } // figure out the emitter size relative to the voxel size, and compute // a per-voxel sampling rate that uses 1 sample/voxel for emitters that // are >= 2 voxels big in all dimensions. For smaller emitters, use up // to 8 samples per voxel. // double emitterVoxelSize[3]; emitterVoxelSize[0] = (highCorner[0]-lowCorner[0])/dx; emitterVoxelSize[1] = (highCorner[1]-lowCorner[1])/dy; emitterVoxelSize[2] = (highCorner[2]-lowCorner[2])/dz; double minVoxelSize = MIN(emitterVoxelSize[0],MIN(emitterVoxelSize[1],emitterVoxelSize[2])); if( minVoxelSize < 1.0 ) { minVoxelSize = 1.0; } int maxSamples = 8; int numSamples = (int)(8.0/(minVoxelSize*minVoxelSize*minVoxelSize) + 0.5); if( numSamples < 1 ) numSamples = 1; if( numSamples > maxSamples ) numSamples = maxSamples; // non-jittered, just use one sample in the voxel center. Should replace // with uniform sampling pattern. // bool jitter = fluidJitter(block); if( !jitter ) { numSamples = 1; } // for each voxel that could potentially intersect the volume emitter // primitive, take some samples in the voxel. For those inside the // volume, compute their dropoff relative to the primitive's local y-axis, // and emit an appropriate amount into the voxel. // for( i = lowCoords[0]; i <= highCoords[0]; i++ ) { double x = Ox + (i+0.5)*dx; for( int j = lowCoords[1]; j < highCoords[1]; j++ ) { double y = Oy + (j+0.5)*dy; for( int k = lowCoords[2]; k < highCoords[2]; k++ ) { double z = Oz + (k+0.5)*dz; for ( int si = 0; si < numSamples; si++) { // compute voxel sample point (object space) // double rx, ry, rz; if(jitter) { rx = x + dx*(randgen() - 0.5); ry = y + dy*(randgen() - 0.5); rz = z + dz*(randgen() - 0.5); } else { rx = x; ry = y; rz = z; } // to world space MPoint pt( rx, ry, rz ); pt *= fluidWorldMatrix; // test to see if point is inside volume primitive // if( volumePrimitivePointInside( pt, emitterWorldMatrix ) ) { // compute dropoff // double dist = pt.distanceTo( emitterPos ); double distDrop = dropoff * (dist*dist); double newVal = (theRate * exp( -distDrop )) / (double)numSamples; // emit into arrays // if( newVal != 0.0 ) { fluid.emitIntoArrays( (float) newVal, i, j, k, (float)densityEmit, (float)heatEmit, (float)fuelEmit, doEmitColor, emitColor ); } } } } } } }
// used when ray does not intersect object // to account for perspective, all edges are flattened onto // a plane defined by the raySource and rayDirection double gpuCacheIsectUtil::getEdgeSnapPointOnBox(const MPoint& raySource, const MVector& rayDirection, const MBoundingBox& bbox, MPoint& snapPoint){ //if ray intersects bbox MPoint boxIntersectionPt; if(firstRayIntersection(bbox.min(), bbox.max(), raySource, rayDirection, NULL, &boxIntersectionPt)) { // ray intersects bounding box, so snapPoint is // closest hit on the outside of the box // and distance to box is 0 (for snapping purposes) snapPoint = boxIntersectionPt; return 0.0; } MPointArray verts; MPoint vmin = bbox.min(); MPoint vmax = bbox.max(); verts.insert(vmin,0); verts.insert(MPoint(vmax[0],vmin[1],vmin[2]),1); verts.insert(MPoint(vmax[0],vmax[1],vmin[2]),2); verts.insert(MPoint(vmin[0],vmax[1],vmin[2]),3); verts.insert(MPoint(vmin[0],vmin[1],vmax[2]),4); verts.insert(MPoint(vmax[0],vmin[1],vmax[2]),5); verts.insert(vmax,6); verts.insert(MPoint(vmin[0],vmax[1],vmax[2]),7); int edgeIndices[12][2]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{3,7},{2,6}}; double minDistRect = std::numeric_limits<double>::max(); for(int edge=0; edge<12;edge++){ MPoint vertex1Org = verts[edgeIndices[edge][0]]; MPoint vertex2Org = verts[edgeIndices[edge][1]]; double coef_plane = rayDirection * raySource; double d = coef_plane - rayDirection * vertex1Org; MPoint vertex1 = vertex1Org + rayDirection * d; d = coef_plane - rayDirection * vertex2Org; MPoint vertex2 = vertex2Org + rayDirection * d; MVector edgeDir = vertex2 - vertex1; if (edgeDir.length()<0.0000001){ double dist = vertex1.distanceTo(raySource); if (dist < minDistRect) { minDistRect = dist; snapPoint = vertex1Org; } } else { MPoint edgePt; // Compute the closest point from the edge to cursor Ray. double percent = gpuCacheIsectUtil::getClosestPointOnLine(raySource, vertex1, vertex2, edgePt); double dist = edgePt.distanceTo(raySource); if (dist < minDistRect) { minDistRect = dist; snapPoint = (vertex1Org + percent * (vertex2Org - vertex1Org)); } } } return minDistRect; }
MStatus VDBQueryCmd::doIt(const MArgList& args) { MStatus status = MS::kSuccess; MArgDatabase arg_data(syntax(), args); // always open new files to simplify code, it's cheap anyhow std::vector<std::string> vdb_paths; if (arg_data.isFlagSet(node_short_flag)) { MSelectionList slist; arg_data.getFlagArgument(node_short_flag, 0, slist); MObject node; slist.getDependNode(0, node); MFnDependencyNode dnode(node, &status); if (!status) return status; if (dnode.typeName() != VDBVisualizerShape::typeName) { MGlobal::displayError("[openvdb] Wrong node was passed to the command : " + dnode.name()); return MS::kFailure; } if (arg_data.isFlagSet(current_frame_short_flag)) vdb_paths.push_back(MPlug(node, VDBVisualizerShape::s_out_vdb_path).asString().asChar()); else { build_file_list(MPlug(node, VDBVisualizerShape::s_vdb_path).asString().asChar(), MPlug(node, VDBVisualizerShape::s_cache_playback_start).asInt(), MPlug(node, VDBVisualizerShape::s_cache_playback_end).asInt(), vdb_paths); } } else if (arg_data.isFlagSet(file_short_flag)) { MString vdb_path; arg_data.getFlagArgument(file_short_flag, 0, vdb_path); if (arg_data.isFlagSet(current_frame_short_flag)) { const int current_frame = static_cast<int>(MAnimControl::currentTime().as(MTime::uiUnit())); build_file_list(vdb_path.asChar(), current_frame, current_frame, vdb_paths); } else { int start_frame = 0; int end_frame = 0; if (arg_data.isFlagSet(start_frame_short_flag)) arg_data.getFlagArgument(start_frame_short_flag, 0, start_frame); else start_frame = static_cast<int>(MAnimControl::animationStartTime().as(MTime::uiUnit())); if (arg_data.isFlagSet(end_frame_short_flag)) arg_data.getFlagArgument(end_frame_short_flag, 0, end_frame); else end_frame = static_cast<int>(MAnimControl::animationEndTime().as(MTime::uiUnit())); build_file_list(vdb_path.asChar(), start_frame, end_frame, vdb_paths); } } else { MGlobal::displayError("[openvdb] No cache was passed to the command, use the -file(f) or the -node(n) flags"); return MS::kFailure; } if (vdb_paths.size() == 0) { MGlobal::displayError("[openvdb] No paths are passed to the command."); return MS::kFailure; } std::vector<openvdb::io::File*> vdb_files; vdb_files.reserve(vdb_paths.size()); MString query_type = ""; if (arg_data.isFlagSet(query_short_flag)) arg_data.getFlagArgument(query_short_flag, 0, query_type); else { MGlobal::displayError("[openvdb] No query is specified."); return MS::kFailure; } auto get_array_from_flag = [&](const char* flag_name, std::vector<std::string>& out_values) { if (arg_data.isFlagSet(flag_name)) { MString flag_data; arg_data.getFlagArgument(flag_name, 0, flag_data); MStringArray flags; if (flag_data.index(',')) flag_data.split(',', flags); else if (flag_data.index(';')) flag_data.split(';', flags); else if (flag_data.index(':')) flag_data.split(':', flags); else if (flag_data.index(' ')) flag_data.split(' ', flags); else flags.append(flag_data); const unsigned int flag_count = flags.length(); out_values.reserve(flag_count); for (unsigned int f = 0; f < flag_count; ++f) out_values.push_back(flags[f].asChar()); } }; std::vector<std::string> queries; get_array_from_flag(query_short_flag, queries); if (queries.size() == 0) { MGlobal::displayError("[openvdb] No queries are specified!"); return MS::kFailure; } for (auto vdb_path : vdb_paths) { openvdb::io::File* vdb_file = new openvdb::io::File(vdb_path); vdb_file->open(false); if (vdb_file->isOpen()) vdb_files.push_back(vdb_file); else delete vdb_file; } if (vdb_files.size() == 0) { MGlobal::displayError("[openvdb] No vdb files can be opened."); return MS::kFailure; } std::vector<std::string> grid_names; get_array_from_flag(grid_short_flag, grid_names); std::vector<std::string> grid_types; get_array_from_flag(grid_type_short_flag, grid_types); const bool all_grids = grid_names.size() == 0 && grid_types.size() == 0; auto grid_required = [&](openvdb::GridBase::ConstPtr grid) -> bool { if (all_grids) return true; else { return std::find(grid_names.begin(), grid_names.end(), grid->getName()) != grid_names.end() || std::find(grid_types.begin(), grid_types.end(), grid->valueType()) != grid_types.end(); } }; for (auto query : queries) { if (query == query_type_bbox) { MBoundingBox bbox; for (auto vdb_file : vdb_files) { openvdb::GridPtrVecPtr grids = vdb_file->readAllGridMetadata(); for (openvdb::GridPtrVec::const_iterator it = grids->begin(); it != grids->end(); ++it) { if (openvdb::GridBase::ConstPtr grid = *it) { if (grid_required(grid)) read_transformed_bounding_box(grid, bbox); } } } const MPoint min = bbox.min(); const MPoint max = bbox.max(); appendToResult(min.x); appendToResult(min.y); appendToResult(min.z); appendToResult(max.x); appendToResult(max.y); appendToResult(max.z); } else if (query == query_type_min_max) { std::vector<double> mins; std::vector<double> maxs; for (auto vdb_file : vdb_files) { openvdb::GridPtrVecPtr grids = vdb_file->readAllGridMetadata(); for (openvdb::GridPtrVec::const_iterator it = grids->begin(); it != grids->end(); ++it) { if (openvdb::GridBase::ConstPtr grid = *it) { if (grid_required(grid)) { // TODO: check for the minimum and maximum metadata if (grid->valueType() == "float") { if (mins.size() < 1) mins.resize(1, std::numeric_limits<double>::max()); if (maxs.size() < 1) maxs.resize(1, std::numeric_limits<double>::min()); openvdb::FloatGrid::ConstPtr grid_data = openvdb::gridConstPtrCast<openvdb::FloatGrid>(vdb_file->readGrid(grid->getName())); for (auto iter = grid_data->beginValueOn(); iter; ++iter) { const double value = static_cast<double>(iter.getValue()); mins[0] = std::min(mins[0], value); maxs[0] = std::max(maxs[0], value); } } else if (grid->valueType() == "vec3s") { if (mins.size() < 3) mins.resize(3, std::numeric_limits<double>::max()); if (maxs.size() < 3) maxs.resize(3, std::numeric_limits<double>::min()); openvdb::Vec3SGrid::ConstPtr grid_data = openvdb::gridConstPtrCast<openvdb::Vec3SGrid>(vdb_file->readGrid(grid->getName())); for (auto iter = grid_data->beginValueOn(); iter; ++iter) { const openvdb::Vec3d value = iter.getValue(); mins[0] = std::min(mins[0], value.x()); mins[1] = std::min(mins[1], value.y()); mins[2] = std::min(mins[2], value.z()); maxs[0] = std::max(maxs[0], value.x()); maxs[1] = std::max(maxs[1], value.y()); maxs[2] = std::max(maxs[2], value.z()); } } } } } } for (auto mn : mins) appendToResult(mn); for (auto mx : maxs) appendToResult(mx); } } for (auto vdb_file : vdb_files) delete vdb_file; return status; }
virtual void ExportProcedural( AtNode *node ) { // do basic node export ExportMatrix( node, 0 ); AtNode *shader = arnoldShader(); if( shader ) { AiNodeSetPtr( node, "shader", shader ); } AiNodeSetInt( node, "visibility", ComputeVisibility() ); MPlug plug = FindMayaObjectPlug( "receiveShadows" ); if( !plug.isNull() ) { AiNodeSetBool( node, "receive_shadows", plug.asBool() ); } plug = FindMayaObjectPlug( "aiSelfShadows" ); if( !plug.isNull() ) { AiNodeSetBool( node, "self_shadows", plug.asBool() ); } plug = FindMayaObjectPlug( "aiOpaque" ); if( !plug.isNull() ) { AiNodeSetBool( node, "opaque", plug.asBool() ); } // export any shading groups or displacement shaders which look like they // may be connected to procedural parameters. this ensures that maya shaders // the procedural will expect to find at rendertime will be exported to the // ass file (they otherwise might not be if they're not assigned to any objects). exportShadingInputs(); // now set the procedural-specific parameters MFnDagNode fnDagNode( m_dagPath ); MBoundingBox bound = fnDagNode.boundingBox(); AiNodeSetPnt( node, "min", bound.min().x, bound.min().y, bound.min().z ); AiNodeSetPnt( node, "max", bound.max().x, bound.max().y, bound.max().z ); const char *dsoPath = getenv( "IECOREARNOLD_PROCEDURAL_PATH" ); AiNodeSetStr( node, "dso", dsoPath ? dsoPath : "ieProcedural.so" ); AiNodeDeclare( node, "className", "constant STRING" ); AiNodeDeclare( node, "classVersion", "constant INT" ); AiNodeDeclare( node, "parameterValues", "constant ARRAY STRING" ); // cast should be ok as we're registered to only work on procedural holders IECoreMaya::ProceduralHolder *pHolder = static_cast<IECoreMaya::ProceduralHolder *>( fnDagNode.userNode() ); std::string className; int classVersion; IECore::ParameterisedProceduralPtr procedural = pHolder->getProcedural( &className, &classVersion ); AiNodeSetStr( node, "className", className.c_str() ); AiNodeSetInt( node, "classVersion", classVersion ); IECorePython::ScopedGILLock gilLock; try { boost::python::object parser = IECoreMaya::PythonCmd::globalContext()["IECore"].attr( "ParameterParser" )(); boost::python::object serialised = parser.attr( "serialise" )( procedural->parameters() ); size_t numStrings = IECorePython::len( serialised ); AtArray *stringArray = AiArrayAllocate( numStrings, 1, AI_TYPE_STRING ); for( size_t i=0; i<numStrings; i++ ) { std::string s = boost::python::extract<std::string>( serialised[i] ); // hack to workaround ass parsing errors /// \todo Remove when we get the Arnold version that fixes this for( size_t c = 0; c<s.size(); c++ ) { if( s[c] == '#' ) { s[c] = '@'; } } AiArraySetStr( stringArray, i, s.c_str() ); } AiNodeSetArray( node, "parameterValues", stringArray ); } catch( boost::python::error_already_set ) { PyErr_Print(); } }
void CScriptedShapeTranslator::RunScripts(AtNode *atNode, unsigned int step, bool update) { std::map<std::string, CScriptedTranslator>::iterator translatorIt; MFnDependencyNode fnNode(GetMayaObject()); translatorIt = gTranslators.find(fnNode.typeName().asChar()); if (translatorIt == gTranslators.end()) { AiMsgError("[mtoa.scriptedTranslators] No command to export node \"%s\" of type %s.", fnNode.name().asChar(), fnNode.typeName().asChar()); return; } MString exportCmd = translatorIt->second.exportCmd; MString cleanupCmd = translatorIt->second.cleanupCmd; MFnDagNode node(m_dagPath.node()); bool isMasterDag = false; bool transformBlur = IsMotionBlurEnabled(MTOA_MBLUR_OBJECT) && IsLocalMotionBlurEnabled(); bool deformBlur = IsMotionBlurEnabled(MTOA_MBLUR_DEFORM) && IsLocalMotionBlurEnabled(); char buffer[64]; MString command = exportCmd; command += "("; sprintf(buffer, "%f", GetExportFrame()); command += buffer; command += ", "; sprintf(buffer, "%d", step); command += buffer; command += ", "; // current sample frame sprintf(buffer, "%f", GetSampleFrame(m_session, step)); command += buffer; command += ", "; // List of arnold attributes the custom shape export command has overriden MStringArray attrs; if (!m_masterNode) { command += "(\"" + m_dagPath.partialPathName() + "\", \""; command += AiNodeGetName(atNode); command += "\"), None)"; isMasterDag = true; } else { command += "(\"" + m_dagPath.partialPathName() + "\", \""; command += AiNodeGetName(atNode); command += "\"), (\"" + GetMasterInstance().partialPathName() + "\", \""; command += AiNodeGetName(m_masterNode); command += "\"))"; } MStatus status = MGlobal::executePythonCommand(command, attrs); if (!status) { AiMsgError("[mtoa.scriptedTranslators] Failed to export node \"%s\".", node.name().asChar()); return; } // Build set of attributes already processed std::set<std::string> attrsSet; for (unsigned int i=0; i<attrs.length(); ++i) { attrsSet.insert(attrs[i].asChar()); } std::set<std::string>::iterator attrsEnd = attrsSet.end(); // Should be getting displacement shader from master instance only // as arnold do not support displacement shader overrides for ginstance MFnDependencyNode masterShadingEngine; MFnDependencyNode shadingEngine; float dispPadding = -AI_BIG; float dispHeight = 1.0f; float dispZeroValue = 0.0f; bool dispAutobump = false; bool outputDispPadding = false; bool outputDispHeight = false; bool outputDispZeroValue = false; bool outputDispAutobump = false; const AtNodeEntry *anodeEntry = AiNodeGetNodeEntry(atNode); GetShapeInstanceShader(m_dagPath, shadingEngine); if (!IsMasterInstance()) { GetShapeInstanceShader(GetMasterInstance(), masterShadingEngine); } else { masterShadingEngine.setObject(shadingEngine.object()); } AtMatrix matrix; MMatrix mmatrix = m_dagPath.inclusiveMatrix(); ConvertMatrix(matrix, mmatrix); // Set transformation matrix if (attrsSet.find("matrix") == attrsEnd) { if (HasParameter(anodeEntry, "matrix")) { if (transformBlur) { if (step == 0) { AtArray* matrices = AiArrayAllocate(1, GetNumMotionSteps(), AI_TYPE_MATRIX); AiArraySetMtx(matrices, step, matrix); AiNodeSetArray(atNode, "matrix", matrices); } else { AtArray* matrices = AiNodeGetArray(atNode, "matrix"); AiArraySetMtx(matrices, step, matrix); } } else { AiNodeSetMatrix(atNode, "matrix", matrix); } } } // Set bounding box if (attrsSet.find("min") == attrsEnd && attrsSet.find("max") == attrsEnd) { // Now check if min and max parameters are valid parameter names on arnold node if (HasParameter(anodeEntry, "min") != 0 && HasParameter(anodeEntry, "max") != 0) { if (step == 0) { MBoundingBox bbox = node.boundingBox(); MPoint bmin = bbox.min(); MPoint bmax = bbox.max(); AiNodeSetPnt(atNode, "min", static_cast<float>(bmin.x), static_cast<float>(bmin.y), static_cast<float>(bmin.z)); AiNodeSetPnt(atNode, "max", static_cast<float>(bmax.x), static_cast<float>(bmax.y), static_cast<float>(bmax.z)); } else { if (transformBlur || deformBlur) { AtPoint cmin = AiNodeGetPnt(atNode, "min"); AtPoint cmax = AiNodeGetPnt(atNode, "max"); MBoundingBox bbox = node.boundingBox(); MPoint bmin = bbox.min(); MPoint bmax = bbox.max(); if (bmin.x < cmin.x) cmin.x = static_cast<float>(bmin.x); if (bmin.y < cmin.y) cmin.y = static_cast<float>(bmin.y); if (bmin.z < cmin.z) cmin.z = static_cast<float>(bmin.z); if (bmax.x > cmax.x) cmax.x = static_cast<float>(bmax.x); if (bmax.y > cmax.y) cmax.y = static_cast<float>(bmax.y); if (bmax.z > cmax.z) cmax.z = static_cast<float>(bmax.z); AiNodeSetPnt(atNode, "min", cmin.x, cmin.y, cmin.z); AiNodeSetPnt(atNode, "max", cmax.x, cmax.y, cmax.z); } } } } if (step == 0) { // Set common attributes MPlug plug; if (AiNodeIs(atNode, "procedural")) { // Note: it is up to the procedural to properly forward (or not) those parameters to the node // it creates if (attrsSet.find("subdiv_type") == attrsEnd) { plug = FindMayaPlug("subdiv_type"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivType"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_type", atNode, "constant INT")) { AiNodeSetInt(atNode, "subdiv_type", plug.asInt()); } } if (attrsSet.find("subdiv_iterations") == attrsEnd) { plug = FindMayaPlug("subdiv_iterations"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivIterations"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_iterations", atNode, "constant BYTE")) { AiNodeSetByte(atNode, "subdiv_iterations", plug.asInt()); } } if (attrsSet.find("subdiv_adaptive_metric") == attrsEnd) { plug = FindMayaPlug("subdiv_adaptive_metric"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivAdaptiveMetric"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_adaptive_metric", atNode, "constant INT")) { AiNodeSetInt(atNode, "subdiv_adaptive_metric", plug.asInt()); } } if (attrsSet.find("subdiv_pixel_error") == attrsEnd) { plug = FindMayaPlug("subdiv_pixel_error"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivPixelError"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_pixel_error", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "subdiv_pixel_error", plug.asFloat()); } } if (attrsSet.find("subdiv_dicing_camera") == attrsEnd) { plug = FindMayaPlug("subdiv_dicing_camera"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivDicingCamera"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_dicing_camera", atNode, "constant NODE")) { AtNode *cameraNode = NULL; MPlugArray plugs; plug.connectedTo(plugs, true, false); if (plugs.length() == 1) { MFnDagNode camDag(plugs[0].node()); MDagPath camPath; if (camDag.getPath(camPath) == MS::kSuccess) { cameraNode = ExportDagPath(camPath); } } AiNodeSetPtr(atNode, "subdiv_dicing_camera", cameraNode); } } if (attrsSet.find("subdiv_uv_smoothing") == attrsEnd) { plug = FindMayaPlug("subdiv_uv_smoothing"); if (plug.isNull()) { plug = FindMayaPlug("aiSubdivUvSmoothing"); } if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_uv_smoothing", atNode, "constant INT")) { AiNodeSetInt(atNode, "subdiv_uv_smoothing", plug.asInt()); } } if (attrsSet.find("subdiv_smooth_derivs") == attrsEnd) { plug = FindMayaPlug("aiSubdivSmoothDerivs"); if (!plug.isNull() && HasParameter(anodeEntry, "subdiv_smooth_derivs", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "subdiv_smooth_derivs", plug.asBool()); } } if (attrsSet.find("smoothing") == attrsEnd) { // Use maya shape built-in attribute plug = FindMayaPlug("smoothShading"); if (!plug.isNull() && HasParameter(anodeEntry, "smoothing", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "smoothing", plug.asBool()); } } if (attrsSet.find("disp_height") == attrsEnd) { plug = FindMayaPlug("aiDispHeight"); if (!plug.isNull()) { outputDispHeight = true; dispHeight = plug.asFloat(); } } if (attrsSet.find("disp_zero_value") == attrsEnd) { plug = FindMayaPlug("aiDispZeroValue"); if (!plug.isNull()) { outputDispZeroValue = true; dispZeroValue = plug.asFloat(); } } if (attrsSet.find("disp_autobump") == attrsEnd) { plug = FindMayaPlug("aiDispAutobump"); if (!plug.isNull()) { outputDispAutobump = true; dispAutobump = plug.asBool(); } } if (attrsSet.find("disp_padding") == attrsEnd) { plug = FindMayaPlug("aiDispPadding"); if (!plug.isNull()) { outputDispPadding = true; dispPadding = MAX(dispPadding, plug.asFloat()); } } // Set diplacement shader if (attrsSet.find("disp_map") == attrsEnd) { if (masterShadingEngine.object() != MObject::kNullObj) { MPlugArray shaderConns; MPlug shaderPlug = masterShadingEngine.findPlug("displacementShader"); shaderPlug.connectedTo(shaderConns, true, false); if (shaderConns.length() > 0) { MFnDependencyNode dispNode(shaderConns[0].node()); plug = dispNode.findPlug("aiDisplacementPadding"); if (!plug.isNull()) { outputDispPadding = true; dispPadding = MAX(dispPadding, plug.asFloat()); } plug = dispNode.findPlug("aiDisplacementAutoBump"); if (!plug.isNull()) { outputDispAutobump = true; dispAutobump = dispAutobump || plug.asBool(); } if (HasParameter(anodeEntry, "disp_map", atNode, "constant ARRAY NODE")) { AtNode *dispImage = ExportNode(shaderConns[0]); AiNodeSetArray(atNode, "disp_map", AiArrayConvert(1, 1, AI_TYPE_NODE, &dispImage)); } } } } if (outputDispHeight && HasParameter(anodeEntry, "disp_height", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "disp_height", dispHeight); } if (outputDispZeroValue && HasParameter(anodeEntry, "disp_zero_value", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "disp_zero_value", dispZeroValue); } if (outputDispPadding && HasParameter(anodeEntry, "disp_padding", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "disp_padding", dispPadding); } if (outputDispAutobump && HasParameter(anodeEntry, "disp_autobump", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "disp_autobump", dispAutobump); } // Old point based SSS parameter if (attrsSet.find("sss_sample_distribution") == attrsEnd) { plug = FindMayaPlug("sss_sample_distribution"); if (plug.isNull()) { plug = FindMayaPlug("aiSssSampleDistribution"); } if (!plug.isNull() && HasParameter(anodeEntry, "sss_sample_distribution", atNode, "constant INT")) { AiNodeSetInt(atNode, "sss_sample_distribution", plug.asInt()); } } // Old point based SSS parameter if (attrsSet.find("sss_sample_spacing") == attrsEnd) { plug = FindMayaPlug("sss_sample_spacing"); if (plug.isNull()) { plug = FindMayaPlug("aiSssSampleSpacing"); } if (!plug.isNull() && HasParameter(anodeEntry, "sss_sample_spacing", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "sss_sample_spacing", plug.asFloat()); } } if (attrsSet.find("min_pixel_width") == attrsEnd) { plug = FindMayaPlug("aiMinPixelWidth"); if (!plug.isNull() && HasParameter(anodeEntry, "min_pixel_width", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "min_pixel_width", plug.asFloat()); } } if (attrsSet.find("mode") == attrsEnd) { plug = FindMayaPlug("aiMode"); if (!plug.isNull() && HasParameter(anodeEntry, "mode", atNode, "constant INT")) { AiNodeSetInt(atNode, "mode", plug.asShort()); } } if (attrsSet.find("basis") == attrsEnd) { plug = FindMayaPlug("aiBasis"); if (!plug.isNull() && HasParameter(anodeEntry, "basis", atNode, "constant INT")) { AiNodeSetInt(atNode, "basis", plug.asShort()); } } } if (AiNodeIs(atNode, "ginstance")) { if (attrsSet.find("node") == attrsEnd) { AiNodeSetPtr(atNode, "node", m_masterNode); } if (attrsSet.find("inherit_xform") == attrsEnd) { AiNodeSetBool(atNode, "inherit_xform", false); } } else { // box or procedural if (attrsSet.find("step_size") == attrsEnd) { plug = FindMayaPlug("step_size"); if (plug.isNull()) { plug = FindMayaPlug("aiStepSize"); } if (!plug.isNull() && HasParameter(anodeEntry, "step_size", atNode, "constant FLOAT")) { AiNodeSetFlt(atNode, "step_size", plug.asFloat()); } } } if (attrsSet.find("sidedness") == attrsEnd) { // Use maya shape built-in attribute plug = FindMayaPlug("doubleSided"); if (!plug.isNull() && HasParameter(anodeEntry, "sidedness", atNode, "constant BYTE")) { AiNodeSetByte(atNode, "sidedness", plug.asBool() ? AI_RAY_ALL : 0); // Only set invert_normals if doubleSided attribute could be found if (!plug.asBool() && attrsSet.find("invert_normals") == attrsEnd) { // Use maya shape built-in attribute plug = FindMayaPlug("opposite"); if (!plug.isNull() && HasParameter(anodeEntry, "invert_normals", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "invert_normals", plug.asBool()); } } } } if (attrsSet.find("receive_shadows") == attrsEnd) { // Use maya shape built-in attribute plug = FindMayaPlug("receiveShadows"); if (!plug.isNull() && HasParameter(anodeEntry, "receive_shadows", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "receive_shadows", plug.asBool()); } } if (attrsSet.find("self_shadows") == attrsEnd) { plug = FindMayaPlug("self_shadows"); if (plug.isNull()) { plug = FindMayaPlug("aiSelfShadows"); } if (!plug.isNull() && HasParameter(anodeEntry, "self_shadows", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "self_shadows", plug.asBool()); } } if (attrsSet.find("opaque") == attrsEnd) { plug = FindMayaPlug("opaque"); if (plug.isNull()) { plug = FindMayaPlug("aiOpaque"); } if (!plug.isNull() && HasParameter(anodeEntry, "opaque", atNode, "constant BOOL")) { AiNodeSetBool(atNode, "opaque", plug.asBool()); } } if (attrsSet.find("visibility") == attrsEnd) { if (HasParameter(anodeEntry, "visibility", atNode, "constant BYTE")) { int visibility = AI_RAY_ALL; // Use maya shape built-in attribute plug = FindMayaPlug("castsShadows"); if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_SHADOW; } // Use maya shape built-in attribute plug = FindMayaPlug("primaryVisibility"); if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_CAMERA; } // Use maya shape built-in attribute plug = FindMayaPlug("visibleInReflections"); if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_REFLECTED; } // Use maya shape built-in attribute plug = FindMayaPlug("visibleInRefractions"); if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_REFRACTED; } plug = FindMayaPlug("diffuse_visibility"); if (plug.isNull()) { plug = FindMayaPlug("aiVisibleInDiffuse"); } if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_DIFFUSE; } plug = FindMayaPlug("glossy_visibility"); if (plug.isNull()) { plug = FindMayaPlug("aiVisibleInGlossy"); } if (!plug.isNull() && !plug.asBool()) { visibility &= ~AI_RAY_GLOSSY; } AiNodeSetByte(atNode, "visibility", visibility & 0xFF); } } if (attrsSet.find("sss_setname") == attrsEnd) { plug = FindMayaPlug("aiSssSetname"); if (!plug.isNull() && plug.asString().length() > 0) { if (HasParameter(anodeEntry, "sss_setname", atNode, "constant STRING")) { AiNodeSetStr(atNode, "sss_setname", plug.asString().asChar()); } } } // Set surface shader if (HasParameter(anodeEntry, "shader", atNode, "constant NODE")) { if (attrsSet.find("shader") == attrsEnd) { if (shadingEngine.object() != MObject::kNullObj) { AtNode *shader = ExportNode(shadingEngine.findPlug("message")); if (shader != NULL) { const AtNodeEntry *entry = AiNodeGetNodeEntry(shader); if (AiNodeEntryGetType(entry) != AI_NODE_SHADER) { MGlobal::displayWarning("[mtoaScriptedTranslators] Node generated from \"" + shadingEngine.name() + "\" of type " + shadingEngine.typeName() + " for shader is not a shader but a " + MString(AiNodeEntryGetTypeName(entry))); } else { AiNodeSetPtr(atNode, "shader", shader); if (AiNodeLookUpUserParameter(atNode, "mtoa_shading_groups") == 0) { AiNodeDeclare(atNode, "mtoa_shading_groups", "constant ARRAY NODE"); AiNodeSetArray(atNode, "mtoa_shading_groups", AiArrayConvert(1, 1, AI_TYPE_NODE, &shader)); } } } } } } } ExportLightLinking(atNode); MPlug plug = FindMayaPlug("aiTraceSets"); if (!plug.isNull()) { ExportTraceSets(atNode, plug); } // Call cleanup command on last export step if (!IsMotionBlurEnabled() || !IsLocalMotionBlurEnabled() || int(step) >= (int(GetNumMotionSteps()) - 1)) { if (HasParameter(anodeEntry, "disp_padding", atNode)) { float padding = AiNodeGetFlt(atNode, "disp_padding"); AtPoint cmin = AiNodeGetPnt(atNode, "min"); AtPoint cmax = AiNodeGetPnt(atNode, "max"); cmin.x -= padding; cmin.y -= padding; cmin.z -= padding; cmax.x += padding; cmax.y += padding; cmax.z += padding; AiNodeSetPnt(atNode, "min", cmin.x, cmin.y, cmin.z); AiNodeSetPnt(atNode, "max", cmax.x, cmax.y, cmax.z); } if (cleanupCmd != "") { command = cleanupCmd += "((\"" + m_dagPath.partialPathName() + "\", \""; command += AiNodeGetName(atNode); command += "\"), "; if (!m_masterNode) { command += "None)"; } else { command += "(\"" + GetMasterInstance().partialPathName() + "\", \""; command += AiNodeGetName(m_masterNode); command += "\"))"; } status = MGlobal::executePythonCommand(command); if (!status) { AiMsgError("[mtoa.scriptedTranslators] Failed to cleanup node \"%s\".", node.name().asChar()); } } } }
virtual void ExportProcedural( AtNode *node ) { // do basic node export ExportMatrix( node, 0 ); // AiNodeSetPtr( node, "shader", arnoldShader(node) ); AiNodeSetInt( node, "visibility", ComputeVisibility() ); MPlug plug = FindMayaObjectPlug( "receiveShadows" ); if( !plug.isNull() ) { AiNodeSetBool( node, "receive_shadows", plug.asBool() ); } plug = FindMayaObjectPlug( "aiSelfShadows" ); if( !plug.isNull() ) { AiNodeSetBool( node, "self_shadows", plug.asBool() ); } plug = FindMayaObjectPlug( "aiOpaque" ); if( !plug.isNull() ) { AiNodeSetBool( node, "opaque", plug.asBool() ); } // now set the procedural-specific parameters AiNodeSetBool( node, "load_at_init", true ); // just for now so that it can load the shaders at the right time MFnDagNode fnDagNode( m_dagPath ); MBoundingBox bound = fnDagNode.boundingBox(); AiNodeSetPnt( node, "min", bound.min().x-m_dispPadding, bound.min().y-m_dispPadding, bound.min().z-m_dispPadding ); AiNodeSetPnt( node, "max", bound.max().x+m_dispPadding, bound.max().y, bound.max().z+m_dispPadding ); const char *dsoPath = getenv( "ALEMBIC_ARNOLD_PROCEDURAL_PATH" ); AiNodeSetStr( node, "dso", dsoPath ? dsoPath : "bb_AlembicArnoldProcedural.so" ); // Set the parameters for the procedural //abcFile path MString abcFile = fnDagNode.findPlug("cacheFileName").asString().expandEnvironmentVariablesAndTilde(); //object path MString objectPath = fnDagNode.findPlug("cacheGeomPath").asString(); //object pattern MString objectPattern = "*"; plug = FindMayaObjectPlug( "objectPattern" ); if (!plug.isNull() ) { if (plug.asString() != "") { objectPattern = plug.asString(); } } //object pattern MString excludePattern = ""; plug = FindMayaObjectPlug( "excludePattern" ); if (!plug.isNull() ) { if (plug.asString() != "") { excludePattern = plug.asString(); } } float shutterOpen = 0.0; plug = FindMayaObjectPlug( "shutterOpen" ); if (!plug.isNull() ) { shutterOpen = plug.asFloat(); } float shutterClose = 0.0; plug = FindMayaObjectPlug( "shutterClose" ); if (!plug.isNull() ) { shutterClose = plug.asFloat(); } float timeOffset = 0.0; plug = FindMayaObjectPlug( "timeOffset" ); if (!plug.isNull() ) { timeOffset = plug.asFloat(); } int subDIterations = 0; plug = FindMayaObjectPlug( "ai_subDIterations" ); if (!plug.isNull() ) { subDIterations = plug.asInt(); } MString nameprefix = ""; plug = FindMayaObjectPlug( "namePrefix" ); if (!plug.isNull() ) { nameprefix = plug.asString(); } // bool exportFaceIds = fnDagNode.findPlug("exportFaceIds").asBool(); bool makeInstance = true; // always on for now plug = FindMayaObjectPlug( "makeInstance" ); if (!plug.isNull() ) { makeInstance = plug.asBool(); } bool flipv = false; plug = FindMayaObjectPlug( "flipv" ); if (!plug.isNull() ) { flipv = plug.asBool(); } bool invertNormals = false; plug = FindMayaObjectPlug( "invertNormals" ); if (!plug.isNull() ) { invertNormals = plug.asBool(); } short i_subDUVSmoothing = 1; plug = FindMayaObjectPlug( "ai_subDUVSmoothing" ); if (!plug.isNull() ) { i_subDUVSmoothing = plug.asShort(); } MString subDUVSmoothing; switch (i_subDUVSmoothing) { case 0: subDUVSmoothing = "pin_corners"; break; case 1: subDUVSmoothing = "pin_borders"; break; case 2: subDUVSmoothing = "linear"; break; case 3: subDUVSmoothing = "smooth"; break; default : subDUVSmoothing = "pin_corners"; break; } MTime curTime = MAnimControl::currentTime(); // fnDagNode.findPlug("time").getValue( frame ); // MTime frameOffset; // fnDagNode.findPlug("timeOffset").getValue( frameOffset ); float time = curTime.as(MTime::kFilm)+timeOffset; MString argsString; if (objectPath != "|"){ argsString += "-objectpath "; // convert "|" to "/" argsString += MString(replace_all(objectPath,"|","/").c_str()); } if (objectPattern != "*"){ argsString += "-pattern "; argsString += objectPattern; } if (excludePattern != ""){ argsString += "-excludepattern "; argsString += excludePattern; } if (shutterOpen != 0.0){ argsString += " -shutteropen "; argsString += shutterOpen; } if (shutterClose != 0.0){ argsString += " -shutterclose "; argsString += shutterClose; } if (subDIterations != 0){ argsString += " -subditerations "; argsString += subDIterations; argsString += " -subduvsmoothing "; argsString += subDUVSmoothing; } if (makeInstance){ argsString += " -makeinstance "; } if (nameprefix != ""){ argsString += " -nameprefix "; argsString += nameprefix; } if (flipv){ argsString += " -flipv "; } if (invertNormals){ argsString += " -invertNormals "; } argsString += " -filename "; argsString += abcFile; argsString += " -frame "; argsString += time; if (m_displaced){ argsString += " -disp_map "; argsString += AiNodeGetName(m_dispNode); } AiNodeSetStr(node, "data", argsString.asChar()); ExportUserAttrs(node); // Export light linking per instance ExportLightLinking(node); }