Camera and view function and properties

12 views (last 30 days)
I've been trying to understand the view and camera functions and created the following code for illustration:
peaks(30);
ax=get(gca);
% Display values
disp('Initial values')
dispprops(ax)
% Change target
ax.CameraTarget = [0 0 10];
disp('Target changed by property')
dispprops(ax)
camtarget([0 0 20])
disp('Target changed by function')
dispprops(ax)
% Change position
ax.CameraPosition = [-30 -40 70];
disp('Position changed by property')
dispprops(ax)
campos([-30 -40 80])
disp('Position changed by function')
dispprops(ax)
% Change view
ax.View = [45 90];
disp('View changed by property')
dispprops(ax)
view([60 60])
disp('View changed by function')
dispprops(ax)
function dispprops(ax)
viewfromax = ax.View %#ok
[azfromfun,elfromfun] = view;
disp(['viewfromfun = ' num2str(azfromfun) ',' num2str(elfromfun)])
posfromax = ax.CameraPosition %#ok
disp(['posfromfun = ' num2str(campos)])
targetfromax = ax.CameraTarget %#ok
disp(['targetfromfun = ' num2str(camtarget)])
end
There are two things that seem odd to me:
1) Changes via the ax properties are stored, but don't do anything in the plot (even if the respective modes are set to manual). On the other hand, changes via functions are not stored in the properties, but do modify the plot. So what are the properties actually good for?
2) Changes to position and target do not change the view values, but view on the other hand does change target and position. Shouldn't the dependency be mutual? I. e. aren't azimuth and elevation determined by camera position and target (since target and position are independent from each other, c. f. https://mathworks.com/help/matlab/creating_plots/defining-scenes-with-camera-graphics.html)?

Accepted Answer

Voss
Voss on 1 Apr 2022
Edited: Voss on 1 Apr 2022
When you do
ax = get(gca);
you are storing the axes properties in a struct called ax. (In this case these are the initial properties of the axes, since you do this before anything else.) Setting values of fields in ax doesn't affect the axes itself:
ax.View
ans = 1×2
0 90
ax.View = [0 0]
ax = struct with fields:
CameraPosition: [0.5000 0.5000 9.1603] CameraPositionMode: 'auto' CameraTarget: [0.5000 0.5000 0.5000] CameraTargetMode: 'auto' CameraUpVector: [0 1 0] CameraUpVectorMode: 'auto' CameraViewAngle: 6.6086 CameraViewAngleMode: 'auto' View: [0 0] Projection: 'orthographic' LabelFontSizeMultiplier: 1.1000 AmbientLightColor: [1 1 1] DataAspectRatio: [1 1 1] DataAspectRatioMode: 'auto' PlotBoxAspectRatio: [1 0.7897 0.7897] PlotBoxAspectRatioMode: 'auto' FontName: 'Helvetica' FontAngle: 'normal' FontWeight: 'normal' FontSmoothing: on TickLabelInterpreter: 'tex' XLim: [0 1] XLimMode: 'auto' YLim: [0 1] YLimMode: 'auto' ZLim: [0 1] ZLimMode: 'auto' XLimitMethod: 'tickaligned' YLimitMethod: 'tickaligned' ZLimitMethod: 'tickaligned' XDir: 'normal' YDir: 'normal' ZDir: 'normal' CLim: [0 1] CLimMode: 'auto' ALim: [0 1] ALimMode: 'auto' Colormap: [256×3 double] Alphamap: [0 0.0159 0.0317 0.0476 0.0635 0.0794 0.0952 0.1111 0.1270 0.1429 0.1587 0.1746 0.1905 0.2063 0.2222 0.2381 0.2540 0.2698 0.2857 0.3016 0.3175 0.3333 0.3492 0.3651 0.3810 0.3968 0.4127 0.4286 0.4444 0.4603 0.4762 0.4921 … ] Layer: 'bottom' TickLength: [0.0100 0.0250] GridLineStyle: '-' MinorGridLineStyle: ':' XAxisLocation: 'bottom' XColor: [0.1500 0.1500 0.1500] XColorMode: 'auto' XTick: [0 0.2000 0.4000 0.6000 0.8000 1] XTickMode: 'auto' XTickLabelRotation: 0 XTickLabelRotationMode: 'auto' XLabel: [1×1 Text] XScale: 'linear' XTickLabel: {6×1 cell} XTickLabelMode: 'auto' XMinorTick: off YAxisLocation: 'left' YColor: [0.1500 0.1500 0.1500] YColorMode: 'auto' YTick: [0 0.1000 0.2000 0.3000 0.4000 0.5000 0.6000 0.7000 0.8000 0.9000 1] YTickMode: 'auto' YTickLabelRotation: 0 YTickLabelRotationMode: 'auto' YLabel: [1×1 Text] YScale: 'linear' YTickLabel: {11×1 cell} YTickLabelMode: 'auto' YMinorTick: off ZColor: [0.1500 0.1500 0.1500] ZColorMode: 'auto' ZTick: [0 0.5000 1] ZTickMode: 'auto' ZTickLabelRotation: 0 ZTickLabelRotationMode: 'auto' ZLabel: [1×1 Text] ZScale: 'linear' ZTickLabel: '' ZTickLabelMode: 'auto' ZMinorTick: off BoxStyle: 'back' LineWidth: 0.5000 Color: [1 1 1] ClippingStyle: '3dbox' CurrentPoint: [2×3 double] ColorScale: 'linear' AlphaScale: 'linear' Title: [1×1 Text] TitleHorizontalAlignment: 'center' Subtitle: [1×1 Text] XAxis: [1×1 NumericRuler] ZAxis: [1×1 NumericRuler] XGrid: off XMinorGrid: off YGrid: off YMinorGrid: off ZGrid: off ZMinorGrid: off YAxis: [1×1 NumericRuler] Units: 'normalized' Position: [0.1300 0.1100 0.7750 0.8150] InnerPosition: [0.1300 0.1100 0.7750 0.8150] OuterPosition: [0 0 1 1] PositionConstraint: 'outerposition' TightInset: [0.0459 0.0543 0.0182 0.0208] ColorOrder: [7×3 double] ColorOrderIndex: 1 LineStyleOrder: '-' LineStyleOrderIndex: 1 NextSeriesIndex: 1 FontUnits: 'points' FontSize: 10 FontSizeMode: 'auto' TitleFontWeight: 'bold' SubtitleFontWeight: 'normal' TitleFontSizeMultiplier: 1.1000 SortMethod: 'childorder' TickDir: 'in' TickDirMode: 'auto' GridColor: [0.1500 0.1500 0.1500] GridColorMode: 'auto' MinorGridColor: [0.1000 0.1000 0.1000] MinorGridColorMode: 'auto' GridAlpha: 0.1500 GridAlphaMode: 'auto' MinorGridAlpha: 0.2500 MinorGridAlphaMode: 'auto' Clipping: on NextPlot: 'replace' Toolbar: [1×1 AxesToolbar] Interactions: [1×1 matlab.graphics.interaction.interface.DefaultAxesInteractionSet] Box: off Children: [0×0 GraphicsPlaceholder] Parent: [1×1 Figure] Visible: on HandleVisibility: 'on' Layout: [0×0 matlab.ui.layout.LayoutOptions] ButtonDownFcn: '' ContextMenu: [0×0 GraphicsPlaceholder] BusyAction: 'queue' BeingDeleted: off Interruptible: on CreateFcn: '' DeleteFcn: '' Type: 'axes' Tag: '' UserData: [] Selected: off SelectionHighlight: on HitTest: on PickableParts: 'visible' Legend: [0×0 GraphicsPlaceholder]
% actual View is still [0 90] because 'View' was set
% in ax, which is a copy of the axes properties
get(gca,'View')
ans = 1×2
0 90
Store the axes itself instead:
ax = gca;
and the properties will be accurate after they are set, regardless of how they are set.
peaks(30);
z = 3*(1-x).^2.*exp(-(x.^2) - (y+1).^2) ... - 10*(x/5 - x.^3 - y.^5).*exp(-x.^2-y.^2) ... - 1/3*exp(-(x+1).^2 - y.^2)
% ax=get(gca);
ax = gca;
% Display values
disp('Initial values')
Initial values
dispprops(ax)
viewfromax = 1×2
-37.5000 30.0000
viewfromfun = -37.5,30
posfromax = 1×3
-27.3943 -35.7009 63.3693
posfromfun = -27.3943 -35.7009 63.3693
targetfromax = 1×3
0 0 0.7954
targetfromfun = 0 0 0.7954
% Change target
ax.CameraTarget = [0 0 10];
disp('Target changed by property')
Target changed by property
dispprops(ax)
viewfromax = 1×2
-37.5000 30.0000
viewfromfun = -37.5,30
posfromax = 1×3
-27.3943 -35.7009 63.3693
posfromfun = -27.3943 -35.7009 63.3693
targetfromax = 1×3
0 0 10
targetfromfun = 0 0 10
camtarget([0 0 20])
disp('Target changed by function')
Target changed by function
dispprops(ax)
viewfromax = 1×2
-37.5000 30.0000
viewfromfun = -37.5,30
posfromax = 1×3
-27.3943 -35.7009 63.3693
posfromfun = -27.3943 -35.7009 63.3693
targetfromax = 1×3
0 0 20
targetfromfun = 0 0 20
% Change position
ax.CameraPosition = [-30 -40 70];
disp('Position changed by property')
Position changed by property
dispprops(ax)
viewfromax = 1×2
-37.5000 30.0000
viewfromfun = -37.5,30
posfromax = 1×3
-30 -40 70
posfromfun = -30 -40 70
targetfromax = 1×3
0 0 20
targetfromfun = 0 0 20
campos([-30 -40 80])
disp('Position changed by function')
Position changed by function
dispprops(ax)
viewfromax = 1×2
-37.5000 30.0000
viewfromfun = -37.5,30
posfromax = 1×3
-30 -40 80
posfromfun = -30 -40 80
targetfromax = 1×3
0 0 20
targetfromfun = 0 0 20
% Change view
ax.View = [45 90];
disp('View changed by property')
View changed by property
dispprops(ax)
viewfromax = 1×2
45 90
viewfromfun = 45,90
posfromax = 1×3
0 0 125.9431
posfromfun = 0 0 125.9431
targetfromax = 1×3
0 0 0.7954
targetfromfun = 0 0 0.7954
view([60 60])
disp('View changed by function')
View changed by function
dispprops(ax)
viewfromax = 1×2
60 60
viewfromfun = 60,60
posfromax = 1×3
22.5000 -12.9904 109.1765
posfromfun = 22.5 -12.99038 109.1765
targetfromax = 1×3
0 0 0.7954
targetfromfun = 0 0 0.7954
function dispprops(ax)
viewfromax = ax.View %#ok
[azfromfun,elfromfun] = view;
disp(['viewfromfun = ' num2str(azfromfun) ',' num2str(elfromfun)])
posfromax = ax.CameraPosition %#ok
disp(['posfromfun = ' num2str(campos)])
targetfromax = ax.CameraTarget %#ok
disp(['targetfromfun = ' num2str(camtarget)])
end
  3 Comments
Voss
Voss on 2 Apr 2022
It looks like it's because the properties don't update instantly, but only when the next drawnow (or other command that processes the graphics event queue such as figure or pause) occurs.
Here's an example where CameraPosition is set and then View is queried afterward. In Case 1 no drawnow is used and View remains at its old value, and in Case 2 drawnow is used in between setting CameraPosition and getting View, and View shows the updated value:
% First, a reference figure with default axes 'View' and
% 'CameraPosition' properties shown:
figure();
peaks(30);
z = 3*(1-x).^2.*exp(-(x.^2) - (y+1).^2) ... - 10*(x/5 - x.^3 - y.^5).*exp(-x.^2-y.^2) ... - 1/3*exp(-(x+1).^2 - y.^2)
ax = gca();
get(ax,'View')
ans = 1×2
-37.5000 30.0000
get(ax,'CameraPosition')
ans = 1×3
-27.3943 -35.7009 63.3693
% Case 1:
% when setting 'CameraPosition', 'View' property doesn't change
% (but actual apparent 'View' does):
figure();
peaks(30);
z = 3*(1-x).^2.*exp(-(x.^2) - (y+1).^2) ... - 10*(x/5 - x.^3 - y.^5).*exp(-x.^2-y.^2) ... - 1/3*exp(-(x+1).^2 - y.^2)
ax = gca();
get(ax,'View')
ans = 1×2
-37.5000 30.0000
get(ax,'CameraPosition')
ans = 1×3
-27.3943 -35.7009 63.3693
set(ax,'CameraPosition',[0 -40 80])
% still the old View (but clearly the surface is seen
% from a different angle than in the first figure)
get(ax,'View')
ans = 1×2
-37.5000 30.0000
% Case 2:
% putting a drawnow() after setting 'CameraPosition'
% causes 'View' property to show the updated value:
figure();
peaks(30);
z = 3*(1-x).^2.*exp(-(x.^2) - (y+1).^2) ... - 10*(x/5 - x.^3 - y.^5).*exp(-x.^2-y.^2) ... - 1/3*exp(-(x+1).^2 - y.^2)
ax = gca();
get(ax,'View')
ans = 1×2
-37.5000 30.0000
get(ax,'CameraPosition')
ans = 1×3
-27.3943 -35.7009 63.3693
set(ax,'CameraPosition',[0 -40 80])
drawnow()
get(ax,'View') % now View is accurate
ans = 1×2
0 39.4248
broken_arrow
broken_arrow on 4 Apr 2022
Edited: broken_arrow on 7 Apr 2022
Thank you very much. It seems to be a little tricky: Apparently view does actually change when modifying CameraPosition, but a query in a script/function immediately after a change may return the outdated value because execution proceeds "too fast". The same query in the command window will return the correct value. drawnow has the same effect because it enforces waiting for the "figure update queue" to finish.
But I still do not fully comprehend the relationship between View, CameraTarget and CameraPosition. I always imagined the line between target and position as the optical axis of the camera, which can be alternatively defined by azimuth and elevation. But that seems to be incorrect. For example, a change of CameraTarget does not change View and CameraPosition, but rather modifies CameraViewAngle. Can someone explain?

Sign in to comment.

More Answers (0)

Categories

Find more on Graphics Performance in Help Center and File Exchange

Products


Release

R2020b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!