/// <summary> /// /// </summary> /// <param name="equation"></param> /// <param name="sizex"></param> /// <param name="sizey"></param> /// <param name="discTexture"></param> /// <param name="backgroundTexture"></param> /// <param name="cameraTilt"></param> /// <param name="trace">If true, the steps of RungeKutta integration will be stored in a list, so that they can be studied after.</param> public RayTracer(KerrBlackHoleEquation equation, int sizex, int sizey, Bitmap discTexture, Bitmap backgroundTexture, double cameraTilt, double cameraYaw, bool trace = false) { this.equation = equation; this.sizex = sizex; this.sizey = sizey; this.discTexture = discTexture; this.backgroundTexture = backgroundTexture; this.cameraTilt = cameraTilt; this.trace = trace; this.cameraYaw = cameraYaw; lock (backgroundTexture) { this.backgroundMap = new SphericalMapping(backgroundTexture.Width, backgroundTexture.Height); } lock (discTexture) { this.discMap = new DiscMapping(equation.Rmstable, equation.Rdisk, discTexture.Width, discTexture.Height); } if (trace) { this.RayPoints = new List <Tuple <double, double, double> >(); } }
public unsafe bool Hit(double *y, double *prevY, double *dydx, double hdid, KerrBlackHoleEquation equation, ref Color color, ref bool stop, bool debug) { double tempX = 0, tempY = 0, tempZ = 0; Util.ToCartesian(y[0], y[1], y[2], ref tempX, ref tempY, ref tempZ); double distance = Math.Sqrt((tempX - centerX) * (tempX - centerX) + (tempY - centerY) * (tempY - centerY) + (tempZ - centerZ) * (tempZ - centerZ)); if (distance < radius) { // Restore Y to its previous values, and perform the binary intersection search. Util.memcpy((IntPtr)y, (IntPtr)prevY, equation.N * sizeof(double)); IntersectionSearch(y, dydx, hdid, equation); // transform impact coordinates to cartesian coordinates relative to center of sphere. Util.ToCartesian(y[0], y[1], y[2], ref tempX, ref tempY, ref tempZ); var impact = new Vector3((float)tempX, (float)tempY, (float)tempZ); var impactFromCenter = Vector3.Normalize(impact - center); // and now transform to spherical coordinates relative to center of sphere. double tempR = 0, tempTheta = 0, tempPhi = 0; // hack: rejigger axes to make textures appear right side up. Util.ToSpherical(-impactFromCenter.X, impactFromCenter.Z, impactFromCenter.Y, ref tempR, ref tempTheta, ref tempPhi); color = Util.AddColor(GetColor(tempR, tempTheta, tempPhi), color); stop = true; return(true); } return(false); }
public unsafe bool Hit(double *y, double *prevY, double *dydx, double hdid, KerrBlackHoleEquation equation, ref Color color, ref bool stop, bool debug) { // Remember what side of the theta-plane we're currently on, so that we can detect // whether we've crossed the plane after stepping. int side = prevY[1] > Math.PI / 2 ? 1 : prevY[1] < Math.PI / 2 ? -1 : 0; // Did we cross the theta (horizontal) plane? bool success = false; if ((y[1] - Math.PI / 2) * side <= 0) { // remember the current values of Y, so that we can restore them after the intersection search. double *yCurrent = stackalloc double[equation.N]; Util.memcpy((IntPtr)yCurrent, (IntPtr)y, equation.N * sizeof(double)); // Overwrite Y with its previous values, and perform the binary intersection search. Util.memcpy((IntPtr)y, (IntPtr)prevY, equation.N * sizeof(double)); IntersectionSearch(y, dydx, hdid, equation); // Is the ray within the accretion disk? if ((y[0] >= radiusInner) && (y[0] <= radiusOuter)) { color = Util.AddColor(GetColor(side, y[0], y[1], y[2]), color); stop = false; success = true; } // ...and reset Y to its original current values. Util.memcpy((IntPtr)y, (IntPtr)yCurrent, equation.N * sizeof(double)); } return(success); }
public unsafe bool Hit(double *y, double *prevY, double *dydx, double hdid, KerrBlackHoleEquation equation, ref Color color, ref bool stop, bool debug) { // Has the ray fallen past the horizon? if (y[0] < equation.Rhor) { Color col = Color.Black; if (checkered) { var m1 = Util.DoubleMod(y[2], 1.04719); // Pi / 3 var m2 = Util.DoubleMod(y[1], 1.04719); // Pi / 3 if ((m1 < 0.52359) ^ (m2 < 0.52359)) // Pi / 6 { col = Color.Green; } } else if (textureBitmap != null) { int xPos, yPos; textureMap.Map(y[0], y[1], -y[2], out xPos, out yPos); col = Color.FromArgb(textureBitmap[yPos * textureWidth + xPos]); } color = Util.AddColor(col, color); stop = true; return(true); } return(false); }
public KerrRayTracer(KerrBlackHoleEquation equation, int sizex, int sizey, List <IHitable> hitables, double cameraTilt, double cameraYaw, bool trace = false) { this.equation = equation; this.sizex = sizex; this.sizey = sizey; this.cameraTilt = cameraTilt; this.cameraYaw = cameraYaw; this.hitables = hitables; this.trace = trace; if (trace) { RayPoints = new List <Tuple <double, double, double> >(); } }
public Scene(Vector3 CameraPosition, Vector3 CameraLookAt, Vector3 UpVector, float Fov, List <IHitable> hitables, float CurvatureCoeff, float AngularMomentum) { this.CameraPosition = CameraPosition; this.CameraLookAt = CameraLookAt; this.UpVector = UpVector; this.hitables = hitables; this.Fov = Fov; double tempR = 0, tempTheta = 0, tempPhi = 0; Util.ToSpherical(CameraPosition.X, CameraPosition.Y, CameraPosition.Z, ref tempR, ref tempTheta, ref tempPhi); CameraDistance = tempR; CameraAngleVert = tempTheta; CameraAngleHorz = tempPhi - 0.1; SchwarzschildEquation = new SchwarzschildBlackHoleEquation(CurvatureCoeff); KerrEquation = new KerrBlackHoleEquation(CameraDistance, CameraAngleHorz, CameraAngleVert, AngularMomentum); }
public unsafe bool Hit(double *y, double *prevY, double *dydx, double hdid, KerrBlackHoleEquation equation, ref Color color, ref bool stop, bool debug) { // Has the ray escaped to infinity? if (y[0] > equation.R0) { // Restore Y to its previous values, and perform the binary intersection search. Util.memcpy((IntPtr)y, (IntPtr)prevY, equation.N * sizeof(double)); IntersectionSearch(y, dydx, hdid, equation); int xPos, yPos; textureMap.Map(y[0], y[1], y[2] + textureOffset, out xPos, out yPos); color = Util.AddColor(Color.FromArgb(textureBitmap[yPos * textureWidth + xPos]), color); stop = true; return(true); } return(false); }
protected unsafe void IntersectionSearch(double *y, double *dydx, double hupper, KerrBlackHoleEquation equation) { double hlower = 0.0; double tempX = 0, tempY = 0, tempZ = 0; equation.Function(y, dydx); while ((y[0] > equation.Rhor) && (y[0] < equation.R0)) { double *yout = stackalloc double[equation.N]; double *yerr = stackalloc double[equation.N]; double hdiff = hupper - hlower; if (Math.Abs(hdiff) < 1e-7) { RungeKutta.IntegrateStep(equation, y, dydx, hupper, yout, yerr); Util.memcpy((IntPtr)y, (IntPtr)yout, equation.N * sizeof(double)); return; } double hmid = (hupper + hlower) / 2; RungeKutta.IntegrateStep(equation, y, dydx, hmid, yout, yerr); Util.ToCartesian(yout[0], yout[1], yout[2], ref tempX, ref tempY, ref tempZ); double distance = Math.Sqrt((tempX - centerX) * (tempX - centerX) + (tempY - centerY) * (tempY - centerY) + (tempZ - centerZ) * (tempZ - centerZ)); if (distance > radius) { hlower = hmid; } else { hupper = hmid; } } }
private unsafe void IntersectionSearch(double *y, double *dydx, double hupper, KerrBlackHoleEquation equation) { double hlower = 0.0; equation.Function(y, dydx); while ((y[0] > equation.Rhor) && (y[0] < equation.R0 * 2)) { double *yout = stackalloc double[equation.N]; double *yerr = stackalloc double[equation.N]; double hdiff = hupper - hlower; if (Math.Abs(hdiff) < 1e-7) { RungeKutta.IntegrateStep(equation, y, dydx, hupper, yout, yerr); Util.memcpy((IntPtr)y, (IntPtr)yout, equation.N * sizeof(double)); return; } double hmid = (hupper + hlower) / 2; RungeKutta.IntegrateStep(equation, y, dydx, hmid, yout, yerr); if (yout[0] < equation.R0) { hlower = hmid; } else { hupper = hmid; } } }
/// <summary> /// Use Runge-Kutta steps to find intersection with horizontal plane of the scene. /// This is necessary to stop integrating when the ray hits the accretion disc. /// </summary> private unsafe void IntersectionSearch(double *y, double *dydx, double hupper, KerrBlackHoleEquation equation) { double hlower = 0.0; int side; if (y[1] > Math.PI / 2) { side = 1; } else if (y[1] < Math.PI / 2) { side = -1; } else { // unlikely, but needs to handle a situation when ray hits the plane EXACTLY return; } equation.Function(y, dydx); while ((y[0] > equation.Rhor) && (y[0] < equation.R0) && (side != 0)) { double *yout = stackalloc double[equation.N]; double *yerr = stackalloc double[equation.N]; double hdiff = hupper - hlower; if (Math.Abs(hdiff) < 1e-7) { RungeKutta.IntegrateStep(equation, y, dydx, hupper, yout, yerr); Util.memcpy((IntPtr)y, (IntPtr)yout, equation.N * sizeof(double)); return; } double hmid = (hupper + hlower) / 2; RungeKutta.IntegrateStep(equation, y, dydx, hmid, yout, yerr); if (side * (yout[1] - Math.PI / 2) > 0) { hlower = hmid; } else { hupper = hmid; } } }