Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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 devstudents · Nov 15, 2014 at 03:22 AM · rotationinstantiateraycastterrainslope

Make an instantiated object match the slope of the terrain

I'm trying to get my instantiated building to not clip through the terrain when I build on a slight slope. I've managed to get the building to drop to the terrain y coordinate but the x and z rotations of the building are not consistent with the gradient of the slope and so the building cuts through the terrain.

I've been researching this for about two hours and I'm finding it really hard to understand the posts about raycast normal. Can someone please explain how to do this in very simple terms? Here is the script:

 void Update()
 {
     Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
     RaycastHit hitInfo; 
 
     if(currentlySelectedBuilding != null)
     {
         if(Physics.Raycast(ray, out hitInfo, Mathf.Infinity))
         {
             if(hitInfo.collider.tag != null && hitInfo.collider.tag == "Ground")
             {
                 Vector3 groundPosition = hitInfo.point;
 
                 //I'm rounding the coordinates so it's easier to place buildings in perfectly straight lines etc. 
                 int x = Mathf.FloorToInt(hitInfo.point.x);
                 int z = Mathf.FloorToInt(hitInfo.point.z); 
                 
                 roundedMousePosition.x = x;
                 roundedMousePosition.z = z; 
 
                 //this allows me to place buildings on the same level as the slope
                 roundedMousePosition.y = groundPosition.y; 
 
                 //I need some code here to change the rotation of currentlySelectedBuidling so matches the slope:
                 
                 //??????????????????????????????????????????// 
 
                 //make the gameObject equal to the mouse position so I can move it around the map
                 currentlySelectedBuilding.transform.position = roundedMousePosition; 
 
                 //this script detects when the building is hovering over another object that should be built on. 
                 oCD = currentlySelectedBuilding.GetComponent<ObjectCollisionDetecter>(); 
                 
                 //rotate building while it's hovering
                 if(Input.GetKeyUp("r"))
                 {
                     currentlySelectedBuilding.transform.Rotate(0,-90,0); 
                 }
 
                 if(Input.GetMouseButtonDown(0) && oCD.objectBelow == false )
                 {
                     //sets the building at the location it was at when mouse0 was hit. 
                     currentlySelectedBuilding.transform.position = roundedMousePosition; 
 
                     //I had to make the prefab ignore raycast hit while it was moving otherwise it interacts with the raycast and creates weird artefacts. 
                     //since I now want the ray to detect it, I changed it back to obstacle. 
                     currentlySelectedBuilding.layer = LayerMask.NameToLayer("Obstacle");
 
                     //this gets around the building(clone) problem. 
                     currentlySelectedBuilding.name = buildingName;
 
                     //update graph so units avoid building 
                     AstarPath.active.UpdateGraphs(currentlySelectedBuilding.collider.bounds); 
 
                     //make the building and ocd script null. 
                     currentlySelectedBuilding = null; 
                     oCD = null; 
                 }
                 else if (Input.GetMouseButtonDown(0) && oCD.objectBelow == true)
                 {
                     Debug.Log("You must build somewhere else!"); 
                 }
             }
         }
     }
 }

  
 
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 robertbu · Nov 15, 2014 at 03:24 AM

You can do something like this:

 function SpawnObject(prefab : GameObject, worldPos : Vector3) {
     var hit : RaycastHit;
     if (Physics.Raycast(worldPos, Vector3.down, hit)) {
         var go = Instantiate(prefab, hit.point, Quaternion.identity);
         go.transform.rotation = Quaternion.FromToRotation(transform.up, hit.normal) * go.transform.rotation;
     }
 }

'worldPos' should be a coordinate that has the right x and z positions, and a 'y' position guaranteed to be above the surface of the terrain. The raycast returns a normal (perpendicular) vector to the surface. The Quaternion.FromToRotation() will rotate the prefab to match the angle.

P.S. For future questions, please post your script. It gives us information like what language you are coding in, and it allows us to tailor the answer to your code.

Comment
Add comment · Show 5 · 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 devstudents · Nov 15, 2014 at 08:20 PM 0
Share

I'm sorry about that. I've edited the question so it has the original script.

avatar image robertbu · Nov 15, 2014 at 08:59 PM 0
Share

Since there is no Instantiate() in this code, that you are dealing with the section starting on line 40. Here is a bit of a untested rewrite of your code to add alignment:

     if(Input.Get$$anonymous$$ouseButtonDown(0) && oCD.objectBelow == false )
     {

         Transform tr = currentlySelectedBuilding.transform;
         RaycastHit hit;

         // Aligns the building with the surface
         if (Physics.Raycast (rounded$$anonymous$$ousePosition + 100 * Vector3.up, Vector3.down, out hit)) {
             tr.rotation = Quaternion.FromToRotation(trrm.up, hit.normal) * tr.rotation;
         }

         //sets the building at the location it was at when mouse0 was hit.
         currentlySelectedBuilding.transform.position = rounded$$anonymous$$ousePosition; 
         
         //I had to make the prefab ignore raycast hit while it was moving otherwise it interacts with the raycast and creates weird artefacts. 
         //since I now want the ray to detect it, I changed it back to obstacle. 
         currentlySelectedBuilding.layer = Layer$$anonymous$$ask.NameToLayer("Obstacle");
         
         //this gets around the building(clone) problem. 
         currentlySelectedBuilding.name = buildingName;
         
         //update graph so units avoid building 
         AstarPath.active.UpdateGraphs(currentlySelectedBuilding.collider.bounds); 
         
         //make the building and ocd script null. 
         currentlySelectedBuilding = null; 
         oCD = null; 
     }

Adjust the 100 as needed. If no other objects but the 'terrain' can be in teh way, you can use the more efficient Collider.Raycast().

avatar image devstudents · Nov 15, 2014 at 10:56 PM 0
Share

Thanks a lot! There is no instantiate in the update because the object has already been instantiate via another method governed by another script. It's instantiated the entire time it follows the mouse around. However your code works wonderfully!

The only problem is that sometimes the y is a bit off (it will either be half submerged or completely under the terrain). I tried deleting my y code on line 22 but then it would instantiate on the zero coordinate when I build on terrain that drops below zero. $$anonymous$$aybe my mistake is having terrain that goes below the zero coordinate?

avatar image robertbu · Nov 16, 2014 at 04:12 AM 0
Share

Not sure why your positioning is wrong, but an easy fix is to use the hit.point from the Raycast to do the positioning. If the pivot for your object is not at the bottom, you might have to the 'y'.

avatar image devstudents · Nov 16, 2014 at 04:28 AM 0
Share

Line 12 and 22 make the y equivalent to the hitpoint y. So it's fine when I build on flat surfaces. When I build on slopes, the angles are great thanks to your code, but the y is sometimes not great. I'm guessing it's because the slopes are uneven so if I click a point that is lower than the surrounding points then the object will instantiate below the surface. If I find a way to get all the y points under the object and then instantiate on a y equal to the average of all those points, that might solve it. I just have no idea how I'd do that.

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

1 Person is following this question.

avatar image

Related Questions

Making a particle effect parallel to the slope of a terrain 1 Answer

Instantiate not shooting in right direction 1 Answer

rotating gameobject according to terrain before instantiate 1 Answer

Unity Invisible Collision With Slope [Rotation Issue] 0 Answers

Unity 3D C# - OnControllerColliderHit Position 0 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