Skip to content

Commit

Permalink
Merge pull request #47 from tomasz-herman/p.flis/bvh_optimization
Browse files Browse the repository at this point in the history
P.flis/bvh optimization
  • Loading branch information
p-flis committed Jan 5, 2021
2 parents cab174f + c12bcf3 commit 05c3229
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 9 deletions.
97 changes: 97 additions & 0 deletions RayTracer/Source/BVH/BvhNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using RayTracing.Maths;
using RayTracing.RayTracing;
using RayTracing.Sampling;

namespace RayTracing.BVH
{
public class BvhNode : IHittable
{
private const int SAMPLES = 10000;
private readonly IHittable _left;
private readonly IHittable _right;
private readonly AABB _box;

// https://raytracing.github.io/books/RayTracingTheNextWeek.html#boundingvolumehierarchies
public BvhNode(List<IHittable> srcObjects, int start, int end, AbstractSampler<int> sampler = null)
{
sampler ??= new ThreadSafeSampler<int>(count => IntSampling.Random(count, 0, 3), SAMPLES);

var objects = srcObjects;
int axis = sampler.GetSample();
int Comparator(IHittable a, IHittable b) => BoxCompare(a, b, axis);

int objectSpan = end - start;
switch (objectSpan)
{
case 1:
_left = _right = objects[start];
break;
case 2 when Comparator(objects[start], objects[start + 1]) < 0:
_left = objects[start];
_right = objects[start + 1];
break;
case 2:
_left = objects[start + 1];
_right = objects[start];
break;
default:
objects.Sort(start, objectSpan - 1, new FuncComparer<IHittable>(Comparator));
int mid = start + objectSpan / 2;
_left = new BvhNode(objects, start, mid, sampler);
_right = new BvhNode(objects, mid, end, sampler);
break;
}

var boxLeft = _left.BoundingBox();
var boxRight = _right.BoundingBox();

_box = boxLeft + boxRight;
}

public bool HitTest(Ray ray, ref HitInfo hit, float @from, float to)
{
if (!_box.Test(ref ray, from, to))
return false;

bool hitLeft = _left.HitTest(ray, ref hit, from, to);
bool hitRight = _right.HitTest(ray, ref hit, from, hitLeft ? hit.Distance : to);

return hitLeft || hitRight;
}

public AABB BoundingBox()
{
return _box;
}

public List<IHittable> Preprocess()
{
throw new System.NotImplementedException();
}

private int BoxCompare(IHittable a, IHittable b, int axis)
{
var boxA = a.BoundingBox();
var boxB = b.BoundingBox();

return boxA.Min[axis].CompareTo(boxB.Min[axis]);
}

private class FuncComparer<T> : IComparer<T>
{
private readonly Func<T, T, int> _func;

public FuncComparer(Func<T, T, int> comparerFunc)
{
_func = comparerFunc;
}

public int Compare(T x, T y)
{
return _func(x, y);
}
}
}
}
1 change: 0 additions & 1 deletion RayTracer/Source/Maths/AABB.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,5 @@ public bool Test(ref Ray ray, float from = 0, float to = float.PositiveInfinity)
return new AABB(Vector3.ComponentMin(first.Min, second.Min),
Vector3.ComponentMax(first.Max, second.Max));
}

}
}
2 changes: 1 addition & 1 deletion RayTracer/Source/Models/CustomModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public override Mesh GetMesh()
{
return Mesh;
}

public override List<IHittable> Preprocess()
{
return MeshToTriangles();
Expand Down
13 changes: 13 additions & 0 deletions RayTracer/Source/Models/Cylinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,19 @@ private void CapHitTest(ref Ray ray, ref HitInfo hit, float from, float to, ref
}
}

// https://www.iquilezles.org/www/articles/diskbbox/diskbbox.htm
public override AABB BoundingBox()
{
var normal = _normal.Normalized();
float x = (float) Math.Sqrt(1 - normal.X * normal.X);
float y = (float) Math.Sqrt(1 - normal.Y * normal.Y);
float z = (float) Math.Sqrt(1 - normal.Z * normal.Z);
Vector3 e = new Vector3(x, y, z) * Scale;
return new AABB(
Vector3.ComponentMin(_top - e, _bottom - e),
Vector3.ComponentMax(_top + e, _bottom + e));
}

private void GetCylinderUV(Vector3 hitPoint, ref Vector2 uv)
{
var hitVector = RotationMatrix * (hitPoint - Position) / _height;
Expand Down
11 changes: 8 additions & 3 deletions RayTracer/Source/Models/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ public Model Unload()
}

public abstract bool HitTest(Ray ray, ref HitInfo hit, float from, float to);


public virtual AABB BoundingBox()
{
throw new System.NotImplementedException();
}

