How To Move Camera
In DynaMaker there are built-in easy-to-use functions to handle camera movements. Not only the camera can go from A to B, but also how it goes and how fast are parameters that can be controlled. Also there are other functions that autocenter the camera based on the existing model. We show all settingsthrough the app below. Check also the video as a summary of the most important.
Using this app as a reference, in this guide we go through:
It's important to notice that the camera can only be updated through
Studio
, which is only available in the UI editor.
Position & Target​
In any 3D software there is always:
- Camera position: 3D point in which the user's eye should be in reality, or where we look from.
- Camera target: 3D point where the camera is looking at, or where we look at.
In the interactive app, to mimic how the camera works from a 3rd-person perspective, notice how no matter where the camera and target are, that the camera is always looking at the target.
Look at camera from target​
As example of use, see how the button Look at camera from target works. Given a position and target, simply
use Studio.setCameraPosition()
and Studio.setCameraTarget()
with the same travelTime
, like in this button below:
const lookAtTargetFromCameraButton = new SKYUI.Button(
'Look at target from camera',
() => {
Studio.setCameraPosition(new SKYMATH.Vector3D(400, 200, 100), { travelTime: 2000 })
Studio.setCameraTarget(new SKYMATH.Vector3D(0, 0, 0), { travelTime: 2000 })
},
{ icon: 'record' },
)
Reset Camera​
Resetting the camera is quite common to find when swiching tab, when a configurator parameter updates or even when we
click on a quickbar item. We might not be interested on the resulting camera position
and target, as long as the camera is resetted given a direction. For this we use a smarter function
Studio.setCameraToFitBounds()
:
Studio.setCameraToFitBounds({
direction: new SKYMATH.Vector3D(0.5, 1, -0.5),
travelTime: 1000,
})
This function takes the whole model presented in the preview, gets its bounds and updates the camera depending on them.
However, you can define your own bounds
, even with some boundsOffset
(e.g. the user is configuring the handle of the
door, so the camera should focus on the bounds of the handle, regardless of the door and its size). Then this can be
done by using its extra optional arguments:
Studio.setCameraToFitBounds({
direction: new SKYMATH.Vector3D(0.5, 1, -0.5),
travelTime: 1000,
bounds: ACTIONS.getDoorHandleBounds(), // custom function to get the bounds of the door handle's geometry
boundsOffset: 50, // bounds + 50 in all 3D-directions (also accepts negative values)
})
Alternatively, you can use the opposite functionality. Let's say you have a door in a wall with curtains, but you want to fit the camera to the bounds of the door, regardless of the curtains and wall perhaps. Then you would want to only ignore the geometry of the wall and curtains. Then:
Studio.setCameraToFitBounds({
direction: new SKYMATH.Vector3D(1, 1, -0.75),
travelTime: 1000,
ignoreGeometryGroups: ['wall', 'curtains'],
})
Notice that
bounds
areignoreGeometryGroups
are mutually exclusive where the latter is ignored if the first is used. The strings ofignoreGeometryGroups
need to match the tag added in the respective geometry groups (e.g.geometryGroup.addGeometry(wallModel, { tag: 'wall' })
).
Move from A to B​
The most intuitive way is to move from one known 3D-position A to another known 3D-position B. To make sure we move to A first, we can take advatange that these functions are async, therefore you can do one and then the other one as shown in the code below:
const targetPosition = new SKYMATH.Vector3D(0, 0, 0)
const A = new SKYMATH.Vector3D(-500, -500, 300)
const B = new SKYMATH.Vector3D(500, -500, 300)
Studio.setCameraTarget(targetPosition, { travelTime: 0 }).then(() => {
Studio.setCameraPosition(A, { travelTime: 0 }).then(() => {
Studio.setCameraPosition(B, { travelTime: 1500 })
})
})
Settings​
In order to set up the rest of the camera behaviors (e.g. locking zoom, orthographic view, etc), you would need to
update the camera settings via Studio.updateCameraSettings()
. You will find quite a lot of options that we try to
explain them depending on the topic (see also
interactive app):
Polar & Azimuth​
The camera position is based on a 3D polar coordinate system, meaning that is driven by two angles: the vertical polar, and the horizontal azimuth. The default polar and azimuth angles are the following:
Studio.updateCameraSettings({
minPolarAngle: 0,
maxPolarAngle: Math.PI / 2,
minAzimuthAngle: -Infinity,
maxAzimuthAngle: +Infinity,
})
See that Infinity
allows for a indefinite spin in the horizontal plane in both directions as it is, but we are never
allow to go above the zenith (polar angle = 0) or the ground (polar angle = 90 deg). However you change those and
typically go up to the nadir (polar angle = 180 deg) by having maxPolarAngle: Math.PI
. Feel free to check the
interactive app) to see how these 3D angles work.
Rotate, Pan & Zoom​
Rotating, panning and zooming is allowed by default in the app. However there are some particular cases that you might don't want the user to rotate (e.g. the app has a 2D mode), pan (e.g. to prevent the user from changing the target position) or zoom (e.g. to always a clear view of the whole model) the camera. You can lock this with:
Studio.updateCameraSettings({
allowRotate: false,
allowPan: false,
allowRotate: false,
})
It's also typical to zoom in and out in buttons for touch-devices. As it is in the interactive app, you can zoom in /out like:
Studio.setQuickBarItems([
{
icon: 'zoom-in',
action: () => Studio.cameraZoomIn(),
tooltip: 'Zoom in',
},
{
icon: 'zoom-out',
action: () => Studio.cameraZoomOut(),
tooltip: 'Zoom out',
},
])
Zoom To Mouse​
By default zooming in/out is centered on the screen (same point as target). However sometimes you might want to be able to zoom in and modify the target position
Studio.updateCameraSettings({
zoomToMouse: false,
})
Ground Lock​
By default ground lock is enabled, meaning that when you pan the view, the target moves along the ground of the app. When disabled, the target moves perpendicular to the screen. In both cases, the target and the camera positions move in the exact same direction and offset. It's best to test in the interactive app.
Studio.updateCameraSettings({
groundLock: false,
})
Orthographic vs Perspective​
By default the view is set to perspective, meaning that the more you zoom in, the more distorted the faces of the model are. However when in orthographic mode, zooming doesn't affect the model shape and therefore it's quite suitable when things must be look from the side or top (as it is a 2D projection) to see if things are behind certain faces. This is typically found when 2D modes are presented in apps, where we want the user see things as if they are projected onto a plane.
Studio.updateCameraSettings({
ortographic: false,
})
Other​
As oher examples and minor settings, in here we go through:
Travel Time​
The time it takes to perform a camera action (e.g. Studio.setCameraToFitBounds()
) is called travelTime
and it comes
as an optional argument in those functions. In the last tab of the
interactive app, you can see how the user experience can
change by simply changing the travelTime
: short times might feel that your app is fast, whereas high times might give
an impactful effect to the app, typically presented when opening apps for the first time. As example:
Studio.setCameraToFitBounds({ travelTime: 3000 })
Notice that travelTime
is given in milliseconds.
Easings​
Easings can be applied to camera transitions and describes how the camera movement transitions from one point to another. You can read more about easings here.
The easings available in DynaMaker are four and can be applied to certain functions. As example:
Studio.setCameraToFitBounds({ easing: 'CubicIn' }) // can also be 'CubicInOut', 'CubicOut' or 'Linear'
Target Distance​
The ability to zoom in or out is limited by the max and min camera distances (between camera and target positions). For example, when having very small or very large products, we want to limit the max camera distance so that the user doesn't get lost when zooming out a lot by accident perhaps.
Studio.updateCameraSettings({
maxTargetDistance: 1000,
minTargetDistance: 0,
})
Although the following are less used, you can also set the min/max distance from which objects are visible, and it's
typically updated when having very unusual object sizes. Make sure to adjust far
and near
so that your objects are
visible.
Studio.updateCameraSettings({
far: 10000, // increase value to see objects not disappearing by a far camera position
near: 0.1, // decrease value to see objects not being cut by a close camera position
})
Rebind Camera Buttons​
We might be used to other camera controls depending on the software we use every day. But don't worry, in DynaMaker you can rebind these very easily giving the behaviors in strings as follows.
select
to interact with the product (e.g. selection)rotate
to rotate the camerapan
to pan the viewzoom
to zoom in
// Default behaviors:
Studio.updateCameraSettings({
mouseButtons: {
left: 'select',
right: 'rotate',
middle: 'pan', // mouse-wheel button
scroll: 'zoom', // mouse-wheel
},
touch: {
oneFinger: 'rotate', // 'interact' | 'interactAndRotate' | 'none',
twoFingers: 'pan', // 'zoom' | 'zoomAndPan' | 'none',
},
})
Notice that there are four mouseButtons
that can be changed, whereas only two touch
options for touch-devices like
phones and tablets.
Force 2D Mode​
Another common example is that you might be configuring your product in a plane. For example, in a wall-builder type app, you might want to look at the product from above (top view) locking any rotation possibilities while drawing the walls with lines. However, when you are done with a certain configuration or perhaps you just change to another UI tab that allows the visualization of 3D models from those drawn lines, then the view can be switched to perspective and naturally allow the 3D rotation again. This can be done by updating the camera settings like:
Studio.updateCameraSettings({
allowRotate: false,
orthographic: true,
})
Studio.setCameraToFitBounds({
direction: new SKYMATH.Vector3D(0, 0, -1), // top view
travelTime: 1000,
})
Remember that the settings need to be "restored" in other places so that you need to include that setting change (
allowRotate: true
andorthographic: false
) anywhere else that needs it.
Rotation Below Ground​
In order to look at things from below the ground, it requires the combination of two settings enabled (see code below), where it allows a natural panning of the view without interfering with the app's ground.
Studio.updateCameraSettings({
maxPolarAngle: Math.PI,
groundLock: false,
})
Would you like to contribute with other camera behaviors or request new ones? Reach us at support@dynamaker.com and help the community to code faster!