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;
}
Esempio n. 3
0
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 );
}
Esempio n. 6
0
Imath::Box3d convert( const MBoundingBox &from )
{
	return Imath::Box3d( convert<V3d>( from.min() ), convert<V3d>( from.max() ) );
}
Esempio n. 7
0
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 );
						}
					}
				}
			}
		}
	}
}
Esempio n. 8
0
	// 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;
	}
Esempio n. 9
0
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;
}
Esempio n. 10
0
		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);

                }