[HDK] Any GUI_PrimitiveHook example?

   17821   40   0
User Avatar
Member
678 posts
Joined: July 2005
Offline
Does anyone have working example? Can it be added to HDK help for reference?

Thanks
User Avatar
Staff
5154 posts
Joined: July 2005
Offline
The prim tetra example in toolkit/samples has an example of how to use GUI_PrimitiveHook (and GR_Primitive).
User Avatar
Member
678 posts
Joined: July 2005
Offline
I'm on it! Thanks!
User Avatar
Member
678 posts
Joined: July 2005
Offline
I stripped all the code that I think I don't need from Tetra example but it seems that I'm missing something because it doesn't want to even register itself (and it doesn't show any errors too).

GR_GUIPrimitiveHook_template.h

#ifndef __GR_GUI_PRIMITIVE_HOOK_H_
#define __GR_GUI_PRIMITIVE_HOOK_H_

#include <GUI/GUI_PrimitiveHook.h>
#include <GR/GR_Primitive.h>

#include <GT/GT_GEOPrimitive.h>
#include <DM/DM_RenderTable.h>
#include <RE/RE_ElementArray.h>
#include <RE/RE_Geometry.h>
#include <RE/RE_LightList.h>
#include <RE/RE_ShaderHandle.h>
#include <RE/RE_VertexArray.h>

#define THIS_HOOK_NAME “GR_GUIPrimitiveHook_Template”
#define THIS_PRIMITIVE_NAME “GR_Primitive_Template”

namespace Mantragora
{
namespace Viewport
{
// primitive
class GR_Primitive_Template : public GR_Primitive
{
public:
GR_Primitive_Template(const GR_RenderInfo* info, const char* cache_name, const GEO_Primitive* prim);
virtual ~GR_Primitive_Template();
virtual const char* className() const;

virtual GR_PrimAcceptResult acceptPrimitive(GT_PrimitiveType t, int geo_type, const GT_PrimitiveHandle& ph, const GEO_Primitive* prim);
virtual void resetPrimitives();

virtual void update(RE_Render* r, const GT_PrimitiveHandle& primh, const GR_UpdateParms& p);
virtual void render(RE_Render* r, GR_RenderMode render_mode, GR_RenderFlags flags, const GR_DisplayOption* opt, const RE_MaterialList* materials);

private:
int _myID;
RE_Geometry* _myGeo;

bool _ogl3;
};

// hook
class GR_GUIPrimitiveHook_Template : public GUI_PrimitiveHook
{
public:
GR_GUIPrimitiveHook_Template();
virtual ~GR_GUIPrimitiveHook_Template();
virtual GR_Primitive* createPrimitive(const GT_PrimitiveHandle& gt_prim, const GEO_Primitive* geo_prim, const GR_RenderInfo* info, const char* cache_name, GR_PrimAcceptResult& processed);
};
}
}

#endif


GR_GUIPrimitiveHook_template.cpp

#include “GR_GUIPrimitiveHook_template.h”
#include <ostream>

using namespace Mantragora::Viewport;
using std::cout;
using std::endl;

// hook registration ————————————————————————
void newRenderHook(DM_RenderTable *table)
{
cout << “registering!” << endl;
const int prim_hook_priority = 0;

table->registerGEOHook(new GR_GUIPrimitiveHook_Template,
GA_PrimitiveTypeId(GA_PRIMPOLYSOUP),
prim_hook_priority);
}

// hook initialization ————————————————————————
GR_GUIPrimitiveHook_Template::GR_GUIPrimitiveHook_Template(): GUI_PrimitiveHook(THIS_HOOK_NAME)
{
cout << “constructor!” << endl;
}
GR_GUIPrimitiveHook_Template::~GR_GUIPrimitiveHook_Template() {}
GR_Primitive* GR_GUIPrimitiveHook_Template::createPrimitive(const GT_PrimitiveHandle& gt_prim, const GEO_Primitive* geo_prim, const GR_RenderInfo* info, const char* cache_name, GR_PrimAcceptResult& processed)
{
cout << “creating primitive!” << endl;
return new GR_Primitive_Template(info, cache_name, geo_prim);
}

// primitive initialization ————————————————————————
GR_Primitive_Template::GR_Primitive_Template(const GR_RenderInfo* info, const char* cache_name, const GEO_Primitive* prim): GR_Primitive(info, cache_name, GA_PrimCompat::TypeMask(0))
{
cout << “primitive initialization!” << endl;
_myID = prim->getTypeId().get();
_myGeo = NULL;
}
GR_Primitive_Template::~GR_Primitive_Template() { delete _myGeo; }
const char* GR_Primitive_Template::className() const { return THIS_PRIMITIVE_NAME; }

