Exemple #1
0
//-*****************************************************************************
void ReadParticles( const std::string &iFileName )
{
    IArchive archive( Alembic::AbcCoreOgawa::ReadArchive(),
                      iFileName );
    IObject topObj( archive, kTop );

    IPoints points( topObj, "simpleParticles" );
    IPointsSchema& pointsSchema = points.getSchema();

    index_t numSamps = pointsSchema.getNumSamples();
    std::cout << "\n\nReading points back in. Num frames: "
              << numSamps << std::endl;

    IV3fArrayProperty velProp( pointsSchema, "velocity" );
    IC3fArrayProperty rgbProp( pointsSchema, "Cs" );
    IFloatArrayProperty ageProp( pointsSchema, "age" );

    for ( index_t samp = 0; samp < numSamps; ++samp )
    {
        IPointsSchema::Sample psamp;
        pointsSchema.get( psamp, samp );

        Box3f bounds;
        bounds.makeEmpty();
        size_t numPoints = psamp.getPositions()->size();
        for ( size_t p = 0; p < numPoints; ++p )
        {
            bounds.extendBy( (*(psamp.getPositions()))[p] );
        }
        std::cout << "Sample: " << samp << ", numPoints: " << numPoints
                  << ", bounds: " << bounds.min
                  << " to " << bounds.max << std::endl;
    }
}
Exemple #2
0
Imath::Box3f SceneNode::unionOfTransformedChildBounds( const ScenePath &path, const ScenePlug *out, const IECore::InternedStringVectorData *childNamesData ) const
{
	ConstInternedStringVectorDataPtr computedChildNames;
	if( !childNamesData )
	{
		computedChildNames = out->childNames( path );
		childNamesData = computedChildNames.get();
	}
	const vector<InternedString> &childNames = childNamesData->readable();

	Box3f result;
	if( childNames.size() )
	{
		ContextPtr tmpContext = new Context( *Context::current(), Context::Borrowed );
		Context::Scope scopedContext( tmpContext.get() );

		ScenePath childPath( path );
		childPath.push_back( InternedString() ); // room for the child name
		for( vector<InternedString>::const_iterator it = childNames.begin(); it != childNames.end(); it++ )
		{
			childPath[path.size()] = *it;
			tmpContext->set( ScenePlug::scenePathContextName, childPath );
			Box3f childBound = out->boundPlug()->getValue();
			childBound = transform( childBound, out->transformPlug()->getValue() );
			result.extendBy( childBound );
		}
	}
	return result;
}
void BackdropNodeGadget::frame( const std::vector<Gaffer::Node *> &nodes )
{
	GraphGadget *graph = ancestor<GraphGadget>();
	if( !graph )
	{
		return;
	}
	
	Box3f b;
	for( std::vector<Node *>::const_iterator it = nodes.begin(), eIt = nodes.end(); it != eIt; ++it )
	{
		NodeGadget *nodeGadget = graph->nodeGadget( *it );
		if( nodeGadget )
		{
			b.extendBy( nodeGadget->transformedBound( NULL ) );
		}
	}
	
	if( b.isEmpty() )
	{
		return;
	}
	
	graph->setNodePosition( node(), V2f( b.center().x, b.center().y ) );
	
	V2f s( b.size().x / 2.0f, b.size().y / 2.0f );
	
	boundPlug()->setValue(
		Box2f( 
			V2f( -s ) - V2f( g_margin ),
			V2f( s ) + V2f( g_margin + 2.0f * g_margin )
		)
	);
}
Exemple #4
0
Imath::Box3f Instancer::computeBranchBound( const ScenePath &parentPath, const ScenePath &branchPath, const Gaffer::Context *context ) const
{
	ContextPtr ic = instanceContext( context, branchPath );
	if( ic )
	{
		Context::Scope scopedContext( ic );
		return instancePlug()->boundPlug()->getValue();
	}
	
	// branchPath == "/"
	
	Box3f result;
	ConstV3fVectorDataPtr p = sourcePoints( parentPath );
	if( p )
	{
		ScenePath branchChildPath( branchPath );
		branchChildPath.push_back( InternedString() ); // where we'll place the instance index
		for( size_t i=0; i<p->readable().size(); i++ )
		{
			/// \todo We could have a very fast InternedString( int ) constructor rather than all this lexical cast nonsense
			branchChildPath[branchChildPath.size()-1] = boost::lexical_cast<string>( i );
			Box3f branchChildBound = computeBranchBound( parentPath, branchChildPath, context );
			branchChildBound = transform( branchChildBound, computeBranchTransform( parentPath, branchChildPath, context ) );
			result.extendBy( branchChildBound );			
		}
	}

	return result;
}
Exemple #5
0
Imath::Box3f Group::computeBound( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent ) const
{
	std::string groupName = namePlug()->getValue();

	if( path.size() <= 1 )
	{
		// either / or /groupName
		Box3f combinedBound;
		for( ScenePlugIterator it( inPlugs() ); it != it.end(); ++it )
		{
			// we don't need to transform these bounds, because the SceneNode
			// guarantees that the transform for root nodes is always identity.
			Box3f bound = (*it)->bound( ScenePath() );
			combinedBound.extendBy( bound );
		}
		if( path.size() == 0 )
		{
			combinedBound = transform( combinedBound, transformPlug()->matrix() );
		}
		return combinedBound;
	}
	else
	{
		const ScenePlug *sourcePlug = 0;
		ScenePath source = sourcePath( path, groupName, &sourcePlug );
		return sourcePlug->bound( source );
	}
}
Exemple #6
0
Imath::Box3f SceneProcedural::bound() const
{
	/// \todo I think we should be able to remove this exception handling in the future.
	/// Either when we do better error handling in ValuePlug computations, or when 
	/// the bug in IECoreGL that caused the crashes in SceneProceduralTest.testComputationErrors
	/// is fixed.
	try
	{
		ContextPtr timeContext = new Context( *m_context );
		Context::Scope scopedTimeContext( timeContext );
		
		/// \todo This doesn't take account of the unfortunate fact that our children may have differing
		/// numbers of segments than ourselves. To get an accurate bound we would need to know the different sample
		/// times the children may be using and evaluate a bound at those times as well. We don't want to visit
		/// the children to find the sample times out though, because that defeats the entire point of deferred loading.
		///
		/// Here are some possible approaches :
		///
		/// 1) Add a new attribute called boundSegments, which defines the number of segments used to calculate
		///    the bounding box. It would be the responsibility of the user to set this to an appropriate value
		///    at the parent levels, so that the parents calculate bounds appropriate for the children.
		///    This seems like a bit too much burden on the user.
		///
		/// 2) Add a global option called "maxSegments" - this will clamp the number of segments used on anything
		///    and will be set to 1 by default. The user will need to increase it to allow the leaf level attributes
		///    to take effect, and all bounding boxes everywhere will be calculated using that number of segments
		///    (actually I think it'll be that number of segments and all nondivisible smaller numbers). This should
		///    be accurate but potentially slower, because we'll be doing the extra work everywhere rather than only
		///    where needed. It still places a burden on the user (increasing the global clamp appropriately),
		///    but not quite such a bad one as they don't have to figure anything out and only have one number to set.
		///
		/// 3) Have the StandardOptions node secretly compute a global "maxSegments" behind the scenes. This would
		///    work as for 2) but remove the burden from the user. However, it would mean preventing any expressions
		///    or connections being used on the segments attributes, because they could be used to cheat the system.
		///    It could potentially be faster than 2) because it wouldn't have to do all nondivisible numbers - it
		///    could know exactly which numbers of segments were in existence. It still suffers from the
		///    "pay the price everywhere" problem.	
				
		std::set<float> times;
		motionTimes( ( m_options.deformationBlur && m_attributes.deformationBlur ) ? m_attributes.deformationBlurSegments : 0, times );
		motionTimes( ( m_options.transformBlur && m_attributes.transformBlur ) ? m_attributes.transformBlurSegments : 0, times );
				
		Box3f result;
		for( std::set<float>::const_iterator it = times.begin(), eIt = times.end(); it != eIt; it++ )
		{
			timeContext->setFrame( *it );
			Box3f b = m_scenePlug->boundPlug()->getValue();
			M44f t = m_scenePlug->transformPlug()->getValue();
			result.extendBy( transform( b, t ) );
		}
		
		return result;
	}
	catch( const std::exception &e )
	{
		IECore::msg( IECore::Msg::Error, "SceneProcedural::bound()", e.what() );
	}
	return Box3f();
}
static Box3fDataPtr bound3( const P *pData, const R *rData, float rMult, typename V::ConstPtr vData, float vMult )
{
	typedef typename P::ValueType::value_type Point;
	typedef typename V::ValueType::value_type Vector;
	typedef typename R::ValueType::value_type Radius;

	Box3f result;
	const typename P::ValueType &pVector = pData->readable();

	size_t vLength = 0;
	const Vector *v = 0;
	if( vData && vData->readable().size() )
	{
		vLength = vData->readable().size();
		v = &(vData->readable()[0]);
	}

	size_t rLength = 0;
	const Radius *r = 0;
	if( rData && rData->readable().size() )
	{
		rLength = rData->readable().size();
		r = &(rData->readable()[0]);
	}

	size_t i = 0;
	for( typename P::ValueType::const_iterator pIt = pVector.begin(); pIt!=pVector.end(); pIt++ )
	{
		Box3f b;
		b.extendBy( *pIt );
		if( v && i<vLength )
		{
			b.extendBy( *pIt + v[i] * vMult );
		}
		if( r && i<rLength )
		{
			Point rr( r[i] * rMult );
			b.min -= rr;
			b.max += rr;

		}
		result.extendBy( b );
		i++;
	}
	return new Box3fData( result );
}
Imath::Box3f StandardConnectionGadget::bound() const
{
	const_cast<StandardConnectionGadget *>( this )->setPositionsFromNodules();
	Box3f r;
	r.extendBy( m_srcPos );
	r.extendBy( m_dstPos );
	return r;
}
void SimpleSubsurface::buildWalk( Tree::NodeIndex nodeIndex )
{
	const Tree::Node &node = m_privateData->tree.node( nodeIndex );
		
	if( node.isLeaf() )
	{
		float totalWeight = 0;
		Color3f nodeColor( 0 );
		V3f centroid( 0 );
		Box3f bound;
		vector<V3f>::const_iterator pointsBegin =  m_privateData->points->readable().begin();
		for( Tree::Iterator *p = node.permFirst(); p!=node.permLast(); p++ )
		{
			const Color3f &c =  m_privateData->colors->readable()[*p - pointsBegin];
			float weight = luminance( c );
			nodeColor += c;
			centroid += **p * weight;
			totalWeight += weight;
			bound.extendBy( **p );
		}
		
		m_privateData->nodeCentroids[nodeIndex] = centroid / ( totalWeight > 0.0f ? totalWeight : 1.0f );
		m_privateData->nodeColors[nodeIndex] = nodeColor;
		m_privateData->nodeBounds[nodeIndex] = bound;
	}
	else
	{
		Tree::NodeIndex lowIndex =  m_privateData->tree.lowChildIndex( nodeIndex );
		Tree::NodeIndex highIndex =  m_privateData->tree.highChildIndex( nodeIndex );
		buildWalk( lowIndex );
		buildWalk( highIndex );
		
		Box3f bound;
		bound.extendBy( m_privateData->nodeBounds[lowIndex] );
		bound.extendBy( m_privateData->nodeBounds[highIndex] );
		m_privateData->nodeBounds[nodeIndex] = bound;
		
		float wLow = luminance( m_privateData->nodeColors[lowIndex] );
		float wHigh = luminance( m_privateData->nodeColors[highIndex] );
		float wSum = wLow + wHigh;
		m_privateData->nodeCentroids[nodeIndex] = ( wLow * m_privateData->nodeCentroids[lowIndex] + wHigh * m_privateData->nodeCentroids[highIndex] ) / ( wSum > 0.0f ? wSum : 1.0f );
		
		m_privateData->nodeColors[nodeIndex] = m_privateData->nodeColors[lowIndex] + m_privateData->nodeColors[highIndex];
	}
}
Exemple #10
0
Imath::Box3f Group::bound() const
{
	Box3f result;
	for( ChildContainer::const_iterator it=children().begin(); it!=children().end(); it++ )
	{
		result.extendBy( (*it)->bound() );
	}
	return transform( result, m_transform );
}
void IECoreArnold::RendererImplementation::procedural( IECore::Renderer::ProceduralPtr proc )
{
	Box3f bound = proc->bound();
	if( bound.isEmpty() )
	{
		return;
	}

	AtNode *procedural = AiNode( "procedural" );

	if( ExternalProcedural *externalProc = dynamic_cast<ExternalProcedural *>( proc.get() ) )
	{
		AiNodeSetStr( procedural, "dso", externalProc->fileName().c_str() );
		ParameterAlgo::setParameters( procedural, externalProc->parameters() );
		applyTransformToNode( procedural );
	}
	else
	{

		// we have to transform the bound, as we're not applying the current transform to the
		// procedural node, but instead applying absolute transforms to the shapes the procedural
		// generates.
		if( bound != Procedural::noBound )
		{
			Box3f transformedBound;
			for( size_t i = 0, e = m_transformStack.numSamples(); i < e; ++i )
			{
				transformedBound.extendBy( transform( bound, m_transformStack.sample( i ) ) );
			}
			bound = transformedBound;
		}

		AiNodeSetPtr( procedural, "funcptr", (void *)procLoader );

		ProceduralData *data = new ProceduralData;
		data->procedural = proc;
		data->renderer = new IECoreArnold::Renderer( new RendererImplementation( *this ) );

		AiNodeSetPtr( procedural, "userptr", data );
	}

	if( bound != Procedural::noBound )
	{
		AiNodeSetPnt( procedural, "min", bound.min.x, bound.min.y, bound.min.z );
		AiNodeSetPnt( procedural, "max", bound.max.x, bound.max.y, bound.max.z );
	}
	else
	{
		// No bound available - expand procedural immediately.
		AiNodeSetBool( procedural, "load_at_init", true );
	}

	// we call addNode() rather than addShape() as we don't want to apply transforms and
	// shaders and attributes to procedurals. if we do, they override the things we set
	// on the nodes generated by the procedurals, which is frankly useless.
	addNode( procedural );
}
        void run() {
            PackageManagerPtr myPackageManager( new PackageManager );
            ScenePtr myScene = Scene::createStubs(myPackageManager);

            dom::NodePtr myMaterial = createColorMaterial(myScene, Vector4f(0.8f,0.8f,0.6f,1.0f));

            Box3f myVoxelBox;
            myVoxelBox.makeEmpty();
            myVoxelBox.extendBy( Point3f(0.0f, 0.0f, 0.0f));
            //myVoxelBox.extendBy( Point3f(10.0, 20.0, 30.0f)); // 10x20x30 voxels
            myVoxelBox.extendBy( Point3f(1.0f, 1.0f, 1.0f)); // 1x2x4 voxels
            Vector3i myVolumeSize(10, 10, 10);
            Matrix4f myModelMatrix;
            Matrix4f myCameraMatrix;
            float mySampleRate = 1.0f;

            VectorOfVector3f myReference;
            VectorOfVector3f myCandidate;

            myModelMatrix.makeIdentity();
            myCameraMatrix.makeIdentity();
            dom::NodePtr myShape = createVoxelProxyGeometry(myScene, myVoxelBox,
                    myModelMatrix, myCameraMatrix, myVolumeSize, mySampleRate,
                    myMaterial->getAttributeString(ID_ATTRIB), "VoxelProxy");
            ENSURE(extractPositions(myShape, myReference));
            myCameraMatrix.makeXRotating( static_cast<float>(asl::PI/2) );
            myShape = createVoxelProxyGeometry(myScene, myVoxelBox, myModelMatrix, myCameraMatrix,
                    myVolumeSize, mySampleRate, myMaterial->getAttributeString(ID_ATTRIB),
                    "VoxelProxy");
            ENSURE(extractPositions(myShape, myCandidate));

            //ENSURE(positionsEqual(myCandidate, myReference, myCameraMatrixf));
            //myModelViewMatrix.rotateY(asl::PI * 0.125);

            //DPRINT( * myShape );

            //dom::NodePtr myBody = createBody(myScene->getWorldRoot(), myShape->getAttributeString(ID_ATTRIBf));
            //myScene->save("proxy.x60", false);
        }
