Jump to content


Photo

Oblique Projection Depth Problems - *solved*


  • This topic is locked This topic is locked
10 replies to this topic

#1 hypothete

hypothete

    GMC Member

  • New Member
  • 6 posts

Posted 25 March 2010 - 08:17 PM

Hello everyone. I'm currently in the process of writing an engine that creates procedural buildings in orthographic projection. The approach I'm using does not use 3D, instead everything is rendered out of primitives and surfaces that are then combined into sprites. Each sprite also has a collision mask that fits the base of the building. Here's a picture:

Posted Image

As you might see, here's where I run into trouble. The buildings are randomly placed, and if their masks collide with one another they jump to new locations. However, if they land collision-free, some tend to hover over others in the air. I'm trying to determine how to set the buildings' depth in the Draw event so that this is a nonissue. Do any of you have suggestions?

One way to cheat around the problem would be to have them be completely solid when they are placed, but I later plan to have a character that can walk amongst the buildings, and I'd like as much convincing depth as possible. The variables that each building possesses for position are as follows:

x,y : these are at the top-left corner of the sprite.
w,h : the width and height of the buildings in "units."
sc: scale of the units. Currently at 16 px.
d: depth of the building in units, but not instance depth. This is how far diagonally back the building is drawn.

The sprite is then (w+d)*sc x (h+d)*sc in size. Have any of you solved this problem before? Oblique projection seems like a method that more people would be familiar with, but there's very little internet literature on the subject. Thanks!

EDIT: I just reread the guidelines, so here's a sample of the code I was using for depth in the screenshot. This is in the Draw event for each building:

depth = -1*(((y+h)/sc)+((x+d)/sc));
draw_sprite(bspr,0,x,y);
//draw_text(x,y-16,string((x+d)/sc) + ', ' + string((y+h)/sc) + ', ' + string(depth));

Edited by hypothete, 26 March 2010 - 08:28 PM.

  • 0

#2 sjakaus

sjakaus

    GMC Member

  • New Member
  • 10 posts

Posted 25 March 2010 - 10:21 PM

have you tried setting the depths in accordance with the lower-right hand corner pixel? If I understand correctly that should get them to draw in the right order.
  • 0

#3 hypothete

hypothete

    GMC Member

  • New Member
  • 6 posts

Posted 26 March 2010 - 12:19 AM

have you tried setting the depths in accordance with the lower-right hand corner pixel? If I understand correctly that should get them to draw in the right order.



Thanks for the response. Not a bad idea, but I can't figure out how. Any suggestions?

If anyone would like to take a look at the code itself, you can download the game here: Buildings - GM8 Pro
  • 0

#4 phathod

phathod

    GMC Member

  • New Member
  • 30 posts

Posted 26 March 2010 - 12:24 AM

Will...

depth = -y

work for ya?
  • 0

#5 slayer 64

slayer 64

    Slayer of gingers

  • GMC Member
  • 4301 posts
  • Version:GM:Studio

Posted 26 March 2010 - 02:33 AM

setting the depth in the draw event will not take effect until the next step, because the depth determines what draw events are executed first. i know that doesn't solve your problem though, lol.
  • 0

5y5rs3d.pngfg0UQNL.png


#6 hypothete

hypothete

    GMC Member

  • New Member
  • 6 posts

Posted 26 March 2010 - 03:32 AM

Will...

depth = -y

work for ya?


Thanks, but not this time unfortunately. The problem with this approach is that the y position is determined by the upper-left hand corner of the sprite, and this doesn't take into account buildings behind buildings that are smaller than y+d+h, and it doesn't take into account how overlaps should work on the x-axis.

setting the depth in the draw event will not take effect until the next step, because the depth determines what draw events are executed first. i know that doesn't solve your problem though, lol.


I'm setting the depth at the beginning of the Draw event, and so far it seems to be working. 'Working.' :P
  • 0

#7 torigara

