# I need Camera Custom Projection Marix

### Godot Version

Godot 4.21 stable

### Question

I need a 3D camera Custom Projection Marix setup.

However, there was no way to set it in GDScript, and there was no way to set it in the tool…

In the Godot scripting world it’s called a transform. If that’s what you mean?

If you are talking shaders… there are definitely options.

I said it wrong.

I was talking about the camera projection matrix.

example

For reference, I used this to express 2D and 3D with my own custom orthogonal projection.

It’s been used that way in other engines, but it’s sad why this engine doesn’t support it.

Well there is a orthogonal camera setting, you can change the aspect ratio, and view distance, which are all aspects of the projection matrix. What do you need specifically?

To be precise
I want to set orthogonal projection according to the window screen size.

In this case, a 3D coordinate system is used, but a 2D image can be created and used at the exact size. I can also mix 3D models at the same time.

3D

For example, I used code like this before:

auto makeOrtho = (float left, float right, float bottom, float top, float nearZ, float farZ)
{
float invw = 1 / (right - left);
float invh = 1 / (top - bottom);
float invd = 1 / (farZ - nearZ);

Matrix4 proj = Matrix4::ZERO;
proj[0][0] = 2 * invw;
proj[0][3] = -(right + left) * invw;
proj[1][1] = 2 * invh;
proj[1][3] = -(top + bottom) * invh;
proj[2][2] = -2 * invd;
proj[2][3] = -(farZ + nearZ) * invd;
proj[3][3] = 1;

return proj;
};

godot processes 2D and 3D separately, but

By manipulating the custom projection matrix like this, it is a system that can use a 3D model in the 2D coordinate system used in sprite2d.

I think I understand, you just want to work in one coordinate system?

Why not use Sprite3d and do everything in the 3d world?

You can adjust the h and v offset of the camera so origin is top left corner. Meshes will still be centered.

Project settings can make sure window sizes don’t matter.

But yeah it would probably be a lot of work to get Godot to do the thing I think you want it to do

You could attach a shader material and modify the projection matrix for each mesh. I tried playing around with it but it seemed to only make the mesh disappear. Not sure I understood what the elements of the matrix is doing.

As you can see from the screenshot

The current screen is a 100 pixel square image in Sprite2D.
It is positioned at 0,0. (Centered flag off)
[What makes these coordinate systems the same is the custom projection matrix I wrote above]

If I want to view it on the same screen in Sprite3D, it is very complicated with existing orthogonal projections, and x and y must be used very differently from the 2D coordinate system values.

For example, if I do orthogonal projection in the project settings with a window size of 1600:900,
A 100 pixel square will appear as 900 pixels on the screen when the game is running.

To make 100 pixels visible, the size value of the orthogonal projection must be set to 9.

The problem doesn’t end there.

Here, if I want to move the square by 1 pixel, I have to set the X value to 0.01m to move it by 1 pixel.

In fact, whether I was debugging or writing code… it is difficult to intuitively understand the position value like sprite2d.

I haven’t tried it yet, but if I rotate the camera 180 degrees on the x-axis so that the y-axis goes down in the 3D coordinate system, the image will be drawn upside down.

But, as I did in other engines, if I set up the projection matrix as I wrote above, it magically works identically to the Sprite2D coordinate system.

With this orthogonal projection camera, Sprite3D can be used like Sprite2D, and 3D models can also be mixed at the same time.

It’s just that Sprite2D has one more Z-axis coordinate.

Therefore, it is possible to use 2D and 3D at the same time.
If I align this Sprite3d and 3D model on the Z axis, I get a layer effect that includes 2D and 3D at the same time.

I think I got close by setting the orthographic camera size to be 1 meter equals 1 pixel (684x648) size = 648 , Then setting the v&h offset by half of resolution (v goes negative half resolution (h=342, v=-342)), then on the camera flipping it’s y scale to -1, to make + y movement go down. Then scaled my meshes to desired size-to-pixel.

Project window settings

Stretch mode viewport, scale mode integer,
Aspect keep.

(There is a lot that could be done with some scripting code if window sizing is a thing to care about.)

1 Like

The other thing you can try is for every mesh customize a spatial shader to modify the PROJECTION_MATRIX of the mesh with your desired maths.

You could make the mat4 a global shader parameter so you could set it once for all shaders that use it.

Windows 1600: 900 (Keep Height)

Modify Sprite3D Pixel Size 0.01m to 1 (1m = 1pixel) and

Because the size of the orthogonal projection camera is set to 900,

The size came out just like Sprite2D.

After setting the camera Y Scale to -1 as you said,
Set the camera’s H Offset to 800 and V Offset to -450.

And if I set Sprite3D’s Y Scale to -1 and then specify offset Y as the image height, it seems to work roughly as I want.
(If the Centered flag is on, offset Y is left as 0)

Once I do this, I think I can use it roughly like Sprite2D by setting Postion and rotation-Z.

The screenshots are sorted by Z value and layers are formed in the following order: Sprite3D(Green-Orange square) > - 3D Model - Sprite3D(Red square)

By doing this, I can place the 2D background in the Sprite2D coordinate system and freely place the 3D model in the same way.

And
I am not sure because I am a beginner in this engine.

to do the shader thing its a little annoying because its not exposed by default, and since you have a material already to color a mesh, there is no easy way to tack it on.

but anyway if you have a material, you can right click it and select “convert to shadermaterial”

This will make it into a shader script, then within the vertex function you can modify the PROJECTION_MATRIX.

``````// for 3d nodes this is the default shader type

uniform mat4 porjection_matrix = mat4(0.0);

void vertex() {
PROJECTION_MATRIX += projection_matrix;
}
``````

by using a uniform you can set the values manually within the “shader parameters” in the inspector.
I found that by creating a zeroed matrix and adding it to the already existing PROJECTION_MATRIX, I could see what I was doing better. (i think the default values for the P_M is defined by the viewport and camera )

The other downside is that you have to use this material setup for every mesh that you render, and it can’t be done once for the camera as you have stated.

anyway to make your life easier if you plan to use this and have to recalculate programmatically, you can setup a global shader parameter and use the RenderServer singleton to set the shader parameter.

if you want to know more on whats available take a peak at the docs,

1 Like

However, when I think about it…
It might be difficult for me to apply my own shader to every mesh…

All I have to do is touch the camera… but having to control all the shaders is difficult.

I’m tempted to try my hand at compiling the godot source code, but considering the frequent engine updates, I don’t think it’s such a good idea.

First, I need to modularize the orthogonal projection camera and Sprite3D to prepare for when I can directly control the camera projection matrix in the future.

1 Like

Hey I was watching a random Godot video, and some how missed that the camera projection matrix is available if you call the camera method. get_camera_projection(). It will return a projection matrix class reference to do what you want with.

1 Like

Oh…thank you
I’ll check it…

Why didn’t I know this?

I will test it and see what the results are.

Hmm…there’s a problem.

I also have to change the order of drawing triangles in Sprite3D… to complete the scene I want…
(Because the spirte image is upside down, the rectangle needs to be redrawn with vertex)
Vertex access is blocked in Sprite3D.

So I guess I’ll have to make it in MeshInstance3D…
Then I end up having to create something identical to Sprite3D (AnimatedSprite3D) that does the same thing.

Thinking about it, if I used ‘Flip V’ on the image in Sprite3D, it worked as I wanted.

I think it would be better to just use the method supported by the editor rather than directly modifying the projection matrix.

Even if I do that, I don’t think there will be any major problems with the work I’m trying to do.

Since I am not familiar with the engine, I need to get more used to how to use it.

Anyway, thanks for the help.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.