For Godot 4, 3D Viewport Cameras
(Could probably be appropriated for 2D as well)
If you just want the code, you can scroll down to the full snippets (titled Implementation). I try to explain first, how this approach is flexible enough, so in case of a code change of Godot itself, there shouldn't be too much change needed in the plugin itself.
Node Structure/Search for a decent starting point
First we have to look at the structure, how the viewport cameras are set up. In contrast to the in-scene cameras (you create yourself) the viewport cameras are separate (and yes, plural camera's because there are ALWAYS four of them).
They exist in the editor interface control structure. So by iterating through the whole control tree, you can find out, that there is the following structure repeating itself four times:
We see, that we have a class name which is easily identifiable in a full recursive tree search:
Node3DEditorViewport. This class doesn't exist anywhere else but in these four instances. And we also see, that further down the line, they contain a
Camera3D Node. These nodes are the viewport cameras in the editor.
Why are there four cameras?:
Since the editor supports the option to display four different viewports at once (via the View menu tab in the 3D viewport editor), there are four such viewports (and their cameras) prepared in advance, in case you want to view more than one viewport. The interesting thing to note here, is that those four viewports/cameras are created in the interface at the start of Godot. So whether you actually use one or all of them (you don't even have to open a 3D scene for them to be created), you can get those nodes once at the starting point which will be relevant for later, when we decide how we want to manage those cameras in our plugin.
(This example is a use case of a dock which will be used in the editor. You can of course use everything in the plugin class itself, but most likely you want the viewport camera information for a reason to use in the editor, so you'll most likely know for yourself, how you want to handle this)
First you have your typical editor plugin:
const GET_EDITOR_CAMERA_DOCK_PATH = \
_dock = preload(GET_EDITOR_CAMERA_DOCK_PATH).instantiate()
In this case I use a custom
init function to be able to pass the editor interface to the subsequent dock object, since I use the camera information in that dock.
Next, we have our subsequent class:
(as mentioned before you can do this in the plugin script as well, though I believe you probably want to be able to interact with some kind of button or other custom interface in the editor, so this use case is most likely the default one)
get_editor_camera_dock.gd (this script is of course attached to our dock
const NODE_3D_VIEWPORT_CLASS_NAME = "Node3DEditorViewport"
var _editor_interface : EditorInterface
var _editor_viewports : Array = 
var _editor_cameras : Array = 
func init(editor_interface : EditorInterface):
_editor_interface = editor_interface
for v in _editor_viewports:
#--- Connect signals to buttons etc., whatever you want to do,
depending on your use case.
func _find_viewports(n : Node):
if n.get_class() == NODE_3D_VIEWPORT_CLASS_NAME:
for c in n.get_children():
func _find_cameras(n : Node):
if n is Camera3D:
for c in n.get_children():
var camera = _editor_cameras # index 0 -> top-left
# var camera = _editor_cameras # index 1 -> top-right
# var camera = _editor_cameras # index 2 -> bottom-left
# var camera = _editor_cameras # index 3 -> bottom-right
#--- do with the camera information whatever you want
1) Now first make sure, that subsequent scripts you use in an editor plugin are flagged as a tool script as well with the initial
2) The constant
NODE_3D_VIEWPORT_CLASS_NAME defines the class name
Node3DEditorViewport of the top most node we want to find in our editor interface node tree, from which on we can be as sure as possible, that under that node, we can find the viewport camera nodes.
Since this class name will probably change the least (but it's possible of course in future versions) we define it as a constant, to be able to change just this value if a change like that should occur.
3) Next come the variables/properties of our dock class:
_editor_interface -> initialized in our custom init function
_editor_viewports -> holds all four 3d viewports of our editor
_editor_cameras-> holds all four 3d cameras from our four 3d viewports
Even though we'll only really need the camera information for further processing, we still define an array for the viewports outside a function, since we'll be populating this array with a recursive function. There are other ways to do this, but it's just the easiest so why not ;)
4) In our
init function we pass the editor interface object (from the plugin script before) to the dock variable.
5) We override the
_ready function in which we will populate the
_editor_cameras array. Since I mentioned before, that the viewport and camera nodes exist even if we haven't opened any 3D scene in the editor, we can do this here once, and don't have to do it everytime we want to do something with the viewport camera information.
We first populate the viewports array (via the recursive function
_find_viewports) and then populate the cameras array by searching through the tree of each viewport node (it's children). Since it's possible that the tree structure might change in future version of Godot, this approach, in my opinion, is the most flexible at the moment.
6) Let's get into details of the
_find_viewports recursive function. The first time we call it from
_ready we pass the base control of our editor interface. Think of the base control as the first node in the user interface tree of the whole editor itself. From there we search down the tree until we find our Node3DEditorViewport Node from the structure mentioned above, and add it to the viewports array. If we find one, we can just stop the recursion for this level in the node tree by simply
return the function. If the node is not the right class, we just go further down the tree. In the end, we will have four viewports in our
7) Let's get into details of the
_find_cameras recursive function. We call this function with each viewport node in the
_editor_viewports array to search down that particular node tree until we find the 3d camera. We do it this way (and not with
get_node(path)) since it's possible, that future Godot versions may change that node tree layout. This way, we can make it at least a little fool proof and a bit more flexible.
At the end, we have now four camera nodes in the
Which camera information to use?
Here is a little screenshot to show you, which index of the array contains which camera in the viewport (if you only use one it's 0):
Or in text:
- 0 -> Upper left viewport camera (or main camera if only one viewport visible)
- 1 -> Upper right viewport camera
- 2 -> Bottom left viewport camera
- 3 -> Bottom right viewport camera
Of course you can always define constants for those indeces in your script as well, so you can make absolutely sure, that you always use the right one for your situation.
Now you can access the viewport camera information just by getting the correct camera node (whichever one you need), by using the different indeces.
(Example function body for quick camera creation from viewport):
var camera = _editor_cameras
var new_scene_camera = Camera3D.new()
# defined somewhere else, doesn't really matter,
# this is just an example ;)
new_scene_camera.owner = _editor_interface.get_edited_scene_root()
new_scene_camera.global_position = camera.global_position
new_scene_camera.global_rotation = camera.global_rotation
Isn't iterating over each node in the editor interface node tree to find the viewports inefficient?:
Yes it is. But since you only need to do it once at the start of Godot (or the moment you activate your plugin) this doesn't really matter. The nodes stay the same as long as Godot is open, so you only need to do it once. And this one time, it doesn't even take half a second. Sometimes it's just enough if something works. It's not that important, since you won't ship your editor plugin within your game to the end user anyway.
The information of the four cameras is dependent on the current scene
Even though the nodes exist permanently, the information of them (location, rotation, etc.) will depend upon the currently selected scene in the 3D editor. So make sure, before you click any buttons on your custom plugin dock (or however you want to handle it), that you open the scene/select it in your 3D editor tab list, on which you want to use the camera information on.