GR_PrimAcceptResult GR_Primitive_Template::acceptPrimitive(GT_PrimitiveType t, int geo_type, const GT_PrimitiveHandle& ph, const GEO_Primitive* prim)
{
cout << “accept primitive!” << endl;

if (geo_type == _myID)
{
cout << “processing!” << endl;
return GR_PROCESSED;
}

return GR_NOT_PROCESSED;
}

void GR_Primitive_Template::resetPrimitives() {}

// main() ————————————————————————
void GR_Primitive_Template::update(RE_Render* r, const GT_PrimitiveHandle& primh, const GR_UpdateParms& p)
{
cout << “update!” << endl;
}
void
GR_Primitive_Template::render(RE_Render* r, GR_RenderMode render_mode, GR_RenderFlags flags, const GR_DisplayOption* opt, const RE_MaterialList* materials)
{
cout << “render!” << endl;
}


I checked it with HDK documentation and it looks that it should work, so what am I missing ?

Can you guys give us a little smaller example than Tertra that also uses newRenderHook() directly instead of registerMyself()? You know, something that uses native primitives and have less than 11 files
User Avatar
Staff
5154 posts
Joined: July 2005
Offline
I'm not in front of a system with Houdini on it this week, so I'm afraid I can't test your code. When you say it isn't registering, do you mean that newRenderHook isn't being called? Try including UT_Version.h and see if that helps. Also set the env variable HOUDINI_DSO_ERROR to 1 to see if any errors are being generated when Houdini starts.

If it is registering but not creating a primitive, I suspect that the iterative detail refinement process is somehow not reaching the GEO_PrimPolySoup point, somehow being caught befoby a native primitive before your hook has processed it. I'll take a look when I'm back in the office next week.

Adding a simple example or two would be a good idea. There are a lot of DM scene hooks, but the primitive hooks are a bit sparse.
User Avatar
Member
678 posts
Joined: July 2005
Offline
twod
Try including UT_Version.h and see if that helps. Also set the env variable HOUDINI_DSO_ERROR to 1 to see if any errors are being generated when Houdini starts.

UT_Version.h didn't help but HOUDINI_DSO_ERROR did and told me that it should be UT_DSOVersion.h . Thank you.

twod
If it is registering but not creating a primitive, I suspect that the iterative detail refinement process is somehow not reaching the GEO_PrimPolySoup point, somehow being caught befoby a native primitive before your hook has processed it. I'll take a look when I'm back in the office next week.

After adding UT_DSOVersion.h I still don't get any output from it on any stage. It doesn't cout from newRenderHook() or any other place.

twod
Adding a simple example or two would be a good idea. There are a lot of DM scene hooks, but the primitive hooks are a bit sparse.

Yeah. Example how to replace rendering of native primitive or how to add decorations/extend rendering of native primitive would be great.
User Avatar
Member
678 posts
Joined: July 2005
Offline
twod
…I'll take a look when I'm back in the office next week.

Adding a simple example or two would be a good idea. There are a lot of DM scene hooks, but the primitive hooks are a bit sparse.

Any news on this topic?
User Avatar
Staff
5154 posts
Joined: July 2005
Offline
The reason that your hook is not registering is because the newRenderHook() function takes a GR_RenderHook * parameter, not a DM_RenderHook *. In order to support both H11 and the GL viewports, the GR_RenderHook * parameter was maintained. However, it will always be a DM_RenderHook object passed, so you can safely cast it to a DM_RenderHook.

Currently it is not possible to hook on a polysoup, as this is running into problems with polygon collection, which combines all polygon-based primitives into a large soup for rendering. We'll look into patching this for the next major version of Houdini (a backport might be possible).
User Avatar
Member
678 posts
Joined: July 2005
Offline
twod
The reason that your hook is not registering is because the newRenderHook() function takes a GR_RenderHook * parameter, not a DM_RenderHook *. In order to support both H11 and the GL viewports, the GR_RenderHook * parameter was maintained. However, it will always be a DM_RenderHook object passed, so you can safely cast it to a DM_RenderHook.

OK. I'm soo totally lost after what you said here.

There are two versions of “newRenderHook()” function, one takes “GR_RenderTable*” and second “DM_RenderTable*”. I don't see any overloaded version that takes “GR_RenderHook*” or “DM_RenderHook*” so I suppose I'm missing some very important part here.

