Files
2025-05-13 03:12:25 +03:00

330 lines
10 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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();
}
}