Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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
0
Question by webstalk3r · Dec 13, 2020 at 10:28 PM · camerascriptingproblem

RTS selection with frustum

So, pretty standard task for RTS game: select multiple units via mouse.

I use well-known way: call ScreenPointToRay for starting and ending points, calculate rectangle with World coordinates and call Physics.OverlapBox with given size and camera rotation.

The problem begins with selection for units that are closer to left/right edges, because Box is not the right figure. It must be some kind of frustum with not-parallel top and bottom planes (terrain is horizontal, camera rotated 45deg to terrain).

In other words, I need to make kind of 3D collider from camera selection rect to projected rect on terrain and than find object that collided with it.

I know there is a CalculateFrustumPlanes for getting 6 planes, corresponds to camera viewport, but I need narrower figure (only selected part of camera viewport) and I haven’t found any method to find Overlaps within planes intersection.

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 Eno-Khaon · Dec 13, 2020 at 11:42 PM

This suggestion doesn't factor in Physics.OverlapBox(), and uses just the center point of each unit, but it should definitely be adaptable as needed.

Let's start by plotting out efficiency at the beginning. It may seem like a silly thing to do, but for a Real Time Strategy game, where you can expect most units to not be visible on screen at a time, this should be able to help significantly overall.

First, let's combine MonoBehaviour/Renderer.OnBecameVisible() with a handy custom script extension, Renderer.IsVisibleFrom(Camera).

 void OnBecameVisible()
 {
     // Simplifying a few variables that are presumed to be kept track of
     
     // if the player's main camera sees the unit
     // and the player owns that unit...
     if(renderer.IsVisibleFrom(playerCamera) && unit.owner == player)
     {
         // Add the unit to a List<Transform> of friendly/owned units currently in view
         player.visibleUnits.Add(transform);
     }
 }

 void OnBecameInvisible()
 {
     if(player.visibleUnits.Contains(transform))
     {
         player.visibleUnits.Remove(transform);
     }
 }



With this out of the way, there are now far fewer units to work with at a time when determining your selection bounds. From here, after you've created your selection box in your viewport, you can run through the on-screen unit list and convert the units' positions to viewport coordinates:

 // When the mouse is released after creating the selection box...
 if(selectionBoxFinalized)
 {
     for(int i = 0; i < player.visibleUnits.Count; i++)
     {
         // Screen point, viewport point, etc.
         if(selectionBoxRect.Contains(playerCamera.WorldToViewportPoint(player.visibleUnits[i].position)))
         {
             AddToSelection(player.visibleUnits[i]);
         }
     }
 }


Even if this doesn't suit your needs exactly, hopefully this can help get you pointed in a good direction.

Edit: Fixed typo
Comment
Add comment · Show 4 · 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 webstalk3r · Dec 15, 2020 at 05:30 PM 0
Share

Thank you for your solution.

Thought of that way too. Will give it a try if my method won’t work.

What I’m trying to do - get two rects (similar to nearClipPlane and farClipPlane except the size is not whole viewport but selection rect) and then build a mesh with collider from their vertices.

I solved problem with back face of that mesh (it looks like trapezoid) and now I’m trying to get correct vertices from ScreenToWorld and mousePoint. It works when camera not rotated but when I apply orbit rotation (camera with offset in empty game object) - Vector3 becomes incorrect.

avatar image Eno-Khaon webstalk3r · Dec 15, 2020 at 07:40 PM 0
Share

If you're defining your 3D selection box's corners using something akin to...

 // msr = mouse selection rect, to save space on repetition
 Vector3 topLeftNear = playerCamera.ScreenToWorldPoint(new Vector3(msr.x$$anonymous$$in, msr.x$$anonymous$$ax, selectionBoxNearDistance));
 Vector3 topLeftFar = playerCamera.ScreenToWorldPoint(new Vector3(msr.x$$anonymous$$in, msr.x$$anonymous$$ax, selectionBoxFarDistance));

... then I'm honestly not sure why you would be seeing errant values from it.

What are you using as your logic to project the vertices from the camera's space?

avatar image webstalk3r Eno-Khaon · Dec 15, 2020 at 10:28 PM 0
Share

I project rect to ground with ray casting and it works fine. I get errant values for top rect cause mousePosition only have x,y coords. So at any camera rotation you will get the same 2d coords and front rect always facing directly to 0 Y rotation.

So I need to rotate points from ScreenToWorld to the same angle as my camera in order to calculate right 3D position of that rect to face my camera at any current rotation.

Just adding multiplication for ScreenToWorld Vector3 with camera Quartenion doesn’t work. I’ll try to make code sample and show visually how it looks.

I know for sure that I don’t calculate correct coords for last two points of rect.

Show more comments
avatar image
0

Answer by webstalk3r · Dec 16, 2020 at 02:04 AM

So, what I have now. Camera is inside CameraRig object

 CameraRig - pos (0, 0, 0) rot (0, 0, 0)
 ===> Camera - pos (0, 20, -40) rot (45, 0, 0)

I visualized front face rect, as you can see if there is no rotation (or rotation by 180deg) - all ok alt text

But when I rotate CameraRig (rotation Y) I get same orientation for that rect (even with correct position).

alt text