BTW. Is there “DM_RenderHook” class at all anywhere in HDK? Are you guys have part there
Edited by - Sept. 9, 2013 16:02:13
User Avatar
Staff
5154 posts
Joined: July 2005
Offline
Sorry, brain apparently took awhile to get moving this morning. Instead of “_RenderHook”, I meant “_RenderTable”. Corrected:
The reason that your hook is not registering is because the newRenderHook() function takes a GR_RenderTable * parameter, not a DM_RenderTable *. In order to support both H11 and the GL viewports, the GR_RenderTable * parameter was maintained. However, it will always be a DM_RenderTable object passed, so you can safely cast it to a DM_RenderTable.

So, just change your newRenderHook() method to:
void newRenderHook(GR_RenderTable *table)
{
cout << “registering!” << endl;
const int prim_hook_priority = 0;

static_cast<DM_RenderTable *>(table)->registerGEOHook(new GR_GUIPrimitiveHook_Template,
GA_PrimitiveTypeId(GA_PRIMPOLYSOUP),
prim_hook_priority);
}
User Avatar
Member
678 posts
Joined: July 2005
Offline


Thank you and have a good day.
User Avatar
Member
678 posts
Joined: July 2005
Offline
It's alive… well, partially.

It does register but doesn't call “createPrimitive()” and since it's the only virtual method (beside destructor) that I can mess with inside the hook and it only returns “new GR_Primitive_Template”, I suppose “priority” parameter may have something to do with lack of any other sign from the hook. I tried setting it from 0 to 10 but nothing changed. Should I set it to something else ?

twod
If it is registering but not creating a primitive, I suspect that the iterative detail refinement process is somehow not reaching the GEO_PrimPolySoup point, somehow being caught befoby a native primitive before your hook has processed it. I'll take a look when I'm back in the office next week.

Yup, this is what I got.
User Avatar
Member
678 posts
Joined: July 2005
Offline
twod
If it is registering but not creating a primitive, I suspect that the iterative detail refinement process is somehow not reaching the GEO_PrimPolySoup point, somehow being caught befoby a native primitive before your hook has processed it. I'll take a look when I'm back in the office next week.

I think that without working example that shows how to replace shading of native primitive I will not move this rock. It doesn't even touch createPrimitive() method.

It would be good to update documentation also because it still shows newRenderHook() version of the code that doesn't work, so if someone would like to follow (and doesn't know this topic) will hit the same wall as me.
User Avatar
Member
678 posts
Joined: July 2005
Offline
I made couple more tests with Tetra example.
1. Modified GU_PrimTetra::registerMyself() method by moving DM_RenderTable::getTable()->registerGEOHook() to newRenderHook() that I added to GR_PrimTetra.C.
2. Instead of PrimTetra id I passed GA_PrimitiveTypeId(GEO_PRIMPOLY) to registerGEOHook()

Questions:
As I understand, by passing different ID to registerGEOHook(), it should now react to any polygonal geometry that I place because of GEO_PRIMPOLY passed instead of PrimTetra ID, but it still reacts only when I place PrimTetra node. Why is that?

I uncommented TETRA_GR_PRIMITIVE and TETRA_GR_PRIM_COLLECTION in tetra example so it should use Hook for rendering and creating primitive, but it doesn't look like it because it also never reaches createPrimitive() method and after primitive detection jumps to GU_PrimTetra::build() method. Why?

I really would be very grateful for native primitive example.
User Avatar
Staff
5154 posts
Joined: July 2005
Offline
There are now two examples and a template GUI class with documentation in H13. It's also now possible to hook on GEO primitives which the GT refinement classes would otherwise consume. It doesn't look like it can be backported to 12.5, but let me know if this is a showstopper and I'll see what can be done.
User Avatar
Member
678 posts
Joined: July 2005
Offline
Thank you. I'm not in Houdini last two weeks at all so I will check it when I have opportunity to come back to it.
User Avatar
Member
678 posts
Joined: July 2005
Offline
Ok, we are back in game. I didn't checked examples yet but even the code above reported correctly from update() and render() in H13. Thanks.
User Avatar
Member
678 posts
Joined: July 2005
Offline
Couple questions.

1. Lets start from registration. If I don't want to modify my geometry but just change its color, should I pass GUI_HOOK_FLAG_AUGMENT_PRIM? Will it be sufficient?

2. Now we are in update(). Is there a way to process copy of geometry there without building array of points and rebuilding everything again?

