3D depth sorting in ortho 3D?

kamiyasi

Member
Hi there. I have an object that does all the 3D drawing for the objects in my room. I use d3d_set_projection_ortho.
What I've effectively done is created a Link to the Past style fake 3D 3/4 overhead view, with orthographically projected 3D models for characters and enemies.
My question is, how do I go about sorting depth for my models so they properly draw over each other?
In a normal 3D perspective, the z-buffer would handle depth sorting, but in my fake 3D environment, whether one object is in front of or behind another would be determined by their y positions, not z positions.

upload_2017-6-3_16-10-41.png
 

mar_cuz

Member
Not sure if it works in 3D but in top down or isometric perspective with game maker, putting:

depth = -y;

In the step event generally sorts drawing depth issues.
 
you should be able to accomplish this simply by tilting the camera. you will need to turn on the zbuffer though. In GMS1, you could disable perspective with d3d_set_perspective(false) and then use d3d_set_projection to tilt the camera.

Since the camera is tilted, if you want to make things draw in the same y position as they would appear when the camera is pointing straight down you will have to scale the y position according to the angle of the camera. An example of doing that:
Code:
//i don't know if up vector needs to be normalized as an argument to d3d_set_projection, but I am doing it anyway.
var _y = 300;
var _z = 600;
var _d = sqrt( _y * _y + _z * _z );
d3d_set_projection( 0,_y,_z,0,0,0,0,-_z/_d,_y/_d);
var _scale = _d / _z;

d3d_model_draw( cube_model, x, y * _scale, 0, cube_tex );
Although I think it would be easier just to draw everything with the new tilted camera (including the ground), so that you don't need to move things in order for them to show up in the right place.
 
Last edited:

kamiyasi

Member
you should be able to accomplish this simply by tilting the camera. you will need to turn on the zbuffer though. In GMS1, you could disable perspective with d3d_set_perspective(false) and then use d3d_set_projection to tilt the camera.

Since the camera is tilted, if you want to make things draw in the same y position as they would appear when the camera is pointing straight down you will have to scale the y position according to the angle of the camera. An example of doing that:
Code:
//i don't know if up vector needs to be normalized as an argument to d3d_set_projection, but I am doing it anyway.
var _y = 300;
var _z = 600;
var _d = sqrt( _y * _y + _z * _z );
d3d_set_projection( 0,_y,_z,0,0,0,0,-_z/_d,_y/_d);
var _scale = _d / _z;

d3d_model_draw( cube_model, x, y * _scale, 0, cube_tex );
Although I think it would be easier just to draw everything with the new tilted camera (including the ground), so that you don't need to move things in order for them to show up in the right place.
I tried implementing your suggestion but I'm having some trouble.
upload_2017-6-4_10-11-40.png
The shadow is where the player object actually is. The model is where it is being drawn with my current code. Also, left and right work properly, but up and down are reversed for the characters movement.
This is what I've tried.

Code:
d3d_start();
d3d_set_lighting(true);
d3d_light_define_ambient(c_white);

var _y = 300;
var _z = 600;
var _d = sqrt( _y * _y + _z * _z );

var wh = view_wview[0]/2;
var hh = view_hview[0]/2;

d3d_set_projection( 0,_y,_z,0,0,0,0,-_z/_d,_y/_d);
d3d_set_perspective(false);

var _scale = _d / _z;


///draw player
with obj_player
{
    d3d_transform_add_rotation_y( -90 - pnd);                   /////default:   z-pnd    x-60
    d3d_transform_add_translation(x, y * _scale , 0 );
 
    ///draw form
    d3d_set_lighting(true);
 
    if wa💩💩💩💩!=0 { d3d_light_define_ambient(c_red);  }
 
    mesh = global.mdwarf;
    d3d_model_draw(mesh,0,0,0,tex);
 
    d3d_light_define_ambient(c_white);
 
    d3d_transform_set_identity();


}
I should also mention that I am using views in my game. When the views x and y coords get further from 0,0 the character moves out of view, as it is currently.


I've also tried this which seems a little closer but the same problem still persists.
Code:
var wh = view_wview[0]/2;
var hh = view_hview[0]/2;

d3d_set_perspective(false);
d3d_set_projection( wh+view_xview[0],hh+view_yview[0] + _y, _z ,wh+view_xview[0],hh+view_yview[0],0,0,-_z/_d,_y/_d);
 

Attachments

Last edited:
I've been thinking about it, and really tilting the camera I think was a boneheaded suggestion. Probably the easiest, and most strightforward solution would be just to depth sort your 3d stuff before drawing it. This, and not using the zbuffer, will also prevent zfighting issues. So if you're not using the normal depth sorting done by gamemaker, you could duplicate it easily. For example you could use a priority queue, and add each 3d instance id to it according to the y position of that instance, then just draw the instances in the order they appear in that queue.
 

kamiyasi

Member
I've been thinking about it, and really tilting the camera I think was a boneheaded suggestion. Probably the easiest, and most strightforward solution would be just to depth sort your 3d stuff before drawing it. This, and not using the zbuffer, will also prevent zfighting issues. So if you're not using the normal depth sorting done by gamemaker, you could duplicate it easily. For example you could use a priority queue, and add each 3d instance id to it according to the y position of that instance, then just draw the instances in the order they appear in that queue.
How can I do depth sorting in 3D without using the zbuffer? If I disable zwriteenable the individual model will draw like this.
upload_2017-6-4_12-48-12.png

If I draw separate models in order using a priority queue, would the depth order work properly with the zbuffer on, or would I need to find another way to sort depth for the individual models?
 
hmmm... no, the zbuffer will supersede the depth ordering. Well you could try the tilted camera after all.

try this, where cam_x and cam_y are supposed to be where the center of your view is located, and still using _scale to scale the y position of your models. By the way, I think the best results will be given if the model's origin is at their feet. Oh, and the values 400 and 600 for _y and _z are totally arbitrary, you will need to substitute with the correct values for your camera angle.
Code:
var _y = 400;
var _z = 600;
var _d = sqrt( _y * _y + _z * _z );
var _scale = _d / _z;
d3d_set_projection( cam_x,cam_y * _scale + _y,_z,cam_x,cam_y * _scale,0,0,-_z/_d,_y/_d);
the problem with this is you will still get zfighting if your models are close to each other.

Another thing you could try is continue using the directly top-down camera angle, but try changing the z position of your models based on their y position.
 

kamiyasi

Member
hmmm... no, the zbuffer will supersede the depth ordering. Well you could try the tilted camera after all.

try this, where cam_x and cam_y are supposed to be where the center of your view is located, and still using _scale to scale the y position of your models. By the way, I think the best results will be given if the model's origin is at their feet. Oh, and the values 400 and 600 for _y and _z are totally arbitrary, you will need to substitute with the correct values for your camera angle.
Code:
var _y = 400;
var _z = 600;
var _d = sqrt( _y * _y + _z * _z );
var _scale = _d / _z;
d3d_set_projection( cam_x,cam_y * _scale + _y,_z,cam_x,cam_y * _scale,0,0,-_z/_d,_y/_d);
the problem with this is you will still get zfighting if your models are close to each other.

Another thing you could try is continue using the directly top-down camera angle, but try changing the z position of your models based on their y position.

Yes. Your last suggestion is an earlier idea I had thought of, but I hadn't been able to get a good result with it until now.
Code:
(((y-view_yview[0])*-15)+7200)
This is what ended up working for me, by plugging this into each mesh's z translation. The number 15 is arbitrary and is simply there to ensure there is enough space between objects on the z axis relative to their distance on the y axis. The +7200 is just so they don't recede off of the far clip plane.
 
Top