Skip to content

Instantly share code, notes, and snippets.

@HurricanKai
Last active April 10, 2020 22:26
Show Gist options
  • Save HurricanKai/0d74787b47d8e221911c0b3442bda788 to your computer and use it in GitHub Desktop.
Save HurricanKai/0d74787b47d8e221911c0b3442bda788 to your computer and use it in GitHub Desktop.
public static class HERO
{
public static bool Intersects(Ray ray, Octree octree)
{
var (sumin, slmax) = CalculateBounds(ray, octree);
return slmax < sumin;
}
public static int? Raytrace(Ray ray, Octree octree)
{
var (sumin, slmax) = CalculateBounds(ray, octree);
if (!(slmax < sumin))
return null;
return Search(ray, octree, slmax, sumin);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static (float, float) CalculateBounds(Ray ray, Octree octree)
{
var min = (Vector3) octree.Offset;
var max = (Vector3) octree.Offset + octree.Extends;
var E = ray.Origin;
var v = ray.Direction;
var vsignz = !(v.Z < 0);
var vsigny = !(v.Y < 0);
var vsignx = !(v.X < 0);
var sxmin = (min.X - E.X) / v.X;
var symin = (min.Y - E.Y) / v.Y;
var szmin = (min.Z - E.Z) / v.Z;
var sxmax = (max.X - E.X) / v.X;
var symax = (max.Y - E.Y) / v.Y;
var szmax = (max.Z - E.Z) / v.Z;
var lowerx = vsignx ? sxmin : sxmax;
var lowery = vsigny ? symin : symax;
var lowerz = vsignz ? szmin : szmax;
var upperx = vsignx ? sxmax : sxmin;
var uppery = vsigny ? symax : symin;
var upperz = vsignz ? szmax : szmin;
var slmax = MathF.Max(lowerx, MathF.Max(lowery, lowerz));
var sumin = MathF.Min(upperx, MathF.Min(uppery, upperz));
return (sumin, slmax);
}
private static int? Search(Ray ray, Octree octree, float slmax, float sumin)
{
if (octree.Value != null)
return octree.Value;
var E = ray.Origin;
var v = ray.Direction;
var vsignz = v.Z < 0;
var vsigny = v.Y < 0;
var vsignx = v.X < 0;
var VMASK = (byte)(
((byte) (vsignz ? 1 : 0) << 2) |
((byte) (vsigny ? 1 : 0) << 1) |
((byte) (vsignx ? 1 : 0) << 0));
var mid = octree.Offset + ((Vector3) octree.Extends / 2);
var sxmid = (mid.X - E.X) / v.X;
var symid = (mid.Y - E.Y) / v.Y;
var szmid = (mid.Z - E.Z) / v.Z;
var CHILDMASK = (byte) (
((byte) (szmid < slmax ? 1 : 0) << 2) |
((byte) (symid < slmax ? 1 : 0) << 1) |
((byte) (sxmid < slmax ? 1 : 0) << 0));
var LASTMASK = (byte) (
((byte) (szmid < sumin ? 1 : 0) << 2) |
((byte) (symid < sumin ? 1 : 0) << 1) |
((byte) (sxmid < sumin ? 1 : 0) << 0));
var a = (byte) (sxmid < symid ? 1 : 0);
var b = (byte) (sxmid < szmid ? 1 : 0);
var c = (byte) (symid < szmid ? 1 : 0);
var na = (byte)(~a & 0b1);
var nb = (byte)(~b & 0b1);
var nc = (byte)(~c & 0b1);
Span<byte> MASKLIST = stackalloc byte[3];
MASKLIST[0] = (byte) (
(((b | nc) & 0b1) << 2) |
(((na & c) & 0b1) << 1) |
(((a & b) & 0b1) << 0)
);
MASKLIST[1] = (byte) (
(((b ^ c) & 0b1) << 2) |
(((byte) ~(a ^ c) & 0b1) << 1) |
(((a ^ b) & 0b1) << 0)
);
MASKLIST[2] = (byte) (
(((b & c) & 0b1) << 2) |
(((a & nc) & 0b1) << 1) |
(((a | nb) & 0b1) << 0)
);
var i = 0;
var children = octree.Children.Span;
while (true)
{
var child = children[CHILDMASK ^ VMASK];
var (csumin, cslmax) = CalculateBounds(ray, child);
var res = Search(ray, child, cslmax, csumin);
if (res != null && res.Value != 0)
return res.Value;
if (CHILDMASK == LASTMASK)
break;
while ((MASKLIST[i] & CHILDMASK) != 0)
i++;
CHILDMASK |= MASKLIST[i];
}
return 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment