Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Math/Transform problem - Raycast direction is different depending on axis

Discussion in 'Scripting' started by _FLX, May 29, 2016.

  1. _FLX

    _FLX

    Joined:
    Nov 10, 2015
    Posts:
    85
    Hi,

    I'm trying to make a predictable faked-random gun recoil pattern for a multiplayer game.
    After playing with unity a bit I have a nice result, when unloading my weapon the pattern is always the same and impact decals are placed on points that look like random.

    I have still a strange problem : The pattern is different depending if i'm shooting in horizontal or vertical axis.
    Here is a screenshot to show you, I have 2 perpendicular walls (perfectly aligned on world rotation) and shot twice on each of them.
    CCSCREEN.png

    I can't explain this difference.

    My prefabs are set like this :
    Player > PlayerWeapon > BulletSpawner.
    When I shoot, a raycast go forward from bullet spawner.

    Here is my shooting code :
    Code (CSharp):
    1.  
    2.                 rayCastDirection = bulletSpawner.forward;
    3.                 //if(shootNb > 1) {
    4.  
    5.                     // Here is the pattern function.
    6.                     spread = Mathf.Lerp(0, (Mathf.Cos(shootNb) * 0.05f), (shootNb / BulletsNb)) * 2;
    7.                     spread = Mathf.Clamp(spread, -gunAccuracy, gunAccuracy);
    8.  
    9.                     rayCastDirection = rayCastDirection + new Vector3(
    10.                         ((shootNb % 2 != 0) ? spread : -spread) + (Mathf.Cos(shootNb) * 0.1f),
    11.                         ((shootNb % 2 != 0) ? -spread : spread) + (Mathf.Cos(-shootNb) * 0.1f),
    12.                         spread
    13.                     );
    14.                 //}
    15.  
    16.             ray = new Ray(bulletSpawner.position, rayCastDirection);
    17.  
    18.             if(Physics.Raycast(ray, out hit, FireRange)) {
    19.                 // hit something
    20.                 Debug.DrawRay(bulletSpawner.position, rayCastDirection * Vector3.Distance(hit.point, bulletSpawner.position), Color.green, 10, false);
    21.  
    22.  
    23.             } else {
    24.                 // nothing hit
    25.                 Debug.DrawRay(bulletSpawner.position, rayCastDirection * FireRange, Color.green, 10, false);
    26.             }
    27.  
    28.         GameObject impactDecal = (GameObject) Instantiate(
    29.             wallImpactDecals[Random.Range(0, wallImpactDecals.Length)],
    30.             hit.point + hit.normal * 0.01f,
    31.             Quaternion.FromToRotation(Vector3.up, hit.normal)
    32.         );
    33.  
    Maybe you'll find something stupid.
    Thanks if you can help or give advice.
     
    Last edited: May 29, 2016
  2. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    I'm not sure, but it seems you're are computing your spread directly in world space. Maybe you could try to, first, compute the spread in local space, then, rotate the directions with the player rotation. This way the pattern is rotation independent.
     
  3. _FLX

    _FLX

    Joined:
    Nov 10, 2015
    Posts:
    85
    Aren't they already in local space ? Because the direction is not wrong, when i shot it follows the player rotation.

    raycastDirection is initialized with bulletSpawner local forward, then I just add a small spread noise.

    I tried to replace position with localPosition but it's worst, raycast goes in strange directions and player is shooting at itself
     
  4. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Code (CSharp):
    1.                     rayCastDirection = rayCastDirection + new Vector3(
    2.                         ((shootNb % 2 != 0) ? spread : -spread) + (Mathf.Cos(shootNb) * 0.1f),
    3.                         ((shootNb % 2 != 0) ? -spread : spread) + (Mathf.Cos(-shootNb) * 0.1f),
    4.                         spread
    5.                     );
    Here the rayCastDirection is probably ok and I guess it rotate with the player. However the term you are adding to it is in world space... though I don't see where you're using rayCastDirection.
     
  5. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    BTW, why are you not using a random function to compute the spread? Why cos?
     
  6. _FLX

    _FLX

    Joined:
    Nov 10, 2015
    Posts:
    85
    Post edited, rayCastDirection was called direction (original code is good, is just made it shorter to post).

    I'm not using a random function because i need a predictable impact position to keep server and clients synced.
    Cos and %2 are little tweaks to make it look random using shootNb.
     
  7. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Did you fixed it?

    Do you know that you can seed the random number generator with the same number both on the client and the server so that you obtain the exact same series of random numbers?
     
  8. _FLX

    _FLX

    Joined:
    Nov 10, 2015
    Posts:
    85
    I didn't know, this can useful.
    I'll still use cos because it allows me to have some kind of point distribution continuity, like a natural recoil. In game it feels realistic enough.

    I still don't understand why the pattern is different on horizontal/vertical axis...
     
  9. _FLX

    _FLX

    Joined:
    Nov 10, 2015
    Posts:
    85
    I think i'm on the right way !
    You were right with the spread being world-spaced !

    I replaced
    Code (CSharp):
    1. rayCastDirection = rayCastDirection + new Vector3...
    by :
    Code (CSharp):
    1. rayCastDirection = rayCastDirection + bulletSpawner.TransformDirection(new Vector3...)
    Now the pattern is the same regardless of what side i'm shooting :D
    Thanks for your help
     
  10. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Nice.

    As I said, the spread is computed in world space not in local space. You have to rotate it with the player, try this:
    Code (CSharp):
    1.         var spreadVectorLocal = new Vector3(
    2.         ((shootNb % 2 != 0) ? spread : -spread) + (Mathf.Cos(shootNb) * 0.1f),
    3.         ((shootNb % 2 != 0) ? -spread : spread) + (Mathf.Cos(-shootNb) * 0.1f),
    4.         spread);
    5.  
    6.         var spreadVectorWorld = bulletSpawner.localToWorldMatrix.MultiplyPoint(spreadVectorLocal);
    7.  
    8.         rayCastDirection = rayCastDirection + spreadVectorWorld;
    If you want, more realism the spread should increase in size with the distance.

    Edit:
    Oh! You've already figured it out.:)