Local project added
This commit is contained in:
128
Assets/Scripts/VoxelOctree/VoxelTreeBuilder.cs
Normal file
128
Assets/Scripts/VoxelOctree/VoxelTreeBuilder.cs
Normal file
@ -0,0 +1,128 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class VoxelTreeBuilder
|
||||
{
|
||||
private int maxDepth;
|
||||
private float minNodeSize;
|
||||
|
||||
public VoxelTreeBuilder(int maxDepth, float minNodeSize)
|
||||
{
|
||||
this.maxDepth = maxDepth;
|
||||
this.minNodeSize = minNodeSize;
|
||||
}
|
||||
|
||||
public OctreeNode Build(Bounds bounds, Func<Vector3, float, IsSolidNodeAnswere> isSolid)
|
||||
{
|
||||
return BuildNode(bounds, isSolid, 0);
|
||||
}
|
||||
|
||||
private OctreeNode BuildNode(Bounds bounds, Func<Vector3, float, IsSolidNodeAnswere> isSolid, int depth)
|
||||
{
|
||||
OctreeNode node = new OctreeNode(bounds);
|
||||
IsSolidNodeAnswere answere;
|
||||
|
||||
// Stop subdivision if we reached the maximum depth or smallest size
|
||||
if (depth >= maxDepth)
|
||||
{
|
||||
// Check the voxel state at the center
|
||||
answere = isSolid(bounds.center, bounds.size.x);
|
||||
node.isOccupied = answere.isSolid;
|
||||
node.penetrationFactor = answere.penetrationFactor;
|
||||
node.reflexionFactor = answere.reflexionFactor;
|
||||
return node;
|
||||
}
|
||||
|
||||
if( bounds.size.x <= minNodeSize )
|
||||
{
|
||||
bool allSolid = true;
|
||||
bool allEmpty = true;
|
||||
|
||||
foreach (Vector3 corner in GetCorners(bounds))
|
||||
{
|
||||
answere = isSolid(corner, bounds.size.x);
|
||||
bool solid = answere.isSolid;
|
||||
|
||||
node.penetrationFactor = answere.penetrationFactor;
|
||||
node.reflexionFactor = answere.reflexionFactor;
|
||||
|
||||
allSolid &= solid;
|
||||
allEmpty &= !solid;
|
||||
}
|
||||
|
||||
// Check if the entire cube is homogeneous (either fully solid or empty)
|
||||
if (depth >= maxDepth || allSolid)
|
||||
{
|
||||
// If homogeneous, stop subdivision
|
||||
if (allSolid || allEmpty)
|
||||
{
|
||||
if (allSolid)
|
||||
{
|
||||
answere = isSolid(bounds.center, bounds.size.x);
|
||||
node.isOccupied = answere.isSolid;
|
||||
node.penetrationFactor = answere.penetrationFactor;
|
||||
node.reflexionFactor = answere.reflexionFactor;
|
||||
node.isOccupied = allSolid;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, subdivide into 8 child nodes
|
||||
node.isLeaf = false;
|
||||
int arrayIndex = 0;
|
||||
|
||||
foreach (var (i, subBounds) in GetSubBounds(bounds).Select((b, i) => (i, b)))
|
||||
{
|
||||
OctreeNode childrenNode = BuildNode(subBounds, isSolid, depth + 1);
|
||||
|
||||
if (childrenNode.isOccupied == true || childrenNode.hasChildrenOccupied == true)
|
||||
{
|
||||
node.hasChildrenOccupied = true;
|
||||
node.children[arrayIndex] = childrenNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
node.children[arrayIndex] = null;
|
||||
}
|
||||
arrayIndex++;
|
||||
}
|
||||
|
||||
if (arrayIndex == 0)
|
||||
node.isLeaf = true;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private IEnumerable<Bounds> GetSubBounds(Bounds parent)
|
||||
{
|
||||
// Generate 8 sub-bounds for the octree subdivision
|
||||
Vector3 size = parent.size / 2f;
|
||||
Vector3 min = parent.min;
|
||||
for (int x = 0; x < 2; x++)
|
||||
for (int y = 0; y < 2; y++)
|
||||
for (int z = 0; z < 2; z++)
|
||||
{
|
||||
Vector3 center = min + Vector3.Scale(new Vector3(x + 0.5f, y + 0.5f, z + 0.5f), size);
|
||||
yield return new Bounds(center, size);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Vector3> GetCorners(Bounds b)
|
||||
{
|
||||
// Return all 8 corners of the bounding box
|
||||
Vector3 min = b.min;
|
||||
Vector3 max = b.max;
|
||||
for (int x = 0; x <= 1; x++)
|
||||
for (int y = 0; y <= 1; y++)
|
||||
for (int z = 0; z <= 1; z++)
|
||||
yield return new Vector3(
|
||||
x == 0 ? min.x : max.x,
|
||||
y == 0 ? min.y : max.y,
|
||||
z == 0 ? min.z : max.z);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user