SceneHook plugin queries

On 23/06/2013 at 07:56, xxxxxxxx wrote:

User Information:
Cinema 4D Version:   R14 
Platform:   Windows  ;   
Language(s) :     C++  ;

Hi Folks,

I may have a few queries on SceneHooks coming up, though am trying to work a few issues out myself first. But one that's always bugged me, and the first question for here:

why would a scenehook hold up things like selecting points/polygons etc? What should I use, and where, to prevent it from doing anything in these modes?

I can use GetMode() to get the docs mode etc, but I don't know how I can use that to make any difference when it comes to whether it runs or not. I only want the scenehook to be 'active' when in Mobject/Mmodel and when my plugin object is selected (which I can do by checking it's instance or getting it's type).



On 23/06/2013 at 15:10, xxxxxxxx wrote:

As stated in the API docs:

Note: Make sure that you only use this function when the user is somehow working with your plugin, so that other plugins can also use this hook when it's their turn.

In other words, when conditions are not met, get out as quickly as possible.  Check the mode and active selection at the very top of each method and exit as soon as conditions are not met.  That way, it will not impede other processes/threads.

On 23/06/2013 at 17:51, xxxxxxxx wrote:

How exactly do you "get out" of a Scene hook Robert?

Lets say for example that you have a tool plugin. And you use FindPlugin() to see if it's active. Then use a SceneHook plugin to poll the mouse while it's active. Just as an example.
How do we "exit" the SceneHook if the tool is no longer active?

It would be handy to see an example of something like that.


On 23/06/2013 at 18:07, xxxxxxxx wrote:

Get out of the SceneHook methods quickly.  Of course, a SceneHook is ALWAYS running.  Thus the reason to minimize its use of time and resources as extensively as possible.  If you are polling, you will need to check if the tool is the active one *every loop* of the poll.  That isn't a great way to minimize use but then if you want to use a SceneHook to track the mouse, don't expect to do much of anything else.  You may want to use a different methodology if it really freezes the system.  You should also check that the cursor is outside the viewport (if (mouse_x < 0.0)) as an escape to the polling.

On 23/06/2013 at 18:11, xxxxxxxx wrote:

// SceneHookData.Draw  
Bool IPPSceneHook::Draw(PluginSceneHook* node, BaseDocument* doc, BaseDraw* bd, BaseDrawHelp* bh, BaseThread* bt, SCENEHOOKDRAW flags)  
 if (CheckIsRunning(CHECKISRUNNING_EXTERNALRENDERING) || CheckIsRunning(CHECKISRUNNING_EDITORRENDERING))        return SceneHookData::Draw(node, doc, bd, bh, bt, flags);  
 if (!doc)                                        return SceneHookData::Draw(node, doc, bd, bh, bt, flags);  
 if (mouseX < 0.0)                                return SceneHookData::Draw(node, doc, bd, bh, bt, flags);  
 // Only Draw in Model or Object modes  
 LONG    mode =            doc->GetMode();  
 if (!((mode == Mmodel) || (mode == Mobject)))    return SceneHookData::Draw(node, doc, bd, bh, bt, flags);  
 if (doc->GetAction() == ID_IPPTOOL)                return SceneHookData::Draw(node, doc, bd, bh, bt, flags);  

On 23/06/2013 at 18:41, xxxxxxxx wrote:

Thanks Robert.

I thought maybe you were shutting it off somehow. Rather than keep it running in the background.


On 24/06/2013 at 09:02, xxxxxxxx wrote:

Thanks Robert,

a bit of a pity we have to test for things in every function. Not entirely convinced these scenehooks are as efficient as they could be. But anyway it's doing what's needed for now!

Thanks again,


On 06/07/2013 at 11:33, xxxxxxxx wrote:

Ok, amongst some of the mess I'm cleaning up in another topic... next query for the SH!

I'm trying to get a TRUE/FALSE return for the GeRayCollider->Intersect() in the SH's input to help me identify an object.

First question, will the GeRayCollider test for a class level variable poly object? I.e. can a class level poly object in the SH be used to test against with the ray?

Second, the SW() and SW_Reference() are a little confusing. If I want the ray to go from X,Y in screen space to some distance defined in the background (say 1,000,000 units directly behind the mouse click) which one do I use? Below is the code I'm using thus far:

