163 lines
5.3 KiB
C#
163 lines
5.3 KiB
C#
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
public class PlanoConvexLens : OpticalSurface2D
|
||
|
|
{
|
||
|
|
public float LensRadius = 1.0f;
|
||
|
|
public float CurveRadius = 1.0f;
|
||
|
|
public int SamplesCount = 10;
|
||
|
|
public float Height = 0.1f;
|
||
|
|
|
||
|
|
// Start is called before the first frame update
|
||
|
|
void Start()
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update is called once per frame
|
||
|
|
void Update()
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
private RaycastMath.RaycastResult2D[] _raycasts;
|
||
|
|
|
||
|
|
public override bool Raycast(Ray2D ray, ref RaycastMath.RaycastResult2D result) {
|
||
|
|
if(_raycasts == null) {
|
||
|
|
_raycasts = new RaycastMath.RaycastResult2D[4];
|
||
|
|
}
|
||
|
|
|
||
|
|
var localSpaceRay = ray;
|
||
|
|
localSpaceRay.origin = transform.InverseTransformPoint(localSpaceRay.origin);
|
||
|
|
localSpaceRay.direction = transform.InverseTransformVector(localSpaceRay.direction).normalized;
|
||
|
|
|
||
|
|
//cs = as + bs
|
||
|
|
//bs = cs - as
|
||
|
|
|
||
|
|
|
||
|
|
float h = Mathf.Sqrt(CurveRadius * CurveRadius - LensRadius * LensRadius);
|
||
|
|
|
||
|
|
|
||
|
|
var sphereCastRay = localSpaceRay;
|
||
|
|
sphereCastRay.origin += Vector2.up * (Mathf.Sign(CurveRadius) * h - Height);
|
||
|
|
|
||
|
|
int raycastsCount = 0;
|
||
|
|
|
||
|
|
bool curveIntersected = RaycastMath.RaycastCircle(sphereCastRay, Mathf.Abs( CurveRadius), ref _raycasts[raycastsCount]);
|
||
|
|
if (curveIntersected) {
|
||
|
|
_raycasts[raycastsCount].Point += Vector2.down * Mathf.Sign(CurveRadius) * (h);
|
||
|
|
|
||
|
|
if(CurveRadius >= 0) {
|
||
|
|
if (_raycasts[raycastsCount].Point.y < 0) {
|
||
|
|
curveIntersected = false;
|
||
|
|
} else {
|
||
|
|
_raycasts[raycastsCount].Point += Vector2.up * Height;
|
||
|
|
raycastsCount++;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (_raycasts[raycastsCount].Point.y > 0) {
|
||
|
|
curveIntersected = false;
|
||
|
|
} else {
|
||
|
|
_raycasts[raycastsCount].Point += Vector2.up * Height;
|
||
|
|
_raycasts[raycastsCount].Normal = -_raycasts[raycastsCount].Normal;
|
||
|
|
raycastsCount++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
Vector2 leftHitPoint = Vector2.zero;
|
||
|
|
if(Height > 0.0f && RaycastMath.RayLineSegmentIntersection(localSpaceRay.origin, localSpaceRay.direction, new Vector2(-LensRadius, 0), new Vector2(-LensRadius, Height), ref leftHitPoint)) {
|
||
|
|
_raycasts[raycastsCount].Normal = Vector2.left;
|
||
|
|
_raycasts[raycastsCount].Point = leftHitPoint;
|
||
|
|
raycastsCount++;
|
||
|
|
}
|
||
|
|
|
||
|
|
Vector2 rightHitPoint = Vector2.zero;
|
||
|
|
if(Height > 0.0f && RaycastMath.RayLineSegmentIntersection(localSpaceRay.origin, localSpaceRay.direction, new Vector2(LensRadius, 0), new Vector2(LensRadius, Height), ref rightHitPoint)) {
|
||
|
|
_raycasts[raycastsCount].Normal = Vector2.right;
|
||
|
|
_raycasts[raycastsCount].Point = rightHitPoint;
|
||
|
|
raycastsCount++;
|
||
|
|
}
|
||
|
|
|
||
|
|
Vector2 bottomHitPoint = Vector2.zero;
|
||
|
|
if(LensRadius > 0.0f && RaycastMath.RayLineSegmentIntersection(localSpaceRay.origin, localSpaceRay.direction, new Vector2(-LensRadius, 0), new Vector2(LensRadius, 0), ref bottomHitPoint)) {
|
||
|
|
_raycasts[raycastsCount].Normal = Vector2.down;
|
||
|
|
_raycasts[raycastsCount].Point = bottomHitPoint;
|
||
|
|
raycastsCount++;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
if(raycastsCount == 0) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
result = _raycasts.Take(raycastsCount).OrderBy(x => Vector2.Distance(x.Point, localSpaceRay.origin)).First();
|
||
|
|
|
||
|
|
result.Point = transform.TransformPoint(result.Point);
|
||
|
|
result.Normal = transform.InverseTransformVector(result.Normal).normalized;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnValidate() {
|
||
|
|
|
||
|
|
if(CurveRadius > 0 && CurveRadius < LensRadius) {
|
||
|
|
CurveRadius = LensRadius;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (CurveRadius < 0 && CurveRadius > -LensRadius) {
|
||
|
|
CurveRadius = -LensRadius;
|
||
|
|
}
|
||
|
|
|
||
|
|
var points = RadialCurve(LensRadius, CurveRadius, SamplesCount);
|
||
|
|
if(points.Length < 2) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
Shape = new Line[points.Length - 1 + 3];
|
||
|
|
|
||
|
|
for(int i = 0; i < points.Length - 1; i++) {
|
||
|
|
Shape[i] = new Line() { P1 = points[i] + Vector2.up * Height, P2 = points[i + 1] + Vector2.up * Height };
|
||
|
|
}
|
||
|
|
|
||
|
|
Vector2 p1 = new Vector2(-LensRadius, Height);
|
||
|
|
Vector2 p2 = new Vector2(-LensRadius, 0);
|
||
|
|
Vector2 p3 = new Vector2(LensRadius, 0);
|
||
|
|
Vector2 p4 = new Vector2(LensRadius, Height);
|
||
|
|
|
||
|
|
Shape[Shape.Length - 3] = new Line() { P1 = p1, P2 = p2 };
|
||
|
|
Shape[Shape.Length - 2] = new Line() { P1 = p2, P2 = p3 };
|
||
|
|
Shape[Shape.Length - 1] = new Line() { P1 = p3, P2 = p4 };
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public static Vector2[] RadialCurve(float lenseRadius, float curveRadius, int samplesCount) {
|
||
|
|
|
||
|
|
|
||
|
|
//r*r = x*x + h*h
|
||
|
|
//h*h = r*r - x*x
|
||
|
|
|
||
|
|
Vector2[] result = new Vector2[samplesCount];
|
||
|
|
|
||
|
|
float h = Mathf.Sqrt(curveRadius * curveRadius - lenseRadius * lenseRadius);
|
||
|
|
|
||
|
|
float dx = (-2.0f * lenseRadius) / (samplesCount - 1);
|
||
|
|
|
||
|
|
for (int i = 0; i < samplesCount; i++) {
|
||
|
|
float x2 = lenseRadius + dx * i;
|
||
|
|
float h2 = Mathf.Sqrt(curveRadius * curveRadius - x2 * x2);
|
||
|
|
|
||
|
|
|
||
|
|
result[i] = new Vector2(x2, Mathf.Sign(curveRadius) * (h2 - h));
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
}
|