Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by Hafnernuss · Oct 18, 2017 at 06:54 AM · 3dprogrammingprojector

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: https://www.skylinescity.com/wp-content/uploads/2014/08/cities-skylines.png

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by theLittleSettler · Oct 20, 2017 at 09:27 AM

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.

Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Hafnernuss · Oct 20, 2017 at 09:35 AM 0
Share

Hi, thanks for your response. To be clear on what I want: http://answers.unity3d.com/questions/442581/how-to-draw-a-grid-over-parts-of-the-terrain.html

This is a similar question, although I dont want to draw a fixed sized grid but a rectangle which is specified by mouse input. The provided solutions mostly use a mesh which is overlayed on the terrain. As you correctly point out, this is a. more difficult and b. not as "beautiful".

$$anonymous$$odifying the terrain shader could be a good idea, but I'm quite new to shader program$$anonymous$$g. How would you modify that shader? I would need several inputs, such as mouse position and if the mouse button is clicked.

avatar image theLittleSettler · Oct 20, 2017 at 10:19 AM 1
Share

well, first you'll need to copy all the relevent files for the terrain shaders. Its not too complicated, but there are a few. First, there's three actual terrain shaders 1 - the first pass terrain shader that draws the first four textures 2 - the add pass shader, drawing each successive four textures 3 - a simple distant shader

And a couple of include files but the one you might need is TerrainSplatmapCommon.

So first, copy the relevent files...I guess just add pass and first pass, along with TerrainSplatmapCommon.

Then I'd edit the SplatmapFinalColor function in TerrainSplatmapCommon, using IN.tc_Control (that's the uv coordinates to the splatmap). You could edit it later in the process, to make it occur after lighting, fog, etc. You can always move when it occurs though...have a look at the finalcolor function in the unity docs.

Anyway, you'd have to pass the two positions defining the rectangle to the shader (Shader.SetGlobalFloat, or material.SetFloat), relative to the terrain position, scaled to the 0..1 range.

The shader code would be something like:

 fixed4 selectionColor; // rgb, a is blend amount. This'd be a property (add to shaders property blocks), for convenience. 
 float2 dragPosition0, dragPosition1; // x, z position. Not properties, only applied through code. There used to be a thing where unity wouldn't set the values through code if something is a property, not sure if its still the case. 
 
 void SplatmapFinalColor(Input IN, TERRAIN_SURFACE_OUTPUT o, inout fixed4 color)
 {
     <snip>
     
     float2 $$anonymous$$ = ...;
     float2 max = ...;
 
     if (IN.tc_Control.x < $$anonymous$$.x && ... etc)
     {
         // mix, because if you just added colour you might be adding it beyond the colour range
         color.rgb = color.rgb * (1.0 - selectionColor.a) + selectionColor.rgb * selectionColor.a;
     }
 }

Hope that's enough to get you going. Oh, and after I'd finished I'd rename the shaders (and change related stuff, which is the #include statements, and the menu path for each shader) so I could still use the unedited terrain shaders if I wanted.

avatar image Hafnernuss · Oct 20, 2017 at 02:16 PM 0
Share

It works!

Only problem I have is, that if i dont set the "selection color" value of the shader in each frame, the selection is not visible. Further, if i dont CHANGE the color in each frame, no selection is visible. This is the shader code:

 //FirstPass.shader:
 Properties {
         ......
         _SelectionColor("Selection Color", Color) = (1,1,1,1)
     }
 
 //SplatmapCOmmon.cginc:
 ....
 fixed4 _SelectionColor;
 ...
 void SplatmapFinalColor(Input IN, TERRAIN_SURFACE_OUTPUT o, inout fixed4 color)
 {
     ......
 
         float xBegin = $$anonymous$$(_$$anonymous$$ousePosStart.x, _$$anonymous$$ousePosEnd.x);
         float xEnd = max(_$$anonymous$$ousePosStart.x, _$$anonymous$$ousePosEnd.x);
         float yBegin = $$anonymous$$(_$$anonymous$$ousePosStart.y, _$$anonymous$$ousePosEnd.y);
         float yEnd = max(_$$anonymous$$ousePosStart.y, _$$anonymous$$ousePosEnd.y);
 
         if (IN.worldPos.x > xBegin && IN.worldPos.x < xEnd)
         {
             if (IN.worldPos.z > yBegin && IN.worldPos.z < yEnd)
             {
                 color.rgb = color.rgb * (1.0 - _SelectionColor.a) + _SelectionColor.rgb * _SelectionColor.a;
             }
         }
 }
avatar image theLittleSettler · Oct 21, 2017 at 08:30 AM 0
Share

Well, that's not something I've seen before, but my guess is _SelectionColor is being used by something else, globally. Or maybe something is assigning the terrain material per frame.

avatar image Hafnernuss theLittleSettler · Oct 23, 2017 at 02:47 PM 0
Share

I changed the name, still nothing. Could it be the ordering in the shader code? I have no idea how and when the suf and SplatmapFinalColor functions are drawn, but ofcourse my SplatmapFinalColor should be the last one, right? How can i enforce that?

avatar image Hafnernuss Hafnernuss · Oct 23, 2017 at 03:13 PM 0
Share

It works now! For the sake of readability, I will add the entire process as seperate answer. Thanks again for your help!

avatar image
0

Answer by Hafnernuss · Oct 23, 2017 at 03:24 PM

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 attached

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:

alt text


shaders.zip (4.0 kB)
unbenannt.png (74.9 kB)
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

81 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Multiple Cars not working 1 Answer

need help regarding rotating arm 0 Answers

Creating A Seesaw Lever 0 Answers

Help 3D Enemy Detection Visual Feedback 3 Answers

Reflect the whole picture to the slope 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges