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
0
Question by Salmjak · Aug 27, 2015 at 09:11 PM · c#gameobjectraycastmodelarea

Bottom area of a 3D model? Raycast?

Hi! I'm working on a system that is like any common RTS. You press a building and put it down where ever you want.

Too be able to level the ground (heightmap) where I put a building I have to know which points to edit (I want to level the area to avoid some parts going through the terrain). So how would I go about to get the area (and corresponding points) of a 3D model/gameobject?

Should I just use Raycast over a large area around the 3D model, see which ones hit terrain and which hit the 3D model. Then use the ones that hit the 3D model as the points to edit in the heightmap? This feels very inefficient though, especially when I don't know which size each model is (so I don't know for sure what the smallest possible area to search is). So if raycasts is the best way, how can I optimize it based on model-size?

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

1 Reply

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

Answer by cjdev · Aug 27, 2015 at 10:23 PM

Personally I wouldn't use raycasting here as you already have the position data of the model and of the terrain. Basically I'd compare the verts in the model to the terrain mesh and get the ones that are closest to the model. An implementation might go something like this (please note this is very much untested):

     GameObject building = GameObject.Find("Building");
     GameObject terrain = GameObject.Find("Terrain");
 
     Mesh mesh = building.GetComponent<MeshFilter>().mesh;
     List<Vector3> verts = mesh.vertices.ToList();
 
     int minX = (int)verts.Min(v => v.x);
     int minZ = (int)verts.Min(v => v.z);
 
     int maxX = (int)verts.Max(v => v.x);
     int maxZ = (int)verts.Max(v => v.z);
 
     //Note: this assumes your terrain is 0,0 based and unscaled, add offsets as needed
     float[,] terrainHeights = terrain.GetComponent<Terrain>().terrainData.GetHeights(minX, minZ, maxX - minX, maxZ - minZ);
     List<Vector3> terrainVerts = new List<Vector3>();
     //Populates a list of terrain vertices from the hieghts list
     for(int i = minX; i < maxX; i++)
     {
         for(int j = minZ; j < maxZ; j++)
         {
             terrainVerts.Add(new Vector3(i, terrainHeights[i - minX, j - minZ], j));
         }
     }
     //Removes all terrain verts farther than 1 from model verts
     //Could be implemented with loops instead of LINQ
     //These are the verts you need to modify in your terrain
     terrainVerts.RemoveAll(v => verts.Exists(x => Vector3.Distance(v, x) > 1f));

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 Salmjak · Aug 28, 2015 at 03:35 PM 0
Share

Thanks a bunch for such an elaborate answer!

I get an array index is out of range-error on the last part (terrainVerts.Add...) and can't for the life of me figure out what is causing it.

EDIT: After some time I finally remembered that heightmap coodinates are indexed [y,x] (the reverse, for some (to me) illogical reason). Flipped the "terrainHeights[i - $$anonymous$$X, j - $$anonymous$$Z]" to "terrainHeights[j - $$anonymous$$Z, i - $$anonymous$$X]" and now I don't get any errors :) Will mark you answer as correct now!

avatar image Salmjak · Aug 28, 2015 at 06:38 PM 0
Share

Hmm... Apparently the "Remove" part removes ALL the elements in the list. First I thought it had to do with the height not being scaled to world-coords (so I scaled it by *terrainData.size.y). But that didn't work. Then I changed it to only compare x and z coordinates with this: terrainVerts.RemoveAll(v => verts.Exists(x => $$anonymous$$athf.Abs(v.x - x.x) > 1f)); but it still removes all elements.

EDIT: Realised this was wrong and did an good ol' pythagoras (comparing points on x- and z-axis), but only get 3 elements that fullfill the requirement. I guess this is because the code only checks for any element in both lists that agree to the condition, and then remove it. So if point B and A are at a greater distance than 1 then they are removed, but B is within the distance of 1 to C so we don't want it to be removed.

avatar image cjdev · Aug 28, 2015 at 07:26 PM 1
Share

Yeah sorry about that, I wasn't sure if the Linq was right without testing it. You're probably better off just using good old fashioned for loops but you might try something like this (still untested though):

 var result = from i in terrainVerts
                      from j in verts
                      where Vector3.Distance(i, j) < 1f
                      select i;
avatar image Salmjak · Aug 28, 2015 at 07:49 PM 1
Share

That worked perfectly! I just changed the condition to $$anonymous$$athf.Sqrt($$anonymous$$athf.Pow((i.x - j.x),2f) + $$anonymous$$athf.Pow((i.z - j.z),2f)) < 1f since I don't really care about the y-axis. (I also noticed earlier when I was reworking your code that my mesh was hollowed at the bottom, so just matching the x- and z-axis might be better for the models I'm using, although I probably will get many duplicates. So your way is totally better if the model allows it).

EDIT: $$anonymous$$ight add that you can use HashSet or List.Distinct() to get rid of duplicates. Went from a list of about 3700 vectors to 117 (with both methods, same 3D model).

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

28 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

Related Questions

How to store player model and then swap the model to an object I Raycast hit? 0 Answers

AI Instantiate targets/prefab. (pick target issue) 1 Answer

Find if any gameObject exists in an exact Vector3? 0 Answers

Getting game logic object from GameObject 1 Answer

compare raycast hit with list of gameobjects c# 2 Answers


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