public virtual List<IHittable> Preprocess()
{
return new List<IHittable> {this};
Expand All @@ -65,8 +70,8 @@ public List<IHittable> MeshToTriangles()
if (Mesh == null) return hittables;

Matrix4 modelMatrix = GetModelMatrix();
for (var index = 0; index < Mesh.Indices.Count; index+=3)

for (var index = 0; index < Mesh.Indices.Count; index += 3)
{
Vector3 v1 = Mesh.GetPostion(index);
Vector3 v2 = Mesh.GetPostion(index + 1);
Expand Down
2 changes: 1 addition & 1 deletion RayTracer/Source/Models/Rectangle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public override Mesh GetMesh()
{
return Mesh;
}

public override List<IHittable> Preprocess()
{
return MeshToTriangles();
Expand Down
4 changes: 4 additions & 0 deletions RayTracer/Source/Models/Sphere.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ public override Mesh GetMesh()
return Mesh;
}

public override AABB BoundingBox()
{
return new AABB(Position - new Vector3(Scale), Position + new Vector3(Scale));
}

private (List<float>, List<float>) GetVertexList(short rings, short sectors)
{
Expand Down
25 changes: 25 additions & 0 deletions RayTracer/Source/Models/Triangle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,31 @@ private protected override void LoadInternal()
throw new Exception("Triangle is used only in ray tracing");
}

public override AABB BoundingBox()
{
var outputBox = new AABB(
Vector3.ComponentMin(Vector3.ComponentMin(_vertices[0], _vertices[1]), _vertices[2]),
Vector3.ComponentMax(Vector3.ComponentMax(_vertices[0], _vertices[1]), _vertices[2])
);
const float thickness = (float) 1e-5;
const float threshold = (float) 1e-7;
for (int i = 0; i < 3; i++)
{
if (Math.Abs(outputBox.Max[i] - outputBox.Min[i]) < threshold)
{
var vec = outputBox.Min;
vec[i] -= thickness;
outputBox.Min = vec;

vec = outputBox.Max;
vec[i] += thickness;
outputBox.Max = vec;
}
}

return outputBox;
}

//source: https://www.scratchapixel.com/code.php?id=9&origin=/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle
public override bool HitTest(Ray ray, ref HitInfo hit, float @from, float to)
{
Expand Down
2 changes: 1 addition & 1 deletion RayTracer/Source/RayTracing/IHittable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace RayTracing.RayTracing
public interface IHittable
{
bool HitTest(Ray ray, ref HitInfo hit, float from, float to);

List<IHittable> Preprocess();
AABB BoundingBox();
}
}
17 changes: 17 additions & 0 deletions RayTracer/Source/Sampling/IntSampling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,22 @@ public static List<int> Distribution(int count, params float[] probabilities)

return samples;
}

public static List<int> Random(int count, int minInclusive, int maxExclusive)
{
if(count < 0)
throw new ArgumentException("Count less than zero");
if (minInclusive >= maxExclusive)
throw new ArgumentException("Wrong limits");

List<int> samples = new List<int>();

for (int i = 0; i < count; i++)
{
samples.Add(_random.Next(minInclusive, maxExclusive));
}

return samples;
}
}
}
46 changes: 44 additions & 2 deletions RayTracer/Source/World/Scene.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
using System.Collections.Generic;
using RayTracing.BVH;
using RayTracing.Lights;
using RayTracing.Materials;
using RayTracing.Maths;
using RayTracing.Models;
using RayTracing.RayTracing;
using RayTracing.Sampling;

namespace RayTracing.World
{
public class Scene : IHittable
{
public bool BvhMode { get; set; } = true;
public List<Model> Models { get; } = new List<Model>();
public List<IHittable> Hittables { get; } = new List<IHittable>();
public List<Model> Lights { get; } = new List<Model>();
Expand Down Expand Up @@ -43,8 +46,12 @@ public bool HitTest(Ray ray, ref HitInfo hit, float from, float to)
return hitAnything;
}

//TODO: Might do octree/bvh/w\e division here
public List<IHittable> Preprocess()
public AABB BoundingBox()
{
throw new System.NotImplementedException();
}

private List<IHittable> StandardPreprocess()
{
Hittables.Clear();
foreach (var model in Models)
Expand All @@ -54,5 +61,40 @@ public List<IHittable> Preprocess()

return Hittables;
}

private List<IHittable> BvhPreprocess()
{
Hittables.Clear();
var planes = new List<IHittable>();
var hittablesToBvh = new List<IHittable>();
foreach (var model in Models)
{
if (model is Plane)
{
planes.Add(model);
}
else
{
hittablesToBvh.AddRange(((IHittable) model).Preprocess());
}
}

var node = new BvhNode(hittablesToBvh, 0, hittablesToBvh.Count);
Hittables.AddRange(planes);
Hittables.Add(node);
return Hittables;
}

public List<IHittable> Preprocess()
{
if (BvhMode)
{
return BvhPreprocess();
}
else
{
return StandardPreprocess();
}
}
}
}

0 comments on commit 05c3229

Please sign in to comment.