True 3D Selection for RTS

Hi!

Im wondering how one would implement a REAL 3D selection. It’s well documented how to make a 2D Rect with the GUI canvas system. But what if one wants the selection plane to appear ontop of the terrain? This would also mean that the selection rect has to compensate for height differences on the map…

I thought about using a projector, but I’m not able to figure out how to set an exact projcetion “rect” rather than an orthographic square.

A first idea is using a projector that is big enough to project on the entire terrain (meh). Then, when the user “draws” a selection, dynamically paint on a texture thats as big as the terrain (more meh) and then set this texture for the projector. This seeems like a heavy task and doesn’t really feel “right”.

To clarify: I’m not looking for a finished code script, I’m rather curious how a Unity - pro would solve this task.

What I want is similar to the zoning mechanism in Cities Skylines:

Is the selection still in camera space? I’m not exactly sure what you mean by real 3d, but no matter where the plain is, the solution would be similar, because a 2D plane in camera space isn’t so different from a 2D plane in an arbitrary space.

So anyway… for finding what is selected, I would have a script with a list of all possible selectable Transforms. Next, I’d implement an IsWithin method. Something with a signature like

public static bool IsWithin(this Transform transform, Vector3 dragPoint0, Vector3 dragPoint1)

If the plain is created from camera space, then its pretty simple (camera.WorldToScreen; then 2D check). Otherwise, I’d write a WorldToPlane method.

Next, to draw it. A projector does sound like the “correct” solution. They should be efficient for such a task (?). But I haven’t used them yet, so I’ll offer another option.

I’d use shaders. I’d edit the terrain shader to include it directly (because exactly matching a mesh to the terrain’s shape with an overlay effect would be more difficult).

For the selectable objects, I’d overlay a semitransparent unlit shader. It would be seperate to the main material of the objects, so that I could still use whatever material I’d like, for convenience. So I’d only need one selection shader for general meshes.

Ok, this is basically what you need:

First, download and modify the built in terrain shaders for your unity version:
https://unity3d.com/de/get-unity/download/archive

The ones you are interested in are:

  1. CGIncludes/TerrainSplatmapCommon.cginc

  2. DefaultResourcesExtra/TerrainShaders/Splats/Standard-FirstPass.shader

  3. DefaultResourcesExtra/TerrainShaders/Splats/Standard-AddPass.shader

Copy these Shaders to your unity project. To achieve something like i wanted, just look at the files [104287-shaders.zip|104287]

Note that i put all variables that i modify into the properties panel of the FirstPass.shader. I dont know why, but you cannot set the variables from your code if you dont.
In your script, just set the positions like that:

Terrain.activeTerrain.materialTemplate.SetFloat("_MousePosStartX", DragStart.x);

Dont forget to create a new material and set the FirstPass as shader. (Change the name of your FirstPass at the top of the file to something like “Custom/Terrain”

Set this material as the material for your terrain: