Hi,
for the purposes of the plugin I am working on (using the C++ SDK), I would like to be able to determine a local “up” vector for a spotlight
The light can be rolled (rotated around the direction vector) while editing, but to my knowledge there is no way to determine this from a CRhinoLight OR a ON_Light object.
Am I missing something considering the SDKs functionality? If not, is it something that is considered as an addition?
grateful for your response. GetLightXForm showed the most promise (I tried PerpendicularDirection), however it doesn’t seem to work: I tried retrieving the transform this way
ON_Xform lightXForm;
CRhinoView* view = RhinoApp().ActiveView();
bool result{ false };
if (view)
{
result = rLight.GetLightXform(view->ActiveViewport().VP(), ON::coordinate_system::world_cs, lightXForm);
}
but although result return value is true, lightXForm is always identity when used with ON::coordinate_system::world_cs (which I assume is the way to get the transformation in world space)
So, by peeking the ON code (from github), I realized that the case in question is likely not covered at all:
My spotlight is a world_spot_light (verified with List command from within Rhino)
The code for GetLightXform uses ON_Viewport::GetXform, which doesn’t seem to handle this light style for srcCS
Our plugin provides the possibility to add IES data to the light, so we are calculating a LookAt matrix in order to control the way the IES graph is “projected” to the environment: rolling the spotlight (rotating around the direction) is expected to have an effect to the highlight appearance
consider this case:
This is the initial position of the spotlight
Now, after rotating around the X axis, the PerpindicularDirection() I get is (1,0,0), which is valid
However, incrementally rotating around the (local?) Z axis, only seemingly yields this transform
but the PerpindicularDirection() I get from the call is still (1,0,0)
The effect I would expect when using IES is akin to rotating a flashlight around its length, and observing the (lens, lamp) irregularities projected in the lit area rotate as well
In any case, the PerpindicularDirection() gives a good-enough solution for the time, so I consider closing this issue.
I understand the issue. As @dale said the spotlight only tracks a position and direction. This makes getting a consistent transform from the object a bit of a pain. The ON_Light::PerpindicularDirection() is itself generated and not stored on the light. One solution is to attach custom user data to the spotlight.
This user data can then store a transform you generate from the position and direction when it is initially added. From there you can override ON_UserData::Transform to update your saved transform when the spotlight is manipulated.
thank you for the suggestion. I was indeed able to work around the issue using UserData to store a transformed up vector.
However, I still came across a Rhino limitation: ON_UserData::Transform gets called as a result of direct object manipulation only, so I am not able to monitor transformation changes caused by Undo/Redo via this path (we could implement it otherwise, but that discussion is outside the scope of this question)
It’s fine to discuss here as well. You might be interested in custom undo events.
You could get your owner object with ON_UserData::Owner and cast it to CRhinoObject assuming you stored it on the light object. From there you can get to the document through CRhinoObject::Document and add a custom undo event. Then when undo is called you can restore the previous transform.
Like the custom user data it is not a quick fix, but you’ll be able handle Undo/Redo correctly.
I managed to setup the undo logic by calling AddCustomUndoEvent at the time of transformation. CRhinoUndoEventHandler::Undo in my derived class does indeed get called on user triggering Undo. However, I don’t seem to get some “symmetrical” effect for Redo. I assumed that Undo would be yet called again, with flag bCreatedByRedo set to true (or something similar), but apparently this is not the case
That’s correct. This is a bit awkward but you should add your custom undo event during the CRhinoUndoEventHandler::Undo call that will handle the redo. In your case this will be the transform that is about to be replaced by the undo.