4
\$\begingroup\$

So a friend of mine and myself are starting to create our first game together. We descided on doing a 2.5D kind of game, so a static camera that moves with the player but cannot rotate.

I got the collisions object from my friend which in unity looks like this:

enter image description here

Now I'd like to create an overlay with a JPG image which is going to cover the entire viewport and is going to "be" the map itself. I want to use this JPG as a kind of background image and then hide the collisions so the player will walk into the collisions and stop there but can't actually see them. In stead, he will see the image with buildings on it.

enter image description here

How can I do this correctly? I've gotten as far as creating a second camera which will show me the image and then trying to create an Image (Create gameobject -> UI -> Image).

But I cannot find any way to continue on this.

Is this a good way to do this whole 2.5D kind of thing?

We want lightweight maps in our game and thought this was a good idea to go about this.

Edit

My friend and me are trying to create an isometric game like this. The reason behind this is that the amount of work for the map is going to be massively reduced if we can do it like this since he can then just work in photoshop, in which he's super good.

This was he does not have to bother with the 3d design in detail and can make the collision blocks much faster.

So does anyone know how to get this to work? Maybe someone has a partial guide on this because I cannot seem to find anyone doing it like this but I imagine that ie Commandos is made like this.

It would be much appreciated!

\$\endgroup\$
  • \$\begingroup\$ The terminology in this question is quite confusing: Isometric and 2.5D are different beasts. As for the core question: Am I right to summarise that you want to use a flat 2D-plane as a collision map, then render the actual world as a 3D extrusion of that? \$\endgroup\$ – Anko Mar 21 '15 at 18:53
  • \$\begingroup\$ Yes indeed, so the actual detail would be in the image yet the collisions would be made by "invisible" blocks on top of that \$\endgroup\$ – Tikkes Mar 22 '15 at 11:58
  • \$\begingroup\$ Jelle's terminology was clearer, so I changed the question title. \$\endgroup\$ – jhocking Apr 20 '15 at 20:40
  • \$\begingroup\$ I found this, it might help you. mehm.net/blog/?p=1211 \$\endgroup\$ – nosmirck Jul 21 '15 at 6:59
2
\$\begingroup\$

First off, there are a lot of games that did this back in the PS1 era (eg. FF8) so this is definitely a done thing.

Basically, you need to render multiple times, and thus may want multiple cameras. First make the low-res collision geometry visible but the overlay and your characters are invisible, then render normally, then make the collision geometry invisible and the overlay image and your characters visible, then render again with the image buffer overwriting but NOT affecting the depth buffer. That way the character will be correctly occluded by the invisible collision objects.

Or maybe it's the other way around with the multiple renders, I haven't done this in a while. It's one or the other anyway.

EDIT: This requires that the collision geometry is more or less shaped like objects in the background image, so that they'll be correctly occluded. From your screenshot that isn't the case, so you'll need to fix that (eg. the collision mesh for the church has the pointy roof).

\$\endgroup\$
  • \$\begingroup\$ That's exactly how we did it :D youtube.com/watch?v=aAEX7A_OSYY - The trick is to use invisible occluders on the collision geometry that way it's not visible, but still occludes the player. answers.unity3d.com/questions/316064/… - and like you said, two cameras: one that renders ONLY the background and another for the 3d objects on top. Bonus: you can easily do shadows! Question to you jhocking: do you think there's any drawbacks with this approach vs using depth maps? \$\endgroup\$ – vexe Jul 22 '15 at 10:51
1
\$\begingroup\$

I'm sure someone else will address the technical aspects of exactly what you have in mind, but have you considered other approaches that are similar but not quite as extreme?

Your models look like they have a lot of fine details, and a lot of those could be baked to normal/displacement maps. That would leave you with simple geometry, but the type of "overlay" effect you're looking for, where the geometry appears much more detailed than it actually is.

Additionally, it removes the complexity of carefully synchronizing a static image with your 3D scene. You'll also be able to take advantage of Unity 5's new lighting system.

What you're describing is more feasible when you're using a tile-based system and each entity is pre-rendered and stored as an object on a tiled map, often itself covered in pre-rendered textures. Storing the entire map in a pre-rendered state in-memory isn't likely to be very efficient, and will probably be extremely limiting down the road.

