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