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
1
Question by PeterB · Mar 05, 2011 at 08:41 PM · vector3graphicssteering

Vector math question

I'm working on flocking behaviour AI, and it was a long time since I did any linear algebra, so I would be grateful from some input from anybody who perhaps has these things fresh in memory.

I have an sphere, about 0.5 units in size, which travels forward along its local coordinate system - it's always turned towards its target. Before the sphere is moved (it's not a rigidbody, btw), I cast another much larger sphere (about 2 units) to the point where its velocity would take it if applied as is. That's the ideal, unhindered movement.

If any collisions are detected, what I want to do is rotate the sphere away from the collision point, using the normal of the point of the hit. If the collision takes place very close to the sphere, the new rotation should be exactly that of the normal. The greater the distance, the less the normal should affect the current rotation of the sphere, down to 0 at the very edge of the larger sphere (or "discomfort zone"). This modification, done for all collisions, should result in smooth collision avoidance.

The problem is that I can't seem to get the rotation right. It's difficult to understand what the best practices are in this respect in Unity, especially since quaternions might be involved.

This is what I have so far (the script is attached to the sphere):

var target : Transform; var speed : float = 1.0; var comfortDist : float = 2.0; var r : float; var repulsionExtent : float;

function Start() { r = transform.lossyScale.x; repulsionExtent = comfortDist - r; }

function Update() { if (!target) return; // Turn towards the target transform.LookAt(target);

 var pos : Vector3 = transform.position;
 var dist : float = Time.deltaTime * speed;
 var ray : Ray = new Ray(pos, target.position - pos);
 var dir : Vector3 = transform.TransformDirection(Vector3.forward);
 Debug.DrawRay(pos, dir * 10);

 var hits : RaycastHit[] = Physics.SphereCastAll(ray, comfortDist, dist);
 for (var h in hits) {
     if (h.transform != target && h.collider != this.collider) { 
         var realDist : float = Vector3.Distance(pos, h.point) - r;

         Debug.DrawLine(pos, h.point, Color.red);
         Debug.DrawRay(h.point, h.normal, Color.blue);

         var repulsion = (repulsionExtent - realDist) / repulsionExtent;
         print("Repulsion: " + repulsion);

         //var ftRot = Quaternion.FromToRotation(transform.eulerAngles, h.normal);

         //transform.Rotate(h.normal * repulsion * 180);
         //transform.rotation = Quaternion.LookRotation(transform.rotation + h.normal * repulsion * 180);
         //transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(h.normal), repulsion * 180);
         //transform.rotation = transform.rotation * h.normal * repulsion;

         transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(h.normal), 
                                                       repulsion * -45.0);

     };
 };

 var newdir : Vector3 = transform.TransformDirection(Vector3.forward);
 Debug.DrawRay(pos, newdir * 10, Color.yellow);

 // Move forward
 // transform.Translate(Vector3.forward * dist);

}

As you can see, the actual movement is commented out at the moment. I have also included various non-working rotation attempts, also commented out. The variable "repulsion" spans from 0.0 to 1.0 and represents the amount that the present rotation should be modified by.

I might be working against the Unity API - there might be better ways of accomplishing what I want to do. I need to understand the correct procedure before I start implementing flocking and collision avoidance using potential functions, which would be the next step. The basic problem here is of course fundamental steering via vector rotation. (If I were using rigidbodies I probably would apply forces, which might be simpler.)

Any help most appreciated.

/ Peter

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
2

Answer by Jesse Anders · Mar 06, 2011 at 01:50 AM

I know it's commented out, but this:

var ftRot = Quaternion.FromToRotation(transform.eulerAngles, h.normal);

Is wrong. Quaternion.FromToRotation() takes two vectors as input, and Transform.eulerAngles is really a vector in name only (it's actually just a set of three angles, and has no meaning in the context of the 'from-to' rotation function).

If I recall correctly, the 'canonical' approach to steering behaviors is based on modifying the velocity vector; the orientation is then derived directly from the velocity vector (rather than being updated independently as in your code above).

Here's one way you could go about it though (based on your current implementation).

First, you'll need a parametric value indicating how much the agent's orientation should be effected. Assuming the agent is within the 'discomfort zone', this value can be computed as (pseudocode, untested):

float t = 1 - (distance / comfortDistance);

You can then compute the desired direction as:

Vector3 direction = Vector3.Slerp(currentForward, normal, t);

Then, use Quaternion.FromToRotation() to compute the quaternion that will rotate the current forward vector onto the desired direction vector, and apply it to Transform.rotation, e.g.:

transform.rotation =
    Quaternion.FromToRotation(currentForward, direction) * transform.rotation;

The above is all off the top of my head and is untested, but maybe it'll help point you in the right direction. (Note that you could also re-arrange things and use Quaternion.Slerp() instead; the results should be similar in either case.)

Comment
Add comment · Show 1 · 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 PeterB · Mar 06, 2011 at 07:54 AM 0
Share

Thanks, much appreciated. Your suggestion worked. This is what the rotation looks like now:

var currentForward : Vector3 = transform.TransformDirection(Vector3.forward); var newdir : Vector3 = Vector3.Slerp(currentForward, h.normal, repulsion); transform.rotation = Quaternion.FromToRotation(currentForward, newdir) * transform.rotation;

This gives exactly the behaviour I needed: and the objects stay away from each other and exhibit flocking behaviour in doing so. Now I just have to figure out why the terrain normals always seem to follow the ray between the agent and the impact point...

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

Change transform.forward while slerping rotations around the transform.forward axis 1 Answer

Drawing borders between an array of objects 1 Answer

Car Front Tires rotation clamped between 270° - 90° 0 Answers

How to Clamp LookAt on the Y Axis 1 Answer

Help with my Flocking Algorithm 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