233 lines
6.4 KiB
C#
Executable File
233 lines
6.4 KiB
C#
Executable File
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using System;
|
|
|
|
[Serializable]
|
|
public class LidarPoint
|
|
{
|
|
public float x;
|
|
public float y;
|
|
public float z;
|
|
public float d;
|
|
public float rx;
|
|
public float ry;
|
|
|
|
public LidarPoint(Vector3 p, float distance, float _rx, float _ry)
|
|
{
|
|
x = p.x;
|
|
y = p.y;
|
|
z = p.z;
|
|
d = distance;
|
|
rx = _rx;
|
|
ry = _ry;
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public class V3
|
|
{
|
|
public float x;
|
|
public float y;
|
|
public float z;
|
|
|
|
public V3(Vector3 p)
|
|
{
|
|
x = p.x;
|
|
y = p.y;
|
|
z = p.z;
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public class LidarPointArray
|
|
{
|
|
//All coordinates in World coordinate system
|
|
|
|
public LidarPoint[] points;
|
|
|
|
public void Init(int numPoints)
|
|
{
|
|
points = new LidarPoint[numPoints];
|
|
}
|
|
}
|
|
|
|
public class Lidar : MonoBehaviour
|
|
{
|
|
|
|
|
|
public LidarPointArray pointArr;
|
|
|
|
//as the ray sweeps around, how many degrees does it advance per sample
|
|
public float degPerSweepInc = 2f;
|
|
|
|
//what is the starting angle for the initial sweep compared to the forward vector
|
|
public float degAngDown = 25f;
|
|
|
|
//what angle change between sweeps
|
|
public float degAngDelta = -1f;
|
|
|
|
//how many complete 360 sweeps
|
|
public int numSweepsLevels = 25;
|
|
|
|
//what it max distance we will register a hit
|
|
public float maxRange = 50f;
|
|
|
|
//how large radius to use when rendering debug display
|
|
public float gizmoSize = 0.1f;
|
|
|
|
//what is the scalar on the perlin noise applied to point position
|
|
public float noise = 0.2f;
|
|
|
|
public bool DisplayDebugInScene = false;
|
|
|
|
// are there layers we don't want to collide with?
|
|
public string[] layerMaskNames;
|
|
|
|
int collMask = 0;
|
|
|
|
void Awake()
|
|
{
|
|
pointArr = new LidarPointArray();
|
|
pointArr.Init((int)(360 / degPerSweepInc * numSweepsLevels));
|
|
|
|
int v = 0;
|
|
|
|
foreach (string layerName in layerMaskNames)
|
|
{
|
|
int layer = LayerMask.NameToLayer(layerName);
|
|
v |= 1 << layer;
|
|
}
|
|
|
|
collMask |= ~v;
|
|
|
|
}
|
|
|
|
public void SetConfig(float offset_x, float offset_y, float offset_z, float rot_x,
|
|
float _degPerSweepInc, float _degAngDown, float _degAngDelta, float _maxRange, float _noise, int _numSweepsLevels)
|
|
{
|
|
degPerSweepInc = _degPerSweepInc;
|
|
degAngDown = _degAngDown;
|
|
degAngDelta = _degAngDelta;
|
|
maxRange = _maxRange;
|
|
noise = _noise;
|
|
numSweepsLevels = _numSweepsLevels;
|
|
|
|
if (offset_x != 0.0f || offset_y != 0.0f || offset_z != 0.0f)
|
|
transform.localPosition = new Vector3(offset_x, offset_y, offset_z);
|
|
|
|
if (rot_x != 0.0f)
|
|
transform.localEulerAngles = new Vector3(rot_x, 0.0f, 0.0f);
|
|
|
|
pointArr = new LidarPointArray();
|
|
pointArr.Init((int)(360 / degPerSweepInc * numSweepsLevels));
|
|
}
|
|
|
|
public JSONObject GetOutputAsJson()
|
|
{
|
|
LidarPointArray points = GetOutput();
|
|
JSONObject json = JSONObject.Create();
|
|
foreach (LidarPoint p in points.points)
|
|
{
|
|
JSONObject vec = JSONObject.Create();
|
|
try
|
|
{
|
|
vec.AddField("d", (float)Math.Round(p.d, 2));
|
|
vec.AddField("rx", p.rx);
|
|
vec.AddField("ry", p.ry);
|
|
json.Add(vec);
|
|
}
|
|
catch
|
|
{
|
|
// just ignore points that don't resolve.
|
|
}
|
|
}
|
|
|
|
return json;
|
|
}
|
|
|
|
public LidarPointArray GetOutput()
|
|
{
|
|
int numSweep = (int)(360 / degPerSweepInc);
|
|
pointArr = new LidarPointArray();
|
|
pointArr.Init(numSweep * numSweepsLevels);
|
|
|
|
Ray ray = new Ray(transform.position, transform.forward);
|
|
RaycastHit hit;
|
|
|
|
// Vertical rotation
|
|
Quaternion rotUp = Quaternion.AngleAxis(degAngDelta, transform.right);
|
|
|
|
// Horizontal rotation
|
|
Quaternion rotSide = Quaternion.AngleAxis(degPerSweepInc, transform.up);
|
|
|
|
//Sample the output texture to create rays.
|
|
int iP = 0;
|
|
float rx = 0.0f;
|
|
float ry = 0.0f;
|
|
|
|
for (int iS = 0; iS < numSweepsLevels; iS++)
|
|
{
|
|
// reset the orientation of the ray
|
|
Quaternion rotDown = Quaternion.AngleAxis(degAngDown + iS * degAngDelta, transform.right);
|
|
ray.direction = rotDown * transform.forward;
|
|
rx = 0.0f;
|
|
|
|
for (int iA = 0; iA < numSweep; iA++)
|
|
{
|
|
if (Physics.Raycast(ray, out hit, maxRange, collMask))
|
|
{
|
|
//sample that ray at the depth given by the pixel.
|
|
Vector3 pos = hit.point - transform.position;
|
|
float distance = hit.distance;
|
|
|
|
//shouldn't hit this unless user is messing around in the interface with things running.
|
|
if (iP >= pointArr.points.Length)
|
|
break;
|
|
|
|
// add some noise to the point position
|
|
float noiseX = Mathf.PerlinNoise(UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f));
|
|
float noiseY = Mathf.PerlinNoise(UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f));
|
|
float noiseZ = Mathf.PerlinNoise(UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f));
|
|
pos.x += noise * noiseX;
|
|
pos.y += noise * noiseY;
|
|
pos.z += noise * noiseZ;
|
|
|
|
//set iPoint
|
|
pointArr.points[iP] = new LidarPoint(pos, distance, rx, ry);
|
|
iP++;
|
|
}
|
|
|
|
ray.direction = rotSide * ray.direction;
|
|
rx += degPerSweepInc;
|
|
}
|
|
|
|
ray.direction = rotUp * ray.direction;
|
|
ry += degAngDelta;
|
|
}
|
|
|
|
return pointArr;
|
|
}
|
|
|
|
void OnDrawGizmosSelected()
|
|
{
|
|
Gizmos.color = Color.red;
|
|
pointArr = GetOutput(); // not really efficient but won't be called in the app, just for visualization purpose
|
|
|
|
Vector3 pos = Vector3.zero;
|
|
foreach (LidarPoint p in pointArr.points)
|
|
{
|
|
if (p == null)
|
|
continue;
|
|
|
|
pos.x = p.x;
|
|
pos.y = p.y;
|
|
pos.z = p.z;
|
|
|
|
//make points global space for drawing
|
|
pos += transform.position;
|
|
Gizmos.DrawSphere(pos, gizmoSize);
|
|
}
|
|
}
|
|
}
|