torigara

    GMC Member

  • GMC Member
  • 6507 posts

Posted 26 March 2010 - 07:49 AM

According to your description, y is the top left corner of the sprite and its height is (h+d)*sc. So, the bottom is y+(h+d)*sc. To take account of horizontal overlap, you can add x/(maximum value of x)*(incremental step of y) to it. Have you tried something like:
depth = -(y+(h+d)*sc) - x/room_width;

I'm setting the depth at the beginning of the Draw event, and so far it seems to be working. 'Working.' :P

Yes, it takes effect at the next step, so it would look as if it is working. It will flash at a wrong depth for 1 step, but your eye may hardly catch it.

Edited by torigara, 26 March 2010 - 07:50 AM.

  • 0

#8 hypothete

hypothete

    GMC Member

  • New Member
  • 6 posts

Posted 26 March 2010 - 03:50 PM

According to your description, y is the top left corner of the sprite and its height is (h+d)*sc. So, the bottom is y+(h+d)*sc. To take account of horizontal overlap, you can add x/(maximum value of x)*(incremental step of y) to it. Have you tried something like:

depth = -(y+(h+d)*sc) - x/room_width;


That gets me pretty close! Your room_width idea was a good one. I've 'massaged' the depth code a bit to look like this:

depth = -1*(y+h+d) + room_width/(x+w);

(I should point out that w,h, and d all get multiplied by sc in the Create event)

...which leaves me with one overlapping exception, presumably based on each building's d value. It only messes up if a building with a greater y value of a building next to it is to the left of said other building:

Posted Image
  • 0

#9 flexaplex

flexaplex

    GMC Member

  • Global Moderators
  • 4814 posts
  • Version:GM8

Posted 26 March 2010 - 04:05 PM

If the buildings can have a z value then you are in for a very rocky ride.

You might want to look at this:
http://gmc.yoyogames...howtopic=254952

I spent many months trying to work out a depth formula and trying people's suggestion but could not manage a way to make the depth set flawlessly, I highly question whether it is actually possible.

However I did find a way of setting the depth properly correct, not by using a formula but by a sorting algorithm. Unfortunately doing this is highly inefficient and left the engine lagging to the point of being practically unusable.

Edited by flexaplex, 26 March 2010 - 06:08 PM.

  • 0
:]

#10 Maarten Baert

Maarten Baert

    GMC Member

  • GMC Member
  • 750 posts
  • Version:GM8.1

Posted 26 March 2010 - 05:51 PM

I don't think it's possible to write a depth formula for this. However, it's possible if all buildings are squares (using the center of the part that touches the ground as the origin). You can decompose any grid-based shape into squares. It will work, but it's slightly slower.

Edited by Maarten Baert, 26 March 2010 - 05:52 PM.

  • 0
Posted Image

#11 hypothete

hypothete

    GMC Member

  • New Member
  • 6 posts

Posted 26 March 2010 - 08:24 PM

flexaplex and Maarten, you both got my neurons firing and I came up with a solution that seems to work 99% of the time. Here's a download:

Download here

What I've ended up doing is having each building also create a 'ghost' instance that I'm calling 'bghost' on top of itself. Each bghost holds the id of its parent, and keeps its x,y, and depth identical. The difference between the bghost and the building in terms of detection is their collision masks; the building's mask is just the base, while the bghost's mask is the building sprite. That way, I can have the buildings in their Step event check to see if anything is overlapping wrong in their bottom-right corners, the only area that fails with my new depth formula. They then adjust a value called 'ff' (fudge factor) in their depth formula, like so:

ccheck = instance_position(x+d+w,y+h+2,bghost);
if(ccheck != noone && ccheck != id && ccheck != 0 && ccheck != pg)
{
	if(depth <= ccheck.depth)
	{
		ff+= 2;
	}
}

depth = round(-1*(y+h+d) + room_width/(x+w) + ff);

Thanks all! This can be closed up now. :P
  • 0