Spotlight Orientation

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?

Thanks in advance,

I don’t use the C++ SDK for my Cycles integration, but perhaps ON_Light::GetLightXform() does what you are looking for? There is also ON_Light::PerpendicularDirection().

Hi Nathan,

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)

Is this familiar at all?

I’ll chime @andy in here as well since he is much more familiar with the C++ SDK.

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

Hi @Nikos_Skiadas,

This is correct. as a spotlight is just a point and a direction vector.

Why do you need an up direction? What problem does this help you solve?

– Dale

Hi Dale,

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

Is there a reason you cannot take the cross product of the ON_Light::PerpindicularDirection() and ON_Light::Direction() to find your up direction?

Hi Joshua,

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.

Thank you all for your responses!

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.

While not an insignificant amount of work it should get you where you’re going.

1 Like

Hi Joshua,

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)

Still, we are in a much better place than before :slight_smile:

Again, thanks everyone!

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.

Learning one step at a time…

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.

Excellent! That worked (and was quite insightful in general)
Thank you