using System; using System.Collections; using System.Collections.Generic; using System.Security.Cryptography; using JetBrains.Annotations; using TMPro; using UnityEngine; using UnityEngine.Rendering; public class BlackHoleRenderer : MonoBehaviour { void Start() { } struct Ray { public SphericalDir Dir; public SphericalCoord P; //Canonical momenta public double b; public double q; public Double3 DirectionOfMotionInCameraCortesianSpace(Double3 N, double beta) { //F double betaSquare = beta * beta; double nfy = (-N.Y + beta) / (1.0 - (beta * N.Y)); double nfx = (-Math.Sqrt(1.0 - betaSquare) * N.X) / (1.0 - beta * N.Y); double nfz = (-Math.Sqrt(1.0 - betaSquare) * N.Z) / (1.0 - beta * N.Y); return new Double3 { X = nfx, Y = nfy, Z = nfz }; } public SphericalCoord FSpherical(SphericalCoord B, Double3 nF) { double kappa = Math.Sqrt(B.R * B.R + B.Dir.Phi * B.Dir.Phi); double nFr = ((B.Dir.Phi / kappa) * nF.X) + (B.R * nF.Y) + ((B.R * B.Dir.Theta) / kappa) * nF.Z; double nFTheta = B.Dir.Theta * nF.Y - kappa * nF.Z; double nFPhi = (-B.R / kappa) * nF.X + B.Dir.Phi * nF.Y + ((B.Dir.Phi * B.Dir.Theta) / kappa) * nF.Z; SphericalCoord result; result.R = nFr; result.Dir.Theta = nFTheta; result.Dir.Phi = nFPhi; return result; } public void CanonicalMomenta(FidoCamera camera, KerrMetric metric) { //p var N = Dir.ToCartesian(); var Fdir = DirectionOfMotionInCameraCortesianSpace(N, camera.Beta); var F = FSpherical(camera.Speed, Fdir); double Ef = 1.0 / (metric.Alpha + metric.Omega * metric.OmegaUpLine * F.Dir.Phi); double pr = Ef * (metric.Rho / Math.Sqrt(metric.Delta)) * F.R; double pTheta = Ef * metric.Rho * F.Dir.Theta; double pPhi = Ef * metric.OmegaUpLine * F.Dir.Phi; SphericalCoord result; result.R = pr; result.Dir.Phi = pPhi; result.Dir.Theta = pTheta; P = result; } public void Update(FidoCamera camera, KerrMetric metric) { CanonicalMomenta(camera, metric); b = P.Dir.Phi; double cosTheta = Math.Cos(Dir.Theta); double sinTheta = Math.Sin(Dir.Theta); q = P.Dir.Theta * P.Dir.Theta + cosTheta * cosTheta * (((b * b) / (sinTheta * sinTheta)) - metric.A * metric.A); } } double betaZero(double r_zero, BlackHole hole) { double r_zero_square = r_zero * r_zero; double r_zero_cube = r_zero_square * r_zero; double a_square = hole.A * hole.A; return -((r_zero_cube - 3 * r_zero_square + a_square * r_zero + a_square) / (hole.A * (r_zero - 1.0))); } double qZero(double r, BlackHole hole) { double rSquare = r * r; double rCube = rSquare * r; double aSquare = hole.A * hole.A; double rm1 = r - 1; double rmSquare = rm1 * rm1; return -(rCube * (rCube - 6 * rSquare + 9 * r - 4 * aSquare)) / (aSquare * rmSquare); } double rZero_0(double b, double a) { //my var aSquare = a * a; var subExpr0 = 3 * aSquare + 3 * a * b - 9; var subExpr2 = (54 - 54 * aSquare); var cubeRootOf2 = Math.Pow(2.0, 1.0 / 3.0); var subExpr1 = Math.Pow(Math.Sqrt(Math.Abs(4 * subExpr0 * subExpr0 * subExpr0 + subExpr2 * subExpr2)) + subExpr2, 1.0 / 3.0); return -(cubeRootOf2 * subExpr0) / (3.0 * subExpr1) + (subExpr1 / (3.0 * cubeRootOf2)) + 1; } double rZero_1(double b, double a) { //my var aSquare = a * a; var subExpr0 = 3 * aSquare + 3 * a * b - 9; var subExpr2 = (54 - 54 * aSquare); var cubeRootOf2 = Math.Pow(2.0, 1.0 / 3.0); var subExpr1 = Math.Pow(Math.Sqrt(Math.Abs(4 * subExpr0 * subExpr0 * subExpr0 + subExpr2 * subExpr2)) + subExpr2, 1.0 / 3.0); return ((1 + Math.Sqrt(3.0)) * subExpr0) / (3.0 * Math.Pow(2.0, 2.0/3.0) * subExpr1) - (( (1 - Math.Sqrt(3)) * subExpr1) / (6.0 * cubeRootOf2)) + 1; } double rZero_2(double b, double a) { //my var aSquare = a * a; var subExpr0 = 3 * aSquare + 3 * a * b - 9; var subExpr2 = (54 - 54 * aSquare); var cubeRootOf2 = Math.Pow(2.0, 1.0 / 3.0); var subExpr1 = Math.Pow(Math.Sqrt(Math.Abs(4 * subExpr0 * subExpr0 * subExpr0 + subExpr2 * subExpr2)) + subExpr2, 1.0 / 3.0); return ((1 - Math.Sqrt(3.0)) * subExpr0) / (3.0 * Math.Pow(2.0, 2.0 / 3.0) * subExpr1) - (((1 + Math.Sqrt(3)) * subExpr1) / (6.0 * cubeRootOf2)) + 1; } [Serializable] public class FidoCamera { public SphericalCoord Position; public SphericalCoord Speed; public double Beta; public void UpdateMetricAndSelf(KerrMetric metric, BlackHole hole) { metric.Update(hole.A, Position.R, Position.Dir.Theta); double bigOmega = 1.0 / (metric.A + Math.Pow(Position.R, 3.0 / 2.0)); Beta = (metric.OmegaUpLine / metric.Alpha) * (bigOmega - metric.Omega); } } [Serializable] public class BlackHole { public double A; public double r1() { return 2 * (1 + Math.Cos((2.0 / 3.0) * Math.Acos(-A))); } public double r2() { return 2 * (1 + Math.Cos((2.0 / 3.0) * Math.Acos(A))); } } [Serializable] public class KerrMetric { public double Delta; public double Rho; public double OmegaUpLine; public double Omega; public double Sigma; public double Alpha; public double A; public void Update(double a, double r, double theta) { double cosTheta = Math.Cos(theta); double sinTheta = Math.Sin(theta); double cosThetaSquare = cosTheta * cosTheta; double sinThetaSquare = sinTheta * sinTheta; double aSquare = a * a; double rSquare = r * r; Rho = Math.Sqrt(rSquare + (aSquare * cosThetaSquare)); Delta = rSquare - (2 * r) + aSquare; Sigma = Math.Sqrt((rSquare + aSquare) * (rSquare + aSquare) - aSquare * Delta * sinThetaSquare); Alpha = (Rho * Math.Sqrt(Delta)) / Sigma; Omega = (2 * a * r) / (Sigma * Sigma); OmegaUpLine = (Sigma * sinTheta) / Rho; A = a; } } public FidoCamera Camera = new FidoCamera(); public KerrMetric Metric = new KerrMetric(); public BlackHole Hole = new BlackHole(); public void RecalcState() { Camera.UpdateMetricAndSelf(Metric, Hole); } double drdt(double delta, double rho, double Pr) { return delta / (rho * rho) * Pr; } SphericalDir[] rays = new SphericalDir[256]; class BlackHoleRayIntegrator : Integrator { } void DrawCameraGizmo() { var pos = Camera.Position.ToCartesian().ToVector3(); UpdateRays(); foreach (var rayDir in rays) { Ray ray = new Ray(); ray.Dir = rayDir; ray.Update(Camera, Metric); var v0 = rZero_0(0.666, 0.9); var v1 = rZero_1(0.666, 0.9); var v2 = rZero_2(0.666, 0.9); // var b1 = betaZero(Hole.r2()); // var b2 = betaZero(Hole.r1()); //-0.1184053483681316836 + 0.×10^-19 i //0.7514421233051754296 + 0.×10^-19 i //2.3669632250629562540 + 0.×10^-20 i var N = ray.Dir.ToCartesian(); var Fdir = ray.DirectionOfMotionInCameraCortesianSpace(N, Camera.Beta); var F = ray.FSpherical(Camera.Speed, Fdir); Gizmos.DrawLine(pos, pos + ray.P.ToCartesian().ToVector3()); /* var r0 = rZero2(b); var r0_ = rZero(b); //r0 = 2.1899962982234369; var q0 = qZero2(r0, b); Color rayColor = Color.white; if (((b1 < b) && (b < b2)) && (q < q0)) { //there are no radial turning points for that {b, q} if (rayCanonicalMomenta_.R > 0) { //horizon rayColor = Color.black; horizon++; } else { celestial++; } } else { var a = a_spinAngularMomentumPerMass; double P = Math.Sqrt(Metric.Delta * ((b - a) * (b - a) + q)); double rUp0 = P + a * b - a * a; double rUp1 = -P + a * b - a * a; double rUp = rUp0 > rUp1 ? rUp0 : rUp1; if (cameraPosition.R > rUp) { celestial++; } else { horizon++; //horizon rayColor = Color.black; } }*/ } } public void OnDrawGizmos() { // double accretionDiskInnerRadius = 9.26 * M_blackHoleMass; // double accretionDiskOuterRadius = 18.7 * M_blackHoleMass; Gizmos.DrawLine(Vector3.zero, Camera.Position.ToCartesian().ToVector3()); Gizmos.DrawWireSphere(Vector3.zero, 1); DrawCameraGizmo(); // double OmegaBig = CameraGeodesicAngularVelocity(Rc); //DrawCameraGizmo(cameraCoord, cameraDirectionOfMotion); } void UpdateRays() { int imageHeight = 16; int imageWidth = 16; int totalRays = imageHeight * imageWidth; if (rays == null || rays.Length != totalRays) { rays = new SphericalDir[totalRays]; } double verticalFov = Math.PI / 2; double horizontalFov = ((double)imageWidth / imageHeight) * verticalFov; for (int y = 0; y < imageHeight; y++) { double rayTheta = (Math.PI / 2) - verticalFov / 2 + (verticalFov / (imageHeight - 1) * y); for (int x = 0; x < imageWidth; x++) { double rayPhi = Math.PI + horizontalFov / 2 - (horizontalFov / (imageWidth - 1) * x); rays[y * imageWidth + x].Phi = rayPhi; rays[y * imageWidth + x].Theta = rayTheta; } } } public void Trace() { RecalcState(); } }