Screenspace (?) to Worldspace conversion question

Hi there. I was wondering if anyone could tell me what the technique would be to accomplish the following coordinate conversion:

I have a standalone (not unity3d) 2d map editor that lets me draw regions on to a 2D texture. A region is defined as a list of Vector2 values (see attachment 1).

Now, in unity, I read this region definition and want to display the map in a perspective view (see attachment 2).

My goal is to be able to mouse over regions on the map and when the mouse is over a defined region, it should light up so the user can peruse the map and explore points of interest.

So far, I have simply created a plane in Unity and textured it with the map. The plan was to somehow convert the 2d texture coordinates that define the game map regions into 3D region objects in Unity and just catch the mouseover events to highlight the region via shader.

I’m wondering if you know how I might create those region objects, given 2D texture coordinates that were previously captured with the map editor.

Thanks in advance!

348634--12137--$region_197.jpg

So thinking about this some more, I think what I’m probably after is…

  1. How do you convert a texture coordinate to world coordinates?

  2. How do you create a mesh, given a series of vectors?

Regarding the first problem, the first step will be to intersect a ray with the plane that represents the map to yield a world-space intersection point. Then, transform the point into the local space of the map game object to yield the local-space intersection point.

Next you’ll want to discard the ‘unused’ coordinate (e.g. y or z) and normalize the remaining coordinates with respect to whichever corner of the plane corresponds to texture coordinate (0, 0). That is, after normalization, ‘0’ should correspond to the left side of the map and ‘1’ should correspond to the right side of the map, and similarly for the vertical dimension. (This just involves some simple arithmetic.)

Finally, multiply these normalized coordinates by the texture dimensions to yield coordinates in the actual space of the texture (e.g. 1024x1024 or whatever).

Note that I’m assuming here that the texture is mapped ‘exactly’ to the plane, with texture coordinates (0, 0), (1, 0), (0, 1), and (1, 1). If the mapping is different you’ll need to add another step to the process, but the basic idea is the same.

Regarding the second problem, you might be able to make mesh objects corresponding to the regions, but you’d probably need to tessellate the regions into convex polygons first.

Or, alternatively, you could perform a point-in-non-convex-poly test against the vertices that make up the region. (This is probably how I’d do it.)

Thanks for the reply! It is illuminating in some regards, but either I may not have communicated clearly, because if I understand what you’re saying, that is the reverse of what I’m looking for.

The confusion may be in the fact that I said “ScreenSpace”, when really i meant “Pixel Coordinate”. In other words, consider this structure:

struct Point
{
   int X;
   int Y;
}

I have an array of these Points. They are pixel coordinates of the map image. I.e. new Point(512,512) is the center of my 1024 X 1024 image.

I thought my strategy would need to be to transform these pixel coordinates into world space coordinates, so that I could build region meshes from them (maybe that’s the wrong approach).

Based on your notes, I can figure out the plane’s corresponding texture coordinate by doing something like this:

Point p1 = new Point(512, 512); // center of bitmap
double U = p1.X / 1024;
double V = p1.Y / 1024;

Now, is there a way to go from U/V coordinates of the plane to corresponding world coordinates? I assume one of the inputs would be the transform of the plane that has the map image texture on it?

Now that I’m thinking more about, would that even give me what I want? When defining a procedural mesh, the vertices are described in local space, not in world space, is that right?

Or, did I completely misunderstand your post and you were suggesting that I should be converting mouse position coordinates (screen space) (in Update, possibly) and casting rays at the map plane, converting to the bitmap’s texture coordinates and then testing those against my internal Region objects which contain the Point structs, mentioned above?

To clarify, the reason I wanted to create these meshes for the regions, is because I’d like to achieve a more polished look by fading them in over time, putting a rim light on them for the outline, etc, etc. Things I thought should be done with a shader, instead of me trying fancy pixel manipulation at the texture level by hand.

I don’t think you need to get coordinates or whatever.

Make objects with collider, put them on top of special zones, and give them a OnMouseOver ?

I second that :twisted:

That’s what I’m trying to do, programmatically. I have many of these maps and the regions are arbitrarily shaped. I’m trying to put together a generic solution into which I can just plug in map data instead of having to lay the maps out manually with region objects. Considering the arbitrary shapes of the special regions, I’d probably have to do that in Maya or something. That would be the end of the world, for sure. :wink:

i’ll tell you what send me a the picture with the outline of the regions drawn onto it and i’ll make the objects in 3ds i’m in a generous mood and i feel like using 3ds but have no excuse :twisted:

That is very high stuff you are asking for !

I don’t know if it can be done, but about that idea of getting the position on the plane…so you retrieve it. Could you compare it to a texture and retrieve a precise color ?

To be more precise, you have two textures, the first being the normal map, the second being an entire black texture with differents uniform colors instead of special locations.

So you get the position (0.5, 0.5) on the first map. You look at the second map at (0.5,0.5) :

  • The color is black : not at special location
  • The color is not black : special location, identified by its associated color.

It could help to detect, but not for your highlighting objective (I don’t see how a texture can help)…

It looks like you already have plenty of good answers, but sure, you can perform the conversion the other way too (which makes sense if you want to create visual ‘highlights’ for your regions).

As you noted, the process would basically be the reverse of what I described earlier:

  • Map the coordinates from the range [0, 1024] (for example) to the range [0, 1].

  • Map the coordinates from the range [0, 1] to the range [-extent, extent], where ‘extent’ is half of the plane’s size in the respective dimensions (for example, for a plane with width and height equal to 10, extent would always be ‘5’).

That will give you the region coordinates in the local space of the plane. You can then create mesh geometry using those coordinates and assign them to game objects with the same transform as the plane. (You could also adjust both coordinates and transform so that each region was centered at the origin, more or less, in local space.)

This is how I’d handle it:

3 textures:

  • The map as it should look with nothing selected.
  • The map as it would look with everything selected.
  • A splatmap where each selectable area gets a unique color.

1 custom shader that takes the 3 maps and a color value (say SelectedColor).

Each frame you do a camera raycast and get a RaycastHit struct on where it hits. The textureCoord member of that struct will give you the UV coord of the hit area. Do a GetPixel on the splatmap texture for the U * width and V * height to get the pixel value. The texture will need to be set as readable.

Set the SelectedColor value of your shader to the value that you got from the GetPixel above.

In your shader, you check the splatmap for the current pixel, if the color matches SelectedColor (or is close to the same value to account for mipmapping) you display the diffuse from the second texture (the one that shows how it should look when selected), if not you display the diffuse from the primary texture (non-selected map).

You could add a timer value to the shader to have it lerp between main and selected textures so it gradually fades in if you want.

Anyways, that’s how I’d approach the problem as doing a color lookup on a texture and painting some colors onto a splatmap is a lot easier than reading XY coords and doing bounding checks. Plus you wouldn’t need a special program to generate the coordinates, you could use any paint program to paint some areas w/ random colors.

Thanks for the help guys. I know what to do now. :smile: