Exemple #1
0
//------------------------------------------------------------------------------
static int 
checkMesh( char const * msg, std::string const & shape, int levels, Scheme scheme, int backend ) {

    int result =0;

    printf("- %s (scheme=%d)\n", msg, scheme);

    xyzmesh * refmesh = simpleHbr<xyzVV>(shape.c_str(), scheme, 0);

    refine( refmesh, levels );


    std::vector<float> coarseverts;

    OsdHbrMesh * hmesh = simpleHbr<OpenSubdiv::OsdVertex>(shape.c_str(), scheme, coarseverts);

    OpenSubdiv::FarMeshFactory<OpenSubdiv::OsdVertex> meshFactory(hmesh, levels);

    OpenSubdiv::FarMesh<OpenSubdiv::OsdVertex> * farmesh = meshFactory.Create();

    std::vector<int> remap = meshFactory.GetRemappingTable();

    switch (backend) {
        case kBackendCPU   : result = checkMeshCPU(farmesh, coarseverts, refmesh, remap); break;
        case kBackendCPUGL : result = checkMeshCPUGL(farmesh, coarseverts, refmesh, remap); break;
        case kBackendCL    : result = checkMeshCL(farmesh, coarseverts, refmesh, remap); break;
    }

    delete hmesh;

    return result;
}
void
OsdPtexMeshData::initializeMesh() 
{
    if (!_hbrmesh)
        return;

    // create far mesh
    OpenSubdiv::FarMeshFactory<OpenSubdiv::OsdVertex>
        meshFactory(_hbrmesh, _level, _adaptive);

    _farmesh = meshFactory.Create(true /*ptex coords*/);

    delete _hbrmesh;
    _hbrmesh = NULL;

    int numTotalVertices = _farmesh->GetNumVertices();

    // create context and vertex buffer
    clearComputeContextAndVertexBuffer();

    if (_kernel == kCPU) {
        _cpuComputeContext = OpenSubdiv::OsdCpuComputeContext::Create(_farmesh);
        _cpuPositionBuffer = OpenSubdiv::OsdCpuGLVertexBuffer::Create(3, numTotalVertices);
        if (not _adaptive)
            _cpuNormalBuffer = OpenSubdiv::OsdCpuGLVertexBuffer::Create(3, numTotalVertices);
#ifdef OPENSUBDIV_HAS_OPENMP
    } else if (_kernel == kOPENMP) {
        _cpuComputeContext = OpenSubdiv::OsdCpuComputeContext::Create(_farmesh);
        _cpuPositionBuffer = OpenSubdiv::OsdCpuGLVertexBuffer::Create(3, numTotalVertices);
        if (not _adaptive)
            _cpuNormalBuffer = OpenSubdiv::OsdCpuGLVertexBuffer::Create(3, numTotalVertices);
#endif
#ifdef OPENSUBDIV_HAS_CUDA
    } else if (_kernel == kCUDA) {
        _cudaComputeContext = OpenSubdiv::OsdCudaComputeContext::Create(_farmesh);
        _cudaPositionBuffer = OpenSubdiv::OsdCudaGLVertexBuffer::Create(3, numTotalVertices);
        if (not _adaptive)
            _cudaNormalBuffer = OpenSubdiv::OsdCudaGLVertexBuffer::Create(3, numTotalVertices);
#endif
#ifdef OPENSUBDIV_HAS_OPENCL
    } else if (_kernel == kCL) {
        _clComputeContext = OpenSubdiv::OsdCLComputeContext::Create(_farmesh, g_clContext);
        _clPositionBuffer = OpenSubdiv::OsdCLGLVertexBuffer::Create(3, numTotalVertices,
                                                                    g_clContext);
        if (not _adaptive)
            _clNormalBuffer = OpenSubdiv::OsdCLGLVertexBuffer::Create(3, numTotalVertices,
                                                                      g_clContext);
#endif
    }

    _needsInitializeMesh = false;

    // get geometry from maya mesh
    MFnMesh meshFn(_meshDagPath);
    meshFn.getPoints(_pointArray);

    _needsUpdate = true;
}
void OpenSubdMesh::tessellate(DiagSplit *split)
{
	if (num_ptex_faces == 0)
		return;

	const int level = 3;
	const bool requirefvar = false;

	/* convert HRB to FAR mesh */
	OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;

	OsdFarMeshFactory meshFactory(hbrmesh, level, true);
	OsdFarMesh *farmesh = meshFactory.Create(requirefvar);
	int num_hbr_verts = hbrmesh->GetNumVertices();

	delete hbrmesh;
	hbrmesh = NULL;
	_hbrmesh = NULL;

	/* refine HBR mesh with vertex coordinates */
	OsdCpuComputeController *compute_controller = new OsdCpuComputeController();
	OsdCpuComputeContext *compute_context = OsdCpuComputeContext::Create(farmesh);

	OsdCpuVertexBuffer *vbuf_base = OsdCpuVertexBuffer::Create(3, num_hbr_verts);
	vbuf_base->UpdateData(&positions[0], 0, num_verts);

	compute_controller->Refine(compute_context, farmesh->GetKernelBatches(), vbuf_base);
	compute_controller->Synchronize();

	/* split & dice patches */
	OpenSubdPatch patch(farmesh, vbuf_base);

	for(int f = 0; f < num_ptex_faces; f++) {
		patch.face_id = f;
		split->split_quad(&patch);
	}

	/* clean up */
	delete farmesh;
	delete compute_controller;
	delete compute_context;
	delete vbuf_base;
}
Exemple #4
0
//------------------------------------------------------------------------------
static OpenSubdiv::FarMesh<OpenSubdiv::OsdVertex> *
createFarMesh( const char * shape, int level, bool adaptive, Scheme scheme=kCatmark ) {

    checkGLErrors("create osd enter");
    // generate Hbr representation from "obj" description
    std::vector<float> positions;
    OsdHbrMesh * hmesh = simpleHbr<OpenSubdiv::OsdVertex>(shape, scheme, positions,
                                                          g_displayStyle == kFaceVaryingColor);

    size_t nModel = g_bboxes.size();
    float x = nModel%g_modelCount - g_modelCount*0.5f;
    float y = nModel/g_modelCount - g_modelCount*0.5f;
    // align origins
    Matrix matrix;
    identity(matrix.value);
    translate(matrix.value, 3*x, 3*y, 0);
    g_transforms.push_back(matrix);
    g_positions.push_back(positions);

    OpenSubdiv::FarMeshFactory<OpenSubdiv::OsdVertex> meshFactory(hmesh, level, adaptive);
    OpenSubdiv::FarMesh<OpenSubdiv::OsdVertex> *farMesh = meshFactory.Create(true);

    // Hbr mesh can be deleted
    delete hmesh;

    // compute model bounding (vertex animation isn't taken into account)
    float min[4] = { FLT_MAX,  FLT_MAX,  FLT_MAX, 1};
    float max[4] = {-FLT_MAX, -FLT_MAX, -FLT_MAX, 1};
    for (size_t i=0; i <positions.size()/3; ++i) {
        float v[4] = {positions[i*3], positions[i*3+1], positions[i*3+2], 1 };
        for(int j=0; j<3; ++j) {
            min[j] = std::min(min[j], v[j]);
            max[j] = std::max(max[j], v[j]);
        }
    }
    g_bboxes.push_back(BBox(min, max));

    return farMesh;
}
Exemple #5
0
bool
OsdMesh::Create(OsdHbrMesh *hbrMesh, int level, int kernel, int exact, std::vector<int> * remap) {

    if (_dispatcher)
        delete _dispatcher;
    _dispatcher = OsdKernelDispatcher::CreateKernelDispatcher(level, kernel);

    if (not _dispatcher) {
        OSD_ERROR("Unknown kernel %d\n", kernel);
        return false;
    }

    _level = level;
    _exact = exact;

    // create Far mesh
    OSD_DEBUG("Create MeshFactory\n");

    FarMeshFactory<OsdVertex> meshFactory(hbrMesh, _level);

    _farMesh = meshFactory.Create(_dispatcher);

    OSD_DEBUG("PREP: NumCoarseVertex = %d\n", _farMesh->GetNumCoarseVertices());
    OSD_DEBUG("PREP: NumVertex = %d\n", _farMesh->GetNumVertices());

    createTables( _farMesh->GetSubdivision() );

    FarVertexEditTables<OsdVertex> const *editTables = _farMesh->GetVertexEdit();
    if (editTables)
        createEditTables( editTables );

    // copy the remapping table if the client needs to remap vertex indices from
    // Osd to Hbr for comparison / regression purposes.
    if (remap)
        (*remap)=meshFactory.GetRemappingTable();

    return true;
}
Exemple #6
0
// ====================================
// Compute
// ====================================
//
//  Description:
//      This method computes the value of the given output plug based
//      on the values of the input attributes.
//
//  Arguments:
//      plug - the plug to compute
//      data - object that provides access to the attributes for this node
//
MStatus OsdPolySmooth::compute( const MPlug& plug, MDataBlock& data ) {

    MStatus returnStatus;

    // Check which output attribute we have been asked to compute.  If this
    // node doesn't know how to compute it, we must return
    // MS::kUnknownParameter.
    //
    if( plug == a_output ) {
        bool createdSubdMesh = false;

        int subdivisionLevel = data.inputValue(a_subdivisionLevels).asInt();
        short stateH = data.inputValue(state).asShort();

        if ((subdivisionLevel > 0) and (stateH !=1)) {

            // == Retrieve input mesh ====================================
            // Get attr values
            MObject inMeshObj        = data.inputValue(a_inputPolymesh).asMesh();
            short vertBoundaryMethod = data.inputValue(a_vertBoundaryMethod).asShort();
            short fvarBoundaryMethod = data.inputValue(a_fvarBoundaryMethod).asShort();
            bool  fvarPropCorners    = data.inputValue(a_fvarPropagateCorners).asBool();
            bool  smoothTriangles    = data.inputValue(a_smoothTriangles).asBool();
            short creaseMethodVal    = data.inputValue(a_creaseMethod).asShort();

            // Convert attr values to OSD enums
            HMesh::InterpolateBoundaryMethod vertInterpBoundaryMethod =
                ConvertMayaBoundaryMethodShortToOsdInterpolateBoundaryMethod(vertBoundaryMethod);

            HMesh::InterpolateBoundaryMethod fvarInterpBoundaryMethod =
                ConvertMayaBoundaryMethodShortToOsdInterpolateBoundaryMethod(fvarBoundaryMethod);

            HCatmark::CreaseSubdivision creaseMethod =
                (creaseMethodVal == k_creaseMethod_chaikin) ?
                    HCatmark::k_CreaseChaikin : HCatmark::k_CreaseNormal;

            HCatmark::TriangleSubdivision triangleSubdivision =
                smoothTriangles ? HCatmark::k_New : HCatmark::k_Normal;

            // == Get Mesh Functions and Iterators ==========================
            MFnMeshData inMeshDat(inMeshObj);
            MFnMesh inMeshFn(inMeshObj, &returnStatus);
            MCHECKERR(returnStatus, "ERROR getting inMeshFn\n");
            MItMeshPolygon inMeshItPolygon(inMeshObj, &returnStatus);
            MCHECKERR(returnStatus, "ERROR getting inMeshItPolygon\n");

            // == Convert MFnMesh to OpenSubdiv =============================
            // Create the hbrMesh
            // Note: These fvar values only need to be kept alive through the life of the farMesh
            std::vector<int> fvarIndices;
            std::vector<int> fvarWidths;

            HMesh *hbrMesh = createOsdHbrFromPoly(
                inMeshFn, inMeshItPolygon, fvarIndices, fvarWidths);
            assert(hbrMesh);

            // Create the farMesh if successfully created the hbrMesh

            if (hbrMesh) {
                // Set Boundary methods and other hbr paramters
                hbrMesh->SetInterpolateBoundaryMethod( vertInterpBoundaryMethod );
                hbrMesh->SetFVarInterpolateBoundaryMethod( fvarInterpBoundaryMethod );
                hbrMesh->SetFVarPropagateCorners(fvarPropCorners);
                hbrMesh->GetSubdivision()->SetCreaseSubdivisionMethod(creaseMethod);

                // Set HBR Catmark Subdivision parameters
                HCatmark *catmarkSubdivision = dynamic_cast<HCatmark *>(hbrMesh->GetSubdivision());
                if (catmarkSubdivision) {
                    catmarkSubdivision->SetTriangleSubdivisionMethod(triangleSubdivision);
                }

                // Finalize subd calculations -- apply boundary interpolation rules and resolves singular verts, etc.
                // NOTE: This HAS to be called after all HBR parameters are set
                hbrMesh->Finish();

                int ncoarseverts = hbrMesh->GetNumVertices();

                // Create a FarMesh from the HBR mesh and pass into
                // It will be owned by the OsdMesh and deleted in the ~OsdMesh()
                FMeshFactory meshFactory(hbrMesh, subdivisionLevel, false);

                FMesh *farMesh = meshFactory.Create((hbrMesh->GetTotalFVarWidth() > 0));

                // == Setup OSD Data Structures =========================
                int numVertexElements  = 3; // only track vertex positions
                int numVaryingElements = 0; // XXX Future: Revise to include varying ColorSets
                int numVertices = inMeshFn.numVertices();

                int numFarVerts = farMesh->GetNumVertices();

                static OpenSubdiv::OsdCpuComputeController computeController = OpenSubdiv::OsdCpuComputeController();

                OpenSubdiv::OsdCpuComputeController::ComputeContext *computeContext =
                    OpenSubdiv::OsdCpuComputeController::ComputeContext::Create(farMesh);

                OpenSubdiv::OsdCpuVertexBuffer *vertexBuffer =
                    OpenSubdiv::OsdCpuVertexBuffer::Create(numVertexElements, numFarVerts );

                OpenSubdiv::OsdCpuVertexBuffer *varyingBuffer =
                    (numVaryingElements) ? OpenSubdiv::OsdCpuVertexBuffer::Create(numVaryingElements, numFarVerts) : NULL;

                // == UPDATE VERTICES (can be done after farMesh generated from topology) ==
                float const * vertex3fArray = inMeshFn.getRawPoints(&returnStatus);
                vertexBuffer->UpdateData(vertex3fArray, 0, numVertices );

                // Hbr dupes singular vertices during Mesh::Finish() - we need
                // to duplicate their positions in the vertex buffer.
                if (ncoarseverts > numVertices) {

                    MIntArray polyverts;

                    for (int i=numVertices; i<ncoarseverts; ++i) {

                        HVertex const * v = hbrMesh->GetVertex(i);

                        HFace const * f = v->GetIncidentEdge()->GetFace();

                        int vidx = -1;
                        for (int j=0; j<f->GetNumVertices(); ++j) {
                            if (f->GetVertex(j)==v) {
                                vidx = j;
                                break;
                            }
                        }
                        assert(vidx>-1);

                        inMeshFn.getPolygonVertices(f->GetID(), polyverts);

                        int vert = polyverts[vidx];

                        vertexBuffer->UpdateData(&vertex3fArray[0]+vert*numVertexElements, i, 1);
                    }
                }

                // == Delete HBR
                // Can now delete the hbrMesh as we will only be referencing the farMesh from this point on
                delete hbrMesh;
                hbrMesh = NULL;

                // == Subdivide OpenSubdiv mesh ==========================
                computeController.Refine(computeContext, farMesh->GetKernelBatches(), vertexBuffer, varyingBuffer);
                computeController.Synchronize();

                // == Convert subdivided OpenSubdiv mesh to MFnMesh Data outputMesh =============

                // Create New Mesh Data Object
                MFnMeshData newMeshData;
                MObject     newMeshDataObj = newMeshData.create(&returnStatus);
                MCHECKERR(returnStatus, "ERROR creating outputData");

                // Create out mesh
                returnStatus = convertOsdFarToMayaMeshData(farMesh, vertexBuffer, subdivisionLevel, inMeshFn, newMeshDataObj);
                MCHECKERR(returnStatus, "ERROR convertOsdFarToMayaMesh");

                // Propagate objectGroups from inMesh to outMesh (for per-facet shading, etc)
                returnStatus = createSmoothMesh_objectGroups(inMeshDat, subdivisionLevel, newMeshData );

                // Write to output plug
                MDataHandle outMeshH = data.outputValue(a_output, &returnStatus);
                MCHECKERR(returnStatus, "ERROR getting polygon data handle\n");
                outMeshH.set(newMeshDataObj);

                // == Cleanup OSD ============================================
                // REVISIT: Re-add these deletes
                delete(vertexBuffer);
                delete(varyingBuffer);
                delete(computeContext);
                delete(farMesh);

                // note that the subd mesh was created (see the section below if !createdSubdMesh)
                createdSubdMesh = true;
            }
        }

        // Pass-through inMesh to outMesh if not created the subd mesh
        if (!createdSubdMesh) {
            MDataHandle outMeshH = data.outputValue(a_output, &returnStatus);
            returnStatus = outMeshH.copy(data.outputValue(a_inputPolymesh, &returnStatus));
            MCHECKERR(returnStatus, "ERROR getting polygon data handle\n");
        }

        // Clean up Maya Plugs
        data.setClean(plug);
    }
    else {
        // Unhandled parameter in this compute function, so return MS::kUnknownParameter
        // so it is handled in a parent compute() function.
        return MS::kUnknownParameter;
    }
    return MS::kSuccess;
}
// Here is where the real meat of the OSD setup happens. The mesh topology is 
// created and stored for later use. Actual subdivision happens in updateGeom 
// which gets called at the end of this function and on frame change.
//
void
createOsdContext(int level)
{
    // 
    // Setup an OsdHbr mesh based on the desired subdivision scheme
    //
    static OpenSubdiv::HbrCatmarkSubdivision<OpenSubdiv::OsdVertex>  _catmark;
    OsdHbrMesh *hmesh(new OsdHbrMesh(&_catmark));

    //
    // Now that we have a mesh, we need to add verticies and define the topology.
    // Here, we've declared the raw vertex data in-line, for simplicity
    //
    float verts[] = {    0.000000f, -1.414214f, 1.000000f,
                        1.414214f, 0.000000f, 1.000000f,
                        -1.414214f, 0.000000f, 1.000000f,
                        0.000000f, 1.414214f, 1.000000f,
                        -1.414214f, 0.000000f, -1.000000f,
                        0.000000f, 1.414214f, -1.000000f,
                        0.000000f, -1.414214f, -1.000000f,
                        1.414214f, 0.000000f, -1.000000f
                        };

    //
    // The cube faces are also in-lined, here they are specified as quads
    //
    int faces[] = {
                        0,1,3,2,
                        2,3,5,4,
                        4,5,7,6,
                        6,7,1,0,
                        1,7,5,3,
                        6,0,2,4
                        };
    //
    // Record the original vertex positions and add verts to the mesh.
    //
    // OsdVertex is really just a place holder, it doesn't care what the 
    // position of the vertex is, it's just being used here as a means of
    // defining the mesh topology.
    //
    for (unsigned i = 0; i < sizeof(verts)/sizeof(float); i += 3) {
        g_orgPositions.push_back(verts[i+0]);
        g_orgPositions.push_back(verts[i+1]);
        g_orgPositions.push_back(verts[i+2]);
        
        OpenSubdiv::OsdVertex vert;
        hmesh->NewVertex(i/3, vert);
    }

    //
    // Now specify the actual mesh topology by processing the faces array 
    //
    const unsigned VERTS_PER_FACE = 4;
    for (unsigned i = 0; i < sizeof(faces)/sizeof(int); i += VERTS_PER_FACE) {
        //
        // Do some sanity checking. It is a good idea to keep this in your 
        // code for your personal sanity as well.
        //
        // Note that this loop is not changing the HbrMesh, it's purely validating
        // the topology that is about to be created below.
        //
        for (unsigned j = 0; j < VERTS_PER_FACE; j++) {
            OsdHbrVertex * origin      = hmesh->GetVertex(faces[i+j]);
            OsdHbrVertex * destination = hmesh->GetVertex(faces[i+((j+1)%VERTS_PER_FACE)]);
            OsdHbrHalfedge * opposite  = destination->GetEdge(origin);

            if(origin==NULL || destination==NULL) {
                std::cerr << 
                    " An edge was specified that connected a nonexistent vertex"
                    << std::endl;
                exit(1);
            }

            if(origin == destination) {
                std::cerr << 
                    " An edge was specified that connected a vertex to itself" 
                    << std::endl;
                exit(1);
            }

            if(opposite && opposite->GetOpposite() ) {
                std::cerr << 
                    " A non-manifold edge incident to more than 2 faces was found" 
                    << std::endl;
                exit(1);
            }

            if(origin->GetEdge(destination)) {
                std::cerr << 
                    " An edge connecting two vertices was specified more than once."
                    " It's likely that an incident face was flipped" 
                    << std::endl;
                exit(1);
            }
        }
        // 
        // Now, create current face given the number of verts per face and the 
        // face index data.
        //
        /* OsdHbrFace * face = */ hmesh->NewFace(VERTS_PER_FACE, faces+i, 0);

        //
        // If you had ptex data, you would set it here, for example
        //
        /* face->SetPtexIndex(ptexIndex) */

    }

    //
    // Apply some tags to drive the subdivision algorithm. Here we set the 
    // default boundary interpolation mode along with a corner sharpness. See 
    // the API and the renderman spec for the full list of available operations.
    //
    hmesh->SetInterpolateBoundaryMethod( OsdHbrMesh::k_InterpolateBoundaryEdgeOnly );
    
    OsdHbrVertex * v = hmesh->GetVertex(0);
    v->SetSharpness(2.7f);

    //
    // Finalize the mesh object. The Finish() call is a signal to the internals 
    // that optimizations can be made on the mesh data. 
    //
    hmesh->Finish();

    //
    // Setup some raw vectors of data. Remember that the actual point values were
    // not stored in the OsdVertex, so we keep track of them here instead
    //
    g_normals.resize(g_orgPositions.size(),0.0f);
    calcNormals( hmesh, g_orgPositions, g_normals );

    // 
    // At this point, we no longer need the topological structure of the mesh, 
    // so we bake it down into subdivision tables by converting the HBR mesh 
    // into an OSD mesh. Note that this is just storing the initial subdivision
    // tables, which will be used later during the actual subdivision process.
    //
    // Again, no vertex positions are being stored here, the point data will be 
    // sent to the mesh in updateGeom().
    //
    OpenSubdiv::FarMeshFactory<OpenSubdiv::OsdVertex> meshFactory(hmesh, level);

    g_farmesh = meshFactory.Create();

    g_osdComputeContext = OpenSubdiv::OsdCpuComputeContext::Create(g_farmesh);

    delete hmesh;

    // 
    // Initialize draw context and vertex buffer
    //
    g_vertexBuffer = 
        OpenSubdiv::OsdCpuGLVertexBuffer::Create(6,  /* 3 floats for position, 
                                                            +
                                                            3 floats for normal*/
                                                 g_farmesh->GetNumVertices());

    g_drawContext =
        OpenSubdiv::OsdGLDrawContext::Create(g_farmesh->GetPatchTables(), false);
    g_drawContext->UpdateVertexTexture(g_vertexBuffer);

    // 
    // Setup camera positioning based on object bounds. This really has nothing
    // to do with OSD.
    //
    computeCenterAndSize(g_orgPositions, g_center, &g_size);

    //
    // Finally, make an explicit call to updateGeom() to force creation of the 
    // initial buffer objects for the first draw call.
    //
    updateGeom();

    //
    // The OsdVertexBuffer provides GL identifiers which can be bound in the 
    // standard way. Here we setup a single VAO and enable points and normals 
    // as attributes on the vertex buffer and set the index buffer.
    //
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, g_vertexBuffer->BindVBO());
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, 0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, (float*)12);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_drawContext->GetPatchIndexBuffer());
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}