-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathVec3.cs
64 lines (50 loc) · 2.68 KB
/
Vec3.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using System;
using System.Runtime.CompilerServices;
namespace RayTracingInOneWeekend;
// In C#, we cannot create a generic Vec3<T> where T could be int, long,
// float, or double. Using where to constrain T by design has no "where
// numeric type". It's only possible to create a Vec3<T> and dispatch on
// type at runtime. For some types this is okay, but not for a Vec3 on the
// hot path.
//
// To avoid heap allocation, Vec3 is implemented as a struct instead of a
// class. That way allocations happen on the stack instead. Turns out in
// .NET, there's negligible difference between float and double, so we went
// with double.
internal readonly struct Vec3(double e0, double e1, double e2)
{
public double X { get; } = e0;
public double Y { get; } = e1;
public double Z { get; } = e2;
public double R => X;
public double G => Y;
public double B => Z;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Length() => Math.Sqrt(X * X + Y * Y + Z * Z);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double SquaredLength() => X * X + Y * Y + Z * Z;
// In C#, overloading a binary operator automatically overloads its
// compound equivalent, i.e., we get both Vec3 + Vec3 and Vec3 +=
// Vec3 with a single overload.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator+(Vec3 v1, Vec3 v2) => new(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator-(Vec3 v1, Vec3 v2) => new (v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator*(Vec3 v1, Vec3 v2) => new (v1.X * v2.X, v1.Y * v2.Y, v1.Z * v2.Z);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator*(Vec3 v, double t) => new (v.X * t, v.Y * t, v.Z * t);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator*(double t, Vec3 v) => new (v.X * t, v.Y * t, v.Z * t);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator/(Vec3 v, double t) => new (v.X / t, v.Y / t, v.Z / t);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 UnitVector(Vec3 v) => v / v.Length();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Vec3 v1, Vec3 v2) => v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 Cross(Vec3 v1, Vec3 v2) =>
new (v1.Y * v2.Z - v1.Z * v2.Y,
v1.Z * v2.X - v1.X * v2.Z,
v1.X * v2.Y - v1.Y * v2.X);
}