Here is some code

 // selectionStartMouse == Input.mousePosition at start
 // selectionEndMouse == Input.mousePosition now

 var frontRect = GetScreenRect(selectionStartMouse, selectionEndMouse);

 var frontBottomLeft = GetMouseToWorldPoint(new Vector3(frontRect.xMin, frontRect.yMin));
 var frontTopRight = GetMouseToWorldPoint(new Vector3(frontRect.xMax, frontRect.yMax));

 // I know that next two lines are incorrect, cause calculation of last 2 corners of rect will work that way only without rotation, but the main problem with first two from ScreenToWorldPoint
 var frontTopLeft = frontTopRight.SetX(frontBottomLeft.x); // SetX == replace x coord
 var frontBottomRight = frontBottomLeft.SetX(frontTopRight.x);
 
     public static Rect GetScreenRect(Vector3 screenPosition1, Vector3 screenPosition2)
     {
         var topLeft = Vector3.Min(screenPosition1, screenPosition2);
         var bottomRight = Vector3.Max(screenPosition1, screenPosition2);
         
         return Rect.MinMaxRect(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
     }
 
     public static Vector3 GetMouseToWorldPoint(Vector3 coords)
     {
         coords.z = cam.nearClipPlane + 0.5f; // move away a bit from viewer
 
         return GetCamera().ScreenToWorldPoint(coord);
     }


снимок-экрана-2020-12-16-в-044538.jpg (368.8 kB)
снимок-экрана-2020-12-16-в-044441.jpg (129.8 kB)
Comment
Add comment · Show 4 · 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 Eno-Khaon · Dec 16, 2020 at 10:04 AM 0
Share

Based on the screenshots (and some personal testing), I can only suspect that your line:

 public static Vector3 Get$$anonymous$$ouseToWorldPoint(Vector3 coords)
 {
     // vvv     vvv
     return GetCamera().ScreenToWorldPoint(coord);
     // ^^^     ^^^
 }

is the problem here. Are you certain you're referencing the correct camera? Your coordinates look fine in the first image, but it seems like it should only be possible to have the problem in the second if the wrong camera is referenced.

I used the following script for a quick test:

 // Script moved to following reply, due to character limits


Using this script for testing in the editor, I can draw a simple box, then go to the scene view (i.e. another camera) and view the 3D box, oriented to match the rotation of the camera (when the box is changed).

avatar image Eno-Khaon Eno-Khaon · Dec 16, 2020 at 10:04 AM 0
Share
 using UnityEngine;
 
 public class CameraBoxTest : $$anonymous$$onoBehaviour
 {
     Vector3 mouseDown = new Vector3(50f, 50f, 50f);
     Vector3 mouseUp = new Vector3(250f, 250f, 250f);
     Camera cam;
     public float $$anonymous$$Depth = 1.0f;
     public float maxDepth = 10.0f;
     Vector3[] positions;
 
     void Start()
     {
         cam = Camera.main;
         positions = new Vector3[8];
     }
     
     void Update()
     {
         bool changed = false;
         if(Input.Get$$anonymous$$ouseButtonDown(0))
         {
             mouseDown = Input.mousePosition;
             changed = true;
         }
         else if(Input.Get$$anonymous$$ouseButton(0))
         {
             mouseUp = Input.mousePosition;
             changed = true;
         }
 
         if(changed)
         {
             positions[0] = cam.ScreenToWorldPoint(new Vector3(mouseDown.x, mouseDown.y, $$anonymous$$Depth)); // front bottom left
             positions[1] = cam.ScreenToWorldPoint(new Vector3(mouseUp.x, mouseDown.y, $$anonymous$$Depth)); // front bottom right
             positions[2] = cam.ScreenToWorldPoint(new Vector3(mouseUp.x, mouseUp.y, $$anonymous$$Depth)); // front top right
             positions[3] = cam.ScreenToWorldPoint(new Vector3(mouseDown.x, mouseUp.y, $$anonymous$$Depth)); // front top left
             positions[4] = cam.ScreenToWorldPoint(new Vector3(mouseDown.x, mouseDown.y, maxDepth)); // back bottom left
             positions[5] = cam.ScreenToWorldPoint(new Vector3(mouseUp.x, mouseDown.y, maxDepth)); // back bottom right
             positions[6] = cam.ScreenToWorldPoint(new Vector3(mouseUp.x, mouseUp.y, maxDepth)); // back top right
             positions[7] = cam.ScreenToWorldPoint(new Vector3(mouseDown.x, mouseUp.y, maxDepth)); // back top left
         }
 
         Debug.DrawLine(positions[0], positions[1], Color.red);
         Debug.DrawLine(positions[1], positions[2], Color.red);
         Debug.DrawLine(positions[2], positions[3], Color.red);
         Debug.DrawLine(positions[3], positions[0], Color.red);
 
         Debug.DrawLine(positions[4], positions[5], Color.blue);
         Debug.DrawLine(positions[5], positions[6], Color.blue);
         Debug.DrawLine(positions[6], positions[7], Color.blue);
         Debug.DrawLine(positions[7], positions[4], Color.blue);
 
         Debug.DrawLine(positions[0], positions[4], Color.green);
         Debug.DrawLine(positions[1], positions[5], Color.green);
         Debug.DrawLine(positions[2], positions[6], Color.green);
         Debug.DrawLine(positions[3], positions[7], Color.green);
     }
 }
avatar image webstalk3r Eno-Khaon · Dec 16, 2020 at 11:01 AM 0
Share

GetCamera() == Camera.main of course, didn't mention that.

I have only one camera in the scene.

Thank you very much for your time.

Will review my code, your solution works like a charm!

Show more comments

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

219 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 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 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

How to make camera position relative to a specific target. 1 Answer

when I use shader grass is disappearing 0 Answers

iOS + Android: Camera Feed in Unity 0 Answers

Game preview incorrect! 0 Answers

Camera appearance black & white 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