ObjectPtr FromHoudiniPolygonsConverter::doDetailConversion( const GU_Detail *geo, const CompoundObject *operands ) const { const GA_PrimitiveList &primitives = geo->getPrimitiveList(); MeshPrimitivePtr result = new MeshPrimitive(); size_t numEdges = 0; std::vector<int> vertIds; std::vector<int> vertsPerFace; GA_Offset start, end; for( GA_Iterator it( geo->getPrimitiveRange() ); it.blockAdvance( start, end ); ) { for( GA_Offset offset = start; offset < end; ++offset ) { const GA_Primitive *prim = primitives.get( offset ); if( prim->getTypeId() != GEO_PRIMPOLY ) { throw std::runtime_error( "FromHoudiniPolygonsConverter: Geometry contains non-polygon primitives" ); } size_t numPrimVerts = prim->getVertexCount(); vertsPerFace.push_back( numPrimVerts ); numEdges += numPrimVerts; std::vector<int> ids( numPrimVerts ); for( size_t j = 0; j < numPrimVerts; j++ ) { vertIds.push_back( geo->pointIndex( prim->getPointOffset( numPrimVerts - 1 - j ) ) ); } } } result->setTopology( new IntVectorData( vertsPerFace ), new IntVectorData( vertIds ) ); CompoundObjectPtr modifiedOperands = transferMeshInterpolation( geo, operands, result.get() ); if( geo->getNumVertices() ) { transferAttribs( geo, result.get(), modifiedOperands ? modifiedOperands.get() : operands ); } // check for corners and creases, which would have been extracted via transferAttribs() // as they are no different to standard attribs in Houdini. convertCorners( result.get() ); convertCreases( result.get(), vertIds, numEdges ); return result; }
PrimitivePtr FromHoudiniPolygonsConverter::doPrimitiveConversion( const GU_Detail *geo, const CompoundObject *operands ) const { const GA_PrimitiveList &primitives = geo->getPrimitiveList(); MeshPrimitivePtr result = new MeshPrimitive(); GA_Iterator firstPrim = geo->getPrimitiveRange().begin(); for ( GA_Iterator it=firstPrim; !it.atEnd(); ++it ) { const GA_Primitive *prim = primitives.get( it.getOffset() ); if ( prim->getTypeId() != GEO_PRIMPOLY ) { throw std::runtime_error( "FromHoudiniPolygonsConverter: Geometry contains non-polygon primitives" ); } } // loop over primitives gathering mesh data std::vector<int> vertIds; std::vector<int> vertsPerFace; for ( GA_Iterator it=firstPrim; !it.atEnd(); ++it ) { const GA_Primitive *prim = primitives.get( it.getOffset() ); size_t numPrimVerts = prim->getVertexCount(); vertsPerFace.push_back( numPrimVerts ); std::vector<int> ids( numPrimVerts ); for ( size_t j=0; j < numPrimVerts; j++ ) { vertIds.push_back( geo->pointIndex( prim->getPointOffset( numPrimVerts - 1 - j ) ) ); } } result->setTopology( new IntVectorData( vertsPerFace ), new IntVectorData( vertIds ) ); if ( geo->getNumVertices() ) { transferAttribs( geo, result, operands ); } return result; }
ObjectPtr BINMeshReader::doOperation( const CompoundObject *operands ) { const std::string &fileName = m_fileNameParameter->getTypedValue(); ifstream f( fileName.c_str() ); f.seekg( 0, ios_base::beg ); uint32_t magic = 0; readLittleEndian( f, magic ); uint32_t version = 0; readLittleEndian( f, version ); if ( version <= 3 ) { throw IOException(( boost::format( "BINMeshReader: '%s' is of an unsupported version" ) % fileName ).str() ); } MeshPrimitivePtr mesh = new MeshPrimitive(); uint32_t numVertices = 0; bool foundGeometryChunk = false; bool done = false; uint32_t chunkId = 0; while ( !done && !f.fail() ) { readLittleEndian( f, chunkId ); if ( f.fail() ) { throw IOException(( boost::format( "BINMeshReader: Error encountered while reading '%s'" ) % fileName ).str() ); } if ( chunkId == 0xDEDEDEDE ) /// EOF marker { if ( !foundGeometryChunk ) { throw IOException(( boost::format( "BINMeshReader: No geometry chunk encountered while reading '%s'" ) % fileName ).str() ); } done = true; } else if ( chunkId == 0xCCCCCCCC ) /// geometry chunk { if ( foundGeometryChunk ) { throw IOException(( boost::format( "BINMeshReader: Duplicate geometry chunk encountered while reading '%s'" ) % fileName ).str() ); } foundGeometryChunk = true; V3fVectorDataPtr pData = new V3fVectorData(); readLittleEndian( f, numVertices ); pData->writable().resize( numVertices ); for ( uint32_t i = 0; i < numVertices; i ++ ) { V3f p; readLittleEndian( f, p.x ); readLittleEndian( f, p.y ); readLittleEndian( f, p.z ); pData->writable()[i] = p; } uint32_t numFaces = 0; readLittleEndian( f, numFaces ); IntVectorDataPtr vertsPerFaceData = new IntVectorData(); /// All faces are triangles vertsPerFaceData->writable().resize( numFaces, 3 ); IntVectorDataPtr vertIdsData = new IntVectorData(); vertIdsData->writable().reserve( numFaces * 3 ); for ( uint32_t i = 0; i < numFaces; i ++ ) { uint32_t v0 = 0, v1 = 0, v2 = 0; readLittleEndian( f, v0 ); readLittleEndian( f, v1 ); readLittleEndian( f, v2 ); vertIdsData->writable().push_back( v0 ); vertIdsData->writable().push_back( v1 ); vertIdsData->writable().push_back( v2 ); } mesh->variables[ "P" ] = PrimitiveVariable( PrimitiveVariable::Vertex, pData ); mesh->setTopology( vertsPerFaceData, vertIdsData, "linear" ); } else if ( chunkId == 0xCCCCCC00 ) /// texture chunk { if ( !foundGeometryChunk ) { throw IOException(( boost::format( "BINMeshReader: No geometry chunk encountered while reading '%s'" ) % fileName ).str() ); } uint32_t numFluids = 0; readLittleEndian( f, numFluids ); V3fVectorDataPtr uvwData = new V3fVectorData(); uvwData->writable().resize( numVertices ); for ( uint32_t v = 0; v < numVertices; v ++ ) { for ( uint32_t fl = 0; fl < numFluids - 1; fl ++ ) { /// Just skip over there for now /// \todo Work out what to do with them float textureWeight = 0.0f; readLittleEndian( f, textureWeight ); } V3f uvw; readLittleEndian( f, uvw.x ); readLittleEndian( f, uvw.y ); readLittleEndian( f, uvw.z ); uvwData->writable()[v] = uvw; } mesh->variables[ "uvw" ] = PrimitiveVariable( PrimitiveVariable::Vertex, uvwData ); } else if ( chunkId == 0xCCCCCC11 ) /// velocity chunk { if ( !foundGeometryChunk ) { throw IOException(( boost::format( "BINMeshReader: No geometry chunk encountered while reading '%s'" ) % fileName ).str() ); } V3fVectorDataPtr velocityData = new V3fVectorData(); velocityData->writable().resize( numVertices ); for ( uint32_t i = 0; i < numVertices; i ++ ) { V3f vel; readLittleEndian( f, vel.x ); readLittleEndian( f, vel.y ); readLittleEndian( f, vel.z ); velocityData->writable()[i] = vel; } mesh->variables[ "velocity" ] = PrimitiveVariable( PrimitiveVariable::Vertex, velocityData ); } else { throw IOException(( boost::format( "BINMeshReader: Invalid chunk encountered while reading '%s'" ) % fileName ).str() ); } } if ( chunkId != 0xDEDEDEDE ) { throw IOException(( boost::format( "BINMeshReader: No end of file chunk encountered while reading '%s'" ) % fileName ).str() ); } assert( mesh ); return mesh; }
IECore::RunTimeTypedPtr ToGLMeshConverter::doConversion( IECore::ConstObjectPtr src, IECore::ConstCompoundObjectPtr operands ) const { IECore::MeshPrimitivePtr mesh = IECore::staticPointerCast<IECore::MeshPrimitive>( src->copy() ); // safe because the parameter validated it for us if( !mesh->variableData<IECore::V3fVectorData>( "P", IECore::PrimitiveVariable::Vertex ) ) { throw IECore::Exception( "Must specify primitive variable \"P\", of type V3fVectorData and interpolation type Vertex." ); } if( mesh->variables.find( "N" )==mesh->variables.end() ) { // the mesh has no normals - we need to explicitly add some. if it's a polygon // mesh (interpolation==linear) then we add per-face normals for a faceted look // and if it's a subdivision mesh we add smooth per-vertex normals. IECore::MeshNormalsOpPtr normalOp = new IECore::MeshNormalsOp(); normalOp->inputParameter()->setValue( mesh ); normalOp->copyParameter()->setTypedValue( false ); normalOp->interpolationParameter()->setNumericValue( mesh->interpolation() == "linear" ? IECore::PrimitiveVariable::Uniform : IECore::PrimitiveVariable::Vertex ); normalOp->operate(); } IECore::TriangulateOpPtr op = new IECore::TriangulateOp(); op->inputParameter()->setValue( mesh ); op->throwExceptionsParameter()->setTypedValue( false ); // it's better to see something than nothing op->copyParameter()->setTypedValue( false ); op->operate(); IECore::FaceVaryingPromotionOpPtr faceVaryingOp = new IECore::FaceVaryingPromotionOp; faceVaryingOp->inputParameter()->setValue( mesh ); faceVaryingOp->copyParameter()->setTypedValue( false ); faceVaryingOp->operate(); MeshPrimitivePtr glMesh = new MeshPrimitive( mesh->vertexIds() ); for ( IECore::PrimitiveVariableMap::iterator pIt = mesh->variables.begin(); pIt != mesh->variables.end(); ++pIt ) { if ( pIt->second.data ) { glMesh->addPrimitiveVariable( pIt->first, pIt->second ); } else { IECore::msg( IECore::Msg::Warning, "ToGLMeshConverter", boost::format( "No data given for primvar \"%s\"" ) % pIt->first ); } } IECore::PrimitiveVariableMap::const_iterator sIt = mesh->variables.find( "s" ); IECore::PrimitiveVariableMap::const_iterator tIt = mesh->variables.find( "t" ); if ( sIt != mesh->variables.end() && tIt != mesh->variables.end() ) { if ( sIt->second.interpolation != IECore::PrimitiveVariable::Constant && tIt->second.interpolation != IECore::PrimitiveVariable::Constant && sIt->second.interpolation == tIt->second.interpolation ) { IECore::ConstFloatVectorDataPtr s = IECore::runTimeCast< const IECore::FloatVectorData >( sIt->second.data ); IECore::ConstFloatVectorDataPtr t = IECore::runTimeCast< const IECore::FloatVectorData >( tIt->second.data ); if ( s && t ) { /// Should hold true if primvarsAreValid assert( s->readable().size() == t->readable().size() ); IECore::V2fVectorDataPtr stData = new IECore::V2fVectorData(); stData->writable().resize( s->readable().size() ); for ( unsigned i = 0; i < s->readable().size(); i++ ) { stData->writable()[i] = Imath::V2f( s->readable()[i], t->readable()[i] ); } glMesh->addPrimitiveVariable( "st", IECore::PrimitiveVariable( sIt->second.interpolation, stData ) ); } else { IECore::msg( IECore::Msg::Warning, "ToGLMeshConverter", "If specified, primitive variables \"s\" and \"t\" must be of type FloatVectorData and interpolation type FaceVarying." ); } } else { IECore::msg( IECore::Msg::Warning, "ToGLMeshConverter", "If specified, primitive variables \"s\" and \"t\" must be of type FloatVectorData and non-Constant interpolation type." ); } } else if ( sIt != mesh->variables.end() || tIt != mesh->variables.end() ) { IECore::msg( IECore::Msg::Warning, "ToGLMeshConverter", "Primitive variable \"s\" or \"t\" found, but not both." ); } return glMesh; }
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() ); }
void IECoreArnold::RendererImplementation::mesh( IECore::ConstIntVectorDataPtr vertsPerFace, IECore::ConstIntVectorDataPtr vertIds, const std::string &interpolation, const IECore::PrimitiveVariableMap &primVars ) { MeshPrimitivePtr mesh = new IECore::MeshPrimitive( vertsPerFace, vertIds, interpolation ); mesh->variables = primVars; addPrimitive( mesh.get(), "ai:polymesh:" ); }
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(); }