Search Unity

A problem with rays and math

Discussion in 'Scripting' started by kaarme, Jan 28, 2015.

  1. kaarme

    kaarme

    Joined:
    May 1, 2014
    Posts:
    177
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Linq;
    6.  
    7. public class Positioner {
    8.     public static Vector3 FixedPosition (GameObject GroundObject, Vector3 hit, Vector3 camera){
    9.         Vector3 oldPosition = GroundObject.transform.position;
    10.         GroundObject.transform.position = hit;
    11.         Vector3[] ObjectVertices = GroundObject.GetComponent<MeshFilter>().mesh.vertices;
    12.         List<Vector3> ProjectedVertices = new List<Vector3>();
    13.         List<float> VerticeDistance = new List<float>();
    14.         foreach(Vector3 vertice in ObjectVertices){        // Projects every vertex point to a line from camera
    15.             Vector3 ProjectedVertice = Math3d.ProjectPointOnLine(camera, hit - camera, GroundObject.transform.TransformPoint(vertice));
    16.             ProjectedVertices.Add (ProjectedVertice);
    17.             VerticeDistance.Add (Vector3.Distance(ProjectedVertice, camera));
    18.         }
    19.         Vector3 FarthestPoint = ProjectedVertices[VerticeDistance.IndexOf(VerticeDistance.Max())];
    20.         float IntersectionDepht = Vector3.Distance(hit, FarthestPoint);
    21.         GroundObject.transform.position = oldPosition;
    22.         return Vector3.MoveTowards(hit, camera, IntersectionDepht);
    23.     }
    24. }
    25.  
    It doesn't work and there is something that I don't understand. I wan't it to get the closest point to the camera where the object doesn't collide with any collider. Currently it puts the object too close to the camera.
     
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Are you implementing a system where the user can place objects on the ground where they click? If not then can you give some more detail about the effect you are looking for - the code is useful but it doesn't really indicate what gameplay effect you want to create.
     
  3. kaarme

    kaarme

    Joined:
    May 1, 2014
    Posts:
    177
    Yes I am, but it can also be a log or anything that isn't terrain.
     
  4. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    In that case, you probably want to check out this manual page about raycasting from the camera. The RaycastHit struct returned from the raycast includes data about which mesh triangle was hit by the ray. You can use the triangle information to identify the three corner vertices of the triangle and then check which of them is nearest to the hit point.
     
  5. kaarme

    kaarme

    Joined:
    May 1, 2014
    Posts:
    177
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Linq;
    6.  
    7. public class Positioner {
    8.     public static Vector3 FixedPosition (GameObject GroundObject, RaycastHit hit){
    9.         Vector3 oldPosition = GroundObject.transform.position;
    10.         GroundObject.transform.position = hit.point;
    11.         Vector3[] ObjectVertices = GroundObject.GetComponent<MeshFilter>().mesh.vertices;
    12.         List<Vector3> ProjectedVertices = new List<Vector3>();
    13.         List<float> VerticeDistance = new List<float>();
    14.         foreach(Vector3 vertice in ObjectVertices){        // Projects every vertex point to a line from linePoint
    15.             Vector3 linePoint = Vector3.MoveTowards(hit.point, hit.normal, Vector3.Distance(GroundObject.collider.bounds.max, hit.point));
    16.             Vector3 ProjectedVertice = Math3d.ProjectPointOnLine(linePoint, (hit.point - linePoint).normalized, GroundObject.transform.TransformPoint(vertice));
    17.             ProjectedVertices.Add (ProjectedVertice);
    18.             VerticeDistance.Add (Vector3.Distance(ProjectedVertice, linePoint));
    19.         }
    20.         Vector3 FarthestPoint = ProjectedVertices[VerticeDistance.IndexOf(VerticeDistance.Max())];
    21.         float IntersectionDepht = Vector3.Distance(hit.point, FarthestPoint);
    22.         GroundObject.transform.position = oldPosition;
    23.         Debug.DrawRay(FarthestPoint, Vector3.up, Color.green, 2, false);
    24.         Vector3 finalPosition = hit.point + (hit.normal.normalized * IntersectionDepht);
    25.         return finalPosition;
    26.     }
    27. }
    28.  
    Well it works better now but the object is floating a bit.. I tried to scale the object and it's now much more visible.
    Debug info line 24:
    297.7, 17.5, 308.0 = 297.7, 17.3, 308.0 + (0.0, 1.0, 0.0 * 0,2324142 )
     
    Last edited: Jan 31, 2015
  6. kaarme

    kaarme

    Joined:
    May 1, 2014
    Posts:
    177
    Help?
     
  7. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    You can use the triangleIndex property of RaycastHit to get the corner points of the triangle that was hit:

    Code (csharp):
    1.  
    2. var corner1 = mesh.vertices[mesh.triangles[hit.triangleIndex * 3]];
    3. var corner2 = mesh.vertices[mesh.triangles[hit.triangleIndex * 3 + 1]];
    4. var corner3 = mesh.vertices[mesh.triangles[hit.triangleIndex * 3 + 2]];
    5.  
    Then, you can measure the distance from the hit point to each of these corners with http://docs.unity3d.com/ScriptReference/Vector3.Distance.html:

    Code (csharp):
    1.  
    2. var distanceToCorner1 = Vector3.Distance(hit.point, corner1);
    3. var distanceToCorner2 ...
    4.  
    You can decide which corner is closest with a nested "if" statement:

    Code (csharp):
    1.  
    2. var closestCorner: Vector3;
    3.  
    4. if (distanceToCorner1 > distanceToCorner2) {
    5.   if (distanceToCorner2 > distanceToCorner3) {
    6.     closestCorner = corner3;
    7.   } else {
    8.     closestCorner = corner2;
    9.   }
    10. } else if (distanceToCorner1 > distanceToCorner3) {
    11.   closestCorner = corner3;
    12. } else {
    13.   closestCorner = corner1;
    14. }
    15.  
    You can then move the object to closestCorner or add an offset to move it slightly upwards off the ground surface, or whatever.

    If this isn't what you are trying to do then maybe you can explain the result you want in a bit more detail - it still isn't quite clear how you intend to position the object relative to the ground (eg, I can't tell if the loop from lines 14 to 19 is actually achieving anything or if there is just a mistake in it).
     
  8. kaarme

    kaarme

    Joined:
    May 1, 2014
    Posts:
    177
    No, I want to move the object the depth of intersection from the surface to avoid intersecting, the problem is the offset. It's always too big and skaling the object makes it even bigger and I don't understand why. The purpose of that loop is to calculate every distance from vertex to the point that should be in free space. After the loop it calculates the depth of intersection, and moves the object away from the surface. Class Math3d is in Unify wiki. I think I don't need to do anything with triangles, hit.point should be fine, or is there something that I don't know or understand?