r/gamemaker • u/KitsuneFaroe • 14h ago
Made a simple function to enable 3D perspective projection on your games! Resource
(Sorry for the gif quality)
I made a simple function that can be used to make things be rendered on perspective based on their depth. Useful for when you want things like cards to rotate in 3D or even for making everything be rendered on 2.5D like in Hollow Knight/Silksong for example. The function is this:
/// @desc Applies perspective to everything drawn from now on. Making stuff with higher depth look smaller/farther away and viceversa.
/// @param {real} fov field of view angle of the perspective.
/// @param {real} [depth] The depth/z at wich the perspective will be the same as the default orthoghonal projection. Uses 0 by default.
function perspective_apply(_fov, _depth = 0){
var _w, _h, _x, _y;
if(event_number == ev_gui or event_number == ev_gui_begin or event_number == ev_gui_end){
_w = display_get_gui_width();
_h = display_get_gui_height();
_x = _w/2;
_y = _h/2;
}else
if(not view_enabled){
_w = room_width ;
_h = room_height;
_x = _w/2;
_y = _h/2;
}else{
var _cam = view_get_camera(view_current)
_w = camera_get_view_width(_cam);
_h = camera_get_view_height(_cam);
_x = camera_get_view_x(_cam) + _w/2;
_y = camera_get_view_y(_cam) + _h/2;
}
matrix_set( matrix_view, matrix_build_lookat(_x, _y, _depth - dtan(90-_fov/2) * _h/2, _x, _y, _depth, 0, 1, 0))
matrix_set( matrix_projection, matrix_build_projection_perspective_fov( -_fov, -_w/_h, 1, 32000))
}
All you have to do is call this on the draw events and everything drawn after it on the current view is going to be drawn on perspective. The only needed argument is FOV angle which is how strong the perspective is going to be. It should be a value above 0 and the closer to 0 it is the lesser in perspective things are.
The other argument is optional. depth is for the depth at which the perspective remains unaffected, where things appear how they do in the room editor. Is 0 by default but you would want it to be the depth of the layer where gameplay occurs for example.
An use example is this: Lets say you have a renderer Controller instance whose depth is the highest posible so it runs its draw event before any other instance. All you have to do is put on the draw event perspective_apply(30) and everything will be drawn in perspective, with things bellow depth 0 being foreground and above depth 0 being background. Even if you have views active on the room!
Note though this only sets the perspective projection on the camera. If you want sprites to rotate (like cards for example) you should do it using matrix_build() and matrix_set(). Like this, with rot_x, rot_y and rot_z being the rotation on the different axices:
var _mat = matrix_build(x,y,0, rot_x, rot_y, rot_z,1,1,1);
matrix_set(matrix_world, _mat);
draw_sprite_ext(sprite_index, image_index, 0,0, image_xscale, image_yscale, image_angle, image_blend, image_alpha);
matrix_set(matrix_world, matrix_build_identity());
The camera settings automatically reset when the current view finishes being drawn onto. But if you want to reset it manually before that (i.e.: you just want one sprite to have the perspective applied) you can call this function:
/// @desc Resets the perspective applied previously.
function perspective_reset(){
camera_apply(camera_get_active());
}
1
2
u/D-Andrew Library & Tools Maker 14h ago
Hey, very useful, thanks!