Beispiel #1
0
	// create result mesh
	umdraw::UMMeshPtr create_result_mesh(DevidedMesh* divided_mesh, unsigned int level)
	{
		if (!divided_mesh) return umdraw::UMMeshPtr();
		// result mesh
		umdraw::UMMeshPtr result = std::make_shared<umdraw::UMMesh>();
		
		const std::vector<UMSubdivVertex>& vertex = divided_mesh->GetVertices();
		const int veretx_size = static_cast<int>(vertex.size());
		const unsigned int* face = divided_mesh->GetPatchTables()->GetFaceVertices();
		const int face_size = divided_mesh->GetPatchTables()->GetNumFaces();
		// important: base vertex index changed by level!
		const unsigned int base_vertex_index = divided_mesh->GetSubdivisionTables()->GetNumVerticesTotal(level - 1);
		
		OpenSubdiv::OsdCpuComputeContext* context
			= OpenSubdiv::OsdCpuComputeContext::Create(reinterpret_cast<const FarMesh<OsdVertex>* >(divided_mesh));
		OpenSubdiv::OsdCpuComputeController* controller
			= new OpenSubdiv::OsdCpuComputeController();
		OpenSubdiv::OsdCpuVertexBuffer *vertex_buffer
			= OpenSubdiv::OsdCpuVertexBuffer::Create(3, divided_mesh->GetNumVertices());
		vertex_buffer->UpdateData(&(vertex[0].pos[0]), 0, divided_mesh->GetNumVertices());

		// vertex will replace subdivided verts.
		controller->Refine(context, divided_mesh->GetKernelBatches(), vertex_buffer);

		// assing refined verts
		result->mutable_vertex_list().resize(veretx_size);
		float * refined_vertex = vertex_buffer->BindCpuBuffer() + (3 * base_vertex_index);
		for (size_t i = 0; i < veretx_size; ++i)
		{
			result->mutable_vertex_list().at(i) = UMVec3d(
				refined_vertex[i * 3 + 0],
				refined_vertex[i * 3 + 1],
				refined_vertex[i * 3 + 2]);
		}
		// assign faces as triangle
		const int triangle_count = face_size * 2;
		result->mutable_face_list().resize(triangle_count);
		for (int i = 0; i < triangle_count; ++i)
		{
			unsigned int f0 = face[ i * 4 + 0 ] - base_vertex_index;
			unsigned int f1 = face[ i * 4 + 1 ] - base_vertex_index;
			unsigned int f2 = face[ i * 4 + 2 ] - base_vertex_index;
			unsigned int f3 = face[ i * 4 + 3 ] - base_vertex_index;
			result->mutable_face_list().at(i * 2 + 0) = UMVec3i(f0, f1, f2);
			result->mutable_face_list().at(i * 2 + 1) = UMVec3i(f0, f2, f3);
		}

		// TODO: calc normals by subdiv
		result->create_normals(true);
		result->mutable_material_list().push_back(mesh_->mutable_material_list().at(0));
		result->mutable_material_list().at(0)->set_polygon_count(triangle_count);
		result->update_box();

		delete vertex_buffer;
		delete context;
		delete controller;
		return result;
	}
Beispiel #2
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;
}