1. Hey! Guest! The 36th GMC Jam will take place between February 27th, 12:00 UTC - March 2nd, 12:00 UTC. Why not join in! Click here to find out more!
    Dismiss Notice
  2. NOTICE: We will be applying a Xenforo update on Tuesday 25th of February. This means that from approximately 10:00 to 14:00 BST the forums will be offline (or possibly longer). Sorry for the inconvenience! Official Announcement here.

3D Translate 3D to 2D perspective?

Discussion in 'Programming' started by IanCSc, Feb 14, 2020.

  1. IanCSc

    IanCSc Member

    Jan 22, 2020
    Hi guys, first post since GMS2!

    I don't quite have the firmest grasp on this math just yet, but this was a huge help.
    I'm currently trying to create something that looks somewhat similar to Octopath Traveler, but FAR less complex.

    If I had started this as a 3D project, I'd be billboarding the sprites, but times change, feature creep happens. So now I'm attempting to overlay my existing (basically feature-complete) 2D gameplay engine over some 3D backgrounds.

    The main thing I need to do is figure out how to move the 2D camera the same observed distance that the 3D camera has traveled, preferably regardless of the size of the 3D projection or position of the camera (in case I'd like to make adjustments to the viewing angle on the fly, etc.)

    This is what I've got, which is a very hacky version of what I'd like to pull off:


    In this case, I'm moving the 2d object in the opposite direction of the 3D camera, but I used trial and error to get it to look (almost) right.

    ///pos3d_get_screen_pos(x, y, z)
    var pos = matrix_transform_vertex(global.mat_world_view_projection, loader3D_obj.xto, loader3D_obj.yto, 0);
    pos[0] = (1 + (pos[0] / (pos[2] + 1))) * 0.5 * 960;
    pos[1] = (1 - (pos[1] / (pos[2] + 1))) * 0.5 * 640;
    var old = matrix_transform_vertex(global.mat_world_view_projection, loader3D_obj.xto_old, loader3D_obj.yto_old, 0);
    old[0] = (1 + (old[0] / (old[2] + 1))) * 0.5 * 960;
    old[1] = (1 - (old[1] / (old[2] + 1))) * 0.5 * 640;
    var new;
    new[1] = pos[1] - old[1];
    new[0] = pos[0] - old[0];
    return new;
    And in the 2D object:
    new = PerspectiveChange();
    x += new[0]*4.5;
    That 4.5 is a made-up number, but that's the number I'd be trying to find presumably.

    I'm confident I can figure this out, but I'm definitely a little out of my depth.

    Thanks so much for any insight.

  2. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Jun 20, 2016
    I think what you'll want to do is make sure the 3d view and the 2d view are showing the same area... i.e., of the xy plane at z=0. This means there has to be a connection between the field of view of the 3d camera, and the distance at which it is located from z=0.

    tan(fov/2) = view_height / (2 * cam_z)
    fov = 2 * atan( view_height / (2 * cam_z )
    cam_z = view_height / (2 * tan(fov/2) )

    If the 3d camera looks directly in the z direction, and the 3d camera shows the same area as the 2d cam, then you should be able to move both cameras the same amount and keep them in sync.

    You know, come to think of it, you should only really need to use the 3d projection, if you are looking down at the xy plane, won't 2d stuff still draw normall? (not sure about background tiles).
    Last edited: Feb 15, 2020
    Joe Ellis likes this.
  3. Joe Ellis

    Joe Ellis Member

    Aug 30, 2016
    Your problem might be simpler than you thought, in the ref pic I think that could all be done with a 3d camera and drawing sprites at different depths, plus the horizontal floors.
    The script I showed was to basically convert a 3d position into the position it is on screen, which you need if the 3d camera could be facing any direction, but with the game you showed, the camera is basically pointing exactly in the z direction, and sprites won't need to be made to face the camera cus they already are, as they're drawn flat onto the z plane.
    So you should be able to just have one camera, with perspective

    If you want to do it manually without making a gamemaker camera you can do:
    matrix_set(matrix_view, matrix_build_lookat(camera_x, camera_y, camera_z, camera_x, camera_y, ground_z, 0, -1, 0))
    matrix_set(matrix_projection, matrix_build_projection_perspective_fov(60, screen_width\screen_height, 1, 10000))

Share This Page