Jump to content

Recommended Posts

Hey guys


I have a simple enough problem i wanted to solve in HDK, and i managed to do it, however im sure there has to be a more elegant solution with enough knowledge of HDK classes.

I wanted to do a simple sop that compares the same user chosen attribute from two different inputs, and either groups the difference as points group, or deletes points that have the same attrib value across both inputs.

Basically i just have the same point cloud on both inputs, the second input has a timeshift node that looks up the previous frame.

Its a simple enough exercise, however i have to ask if anyone knows if im reinventing the wheel, if the interface for doing stuff like this is more simple to use, or could give me some hints on how to do it better.


Now the problem i came across was how would one define an array to hold values of an attribute of type we dont know in advance?

Ive used a hacky solution where i would do the following in cookMySop()

//get ptrs to our input geoconst GU_Detail *firstInput  = inputGeo(0);
const GU_Detail *secondInput = inputGeo(1);
//find if attr exist in those geos, lookup is our string that holds the attr name user chose from the UI
const GA_Attribute *fattr = firstInput->findAttribute(GA_ATTRIB_POINT, lookup);
const GA_Attribute *sattr;
//get our total numpts
std::cout << "total num of pts (1): " << firstInput->getPointMap().indexSize() << std::endl;
//    std::cout << (GA_StorageClass)fattr->getStorageClass() << std::endl;
//if we have hooked a second input, find attrs and get total numpts
    sattr = secondInput->findAttribute(GA_ATTRIB_POINT, lookup);
    std::cout << "total num of pts (2): " << secondInput->getPointMap().indexSize() << std::endl;
// If source attribute doesn't exist, error.
if (!fattr || !sattr)
    addError(SOP_ATTRIBUTE_INVALID, (const char *)lookup);
    return error();

//define our arrays
UT_ValArray<int32> ptNumListFirst;
UT_ValArray<int32> ptNumListSecond;
UT_ValArray<int32> ptNumListDiff;

//only if our attr is not string shall we compare, have no idea how to figure out string yet
if(fattr->getStorageClass() == GA_STORECLASS_INT)
    std::cout << "Yes it is a numeric!" << std::endl;

    //feed our list of attr values in the array FIRST GEO
    gdp->getPointAttributeAsArray(fattr,gdp->getPointRange(), ptNumListFirst);

    //if we have connected the second geo
        //feed our list of attr values in the array SECOND GEO
        secondInput->getPointAttributeAsArray(fattr,secondInput->getPointRange(), ptNumListSecond);

        //compare our first and second input list and feed the diff in the third input
        //this is our class method
        compareUTArrays(ptNumListFirst, ptNumListSecond, ptNumListDiff);

I actually dont allow the user to pick an attrib from the list thats not int or the node errors out, so basically im forcing the user to choose an int attr.

Im sure there is a better way of doing this. Also i tried using the sortedIntersection() method of the UT_ValNumeric array type, however i could never get the difference to be calculated so i had to write my own implementation of the method (compareUTArrays()).


Also in the end i use this approach to get the pts in an array that either needed to be grouped or deleted, im not entirely sure if its the "proper" way of doing things:


    //if we ticked new group, create a new group for pts
    if(newGrp || deletePts)
        //create our new group
        GA_PointGroup *diffGrp;
        diffGrp = gdp->newPointGroup(grpName, false);
        //create a temp group we will delete later if we need to delete points
        GA_PointGroup *delGrp = gdp->newPointGroup("__tempDelGrp__", false);
        //get the handle to our int attribute 
        //would prefer if i could somehow make the handle type recognize the attr data type
        GA_ROHandleI lookup_attr(fattr);

        int32 value;
        //iterate thru all points 
        for(GA_Iterator it(gdp->getPointRange()); !it.atEnd(); ++it)
            GA_Offset offset = *it;
            value = lookup_attr.get(offset);
            std::cout << value << " is value of pts attr" << std::endl;

            //iterate thru the array and if we have found same attr value add it to the group
            for(UT_ValArray<int32>::const_iterator itarr = ptNumListDiff.begin(); itarr != ptNumListDiff.end(); ++itarr)
                if(value == *itarr)


        //the diff between the first and second input is found in the diff array
        //however we need to delete everything thats not the diff, and that is the second inputs members translated into first
        for(GA_Iterator it(secondInput->getPointRange()); !it.atEnd(); ++it)
            GA_Offset offset = *it;

Now i guess i can use the GA_Attribute.getStorageClass and a switch or if statement and initialize my arrays according to the type, but like i said somehow im sure there has to be a more intelligent way of doing this :)


Also im a bit confused about the bumpDataId, what should i do in this case?

If i just group my points and dont even modify the geo or attrib values, should i signal houdini to bumpDataId and whats the syntax for doing that?

If i delete points however im sure i have to inform houdini that ive modified geo, which class or method should i use to do something like that?


I hope all of this makes sense, let me know if it doesnt ill try and elaborate better :)

Any help would be greatly appreciated





Link to comment
Share on other sites

I don't believe there is any HDK based solution to this problem, not that I'm aware of.  But I would try to write a template function, probably still need a switch for each type though, should be way simpler though.


This way you specify the type handle type like "GA_ROHandleT<T>"  and the array the same way.   Strings may need to be handled slightly differently though.


You shouldn't need to manually bump the attribute data ids, from my understanding that more for situations like the paint SOP, where you want to update the visuals, in the current node rather then in the subsequent node.


EDIT - Okay, that's not entirely true.. I haven't looked at that in a while.  Normally Houdini bumps all the data ids, unless you specify you want to manage them yourself.  Which in most cases is probably unnecessary, however it could be faster to bump nothing, and it definitely shouldn't care about groups, though point deletion may make a difference.  The only way to know is to test.  If you get weird results bump the ids.

The samples in the toolkit show the syntax for doing such things.


But unless you specify you want to manually manage something you don't need to do anything special.

Edited by captain
Link to comment
Share on other sites

Thanks captain


I was thinking about creating a template function for the UT_ValArray i just thought that there could be another way of doing this.


As for ids thanks for the info, i was generally confused about it, and have since read the header files which explain the whole thing in more detailed way.

Ill give it another go and see how it turns out.


Thanks again

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...