Exemple #13
0
Imath::Box3f computeBounds(const float* vertices, size_t numVertices)
{
	using namespace Imath;
	Box3f bounds;
	bounds.makeEmpty();
	V3f vertex;
	for(size_t v=0; v < numVertices; ++v)
	{
		vertex.x = vertices[3 * v + 0];
		vertex.y = vertices[3 * v + 1];
		vertex.z = vertices[3 * v + 2];
		bounds.extendBy(vertex);
	}
	return bounds;
}
Exemple #14
0
		Box3f selectionBound() const
		{
			if( m_selected )
			{
				return m_bound;
			}
			else
			{
				Box3f childSelectionBound;
				for( std::vector<SceneGraph *>::const_iterator it = m_children.begin(), eIt = m_children.end(); it != eIt; ++it )
				{
					const Box3f childBound = transform( (*it)->selectionBound(), (*it)->m_transform );
					childSelectionBound.extendBy( childBound );
				}
				return childSelectionBound;
			}
		}
Exemple #15
0
Imath::Box3f Gadget::bound() const
{
	Box3f result;
	for( ChildContainer::const_iterator it=children().begin(); it!=children().end(); it++ )
	{
		// cast is safe because of the guarantees acceptsChild() gives us
		const Gadget *c = static_cast<const Gadget *>( it->get() );
		if( !c->getVisible() )
		{
			continue;
		}
		Imath::Box3f b = c->bound();
		b = Imath::transform( b, c->getTransform() );
		result.extendBy( b );
	}
	return result;
}
Exemple #16
0
Imath::Box3f Primitive::bound() const
{
    Box3f result;
    PrimitiveVariableMap::const_iterator it = variables.find( "P" );
    if( it!=variables.end() )
    {
        ConstV3fVectorDataPtr p = runTimeCast<const V3fVectorData>( it->second.data );
        if( p )
        {
            const vector<V3f> &pp = p->readable();
            for( size_t i=0; i<pp.size(); i++ )
            {
                result.extendBy( pp[i] );
            }
        }
    }
    return result;
}
Exemple #17
0
bool Line::intersect( float angle, const Box3f& box ) const
{
	if (box.isEmpty())		return false;

	const Vec3f	&max = box.getMax(), &min = box.getMin();
	float		fuzz = 0.0;
	int			i;

	if (angle < 0.0)
	{
		fuzz = - angle;
	}
	else 
	{
		// Find the farthest point on the bounding box (where the pick
		// cone will be largest).  The amount of fuzz at this point will
		// be the minimum we can use.  Expand the box by that amount and
		// do an intersection.
		double tanA = tan(angle);
		for(i = 0; i < 8; i++) 
		{
			Vec3f point(i & 01 ? min[0] : max[0],
				  i & 02 ? min[1] : max[1],
				  i & 04 ? min[2] : max[2]);
			// how far is point from line origin??
			Vec3f	diff(point - getPosition());
			double	thisFuzz = sqrt(diff.dot(diff)) * tanA;

			if (thisFuzz > fuzz)
				fuzz = float(thisFuzz);
		}
	}

	Box3f fuzzBox = box;

	fuzzBox.extendBy(Vec3f(min[0] - fuzz, min[1] - fuzz, min[2] - fuzz));
	fuzzBox.extendBy(Vec3f(max[0] + fuzz, max[1] + fuzz, max[2] + fuzz));

	Vec3f scratch1, scratch2;
	return intersect(fuzzBox, scratch1, scratch2);
}
Exemple #18
0
Imath::Box3f SplinePlugGadget::bound() const
{
	Box3f result;
	
	for( size_t i = 0, e = m_splines->size(); i < e ; i++ )
	{
		SplineffPlugPtr spline = IECore::runTimeCast<SplineffPlug>( m_splines->member( i ) );
		if( spline )
		{
			unsigned n = spline->numPoints();
			for( unsigned i=0; i<n; i++ )
			{
				V3f p( 0 );
				p.x = spline->pointXPlug( i )->getValue();
				p.y = spline->pointYPlug( i )->getValue();
				result.extendBy( p );
			}
		}
	}
	return result;
}
Exemple #19
0
Imath::Box3f BranchCreator::computeBound( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent ) const
{
	ConstCompoundDataPtr mapping = staticPointerCast<const CompoundData>( mappingPlug()->getValue() );
	ScenePath parentPath, branchPath;
	Filter::Result parentMatch = parentAndBranchPaths( mapping, path, parentPath, branchPath );

	if( parentMatch == Filter::AncestorMatch )
	{
		return computeBranchBound( parentPath, branchPath, context );
	}
	else if( parentMatch == Filter::ExactMatch || parentMatch == Filter::DescendantMatch )
	{
		Box3f result = inPlug()->boundPlug()->getValue();
		result.extendBy( unionOfTransformedChildBounds( path, outPlug() ) );
		return result;
	}
	else
	{
		return inPlug()->boundPlug()->getValue();
	}
}
Exemple #20
0
Imath::Box3f RenderableGadget::selectionBound( IECoreGL::Group *group ) const
{
	IECoreGL::State *state = group->getState();
	IECoreGL::NameStateComponent *nameState = state->get<IECoreGL::NameStateComponent>();
	if( nameState && m_selection.find( nameState->name() ) != m_selection.end() )
	{
		return group->bound();
	}
	else
	{
		Box3f childSelectionBound;
		const IECoreGL::Group::ChildContainer &children = group->children();
		for( IECoreGL::Group::ChildContainer::const_iterator it = children.begin(), eIt = children.end(); it != eIt; it++ )
		{
			IECoreGL::Group *childGroup = IECore::runTimeCast<IECoreGL::Group>( (*it).get() );
			if( childGroup )
			{
				childSelectionBound.extendBy( selectionBound( childGroup ) );
			}
		}
		return transform( childSelectionBound, group->getTransform() );
	}
}
void CurvesPrimitiveEvaluator::buildTree()
{
	if( m_haveTree )
	{
		return;
	}
	
	TreeMutex::scoped_lock lock( m_treeMutex );
	if( m_haveTree )
	{
		// another thread may have built the tree while we waited for the mutex
		return;
	}
	
	bool linear = m_curvesPrimitive->basis() == CubicBasisf::linear();
	const std::vector<V3f> &p = static_cast<const V3fVectorData *>( m_p.data.get() )->readable();
	PrimitiveEvaluator::ResultPtr result = createResult();
	
	size_t numCurves = m_curvesPrimitive->numCurves();
	for( size_t curveIndex = 0; curveIndex<numCurves; curveIndex++ )
	{
		if( linear )
		{
			int numVertices = m_verticesPerCurve[curveIndex];
			int vertIndex = m_vertexDataOffsets[curveIndex];
			float prevV = 0.0f;
			for( int i=0; i<numVertices; i++, vertIndex++ )
			{
				float v = clamp( (float)i/(float)(numVertices-1), 0.0f, 1.0f );
				if( i!=0 )
				{
					Box3f b;
					b.extendBy( p[vertIndex-1] );
					b.extendBy( p[vertIndex] );
					m_treeBounds.push_back( b );
					m_treeLines.push_back( Line(  p[vertIndex-1], p[vertIndex], curveIndex, prevV, v ) );
				}
				prevV = v;				
			}
		}
		else
		{
			unsigned numSegments = m_curvesPrimitive->numSegments( curveIndex );
			int steps = numSegments * Line::linesPerCurveSegment();
			V3f prevP( 0 );
			float prevV = 0;
			for( int i=0; i<steps; i++ )
			{
				float v = clamp( (float)i/(float)(steps-1), 0.0f, 1.0f );
				pointAtV( curveIndex, v, result.get() );
				V3f p = result->point();
				if( i!=0 )
				{
					Box3f b;
					b.extendBy( prevP );
					b.extendBy( p );
					m_treeBounds.push_back( b );
					m_treeLines.push_back( Line( prevP, p, curveIndex, prevV, v ) );
				}

				prevP = p;
				prevV = v;
			}
		}
	}
	
	m_tree.init( m_treeBounds.begin(), m_treeBounds.end() );
	m_haveTree = true;
}
void IECoreArnold::RendererImplementation::procedural( IECore::Renderer::ProceduralPtr proc )
{
	Box3f bound = proc->bound();
	if( bound.isEmpty() )
	{
		return;
	}

	AtNode *node = NULL;
	std::string nodeType = "procedural";

	if( const ExternalProcedural *externalProc = dynamic_cast<ExternalProcedural *>( proc.get() ) )
	{
		// Allow a parameter "ai:nodeType" == "volume" to create a volume shape rather
		// than a procedural shape. Volume shapes provide "dso", "min" and "max" parameters
		// just as procedural shapes do, so the mapping is a fairly natural one.
		CompoundDataMap::const_iterator nodeTypeIt = externalProc->parameters().find( "ai:nodeType" );
		if( nodeTypeIt != externalProc->parameters().end() && nodeTypeIt->second->isInstanceOf( StringData::staticTypeId() ) )
		{
			nodeType = static_cast<const StringData *>( nodeTypeIt->second.get() )->readable();
		}
		node = AiNode( nodeType.c_str() );

		AiNodeSetStr( node, "dso", externalProc->fileName().c_str() );
		ParameterAlgo::setParameters( node, externalProc->parameters() );
		applyTransformToNode( node );
	}
	else
	{
		node = AiNode( nodeType.c_str() );

		// we have to transform the bound, as we're not applying the current transform to the
		// procedural node, but instead applying absolute transforms to the shapes the procedural
		// generates.
		if( bound != Procedural::noBound )
		{
			Box3f transformedBound;
			for( size_t i = 0, e = m_transformStack.numSamples(); i < e; ++i )
			{
				transformedBound.extendBy( transform( bound, m_transformStack.sample( i ) ) );
			}
			bound = transformedBound;
		}

		AiNodeSetPtr( node, "funcptr", (void *)procLoader );

		ProceduralData *data = new ProceduralData;
		data->procedural = proc;
		data->renderer = new IECoreArnold::Renderer( new RendererImplementation( *this ) );

		AiNodeSetPtr( node, "userptr", data );
	}

	if( bound != Procedural::noBound )
	{
		AiNodeSetPnt( node, "min", bound.min.x, bound.min.y, bound.min.z );
		AiNodeSetPnt( node, "max", bound.max.x, bound.max.y, bound.max.z );
	}
	else
	{
		// No bound available - expand procedural immediately.
		AiNodeSetBool( node, "load_at_init", true );
	}

	if( nodeType == "procedural" )
	{
		// We call addNode() rather than addShape() as we don't want to apply transforms and
		// shaders and attributes to procedurals. If we do, they override the things we set
		// on the nodes generated by the procedurals, which is frankly useless.
		addNode( node );
	}
	else
	{
		addShape( node );
	}
}
void MeshPrimitiveImplicitSurfaceOp::modifyTypedPrimitive( MeshPrimitive * typedPrimitive, const CompoundObject * operands )
{
	const float threshold = m_thresholdParameter->getNumericValue();

	bool automaticBound = static_cast<const BoolData *>( m_automaticBoundParameter->getValue() )->readable();
	Box3f bound;

	if (automaticBound)
	{
		bound.makeEmpty();

		PrimitiveVariableMap::const_iterator it = typedPrimitive->variables.find("P");

		if (it != typedPrimitive->variables.end())
		{
			const DataPtr &verticesData = it->second.data;

			/// \todo Use depatchTypedData
			if (runTimeCast<V3fVectorData>(verticesData))
			{
				ConstV3fVectorDataPtr p = runTimeCast<V3fVectorData>(verticesData);

				for ( V3fVectorData::ValueType::const_iterator it = p->readable().begin();
					it != p->readable().end(); ++it)
				{
					bound.extendBy( *it );
				}
			}
			else if (runTimeCast<V3dVectorData>(verticesData))
			{
				ConstV3dVectorDataPtr p = runTimeCast<V3dVectorData>(verticesData);

				for ( V3dVectorData::ValueType::const_iterator it = p->readable().begin();
					it != p->readable().end(); ++it)
				{
					bound.extendBy( *it );
				}
			}
			else
			{
				throw InvalidArgumentException("MeshPrimitive has no primitive variable \"P\" of type V3fVectorData/V3dVectorData in MeshPrimitiveImplicitSurfaceOp");
			}
		}
		else
		{
			throw InvalidArgumentException("MeshPrimitive has no primitive variable \"P\" in MeshPrimitiveImplicitSurfaceOp");
		}
	}
	else
	{
		bound = static_cast<const Box3fData *>( m_boundParameter->getValue() )->readable();
	}

	float boundExtend = m_boundExtendParameter->getNumericValue();
	bound.min -= V3f( boundExtend, boundExtend, boundExtend );
	bound.max += V3f( boundExtend, boundExtend, boundExtend );


	V3i resolution;
	int gridMethod = m_gridMethodParameter->getNumericValue();
	if ( gridMethod == Resolution )
	{
		resolution = static_cast<const V3iData *>( m_resolutionParameter->getValue() )->readable();
	}
	else if ( gridMethod == DivisionSize )
	{
		V3f divisionSize = static_cast<const V3fData *>( m_divisionSizeParameter->getValue() )->readable();

		resolution.x = (int)((bound.max.x - bound.min.x) / divisionSize.x);
		resolution.y = (int)((bound.max.y - bound.min.y) / divisionSize.y);
		resolution.z = (int)((bound.max.z - bound.min.z) / divisionSize.z);

	}
	else
	{
		assert( false );
	}


	resolution.x = std::max( 1, resolution.x );
	resolution.y = std::max( 1, resolution.y );
	resolution.z = std::max( 1, resolution.z );

	/// Calculate a tolerance which is half the size of the smallest grid division
	double cacheTolerance = ((bound.max.x - bound.min.x) / (double)resolution.x) / 2.0;
	cacheTolerance = std::min(cacheTolerance, ((bound.max.y - bound.min.y) / (double)resolution.y) / 2.0 );
	cacheTolerance = std::min(cacheTolerance, ((bound.max.z - bound.min.z) / (double)resolution.z) / 2.0 );

	MeshPrimitiveBuilderPtr builder = new MeshPrimitiveBuilder();

	typedef MarchingCubes< CachedImplicitSurfaceFunction< V3f, float > > Marcher ;

	MeshPrimitiveImplicitSurfaceFunctionPtr fn = new MeshPrimitiveImplicitSurfaceFunction( typedPrimitive );

	Marcher::Ptr m = new Marcher
	(
		new CachedImplicitSurfaceFunction< V3f, float >(
			fn,
			cacheTolerance
		),

		builder
	);

	m->march( Box3f( bound.min, bound.max ), resolution, threshold );
	MeshPrimitivePtr resultMesh = builder->mesh();
	typedPrimitive->variables.clear();

	typedPrimitive->setTopology(
		resultMesh->verticesPerFace(),
		resultMesh->vertexIds()
	);

	typedPrimitive->variables["P"] = PrimitiveVariable( resultMesh->variables["P"].interpolation, resultMesh->variables["P"].data->copy() );
	typedPrimitive->variables["N"] = PrimitiveVariable( resultMesh->variables["N"].interpolation, resultMesh->variables["N"].data->copy() );

}
Exemple #24
0
void XfBox3f::extendBy( const XfBox3f& bb )
{
	if ( bb.isEmpty() )
	{
		// bb is empty, no change
		return;
	}
	else if ( isEmpty() )
	{
		// we're empty, use bb
		*this = bb;
	}
	else if (	xformInv[0][0] != std::numeric_limits<float>::max() &&
				bb.xformInv[0][0] != std::numeric_limits<float>::max())
	{
		// Neither box is empty and they are in different spaces. To
		// get the best results, we'll perform the merge of the two
		// boxes in each of the two spaces. Whichever merge ends up
		// being smaller is the one we'll use.
		// Note that we don't perform a project() as part of the test.
		// This is because projecting almost always adds a little extra
		// space. It also gives an unfair advantage to the
		// box more closely aligned with world space.  In the simplest
		// case this might be preferable. However, over many objects,
		// we are better off going with the minimum in local space,
		// and not worrying about projecting until the very end.

		XfBox3f	xfbox1, xfbox2;
		Box3f		box1, box2;

		// Convert bb into this's space to get box1
		xfbox1 = bb;
		// Rather than calling transform(), which calls inverse(),
		// we'll do it ourselves, since we already know the inverse matrix.
		// I.e., we could call: xfbox1.transform(xformInv);
		xfbox1.xform *= xformInv;
		xfbox1.xformInv.multRight(xform);
		box1 = xfbox1.project();

		// Convert this into bb's space to get box2
		xfbox2 = *this;
		// Same here for: xfbox2.transform(bb.xformInv);
		xfbox2.xform *= bb.xformInv;
		xfbox2.xformInv.multRight(bb.xform);
		box2 = xfbox2.project();

		// Extend this by box1 to get xfbox1
		xfbox1 = *this;
		xfbox1.Box3f::extendBy(box1);
		// Use Box3f method; box1 is already in xfbox1's space
		// (otherwise, we'll get an infinite loop!)

		// Extend bb by box2 to get xfbox2
		xfbox2 = bb;
		xfbox2.Box3f::extendBy(box2);
		// Use Box3f method; box2 is already in xfbox2's space
		// (otherwise, we'll get an infinite loop!)

		float vol1 = xfbox1.getVolume();
		float vol2 = xfbox2.getVolume();

		// Take the smaller result and extend appropriately
		if (vol1 <= vol2) 
		{
			Box3f::extendBy(box1);
		}
		else 
		{
			*this = bb;
			Box3f::extendBy(box2);
		}
		
	}
	else if (xformInv[0][0] == std::numeric_limits<float>::max()) 
	{
		if (bb.xformInv[0][0] == std::numeric_limits<float>::max()) 
		{
			// Both boxes are degenerate; project them both and
			// combine them:
			Box3f box = this->project();
			box.extendBy(bb.project());
			*this = XfBox3f(box);
		}
		else
		{
			// this is degenerate; transform our min/max into bb's
			// space, and combine there:
			Box3f box(getMin(), getMax());
			box.transform(xform*bb.xformInv);
			*this = bb;
			Box3f::extendBy(box);
		}
	}
	else
	{
		// bb is degenerate; transform it into our space and combine:
		Box3f box(bb.getMin(), bb.getMax());
		box.transform(bb.xform*xformInv);
		Box3f::extendBy(box);
	}
}