How to apply an inverted Pythagorean calculation for my orthogonal camera?

Godot Version

v4.4.1.stable.official [49a5bc7b6]

Question

I need help to keep all my elements on the screen in my game. But, I need advanced calculus to do it. Because I set the orthogonal camera at an angle of 11.4 and I have to move the camera back to keep the elements on the screen while the camera is resized. For every 1 meter the camera gets bigger it will move back 1 meter. That's not enough after making the camera bigger by +40 meters the game elements and objects start to appear below my cameras FOV/POV. The problem is simple the camera will resize below the z axis. How would I go about moving the camera back enough to keep it above the z axis. A ratio of 1:2 will work too. What is the exact equation to always keep the bottom of the camera on the same location; a.k.a. 0 Z axis.

No calculus needed, you need a little trigonometry.
For every meter you the camera size grows just move the camera up on the y axis by the ratio of your resolution and the axis that is set to keep.

So with a ratio of 4:3 (width:height), keeping the height. The conversion of change in width size to the change in height becomes
position.y = width/height*size/2.0
Or
position.y = 4.0/3.0*size/2.0

To deal with the angle all you need to do is create a camera arm that is tilted where the camera itself has a non rotated local space and you can adjust the y position as normal. Or if you wanted to find the conversion you just need to do a little trig making the opposite the hypotenuse of a smaller triangle that can find the height of larger triangle perpendicular to the z plane.

But also, the triangle is inaccurate because the camera is orthogonal, you should draw it like a rectangle.

The thing about orthogonal cameras is that the distance you are to the subject doesnt matter. If you had an infinite render distance the camera could be a foot away or a million miles away and the perspective on the subject wouldn’t change. So moving the z axis of the camera may also change the y axis depending on your transform setup, but i would rig it so all you need to do is move the camera up on the y axis.

1 Like

It’s impossible in this case. Because like I said the camera is connected to a ball pivot turned to 11.4 degrees. The camera is also, 55 meters away from the ball pivot at the Z axis. “That’s why I’m asking. What I need to know.” The camera moving on the Z axis is moving locally. And, my variables are the distance on the z axis and size only. That’s all I can do. Distance and size.
I already know “super russiar” the growth is at 53.8 degrees. Closest ratio I can find 20/66. I hate that by the way. It’s all over the place. It’s 0.333333…

Here I made a graph to my original drawing.
If you look at the data;
During constant growth; my camera distance and size increase the same.
I also counted on the fact that for this example the camera size should be 16:9 ratio.
But, in any case as you can see, the more I zoom out the more will the camera fall below that line where the original is. And, eventually below the Z axis where my elements are supposed to be drawn.
Sorry, it’s my fault for trying a dynamic orthogonal camera. Not, too mention a few other flaws I will not use in future releases.(e.g. panoramic skyboxes, even with custom fov)


Let’s use a simple formula as a device.
I move the camera by 45 meters.
The camera is increased in size by 45 meters.
20 + 45 = 65 meters
65 / 2 = 32.5 meters for the bottom half
32.5 * 0.5625 = 18.28125 this is to account for the 16:9 screen ratio
e.g. ratio does not apply like this because I have to make sure the app resolution is 16:9 ratio

I made another graph.
I just need to follow this one simple triangle. It’s that easy.


When I do. I know that my camera has to be a little smaller when I zoom out and move back on the z axis.
It says it right there.
my camera size ends up 65 meters
but, what I need to do is make the camera 36.5625‬ meters to fit into that triangle

This is the scene set-up.


That’s all. That easy.

I’ll explain why I’m a bad student.
I’m tired.
The triangles are corespondent to only 90 degrees.
I also do this a lot. Except I decided to take a small break.

sorry, it is just size/2.0 as you mentioned
but the rest is trig.

camera.position.z = camera.size/2.0/tan(deg_to_rad(11.4))

image