3. If I want to have different color on each of my polygon, can I send multiple primitives from update in a group and then shade each differently in my custom shade function (by accessing my RE_Geometry* and comparing some stuff there) before they will get shaded, or should I just send each polygon separately and process one by one?
User Avatar
Staff
5154 posts
Joined: July 2005
Offline
1. Lets start from registration. If I don't want to modify my geometry but just change its color, should I pass GUI_HOOK_FLAG_AUGMENT_PRIM? Will it be sufficient?
“Augment Prim” is meant to add additional custom rendering on top of a native Houdini primitive that is already rendering in the viewport. For example, if you wanted to add custom rendering to a volume primitive, such as a vector field, while letting Houdini render the volume.

If you're doing all the rendering yourself, you don't want AUGMENT_PRIM.

2. Now we are in update(). Is there a way to process copy of geometry there without building array of points and rebuilding everything again?
Currently no, though certain update reasons can allow you to keep a good chunk of your vertex arrays intact (GR_GEO_SELECTION_CHANGED, GR_INSTANCE_PARMS_CHANGED). Generally on GR_GEO_CHANGED and GR_GEO_TOPOLOGY_CHANGED (which you will currently always get together), you'll have to rebuild your geometry.

There is some infrastructure in place in GEO/GR to determine if a given attribute has changed (GA_Attribute::getDataId()/assignNewDataId()/bumpDataId()). However, this requires SOP support, which wasn't able to be addressed before the H13 release buzzer went off. This will be hopefully be addressed soon. If you have a custom SOP and can figure out which attributes need updating, you can program this into the SOP itself (which is a topic unto itself).

Alembic primitives currently use this DataID system (via GT_DataArray::getDataId()). However, because Alembic primitives do not create GU_Details (they directly create GT_Primitives), any custom hooks that hook on GEO_Primitives won't be called.

3. If I want to have different color on each of my polygon, can I send multiple primitives from update in a group and then shade each differently in my custom shade function (by accessing my RE_Geometry* and comparing some stuff there) before they will get shaded, or should I just send each polygon separately and process one by one?
You really don't want to draw polygons one by one. GL will hate you The way our stuff handles multiple materials is to partition the polygons into different connection groups (see RE_Geometry::connect*PrimsI() methods). Then the draw code cycles through the materials and draws group-by-group. If you have a small palette of colors, that might be an acceptable solution (push color, draw group, push next color, draw group, etc).

If your polygon colors are instead essentially random, you can also send the polygon color to the shader directly. It's important to note that OpenGL does not support primitive attributes directly, nor can you easily look up a gl_PrimitiveID for a polygon (GL likes triangles). So, you can go the GL2 route and send the position/color pair for every vertex in the polygon, which adds up quickly for large meshes.

Or, you can go the GL3 route and use a textureBuffer and index it with gl_PrimitiveID. The trick there is that you need to first convert your polygons to triangles. If they're already triangles, you're in luck - you just need to do a texelFetch(attrCd, gl_PrimitiveID) in the shader. If they're quads tessellated to triangles, it's texelFetch(attrCd, gl_PrimitiveID/2). Variable-sided polygons are the most tricky, as you then need to tessellate each one to triangles and repeat the color for each triangle in the polygon, then index with gl_PrimitiveID.

You can create a primitive attribute in RE_Geometry:

(RE_Geometry*)->setNumPrimitives( num_color_entries );
Cd = (RE_Geometry*)->createAttribute(r, “Cd”, RE_GPU_FLOAT32, 3, col_data, RE_ARRAY_PRIMITIVE);
where col_data is sizeof(float)*3*num_color_entries long, and then access this in the fragment shader via:

uniform samplerBuffer attrCd;
….
vec3 Cd = texelFetch(attrCd, gl_PrimitiveID).rgb;

You'll need to use at least #version 140 or #extension GL_EXT_gpu_shader4 : enable for that shader to compile correctly.

Vertex attributes can be index in a similar fashion (gl_PrimitiveIDIn*3), but you need a geometry shader to process the triangle and emit each vertex with a different color. Point and Detail attributes are definitely the easiest to work with.
User Avatar
Member
678 posts
Joined: July 2005
Offline
There are three overloaded versions of connectIndexedPrimsI().

I'm recreating geometry and switch()-ing based on how many points my polygon have to add it to correct group.
I don't have problem with specifying how my prims should be connected for knows polygons. I know that I may have quads so I pass how they should be connected ({0,1, 1,2, 2,3, 3,0}). The problem starts when I get N-gons. I can construct array automatically but this method needs const array so I can't compile because size of this array is unknown on runtime.

Two other versions of this function takes RE_ElementArray and RE_VertexArray, but I don't know how to use them.

So how to approach reconstruction of N-gons?
  • Quick Links