Permalink
Browse files

C#: update with C++ side optimizations (SoA, algebraic simplification…

…s, list of emissive objects, aggressive inlining)

- PC 67.1 -> 104.6 Mray/s
- Mac 17.5 -> 23.6 Mray/s
  • Loading branch information...
aras-p committed Apr 16, 2018
1 parent f0452ca commit 5895cb3d3c8919c715139539f24262c549607569
Showing with 82 additions and 49 deletions.
  1. +70 −29 Cs/Maths.cs
  2. +12 −20 Cs/Test.cs
@@ -132,44 +132,85 @@ public struct Sphere
{
public float3 center;
public float radius;
public float invRadius;
public Sphere(float3 center_, float radius_) { center = center_; radius = radius_; }
}
public Sphere(float3 center_, float radius_) { center = center_; radius = radius_; invRadius = 1.0f / radius_; }
public void UpdateDerivedData() { invRadius = 1.0f / radius; }
struct SpheresSoA
{
public float[] centerX;
public float[] centerY;
public float[] centerZ;
public float[] sqRadius;
public float[] invRadius;
public int[] emissives;
public int emissiveCount;
public SpheresSoA(int len)
{
centerX = new float[len];
centerY = new float[len];
centerZ = new float[len];
sqRadius = new float[len];
invRadius = new float[len];
emissives = new int[len];
emissiveCount = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HitSphere(ref Ray r, float tMin, float tMax, ref Hit outHit)
public void Update(Sphere[] src, Material[] mat)
{
Debug.Assert(invRadius == 1.0f / radius);
Debug.Assert(r.dir.IsNormalized);
float3 oc = r.orig - center;
float b = float3.Dot(oc, r.dir);
float c = float3.Dot(oc, oc) - radius * radius;
float discr = b * b - c;
if (discr > 0)
emissiveCount = 0;
for (var i = 0; i < src.Length; ++i)
{
float discrSq = MathF.Sqrt(discr);
float t = (-b - discrSq);
if (t < tMax && t > tMin)
ref Sphere s = ref src[i];
centerX[i] = s.center.x;
centerY[i] = s.center.y;
centerZ[i] = s.center.z;
sqRadius[i] = s.radius * s.radius;
invRadius[i] = 1.0f / s.radius;
if (mat[i].HasEmission)
{
outHit.pos = r.PointAt(t);
outHit.normal = (outHit.pos - center) * invRadius;
Debug.Assert(outHit.normal.IsNormalized);
outHit.t = t;
return true;
emissives[emissiveCount++] = i;
}
t = (-b + discrSq);
if (t < tMax && t > tMin)
}
}
public int HitSpheres(ref Ray r, float tMin, float tMax, ref Hit outHit)
{
float hitT = tMax;
int id = -1;
for (int i = 0; i < centerX.Length; ++i)
{
float coX = centerX[i] - r.orig.x;
float coY = centerY[i] - r.orig.y;
float coZ = centerZ[i] - r.orig.z;
float nb = coX * r.dir.x + coY * r.dir.y + coZ * r.dir.z;
float c = coX * coX + coY * coY + coZ * coZ - sqRadius[i];
float discr = nb * nb - c;
if (discr > 0)
{
outHit.pos = r.PointAt(t);
outHit.normal = (outHit.pos - center) * invRadius;
Debug.Assert(outHit.normal.IsNormalized);
outHit.t = t;
return true;
float discrSq = MathF.Sqrt(discr);
// Try earlier t
float t = nb - discrSq;
if (t <= tMin) // before min, try later t!
t = nb + discrSq;
if (t > tMin && t < hitT)
{
id = i;
hitT = t;
}
}
}
return false;
if (id != -1)
{
outHit.pos = r.PointAt(hitT);
outHit.normal = (outHit.pos - new float3(centerX[id], centerY[id], centerZ[id])) * invRadius[id];
outHit.t = hitT;
return id;
}
else
return -1;
}
}
@@ -56,27 +56,22 @@ class Test
new Material(Material.Type.Lambert, new float3(0.8f, 0.6f, 0.2f), new float3(30,25,15), 0, 0),
};
SpheresSoA s_SpheresSoA;
public Test()
{
s_SpheresSoA = new SpheresSoA(s_Spheres.Length);
}
const float kMinT = 0.001f;
const float kMaxT = 1.0e7f;
const int kMaxDepth = 10;
bool HitWorld(ref Ray r, float tMin, float tMax, ref Hit outHit, ref int outID)
{
Hit tmpHit = default(Hit);
bool anything = false;
float closest = tMax;
for (int i = 0; i < s_Spheres.Length; ++i)
{
if (s_Spheres[i].HitSphere(ref r, tMin, closest, ref tmpHit))
{
anything = true;
closest = tmpHit.t;
outHit = tmpHit;
outID = i;
}
}
return anything;
outID = s_SpheresSoA.HitSpheres(ref r, tMin, tMax, ref outHit);
return outID != -1;
}
bool Scatter(ref Material mat, ref Ray r_in, Hit rec, out float3 attenuation, out Ray scattered, out float3 outLightE, ref int inoutRayCount, ref uint state)
@@ -91,11 +86,10 @@ bool Scatter(ref Material mat, ref Ray r_in, Hit rec, out float3 attenuation, ou
// sample lights
#if DO_LIGHT_SAMPLING
for (int i = 0; i < s_Spheres.Length; ++i)
for (int j = 0; j < s_SpheresSoA.emissiveCount; ++j)
{
int i = s_SpheresSoA.emissives[j];
ref Material sphereMat = ref s_SphereMats[i];
if (!sphereMat.HasEmission)
continue; // skip non-emissive
//@TODO if (&mat == &smat)
// continue; // skip self
var s = s_Spheres[i];
@@ -112,7 +106,6 @@ bool Scatter(ref Material mat, ref Ray r_in, Hit rec, out float3 attenuation, ou
float sinA = MathF.Sqrt(1.0f - cosA * cosA);
float phi = 2 * PI * eps2;
float3 l = su * MathF.Cos(phi) * sinA + sv * MathF.Sin(phi) * sinA + sw * cosA;
l.Normalize();
// shoot shadow ray
Hit lightHit = default(Hit);
@@ -274,8 +267,7 @@ public void DrawTest(float time, int frameCount, int screenWidth, int screenHeig
float distToFocus = 3;
float aperture = 0.1f;
for (int i = 0; i < s_Spheres.Length; ++i)
s_Spheres[i].UpdateDerivedData();
s_SpheresSoA.Update(s_Spheres, s_SphereMats);
Camera cam = new Camera(lookfrom, lookat, new float3(0, 1, 0), 60, (float)screenWidth / (float)screenHeight, aperture, distToFocus);

0 comments on commit 5895cb3

Please sign in to comment.