To explain the formula, its just the average SohCahToa trig problem. the angled height you want is always going to be size/2.0 call this leg-b, but you want the length of the leg-a to move the camera back so the bottom of the camera is always tuching the z-plane. since you know the angle 11.4 we can make leg-a the adjacent and leg-b the opposite and use the toa formula to find the length of leg-a.

The Toa forumala:
tangent(angle) = opposite/adjacent

becomes:
tangent(11.4) = leg-b / leg-a
= ( size/2.0 ) / leg-a

then to solve for leg-a (the adjacent):
leg-a = leg-b/tangent(angle)
= ( size / 2.0 ) / tang(11.4)

2 Likes

But also you dont need to move an orthogonal camera at all as long as you distance it sufficiently for your scene, and can just change the size of the camera.

I’ll have to review this answer. Because the code is actually like this;

extends Marker3D

@export var default_camera_zoom_speed = 16

func _unhandled_input(event):
	if event is InputEventMouseButton:

		if event.button_index == MOUSE_BUTTON_WHEEL_UP:
			if $ball_que/Camera3D.position.z > 23:
				$ball_que/Camera3D.translate_object_local(-Vector3(0.0,0.0,1.0) * default_camera_zoom_speed)
				$ball_que/Camera3D.size -= 1 * default_camera_zoom_speed

		elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
			if $ball_que/Camera3D.position.z < 1000:
				$ball_que/Camera3D.translate_object_local(Vector3(0.0,0.0,1.0) * default_camera_zoom_speed)
				$ball_que/Camera3D.size += 1 * default_camera_zoom_speed

Just for the demonstration. I have to show you. I guess.
I put this together real quick.
When I load everything is fine. That’s me in the middle. The marker 3D with a mesh and texture.


As soon as I zoom out. I start to loose the bottom of the screen.

And, as I keep playing I loose more of the screen. This happens at 1000 meters.

That’s why it’s important. Sorry I had to flag down my z axis 0 here. Like I always do.

I’m going to mark that as a solution it’s close enough.
And, I’m going to keep this code for two reasons.

  • It works
  • I can actually make fast changes in case my screen size changes

But, the code on the tiles here is actually like this.

extends Marker3D

var camera_ratio = 2 * tan(deg_to_rad(11.4))
@export var default_camera_zoom_speed = 16

func _unhandled_input(event):
	if event is InputEventMouseButton:

		if event.button_index == MOUSE_BUTTON_WHEEL_UP:
			if $ball_que/Camera3D.position.z > 23:
				$ball_que/Camera3D.translate_object_local(-Vector3(0.0,0.0,1.0) * default_camera_zoom_speed)
				$ball_que/Camera3D.size -= camera_ratio * default_camera_zoom_speed

		elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
			if $ball_que/Camera3D.position.z < 1000:
				$ball_que/Camera3D.translate_object_local(Vector3(0.0,0.0,1.0) * default_camera_zoom_speed)
				$ball_que/Camera3D.size += camera_ratio * default_camera_zoom_speed

I can make that change. Since I add every time to the lines. I don’t apply the camera size here. But, this part works for me.

...tan(deg_to_rad(11.4))

I have to tell you why this is important to me.
Because I’m watching the debugger here.
And, I get the information from the print. Like the camera location and size.
This code is added as a print in the wheel up and down to make sure I get the correct perspective. So after a few minimums and maximum.
The print always gets me my default location of;

(0.0, 0.0, 55.0)
20.0

I would rather start a new test scene to discuss this;

extends Node2D

var function = (1 / 2)
var camera_ratio = 2 * tan(deg_to_rad(11.4))

func _ready() -> void:
	print(camera_ratio)
	print(function) # Don't really care why this is happening

I get this test print
0.40327073874308
0

integer division, you probably get a warning for this. Add a decimal point and a type “float” to ensure decimals

var function: float = 1.0 / 2.0
print(function) # 0.5