MATLAB: How to make camera light follow 3D Rotation

2.1k views Asked by At

I have come into a problem recently when trying to rotate 3D objects. I am building a GUI and I have a separate figure where an object is plotted. In the figure, I allow the user to use MATLAB's built-in rotate button to move the object around. However, I am unable to have the light also follow the rotation as it seems to be fixed on one part of the object. To create the light, I am using

c=camlight('right');
set(c,'style','infinite');

One solution I have thought of is to add light whenever the user releases the rotate button, but this is not very nice. I also do not know how to use the rotate callbacks when the button is in a separate figure.

Does anyone know how to make the light "track" the 3D rotation, so that the current view is illuminated?

Thanks!

1

There are 1 answers

4
Matt On BEST ANSWER

Implement own rotation functionality

You can implement an own functionality to adjust the axes and the lights at the same time. This way the light gets adjusted continuously while rotating the axes.

function follow_me_1
    figure
    axes('buttondownfcn', @buttondownfcn);  % assign callback
    set(gca,'NextPlot','add');              % add next plot to current axis
    surf(peaks,'hittest','off');            % hittest -> off is important
    view(3);                                % view to start from
    c = camlight('headlight');              % add light
    set(c,'style','infinite');              % set style of light

    function buttondownfcn(ax,~)
        fig = ancestor(ax,'figure');        % get figure handle
        [oaz, oel] = view(ax);              % get current azimuth and elevation
        oloc = get(0,'PointerLocation');    % get starting point
        set(fig,'windowbuttonmotionfcn',{@rotationcallback,ax,oloc,oaz,oel});
        set(fig,'windowbuttonupfcn',{@donecallback});
    end

    function rotationcallback(~,~,ax,oloc,oaz,oel)
        locend = get(0, 'PointerLocation'); % get mouse location
        dx = locend(1) - oloc(1);           % calculate difference x
        dy = locend(2) - oloc(2);           % calculate difference y
        factor = 2;                         % correction mouse -> rotation
        newaz = oaz-dx/factor;              % calculate new azimuth
        newel = oel-dy/factor;              % calculate new elevation
        view(ax,newaz,newel);               % adjust view
        c = camlight(c,'headlight');        % adjust light
    end

    function donecallback(src,~)
        fig = ancestor(src,'figure');           % get figure handle
        set(fig,'windowbuttonmotionfcn',[]);    % unassign windowbuttonmotionfcn
        set(fig,'windowbuttonupfcn',[]);        % unassign windowbuttonupfcn
    end

end

Using rotate3d

This example uses the built-in rotate3d and assigned callback functions. This is the 'not very nice'-solution but takes only some lines of code.

function follow_me_2
    surf(peaks);                  % Load demo data
    c = camlight('headlight');    % Create light
    set(c,'style','infinite');    % Set style
    h = rotate3d;                 % Create rotate3d-handle
    h.ActionPostCallback = @RotationCallback; % assign callback-function
    h.Enable = 'on';              % no need to click the UI-button

    % Sub function for callback
    function RotationCallback(~,~)
        c = camlight(c,'headlight');
    end
end