Local project added
This commit is contained in:
101
Assets/Scripts/VoxelOctree/CPU/VoxelTreeRaycaster.cs
Normal file
101
Assets/Scripts/VoxelOctree/CPU/VoxelTreeRaycaster.cs
Normal file
@ -0,0 +1,101 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class VoxelTreeRaycaster
|
||||
{
|
||||
public struct HitInfo
|
||||
{
|
||||
public Vector3 point;
|
||||
public Vector3 normal;
|
||||
public float distance;
|
||||
public OctreeNode node;
|
||||
}
|
||||
|
||||
// Public API: perform a raycast through the voxel tree
|
||||
public bool Raycast(OctreeNode root, Vector3 origin, Vector3 direction, float maxDistance, out HitInfo hit)
|
||||
{
|
||||
hit = new HitInfo();
|
||||
if (root == null || direction == Vector3.zero)
|
||||
return false;
|
||||
|
||||
direction.Normalize();
|
||||
Bounds treeBounds = root.bounds;
|
||||
|
||||
// First, check if ray starts inside or intersects the tree bounds
|
||||
if (!treeBounds.IntersectRay(new Ray(origin, direction), out float entryDist))
|
||||
{
|
||||
// If outside, skip rays that miss the whole tree
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clamp to max distance
|
||||
float dist = Mathf.Max(0f, entryDist);
|
||||
float endDist = Mathf.Min(maxDistance, entryDist + maxDistance);
|
||||
|
||||
return Traverse(root, origin, direction, ref dist, endDist, out hit);
|
||||
}
|
||||
|
||||
// Recursive traversal
|
||||
private bool Traverse(OctreeNode node, Vector3 origin, Vector3 dir, ref float dist, float maxDist, out HitInfo hit)
|
||||
{
|
||||
hit = new HitInfo();
|
||||
|
||||
// Stop if beyond range or node is outside of ray segment
|
||||
if (dist > maxDist) return false;
|
||||
if (!node.bounds.IntersectRay(new Ray(origin, dir), out float entry))
|
||||
return false;
|
||||
|
||||
// Adjust distance to this node's entry point
|
||||
dist = Mathf.Max(dist, entry);
|
||||
|
||||
// Leaf node
|
||||
if (node.isLeaf)
|
||||
{
|
||||
if (node.isOccupied)
|
||||
{
|
||||
// Approximate hit point (entry point)
|
||||
hit.point = origin + dir * dist;
|
||||
hit.distance = dist;
|
||||
hit.normal = GetApproximateNormal(node, origin, dir);
|
||||
hit.node = node;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, traverse children
|
||||
if (node.children != null)
|
||||
{
|
||||
// Check all child nodes that intersect the ray
|
||||
foreach (var child in node.children)
|
||||
{
|
||||
if (child == null) continue;
|
||||
if (Traverse(child, origin, dir, ref dist, maxDist, out hit))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Approximate normal from cube face hit
|
||||
private Vector3 GetApproximateNormal(OctreeNode node, Vector3 origin, Vector3 dir)
|
||||
{
|
||||
Vector3 p = origin;
|
||||
Bounds b = node.bounds;
|
||||
Vector3 center = b.center;
|
||||
Vector3 extents = b.extents;
|
||||
|
||||
Vector3 local = p - center;
|
||||
Vector3 absDir = new Vector3(Mathf.Abs(dir.x), Mathf.Abs(dir.y), Mathf.Abs(dir.z));
|
||||
Vector3 normal = Vector3.zero;
|
||||
|
||||
if (absDir.x > absDir.y && absDir.x > absDir.z)
|
||||
normal = new Vector3(Mathf.Sign(-dir.x), 0, 0);
|
||||
else if (absDir.y > absDir.z)
|
||||
normal = new Vector3(0, Mathf.Sign(-dir.y), 0);
|
||||
else
|
||||
normal = new Vector3(0, 0, Mathf.Sign(-dir.z));
|
||||
|
||||
return normal;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user