Bool TestCollide = FALSE;   
AutoAlloc<GeRayCollider> Collider;   
Collider->Init(Cube, TRUE); // Cube is a class level PolyObj   
Vector RayStart = bd->SW(Vector(Move_X_Start, Move_Y_Start, 0));   
Vector RayEnd = bd->SW(Vector(Move_X_Start, Move_Y_Start, 100000000));   
Bool TestCollide = FALSE;   
TestCollide = Collider->Intersect(RayStart, RayEnd, 1, FALSE);   
GePrint("Collider value = " + LongToString(TestCollide)); // always returns FALSE..   
if(TestCollide){GePrint("Cube found!!");}   

But it always returns FALSE. The coords given are in screen space, they appear to be printing correct values. I'm only wishing to test for a TRUE/FALSE hit, I have no need for anything else. Is what I'm doing above right?



On 06/07/2013 at 11:51, xxxxxxxx wrote:

Coordinates for GeRayCollider must be in the object space of the object you initialized it with.   And to get the global matrix of an object, it must be in a document (BaseDocument).

// Invert the global matrix to put your ray and direction vectors into the Cube's local space  
Matrix img = !(Cube->GetMg());  
Vector RayStart = img * bd->SW(Vector(...));  
Vector RayDir = !(bd->SW(...)-RayStart) ^ img);

Oh, and the second argument for Intersect() is not the end of the ray but the normal direction vector!

On 28/07/2013 at 13:46, xxxxxxxx wrote:

Thanks or the clarification of the second Intersect() argument Robert.

I'm still having a problem with this though. I'm getting just about false returns on every click. I've noticed though, that the RayDirection vector is always Vector(0,0,0). Why is this?

From Robert's code above, I'm not using the bitwise ^ img at the end of the second vector because the object will always be at world 0,0,0. Is this an issue?

An update of what I'm using:

Vector RayStart = bd->SW(Vector(Move_X_Start, Move_Y_Start, 0));   
Vector RayDirection = bd->SW(Vector(Move_X_Start, Move_Y_Start, 1000000000)) - RayStart; // this returns (0,0,0)   
Bool TestCollide = FALSE;   
TestCollide = Collider->Intersect(RayStart, !RayDirection, 1000000000, FALSE); // this just about always returns false..   

When it does occasionally work, I appear to get the right results from the GeRayColResult. So might there be something I'm missing? Or is this bug ridden... or something else..

Thanks all,


EDIT: small update to code.

On 28/07/2013 at 15:35, xxxxxxxx wrote:

You MUST put the Vectors into local object space.  With the code you show, the only time you will get correct results is if the intersection object's transformations coincide with the global system.

For the ray direction, translation doesn't matter, only its orientation with respect to local object space (thus the use of ^ img).

// bd->SW() returns screen coordinates (your mouse position) converted into 3D world coordinates.  
// For the GeRayCollider, all coordinates must be local object coordinates (of the object in Init() below).  
// To do that, you take the object's global matrix, invert it and apply to coordinates in World space.  
Collider->Init(Cube, TRUE);  
Matrix img = !(myObject->GetMg());  
Vector RayStart = img * bd->SW(Vector(Move_X_Start, Move_Y_Start, 0));  
Vector RayDirection = (bd->SW(Vector(Move_X_Start, Move_Y_Start, 1000000000))) ^ img;  // this returns (0,0,0) - not anymore  
Bool TestCollide =  Collider->Intersect(RayStart, !RayDirection, 1000000000, FALSE);

On 29/07/2013 at 07:53, xxxxxxxx wrote:

Well, after getting increasingly frustrated, I was going to write another "it's not working" post!! But then I noticed that the values were not where I was clicking. This led me to think about how SW used the coords I was giving it. I had "win->Global2Local(&Move;_X_Start, &Move;_Y_Start);" after the GeRayCollider coding. It needed to be moved to before it. I think I was misunderstanding the terminology in "global/screen/world coordinates" and how they are initially returned.

I feel a bit annoyed at myself for not picking up on this earlier. Anyway, it appears to be working now. So I'll run with it while I can! Thanks Robert,