\$\endgroup\$
  • \$\begingroup\$ So I'd have to create the entire model in unity itself and leave the overlay behind? That would take a ton of time modelling all those fine details wouldn't it? \$\endgroup\$ – Tikkes Mar 21 '15 at 14:03
  • \$\begingroup\$ I assumed you the detailed picture from your example was rendered in a 3d modelling program. You'd use that modelling program to generate the normal/displacement map for the model, then import the models into Unity3D. It's a pretty standard workflow and should be much more efficient than matching colliders. \$\endgroup\$ – Selali Adobor Mar 21 '15 at 15:34
  • \$\begingroup\$ Thing is, this is made by my friend, he's an artist so I'll ask him. If we can get it like such, I will accept your answer and upvote too. Thanks for the help in advance! \$\endgroup\$ – Tikkes Mar 21 '15 at 15:59
  • \$\begingroup\$ Ok so we are actually creating an Isometric game...we will really need the overlay since it's going to cut down the work for the artist by alot. Any ideas? \$\endgroup\$ – Tikkes Mar 21 '15 at 16:23
  • \$\begingroup\$ Well the artist doesn't need to model anything more than what he or she would with an overlay. It's ok if the models only have two sides, and the other occluded sides are blank. To be more direct, I don't find your original idea to be feasible, that is, I don't think pre-rendering your entire game and matching it with the colliders will work. You could do something like that in 2D and leave all of the 3D aspects to your overlays, but as you currently have it planned, I doubt it will actually work. \$\endgroup\$ – Selali Adobor Mar 21 '15 at 19:25
1
\$\begingroup\$

Z-buffering in a non-prerendered scene

I will use the term pre-rendered background for what you describe as a 2.5D scene, as I assume this is what you are looking for. Ideally, you would want your character to be able to walk around the environment, as if it were not rendered as a flat image. Your character should be able to move behind and in front of objects as he moves away from or towards the camera. The way "drawing only the front-most objects" works is by using a Z-buffer or depth buffer. When rendering a fragment, the depth of the fragment is written to this buffer. When a new fragment is drawn on the same onscreen position, the depth buffer is consulted to see whether this previous fragment was in front of the new one. If so, the new fragment is not drawn.


Solution 1: Z-buffering for pre-rendered backgrounds

Ideally, you would want to exploit this mechanism for your pre-rendered backgrounds as well. Technically, you would do this by rendering two passes of your background: the actual color data and a depth map.

  1. The color pass would be a simple color image. It should obviously be rendered with a camera identical to the one used in your game.
  2. The depth map is a grayscale image that represents the distance of pixels to the camera. White pixels are very close to the camera's near plane, whereas black pixels are very far away from the camera (close to the far plane). Again, this map should be rendered with a camera identical to the one used in your game. Pay special attention to the near and far plane settings here! (You can do a Google search for Depth Map to see an example of these maps)

What you want to do in the draw phase of your game loop, is render the background first. This means, you'd write the color image to the screen. Additionally, you want to copy the depth map to the depth buffer, so that it is filled with the same depth data, as if it were truly rendered as 3D geometry. Note that after these steps, the screen and depth buffer will be in exactly the same state, as if you has truly drawn the state in 3D. You however can render as much detail as you want, as the color and depth data are pre-rendered, thus they don't have any real-time constraints. After that you can simply draw all of your objects on top. Objects that appear behind segments of your pre-rendered background will be occluded correctly if depth buffering is enabled.

Now, this is where you might run into a problem. I'm not very familiar with Unity myself, but I do not know if it is possible to write to the depth buffer directly. If it is not, you could try the following.


Solution 2: Splitting of your pre-rendered background into depth planes

If direct write access to the z-buffer is impossible, you'll need to fill it with the correct depth data "the right way" (i.e. by rendering polygons). A solution would be to split your backgrounds up into multiple layers of different depths. Within a single layer all objects in your pre-rendered background will be considered to be at the same depth plane. For example, if you need to render a scene with a floor, a sky and two church buildings, you would use separate layers for:

  1. The ground + sky: the backmost layer, as the player is always in front of these
  2. The backmost church: an inbetween layer, so that the player can walk both behind and in front of it
  3. The frontmost church: a more nearby layer, so that the player can walk inbetween both churches, as well as in front of the front-most one

Note that this is an approximation! For example, a wall that is not perfectly parallel with the camera should have a gradually increasing depth value as it comes closer to the camera. You will need to be clever in designing your backgrounds, and assigning a single depth value to every layer. This is how it is done in some older PS1 games however, so you should be able to use the same clever tricks.

To actually render your pre-rendered background, you will render all layers separately on full-screen quads. In your shader, make sure to discard fragments (using the discard keyword in GLSL, or something similar) if they are fully transparant. For example, in the depth plane of the frontmost church, you only want to render the church. The area around it should be fully transparant (think of it as a cut-out, or a PNG with a transparant background). By using the discard keyword, you make sure no data is written to the depth buffer. What you will end up with, after rendering all depth planes, is:

  1. The color data of the pre-predered background background drawn onscreen
  2. Your depth buffer filled with multiple depth planes

As in the first solution, you can now draw your objects on top of this setup. Fragments of objects that should appear behind background depth planes will be occluded correctly thanks to automated depth testing with the z-buffer!


To summarize, you will want to make use of the depth buffer (= z-buffer) to achieve your effect. If Unity allows you to write data to the depth buffer directly, pre-rendered depth maps are the way to go. They will provide pixel-perfect depth data, which will make your scene indistinguishable from a true 3D rendered scene. If you can't write data to the buffer directly, the classic approach using depth planes is the way to go. Segment your background into multiple planes, assign depths to them, and render them before drawing anything else.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.