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() );

}
Ejemplo n.º 2
0
renderer::MeshObject *convert( const IECore::Object *primitive )
{
	assert( primitive->typeId() == IECore::MeshPrimitiveTypeId );
	const IECore::MeshPrimitive *mesh = static_cast<const IECore::MeshPrimitive *>( primitive );

	const V3fVectorData *p = mesh->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
	if( !p )
	{
		throw Exception( "MeshPrimitive does not have \"P\" primitive variable of interpolation type Vertex." );
	}

	asf::auto_release_ptr<asr::MeshObject> meshEntity = asr::MeshObjectFactory::create( "mesh", asr::ParamArray() );
	const size_t materialSlot = meshEntity->push_material_slot( "default" );

	// vertices
	{
		size_t numVertices = p->readable().size();
		meshEntity->reserve_vertices( numVertices );
		const std::vector<V3f> &points = p->readable();
		for( size_t i = 0; i < numVertices; ++i )
		{
			meshEntity->push_vertex( asr::GVector3( points[i].x, points[i].y, points[i].z ) );
		}
	}

	// triangulate primitive (this should be in appleseed at some point)
	MeshPrimitivePtr triangulatedMeshPrimPtr = mesh->copy();
	{
		TriangulateOpPtr op = new TriangulateOp();
		op->inputParameter()->setValue( triangulatedMeshPrimPtr );
		op->throwExceptionsParameter()->setTypedValue( false ); // it's better to see something than nothing
		op->copyParameter()->setTypedValue( false );
		op->operate();
	}

	// triangles
	size_t numTriangles = triangulatedMeshPrimPtr->numFaces();
	std::vector<asr::Triangle> triangles;
	triangles.reserve( numTriangles );
	const std::vector<int> &vidx = triangulatedMeshPrimPtr->vertexIds()->readable();
	for( size_t i = 0; i < vidx.size(); i += 3 )
	{
		triangles.push_back( asr::Triangle( vidx[i], vidx[i+1], vidx[i+2], materialSlot ) );
	}

	// texture coords
	{
		const FloatVectorData *s = triangulatedMeshPrimPtr->variableData<FloatVectorData>( "s" );
		const FloatVectorData *t = triangulatedMeshPrimPtr->variableData<FloatVectorData>( "t" );
		if( s && t )
		{
			PrimitiveVariable::Interpolation sInterpolation = triangulatedMeshPrimPtr->variables.find( "s" )->second.interpolation;
			PrimitiveVariable::Interpolation tInterpolation = triangulatedMeshPrimPtr->variables.find( "t" )->second.interpolation;
			if( sInterpolation == tInterpolation )
			{
				if( sInterpolation == PrimitiveVariable::Varying || sInterpolation == PrimitiveVariable::Vertex || sInterpolation == PrimitiveVariable::FaceVarying )
				{
					size_t numSTs = s->readable().size();
					meshEntity->reserve_tex_coords( numSTs );
					const std::vector<float> &svec = s->readable();
					const std::vector<float> &tvec = t->readable();

					for( size_t i = 0; i < numSTs; ++i)
					{
						meshEntity->push_tex_coords( asr::GVector2( svec[i], 1.0f - tvec[i] ) );
					}

					if( sInterpolation == PrimitiveVariable::FaceVarying )
					{
						for( size_t i = 0, j = 0; i < numTriangles; ++i)
						{
							asr::Triangle& tri = triangles[i];
							tri.m_a0 = j++;
							tri.m_a1 = j++;
							tri.m_a2 = j++;
						}
					}
					else
					{
						for( size_t i = 0; i < vidx.size(); i += 3)
						{
							asr::Triangle& tri = triangles[i / 3];
							tri.m_a0 = vidx[i];
							tri.m_a1 = vidx[i+1];
							tri.m_a2 = vidx[i+2];
						}
					}
				}
				else
				{
					msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", "Variables s and t have unsupported interpolation type - not generating uvs." );
				}
			}
			else
			{
				msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", "Variables s and t have different interpolation - not generating uvs." );
			}
		}
		else if( s || t )
		{
			msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", "Only one of s and t available - not generating uvs." );
		}
	}

	// normals
	{
		PrimitiveVariableMap::const_iterator nIt = triangulatedMeshPrimPtr->variables.find( "N" );
		if( nIt != triangulatedMeshPrimPtr->variables.end() )
		{
			const V3fVectorData *n = runTimeCast<const V3fVectorData>( nIt->second.data.get() );
			if( n )
			{
				PrimitiveVariable::Interpolation nInterpolation = nIt->second.interpolation;
				if( nInterpolation == PrimitiveVariable::Varying || nInterpolation == PrimitiveVariable::Vertex || nInterpolation == PrimitiveVariable::FaceVarying )
				{
					size_t numNormals = n->readable().size();
					meshEntity->reserve_vertex_normals( numNormals );
					const std::vector<V3f> &normals = n->readable();
					for( size_t i = 0; i < numNormals; ++i)
					{
						asr::GVector3 n( normals[i].x, normals[i].y, normals[i].z );
						meshEntity->push_vertex_normal( asf::normalize( n ) );
					}

					if( nInterpolation == PrimitiveVariable::FaceVarying )
					{
						for( size_t i = 0, j = 0; i < numTriangles; ++i)
						{
							asr::Triangle& tri = triangles[i];
							tri.m_n0 = j++;
							tri.m_n1 = j++;
							tri.m_n2 = j++;
						}
					}
					else
					{
						for( size_t i = 0; i < vidx.size(); i += 3)
						{
							asr::Triangle& tri = triangles[i / 3];
							tri.m_n0 = vidx[i];
							tri.m_n1 = vidx[i+1];
							tri.m_n2 = vidx[i+2];
						}
					}
				}
				else
				{
					msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", "Variable \"N\" has unsupported interpolation type - not generating normals." );
				}
			}
			else
			{
				msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", boost::format( "Variable \"N\" has unsupported type \"%s\" (expected V3fVectorData)." ) % nIt->second.data->typeName() );
			}
		}
	}

	// tangents
	{
		PrimitiveVariableMap::const_iterator tIt = triangulatedMeshPrimPtr->variables.find( "uTangent" );
		if( tIt != triangulatedMeshPrimPtr->variables.end() )
		{
			const V3fVectorData *t = runTimeCast<const V3fVectorData>( tIt->second.data.get() );
			if( t )
			{
				PrimitiveVariable::Interpolation tInterpolation = tIt->second.interpolation;
				if( tInterpolation == PrimitiveVariable::Varying || tInterpolation == PrimitiveVariable::Vertex )
				{
					size_t numTangents = t->readable().size();
					meshEntity->reserve_vertex_tangents( numTangents );
					const std::vector<V3f> &tangents = t->readable();
					for( size_t i = 0; i < numTangents; ++i)
					{
						asr::GVector3 t( tangents[i].x, tangents[i].y, tangents[i].z );
						meshEntity->push_vertex_tangent( asf::normalize( t ) );
					}
				}
				else
				{
					msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", "Variable \"uTangent\" has unsupported interpolation type - not generating tangents." );
				}
			}
			else
			{
				msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", boost::format( "Variable \"uTangent\" has unsupported type \"%s\" (expected V3fVectorData)." ) % tIt->second.data->typeName() );
			}
		}
	}

	// copy triangles to mesh entity
	{
		meshEntity->reserve_triangles( numTriangles );

		for( size_t i = 0; i < triangles.size(); ++i)
		{
			meshEntity->push_triangle( triangles[i] );
		}
	}

	return meshEntity.release();
}