I got some troubles while creating a custom VEX function via HDK.
I need to access geometry data inside the function at different frame on specific node inside my custom C++ function which should be used by VEX and I used two methods for doing this:
- Using GU_SopQuery class to access geometry data on the given node address in for example "op:/obj/geo1/OUT_Volume" format.
Here is the sample:#include <iostream> #include <VEX/VEX_VexOp.h> #include <OP/OP_Director.h> #include <GU/GU_Detail.h> #include <SOP/SOP_Node.h> #include <GEO/GEO_VolumeSampler.h> #include <GU/GU_PrimVolume.h> #include <GU/GU_SopResolver.h> template <VEX_Precision PREC> static void wetmap(int argc, void *argv[], void *) { const char *surfaceAddress = static_cast<const char *>(argv[0]); const VEXvec3<PREC> *P = static_cast<const VEXvec3<PREC>*>(argv[1]); const VEXvec3<PREC> *Cd = static_cast<const VEXvec3<PREC>*>(argv[2]); VEXvec3<PREC> *resultCd = static_cast<VEXvec3<PREC>*>(argv[3]); *resultCd = *Cd; exint currentFrame = CHgetFrameFromTime(CHgetEvalTime()); GU_SopQuery quary; for (exint frame = currentFrame; frame > 0; --frame) { quary.setFrame(frame); GU_ConstDetailHandle handle = quary.getDetail(surfaceAddress); if (handle.isValid()) { const GU_Detail *gdp = handle.gdp(); const GEO_PrimVolume* volume = static_cast<const GEO_PrimVolume *>(gdp->getGEOPrimitive(0)); if (volume != nullptr) { GEO_VolumeSampler volumeSampler{volume}; *resultCd = volumeSampler.getValueF(*P); } } } } void newVEXOp(void *) { using UT::Literal::operator""_sh; new VEX_VexOp("wetness@SVV&V"_sh, // Signature wetmap<VEX_32>, // Evaluator 32 wetmap<VEX_64> // Evaluator 64 ); }
- Creating a OP_Context instance at specific frame and pass it to SOP_Node::getCookedGeoHandle function to access to geometry data.
Here is the sample:#include <iostream> #include <VEX/VEX_VexOp.h> #include <OP/OP_Director.h> #include <GU/GU_Detail.h> #include <SOP/SOP_Node.h> #include <GEO/GEO_VolumeSampler.h> #include <GU/GU_PrimVolume.h> #include <GU/GU_SopResolver.h> template <VEX_Precision PREC> static void wetmap(int argc, void *argv[], void *) { const char * surfaceAddress = static_cast<const char *>(argv[0]); VEXvec3<PREC> *P = static_cast<VEXvec3<PREC>*>(argv[1]); VEXvec3<PREC> *Cd = static_cast<VEXvec3<PREC>*>(argv[2]); VEXvec3<PREC> *resultCd = static_cast<VEXvec3<PREC>*>(argv[3]); *resultCd = *Cd; SOP_Node *sufaceNode = OPgetDirector()->findSOPNode(surfaceAddress); OP_Context context{OP_Context::CurrentEvalTime}; exint currentFrame = context.getFrame(); if(sufaceNode != nullptr) { GEO_VolumeSampler volume; GU_DetailHandle gd_handle = sufaceNode->getCookedGeoHandle(context); if(!gd_handle.isNull()) { const GU_Detail* gdp = gd_handle.gdp(); const GEO_PrimVolume* volume = static_cast<const GEO_PrimVolume *>(gdp->getGEOPrimitive(0)); GEO_VolumeSampler volumeSampler{volume}; if (volume != nullptr) { for (exint i = currentFrame; i > 0; --i) { fpreal sample = volumeSampler.getValueF(*P); *resultCd = sample; } } } } } void newVEXOp(void *) { using UT::Literal::operator""_sh; new VEX_VexOp("wetness@SVV&V"_sh, // Signature wetmap<VEX_32>, // Evaluator 32 wetmap<VEX_64> // Evaluator 64 ); }
The FPS for the first method on my machine while playing is around 3 and for the second method is around 10.
Since we can't access geometry data in VEX directly I write similar code in VEX just for a rough comparison with HDK versions.
The FPS for pure VEX version is around 20!
Here is the VEX code:
for (int i = int(@Frame); i > 0; --i) { v@Cd = volumesample(chs("address"), 0, v@P); }
Thank you so much!