Jump to content

Search the Community

Showing results for tags 'hdk'.

More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • General
    • Lounge/General chat
    • Education
    • Jobs
    • Marketplace
  • Houdini
    • General Houdini Questions
    • Effects
    • Modeling
    • Animation & Rigging
    • Lighting & Rendering
    • Compositing
    • Games
    • Tools (HDA's etc.)
  • Coders Corner
    • HDK : Houdini Development Kit
    • Scripting
    • Shaders
  • Art and Challenges
    • Finished Work
    • Work in Progress
    • VFX Challenge
    • Effects Challenge Archive
  • Systems and Other Applications
    • Other 3d Packages
    • Operating Systems
    • Hardware
    • Pipeline
  • od|force
    • Feedback, Suggestions, Bugs

Found 84 results

  1. Hi, With the following code, I can write out a single bezier curve but anything more than one, the second bezier curves are not in the bgeo file being written out. The point count indicates that it is aware of additional points associated with the second curve. #include <string> #include <GU/GU_Detail.h> #include <GU/GU_PrimRBezCurve.h> #include <UT/UT_Version.h> #include <GEO/GEO_Point.h> #include <OpenEXR/ImathVec.h> #include <vector> typedef std::vector<Imath::V3d> V3dContainer; void create_single_bezier_curve(const std::string& bgeo_filename) { GU_Detail gdp; V3dContainer cvs; cvs.push_back(Imath::V3d(0,0,0)); cvs.push_back(Imath::V3d(1,1,0)); cvs.push_back(Imath::V3d(2,1,0)); cvs.push_back(Imath::V3d(3,0,0)); GA_Size num_points = cvs.size(); for ( size_t i = 0; i < num_points; ++i ) { GA_Offset pt = gdp.appendPointOffset(); gdp.setPos3(pt, cvs[i][0], cvs[i][1], cvs[i][2]); } GU_PrimRBezCurve* bezier_curve = GU_PrimRBezCurve::build(&gdp,num_points); if (bezier_curve) { for ( size_t i = 0; i < num_points; ++i ) { bezier_curve->setVertexPoint(i,gdp.pointOffset(i)); } gdp.save(bgeo_filename.c_str(), NULL); } } void create_multilpe_bezier_curves(const std::string& bgeo_filename) { GU_Detail gdp; V3dContainer cvs; // Curve 0 cvs.push_back(Imath::V3d(0,0,0)); cvs.push_back(Imath::V3d(1,1,0)); cvs.push_back(Imath::V3d(2,1,0)); cvs.push_back(Imath::V3d(3,0,0)); // Curve 1 double y_offset = 2.0; cvs.push_back(Imath::V3d(0,0 + y_offset,0)); cvs.push_back(Imath::V3d(1,1 + y_offset,0)); cvs.push_back(Imath::V3d(2,1 + y_offset,0)); cvs.push_back(Imath::V3d(3,0 + y_offset,0)); cvs.push_back(Imath::V3d(4,0 + y_offset,0)); // Store all the points GA_Size num_points = cvs.size(); for ( size_t i = 0; i < num_points; ++i ) { GA_Offset pt = gdp.appendPointOffset(); gdp.setPos3(pt, cvs[i][0], cvs[i][1], cvs[i][2]); } // Setup curve 0 GA_Size num_points_curve_0 = 4; GU_PrimRBezCurve* bezier_curve_0 = GU_PrimRBezCurve::build(&gdp,num_points_curve_0); if (bezier_curve_0) { for ( size_t i = 0; i < num_points_curve_0; ++i ) { bezier_curve_0->setVertexPoint(i,gdp.pointOffset(i)); } } // Setup curve 1 GA_Size num_points_curve_1 = 5; GA_Offset curve_offset_1 = 4; // because the first 4 points is for curve 0 GU_PrimRBezCurve* bezier_curve_1 = GU_PrimRBezCurve::build(&gdp,num_points_curve_1); if (bezier_curve_1) { for ( size_t i = 0; i < num_points_curve_1; ++i ) { bezier_curve_1->setVertexPoint(i,gdp.pointOffset(i+curve_offset_1)); // bezier_curve_1->setVertexPoint(i,curve_offset_1); } } gdp.save(bgeo_filename.c_str(), NULL); } int main(int argc, char *argv[]) { create_single_bezier_curve("single_bezier_curve.bgeo"); create_multilpe_bezier_curves("multiple_bezier_curves.bgeo"); return 0; }
  2. Hello, devs, I have compiled geoisosurface.C but running geoisosurface.exe raise an error: Entry Point Not Found. The procedure entry point gzdirect could not be located in the dynamic link library C:\Program Files\Side Effects Software\Houdini 18.0.460\bin\libxml2.dll If I place geoisosurface.exe into the Houdini bin folder it is working and produce me sphere.bgeo. If I copy libxml2.dll to the folder with exe file the error is: The procedure entry point gzdirect could not be located in the dynamic link library D:/path_to_geoisosurface/libxml2.dll I am pretty sure that exe file should work outside Houdini bin dir, but have no idea how to fix this. Alex @Stalkerx777, anything comes into mind?
  3. I am trying to resurrect an old version of a Houdini plugin that no longer works with newer versions of Houdini. I've tracked down the issue to a segfault happening in the file $HFS/toolkit/include/openvdb/Grid.h , where the function Grid<TreeT>::setTree(TreeBase::Ptr tree) is checking the type of the tree: tree->type() I can't figure out what could be causing this to segfault. When I print ouf the tree details with tree->print(std::cout, 4) I see that the tree type is "Tree_float_5_4_3", which seems fine? So why would this cause an issue? Anyone have any ideas? The full print output is: Information about Tree: Type: Tree_float_5_4_3 Configuration: Root(1 x 1), Internal(1 x 32^3), Internal(6 x 16^3), Leaf(5,207 x 8^3) Background value: 0 Min value: 0 Max value: 15.9799 Number of active voxels: 4,927,500 Number of active tiles: 5,813 Bounding box of active voxels: [0, 0, 0] -> [299, 224, 72] Dimensions of active voxels: 300 x 225 x 73 Percentage of active voxels: 100% Average leaf node fill ratio: 73.2% Number of unallocated nodes: 0 (0%) Memory footprint: Actual: 11.099 MB Active leaf voxels: 7.443 MB Dense equivalent: 18.797 MB Actual footprint is 59% of an equivalent dense volume Leaf voxel footprint is 67.1% of actual footprint Tree_float_5_4_3
  4. Hello, I am trying to start Learning Houdini HDK so i started by compiling the sample files. I managed to compile with hcustom, everything worked fine so i tried with cmake. generating the project worked but when i open the solution file in visual studio and i build i get a lot of errors saying impossible to initialize member "....". I'm on Windows 10 i use Houdini 17.5.425 and visual studio Community 15 2017 and cmake 3.18. Any ideas why i get all these errors ? should I upgrade to Houdini 18 ? I can work with hcustom for now because i'm just Learning but I would be very happy to undertand why it doesnt work. Thanks !
  5. ACM Transactions on Graphics "Generalized non-reflecting boundaries for fluid re-simulation" How do I build the HDK for this paper? website: http://alas.dk/publications/2016/GNRBfFRS/ Download HDK Source Code: http://pub.ist.ac.at/group_wojtan/projects/2016_Bojsen-Hansen_GNRBfFRS/2016_Bojsen-Hansen_GNRBfFRS.zip I tried halfway through with Visual Studio 2015 and it looked like I could build with Houdini 17.0, but I got so many errors with Houdini 18. I'm a beginner in programming, but I'm very interested in the HDK for this paper and would like to install it on Houdini. Thank you.
  6. Hello, I'd like to perform matrix multiplication between 2 of 3x3 matrices(not coefficient-wise) and outer product between 2 vectors using HDK. So I'd like to know if the * operator supports matrix multiplication and outer product of vectors as in the example code below. UT_Matrix3 A = ... UT_Matrix3 B = ... UT_Matrix3 C = A * B // matrix multiplication UT_Vector3 u = ... UT_Vector3 v = ... UT_Matrix3 X = u * v // outer product If not, is there a function/operator to do matrix multiplication and outer product? Thank you.
  7. hello everyone,i'm learning c++ and I'm new to Houdini HDK. I was reading another topic, someone told that you can use example files and manipulate them. so I have some questions for you: as you can see the header code and it's definition namespace HDK_Sample { /// Run a sin() wave through geometry by deforming points /// @see @ref HOM/SOP_HOMWave.C, SOP_HOMWave, SOP_CPPWave class SOP_PointWave : public SOP_Node { public: SOP_PointWave(OP_Network *net, const char *name, OP_Operator *op); virtual ~SOP_PointWave(); static PRM_Template myTemplateList[]; static OP_Node *myConstructor(OP_Network*, const char *, OP_Operator *); /// This method is created so that it can be called by handles. It only /// cooks the input group of this SOP. The geometry in this group is /// the only geometry manipulated by this SOP. virtual OP_ERROR cookInputGroups(OP_Context &context, int alone = 0); protected: /// Method to cook geometry for the SOP virtual OP_ERROR cookMySop(OP_Context &context); private: void getGroups(UT_String &str){ evalString(str, "group", 0, 0); } fpreal AMP(fpreal t) { return evalFloat("amp", 0, t); } fpreal PHASE(fpreal t) { return evalFloat("phase", 0, t); } fpreal PERIOD(fpreal t) { return evalFloat("period", 0, t); } /// This is the group of geometry to be manipulated by this SOP and cooked /// by the method "cookInputGroups". const GA_PointGroup *myGroup; }; using namespace HDK_Sample; void newSopOperator(OP_OperatorTable *table) { table->addOperator(new OP_Operator( "hdk_pointwave", "Point Wave", SOP_PointWave::myConstructor, SOP_PointWave::myTemplateList, 1, 1, 0)); } static PRM_Name names[] = { PRM_Name("amp", "Amplitude"), PRM_Name("phase", "Phase"), PRM_Name("period", "Period"), }; PRM_Template SOP_PointWave::myTemplateList[] = { PRM_Template(PRM_STRING, 1, &PRMgroupName, 0, &SOP_Node::pointGroupMenu, 0, 0, SOP_Node::getGroupSelectButton( GA_GROUP_POINT)), PRM_Template(PRM_FLT_J, 1, &names[0], PRMoneDefaults, 0, &PRMscaleRange), PRM_Template(PRM_FLT_J, 1, &names[1], PRMzeroDefaults), PRM_Template(PRM_FLT_J, 1, &names[2], PRMoneDefaults), PRM_Template(), }; OP_Node * SOP_PointWave::myConstructor(OP_Network *net, const char *name, OP_Operator *op) { return new SOP_PointWave(net, name, op); } SOP_PointWave::SOP_PointWave(OP_Network *net, const char *name, OP_Operator *op) : SOP_Node(net, name, op), myGroup(NULL) { mySopFlags.setManagesDataIDs(true); } SOP_PointWave::~SOP_PointWave() {} OP_ERROR SOP_PointWave::cookInputGroups(OP_Context &context, int alone) { return cookInputPointGroups( context, // This is needed for cooking the group parameter, and cooking the input if alone. myGroup, // The group (or NULL) is written to myGroup if not alone. alone, // This is true iff called outside of cookMySop to update handles. // true means the group will be for the input geometry. // false means the group will be for gdp (the working/output geometry). true, // (default) true means to set the selection to the group if not alone and the highlight flag is on. 0, // (default) Parameter index of the group field -1, // (default) Parameter index of the group type field (-1 since there isn't one) true, // (default) true means that a pointer to an existing group is okay; false means group is always new. false, // (default) false means new groups should be unordered; true means new groups should be ordered. true, // (default) true means that all new groups should be detached, so not owned by the detail; // false means that new point and primitive groups on gdp will be owned by gdp. 0 // (default) Index of the input whose geometry the group will be made for if alone. ); } OP_ERROR SOP_PointWave::cookMySop(OP_Context &context) { OP_AutoLockInputs inputs(this); if (inputs.lock(context) >= UT_ERROR_ABORT) return error(); duplicatePointSource(0, context); fpreal t = context.getTime(); float phase = PHASE(t); float amp = AMP(t); float period = PERIOD(t); if (error() >= UT_ERROR_ABORT) return error(); if (cookInputGroups(context) >= UT_ERROR_ABORT) return error(); GA_Offset ptoff; GA_FOR_ALL_GROUP_PTOFF(gdp, myGroup, ptoff) { UT_Vector3 p = gdp->getPos3(ptoff); p.y() += SYSsin( (p.x() / period + phase) * M_PI * 2 ) * amp; gdp->setPos3(ptoff, p); } if (!myGroup || !myGroup->isEmpty()) gdp->getP()->bumpDataId(); return error(); } my first question is: we have this int header file : SOP_PointWave(OP_Network *net, const char *name, OP_Operator *op); where is it's definition in *.c file? ----------------------------------------------------------------------------------------------------------------------------------------- my second question is: void newSopOperator(OP_OperatorTable *table) { table->addOperator(new OP_Operator( "hdk_pointwave", "Point Wave", SOP_PointWave::myConstructor, SOP_PointWave::myTemplateList, 1, 1, 0)); } why this function is void? I know because it won't return anything, but why it shouldn't? why newSopOperator's parameter is a class (i know a class is custom data type) but why? and what is table in the parameter? ----------------------------------------------------------------- BEST REGARDS
  8. Hello, guys! For example, I have a button with a callback function and some float value: PRM_Template(PRM_CALLBACK, 1, &someBtnName, 0, 0, 0, &callbackFunc), PRM_Template(PRM_FLT, TOOL_PARM, 1, &someValueName, PRMzeroDefaults), ... int callbackFunc(void *data, int index, fpreal t, const PRM_Template *tplate) { ... } How to change value of a float control from the callbackFunc function?
  9. Hello, I'm working on a big project which uses 3rd party library and I get some strange results if I try to interrupt my nodes. At first i thought that I'm doing something wrong and UT_AutoInterrupt send to callback of this library is not working properly, so I took example node that comes with Houdini SOP_Flatten, removed almost all code from cookMySop() and tried to interrupt it. This is what I get: There should be only Warning set. But I do get additional Error. And I don't know from where it come from. This is the code I have in cookMySOp(): OP_ERROR SOP_Flatten::cookMySop(OP_Context &context) { OP_AutoLockInputs inputs(this); if (inputs.lock(context) >= UT_ERROR_ABORT) return error(); auto progress = UT_AutoInterrupt(""); for (auto i = 0; i < 10000; i++) { if (progress.wasInterrupted()) { this->addWarning(SOP_MESSAGE, "Test interrupted."); return error(); } std::cout << "YAY: " << i << "\n"; } return error(); } Anybody knows why I do get this additional Error state when interrupting the node? I'm on H18.0.348.
  10. Houdini HDK

    hello, nowadays I'm working on Houdini HDK I created a discord server to help each other this is the discord's link: https://discord.gg/RtNRscp and this is my blog:https://aminkhormaei1.wixsite.com/base i put solutions inside my blog. please share this post, maybe your friends are into developing a plugin for Houdini BEST REGARDS
  11. Hi, I want to start learning the hdk and by creating simple standalone application. I managed to get the example of the docs compiling and it is creating a sphere so everything is fine. For that, I was using a simple console application. But as soon as I add the Qt5 Core library so I can create my interface, it's not compiling anymore, if I don't include the library in my main file. Here is my error: undefined reference to `QApplication::setCustomDPIOverride(int)@Qt_5 This is in libHoudiniUI.so Does any of you have any idea of what can causes this? edit: For those of you who are interesteed, I managed to recently find the solution. I didn't have the exact same version of Qt as Houdini is using, and also there was some issues with cmake file
  12. I wrote an article that is probably only of interest for the .1% It is a crash introduction to HDK, C++ and the mesh laplacian. https://mbaadsgaard.com/portfolio/laplacian-eigenvector-plugin-for-houdini/ Feedback is, of course, also welcome
  13. Geodesics in Heat

    Hi everyone! I've made an illustration video-tutorial about the Heat Method application to point clouds by Keenan Crane et al, Yang Liu et al and others.
  14. So I'm still building some microsolver nodes for water simulation. I noticed that all the microsolver I made including the Gas Add from the HDK sample all have a grey input point on the left. All built-in in gas node do not. Seems like this doesn't effect the execution result but I'm still curious how do I make a node that looks exactly like the built-in ones. And also, enable bypass on these nodes doesn't seem to work. Do I need to manually skip in solveGasSubclass()?
  15. I'm learning HDK and fluid sim by swapping out microsolver nodes in Houdini's built in FLIP solver. I've successfully changed the GasExternalForce node to my simple gravity node. It works okay but there's a small problem that bugs me a lot. So here's the implementation in the built in solver: There's a gravity node in the Auto DOP network (looks like the order doesn't really matter. I tried putting the gravity node before the flipsover and nothing changed.) And then in the flipsolver there's a GasExternalForces microsolver that apply forces on the particles. I deleted the gravity node and changed the GasExternalForces node to my implementation: bool SIM_HZExternalForce::solveGasSubclass(SIM_Engine &engine, SIM_Object *obj, SIM_Time time, SIM_Time timestep) { SIM_Geometry* geo = (SIM_Geometry*)obj->getGeometry(); if (!geo) { return false; } GU_DetailHandle gdh = geo->getOwnGeometry(); const GU_Detail* gdp_in = gdh.readLock(); // Must unlock later GU_Detail* gdp_out = gdh.writeLock(); GA_RWAttributeRef p_ref_vel = gdp_out->findPointAttribute("v"); GA_RWHandleT<UT_Vector3F> p_vel(p_ref_vel.getAttribute()); if (p_vel.isInvalid()) { return false; } for (GA_Iterator it(gdp_out->getPointRange()); !it.atEnd(); it.advance()){ int pid = it.getOffset(); UT_Vector3F vel = p_vel.get(pid); vel[1] -= timestep * 9.80665f; p_vel.set(pid, vel); } gdh.unlock(gdp_out); gdh.unlock(gdp_in); // Successful cook return true; } The problem is, the velocities in the first frame are all zero in the official implementation: But in my implementation, the velocities got changed in the first frame: I really want to know where this discrepancy comes from. Any suggestions? I've uploaded the source code and scene file if anyone is interested. GravityTest.zip
  16. I'm trying to work on a VDB SOP but I'm having problems compiling. I'm windows with Houdini 16.5 and I'm getting "unresolved externals". Along with the usual inclusions I have: #include <GU/GU_PrimVDB.h> #include <openvdb/openvdb.h> #include <openvdb/Grid.h> I'm compiling with cmake which looks like this cmake_minimum_required( VERSION 3.6 ) project( HDK_VolumeDeform ) list( APPEND CMAKE_PREFIX_PATH "$ENV{HFS}/toolkit/cmake" ) find_package( Houdini REQUIRED ) set( library_name SOP_VolumeDeform ) add_library( ${library_name} SHARED SOP_Volume_Deform.C SOP_Volume_Deform.h ) target_link_libraries( ${library_name} Houdini) SET(COMPILE_FLAGS "-TP -std=c++11 -DOPENVDB_3_ABI_COMPATIBLE") add_definitions(${COMPILE_FLAGS}) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILE_FLAGS}") target_include_directories( ${library_name} PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) houdini_configure_target( ${library_name} ) Strangely enough, the program does compile if I don't try use iterators, though I'm sure there is a lot that would break it. I've also tried with Hcustom, but running with that yields the same problems. Does anyone have any suggestions? Thank you very much!
  17. I need to have context for some calculations inside newContextData method of COP2_Node class. Is it safe to call getContext from inside this method?
  18. I need to know the size of the COP2 node for some input node. I can get a sequence info (TIL_Sequence) by calling getSequenceInfo member function of COP2_Node class. But it has only resolution info (getRes function), which is a visible size of the image, not an actual size.
  19. Hi guys, I need to make a login GUI in Houdini so that users can input their usename and password to log into our internal server to download assets for editing. The username control is easy but the password one is hard in that it needs to mask the input, e.g. with ‘*’. Is there any way to make this happen? Thanks for any inputs! I'm working on Houdini 16.5 and our plugin needs to know the login status, so it's better that the suggested way can communicate the status between C++ code. Thanks, Quan
  20. Hi everyone. I encountered a few problems compiling HDK assets for Houdini 17 using cmake. Houdini seems unable to detect the assets even though they build just fine without error. I use the community edition of visual studio 2015 update 3, and as far as I can tell, this is the correct version for Houdini 17 ?? When I try a simple SOP_Star example with Hcustom it does not work either as I get the error: Failed to run C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\Hostx86\x64\cl with error 2: The system cannot find the file specified. This path does not seems to exist but when I use cmake it targets this dir: This path exists in Visual studio 2017 but not in 2015. However, when I try with cmake, it finds the compiler here: CProgram Files (x86)/Microsoft Visual Studio 14.0/VC/bin/x86_amd64/cl.exe And creates the solution just fine. When I build the solution however, it does not show up in Houdini... I have been using a similar procedure to compile assets with cmake for earlier versions of Houdini with no issues. Reading thourgh the HDK docs for comiling with cmake, they suggest parsing the argument "Visual Studio 14 2017 Win64" Does this version even exist ? I have not been able to locate it... I have tried to compile with VS 2017 as well without luck. So do anyone know what the problem might be ?
  21. We pull out service information about the processes and sign next to the node. The plugin is compiled for Linux, Windows. Houdini HDK 17.0 Plugin Link: https://drive.google.com/open?id=1KKri5K-m41ZRr4XukwqTYHmeGGz_e6f_
  22. Hi, I`m trying to create a SOP node, that basically does the same thing as the copytopoints SOP in Houdini but with a Box deformation added to it. Now I was able to copy the detail from the second Input into the gdp, but I find myself unable to access the newly added geo to actually offset it to the corresponding point in the first input. I want to add that I am a noobie when it comes to HDK (as you can probably see) and any help is much appreciated and thanks in advance. OP_ERROR SOP_copyPTs::cookMySop(OP_Context &context) { OP_AutoLockInputs inputs(this); if (inputs.lock(context) >= UT_ERROR_ABORT) return error(); const GU_Detail *firstGDP = inputGeo(0, context); const GU_Detail *secondGDP = inputGeo(1, context); UT_AutoInterrupt progress("still copying..."); duplicateSource(0, context); GA_RWHandleV3 Phandle(gdp->findAttribute(GA_ATTRIB_POINT, "P")); GA_Offset firstPToff; GEO_CopyMethod copymethod = GEO_COPY_ADD; GA_FOR_ALL_PTOFF(firstGDP, firstPToff) { if (progress.wasInterrupted()) break; gdp->copy(*secondGDP, copymethod, true, false, GA_DATA_ID_CLONE); UT_Vector3 Pvalue = Phandle.get(firstPToff); } Phandle.bumpDataId(); return error(); } i got it to work! (propably a pretty bad way to do it but it works) (orientation is working as well now but its not in the code down below) I am still very interested how experienced users would have written it. :S GA_FOR_ALL_PTOFF(firstGDP, gridPoints) { if (progress.wasInterrupted()) break; GU_Detail *newgdp = new GU_Detail(); GA_RWHandleV3 newPhandle(newgdp->findAttribute(GA_ATTRIB_POINT, "P")); newgdp->copy(*secondGDP, copymethod, true, false, GA_DATA_ID_CLONE); GA_Offset spherePoint; UT_Vector3 pointPos = Phandle.get(gridPoints); GA_FOR_ALL_PTOFF(newgdp, spherePoint) { UT_Vector3 spherePos = newPhandle.get(spherePoint); UT_Vector3 addedPos = spherePos + pointPos; newPhandle.set(spherePoint, addedPos); } gdp->copy(*newgdp, copymethod, true, false, GA_DATA_ID_CLONE); }
  23. I am asking because of this text in documentation (https://www.sidefx.com/docs/hdk/_h_d_k__intro__compiling.html#HDK_Intro_Compiling_CustomAllocators):
  24. I was working on some custom json nodes. I wanted to export some data using json format, so I did that like as follow in cookMySop: UT_JSONValueMap *rootMap = new UT_JSONValueMap; UT_JSONValue *floatV = new UT_JSONValue(35.0); rootMap->append("Value1", floatV); rootValue->setMap(rootMap);//rootValue is an object of UT_JSONValue rootValue->saveToFile("G:\\test.json"); after that, I wanted to remove temp exporting data: rootValue->setNull(); delete rootMap; rootMap = nullptr; delete floatV; floatV = nullptr; however, using "delete" caused an error. without "delete" everything works fine, but I am afraid there can be some memory leakage. is there something wrong?
  25. I'm looking for documentation or an example of creating a SOP with the HDK that can be used in a compiled "for each" loop, as described here: https://www.sidefx.com/tutorials/houdini-16-masterclass-compiled-sops/ Thanks!