From f5f7078e46ca28342d069d48b986583bc2cc0269 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Tue, 12 Dec 2023 13:41:23 +0200 Subject: (blog/bhs) Added an initial explanation of math and physics behind it --- ...tric-in-Schwarzschild-coordinates-wikipedia.png | Bin 0 -> 3423 bytes .../img/Schwarzschild-radius-wikipedia.png | Bin 0 -> 1054 bytes .../img/algorithm.png | Bin 0 -> 28039 bytes .../img/antonelli-formula-expanded.png | Bin 0 -> 11619 bytes .../img/isco-wikipedia.png | Bin 0 -> 1614 bytes .../img/normalize-vector-wikipedia.png | Bin 0 -> 625 bytes .../img/photon-sphere-wikipedia.png | Bin 0 -> 1472 bytes ...chwarzschild-black-hole-force-field-formula.png | Bin 0 -> 2265 bytes .../img/specific-angular-momentum-wikipedia.png | Bin 0 -> 529 bytes .../img/variables-expanded.png | Bin 0 -> 9318 bytes .../index.md | 289 +++++++++++++++++++++ 11 files changed, 289 insertions(+) create mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png create mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png create mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/algorithm.png create mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/antonelli-formula-expanded.png create mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/isco-wikipedia.png create mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/normalize-vector-wikipedia.png create mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/photon-sphere-wikipedia.png create mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png create mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png create mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/variables-expanded.png create mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/index.md (limited to 'src') diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png new file mode 100644 index 0000000..3964615 Binary files /dev/null and b/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png new file mode 100644 index 0000000..fccf54f Binary files /dev/null and b/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/algorithm.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/algorithm.png new file mode 100644 index 0000000..40d4c86 Binary files /dev/null and b/src/blog/difficulties-of-making-a-black-hole-shader/img/algorithm.png differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/antonelli-formula-expanded.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/antonelli-formula-expanded.png new file mode 100644 index 0000000..48eb7d4 Binary files /dev/null and b/src/blog/difficulties-of-making-a-black-hole-shader/img/antonelli-formula-expanded.png differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/isco-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/isco-wikipedia.png new file mode 100644 index 0000000..2b01135 Binary files /dev/null and b/src/blog/difficulties-of-making-a-black-hole-shader/img/isco-wikipedia.png differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/normalize-vector-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/normalize-vector-wikipedia.png new file mode 100644 index 0000000..517e142 Binary files /dev/null and b/src/blog/difficulties-of-making-a-black-hole-shader/img/normalize-vector-wikipedia.png differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/photon-sphere-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/photon-sphere-wikipedia.png new file mode 100644 index 0000000..840572c Binary files /dev/null and b/src/blog/difficulties-of-making-a-black-hole-shader/img/photon-sphere-wikipedia.png differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png new file mode 100644 index 0000000..846b0d3 Binary files /dev/null and b/src/blog/difficulties-of-making-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png new file mode 100644 index 0000000..61b3383 Binary files /dev/null and b/src/blog/difficulties-of-making-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/variables-expanded.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/variables-expanded.png new file mode 100644 index 0000000..484e2f1 Binary files /dev/null and b/src/blog/difficulties-of-making-a-black-hole-shader/img/variables-expanded.png differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/index.md b/src/blog/difficulties-of-making-a-black-hole-shader/index.md new file mode 100644 index 0000000..7c78c05 --- /dev/null +++ b/src/blog/difficulties-of-making-a-black-hole-shader/index.md @@ -0,0 +1,289 @@ +# Difficulties of making a black hole shader + +## Contents + +This year I took a university elective course for WebGL programming. +Back in August I had to create and submit some sort of a project, so I chose to create an interractive and animated black hole demo. +The primary idea was to show how the gravitational pull of black holes bend light and how the result looks from different points of view. + +During development I found a lot of hurdles, primarily with the actual bending of light. +Information online is kind of hard to understand and find, so I'll try my best to lay out everything I know. + +I'll assume you don't understand a lot of physics, but are familiar with vectors and operations with them. +Also this is in no way an exploration of best practices and good WebGL development. + +## Context + +This section serves as a quick refresher. + +### Brief introduction to computer graphics + +Imagine a photo of a bottle: you can see the bottle, but you cannot rotate it, or change it's size, or modify it in any way, without having to download the image, fire up a comlicated image editing program and spend hours upon hours doing your modifications. +And it becomes even harder if you want to add or remove objects, say a table on which the bottle sits. + +The main idea of computer graphics is to define your objects with some few but "abstract" values: the bottle is X tall, the base is Y wide, it has Z color, etc. and then a computer program has to take those values and "generate" the actual image. +Or to be more precise, for every pixel on the screen where you should be able to see the bottle, the computer calculates what the precise color of that pixel is. + +This allows us to dynamically change objects: if I wanna make the bottle shorter, I make X a smaller number, and the computer recalculates everything using the new height. +If I want to add or remove objects, I just give or remove the specific parameters that define those objects and tell the computer to recalculate the image again. + +As you might imagine, it's extremely difficult to calculate everything needed to show an image, and it takes an absurd amount of system resources and time. +That's why people decided to create a separate processing unit, just for rendering graphics: the [GPU](TODO). + +A GPU is optimized on the hardware level for parallel computation (calculate multiple stuff at the same time), fast math with 3D points and matricies, and so on. +The tradeoff is that a GPU doesn't implement most of the normal stuff a [CPU](TODO) does. + +For this reason, programs written for GPUs are called "shaders". +Most often shaders are written in some "higher" level programming language, which is then translated via a graphics API or library to something the actual GPU can understand. +For comparison, in normal softare development you write a program (not a shader), which is then translated to something the CPU can understand via a compiler or interpreter. + +### Brief introduction to WebGL + +One of the most popular such libraries is [OpenGL](TODO) with it's associated shader programming languages [GLSL](TODO) and [GLSL ES](TODO). +In the 2000s people decided it would be a good idea to add a graphics API/library to web browsers. +Skipping over a lot of history, [WebGL](TODO) was born and widely adopted. + +It serves as a "layer above" OpenGL: you write JavaScript code with which the browser tells OpenGL what to do. +You would get a DOM object in which the graphics will be rendered, and a "context" object to which you'll pass down your shaders, shader parameters and change graphics settings. + +## Theory behind black holes + +As we know from physics, objects with mass create a gravitational field which "pulls" inwards everything around them. +However, [Einstein's general theory of relativity](https://en.wikipedia.org/wiki/General_relativity) showed that this isn't really a force which pulls, like with (eletro)magnetism, but more of an effect: mass changes the curvature of [spacetime](TODO), which by extension changes the geodesic's "curavture". + +### Explanation of geodesics and gravitational lensing + +Let's back up a bit, first think of a flat surface, like a table or a (flat) sheet of paper. +What is the shortest distance between two points? +Obviously, that's a straight line. + +However, what if our surface isn't flat? +Imagine two points on a sphere, what is the shortest distance between them? +You might be inclined to say that's also a straight line, but it really isn't: it's an arc of a circle! + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Illustration_of_great-circle_distance.svg/480px-Illustration_of_great-circle_distance.svg.png) +[*Image by CheCheDaWaff on Wikipedia*](https://commons.wikimedia.org/w/index.php?curid=48187293) + +This circle is called a [great circle](https://en.wikipedia.org/wiki/Great_circle). +Looking at all possible great circles, we find they have an interesting property: their center (and radius) matches with the center (and radius) of the sphere. + +Another big difference between this arc and a "line" is that lines can be parallel, but arcs cannot. +Again, the shortest distance between to points is a line *segment*, extend that segment into infinity and it becomes a line. +On a flat surface, we know that if you take two points and create the line passing through them, then there exists at least two other distinct points, whose line, crated from intersecting them, does not ever intersect the first line. +However, as we said, on a sphere all great circles have the same center and radius, so it doesn't matter which two pairs of points we take, their great circles must always intersect[^parallels-of-latitude]! + +In non-flat surfaces, the segment which has the shortest distance between two points is called a geodesic (in flat surfaces, a line is practically a geodesic, on spheres, great circles are geodesics). +We can now also define what it means to "go straight forwards": in flat surfaces we would say that means following a straight line, while on non-flat it means following a geodesic. + +Going back to physics, what the General theory of relativity tells us is that gravity bends spacetime, the actual space, or 3D surface, in which the universe exists. +In effect, the geodesics in our space are also curved. +Therefore, if you are always travelling forward, perfectly following a geodesic, if you start passing an object of great mass, it's gravity will bend that geodesic, so even though you are always going forwards, you'll actually "turn" or follow a curve. + +This is the exact effect a black hole produces: it's mass is so great and it bends space(time) **so much**, light can take a really sharp curve. +We call this [graviational lensing](TODO): + +![](https://upload.wikimedia.org/wikipedia/commons/0/02/Gravitational_lens-full.jpg) +*(notice how the gray arrows show the path light travels from a galaxy that is behind (obstructed by) the black hole)* + +I spent a good amount of time explaning that gravity doesn't curve object's path but spacetime itself, however, this distinction really matters for physics, in our simulation it requires significantly less computation and programmer effort if we assume the former. + +Then were all of these explanations a waste of time? +Not really, since physics works with the spacetime curvature, we'll have to do conversions/modifications to the formulae, so they behaves like a force that pulls on the object in motion. + +### Finding a formula + +Now, how do we calculate the exact curvature a black hole produces? +General theory of relativity provides us with the [Einstein field equations](https://en.wikipedia.org/wiki/Einstein_field_equations), a complicated set of equations which allows us to calculate how spacetime curves around an object with large mass. +[Schwartzschild](TODO) solved these equations, assuming that the body with mass doesn't spin[^schwm-assumptions]. +This solution is called the [Schwarzschild metric](https://en.wikipedia.org/wiki/Schwarzschild_metric). +A black hole for which this (these) assumption is true is called a "Shwartzschild black hole". + +This is the simplest solution to those equation, and a Schwartzschild black hole is the simplest type of black hole, so we're gonna use that. +Now, by definition, here is the Schwartzschild metric in Schwartzschild coordinates: + +![](./img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png) + +**YOUCH!** + +You might notice there are derivatives in this equation, as you might imagine, it's unbearably slow to calculate it, especially if we want our demo to run at at least 30 frames per second! +There is also another problem: Schwartzschild coordinates, our GPU works with normal cartesian coordinates, so we'll also have to do transform the coordinates. +We'll also need to transfrom the curved spacestime coordinates to cartesian, as if spacetime wasn't curved around the black hole. + +I personally have zero clue how to deal with this monster. +Thankfully [Riccardo Antonelli](http://rantonels.github.io/starless/) was able to do all of our coordinate conversions and simplify the living crap out of that monster (using some approximations), turning it in a pretty small equation: + +![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png) + +Question now is: how do we use it? +This turned out to be a much harder problem than it should have, I actually had to refer to [Dmitry Brant](https://dmitrybrant.com/2018/12/11/ray-tracing-black-holes)'s usage of [the formula for his own project](https://github.com/dbrant/BlackHoleRaytracer) as well as [Ricardo Antonelli's implementation](https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py). + +### Applying the formula to "bend" light's path + +First, how are we going to represent light? +The simplest way is to think of light as a small particle (or spaceship) travelling through space. +We'll move our particle by a tiny amount, and before moving it, we'll calculate how much the black hole changes it's direction and move the particle in that new direction. + +Referring at the formula again: + +![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png) + +The F→ returns a force vector (`F` for "force" and → for "vector"): any force acting on an object has a strength (magnitude) and a direction. +Imagine you are pushing a box: you are applying some force to it in a "forward" direction. +If you pull the box, you'll apply some force in a "backward" direction. + +This force vector specifies how much and in what direction exactly the black hole is pulling on the light "particle". + +Although the function takes in only one argument, `r`, that doesn't mean that `h` and r\^ are some universal constants: they also need to be calculted and "passed" to the function. + +`r` is the distance from the center of the black hole (the singularity) to the **current** position of the light "particle". + +`h` is the magnitude of the ["specific angular momentum"](https://en.wikipedia.org/wiki/Specific_angular_momentum) of the light "particle". + +"Normal" linear momentum specifies how much "force" at what speed it takes to stop (or change) the speed and direction of an object in linear motion (that's why it's in kg\*m/s). +Imagine a big heavy train going at a fast speed. +How do you forcefully stop it? + +You can put a *really* heavy barrier on the tracks, in front of the train. +Since the train has a lot of momentum, this barrier will have to be much much heavier (with much more mass) than the train itself (when the train would be stationary). + +Alternatively, you can "launch" something against the train, meaning you can take a second train, and make it go in the opposite direction of the first train, so they hit head-on. +Since the second train would also be moving, that would add to it's momentum, and the second train wouldn't need to be much heavier than the first train. +In fact, if the second train travels at the same speed as the first, then the mass of both trains would suffice to be equal, and if it travels twice as fast, it would suffice if the second train has half the mass of the first. + +Angular momentum specifies how much "force" at what speed it takes to stop (or change) the speed and directino of a rotating object. +Imagine the train scenario but on a circular track. + +The specific angular momentum is the angular momentum of an object, divided by it's mass. +It kind of tells us which property is more prevalent in the momentum, the mass or the speed: for the same angular momentum, a high *specific* angular momentum means our object is small and moves fast, while for a small *specific* angular momentum out object is large and moves slowly. + +In our case a light "particle" is being pulled by a stationary object of large mass (a Shwarzschild black hole), so rather than finding the angular momentum[^angular-momentum] and then dividing by the mass[^light-has-no-mass], we'll use another formula: + +![](./img/specific-angular-momentum-wikipedia.png) + +where **in this specific formula only** `r` is the vector from the center of the big mass (the singularity of the black hole) to the light "particle" and `v` is the velocity (direction and amount of speed) the light is travelling with. + +The cross product returns a vector, so we'll need to take the magnitutde of the result and plug that into the formula. +It's also important that **we calculate it only once, in the beginning**. +So, we shouldn't be calculating the magnitude of the specific angular momentum every time the light "particle" is moved, rather we calculate it once, after it gets close enough to be affected by the black hole. + +r^ is the vector from the center of the black hole to the light particle as a [unit](https://en.wikipedia.org/wiki/Unit_vector) vector (hence the `^` on top). + +This means that we normalize the vector, meaning divide it by it's magnitude (length): + +![](./img/normalize-vector-wikipedia.png) + +Finally, putting all needed variables together in one formula, we get: + + +![](./img/variables-expanded.png) + +where velocity of light "particle" means a vector, with the direction in which the light "particle" will travel, and a magnitude equal to the distance (speed) the light "particle" will travel in. +As you may notice, this can be simplified, if we substitude r^: + + +![](./img/antonelli-formula-expanded.png) + +Finally, we know what to give the formula, and what it will return. +Current question is: how do we use it's output? +For that we'll need to get familiar with black holes. + +### Explaning black holes + +Physics regards black holes as an infinitessimal (infinitely small) point with some huge amount of mass. +From the mass we can derive three radii, which will be the backbone of our black hole: the event horizon, the photon sphere and [ISCO](https://en.wikipedia.org/wiki/Innermost_stable_circular_orbit). + +The event horizon, also called the Schwarzschild radius, is the distance from the center of the black hole (singularity), which once passed, cannot be escaped. +In other words, once something gets too close, and passes this distance, then it cannot ever escape, even if it's light. +The formula for it is: + +![](./img/Schwarzschild-radius-wikipedia.png) + +where `G` is the [gravitational constant](https://en.wikipedia.org/wiki/Gravitational_constant) and `M` is the mass of the black hole (in kg). + +The photon sphere is the distance from the singularity, in which photons start orbiting the black hole (and can either escape or pass the event horizon). +Formula: + +![](./img/photon-sphere-wikipedia.png) + +where `G` and `M` are the same as before, `c` is the speed of light in vacuum and rs is the afroementioned Schwarzschild radius. + +Finally, the innermost stable circular orbit (ISCO), officially it's the distance, before which you can orbit the black hole, but once passed, you'll get sucked in and either get shot out or forever lost past the event horizon. +For our purposes, it's fine to approximate it as the maximum radius after which spacetime isn't bent[^isco] and objects aren't affected. +Formula: + +![](./img/isco-wikipedia.png) + +Putting them all together, we should expect light to travel like this: +![](https://upload.wikimedia.org/wikipedia/commons/2/27/Black_Hole_Shadow.gif) +*Animation by Hugo Spinelli on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=138168679)* + +### Putting everything together + +Finally, now we have everything we need to divise an algorithm for our light. +For light we'll store two vectors: one for it's position and one for it's velocity. +For a black hole we'll store a vector and a quantity: the position of the black hole's center and it's mass. +For convinience, we could just store the Schwarzschild radius, since all of our radii depend only on it. + +Once the distance between the light and the center is less than or equal to the ISCO, we can begin augmenting light's velocity. +On small steps, we move the light forward a bit with the velocity and then update the velocity with the black hole's pull. + +If light enters the event horizon, then we know it cannot escape, and stop moving it. +If it passes the ISCO then it has left the black hole and will never approach it again. + +If light enters the photon sphere, then we'll have to "track" how long it's been there, if it decides to orbit in a stable manner, then it will stay there indefinetly. +The simplest way to "track" this is just to limit how many times we can move the light forward. + +An algorithm doing this would look a bit like this (in pseudocode, inspired by Python): + + + +![](./img/algorithm.png) + +as a reminder, here is the definiton of F→: + +![](./img/antonelli-formula-expanded.png) + +[^parallels-of-latitude]: You might think about the latituginal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest. +[^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](TODO) is zero. These are way outside of my understanding and our purposes, so I skiped them for simplicity. +[^isco]: It's not really true that gravity stopps affecting spacetime after the ISCO, even though things can orbit Earth that doesn't mean that Earth doesn't bend spacetime. However, for the purposes of a simple shader, this assumption produces perfectly useable results. +[^angular-momentum]: Angular momentum is actually [defined using the cross product](https://en.wikipedia.org/wiki/Specific_angular_momentum#Definition) +[^light-has-no-mass]: Actually, light has no mass, so this version of the formula wouldn't work. You might think that makes no sense, since we cannot divide by zero, so the specific angular momentum shouldn't exist, but then with the cross product we find a value for it. You would be correct: Antonelli does some funky approximations, combining Newtonian physics with General theory of relativity, to make the formula that simple. Someone in physics will probably vomit looking at it, but for our purposes it's more than perfect. -- cgit v1.3.1-26-gb76a From 71db9a7a0a240a6d4ba81dd0c4a4941385419339 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Fri, 15 Dec 2023 07:37:36 +0200 Subject: (blog/bhs) Major rewrite of most text --- .../index.md | 249 ++++++++++++--------- 1 file changed, 143 insertions(+), 106 deletions(-) (limited to 'src') diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/index.md b/src/blog/difficulties-of-making-a-black-hole-shader/index.md index 7c78c05..b142f99 100644 --- a/src/blog/difficulties-of-making-a-black-hole-shader/index.md +++ b/src/blog/difficulties-of-making-a-black-hole-shader/index.md @@ -2,128 +2,153 @@ ## Contents -This year I took a university elective course for WebGL programming. -Back in August I had to create and submit some sort of a project, so I chose to create an interractive and animated black hole demo. -The primary idea was to show how the gravitational pull of black holes bend light and how the result looks from different points of view. +Back in August I had to submit a project for an elective WebGL programming course in university. +I chose to create an interractive and animated black hole demo. +The primary idea was to show how the gravitational pull of black holes "bend" light and how the result looks from different points of view. -During development I found a lot of hurdles, primarily with the actual bending of light. -Information online is kind of hard to understand and find, so I'll try my best to lay out everything I know. +During development I found a lot of hurdles, primarily with the actual mathematics behind it. +Information online is difficult to parse and understand if you don't have a physics background, so I'll try my best to lay out everything I know. -I'll assume you don't understand a lot of physics, but are familiar with vectors and operations with them. -Also this is in no way an exploration of best practices and good WebGL development. +I'll assume you don't know much about physics, but are familiar with mathematics and at the very least vectors. -## Context - -This section serves as a quick refresher. +## Preface ### Brief introduction to computer graphics -Imagine a photo of a bottle: you can see the bottle, but you cannot rotate it, or change it's size, or modify it in any way, without having to download the image, fire up a comlicated image editing program and spend hours upon hours doing your modifications. -And it becomes even harder if you want to add or remove objects, say a table on which the bottle sits. +Image and video files store visual information in a "fixed" way: you get a huge array of colors, each connected to a particular pixel on your screen. +The objects in those mediums cannot be modified easily, and additions or subtractions are even harder to do, usually requiring an expert using a professional tools for hours, days, weeks or months on end. + +Computer graphics aims to offload a lot of the creator's workload by "generating" the images on the fly using a set of descriptions for our objects. +The idea is to define objects with some simpler geometric figures, then give those to the computer, which will in turn have to calculate what the precise color of every pixel in the resultant image should be. + +For example, we can represent a tin can (without a label) as a simple cyllinder. +Changing it's height or width is trivial: just change the corresponding property you pass to the computer, and it will handle the rest. + +Of course this system has it's limitations: the more detail you add to an object, the more difficult it is to crunch up the math. +And adding lighting with shadows, bloom, refractions and so on becomes even more demanding for the computer. + +Expanding on out tin can example, if you want an image with a tin can up close, with a bright light shining on it, showing the hunderds or thousands of small scratches, bumps and kicks from manufacturing and usage, alongside reflections and shadows, you'll swiftly find that computer graphics are not the correct tool for the job. -The main idea of computer graphics is to define your objects with some few but "abstract" values: the bottle is X tall, the base is Y wide, it has Z color, etc. and then a computer program has to take those values and "generate" the actual image. -Or to be more precise, for every pixel on the screen where you should be able to see the bottle, the computer calculates what the precise color of that pixel is. +![](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Empty_tin_can2009-01-19.jpg/514px-Empty_tin_can2009-01-19.jpg) +*Image by Sun Ladder on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=5746428)* -This allows us to dynamically change objects: if I wanna make the bottle shorter, I make X a smaller number, and the computer recalculates everything using the new height. -If I want to add or remove objects, I just give or remove the specific parameters that define those objects and tell the computer to recalculate the image again. +Such an image contains way way too much detail the average computer to handle in reasonable time (some small fraction of a second). +However, computer generated graphics are still a very useful tools. +Thats why modern machines come with a processor, handling most tasks like running programs, managing internet traffic, etc. and a graphics card handling *only* graphical tasks. -As you might imagine, it's extremely difficult to calculate everything needed to show an image, and it takes an absurd amount of system resources and time. -That's why people decided to create a separate processing unit, just for rendering graphics: the [GPU](TODO). +A graphics card is a combination of a special processor (GPU), designed to be able to *only* compute stuff related to graphics, with the upside of doing so much much faster than a general purpose processor (CPU) could, and some memory for use exclusively by that GPU. -A GPU is optimized on the hardware level for parallel computation (calculate multiple stuff at the same time), fast math with 3D points and matricies, and so on. -The tradeoff is that a GPU doesn't implement most of the normal stuff a [CPU](TODO) does. +Since the GPU is different on the hardware level, it accepts significantly different instructions than a normal processor does. +For this reason programs written for a graphics processing unit are called "shaders", rather than just "programs". -For this reason, programs written for GPUs are called "shaders". -Most often shaders are written in some "higher" level programming language, which is then translated via a graphics API or library to something the actual GPU can understand. -For comparison, in normal softare development you write a program (not a shader), which is then translated to something the CPU can understand via a compiler or interpreter. +Of course, higher-level programming languages have been designed, which can then be transformed into the GPU-specific instructions. +But, contrary to normal software development, we don't really have standalone "shader compilers", but graphics library which do the job, alongside TODO ### Brief introduction to WebGL One of the most popular such libraries is [OpenGL](TODO) with it's associated shader programming languages [GLSL](TODO) and [GLSL ES](TODO). -In the 2000s people decided it would be a good idea to add a graphics API/library to web browsers. -Skipping over a lot of history, [WebGL](TODO) was born and widely adopted. +In the 2000s people decided it would be a good idea to add a graphics API/library to web browsers, which later morphed into what we call today [WebGL](TODO). It serves as a "layer above" OpenGL: you write JavaScript code with which the browser tells OpenGL what to do. You would get a DOM object in which the graphics will be rendered, and a "context" object to which you'll pass down your shaders, shader parameters and change graphics settings. -## Theory behind black holes +## Theoretical and algorithmic background + +Using [Einstein's field equations](TODO), or to simplify our life, [Schwarzschild's metric](TODO), we can precisely calculate the curvatures in space(time) at every point around a massive stationary object, like a non-rotating black hole. +Of course, the computation would still be too laborious, so making an approximation using [celestial mechanics](TODO) and representing light as a particle (corpiscule), we can tame the physics into a simple algorithm. + +Of course, there are a lot more details, so let's back up a bit. + +### What is a black hole + +A black hole is an object in space, which "collapsed" down to an infinitely small point. +In other words, if you take something with mass (although it's incorrect, you may think of mass as the amount of atoms comprising the object) and compress it into a small enough size, then the forces between the atoms and even subatomic particles will not be strong enough to keep themselves intact and separate. -As we know from physics, objects with mass create a gravitational field which "pulls" inwards everything around them. -However, [Einstein's general theory of relativity](https://en.wikipedia.org/wiki/General_relativity) showed that this isn't really a force which pulls, like with (eletro)magnetism, but more of an effect: mass changes the curvature of [spacetime](TODO), which by extension changes the geodesic's "curavture". +You can think of atoms like magnetic marbles, all marbles are separated with empty space (due to the magnet force), so if you push on them, you can compress them so they get closer together. +However, you can continue pushing them together, after enough forces, they'll all start deforming into a small really dense block of metal. -### Explanation of geodesics and gravitational lensing +Outside analogies, keep in mind that this infinitessimal point has the same initial mass as the object which collapsed. +This has great consequences on gravity, but what is gravity anyway? -Let's back up a bit, first think of a flat surface, like a table or a (flat) sheet of paper. +### Geodesics, gravity and gravitational lensing + +Think of a flat surface, like a table or a (flat) sheet of paper. What is the shortest distance between two points? -Obviously, that's a straight line. +Obviously, that's a straight line segment. +If you then extend that segment, so it has an infinite length, it becomes a line. However, what if our surface isn't flat? Imagine two points on a sphere, what is the shortest distance between them? -You might be inclined to say that's also a straight line, but it really isn't: it's an arc of a circle! +You might be inclined to say that's also a "straight" line, but it really isn't: it's an arc of a circle! ![](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Illustration_of_great-circle_distance.svg/480px-Illustration_of_great-circle_distance.svg.png) [*Image by CheCheDaWaff on Wikipedia*](https://commons.wikimedia.org/w/index.php?curid=48187293) This circle is called a [great circle](https://en.wikipedia.org/wiki/Great_circle). -Looking at all possible great circles, we find they have an interesting property: their center (and radius) matches with the center (and radius) of the sphere. +The main problem with calling this arc a "spherical line segment" (and the great circle a "spherical line" or something similar) is that both objects have different properties. -Another big difference between this arc and a "line" is that lines can be parallel, but arcs cannot. -Again, the shortest distance between to points is a line *segment*, extend that segment into infinity and it becomes a line. -On a flat surface, we know that if you take two points and create the line passing through them, then there exists at least two other distinct points, whose line, crated from intersecting them, does not ever intersect the first line. -However, as we said, on a sphere all great circles have the same center and radius, so it doesn't matter which two pairs of points we take, their great circles must always intersect[^parallels-of-latitude]! +Looking at all possible great circles, we find that their center (and radius) matches with the center (and radius) of the sphere. +From this we can find the bigest difference: lines can be parallel, but great circles cannot. +A line is an extended segment, so if you extend two different arcs (which are the shortest distance between two pairs of points on the sphere) and get the great circles, those will always intersect[^parallels-of-latitude]. -In non-flat surfaces, the segment which has the shortest distance between two points is called a geodesic (in flat surfaces, a line is practically a geodesic, on spheres, great circles are geodesics). +Therefore, the general term for the shortest path between two points on a non-flat surface is (kind of) called a geodesic[^geodesics-are-local] (the arc on the sphere is a geodesic). We can now also define what it means to "go straight forwards": in flat surfaces we would say that means following a straight line, while on non-flat it means following a geodesic. -Going back to physics, what the General theory of relativity tells us is that gravity bends spacetime, the actual space, or 3D surface, in which the universe exists. -In effect, the geodesics in our space are also curved. -Therefore, if you are always travelling forward, perfectly following a geodesic, if you start passing an object of great mass, it's gravity will bend that geodesic, so even though you are always going forwards, you'll actually "turn" or follow a curve. +Going back to physics, what the General theory of relativity tells us is that objects with mass bend the physical space, or 3D surface, of the universe, and we call that gravity. +As a result, the geodesics too are curved, so even though you may be always moving forwards at the same speed, to an outside observer it will look like you turn and change speed. + +The amount by which and the size of the area which is affected depend on that object's mass and size. +Generally, if two objects have the same mass, the bigger one will bend less a larger portion of space, compared to the smaller one, which will bend a lot the smaller portion of space. -This is the exact effect a black hole produces: it's mass is so great and it bends space(time) **so much**, light can take a really sharp curve. -We call this [graviational lensing](TODO): +Since a black hole is a single infinetly small point, then all of it's mass is concentrated on that point, making a really really **really** strong bend in a small (compared to a non-blackhole object with the same mass) area. +Strong enough in fact, that if you get too close, you will not be able to overwhelm gravity and "merge" into that infinitessimal point. + +An interesting effect from gravity is that light (which always travells "forwards", so along a geodesic) also gets "bent", allowing an observer to view otherwise obstructed objects. +We call that [graviational lensing](TODO). +Though not unique to black holes, thats when the effect is strongest: ![](https://upload.wikimedia.org/wikipedia/commons/0/02/Gravitational_lens-full.jpg) *(notice how the gray arrows show the path light travels from a galaxy that is behind (obstructed by) the black hole)* -I spent a good amount of time explaning that gravity doesn't curve object's path but spacetime itself, however, this distinction really matters for physics, in our simulation it requires significantly less computation and programmer effort if we assume the former. - -Then were all of these explanations a waste of time? -Not really, since physics works with the spacetime curvature, we'll have to do conversions/modifications to the formulae, so they behaves like a force that pulls on the object in motion. +The distinction that gravity doesn't change the direction or speed of an object "directly" (preserving the speed for light rays) is at upmost importance for physics. +However, in our simulation, it would be significantly simpler to assume the opposite, since to an outside observer (like the "player") the difference is indistinguishable. +Therefore, we would need to make some modifications to the proper physics equations. ### Finding a formula Now, how do we calculate the exact curvature a black hole produces? -General theory of relativity provides us with the [Einstein field equations](https://en.wikipedia.org/wiki/Einstein_field_equations), a complicated set of equations which allows us to calculate how spacetime curves around an object with large mass. +General theory of relativity provides us with the (really complicated) [Einstein field equations](https://en.wikipedia.org/wiki/Einstein_field_equations) for this exact problem. [Schwartzschild](TODO) solved these equations, assuming that the body with mass doesn't spin[^schwm-assumptions]. This solution is called the [Schwarzschild metric](https://en.wikipedia.org/wiki/Schwarzschild_metric). A black hole for which this (these) assumption is true is called a "Shwartzschild black hole". -This is the simplest solution to those equation, and a Schwartzschild black hole is the simplest type of black hole, so we're gonna use that. -Now, by definition, here is the Schwartzschild metric in Schwartzschild coordinates: +The Shwarzschild black hole is the symplest of it's type, so using the Schwarzschild metric should give us the least trouble. +Now, here is the metric in Schwartzschild coordinates: ![](./img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png) **YOUCH!** -You might notice there are derivatives in this equation, as you might imagine, it's unbearably slow to calculate it, especially if we want our demo to run at at least 30 frames per second! -There is also another problem: Schwartzschild coordinates, our GPU works with normal cartesian coordinates, so we'll also have to do transform the coordinates. -We'll also need to transfrom the curved spacestime coordinates to cartesian, as if spacetime wasn't curved around the black hole. +The variables themselves aren't that bad: `c` is the speed of light, τ is time, Ω, `t` and `r` are Schwarzschild coordinates. -I personally have zero clue how to deal with this monster. -Thankfully [Riccardo Antonelli](http://rantonels.github.io/starless/) was able to do all of our coordinate conversions and simplify the living crap out of that monster (using some approximations), turning it in a pretty small equation: +However, as you can see, there are two big problems: we have to calculate derivatives (that's what the `d` signifies) and convert from Schwarzschild coordinates to normal (eucledian) coordinates, that the computer understands natively. +Both of those operations are **incredibly slow**, the average computer doesn't standa a chance at rendering anything in a reasonable amount of time. + +Thankfully [Riccardo Antonelli](http://rantonels.github.io/starless/) was able to do all of our coordinate conversions and simplify the living crap out of that monster (using some approximations with celestial mechanics), turning it into something digestible: ![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png) Question now is: how do we use it? -This turned out to be a much harder problem than it should have, I actually had to refer to [Dmitry Brant](https://dmitrybrant.com/2018/12/11/ray-tracing-black-holes)'s usage of [the formula for his own project](https://github.com/dbrant/BlackHoleRaytracer) as well as [Ricardo Antonelli's implementation](https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py). +This turned out to be a much harder problem than it should have, I actually had to refer [Ricardo Antonelli's](https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py) and [Dmitry Brant's](https://dmitrybrant.com/2018/12/11/ray-tracing-black-holes) implementation in their projects, alongside copus articles on wikipedia to fully grasp how to put it to work. ### Applying the formula to "bend" light's path First, how are we going to represent light? -The simplest way is to think of light as a small particle (or spaceship) travelling through space. -We'll move our particle by a tiny amount, and before moving it, we'll calculate how much the black hole changes it's direction and move the particle in that new direction. +The simplest way is to think of light as a small particle (which Newton called "corpiscule") travelling through space. +We'll move our particle by a tiny amount in a certain direction, then update the direction, accounting for gravity, and then repeat. +The direction, alongside the amount by which the particle moves can be represented with a single vector, which we'll call light's "velocity". -Referring at the formula again: +Referring to the formula again: ![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png) @@ -131,48 +156,49 @@ The F→ returns a force vector (`F` for "force" and Imagine you are pushing a box: you are applying some force to it in a "forward" direction. If you pull the box, you'll apply some force in a "backward" direction. -This force vector specifies how much and in what direction exactly the black hole is pulling on the light "particle". - -Although the function takes in only one argument, `r`, that doesn't mean that `h` and r\^ are some universal constants: they also need to be calculted and "passed" to the function. - -`r` is the distance from the center of the black hole (the singularity) to the **current** position of the light "particle". - -`h` is the magnitude of the ["specific angular momentum"](https://en.wikipedia.org/wiki/Specific_angular_momentum) of the light "particle". - -"Normal" linear momentum specifies how much "force" at what speed it takes to stop (or change) the speed and direction of an object in linear motion (that's why it's in kg\*m/s). -Imagine a big heavy train going at a fast speed. -How do you forcefully stop it? - -You can put a *really* heavy barrier on the tracks, in front of the train. -Since the train has a lot of momentum, this barrier will have to be much much heavier (with much more mass) than the train itself (when the train would be stationary). - -Alternatively, you can "launch" something against the train, meaning you can take a second train, and make it go in the opposite direction of the first train, so they hit head-on. -Since the second train would also be moving, that would add to it's momentum, and the second train wouldn't need to be much heavier than the first train. -In fact, if the second train travels at the same speed as the first, then the mass of both trains would suffice to be equal, and if it travels twice as fast, it would suffice if the second train has half the mass of the first. - -Angular momentum specifies how much "force" at what speed it takes to stop (or change) the speed and directino of a rotating object. -Imagine the train scenario but on a circular track. - -The specific angular momentum is the angular momentum of an object, divided by it's mass. -It kind of tells us which property is more prevalent in the momentum, the mass or the speed: for the same angular momentum, a high *specific* angular momentum means our object is small and moves fast, while for a small *specific* angular momentum out object is large and moves slowly. - -In our case a light "particle" is being pulled by a stationary object of large mass (a Shwarzschild black hole), so rather than finding the angular momentum[^angular-momentum] and then dividing by the mass[^light-has-no-mass], we'll use another formula: - -![](./img/specific-angular-momentum-wikipedia.png) - -where **in this specific formula only** `r` is the vector from the center of the big mass (the singularity of the black hole) to the light "particle" and `v` is the velocity (direction and amount of speed) the light is travelling with. - -The cross product returns a vector, so we'll need to take the magnitutde of the result and plug that into the formula. -It's also important that **we calculate it only once, in the beginning**. -So, we shouldn't be calculating the magnitude of the specific angular momentum every time the light "particle" is moved, rather we calculate it once, after it gets close enough to be affected by the black hole. - -r^ is the vector from the center of the black hole to the light particle as a [unit](https://en.wikipedia.org/wiki/Unit_vector) vector (hence the `^` on top). - -This means that we normalize the vector, meaning divide it by it's magnitude (length): - -![](./img/normalize-vector-wikipedia.png) - -Finally, putting all needed variables together in one formula, we get: +This force vector specifies how much and in what direction exactly the black hole is pulling on the corpiscule. + +Although the function takes in only one argument, `r`, that doesn't mean that `h` and r\^ aren't also arguments: + +- `r` is the distance from the center of the black hole (the singularity) to the **current** position of the corpiscule. + +- `h` is the magnitude of the ["specific angular momentum"](https://en.wikipedia.org/wiki/Specific_angular_momentum) of the light "particle". + + "Normal" linear momentum specifies how much "force" at what speed it takes to stop (or change) the speed and direction of an object in linear motion (that's why it's in kg\*m/s). + Imagine a big heavy train on a perfectly straight rails going at a fast speed. + How do you forcefully stop it? + + You can put a *really* heavy barrier on the tracks, in front of the train. + Since the train is moving at a really great speed, this barrier will have to be much much heavier (with much more mass) than the train itself. + + Alternatively, you can "launch" something against the train, meaning you can put a second train, moving in the opposite direction of the first train, so they hit head-on. + Since the second train would also be moving, if it's travelling at the same speed and has the same mass as the first train, when they hit they would both stop. + If the second travells at twice the speed, then it can have half of the mass of the first to produce the same effect. + + The property with which we can "prove" why both a larger mass at no speed, and a smaller mass at a faster speed, can stop the train, is the momentum. + + Angular momentum specifies how much "force" at what speed it takes to stop (or change) the speed and directino of a rotating object. + Imagine the train scenario but on a circular track. + + The specific angular momentum is the angular momentum of an object, divided by it's mass. + It's magnitude kind of tells us which property is more prevalent in the momentum, the mass or the speed. + For the same angular momentum, a long (big magnitutde) *specific* angular momentum means our object is small and moves fast, while for a short (small magnitutde) *specific* angular momentum out object is large and moves slowly. + + In our case a light "particle" is being pulled by a stationary object of large mass (a Shwarzschild black hole), so rather than finding the angular momentum[^angular-momentum] and then dividing by the mass[^light-has-no-mass], we'll use another formula: + + ![](./img/specific-angular-momentum-wikipedia.png) + + where **in this specific formula only** `r` is the vector from the center of the big mass (the singularity of the black hole) to the light "particle" and `v` is the velocity (direction and amount of speed) the light is travelling with. + + The cross product returns a vector, so we'll need to take the magnitutde of the result and plug that into the formula. + It's also important that **we calculate it only once, in the beginning**. + So, we shouldn't be calculating the magnitude of the specific angular momentum every time the light "particle" is moved, rather we calculate it once, after it gets close enough to be affected by the black hole. + +- r^ is the normalized ([unit](https://en.wikipedia.org/wiki/Unit_vector), hence the `^` on top) vector from the center of the black hole to the light particle: + + ![](./img/normalize-vector-wikipedia.png) + +Finally, putting all needed variables together in one proper function, we get: ![](./img/variables-expanded.png) -where velocity of light "particle" means a vector, with the direction in which the light "particle" will travel, and a magnitude equal to the distance (speed) the light "particle" will travel in. As you may notice, this can be simplified, if we substitude r^: ![](./img/antonelli-formula-expanded.png) +In effect, we pass the distance from the black hole to the corpiscule and the function returns how light's velocity changes. + Finally, we know what to give the formula, and what it will return. -Current question is: how do we use it's output? +The task at hand is making an algorithm which utilises it. For that we'll need to get familiar with black holes. -### Explaning black holes +### Properties of a black hole + +We'll be working with non-rotating stationary black holes, since those are the simplest and provide perfectly useable results. + +From the [no-hair conjecture](https://en.wikipedia.org/wiki/No-hair_theorem) we know that a stationary black hole Physics regards black holes as an infinitessimal (infinitely small) point with some huge amount of mass. From the mass we can derive three radii, which will be the backbone of our black hole: the event horizon, the photon sphere and [ISCO](https://en.wikipedia.org/wiki/Innermost_stable_circular_orbit). @@ -234,6 +265,7 @@ Putting them all together, we should expect light to travel like this: ![](https://upload.wikimedia.org/wikipedia/commons/2/27/Black_Hole_Shadow.gif) *Animation by Hugo Spinelli on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=138168679)* + ### Putting everything together Finally, now we have everything we need to divise an algorithm for our light. @@ -256,6 +288,7 @@ An algorithm doing this would look a bit like this (in pseudocode, inspired by P \begin{align*} & p_{cbh} = \text{position of center of black hole}\\ & r_s = \text{Schwarzchild distance from } p_{cbn} \\ +& r_{ps} = \frac{2}{3}r_s \quad \text{(photon sphere)}\\ & r_{ISCO} = 3 r_s \\ \\ & p_l = \text{position of light "particle"}\\ @@ -264,9 +297,12 @@ An algorithm doing this would look a bit like this (in pseudocode, inspired by P & r_l = \| p_l-p_{cbh} \| \quad \text{(distance between black hole and light)}\\ & \text{If } r_l \leq r_{ISCO} : \\ & \quad h = \| r_l \cross v_l \|\\ -& \quad \text{Do maximum 100 times}:\\ -& \qquad \text{If } r_l < r_s : \\ +& \quad \text{LightMovesLimit} = \infty \\ +& \quad \text{Repeat maximum LightMovesLimit times}:\\ +& \qquad \text{If } r_l \leq r_s : \\ & \qquad \quad \text{return "Light never escapes"} \\ +& \qquad \text{If } r_l \leq r_{ps} : \\ +& \qquad \quad \text{LightMovesLimit} = 100 \\ & \qquad \text{If } r_l > r_{ISCO} : \\ & \qquad \quad \text{return "Light escaped black hole"} \\ & \qquad p_l = p_l + v_l \quad \text{(move light)}\\ @@ -283,6 +319,7 @@ as a reminder, here is the definiton of F→: ![](./img/antonelli-formula-expanded.png) [^parallels-of-latitude]: You might think about the latituginal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest. +[^geodesics-are-local]: This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purpopses. More info can be found on [wikipedia](https://en.wikipedia.org/wiki/Geodesic#Introduction). [^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](TODO) is zero. These are way outside of my understanding and our purposes, so I skiped them for simplicity. [^isco]: It's not really true that gravity stopps affecting spacetime after the ISCO, even though things can orbit Earth that doesn't mean that Earth doesn't bend spacetime. However, for the purposes of a simple shader, this assumption produces perfectly useable results. [^angular-momentum]: Angular momentum is actually [defined using the cross product](https://en.wikipedia.org/wiki/Specific_angular_momentum#Definition) -- cgit v1.3.1-26-gb76a From c2f3a63ed8da8490071972c8fd9d34be35d34b48 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sun, 24 Dec 2023 21:09:30 +0200 Subject: (blog/bhs) Added contents, pretty major rewording and restructuring, put LaTeX source in appendix --- .../index.md | 235 +++++++++++++-------- 1 file changed, 143 insertions(+), 92 deletions(-) (limited to 'src') diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/index.md b/src/blog/difficulties-of-making-a-black-hole-shader/index.md index b142f99..17304c6 100644 --- a/src/blog/difficulties-of-making-a-black-hole-shader/index.md +++ b/src/blog/difficulties-of-making-a-black-hole-shader/index.md @@ -2,12 +2,26 @@ ## Contents +1. [Preface](#preface) + 1. [Brief introduction to computer graphics](#brief-introduction-to-computer-graphics) + 2. [Brief introduction to WebGL](#brief-introduction-to-webgl) +2. [Theoretical and algorithmic background](#theoretical-and-algorithmic-background) + 1. [What is a black hole](#what-is-a-black-hole) + 2. [Geodesics, gravity and gravitational lensing](#geodesics-gravity-and-gravitational-lensing) + 3. [Finding a formula](#finding-a-formula) + 4. [Applying the formula to "bend" light's path](#applying-the-formula-to-bend-lights-path) + 5. [Properties of a black hole](#properties-of-a-black-hole) + 6. [Putting everything together](#putting-everything-together) +3. [WebGL preparation](#webgl-preparation) +4. [Shader](#shader) +5. [Appendix](#appendix) + Back in August I had to submit a project for an elective WebGL programming course in university. I chose to create an interractive and animated black hole demo. The primary idea was to show how the gravitational pull of black holes "bend" light and how the result looks from different points of view. During development I found a lot of hurdles, primarily with the actual mathematics behind it. -Information online is difficult to parse and understand if you don't have a physics background, so I'll try my best to lay out everything I know. +Information online is difficult to find and understand if you don't have a physics background, so I'll try my best to lay out everything I know. I'll assume you don't know much about physics, but are familiar with mathematics and at the very least vectors. @@ -16,10 +30,10 @@ I'll assume you don't know much about physics, but are familiar with mathematics ### Brief introduction to computer graphics Image and video files store visual information in a "fixed" way: you get a huge array of colors, each connected to a particular pixel on your screen. -The objects in those mediums cannot be modified easily, and additions or subtractions are even harder to do, usually requiring an expert using a professional tools for hours, days, weeks or months on end. +The objects in those mediums cannot be modified easily, and additions or subtractions are even harder to do, usually requiring an expert using professional tools for hours, days or weeks on end. Computer graphics aims to offload a lot of the creator's workload by "generating" the images on the fly using a set of descriptions for our objects. -The idea is to define objects with some simpler geometric figures, then give those to the computer, which will in turn have to calculate what the precise color of every pixel in the resultant image should be. +The idea is to define objects with some the primary properties of simpler geometric figures, like the points on a triangle, then give those to the computer, which will in turn have to calculate what the precise color of every pixel in the resultant image should be. For example, we can represent a tin can (without a label) as a simple cyllinder. Changing it's height or width is trivial: just change the corresponding property you pass to the computer, and it will handle the rest. @@ -32,9 +46,9 @@ Expanding on out tin can example, if you want an image with a tin can up close, ![](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Empty_tin_can2009-01-19.jpg/514px-Empty_tin_can2009-01-19.jpg) *Image by Sun Ladder on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=5746428)* -Such an image contains way way too much detail the average computer to handle in reasonable time (some small fraction of a second). +Such an image contains way way too much detail for the average computer to handle in reasonable time (some small fraction of a second). However, computer generated graphics are still a very useful tools. -Thats why modern machines come with a processor, handling most tasks like running programs, managing internet traffic, etc. and a graphics card handling *only* graphical tasks. +Thats why modern machines come with a graphics card handling *only* graphical tasks (alongside a processor, handling all other tasks like running programs, managing internet traffic, etc.). A graphics card is a combination of a special processor (GPU), designed to be able to *only* compute stuff related to graphics, with the upside of doing so much much faster than a general purpose processor (CPU) could, and some memory for use exclusively by that GPU. @@ -54,21 +68,34 @@ You would get a DOM object in which the graphics will be rendered, and a "contex ## Theoretical and algorithmic background -Using [Einstein's field equations](TODO), or to simplify our life, [Schwarzschild's metric](TODO), we can precisely calculate the curvatures in space(time) at every point around a massive stationary object, like a non-rotating black hole. -Of course, the computation would still be too laborious, so making an approximation using [celestial mechanics](TODO) and representing light as a particle (corpiscule), we can tame the physics into a simple algorithm. +Using [Einstein's field equations](TODO), or to simplify our life, [Schwarzschild's metric](TODO), we can precisely calculate the curvatures in space(time) at every point around a Schwarzschild black hole. +Unfortunetly, the computation would still be too laborious, so we'll need to make an approximation using [celestial mechanics](TODO). -Of course, there are a lot more details, so let's back up a bit. +That is the overall gist of the underlying physics, but I promised an explanation, so let's back up a bit. ### What is a black hole -A black hole is an object in space, which "collapsed" down to an infinitely small point. -In other words, if you take something with mass (although it's incorrect, you may think of mass as the amount of atoms comprising the object) and compress it into a small enough size, then the forces between the atoms and even subatomic particles will not be strong enough to keep themselves intact and separate. +First, imagine atoms like marbles on a table. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Marbles_from_Indonesia.jpg/1280px-Marbles_from_Indonesia.jpg) +*Image from By Okkisafire on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=30338734)* + +Now, take those marbles and start pushing on them from all sides. +In the beginning, when they are all faraways apart, it won't be very hard, since you only have to move them. +After they are touching each other, you'll find that your push doesn't do anything, the glass will keep the marbles together and just "deal" with your force, until a certain threshold. +When reached, the glass will break, turning the marbles into shards. + +A similar occurence can happen with atoms. +Ignoring what happens to the orbiting electrons, by pushing atoms together, you reach a certain point where all of the nuclei are "touching". +Then, the [nuclear force](https://en.wikipedia.org/wiki/Nuclear_force) will try and keep those nuclei together, but if you push hard enough, then you can overcome it, and "shatter" the nucleus into it's subatomic particles. -You can think of atoms like magnetic marbles, all marbles are separated with empty space (due to the magnet force), so if you push on them, you can compress them so they get closer together. -However, you can continue pushing them together, after enough forces, they'll all start deforming into a small really dense block of metal. +But in the same way you can continue compressing the shards until they break and turn into glass granules, you can continue compressing those subatomic particles. +At a certain point, what breaks, is physics. +After that certain threshold all atomic and "subatomic" "forces" will be overcame and nothing will be able to hold matter "together"[^matter-together]. -Outside analogies, keep in mind that this infinitessimal point has the same initial mass as the object which collapsed. -This has great consequences on gravity, but what is gravity anyway? +The result is a "collapse", all of that matter just "deflates" into a single, infinetly small point. +That's called a **black hole** (keep in mind that this infinitessimal point has the same initial mass as the object which collapsed). +It doesn't affect many stuff in the universe, but the effect on gravity is the most special one. ### Geodesics, gravity and gravitational lensing @@ -79,16 +106,16 @@ If you then extend that segment, so it has an infinite length, it becomes a line However, what if our surface isn't flat? Imagine two points on a sphere, what is the shortest distance between them? -You might be inclined to say that's also a "straight" line, but it really isn't: it's an arc of a circle! +You might be inclined to say that's also a "straight" line, but it really isn't: it's an arc of a circle. ![](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Illustration_of_great-circle_distance.svg/480px-Illustration_of_great-circle_distance.svg.png) -[*Image by CheCheDaWaff on Wikipedia*](https://commons.wikimedia.org/w/index.php?curid=48187293) +*Image by CheCheDaWaff on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=48187293)* This circle is called a [great circle](https://en.wikipedia.org/wiki/Great_circle). The main problem with calling this arc a "spherical line segment" (and the great circle a "spherical line" or something similar) is that both objects have different properties. Looking at all possible great circles, we find that their center (and radius) matches with the center (and radius) of the sphere. -From this we can find the bigest difference: lines can be parallel, but great circles cannot. +From this we can extrapolate that lines can be parallel, but great circles cannot. A line is an extended segment, so if you extend two different arcs (which are the shortest distance between two pairs of points on the sphere) and get the great circles, those will always intersect[^parallels-of-latitude]. Therefore, the general term for the shortest path between two points on a non-flat surface is (kind of) called a geodesic[^geodesics-are-local] (the arc on the sphere is a geodesic). @@ -98,10 +125,13 @@ Going back to physics, what the General theory of relativity tells us is that ob As a result, the geodesics too are curved, so even though you may be always moving forwards at the same speed, to an outside observer it will look like you turn and change speed. The amount by which and the size of the area which is affected depend on that object's mass and size. -Generally, if two objects have the same mass, the bigger one will bend less a larger portion of space, compared to the smaller one, which will bend a lot the smaller portion of space. +Generally, if two objects have the same mass, the bigger one will affect a larger portion of space, but will bend it less, compared to the smaller one, which will affect a smaller portion, which will be bend a lot. -Since a black hole is a single infinetly small point, then all of it's mass is concentrated on that point, making a really really **really** strong bend in a small (compared to a non-blackhole object with the same mass) area. -Strong enough in fact, that if you get too close, you will not be able to overwhelm gravity and "merge" into that infinitessimal point. +Since a black hole is a single infinetly small point, then all of it's mass is concentrated on that point, making it bend a relatively small are of space **a lot**. +Strong enough in fact, that if you get too close, you will not be able to overwhelm gravity and "merge" into that infinitessimal point (the white lines are our "geodesics"): + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/CNX_UPhysics_13_07_spacetime.png/800px-CNX_UPhysics_13_07_spacetime.png?20171124170318) +*Image by OpenStax University Physics on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=64307901)* An interesting effect from gravity is that light (which always travells "forwards", so along a geodesic) also gets "bent", allowing an observer to view otherwise obstructed objects. We call that [graviational lensing](TODO). @@ -110,17 +140,22 @@ Though not unique to black holes, thats when the effect is strongest: ![](https://upload.wikimedia.org/wikipedia/commons/0/02/Gravitational_lens-full.jpg) *(notice how the gray arrows show the path light travels from a galaxy that is behind (obstructed by) the black hole)* -The distinction that gravity doesn't change the direction or speed of an object "directly" (preserving the speed for light rays) is at upmost importance for physics. +I'll abstrain from explaining light, but you may think of it as a small particle, "similar" to an electron, travelling through space. +In fact, Newton understood light to be just that, and called the underlying particle a "corpiscule". +For our purpopses, this approximation will serve us well. + +The distinction that gravity doesn't change the direction or speed of an object "directly" is at upmost importance for physics, since this way we preserve two very important properties of light: it's constant speed and straight travelling path. However, in our simulation, it would be significantly simpler to assume the opposite, since to an outside observer (like the "player") the difference is indistinguishable. -Therefore, we would need to make some modifications to the proper physics equations. + +Therefore, in our simulation, we'll have light rays, but when they approach a black hole, their speed and direction would change. +This will be determined by some physics equations. ### Finding a formula Now, how do we calculate the exact curvature a black hole produces? General theory of relativity provides us with the (really complicated) [Einstein field equations](https://en.wikipedia.org/wiki/Einstein_field_equations) for this exact problem. [Schwartzschild](TODO) solved these equations, assuming that the body with mass doesn't spin[^schwm-assumptions]. -This solution is called the [Schwarzschild metric](https://en.wikipedia.org/wiki/Schwarzschild_metric). -A black hole for which this (these) assumption is true is called a "Shwartzschild black hole". +This solution is called the [Schwarzschild metric](https://en.wikipedia.org/wiki/Schwarzschild_metric), and a black hole for which this assumption is true is called a "Shwartzschild black hole". The Shwarzschild black hole is the symplest of it's type, so using the Schwarzschild metric should give us the least trouble. Now, here is the metric in Schwartzschild coordinates: @@ -138,15 +173,15 @@ Thankfully [Riccardo Antonelli](http://rantonels.github.io/starless/) was able t ![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png) -Question now is: how do we use it? +I will not be trying to explain why or how the Schwarzschild metric and this formula work, that's way way beyond my elementary understanding and the scope of this post. + +Question now is: what do all of those letters represent? This turned out to be a much harder problem than it should have, I actually had to refer [Ricardo Antonelli's](https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py) and [Dmitry Brant's](https://dmitrybrant.com/2018/12/11/ray-tracing-black-holes) implementation in their projects, alongside copus articles on wikipedia to fully grasp how to put it to work. ### Applying the formula to "bend" light's path -First, how are we going to represent light? -The simplest way is to think of light as a small particle (which Newton called "corpiscule") travelling through space. -We'll move our particle by a tiny amount in a certain direction, then update the direction, accounting for gravity, and then repeat. -The direction, alongside the amount by which the particle moves can be represented with a single vector, which we'll call light's "velocity". +Our plan for simulating gravitational lensing is to move the corpiscule by a tiny amount in a certain direction by a certain amount, update the direction and amount according to gravity, rince and repeat. +The direction, alongside the amount by which the particle moves, can be represented with a single vector, which we'll call light's "velocity". Referring to the formula again: @@ -156,9 +191,9 @@ The F→ returns a force vector (`F` for "force" and Imagine you are pushing a box: you are applying some force to it in a "forward" direction. If you pull the box, you'll apply some force in a "backward" direction. -This force vector specifies how much and in what direction exactly the black hole is pulling on the corpiscule. +This force vector conveys how much and in what direction exactly the black hole is "pulling" on the corpiscule. -Although the function takes in only one argument, `r`, that doesn't mean that `h` and r\^ aren't also arguments: +Although the function takes in only one argument, `r`, that doesn't mean that `h` or r\^ aren't also arguments: - `r` is the distance from the center of the black hole (the singularity) to the **current** position of the corpiscule. @@ -172,7 +207,7 @@ Although the function takes in only one argument, `r`, that doesn't mean that `h Since the train is moving at a really great speed, this barrier will have to be much much heavier (with much more mass) than the train itself. Alternatively, you can "launch" something against the train, meaning you can put a second train, moving in the opposite direction of the first train, so they hit head-on. - Since the second train would also be moving, if it's travelling at the same speed and has the same mass as the first train, when they hit they would both stop. + Since the second train would also be moving, if it's travelling at the same speed and has the same mass as the first train, upon collision they would both stop[^hitting-trains]. If the second travells at twice the speed, then it can have half of the mass of the first to produce the same effect. The property with which we can "prove" why both a larger mass at no speed, and a smaller mass at a faster speed, can stop the train, is the momentum. @@ -200,62 +235,41 @@ Although the function takes in only one argument, `r`, that doesn't mean that `h Finally, putting all needed variables together in one proper function, we get: - -![](./img/variables-expanded.png) +![Refer to "Antonelli’s formula - explained" in the Appendix](./img/variables-expanded.png) As you may notice, this can be simplified, if we substitude r^: - -![](./img/antonelli-formula-expanded.png) +![Refer to "Antonelli’s formula - simplified" in the Appendix](./img/antonelli-formula-expanded.png) In effect, we pass the distance from the black hole to the corpiscule and the function returns how light's velocity changes. Finally, we know what to give the formula, and what it will return. The task at hand is making an algorithm which utilises it. -For that we'll need to get familiar with black holes. +For that we'll need to get even more familiar with black holes. ### Properties of a black hole -We'll be working with non-rotating stationary black holes, since those are the simplest and provide perfectly useable results. - -From the [no-hair conjecture](https://en.wikipedia.org/wiki/No-hair_theorem) we know that a stationary black hole +As stated, we'll be working with non-rotating stationary black holes, Schwarzschild black holes. +From the [no-hair conjecture](https://en.wikipedia.org/wiki/No-hair_theorem) we know that such a black hole has only three distinct properties: mass, electric charge and angular momentum. +The last one doesn't apply for our case, and the second is irrelevant. -Physics regards black holes as an infinitessimal (infinitely small) point with some huge amount of mass. -From the mass we can derive three radii, which will be the backbone of our black hole: the event horizon, the photon sphere and [ISCO](https://en.wikipedia.org/wiki/Innermost_stable_circular_orbit). +Meaning, from the mass alone, we can derive the gravitational "forces", alongside three radii, which will be the backbone of our black hole: the event horizon, the photon sphere and [ISCO](https://en.wikipedia.org/wiki/Innermost_stable_circular_orbit). -The event horizon, also called the Schwarzschild radius, is the distance from the center of the black hole (singularity), which once passed, cannot be escaped. -In other words, once something gets too close, and passes this distance, then it cannot ever escape, even if it's light. +The event horizon, also called the Schwarzschild radius, is the distance from the center of the black hole (singularity), which once passed, cannot be passed again (you cannot escape the black hole). The formula for it is: -![](./img/Schwarzschild-radius-wikipedia.png) +![r_s = (2GM)/(c^2)](./img/Schwarzschild-radius-wikipedia.png) where `G` is the [gravitational constant](https://en.wikipedia.org/wiki/Gravitational_constant) and `M` is the mass of the black hole (in kg). The photon sphere is the distance from the singularity, in which photons start orbiting the black hole (and can either escape or pass the event horizon). Formula: -![](./img/photon-sphere-wikipedia.png) +![r = r_s * 3/2](./img/photon-sphere-wikipedia.png) where `G` and `M` are the same as before, `c` is the speed of light in vacuum and rs is the afroementioned Schwarzschild radius. -Finally, the innermost stable circular orbit (ISCO), officially it's the distance, before which you can orbit the black hole, but once passed, you'll get sucked in and either get shot out or forever lost past the event horizon. +Finally, the innermost stable circular orbit (ISCO), formally it's the distance, before which you can orbit the black hole, but once passed, you'll get sucked in and either get shot out or be forever lost past the event horizon. For our purposes, it's fine to approximate it as the maximum radius after which spacetime isn't bent[^isco] and objects aren't affected. Formula: @@ -284,39 +298,76 @@ The simplest way to "track" this is just to limit how many times we can move the An algorithm doing this would look a bit like this (in pseudocode, inspired by Python): - +``` -![](./img/algorithm.png) +###### Antonelli's formula - simplified -as a reminder, here is the definiton of F→: +```latex +\begin{align*} + & \overrightarrow{F}(r_l,h) = -\frac{3}{2} \; h^2 \; \frac{r_l}{\|r_l\|^6} \quad \text{, where}\\ + & h = \|r_l \cross v_l\| \text{ (calculated right before being affected by black hole)}\\ + & \|x\| = \text{magnitude of }x\\ + & r_l = \text{vector from black hole center to light "particle"}\\ + & v_l = \text{velocity of light "particle"} +\end{align*} +``` -![](./img/antonelli-formula-expanded.png) +###### Algorithm + +```latex +\begin{align*} + & p_{cbh} = \text{position of center of black hole}\\ + & r_s = \text{Schwarzchild distance from } p_{cbn} \\ + & r_{ps} = \frac{2}{3}r_s \quad \text{(photon sphere)}\\ + & r_{ISCO} = 3 r_s \\ + \\ + & p_l = \text{position of light "particle"}\\ + & v_l = \text{velocity of light "particle"}\\ + \\ + & r_l = \| p_l-p_{cbh} \| \quad \text{(distance between black hole and light)}\\ + & \text{If } r_l \leq r_{ISCO} : \\ + & \quad h = \| r_l \cross v_l \|\\ + & \quad \text{LightMovesLimit} = \infty \\ + & \quad \text{Repeat maximum LightMovesLimit times}:\\ + & \qquad \text{If } r_l \leq r_s : \\ + & \qquad \quad \text{return "Light never escapes"} \\ + & \qquad \text{If } r_l \leq r_{ps} : \\ + & \qquad \quad \text{LightMovesLimit} = 100 \\ + & \qquad \text{If } r_l > r_{ISCO} : \\ + & \qquad \quad \text{return "Light escaped black hole"} \\ + & \qquad p_l = p_l + v_l \quad \text{(move light)}\\ + & \qquad r_l = \| p_l-p_{cbh} \| \quad \text{(update distance to $p_{cbh}$)}\\ + & \qquad v_l = v_l + \overrightarrow{F}(r_l,h) \quad \text{(update light velocity)} \\ + & \quad \text{return "Light stuck in photon sphere, never escapes"} +\end{align*} +``` [^parallels-of-latitude]: You might think about the latituginal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest. [^geodesics-are-local]: This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purpopses. More info can be found on [wikipedia](https://en.wikipedia.org/wiki/Geodesic#Introduction). -- cgit v1.3.1-26-gb76a From 29090187820c880e3f712a18d66482c4a7fd9ff5 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Tue, 26 Dec 2023 17:48:36 +0200 Subject: (blog/bhs) Added initial contents of webgl and shaders sections --- .../index.md | 159 ++++++++++++++++++++- 1 file changed, 156 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/index.md b/src/blog/difficulties-of-making-a-black-hole-shader/index.md index 17304c6..70c711e 100644 --- a/src/blog/difficulties-of-making-a-black-hole-shader/index.md +++ b/src/blog/difficulties-of-making-a-black-hole-shader/index.md @@ -18,7 +18,7 @@ Back in August I had to submit a project for an elective WebGL programming course in university. I chose to create an interractive and animated black hole demo. -The primary idea was to show how the gravitational pull of black holes "bend" light and how the result looks from different points of view. +The primary idea was to show how the gravitational pull of black holes "bends" light and how the result looks from different points of view. During development I found a lot of hurdles, primarily with the actual mathematics behind it. Information online is difficult to find and understand if you don't have a physics background, so I'll try my best to lay out everything I know. @@ -33,7 +33,7 @@ Image and video files store visual information in a "fixed" way: you get a huge The objects in those mediums cannot be modified easily, and additions or subtractions are even harder to do, usually requiring an expert using professional tools for hours, days or weeks on end. Computer graphics aims to offload a lot of the creator's workload by "generating" the images on the fly using a set of descriptions for our objects. -The idea is to define objects with some the primary properties of simpler geometric figures, like the points on a triangle, then give those to the computer, which will in turn have to calculate what the precise color of every pixel in the resultant image should be. +The idea is to define objects with some primary properties of simpler geometric figures, like the points on a triangle, then give those to the computer, which will in turn have to calculate what the precise color of every pixel in the resultant image should be. For example, we can represent a tin can (without a label) as a simple cyllinder. Changing it's height or width is trivial: just change the corresponding property you pass to the computer, and it will handle the rest. @@ -68,6 +68,9 @@ You would get a DOM object in which the graphics will be rendered, and a "contex ## Theoretical and algorithmic background +&&important I haven't formally studied physics, so you must read with scepticism in mind. + There are most definetly errors, steming from my lackluster understanding of the subject. + Using [Einstein's field equations](TODO), or to simplify our life, [Schwarzschild's metric](TODO), we can precisely calculate the curvatures in space(time) at every point around a Schwarzschild black hole. Unfortunetly, the computation would still be too laborious, so we'll need to make an approximation using [celestial mechanics](TODO). @@ -124,6 +127,10 @@ We can now also define what it means to "go straight forwards": in flat surfaces Going back to physics, what the General theory of relativity tells us is that objects with mass bend the physical space, or 3D surface, of the universe, and we call that gravity. As a result, the geodesics too are curved, so even though you may be always moving forwards at the same speed, to an outside observer it will look like you turn and change speed. +The explanation for modified speed is simpler: since we are travelling at the same speed, from the point of view of an outside observer, it should take the same amount of time to go between points P and Q, regardless of gravity. +However, a normal straight line segment through the points is always shorter than the gravitationally-induced circular arc, meaning it will look like you are travelling a greater distance. +The only way to balance everything out, is to travel faster. + The amount by which and the size of the area which is affected depend on that object's mass and size. Generally, if two objects have the same mass, the bigger one will affect a larger portion of space, but will bend it less, compared to the smaller one, which will affect a smaller portion, which will be bend a lot. @@ -306,7 +313,151 @@ as a reminder, here is the definiton of F→: ## WebGL preparation -## Shader +The course was focused on handmade solutions, so some of the logic uses a [custom handmade library](TODO). + +Since the primary component was the shader itself, I made sure to simplify my logic to the absolute minimum. +A **lot** of decisions were made to optimize development time, without considering how good they were. + +In a scene there really are only 3 distinct objects: the stars, the black holes and the skybox. +The latter is just a simple cube, inside which everything resides, if a ray doesn't hit anything of interest, it will hit the cube. +Both stars and black holes are simple spheres, the former with an orange-y color (#f4803b) and any radious. +Black holes aren't rendered and their underlying sphere has the same radius as the ISCO, so their purpose is for intersection checks (more on those when we get to the [shaders](#shaders)). + +Most JavaScript code isn't worth talking about, wherever possible I use the [course library](TODO) and where I can't it's mostly simple WebGL configurations, elementary object "classes" and trivial HTML handling. +Though, there are still two somewhat interesting systems: + +### Scenes + +I wanted to have multiple scenes, with different arrangements of objects and with animations (stars moving around). +For that I devised a dead-simple level loading and animation system. + +An object of type "Level" stores a name, description, location of camera (the viewer) and arrays for stars, black holes and animations. +Though, for creating new levels, you only pass the first three: + +```javascript +var level1 = new Level( + "Star passing behind black hole", // Level title + "The black hole warps the light", // Level description + [1000,0,650]); // Initial coordinates of camera +``` + +Adding stars or black holes requires going through two member functions: `addStar` and `addBlackHole`. +Both take the center of the object, as well as it's radius, alongside an animation function. +The latter has two parameters: current time in TODO(seconds,milliseconds,?) from the beginning and the current object that will be created. +This function is called on each frame with the appropriate arguments, so inside you'll have to "manually" modify the object's properties. + +For example, a simple star going forwards could be added like this (`vecSum` is just [componentwise vector summation](TODO)): + +```javascript +level1.addStar([1070,0,1000], // Coordinates of center + 10, // Radius + (t, star) => vecSum(star.center, [-t,0,0])); // Move from left to right +``` + +Or one which rotates around a point: + +```javascript +var speed = Math.PI / 20, rad = 40; +level1.addStar([1000+rad,0,900], + 3, + (t, star) => vecSum([1000,0,900], [Math.cos(t*speed) * rad, + Math.sin(t*speed) * 5, + Math.sin(t*speed) * rad])); +``` + +For black holes it's the same. +If you want the object to not move, you could just pass `undefined` as the function: + +```javascript +level1.addBlackHole([1000,0,900], 30, undefined); +``` + +### Movement + +It wouldn't be fun without the ability to move around in the scene, so I added a simple system for that too. +WASD moves the camera position forward, left, backward and right, shift moves down and space moves up, all relative to the current direction the camera is looking towards. +Those are all done with relatively simple analytic geometry: we store three vectors, one pointing up, one pointing forward and one pointing left (which can be calculated from the other two with a cross product). +To move forward, add to the position the forward vector times some constant, to move backwards subtract and so on. + +Looking around with the mouse was kinda tricky, since I decided to use [spherical coordinates](TODO). +You store two angles, the "up" and "left" angle, moving the mouse forwards adds to the "up" angle, moving it downwards subtracts and so on. +The tricky part was what to do after + +TODO + +## Shaders + +As a gentle reminder, in OpenGL we have a vertex shader and a fragment shader: + +- The vertex shader is ran on every point of every object in our scene +- The fragment shader is ran on every pixel of your screen, with the added bonus that depending on the pixel, certain values are passed down from the vertex shader. + + This includes interpolated points: a line is made up of two points, the vertex shader is ran on both of them, then the line is interpolated and the fragment shader is ran on each pixel, corresponding to a point on the line. + The vertex shader values are also passed down interpolated, so if one end of the line is the color red, while the other end is green, then the fragment shader corresponding to the pixel, which shows the middle of the line, will have the color yellow. + +### Vertex shader + +As already mentioned, black holes aren't rendered, so the only objects with special rendering are the stars. +To simplify my life, I chose to do a simple [diffusion reflection](https://learnopengl.com/Lighting/Basic-Lighting), with the light source emminating from the camera, something which was already made in lectures: + +![](TODO) + +The result isn't amazing, but you can clearly make out the sphere as a 3D object (not a flat circle). + +### Fragment shader + +This is the meat of our logic, this is where we'll implement our algorithm: + +![](./img/algorithm.png) + +In real life, every star emits light, which then travells some distance, until it reaches our eyes. +However, computing it this way is incredibly inefficient, for every star we'll have to create hundreds or thousands of light rays (corpiscules), most of which probably wont reach us. +We want performance, so this is a no-go. + +The alternative is to do the opposite, assume every pixel was hit by a "ray" and trace back it's steps, if it came out of a star then it has some specific color (it was an actual ray), but if it didn't then show it as black (no ray hit us). +Taking it further, how do we "trace back" those steps? +Well, we can find the precise coordinate of every pixel inside the 3D scene, and move each point in the direction we're looking (though this image is about raytracing, just look at the two top red vectors): + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Ray_trace_diagram.png/800px-Ray_trace_diagram.png?20080214101526) +*Image by Timrb on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=3553478)* + +In the context of computer graphics, this is called [ray marching](TODO). + +Now, how do we detect if the ray hit something? +The dumb way is to move the ray forward a bit and check with every object whether the ray intersects it. +However, since all of our objects are spheres, there is a very easy optimization and simplification - imagine the ray as an infinitely long line and just get the shortest (perpendicular) distance between it and the center of the sphere: + +TODO custom image #1 + +For this we can implement a simple distance function: + +![](https://wikimedia.org/api/rest_v1/media/math/render/svg/42c53741fd3d8765e56ea652369a512a2cd09eac) + +```glsl +float linePointDistance(vec3 a, vec3 n, vec3 p) { + return length((p - a) - dot(p - a, n) * n); +} +``` + +Where `a` is the coordinate of our ray (pixel), `n` is the direction it will be travelling in and `p` is the sphere center we're comparing with. + +However, there is a huge problem: our line extends in both directions, so a check like `linePointDistance(ray, step, center) <= radius` would also detect if the ray interects the point behind us (when ray is going in the opposite direction)! +A very simple solution is to just add a sign to our distance: if positive then the distance is in reference to a point in front, while negative means it's behind. +The simplest way to get this information is by taking the [dot product](TODO) between our "forwards" direction and the direction from our coordinates to the [projection](TODO) of our point on the line: + +TODO custom image #2 + +```glsl +float linePointDistance(vec3 a, vec3 n, vec3 p) { + vec3 projection = dot(p - a, n) * n; + float dist = length((p - a) - projection); + + if (dot(projection, n) < 0.0) return -dist; + return dist; +} +``` + +Since all of our objects are spheres, we can just iterate through all of them and do this check. ## Appendix @@ -369,9 +520,11 @@ The images for my custom LaTeX equations were created on [latexeditor.lagrida.co \end{align*} ``` +[^matter-together]: Technically, it's more accurate to say "matter apart", since after the collapse matter is as close together as physically possible, and the nuclear forces keep everything in order but also separated. However, considering the intuitive approach I'm striving for, "matter together" is simpler to understand. [^parallels-of-latitude]: You might think about the latituginal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest. [^geodesics-are-local]: This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purpopses. More info can be found on [wikipedia](https://en.wikipedia.org/wiki/Geodesic#Introduction). [^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](TODO) is zero. These are way outside of my understanding and our purposes, so I skiped them for simplicity. [^isco]: It's not really true that gravity stopps affecting spacetime after the ISCO, even though things can orbit Earth that doesn't mean that Earth doesn't bend spacetime. However, for the purposes of a simple shader, this assumption produces perfectly useable results. +[^hitting-trains]: Of course, I'm asuming the trains are strong enough they won't break upon the collision. [^angular-momentum]: Angular momentum is actually [defined using the cross product](https://en.wikipedia.org/wiki/Specific_angular_momentum#Definition) [^light-has-no-mass]: Actually, light has no mass, so this version of the formula wouldn't work. You might think that makes no sense, since we cannot divide by zero, so the specific angular momentum shouldn't exist, but then with the cross product we find a value for it. You would be correct: Antonelli does some funky approximations, combining Newtonian physics with General theory of relativity, to make the formula that simple. Someone in physics will probably vomit looking at it, but for our purposes it's more than perfect. -- cgit v1.3.1-26-gb76a From be9b4ce5c12d140f656c28389d1913f240aa781b Mon Sep 17 00:00:00 2001 From: Syndamia Date: Thu, 15 Feb 2024 18:52:04 +0200 Subject: (blog/bhs) Rewording and simplifications --- .../index.md | 76 +++++++++++++--------- 1 file changed, 45 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/index.md b/src/blog/difficulties-of-making-a-black-hole-shader/index.md index 70c711e..555744a 100644 --- a/src/blog/difficulties-of-making-a-black-hole-shader/index.md +++ b/src/blog/difficulties-of-making-a-black-hole-shader/index.md @@ -21,7 +21,7 @@ I chose to create an interractive and animated black hole demo. The primary idea was to show how the gravitational pull of black holes "bends" light and how the result looks from different points of view. During development I found a lot of hurdles, primarily with the actual mathematics behind it. -Information online is difficult to find and understand if you don't have a physics background, so I'll try my best to lay out everything I know. +Information online is difficult to find and understand without having a physics background, so I'll try my best to lay out everything I know. I'll assume you don't know much about physics, but are familiar with mathematics and at the very least vectors. @@ -68,8 +68,8 @@ You would get a DOM object in which the graphics will be rendered, and a "contex ## Theoretical and algorithmic background -&&important I haven't formally studied physics, so you must read with scepticism in mind. - There are most definetly errors, steming from my lackluster understanding of the subject. +&&important I haven't formally studied physics, so don't fully trust anything here. + There are most definetly errors, steming from my lackluster understanding. Using [Einstein's field equations](TODO), or to simplify our life, [Schwarzschild's metric](TODO), we can precisely calculate the curvatures in space(time) at every point around a Schwarzschild black hole. Unfortunetly, the computation would still be too laborious, so we'll need to make an approximation using [celestial mechanics](TODO). @@ -78,58 +78,72 @@ That is the overall gist of the underlying physics, but I promised an explanatio ### What is a black hole -First, imagine atoms like marbles on a table. +Before we even begin to talk about gravity and light, we need to understand how atoms work. +Imagine a set of marbles, scattered on a table. ![](https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Marbles_from_Indonesia.jpg/1280px-Marbles_from_Indonesia.jpg) *Image from By Okkisafire on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=30338734)* -Now, take those marbles and start pushing on them from all sides. -In the beginning, when they are all faraways apart, it won't be very hard, since you only have to move them. -After they are touching each other, you'll find that your push doesn't do anything, the glass will keep the marbles together and just "deal" with your force, until a certain threshold. -When reached, the glass will break, turning the marbles into shards. +Now, start pushing on all of them from the edges of the table to it's center. +In the beginning, you'll mostly roll them, until they all get in contact with each other. +At that point (assuming they all stay flat on the table), the glass will keep the marbles together, handling your force. -A similar occurence can happen with atoms. -Ignoring what happens to the orbiting electrons, by pushing atoms together, you reach a certain point where all of the nuclei are "touching". -Then, the [nuclear force](https://en.wikipedia.org/wiki/Nuclear_force) will try and keep those nuclei together, but if you push hard enough, then you can overcome it, and "shatter" the nucleus into it's subatomic particles. +By increasing the force with which you push on them, after a certain threshold, the glass will break, turning the marbles into shards. +Those shards will still have some fight in them, so after increasing your force by another level, you'll turn all of those shards into tiny glass granules. -But in the same way you can continue compressing the shards until they break and turn into glass granules, you can continue compressing those subatomic particles. -At a certain point, what breaks, is physics. -After that certain threshold all atomic and "subatomic" "forces" will be overcame and nothing will be able to hold matter "together"[^matter-together]. +A similar occurence happens with atoms. +Normally atoms are spread apart, by pushing them together, at a certain point (ignoring the orbitin electrons) all nuclei will be "touching" and the [nuclar force](TODO) will keep them together. +By increasing your pushing force you can overwhelm the nuclear force and "shatter" the nuclei into their subatomic particles. -The result is a "collapse", all of that matter just "deflates" into a single, infinetly small point. -That's called a **black hole** (keep in mind that this infinitessimal point has the same initial mass as the object which collapsed). -It doesn't affect many stuff in the universe, but the effect on gravity is the most special one. +Assuming an enormus explosion doesn't happen, and you can keep increasing your force, it's also possible to overwhelm the "subatomic forces" that keep those subatomic particles "together"[^matter-together]. +However, those subatomic particles are more commonly referred to as [elementary particles](https://en.wikipedia.org/wiki/Elementary_particle), meaning there are no "granules" into which the elementary particles can break down. +It doesn't make sense if subatomic particles wouldn't be "breakable", since that would require dealing with potentially infinite amounts of force and such an assumption would destroy all of humanity's physics. + +Then that leaves us with only one solution: laws of matter break. +If nothing can keep the elementary particles "together", so keep matter "together", then the result is a sort of "collapse", all of that matter just "deflates" into a single, infinetly small point (but the amount of mass isn't infinite, it's the sum of mass from the particles that collapsed). +That point is called a **black hole**. + +This object is very bizzare, generally it doesn't have too much properties, but the ones it has are really unique. +In my case of computer graphics, the only important part is it's effect on light. ### Geodesics, gravity and gravitational lensing -Think of a flat surface, like a table or a (flat) sheet of paper. +To understand how black holes affect light, we first need to understand how black holes affect gravity. + +Think of a flat surface, like a table. What is the shortest distance between two points? Obviously, that's a straight line segment. If you then extend that segment, so it has an infinite length, it becomes a line. However, what if our surface isn't flat? Imagine two points on a sphere, what is the shortest distance between them? -You might be inclined to say that's also a "straight" line, but it really isn't: it's an arc of a circle. +Obviously, it's an arc of a circle and extending it to it's maximum possible length, we get a [great circle](https://en.wikipedia.org/wiki/Great_circle). ![](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Illustration_of_great-circle_distance.svg/480px-Illustration_of_great-circle_distance.svg.png) *Image by CheCheDaWaff on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=48187293)* -This circle is called a [great circle](https://en.wikipedia.org/wiki/Great_circle). -The main problem with calling this arc a "spherical line segment" (and the great circle a "spherical line" or something similar) is that both objects have different properties. +Now, what does it mean to go "forwards"? +On a flat surface, we can define it as "following a (straight) line segment", on our sphere we can say "following an arc of a great circle". +But what we really need is a more generalized definition, which handles both of our cases (and more). + +That's why in geometry there is the notion of [geodesics](TODO), the generalized curve on any surface which (roughly speaking) is the shortest[^geodesics-are-local] path between any two points. +On a flat surface, that's the line segment, on the sphere it's the great circle arc. +It's important to note that a general geodesic cannot have most properties you might be used to from "the shortest path between two points". +For example, on a flat surface, we can have parallel lines, but on our sphere, great circles will always intersect[^parallels-of-latitude]. + +And there are a lot more complicated surfaces, imagine a flat surface but with half-spherical "trophs" in it, on the flat segments your geodesic would be the line segment, but on those trophs it will be an arc (of a great circle). +Actually, you don't need to imagine: the entire universe is a 3D surface, which is mostly flat, but has sherical-ish "trophs" in it. + +That's one of the primary results from the General theory of relativity, normally the universe's surface is nice and flat, but objects with mass "produce" gravity, which some sort of a force[^gravity-isnt-a-force] that bends our surface and creates those trophs, changing the local geodesics. +The resultant effect is that if you travel perfectly forwards in a spaceship and pass by an object with mass (like a planet) from a close enough distance, your path will be curved, without you steering your ship. -Looking at all possible great circles, we find that their center (and radius) matches with the center (and radius) of the sphere. -From this we can extrapolate that lines can be parallel, but great circles cannot. -A line is an extended segment, so if you extend two different arcs (which are the shortest distance between two pairs of points on the sphere) and get the great circles, those will always intersect[^parallels-of-latitude]. +Here comes the meat of this section: if you have no outside references (if all planets and stars are invisible), you, in your ship, *wouldn't* really be able to tell your path is curved. +But to a (stationary) outside observer, like another spaceship, it *would* look like you've turned. +In fact, while "turning" it will look like you've slowed down, since an arc is always longer than a straight line segment, but you're travelling at the same speed. -Therefore, the general term for the shortest path between two points on a non-flat surface is (kind of) called a geodesic[^geodesics-are-local] (the arc on the sphere is a geodesic). -We can now also define what it means to "go straight forwards": in flat surfaces we would say that means following a straight line, while on non-flat it means following a geodesic. +For the cherry on top, light is also affected by gravity, and we know it's speed is constant and always travels forwards, therefore gravity "bends" light. -Going back to physics, what the General theory of relativity tells us is that objects with mass bend the physical space, or 3D surface, of the universe, and we call that gravity. -As a result, the geodesics too are curved, so even though you may be always moving forwards at the same speed, to an outside observer it will look like you turn and change speed. -The explanation for modified speed is simpler: since we are travelling at the same speed, from the point of view of an outside observer, it should take the same amount of time to go between points P and Q, regardless of gravity. -However, a normal straight line segment through the points is always shorter than the gravitationally-induced circular arc, meaning it will look like you are travelling a greater distance. -The only way to balance everything out, is to travel faster. The amount by which and the size of the area which is affected depend on that object's mass and size. Generally, if two objects have the same mass, the bigger one will affect a larger portion of space, but will bend it less, compared to the smaller one, which will affect a smaller portion, which will be bend a lot. -- cgit v1.3.1-26-gb76a From 14526cb38d986bd190b9308ed0695c3b614c5ace Mon Sep 17 00:00:00 2001 From: Syndamia Date: Thu, 1 Aug 2024 08:24:30 +0300 Subject: (blog/tpbhs) Changed post from a general article about the project to only about the physics --- csg | 2 +- ...tric-in-Schwarzschild-coordinates-wikipedia.png | Bin 3423 -> 0 bytes .../img/Schwarzschild-radius-wikipedia.png | Bin 1054 -> 0 bytes .../img/algorithm.png | Bin 28039 -> 0 bytes .../img/antonelli-formula-expanded.png | Bin 11619 -> 0 bytes .../img/isco-wikipedia.png | Bin 1614 -> 0 bytes .../img/normalize-vector-wikipedia.png | Bin 625 -> 0 bytes .../img/photon-sphere-wikipedia.png | Bin 1472 -> 0 bytes ...chwarzschild-black-hole-force-field-formula.png | Bin 2265 -> 0 bytes .../img/specific-angular-momentum-wikipedia.png | Bin 529 -> 0 bytes .../img/variables-expanded.png | Bin 9318 -> 0 bytes .../index.md | 544 --------------------- ...tric-in-Schwarzschild-coordinates-wikipedia.png | Bin 0 -> 3423 bytes .../img/Schwarzschild-radius-wikipedia.png | Bin 0 -> 1054 bytes .../img/algorithm.png | Bin 0 -> 28039 bytes .../img/antonelli-formula-expanded.png | Bin 0 -> 11619 bytes .../img/isco-wikipedia.png | Bin 0 -> 1614 bytes .../img/normalize-vector-wikipedia.png | Bin 0 -> 625 bytes .../img/photon-sphere-wikipedia.png | Bin 0 -> 1472 bytes ...chwarzschild-black-hole-force-field-formula.png | Bin 0 -> 2265 bytes .../img/specific-angular-momentum-wikipedia.png | Bin 0 -> 529 bytes .../img/variables-expanded.png | Bin 0 -> 9318 bytes .../index.md | 544 +++++++++++++++++++++ 23 files changed, 545 insertions(+), 545 deletions(-) delete mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png delete mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png delete mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/algorithm.png delete mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/antonelli-formula-expanded.png delete mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/isco-wikipedia.png delete mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/normalize-vector-wikipedia.png delete mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/photon-sphere-wikipedia.png delete mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png delete mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png delete mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/img/variables-expanded.png delete mode 100644 src/blog/difficulties-of-making-a-black-hole-shader/index.md create mode 100644 src/blog/the-physics-behind-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png create mode 100644 src/blog/the-physics-behind-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png create mode 100644 src/blog/the-physics-behind-a-black-hole-shader/img/algorithm.png create mode 100644 src/blog/the-physics-behind-a-black-hole-shader/img/antonelli-formula-expanded.png create mode 100644 src/blog/the-physics-behind-a-black-hole-shader/img/isco-wikipedia.png create mode 100644 src/blog/the-physics-behind-a-black-hole-shader/img/normalize-vector-wikipedia.png create mode 100644 src/blog/the-physics-behind-a-black-hole-shader/img/photon-sphere-wikipedia.png create mode 100644 src/blog/the-physics-behind-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png create mode 100644 src/blog/the-physics-behind-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png create mode 100644 src/blog/the-physics-behind-a-black-hole-shader/img/variables-expanded.png create mode 100644 src/blog/the-physics-behind-a-black-hole-shader/index.md (limited to 'src') diff --git a/csg b/csg index 6c60778..4409b3c 160000 --- a/csg +++ b/csg @@ -1 +1 @@ -Subproject commit 6c60778bd3bc3d4b9fda32c9c6d9c412463df31a +Subproject commit 4409b3c0998d06ef3f06f40d1f691e8bf0328e2d diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png deleted file mode 100644 index 3964615..0000000 Binary files a/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png and /dev/null differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png deleted file mode 100644 index fccf54f..0000000 Binary files a/src/blog/difficulties-of-making-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png and /dev/null differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/algorithm.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/algorithm.png deleted file mode 100644 index 40d4c86..0000000 Binary files a/src/blog/difficulties-of-making-a-black-hole-shader/img/algorithm.png and /dev/null differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/antonelli-formula-expanded.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/antonelli-formula-expanded.png deleted file mode 100644 index 48eb7d4..0000000 Binary files a/src/blog/difficulties-of-making-a-black-hole-shader/img/antonelli-formula-expanded.png and /dev/null differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/isco-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/isco-wikipedia.png deleted file mode 100644 index 2b01135..0000000 Binary files a/src/blog/difficulties-of-making-a-black-hole-shader/img/isco-wikipedia.png and /dev/null differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/normalize-vector-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/normalize-vector-wikipedia.png deleted file mode 100644 index 517e142..0000000 Binary files a/src/blog/difficulties-of-making-a-black-hole-shader/img/normalize-vector-wikipedia.png and /dev/null differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/photon-sphere-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/photon-sphere-wikipedia.png deleted file mode 100644 index 840572c..0000000 Binary files a/src/blog/difficulties-of-making-a-black-hole-shader/img/photon-sphere-wikipedia.png and /dev/null differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png deleted file mode 100644 index 846b0d3..0000000 Binary files a/src/blog/difficulties-of-making-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png and /dev/null differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png deleted file mode 100644 index 61b3383..0000000 Binary files a/src/blog/difficulties-of-making-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png and /dev/null differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/img/variables-expanded.png b/src/blog/difficulties-of-making-a-black-hole-shader/img/variables-expanded.png deleted file mode 100644 index 484e2f1..0000000 Binary files a/src/blog/difficulties-of-making-a-black-hole-shader/img/variables-expanded.png and /dev/null differ diff --git a/src/blog/difficulties-of-making-a-black-hole-shader/index.md b/src/blog/difficulties-of-making-a-black-hole-shader/index.md deleted file mode 100644 index 555744a..0000000 --- a/src/blog/difficulties-of-making-a-black-hole-shader/index.md +++ /dev/null @@ -1,544 +0,0 @@ -# Difficulties of making a black hole shader - -## Contents - -1. [Preface](#preface) - 1. [Brief introduction to computer graphics](#brief-introduction-to-computer-graphics) - 2. [Brief introduction to WebGL](#brief-introduction-to-webgl) -2. [Theoretical and algorithmic background](#theoretical-and-algorithmic-background) - 1. [What is a black hole](#what-is-a-black-hole) - 2. [Geodesics, gravity and gravitational lensing](#geodesics-gravity-and-gravitational-lensing) - 3. [Finding a formula](#finding-a-formula) - 4. [Applying the formula to "bend" light's path](#applying-the-formula-to-bend-lights-path) - 5. [Properties of a black hole](#properties-of-a-black-hole) - 6. [Putting everything together](#putting-everything-together) -3. [WebGL preparation](#webgl-preparation) -4. [Shader](#shader) -5. [Appendix](#appendix) - -Back in August I had to submit a project for an elective WebGL programming course in university. -I chose to create an interractive and animated black hole demo. -The primary idea was to show how the gravitational pull of black holes "bends" light and how the result looks from different points of view. - -During development I found a lot of hurdles, primarily with the actual mathematics behind it. -Information online is difficult to find and understand without having a physics background, so I'll try my best to lay out everything I know. - -I'll assume you don't know much about physics, but are familiar with mathematics and at the very least vectors. - -## Preface - -### Brief introduction to computer graphics - -Image and video files store visual information in a "fixed" way: you get a huge array of colors, each connected to a particular pixel on your screen. -The objects in those mediums cannot be modified easily, and additions or subtractions are even harder to do, usually requiring an expert using professional tools for hours, days or weeks on end. - -Computer graphics aims to offload a lot of the creator's workload by "generating" the images on the fly using a set of descriptions for our objects. -The idea is to define objects with some primary properties of simpler geometric figures, like the points on a triangle, then give those to the computer, which will in turn have to calculate what the precise color of every pixel in the resultant image should be. - -For example, we can represent a tin can (without a label) as a simple cyllinder. -Changing it's height or width is trivial: just change the corresponding property you pass to the computer, and it will handle the rest. - -Of course this system has it's limitations: the more detail you add to an object, the more difficult it is to crunch up the math. -And adding lighting with shadows, bloom, refractions and so on becomes even more demanding for the computer. - -Expanding on out tin can example, if you want an image with a tin can up close, with a bright light shining on it, showing the hunderds or thousands of small scratches, bumps and kicks from manufacturing and usage, alongside reflections and shadows, you'll swiftly find that computer graphics are not the correct tool for the job. - -![](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Empty_tin_can2009-01-19.jpg/514px-Empty_tin_can2009-01-19.jpg) -*Image by Sun Ladder on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=5746428)* - -Such an image contains way way too much detail for the average computer to handle in reasonable time (some small fraction of a second). -However, computer generated graphics are still a very useful tools. -Thats why modern machines come with a graphics card handling *only* graphical tasks (alongside a processor, handling all other tasks like running programs, managing internet traffic, etc.). - -A graphics card is a combination of a special processor (GPU), designed to be able to *only* compute stuff related to graphics, with the upside of doing so much much faster than a general purpose processor (CPU) could, and some memory for use exclusively by that GPU. - -Since the GPU is different on the hardware level, it accepts significantly different instructions than a normal processor does. -For this reason programs written for a graphics processing unit are called "shaders", rather than just "programs". - -Of course, higher-level programming languages have been designed, which can then be transformed into the GPU-specific instructions. -But, contrary to normal software development, we don't really have standalone "shader compilers", but graphics library which do the job, alongside TODO - -### Brief introduction to WebGL - -One of the most popular such libraries is [OpenGL](TODO) with it's associated shader programming languages [GLSL](TODO) and [GLSL ES](TODO). -In the 2000s people decided it would be a good idea to add a graphics API/library to web browsers, which later morphed into what we call today [WebGL](TODO). - -It serves as a "layer above" OpenGL: you write JavaScript code with which the browser tells OpenGL what to do. -You would get a DOM object in which the graphics will be rendered, and a "context" object to which you'll pass down your shaders, shader parameters and change graphics settings. - -## Theoretical and algorithmic background - -&&important I haven't formally studied physics, so don't fully trust anything here. - There are most definetly errors, steming from my lackluster understanding. - -Using [Einstein's field equations](TODO), or to simplify our life, [Schwarzschild's metric](TODO), we can precisely calculate the curvatures in space(time) at every point around a Schwarzschild black hole. -Unfortunetly, the computation would still be too laborious, so we'll need to make an approximation using [celestial mechanics](TODO). - -That is the overall gist of the underlying physics, but I promised an explanation, so let's back up a bit. - -### What is a black hole - -Before we even begin to talk about gravity and light, we need to understand how atoms work. -Imagine a set of marbles, scattered on a table. - -![](https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Marbles_from_Indonesia.jpg/1280px-Marbles_from_Indonesia.jpg) -*Image from By Okkisafire on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=30338734)* - -Now, start pushing on all of them from the edges of the table to it's center. -In the beginning, you'll mostly roll them, until they all get in contact with each other. -At that point (assuming they all stay flat on the table), the glass will keep the marbles together, handling your force. - -By increasing the force with which you push on them, after a certain threshold, the glass will break, turning the marbles into shards. -Those shards will still have some fight in them, so after increasing your force by another level, you'll turn all of those shards into tiny glass granules. - -A similar occurence happens with atoms. -Normally atoms are spread apart, by pushing them together, at a certain point (ignoring the orbitin electrons) all nuclei will be "touching" and the [nuclar force](TODO) will keep them together. -By increasing your pushing force you can overwhelm the nuclear force and "shatter" the nuclei into their subatomic particles. - -Assuming an enormus explosion doesn't happen, and you can keep increasing your force, it's also possible to overwhelm the "subatomic forces" that keep those subatomic particles "together"[^matter-together]. -However, those subatomic particles are more commonly referred to as [elementary particles](https://en.wikipedia.org/wiki/Elementary_particle), meaning there are no "granules" into which the elementary particles can break down. -It doesn't make sense if subatomic particles wouldn't be "breakable", since that would require dealing with potentially infinite amounts of force and such an assumption would destroy all of humanity's physics. - -Then that leaves us with only one solution: laws of matter break. -If nothing can keep the elementary particles "together", so keep matter "together", then the result is a sort of "collapse", all of that matter just "deflates" into a single, infinetly small point (but the amount of mass isn't infinite, it's the sum of mass from the particles that collapsed). -That point is called a **black hole**. - -This object is very bizzare, generally it doesn't have too much properties, but the ones it has are really unique. -In my case of computer graphics, the only important part is it's effect on light. - -### Geodesics, gravity and gravitational lensing - -To understand how black holes affect light, we first need to understand how black holes affect gravity. - -Think of a flat surface, like a table. -What is the shortest distance between two points? -Obviously, that's a straight line segment. -If you then extend that segment, so it has an infinite length, it becomes a line. - -However, what if our surface isn't flat? -Imagine two points on a sphere, what is the shortest distance between them? -Obviously, it's an arc of a circle and extending it to it's maximum possible length, we get a [great circle](https://en.wikipedia.org/wiki/Great_circle). - -![](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Illustration_of_great-circle_distance.svg/480px-Illustration_of_great-circle_distance.svg.png) -*Image by CheCheDaWaff on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=48187293)* - -Now, what does it mean to go "forwards"? -On a flat surface, we can define it as "following a (straight) line segment", on our sphere we can say "following an arc of a great circle". -But what we really need is a more generalized definition, which handles both of our cases (and more). - -That's why in geometry there is the notion of [geodesics](TODO), the generalized curve on any surface which (roughly speaking) is the shortest[^geodesics-are-local] path between any two points. -On a flat surface, that's the line segment, on the sphere it's the great circle arc. -It's important to note that a general geodesic cannot have most properties you might be used to from "the shortest path between two points". -For example, on a flat surface, we can have parallel lines, but on our sphere, great circles will always intersect[^parallels-of-latitude]. - -And there are a lot more complicated surfaces, imagine a flat surface but with half-spherical "trophs" in it, on the flat segments your geodesic would be the line segment, but on those trophs it will be an arc (of a great circle). -Actually, you don't need to imagine: the entire universe is a 3D surface, which is mostly flat, but has sherical-ish "trophs" in it. - -That's one of the primary results from the General theory of relativity, normally the universe's surface is nice and flat, but objects with mass "produce" gravity, which some sort of a force[^gravity-isnt-a-force] that bends our surface and creates those trophs, changing the local geodesics. -The resultant effect is that if you travel perfectly forwards in a spaceship and pass by an object with mass (like a planet) from a close enough distance, your path will be curved, without you steering your ship. - -Here comes the meat of this section: if you have no outside references (if all planets and stars are invisible), you, in your ship, *wouldn't* really be able to tell your path is curved. -But to a (stationary) outside observer, like another spaceship, it *would* look like you've turned. -In fact, while "turning" it will look like you've slowed down, since an arc is always longer than a straight line segment, but you're travelling at the same speed. - -For the cherry on top, light is also affected by gravity, and we know it's speed is constant and always travels forwards, therefore gravity "bends" light. - - - -The amount by which and the size of the area which is affected depend on that object's mass and size. -Generally, if two objects have the same mass, the bigger one will affect a larger portion of space, but will bend it less, compared to the smaller one, which will affect a smaller portion, which will be bend a lot. - -Since a black hole is a single infinetly small point, then all of it's mass is concentrated on that point, making it bend a relatively small are of space **a lot**. -Strong enough in fact, that if you get too close, you will not be able to overwhelm gravity and "merge" into that infinitessimal point (the white lines are our "geodesics"): - -![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/CNX_UPhysics_13_07_spacetime.png/800px-CNX_UPhysics_13_07_spacetime.png?20171124170318) -*Image by OpenStax University Physics on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=64307901)* - -An interesting effect from gravity is that light (which always travells "forwards", so along a geodesic) also gets "bent", allowing an observer to view otherwise obstructed objects. -We call that [graviational lensing](TODO). -Though not unique to black holes, thats when the effect is strongest: - -![](https://upload.wikimedia.org/wikipedia/commons/0/02/Gravitational_lens-full.jpg) -*(notice how the gray arrows show the path light travels from a galaxy that is behind (obstructed by) the black hole)* - -I'll abstrain from explaining light, but you may think of it as a small particle, "similar" to an electron, travelling through space. -In fact, Newton understood light to be just that, and called the underlying particle a "corpiscule". -For our purpopses, this approximation will serve us well. - -The distinction that gravity doesn't change the direction or speed of an object "directly" is at upmost importance for physics, since this way we preserve two very important properties of light: it's constant speed and straight travelling path. -However, in our simulation, it would be significantly simpler to assume the opposite, since to an outside observer (like the "player") the difference is indistinguishable. - -Therefore, in our simulation, we'll have light rays, but when they approach a black hole, their speed and direction would change. -This will be determined by some physics equations. - -### Finding a formula - -Now, how do we calculate the exact curvature a black hole produces? -General theory of relativity provides us with the (really complicated) [Einstein field equations](https://en.wikipedia.org/wiki/Einstein_field_equations) for this exact problem. -[Schwartzschild](TODO) solved these equations, assuming that the body with mass doesn't spin[^schwm-assumptions]. -This solution is called the [Schwarzschild metric](https://en.wikipedia.org/wiki/Schwarzschild_metric), and a black hole for which this assumption is true is called a "Shwartzschild black hole". - -The Shwarzschild black hole is the symplest of it's type, so using the Schwarzschild metric should give us the least trouble. -Now, here is the metric in Schwartzschild coordinates: - -![](./img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png) - -**YOUCH!** - -The variables themselves aren't that bad: `c` is the speed of light, τ is time, Ω, `t` and `r` are Schwarzschild coordinates. - -However, as you can see, there are two big problems: we have to calculate derivatives (that's what the `d` signifies) and convert from Schwarzschild coordinates to normal (eucledian) coordinates, that the computer understands natively. -Both of those operations are **incredibly slow**, the average computer doesn't standa a chance at rendering anything in a reasonable amount of time. - -Thankfully [Riccardo Antonelli](http://rantonels.github.io/starless/) was able to do all of our coordinate conversions and simplify the living crap out of that monster (using some approximations with celestial mechanics), turning it into something digestible: - -![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png) - -I will not be trying to explain why or how the Schwarzschild metric and this formula work, that's way way beyond my elementary understanding and the scope of this post. - -Question now is: what do all of those letters represent? -This turned out to be a much harder problem than it should have, I actually had to refer [Ricardo Antonelli's](https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py) and [Dmitry Brant's](https://dmitrybrant.com/2018/12/11/ray-tracing-black-holes) implementation in their projects, alongside copus articles on wikipedia to fully grasp how to put it to work. - -### Applying the formula to "bend" light's path - -Our plan for simulating gravitational lensing is to move the corpiscule by a tiny amount in a certain direction by a certain amount, update the direction and amount according to gravity, rince and repeat. -The direction, alongside the amount by which the particle moves, can be represented with a single vector, which we'll call light's "velocity". - -Referring to the formula again: - -![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png) - -The F→ returns a force vector (`F` for "force" and → for "vector"): any force acting on an object has a strength (magnitude) and a direction. -Imagine you are pushing a box: you are applying some force to it in a "forward" direction. -If you pull the box, you'll apply some force in a "backward" direction. - -This force vector conveys how much and in what direction exactly the black hole is "pulling" on the corpiscule. - -Although the function takes in only one argument, `r`, that doesn't mean that `h` or r\^ aren't also arguments: - -- `r` is the distance from the center of the black hole (the singularity) to the **current** position of the corpiscule. - -- `h` is the magnitude of the ["specific angular momentum"](https://en.wikipedia.org/wiki/Specific_angular_momentum) of the light "particle". - - "Normal" linear momentum specifies how much "force" at what speed it takes to stop (or change) the speed and direction of an object in linear motion (that's why it's in kg\*m/s). - Imagine a big heavy train on a perfectly straight rails going at a fast speed. - How do you forcefully stop it? - - You can put a *really* heavy barrier on the tracks, in front of the train. - Since the train is moving at a really great speed, this barrier will have to be much much heavier (with much more mass) than the train itself. - - Alternatively, you can "launch" something against the train, meaning you can put a second train, moving in the opposite direction of the first train, so they hit head-on. - Since the second train would also be moving, if it's travelling at the same speed and has the same mass as the first train, upon collision they would both stop[^hitting-trains]. - If the second travells at twice the speed, then it can have half of the mass of the first to produce the same effect. - - The property with which we can "prove" why both a larger mass at no speed, and a smaller mass at a faster speed, can stop the train, is the momentum. - - Angular momentum specifies how much "force" at what speed it takes to stop (or change) the speed and directino of a rotating object. - Imagine the train scenario but on a circular track. - - The specific angular momentum is the angular momentum of an object, divided by it's mass. - It's magnitude kind of tells us which property is more prevalent in the momentum, the mass or the speed. - For the same angular momentum, a long (big magnitutde) *specific* angular momentum means our object is small and moves fast, while for a short (small magnitutde) *specific* angular momentum out object is large and moves slowly. - - In our case a light "particle" is being pulled by a stationary object of large mass (a Shwarzschild black hole), so rather than finding the angular momentum[^angular-momentum] and then dividing by the mass[^light-has-no-mass], we'll use another formula: - - ![](./img/specific-angular-momentum-wikipedia.png) - - where **in this specific formula only** `r` is the vector from the center of the big mass (the singularity of the black hole) to the light "particle" and `v` is the velocity (direction and amount of speed) the light is travelling with. - - The cross product returns a vector, so we'll need to take the magnitutde of the result and plug that into the formula. - It's also important that **we calculate it only once, in the beginning**. - So, we shouldn't be calculating the magnitude of the specific angular momentum every time the light "particle" is moved, rather we calculate it once, after it gets close enough to be affected by the black hole. - -- r^ is the normalized ([unit](https://en.wikipedia.org/wiki/Unit_vector), hence the `^` on top) vector from the center of the black hole to the light particle: - - ![](./img/normalize-vector-wikipedia.png) - -Finally, putting all needed variables together in one proper function, we get: - -![Refer to "Antonelli’s formula - explained" in the Appendix](./img/variables-expanded.png) - -As you may notice, this can be simplified, if we substitude r^: - -![Refer to "Antonelli’s formula - simplified" in the Appendix](./img/antonelli-formula-expanded.png) - -In effect, we pass the distance from the black hole to the corpiscule and the function returns how light's velocity changes. - -Finally, we know what to give the formula, and what it will return. -The task at hand is making an algorithm which utilises it. -For that we'll need to get even more familiar with black holes. - -### Properties of a black hole - -As stated, we'll be working with non-rotating stationary black holes, Schwarzschild black holes. -From the [no-hair conjecture](https://en.wikipedia.org/wiki/No-hair_theorem) we know that such a black hole has only three distinct properties: mass, electric charge and angular momentum. -The last one doesn't apply for our case, and the second is irrelevant. - -Meaning, from the mass alone, we can derive the gravitational "forces", alongside three radii, which will be the backbone of our black hole: the event horizon, the photon sphere and [ISCO](https://en.wikipedia.org/wiki/Innermost_stable_circular_orbit). - -The event horizon, also called the Schwarzschild radius, is the distance from the center of the black hole (singularity), which once passed, cannot be passed again (you cannot escape the black hole). -The formula for it is: - -![r_s = (2GM)/(c^2)](./img/Schwarzschild-radius-wikipedia.png) - -where `G` is the [gravitational constant](https://en.wikipedia.org/wiki/Gravitational_constant) and `M` is the mass of the black hole (in kg). - -The photon sphere is the distance from the singularity, in which photons start orbiting the black hole (and can either escape or pass the event horizon). -Formula: - -![r = r_s * 3/2](./img/photon-sphere-wikipedia.png) - -where `G` and `M` are the same as before, `c` is the speed of light in vacuum and rs is the afroementioned Schwarzschild radius. - -Finally, the innermost stable circular orbit (ISCO), formally it's the distance, before which you can orbit the black hole, but once passed, you'll get sucked in and either get shot out or be forever lost past the event horizon. -For our purposes, it's fine to approximate it as the maximum radius after which spacetime isn't bent[^isco] and objects aren't affected. -Formula: - -![](./img/isco-wikipedia.png) - -Putting them all together, we should expect light to travel like this: -![](https://upload.wikimedia.org/wikipedia/commons/2/27/Black_Hole_Shadow.gif) -*Animation by Hugo Spinelli on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=138168679)* - - -### Putting everything together - -Finally, now we have everything we need to divise an algorithm for our light. -For light we'll store two vectors: one for it's position and one for it's velocity. -For a black hole we'll store a vector and a quantity: the position of the black hole's center and it's mass. -For convinience, we could just store the Schwarzschild radius, since all of our radii depend only on it. - -Once the distance between the light and the center is less than or equal to the ISCO, we can begin augmenting light's velocity. -On small steps, we move the light forward a bit with the velocity and then update the velocity with the black hole's pull. - -If light enters the event horizon, then we know it cannot escape, and stop moving it. -If it passes the ISCO then it has left the black hole and will never approach it again. - -If light enters the photon sphere, then we'll have to "track" how long it's been there, if it decides to orbit in a stable manner, then it will stay there indefinetly. -The simplest way to "track" this is just to limit how many times we can move the light forward. - -An algorithm doing this would look a bit like this (in pseudocode, inspired by Python): - -![Refer to "Algorithm" section of the Appendix](./img/algorithm.png) - -as a reminder, here is the definiton of F→: - -![](./img/antonelli-formula-expanded.png) - -## WebGL preparation - -The course was focused on handmade solutions, so some of the logic uses a [custom handmade library](TODO). - -Since the primary component was the shader itself, I made sure to simplify my logic to the absolute minimum. -A **lot** of decisions were made to optimize development time, without considering how good they were. - -In a scene there really are only 3 distinct objects: the stars, the black holes and the skybox. -The latter is just a simple cube, inside which everything resides, if a ray doesn't hit anything of interest, it will hit the cube. -Both stars and black holes are simple spheres, the former with an orange-y color (#f4803b) and any radious. -Black holes aren't rendered and their underlying sphere has the same radius as the ISCO, so their purpose is for intersection checks (more on those when we get to the [shaders](#shaders)). - -Most JavaScript code isn't worth talking about, wherever possible I use the [course library](TODO) and where I can't it's mostly simple WebGL configurations, elementary object "classes" and trivial HTML handling. -Though, there are still two somewhat interesting systems: - -### Scenes - -I wanted to have multiple scenes, with different arrangements of objects and with animations (stars moving around). -For that I devised a dead-simple level loading and animation system. - -An object of type "Level" stores a name, description, location of camera (the viewer) and arrays for stars, black holes and animations. -Though, for creating new levels, you only pass the first three: - -```javascript -var level1 = new Level( - "Star passing behind black hole", // Level title - "The black hole warps the light", // Level description - [1000,0,650]); // Initial coordinates of camera -``` - -Adding stars or black holes requires going through two member functions: `addStar` and `addBlackHole`. -Both take the center of the object, as well as it's radius, alongside an animation function. -The latter has two parameters: current time in TODO(seconds,milliseconds,?) from the beginning and the current object that will be created. -This function is called on each frame with the appropriate arguments, so inside you'll have to "manually" modify the object's properties. - -For example, a simple star going forwards could be added like this (`vecSum` is just [componentwise vector summation](TODO)): - -```javascript -level1.addStar([1070,0,1000], // Coordinates of center - 10, // Radius - (t, star) => vecSum(star.center, [-t,0,0])); // Move from left to right -``` - -Or one which rotates around a point: - -```javascript -var speed = Math.PI / 20, rad = 40; -level1.addStar([1000+rad,0,900], - 3, - (t, star) => vecSum([1000,0,900], [Math.cos(t*speed) * rad, - Math.sin(t*speed) * 5, - Math.sin(t*speed) * rad])); -``` - -For black holes it's the same. -If you want the object to not move, you could just pass `undefined` as the function: - -```javascript -level1.addBlackHole([1000,0,900], 30, undefined); -``` - -### Movement - -It wouldn't be fun without the ability to move around in the scene, so I added a simple system for that too. -WASD moves the camera position forward, left, backward and right, shift moves down and space moves up, all relative to the current direction the camera is looking towards. -Those are all done with relatively simple analytic geometry: we store three vectors, one pointing up, one pointing forward and one pointing left (which can be calculated from the other two with a cross product). -To move forward, add to the position the forward vector times some constant, to move backwards subtract and so on. - -Looking around with the mouse was kinda tricky, since I decided to use [spherical coordinates](TODO). -You store two angles, the "up" and "left" angle, moving the mouse forwards adds to the "up" angle, moving it downwards subtracts and so on. -The tricky part was what to do after - -TODO - -## Shaders - -As a gentle reminder, in OpenGL we have a vertex shader and a fragment shader: - -- The vertex shader is ran on every point of every object in our scene -- The fragment shader is ran on every pixel of your screen, with the added bonus that depending on the pixel, certain values are passed down from the vertex shader. - - This includes interpolated points: a line is made up of two points, the vertex shader is ran on both of them, then the line is interpolated and the fragment shader is ran on each pixel, corresponding to a point on the line. - The vertex shader values are also passed down interpolated, so if one end of the line is the color red, while the other end is green, then the fragment shader corresponding to the pixel, which shows the middle of the line, will have the color yellow. - -### Vertex shader - -As already mentioned, black holes aren't rendered, so the only objects with special rendering are the stars. -To simplify my life, I chose to do a simple [diffusion reflection](https://learnopengl.com/Lighting/Basic-Lighting), with the light source emminating from the camera, something which was already made in lectures: - -![](TODO) - -The result isn't amazing, but you can clearly make out the sphere as a 3D object (not a flat circle). - -### Fragment shader - -This is the meat of our logic, this is where we'll implement our algorithm: - -![](./img/algorithm.png) - -In real life, every star emits light, which then travells some distance, until it reaches our eyes. -However, computing it this way is incredibly inefficient, for every star we'll have to create hundreds or thousands of light rays (corpiscules), most of which probably wont reach us. -We want performance, so this is a no-go. - -The alternative is to do the opposite, assume every pixel was hit by a "ray" and trace back it's steps, if it came out of a star then it has some specific color (it was an actual ray), but if it didn't then show it as black (no ray hit us). -Taking it further, how do we "trace back" those steps? -Well, we can find the precise coordinate of every pixel inside the 3D scene, and move each point in the direction we're looking (though this image is about raytracing, just look at the two top red vectors): - -![](https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Ray_trace_diagram.png/800px-Ray_trace_diagram.png?20080214101526) -*Image by Timrb on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=3553478)* - -In the context of computer graphics, this is called [ray marching](TODO). - -Now, how do we detect if the ray hit something? -The dumb way is to move the ray forward a bit and check with every object whether the ray intersects it. -However, since all of our objects are spheres, there is a very easy optimization and simplification - imagine the ray as an infinitely long line and just get the shortest (perpendicular) distance between it and the center of the sphere: - -TODO custom image #1 - -For this we can implement a simple distance function: - -![](https://wikimedia.org/api/rest_v1/media/math/render/svg/42c53741fd3d8765e56ea652369a512a2cd09eac) - -```glsl -float linePointDistance(vec3 a, vec3 n, vec3 p) { - return length((p - a) - dot(p - a, n) * n); -} -``` - -Where `a` is the coordinate of our ray (pixel), `n` is the direction it will be travelling in and `p` is the sphere center we're comparing with. - -However, there is a huge problem: our line extends in both directions, so a check like `linePointDistance(ray, step, center) <= radius` would also detect if the ray interects the point behind us (when ray is going in the opposite direction)! -A very simple solution is to just add a sign to our distance: if positive then the distance is in reference to a point in front, while negative means it's behind. -The simplest way to get this information is by taking the [dot product](TODO) between our "forwards" direction and the direction from our coordinates to the [projection](TODO) of our point on the line: - -TODO custom image #2 - -```glsl -float linePointDistance(vec3 a, vec3 n, vec3 p) { - vec3 projection = dot(p - a, n) * n; - float dist = length((p - a) - projection); - - if (dot(projection, n) < 0.0) return -dist; - return dist; -} -``` - -Since all of our objects are spheres, we can just iterate through all of them and do this check. - -## Appendix - -##### LaTeX source for equations - -The images for my custom LaTeX equations were created on [latexeditor.lagrida.com](https://latexeditor.lagrida.com/), by using Firefox's built-in ability to screenshot HTML nodes, in particular the [MathJax](https://www.mathjax.org/) node with the equation. - -###### Antonelli's formula - explained - -```latex -\begin{align*} - & \overrightarrow{F}(r_l,h) = -\frac{3}{2} \; h^2 \; \frac{\hat{r_l}}{\|r_l\|^5} \quad \text{, where}\\ - & h = \|r_l \cross v_l\|\\ - & \hat{r_l} = \frac{r_l}{\|r_l\|}\\ - & \|x\| = \text{magnitude of }x\\ - & r_l = \text{vector from black hole center to light "particle"}\\ - & v_l = \text{velocity of light "particle"} -\end{align*} -``` - -###### Antonelli's formula - simplified - -```latex -\begin{align*} - & \overrightarrow{F}(r_l,h) = -\frac{3}{2} \; h^2 \; \frac{r_l}{\|r_l\|^6} \quad \text{, where}\\ - & h = \|r_l \cross v_l\| \text{ (calculated right before being affected by black hole)}\\ - & \|x\| = \text{magnitude of }x\\ - & r_l = \text{vector from black hole center to light "particle"}\\ - & v_l = \text{velocity of light "particle"} -\end{align*} -``` - -###### Algorithm - -```latex -\begin{align*} - & p_{cbh} = \text{position of center of black hole}\\ - & r_s = \text{Schwarzchild distance from } p_{cbn} \\ - & r_{ps} = \frac{2}{3}r_s \quad \text{(photon sphere)}\\ - & r_{ISCO} = 3 r_s \\ - \\ - & p_l = \text{position of light "particle"}\\ - & v_l = \text{velocity of light "particle"}\\ - \\ - & r_l = \| p_l-p_{cbh} \| \quad \text{(distance between black hole and light)}\\ - & \text{If } r_l \leq r_{ISCO} : \\ - & \quad h = \| r_l \cross v_l \|\\ - & \quad \text{LightMovesLimit} = \infty \\ - & \quad \text{Repeat maximum LightMovesLimit times}:\\ - & \qquad \text{If } r_l \leq r_s : \\ - & \qquad \quad \text{return "Light never escapes"} \\ - & \qquad \text{If } r_l \leq r_{ps} : \\ - & \qquad \quad \text{LightMovesLimit} = 100 \\ - & \qquad \text{If } r_l > r_{ISCO} : \\ - & \qquad \quad \text{return "Light escaped black hole"} \\ - & \qquad p_l = p_l + v_l \quad \text{(move light)}\\ - & \qquad r_l = \| p_l-p_{cbh} \| \quad \text{(update distance to $p_{cbh}$)}\\ - & \qquad v_l = v_l + \overrightarrow{F}(r_l,h) \quad \text{(update light velocity)} \\ - & \quad \text{return "Light stuck in photon sphere, never escapes"} -\end{align*} -``` - -[^matter-together]: Technically, it's more accurate to say "matter apart", since after the collapse matter is as close together as physically possible, and the nuclear forces keep everything in order but also separated. However, considering the intuitive approach I'm striving for, "matter together" is simpler to understand. -[^parallels-of-latitude]: You might think about the latituginal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest. -[^geodesics-are-local]: This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purpopses. More info can be found on [wikipedia](https://en.wikipedia.org/wiki/Geodesic#Introduction). -[^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](TODO) is zero. These are way outside of my understanding and our purposes, so I skiped them for simplicity. -[^isco]: It's not really true that gravity stopps affecting spacetime after the ISCO, even though things can orbit Earth that doesn't mean that Earth doesn't bend spacetime. However, for the purposes of a simple shader, this assumption produces perfectly useable results. -[^hitting-trains]: Of course, I'm asuming the trains are strong enough they won't break upon the collision. -[^angular-momentum]: Angular momentum is actually [defined using the cross product](https://en.wikipedia.org/wiki/Specific_angular_momentum#Definition) -[^light-has-no-mass]: Actually, light has no mass, so this version of the formula wouldn't work. You might think that makes no sense, since we cannot divide by zero, so the specific angular momentum shouldn't exist, but then with the cross product we find a value for it. You would be correct: Antonelli does some funky approximations, combining Newtonian physics with General theory of relativity, to make the formula that simple. Someone in physics will probably vomit looking at it, but for our purposes it's more than perfect. diff --git a/src/blog/the-physics-behind-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png b/src/blog/the-physics-behind-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png new file mode 100644 index 0000000..3964615 Binary files /dev/null and b/src/blog/the-physics-behind-a-black-hole-shader/img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png differ diff --git a/src/blog/the-physics-behind-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png b/src/blog/the-physics-behind-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png new file mode 100644 index 0000000..fccf54f Binary files /dev/null and b/src/blog/the-physics-behind-a-black-hole-shader/img/Schwarzschild-radius-wikipedia.png differ diff --git a/src/blog/the-physics-behind-a-black-hole-shader/img/algorithm.png b/src/blog/the-physics-behind-a-black-hole-shader/img/algorithm.png new file mode 100644 index 0000000..40d4c86 Binary files /dev/null and b/src/blog/the-physics-behind-a-black-hole-shader/img/algorithm.png differ diff --git a/src/blog/the-physics-behind-a-black-hole-shader/img/antonelli-formula-expanded.png b/src/blog/the-physics-behind-a-black-hole-shader/img/antonelli-formula-expanded.png new file mode 100644 index 0000000..48eb7d4 Binary files /dev/null and b/src/blog/the-physics-behind-a-black-hole-shader/img/antonelli-formula-expanded.png differ diff --git a/src/blog/the-physics-behind-a-black-hole-shader/img/isco-wikipedia.png b/src/blog/the-physics-behind-a-black-hole-shader/img/isco-wikipedia.png new file mode 100644 index 0000000..2b01135 Binary files /dev/null and b/src/blog/the-physics-behind-a-black-hole-shader/img/isco-wikipedia.png differ diff --git a/src/blog/the-physics-behind-a-black-hole-shader/img/normalize-vector-wikipedia.png b/src/blog/the-physics-behind-a-black-hole-shader/img/normalize-vector-wikipedia.png new file mode 100644 index 0000000..517e142 Binary files /dev/null and b/src/blog/the-physics-behind-a-black-hole-shader/img/normalize-vector-wikipedia.png differ diff --git a/src/blog/the-physics-behind-a-black-hole-shader/img/photon-sphere-wikipedia.png b/src/blog/the-physics-behind-a-black-hole-shader/img/photon-sphere-wikipedia.png new file mode 100644 index 0000000..840572c Binary files /dev/null and b/src/blog/the-physics-behind-a-black-hole-shader/img/photon-sphere-wikipedia.png differ diff --git a/src/blog/the-physics-behind-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png b/src/blog/the-physics-behind-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png new file mode 100644 index 0000000..846b0d3 Binary files /dev/null and b/src/blog/the-physics-behind-a-black-hole-shader/img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png differ diff --git a/src/blog/the-physics-behind-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png b/src/blog/the-physics-behind-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png new file mode 100644 index 0000000..61b3383 Binary files /dev/null and b/src/blog/the-physics-behind-a-black-hole-shader/img/specific-angular-momentum-wikipedia.png differ diff --git a/src/blog/the-physics-behind-a-black-hole-shader/img/variables-expanded.png b/src/blog/the-physics-behind-a-black-hole-shader/img/variables-expanded.png new file mode 100644 index 0000000..484e2f1 Binary files /dev/null and b/src/blog/the-physics-behind-a-black-hole-shader/img/variables-expanded.png differ diff --git a/src/blog/the-physics-behind-a-black-hole-shader/index.md b/src/blog/the-physics-behind-a-black-hole-shader/index.md new file mode 100644 index 0000000..555744a --- /dev/null +++ b/src/blog/the-physics-behind-a-black-hole-shader/index.md @@ -0,0 +1,544 @@ +# Difficulties of making a black hole shader + +## Contents + +1. [Preface](#preface) + 1. [Brief introduction to computer graphics](#brief-introduction-to-computer-graphics) + 2. [Brief introduction to WebGL](#brief-introduction-to-webgl) +2. [Theoretical and algorithmic background](#theoretical-and-algorithmic-background) + 1. [What is a black hole](#what-is-a-black-hole) + 2. [Geodesics, gravity and gravitational lensing](#geodesics-gravity-and-gravitational-lensing) + 3. [Finding a formula](#finding-a-formula) + 4. [Applying the formula to "bend" light's path](#applying-the-formula-to-bend-lights-path) + 5. [Properties of a black hole](#properties-of-a-black-hole) + 6. [Putting everything together](#putting-everything-together) +3. [WebGL preparation](#webgl-preparation) +4. [Shader](#shader) +5. [Appendix](#appendix) + +Back in August I had to submit a project for an elective WebGL programming course in university. +I chose to create an interractive and animated black hole demo. +The primary idea was to show how the gravitational pull of black holes "bends" light and how the result looks from different points of view. + +During development I found a lot of hurdles, primarily with the actual mathematics behind it. +Information online is difficult to find and understand without having a physics background, so I'll try my best to lay out everything I know. + +I'll assume you don't know much about physics, but are familiar with mathematics and at the very least vectors. + +## Preface + +### Brief introduction to computer graphics + +Image and video files store visual information in a "fixed" way: you get a huge array of colors, each connected to a particular pixel on your screen. +The objects in those mediums cannot be modified easily, and additions or subtractions are even harder to do, usually requiring an expert using professional tools for hours, days or weeks on end. + +Computer graphics aims to offload a lot of the creator's workload by "generating" the images on the fly using a set of descriptions for our objects. +The idea is to define objects with some primary properties of simpler geometric figures, like the points on a triangle, then give those to the computer, which will in turn have to calculate what the precise color of every pixel in the resultant image should be. + +For example, we can represent a tin can (without a label) as a simple cyllinder. +Changing it's height or width is trivial: just change the corresponding property you pass to the computer, and it will handle the rest. + +Of course this system has it's limitations: the more detail you add to an object, the more difficult it is to crunch up the math. +And adding lighting with shadows, bloom, refractions and so on becomes even more demanding for the computer. + +Expanding on out tin can example, if you want an image with a tin can up close, with a bright light shining on it, showing the hunderds or thousands of small scratches, bumps and kicks from manufacturing and usage, alongside reflections and shadows, you'll swiftly find that computer graphics are not the correct tool for the job. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Empty_tin_can2009-01-19.jpg/514px-Empty_tin_can2009-01-19.jpg) +*Image by Sun Ladder on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=5746428)* + +Such an image contains way way too much detail for the average computer to handle in reasonable time (some small fraction of a second). +However, computer generated graphics are still a very useful tools. +Thats why modern machines come with a graphics card handling *only* graphical tasks (alongside a processor, handling all other tasks like running programs, managing internet traffic, etc.). + +A graphics card is a combination of a special processor (GPU), designed to be able to *only* compute stuff related to graphics, with the upside of doing so much much faster than a general purpose processor (CPU) could, and some memory for use exclusively by that GPU. + +Since the GPU is different on the hardware level, it accepts significantly different instructions than a normal processor does. +For this reason programs written for a graphics processing unit are called "shaders", rather than just "programs". + +Of course, higher-level programming languages have been designed, which can then be transformed into the GPU-specific instructions. +But, contrary to normal software development, we don't really have standalone "shader compilers", but graphics library which do the job, alongside TODO + +### Brief introduction to WebGL + +One of the most popular such libraries is [OpenGL](TODO) with it's associated shader programming languages [GLSL](TODO) and [GLSL ES](TODO). +In the 2000s people decided it would be a good idea to add a graphics API/library to web browsers, which later morphed into what we call today [WebGL](TODO). + +It serves as a "layer above" OpenGL: you write JavaScript code with which the browser tells OpenGL what to do. +You would get a DOM object in which the graphics will be rendered, and a "context" object to which you'll pass down your shaders, shader parameters and change graphics settings. + +## Theoretical and algorithmic background + +&&important I haven't formally studied physics, so don't fully trust anything here. + There are most definetly errors, steming from my lackluster understanding. + +Using [Einstein's field equations](TODO), or to simplify our life, [Schwarzschild's metric](TODO), we can precisely calculate the curvatures in space(time) at every point around a Schwarzschild black hole. +Unfortunetly, the computation would still be too laborious, so we'll need to make an approximation using [celestial mechanics](TODO). + +That is the overall gist of the underlying physics, but I promised an explanation, so let's back up a bit. + +### What is a black hole + +Before we even begin to talk about gravity and light, we need to understand how atoms work. +Imagine a set of marbles, scattered on a table. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Marbles_from_Indonesia.jpg/1280px-Marbles_from_Indonesia.jpg) +*Image from By Okkisafire on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=30338734)* + +Now, start pushing on all of them from the edges of the table to it's center. +In the beginning, you'll mostly roll them, until they all get in contact with each other. +At that point (assuming they all stay flat on the table), the glass will keep the marbles together, handling your force. + +By increasing the force with which you push on them, after a certain threshold, the glass will break, turning the marbles into shards. +Those shards will still have some fight in them, so after increasing your force by another level, you'll turn all of those shards into tiny glass granules. + +A similar occurence happens with atoms. +Normally atoms are spread apart, by pushing them together, at a certain point (ignoring the orbitin electrons) all nuclei will be "touching" and the [nuclar force](TODO) will keep them together. +By increasing your pushing force you can overwhelm the nuclear force and "shatter" the nuclei into their subatomic particles. + +Assuming an enormus explosion doesn't happen, and you can keep increasing your force, it's also possible to overwhelm the "subatomic forces" that keep those subatomic particles "together"[^matter-together]. +However, those subatomic particles are more commonly referred to as [elementary particles](https://en.wikipedia.org/wiki/Elementary_particle), meaning there are no "granules" into which the elementary particles can break down. +It doesn't make sense if subatomic particles wouldn't be "breakable", since that would require dealing with potentially infinite amounts of force and such an assumption would destroy all of humanity's physics. + +Then that leaves us with only one solution: laws of matter break. +If nothing can keep the elementary particles "together", so keep matter "together", then the result is a sort of "collapse", all of that matter just "deflates" into a single, infinetly small point (but the amount of mass isn't infinite, it's the sum of mass from the particles that collapsed). +That point is called a **black hole**. + +This object is very bizzare, generally it doesn't have too much properties, but the ones it has are really unique. +In my case of computer graphics, the only important part is it's effect on light. + +### Geodesics, gravity and gravitational lensing + +To understand how black holes affect light, we first need to understand how black holes affect gravity. + +Think of a flat surface, like a table. +What is the shortest distance between two points? +Obviously, that's a straight line segment. +If you then extend that segment, so it has an infinite length, it becomes a line. + +However, what if our surface isn't flat? +Imagine two points on a sphere, what is the shortest distance between them? +Obviously, it's an arc of a circle and extending it to it's maximum possible length, we get a [great circle](https://en.wikipedia.org/wiki/Great_circle). + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Illustration_of_great-circle_distance.svg/480px-Illustration_of_great-circle_distance.svg.png) +*Image by CheCheDaWaff on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=48187293)* + +Now, what does it mean to go "forwards"? +On a flat surface, we can define it as "following a (straight) line segment", on our sphere we can say "following an arc of a great circle". +But what we really need is a more generalized definition, which handles both of our cases (and more). + +That's why in geometry there is the notion of [geodesics](TODO), the generalized curve on any surface which (roughly speaking) is the shortest[^geodesics-are-local] path between any two points. +On a flat surface, that's the line segment, on the sphere it's the great circle arc. +It's important to note that a general geodesic cannot have most properties you might be used to from "the shortest path between two points". +For example, on a flat surface, we can have parallel lines, but on our sphere, great circles will always intersect[^parallels-of-latitude]. + +And there are a lot more complicated surfaces, imagine a flat surface but with half-spherical "trophs" in it, on the flat segments your geodesic would be the line segment, but on those trophs it will be an arc (of a great circle). +Actually, you don't need to imagine: the entire universe is a 3D surface, which is mostly flat, but has sherical-ish "trophs" in it. + +That's one of the primary results from the General theory of relativity, normally the universe's surface is nice and flat, but objects with mass "produce" gravity, which some sort of a force[^gravity-isnt-a-force] that bends our surface and creates those trophs, changing the local geodesics. +The resultant effect is that if you travel perfectly forwards in a spaceship and pass by an object with mass (like a planet) from a close enough distance, your path will be curved, without you steering your ship. + +Here comes the meat of this section: if you have no outside references (if all planets and stars are invisible), you, in your ship, *wouldn't* really be able to tell your path is curved. +But to a (stationary) outside observer, like another spaceship, it *would* look like you've turned. +In fact, while "turning" it will look like you've slowed down, since an arc is always longer than a straight line segment, but you're travelling at the same speed. + +For the cherry on top, light is also affected by gravity, and we know it's speed is constant and always travels forwards, therefore gravity "bends" light. + + + +The amount by which and the size of the area which is affected depend on that object's mass and size. +Generally, if two objects have the same mass, the bigger one will affect a larger portion of space, but will bend it less, compared to the smaller one, which will affect a smaller portion, which will be bend a lot. + +Since a black hole is a single infinetly small point, then all of it's mass is concentrated on that point, making it bend a relatively small are of space **a lot**. +Strong enough in fact, that if you get too close, you will not be able to overwhelm gravity and "merge" into that infinitessimal point (the white lines are our "geodesics"): + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/CNX_UPhysics_13_07_spacetime.png/800px-CNX_UPhysics_13_07_spacetime.png?20171124170318) +*Image by OpenStax University Physics on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=64307901)* + +An interesting effect from gravity is that light (which always travells "forwards", so along a geodesic) also gets "bent", allowing an observer to view otherwise obstructed objects. +We call that [graviational lensing](TODO). +Though not unique to black holes, thats when the effect is strongest: + +![](https://upload.wikimedia.org/wikipedia/commons/0/02/Gravitational_lens-full.jpg) +*(notice how the gray arrows show the path light travels from a galaxy that is behind (obstructed by) the black hole)* + +I'll abstrain from explaining light, but you may think of it as a small particle, "similar" to an electron, travelling through space. +In fact, Newton understood light to be just that, and called the underlying particle a "corpiscule". +For our purpopses, this approximation will serve us well. + +The distinction that gravity doesn't change the direction or speed of an object "directly" is at upmost importance for physics, since this way we preserve two very important properties of light: it's constant speed and straight travelling path. +However, in our simulation, it would be significantly simpler to assume the opposite, since to an outside observer (like the "player") the difference is indistinguishable. + +Therefore, in our simulation, we'll have light rays, but when they approach a black hole, their speed and direction would change. +This will be determined by some physics equations. + +### Finding a formula + +Now, how do we calculate the exact curvature a black hole produces? +General theory of relativity provides us with the (really complicated) [Einstein field equations](https://en.wikipedia.org/wiki/Einstein_field_equations) for this exact problem. +[Schwartzschild](TODO) solved these equations, assuming that the body with mass doesn't spin[^schwm-assumptions]. +This solution is called the [Schwarzschild metric](https://en.wikipedia.org/wiki/Schwarzschild_metric), and a black hole for which this assumption is true is called a "Shwartzschild black hole". + +The Shwarzschild black hole is the symplest of it's type, so using the Schwarzschild metric should give us the least trouble. +Now, here is the metric in Schwartzschild coordinates: + +![](./img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png) + +**YOUCH!** + +The variables themselves aren't that bad: `c` is the speed of light, τ is time, Ω, `t` and `r` are Schwarzschild coordinates. + +However, as you can see, there are two big problems: we have to calculate derivatives (that's what the `d` signifies) and convert from Schwarzschild coordinates to normal (eucledian) coordinates, that the computer understands natively. +Both of those operations are **incredibly slow**, the average computer doesn't standa a chance at rendering anything in a reasonable amount of time. + +Thankfully [Riccardo Antonelli](http://rantonels.github.io/starless/) was able to do all of our coordinate conversions and simplify the living crap out of that monster (using some approximations with celestial mechanics), turning it into something digestible: + +![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png) + +I will not be trying to explain why or how the Schwarzschild metric and this formula work, that's way way beyond my elementary understanding and the scope of this post. + +Question now is: what do all of those letters represent? +This turned out to be a much harder problem than it should have, I actually had to refer [Ricardo Antonelli's](https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py) and [Dmitry Brant's](https://dmitrybrant.com/2018/12/11/ray-tracing-black-holes) implementation in their projects, alongside copus articles on wikipedia to fully grasp how to put it to work. + +### Applying the formula to "bend" light's path + +Our plan for simulating gravitational lensing is to move the corpiscule by a tiny amount in a certain direction by a certain amount, update the direction and amount according to gravity, rince and repeat. +The direction, alongside the amount by which the particle moves, can be represented with a single vector, which we'll call light's "velocity". + +Referring to the formula again: + +![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png) + +The F→ returns a force vector (`F` for "force" and → for "vector"): any force acting on an object has a strength (magnitude) and a direction. +Imagine you are pushing a box: you are applying some force to it in a "forward" direction. +If you pull the box, you'll apply some force in a "backward" direction. + +This force vector conveys how much and in what direction exactly the black hole is "pulling" on the corpiscule. + +Although the function takes in only one argument, `r`, that doesn't mean that `h` or r\^ aren't also arguments: + +- `r` is the distance from the center of the black hole (the singularity) to the **current** position of the corpiscule. + +- `h` is the magnitude of the ["specific angular momentum"](https://en.wikipedia.org/wiki/Specific_angular_momentum) of the light "particle". + + "Normal" linear momentum specifies how much "force" at what speed it takes to stop (or change) the speed and direction of an object in linear motion (that's why it's in kg\*m/s). + Imagine a big heavy train on a perfectly straight rails going at a fast speed. + How do you forcefully stop it? + + You can put a *really* heavy barrier on the tracks, in front of the train. + Since the train is moving at a really great speed, this barrier will have to be much much heavier (with much more mass) than the train itself. + + Alternatively, you can "launch" something against the train, meaning you can put a second train, moving in the opposite direction of the first train, so they hit head-on. + Since the second train would also be moving, if it's travelling at the same speed and has the same mass as the first train, upon collision they would both stop[^hitting-trains]. + If the second travells at twice the speed, then it can have half of the mass of the first to produce the same effect. + + The property with which we can "prove" why both a larger mass at no speed, and a smaller mass at a faster speed, can stop the train, is the momentum. + + Angular momentum specifies how much "force" at what speed it takes to stop (or change) the speed and directino of a rotating object. + Imagine the train scenario but on a circular track. + + The specific angular momentum is the angular momentum of an object, divided by it's mass. + It's magnitude kind of tells us which property is more prevalent in the momentum, the mass or the speed. + For the same angular momentum, a long (big magnitutde) *specific* angular momentum means our object is small and moves fast, while for a short (small magnitutde) *specific* angular momentum out object is large and moves slowly. + + In our case a light "particle" is being pulled by a stationary object of large mass (a Shwarzschild black hole), so rather than finding the angular momentum[^angular-momentum] and then dividing by the mass[^light-has-no-mass], we'll use another formula: + + ![](./img/specific-angular-momentum-wikipedia.png) + + where **in this specific formula only** `r` is the vector from the center of the big mass (the singularity of the black hole) to the light "particle" and `v` is the velocity (direction and amount of speed) the light is travelling with. + + The cross product returns a vector, so we'll need to take the magnitutde of the result and plug that into the formula. + It's also important that **we calculate it only once, in the beginning**. + So, we shouldn't be calculating the magnitude of the specific angular momentum every time the light "particle" is moved, rather we calculate it once, after it gets close enough to be affected by the black hole. + +- r^ is the normalized ([unit](https://en.wikipedia.org/wiki/Unit_vector), hence the `^` on top) vector from the center of the black hole to the light particle: + + ![](./img/normalize-vector-wikipedia.png) + +Finally, putting all needed variables together in one proper function, we get: + +![Refer to "Antonelli’s formula - explained" in the Appendix](./img/variables-expanded.png) + +As you may notice, this can be simplified, if we substitude r^: + +![Refer to "Antonelli’s formula - simplified" in the Appendix](./img/antonelli-formula-expanded.png) + +In effect, we pass the distance from the black hole to the corpiscule and the function returns how light's velocity changes. + +Finally, we know what to give the formula, and what it will return. +The task at hand is making an algorithm which utilises it. +For that we'll need to get even more familiar with black holes. + +### Properties of a black hole + +As stated, we'll be working with non-rotating stationary black holes, Schwarzschild black holes. +From the [no-hair conjecture](https://en.wikipedia.org/wiki/No-hair_theorem) we know that such a black hole has only three distinct properties: mass, electric charge and angular momentum. +The last one doesn't apply for our case, and the second is irrelevant. + +Meaning, from the mass alone, we can derive the gravitational "forces", alongside three radii, which will be the backbone of our black hole: the event horizon, the photon sphere and [ISCO](https://en.wikipedia.org/wiki/Innermost_stable_circular_orbit). + +The event horizon, also called the Schwarzschild radius, is the distance from the center of the black hole (singularity), which once passed, cannot be passed again (you cannot escape the black hole). +The formula for it is: + +![r_s = (2GM)/(c^2)](./img/Schwarzschild-radius-wikipedia.png) + +where `G` is the [gravitational constant](https://en.wikipedia.org/wiki/Gravitational_constant) and `M` is the mass of the black hole (in kg). + +The photon sphere is the distance from the singularity, in which photons start orbiting the black hole (and can either escape or pass the event horizon). +Formula: + +![r = r_s * 3/2](./img/photon-sphere-wikipedia.png) + +where `G` and `M` are the same as before, `c` is the speed of light in vacuum and rs is the afroementioned Schwarzschild radius. + +Finally, the innermost stable circular orbit (ISCO), formally it's the distance, before which you can orbit the black hole, but once passed, you'll get sucked in and either get shot out or be forever lost past the event horizon. +For our purposes, it's fine to approximate it as the maximum radius after which spacetime isn't bent[^isco] and objects aren't affected. +Formula: + +![](./img/isco-wikipedia.png) + +Putting them all together, we should expect light to travel like this: +![](https://upload.wikimedia.org/wikipedia/commons/2/27/Black_Hole_Shadow.gif) +*Animation by Hugo Spinelli on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=138168679)* + + +### Putting everything together + +Finally, now we have everything we need to divise an algorithm for our light. +For light we'll store two vectors: one for it's position and one for it's velocity. +For a black hole we'll store a vector and a quantity: the position of the black hole's center and it's mass. +For convinience, we could just store the Schwarzschild radius, since all of our radii depend only on it. + +Once the distance between the light and the center is less than or equal to the ISCO, we can begin augmenting light's velocity. +On small steps, we move the light forward a bit with the velocity and then update the velocity with the black hole's pull. + +If light enters the event horizon, then we know it cannot escape, and stop moving it. +If it passes the ISCO then it has left the black hole and will never approach it again. + +If light enters the photon sphere, then we'll have to "track" how long it's been there, if it decides to orbit in a stable manner, then it will stay there indefinetly. +The simplest way to "track" this is just to limit how many times we can move the light forward. + +An algorithm doing this would look a bit like this (in pseudocode, inspired by Python): + +![Refer to "Algorithm" section of the Appendix](./img/algorithm.png) + +as a reminder, here is the definiton of F→: + +![](./img/antonelli-formula-expanded.png) + +## WebGL preparation + +The course was focused on handmade solutions, so some of the logic uses a [custom handmade library](TODO). + +Since the primary component was the shader itself, I made sure to simplify my logic to the absolute minimum. +A **lot** of decisions were made to optimize development time, without considering how good they were. + +In a scene there really are only 3 distinct objects: the stars, the black holes and the skybox. +The latter is just a simple cube, inside which everything resides, if a ray doesn't hit anything of interest, it will hit the cube. +Both stars and black holes are simple spheres, the former with an orange-y color (#f4803b) and any radious. +Black holes aren't rendered and their underlying sphere has the same radius as the ISCO, so their purpose is for intersection checks (more on those when we get to the [shaders](#shaders)). + +Most JavaScript code isn't worth talking about, wherever possible I use the [course library](TODO) and where I can't it's mostly simple WebGL configurations, elementary object "classes" and trivial HTML handling. +Though, there are still two somewhat interesting systems: + +### Scenes + +I wanted to have multiple scenes, with different arrangements of objects and with animations (stars moving around). +For that I devised a dead-simple level loading and animation system. + +An object of type "Level" stores a name, description, location of camera (the viewer) and arrays for stars, black holes and animations. +Though, for creating new levels, you only pass the first three: + +```javascript +var level1 = new Level( + "Star passing behind black hole", // Level title + "The black hole warps the light", // Level description + [1000,0,650]); // Initial coordinates of camera +``` + +Adding stars or black holes requires going through two member functions: `addStar` and `addBlackHole`. +Both take the center of the object, as well as it's radius, alongside an animation function. +The latter has two parameters: current time in TODO(seconds,milliseconds,?) from the beginning and the current object that will be created. +This function is called on each frame with the appropriate arguments, so inside you'll have to "manually" modify the object's properties. + +For example, a simple star going forwards could be added like this (`vecSum` is just [componentwise vector summation](TODO)): + +```javascript +level1.addStar([1070,0,1000], // Coordinates of center + 10, // Radius + (t, star) => vecSum(star.center, [-t,0,0])); // Move from left to right +``` + +Or one which rotates around a point: + +```javascript +var speed = Math.PI / 20, rad = 40; +level1.addStar([1000+rad,0,900], + 3, + (t, star) => vecSum([1000,0,900], [Math.cos(t*speed) * rad, + Math.sin(t*speed) * 5, + Math.sin(t*speed) * rad])); +``` + +For black holes it's the same. +If you want the object to not move, you could just pass `undefined` as the function: + +```javascript +level1.addBlackHole([1000,0,900], 30, undefined); +``` + +### Movement + +It wouldn't be fun without the ability to move around in the scene, so I added a simple system for that too. +WASD moves the camera position forward, left, backward and right, shift moves down and space moves up, all relative to the current direction the camera is looking towards. +Those are all done with relatively simple analytic geometry: we store three vectors, one pointing up, one pointing forward and one pointing left (which can be calculated from the other two with a cross product). +To move forward, add to the position the forward vector times some constant, to move backwards subtract and so on. + +Looking around with the mouse was kinda tricky, since I decided to use [spherical coordinates](TODO). +You store two angles, the "up" and "left" angle, moving the mouse forwards adds to the "up" angle, moving it downwards subtracts and so on. +The tricky part was what to do after + +TODO + +## Shaders + +As a gentle reminder, in OpenGL we have a vertex shader and a fragment shader: + +- The vertex shader is ran on every point of every object in our scene +- The fragment shader is ran on every pixel of your screen, with the added bonus that depending on the pixel, certain values are passed down from the vertex shader. + + This includes interpolated points: a line is made up of two points, the vertex shader is ran on both of them, then the line is interpolated and the fragment shader is ran on each pixel, corresponding to a point on the line. + The vertex shader values are also passed down interpolated, so if one end of the line is the color red, while the other end is green, then the fragment shader corresponding to the pixel, which shows the middle of the line, will have the color yellow. + +### Vertex shader + +As already mentioned, black holes aren't rendered, so the only objects with special rendering are the stars. +To simplify my life, I chose to do a simple [diffusion reflection](https://learnopengl.com/Lighting/Basic-Lighting), with the light source emminating from the camera, something which was already made in lectures: + +![](TODO) + +The result isn't amazing, but you can clearly make out the sphere as a 3D object (not a flat circle). + +### Fragment shader + +This is the meat of our logic, this is where we'll implement our algorithm: + +![](./img/algorithm.png) + +In real life, every star emits light, which then travells some distance, until it reaches our eyes. +However, computing it this way is incredibly inefficient, for every star we'll have to create hundreds or thousands of light rays (corpiscules), most of which probably wont reach us. +We want performance, so this is a no-go. + +The alternative is to do the opposite, assume every pixel was hit by a "ray" and trace back it's steps, if it came out of a star then it has some specific color (it was an actual ray), but if it didn't then show it as black (no ray hit us). +Taking it further, how do we "trace back" those steps? +Well, we can find the precise coordinate of every pixel inside the 3D scene, and move each point in the direction we're looking (though this image is about raytracing, just look at the two top red vectors): + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Ray_trace_diagram.png/800px-Ray_trace_diagram.png?20080214101526) +*Image by Timrb on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=3553478)* + +In the context of computer graphics, this is called [ray marching](TODO). + +Now, how do we detect if the ray hit something? +The dumb way is to move the ray forward a bit and check with every object whether the ray intersects it. +However, since all of our objects are spheres, there is a very easy optimization and simplification - imagine the ray as an infinitely long line and just get the shortest (perpendicular) distance between it and the center of the sphere: + +TODO custom image #1 + +For this we can implement a simple distance function: + +![](https://wikimedia.org/api/rest_v1/media/math/render/svg/42c53741fd3d8765e56ea652369a512a2cd09eac) + +```glsl +float linePointDistance(vec3 a, vec3 n, vec3 p) { + return length((p - a) - dot(p - a, n) * n); +} +``` + +Where `a` is the coordinate of our ray (pixel), `n` is the direction it will be travelling in and `p` is the sphere center we're comparing with. + +However, there is a huge problem: our line extends in both directions, so a check like `linePointDistance(ray, step, center) <= radius` would also detect if the ray interects the point behind us (when ray is going in the opposite direction)! +A very simple solution is to just add a sign to our distance: if positive then the distance is in reference to a point in front, while negative means it's behind. +The simplest way to get this information is by taking the [dot product](TODO) between our "forwards" direction and the direction from our coordinates to the [projection](TODO) of our point on the line: + +TODO custom image #2 + +```glsl +float linePointDistance(vec3 a, vec3 n, vec3 p) { + vec3 projection = dot(p - a, n) * n; + float dist = length((p - a) - projection); + + if (dot(projection, n) < 0.0) return -dist; + return dist; +} +``` + +Since all of our objects are spheres, we can just iterate through all of them and do this check. + +## Appendix + +##### LaTeX source for equations + +The images for my custom LaTeX equations were created on [latexeditor.lagrida.com](https://latexeditor.lagrida.com/), by using Firefox's built-in ability to screenshot HTML nodes, in particular the [MathJax](https://www.mathjax.org/) node with the equation. + +###### Antonelli's formula - explained + +```latex +\begin{align*} + & \overrightarrow{F}(r_l,h) = -\frac{3}{2} \; h^2 \; \frac{\hat{r_l}}{\|r_l\|^5} \quad \text{, where}\\ + & h = \|r_l \cross v_l\|\\ + & \hat{r_l} = \frac{r_l}{\|r_l\|}\\ + & \|x\| = \text{magnitude of }x\\ + & r_l = \text{vector from black hole center to light "particle"}\\ + & v_l = \text{velocity of light "particle"} +\end{align*} +``` + +###### Antonelli's formula - simplified + +```latex +\begin{align*} + & \overrightarrow{F}(r_l,h) = -\frac{3}{2} \; h^2 \; \frac{r_l}{\|r_l\|^6} \quad \text{, where}\\ + & h = \|r_l \cross v_l\| \text{ (calculated right before being affected by black hole)}\\ + & \|x\| = \text{magnitude of }x\\ + & r_l = \text{vector from black hole center to light "particle"}\\ + & v_l = \text{velocity of light "particle"} +\end{align*} +``` + +###### Algorithm + +```latex +\begin{align*} + & p_{cbh} = \text{position of center of black hole}\\ + & r_s = \text{Schwarzchild distance from } p_{cbn} \\ + & r_{ps} = \frac{2}{3}r_s \quad \text{(photon sphere)}\\ + & r_{ISCO} = 3 r_s \\ + \\ + & p_l = \text{position of light "particle"}\\ + & v_l = \text{velocity of light "particle"}\\ + \\ + & r_l = \| p_l-p_{cbh} \| \quad \text{(distance between black hole and light)}\\ + & \text{If } r_l \leq r_{ISCO} : \\ + & \quad h = \| r_l \cross v_l \|\\ + & \quad \text{LightMovesLimit} = \infty \\ + & \quad \text{Repeat maximum LightMovesLimit times}:\\ + & \qquad \text{If } r_l \leq r_s : \\ + & \qquad \quad \text{return "Light never escapes"} \\ + & \qquad \text{If } r_l \leq r_{ps} : \\ + & \qquad \quad \text{LightMovesLimit} = 100 \\ + & \qquad \text{If } r_l > r_{ISCO} : \\ + & \qquad \quad \text{return "Light escaped black hole"} \\ + & \qquad p_l = p_l + v_l \quad \text{(move light)}\\ + & \qquad r_l = \| p_l-p_{cbh} \| \quad \text{(update distance to $p_{cbh}$)}\\ + & \qquad v_l = v_l + \overrightarrow{F}(r_l,h) \quad \text{(update light velocity)} \\ + & \quad \text{return "Light stuck in photon sphere, never escapes"} +\end{align*} +``` + +[^matter-together]: Technically, it's more accurate to say "matter apart", since after the collapse matter is as close together as physically possible, and the nuclear forces keep everything in order but also separated. However, considering the intuitive approach I'm striving for, "matter together" is simpler to understand. +[^parallels-of-latitude]: You might think about the latituginal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest. +[^geodesics-are-local]: This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purpopses. More info can be found on [wikipedia](https://en.wikipedia.org/wiki/Geodesic#Introduction). +[^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](TODO) is zero. These are way outside of my understanding and our purposes, so I skiped them for simplicity. +[^isco]: It's not really true that gravity stopps affecting spacetime after the ISCO, even though things can orbit Earth that doesn't mean that Earth doesn't bend spacetime. However, for the purposes of a simple shader, this assumption produces perfectly useable results. +[^hitting-trains]: Of course, I'm asuming the trains are strong enough they won't break upon the collision. +[^angular-momentum]: Angular momentum is actually [defined using the cross product](https://en.wikipedia.org/wiki/Specific_angular_momentum#Definition) +[^light-has-no-mass]: Actually, light has no mass, so this version of the formula wouldn't work. You might think that makes no sense, since we cannot divide by zero, so the specific angular momentum shouldn't exist, but then with the cross product we find a value for it. You would be correct: Antonelli does some funky approximations, combining Newtonian physics with General theory of relativity, to make the formula that simple. Someone in physics will probably vomit looking at it, but for our purposes it's more than perfect. -- cgit v1.3.1-26-gb76a From 5accc983088aee1e1e45eae706cf3584e43df9aa Mon Sep 17 00:00:00 2001 From: Syndamia Date: Thu, 1 Aug 2024 14:02:11 +0300 Subject: (blog/tpbhs) Rewrote first half of post --- .../index.md | 344 ++++++--------------- 1 file changed, 95 insertions(+), 249 deletions(-) (limited to 'src') diff --git a/src/blog/the-physics-behind-a-black-hole-shader/index.md b/src/blog/the-physics-behind-a-black-hole-shader/index.md index 555744a..a517cdf 100644 --- a/src/blog/the-physics-behind-a-black-hole-shader/index.md +++ b/src/blog/the-physics-behind-a-black-hole-shader/index.md @@ -1,98 +1,136 @@ -# Difficulties of making a black hole shader +# The physics behind a black hole shader ## Contents -1. [Preface](#preface) - 1. [Brief introduction to computer graphics](#brief-introduction-to-computer-graphics) - 2. [Brief introduction to WebGL](#brief-introduction-to-webgl) -2. [Theoretical and algorithmic background](#theoretical-and-algorithmic-background) - 1. [What is a black hole](#what-is-a-black-hole) - 2. [Geodesics, gravity and gravitational lensing](#geodesics-gravity-and-gravitational-lensing) - 3. [Finding a formula](#finding-a-formula) - 4. [Applying the formula to "bend" light's path](#applying-the-formula-to-bend-lights-path) - 5. [Properties of a black hole](#properties-of-a-black-hole) - 6. [Putting everything together](#putting-everything-together) -3. [WebGL preparation](#webgl-preparation) -4. [Shader](#shader) +1. [What do the physics say?](TODO) + 1. [What is gravity?](TODO) + 2. [What does it mean to bend space?](TODO) + 3. [How to solve the EFEs?](TODO) + 4. [What is a black hole?](TODO) +2. [Finding a formula](TODO) +3. [Applying the formula to “bend” light’s path](TODO) + 1. [Properties of a black hole](TODO) +4. [Light-bending algorithm](TODO) 5. [Appendix](#appendix) -Back in August I had to submit a project for an elective WebGL programming course in university. +Back in August 2023 I had to submit a project for an elective WebGL programming course in university. I chose to create an interractive and animated black hole demo. The primary idea was to show how the gravitational pull of black holes "bends" light and how the result looks from different points of view. -During development I found a lot of hurdles, primarily with the actual mathematics behind it. -Information online is difficult to find and understand without having a physics background, so I'll try my best to lay out everything I know. +Then in the December of that same year, I sat down and started writing a blogpost, explaning how some of the more complicated parts were made. +Funnily enough, I started finding errors... a *lot* of errors. + +As it turned out, my implementation was completely wrong, but somehow I fudged the formulas around in just the right way to make it *look* correct. +So the post got delayed and sparsely rejuvenated over the following months. + +For this reason I chose to take up two related electives this year: one on general relativity and one on raytracing, with the hopes of gaining enough understanding of the material to rework the original solution into something proper. + +This article represents the first of a two-part series about this very shader. +Here, we'll talk about physics and how to generally model them. +In the second part, we'll explore raytracing and computer graphics with WebGL. I'll assume you don't know much about physics, but are familiar with mathematics and at the very least vectors. -## Preface +## What do the physics say? + +The "big words" version of what we're going to explore is: + +Using [Einstein's field equations](TODO), we can precisely calculate the curvatures in space(time) at every point around a black hole. +Obviously we're going to use [Schwarzschild metric](TODO) on a (Schwarzschild) black hole. +To further simplify our calculations, we can make approximations using [celestial mechanics](TODO). + +Now, let's try and unravel everything. + +### What is gravity? + +Everything with mass applies a "pulling" force to everything else with mass. +It's easy to see this is true, but we get into trouble when trying to find formula which predict/calculate that pulling force. + +Newton gave it a good shot, with his [3 laws of motion](https://en.wikipedia.org/wiki/Newton%27s_laws_of_motion), which proved to be correct for about a century and a half. +They even helped the discovery of Neptune, since measurements showed that the orbit of Uranus didn't meet expectations if there wasn't another planet meddling with things. +The real crux of the issue came when the same problem occured with [Mercury's orbit](https://en.wikipedia.org/wiki/Mercury_%28planet%29#Advance_of_perihelion), but no new planet was found. + +As it turned out, Newton's formulae had only been approximations, they worked when light (and therefore [causality, or the speed at which changes propagate](https://www.youtube.com/watch?v=msVuCEs8Ydo)) had infinite speed. + +Albert Einstein's general theory of relativity showed that gravity wasn't a "force which pulled", it was actually an effect which **bent** space. +And that only happened because the speed of light wasn't infinite. + +### What does it mean to bend space? + +Think of a flat surface, like a table. +What is the shortest distance between two points? +Obviously, that's a straight line segment. +If you then extend that segment, so it has an infinite length, it becomes a line[^line-definition]. + +[^line-definition]: This is the mathematical definition of a line, obviously in conversation we refer to a line segment as a line. But this distinction will be useful. -### Brief introduction to computer graphics +However, what if our surface isn't flat? +Imagine two points on a sphere, what is the shortest distance between them? +Obviously, it's an arc of a circle and extending it to it's maximum possible length, we get a [great circle](https://en.wikipedia.org/wiki/Great_circle). -Image and video files store visual information in a "fixed" way: you get a huge array of colors, each connected to a particular pixel on your screen. -The objects in those mediums cannot be modified easily, and additions or subtractions are even harder to do, usually requiring an expert using professional tools for hours, days or weeks on end. +![](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Illustration_of_great-circle_distance.svg/480px-Illustration_of_great-circle_distance.svg.png) +*Image by CheCheDaWaff on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=48187293)* -Computer graphics aims to offload a lot of the creator's workload by "generating" the images on the fly using a set of descriptions for our objects. -The idea is to define objects with some primary properties of simpler geometric figures, like the points on a triangle, then give those to the computer, which will in turn have to calculate what the precise color of every pixel in the resultant image should be. +Now, what does it mean to go "forwards"? +On a flat surface, we can define it as "following a (straight) line segment", on our sphere we can say "following an arc of a great circle". -For example, we can represent a tin can (without a label) as a simple cyllinder. -Changing it's height or width is trivial: just change the corresponding property you pass to the computer, and it will handle the rest. +Better yet, in geometry there are [geodesics](TODO), the general term for a curve on any surface which is the shortest[^geodesics-are-local] path between any two points. +So now we can say "going forwards means going along a geodesic". -Of course this system has it's limitations: the more detail you add to an object, the more difficult it is to crunch up the math. -And adding lighting with shadows, bloom, refractions and so on becomes even more demanding for the computer. +[^geodesics-are-local]: This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purpopses. More info can be found on [wikipedia](https://en.wikipedia.org/wiki/Geodesic#Introduction). -Expanding on out tin can example, if you want an image with a tin can up close, with a bright light shining on it, showing the hunderds or thousands of small scratches, bumps and kicks from manufacturing and usage, alongside reflections and shadows, you'll swiftly find that computer graphics are not the correct tool for the job. +It's important to note that an arbitrary geodesic doesn't have most properties you might be used to. +For example, on a flat surface, we can have parallel lines, but on our sphere, great circles will always intersect[^parallels-of-latitude]. -![](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Empty_tin_can2009-01-19.jpg/514px-Empty_tin_can2009-01-19.jpg) -*Image by Sun Ladder on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=5746428)* +[^parallels-of-latitude]: You might think about the latituginal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest. -Such an image contains way way too much detail for the average computer to handle in reasonable time (some small fraction of a second). -However, computer generated graphics are still a very useful tools. -Thats why modern machines come with a graphics card handling *only* graphical tasks (alongside a processor, handling all other tasks like running programs, managing internet traffic, etc.). +Another important effect is that every N-dimentional object can be curved in N+1-dimentions. +Meaning, a 1D line can be bent into a 2D squigle. +A 2D plane can be bent into a 3D curvature. +But what that really means is, for the N-dimentional being, it can view the effects of this change, without begin able to percieve the entire change. -A graphics card is a combination of a special processor (GPU), designed to be able to *only* compute stuff related to graphics, with the upside of doing so much much faster than a general purpose processor (CPU) could, and some memory for use exclusively by that GPU. +Imagine a flatlander, some creature living in a 2D plane, which can only look at thing on the X and Y coordinates. +If we fold this flat plane into a 3D sphere[^sphere-plane-homeomorphism], that creature can calculate the change, but it can't understand or imagine what a 3D sphere is, since it only thinks and percieves in 2D. -Since the GPU is different on the hardware level, it accepts significantly different instructions than a normal processor does. -For this reason programs written for a graphics processing unit are called "shaders", rather than just "programs". +[^sphere-plane-homeomorphism]: In reality, [math shows this cannot be done](https://old.reddit.com/r/math/comments/152kfq/is_it_possible_to_form_a_flat_plane_into_a_sphere/c7iqo6p/) without making important changes to the plane. But this serves as a decent-enough intuitive example. -Of course, higher-level programming languages have been designed, which can then be transformed into the GPU-specific instructions. -But, contrary to normal software development, we don't really have standalone "shader compilers", but graphics library which do the job, alongside TODO +This means the same thing can happen with our 3D space. +It can get bent into a more-complicated 4D shape, we can calculate the exact object and understand it on a mathematical level, but we cannot truly envision it. -### Brief introduction to WebGL +This is what gravity does, it *somehow* changes the curvature of space. +We can't really imagine or see it, but we can understand and work with it in practice as the **bending of our geodesics**. -One of the most popular such libraries is [OpenGL](TODO) with it's associated shader programming languages [GLSL](TODO) and [GLSL ES](TODO). -In the 2000s people decided it would be a good idea to add a graphics API/library to web browsers, which later morphed into what we call today [WebGL](TODO). +The resultant effect is that if you travel perfectly forwards in a spaceship and pass by an object with mass (like a planet) from a close enough distance, your path will be curved, without you steering your ship. -It serves as a "layer above" OpenGL: you write JavaScript code with which the browser tells OpenGL what to do. -You would get a DOM object in which the graphics will be rendered, and a "context" object to which you'll pass down your shaders, shader parameters and change graphics settings. +Einstein gives us the necessary equations for those geodesics, the [Einstein Field Equations](TODO). -## Theoretical and algorithmic background +### How to solve the EFEs? -&&important I haven't formally studied physics, so don't fully trust anything here. - There are most definetly errors, steming from my lackluster understanding. +This problem of not being able to see or imagine 4D space is quite significant, since we have our equations, but it's incredibly difficult to assign them to reality. +Schwartzchild solved them for a universe where there is only one particle with mass in the 1910s, then in the 1960s the equations were solved with one spinning particle with mass, and that's it. -Using [Einstein's field equations](TODO), or to simplify our life, [Schwarzschild's metric](TODO), we can precisely calculate the curvatures in space(time) at every point around a Schwarzschild black hole. -Unfortunetly, the computation would still be too laborious, so we'll need to make an approximation using [celestial mechanics](TODO). +There are plenty of mathematical solutions, but these are the only ones which have been connected to the physical phenomena. +Generally we call a solution a metric, since that's the main mathematical "function" we get. -That is the overall gist of the underlying physics, but I promised an explanation, so let's back up a bit. +That's why we'll work with that initial Schwartzschild metric, which assumed a non-rotating single mass. +And that's what defines Schwartzchild blackholes too. ### What is a black hole -Before we even begin to talk about gravity and light, we need to understand how atoms work. -Imagine a set of marbles, scattered on a table. +Let's imagine atoms as a set of marbles, scattered on a table: ![](https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Marbles_from_Indonesia.jpg/1280px-Marbles_from_Indonesia.jpg) *Image from By Okkisafire on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=30338734)* -Now, start pushing on all of them from the edges of the table to it's center. +Now, start pushing from all sides of the table to it's center. In the beginning, you'll mostly roll them, until they all get in contact with each other. -At that point (assuming they all stay flat on the table), the glass will keep the marbles together, handling your force. +At that point (assuming they all stay flat on the table), the glass will keep the marbles together, it's strength opposing your force. By increasing the force with which you push on them, after a certain threshold, the glass will break, turning the marbles into shards. Those shards will still have some fight in them, so after increasing your force by another level, you'll turn all of those shards into tiny glass granules. A similar occurence happens with atoms. -Normally atoms are spread apart, by pushing them together, at a certain point (ignoring the orbitin electrons) all nuclei will be "touching" and the [nuclar force](TODO) will keep them together. +Normally atoms are spread apart, by pushing them together, at a certain point (ignoring the orbiting electrons) all nuclei will be "touching" and the [nuclar force](TODO) will keep them together. By increasing your pushing force you can overwhelm the nuclear force and "shatter" the nuclei into their subatomic particles. Assuming an enormus explosion doesn't happen, and you can keep increasing your force, it's also possible to overwhelm the "subatomic forces" that keep those subatomic particles "together"[^matter-together]. @@ -106,47 +144,6 @@ That point is called a **black hole**. This object is very bizzare, generally it doesn't have too much properties, but the ones it has are really unique. In my case of computer graphics, the only important part is it's effect on light. -### Geodesics, gravity and gravitational lensing - -To understand how black holes affect light, we first need to understand how black holes affect gravity. - -Think of a flat surface, like a table. -What is the shortest distance between two points? -Obviously, that's a straight line segment. -If you then extend that segment, so it has an infinite length, it becomes a line. - -However, what if our surface isn't flat? -Imagine two points on a sphere, what is the shortest distance between them? -Obviously, it's an arc of a circle and extending it to it's maximum possible length, we get a [great circle](https://en.wikipedia.org/wiki/Great_circle). - -![](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Illustration_of_great-circle_distance.svg/480px-Illustration_of_great-circle_distance.svg.png) -*Image by CheCheDaWaff on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=48187293)* - -Now, what does it mean to go "forwards"? -On a flat surface, we can define it as "following a (straight) line segment", on our sphere we can say "following an arc of a great circle". -But what we really need is a more generalized definition, which handles both of our cases (and more). - -That's why in geometry there is the notion of [geodesics](TODO), the generalized curve on any surface which (roughly speaking) is the shortest[^geodesics-are-local] path between any two points. -On a flat surface, that's the line segment, on the sphere it's the great circle arc. -It's important to note that a general geodesic cannot have most properties you might be used to from "the shortest path between two points". -For example, on a flat surface, we can have parallel lines, but on our sphere, great circles will always intersect[^parallels-of-latitude]. - -And there are a lot more complicated surfaces, imagine a flat surface but with half-spherical "trophs" in it, on the flat segments your geodesic would be the line segment, but on those trophs it will be an arc (of a great circle). -Actually, you don't need to imagine: the entire universe is a 3D surface, which is mostly flat, but has sherical-ish "trophs" in it. - -That's one of the primary results from the General theory of relativity, normally the universe's surface is nice and flat, but objects with mass "produce" gravity, which some sort of a force[^gravity-isnt-a-force] that bends our surface and creates those trophs, changing the local geodesics. -The resultant effect is that if you travel perfectly forwards in a spaceship and pass by an object with mass (like a planet) from a close enough distance, your path will be curved, without you steering your ship. - -Here comes the meat of this section: if you have no outside references (if all planets and stars are invisible), you, in your ship, *wouldn't* really be able to tell your path is curved. -But to a (stationary) outside observer, like another spaceship, it *would* look like you've turned. -In fact, while "turning" it will look like you've slowed down, since an arc is always longer than a straight line segment, but you're travelling at the same speed. - -For the cherry on top, light is also affected by gravity, and we know it's speed is constant and always travels forwards, therefore gravity "bends" light. - - - -The amount by which and the size of the area which is affected depend on that object's mass and size. -Generally, if two objects have the same mass, the bigger one will affect a larger portion of space, but will bend it less, compared to the smaller one, which will affect a smaller portion, which will be bend a lot. Since a black hole is a single infinetly small point, then all of it's mass is concentrated on that point, making it bend a relatively small are of space **a lot**. Strong enough in fact, that if you get too close, you will not be able to overwhelm gravity and "merge" into that infinitessimal point (the white lines are our "geodesics"): @@ -171,7 +168,7 @@ However, in our simulation, it would be significantly simpler to assume the oppo Therefore, in our simulation, we'll have light rays, but when they approach a black hole, their speed and direction would change. This will be determined by some physics equations. -### Finding a formula +## Finding a formula Now, how do we calculate the exact curvature a black hole produces? General theory of relativity provides us with the (really complicated) [Einstein field equations](https://en.wikipedia.org/wiki/Einstein_field_equations) for this exact problem. @@ -199,7 +196,7 @@ I will not be trying to explain why or how the Schwarzschild metric and this for Question now is: what do all of those letters represent? This turned out to be a much harder problem than it should have, I actually had to refer [Ricardo Antonelli's](https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py) and [Dmitry Brant's](https://dmitrybrant.com/2018/12/11/ray-tracing-black-holes) implementation in their projects, alongside copus articles on wikipedia to fully grasp how to put it to work. -### Applying the formula to "bend" light's path +## Applying the formula to "bend" light's path Our plan for simulating gravitational lensing is to move the corpiscule by a tiny amount in a certain direction by a certain amount, update the direction and amount according to gravity, rince and repeat. The direction, alongside the amount by which the particle moves, can be represented with a single vector, which we'll call light's "velocity". @@ -300,8 +297,7 @@ Putting them all together, we should expect light to travel like this: ![](https://upload.wikimedia.org/wikipedia/commons/2/27/Black_Hole_Shadow.gif) *Animation by Hugo Spinelli on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=138168679)* - -### Putting everything together +## Light-bending algorithm Finally, now we have everything we need to divise an algorithm for our light. For light we'll store two vectors: one for it's position and one for it's velocity. @@ -325,154 +321,6 @@ as a reminder, here is the definiton of F→: ![](./img/antonelli-formula-expanded.png) -## WebGL preparation - -The course was focused on handmade solutions, so some of the logic uses a [custom handmade library](TODO). - -Since the primary component was the shader itself, I made sure to simplify my logic to the absolute minimum. -A **lot** of decisions were made to optimize development time, without considering how good they were. - -In a scene there really are only 3 distinct objects: the stars, the black holes and the skybox. -The latter is just a simple cube, inside which everything resides, if a ray doesn't hit anything of interest, it will hit the cube. -Both stars and black holes are simple spheres, the former with an orange-y color (#f4803b) and any radious. -Black holes aren't rendered and their underlying sphere has the same radius as the ISCO, so their purpose is for intersection checks (more on those when we get to the [shaders](#shaders)). - -Most JavaScript code isn't worth talking about, wherever possible I use the [course library](TODO) and where I can't it's mostly simple WebGL configurations, elementary object "classes" and trivial HTML handling. -Though, there are still two somewhat interesting systems: - -### Scenes - -I wanted to have multiple scenes, with different arrangements of objects and with animations (stars moving around). -For that I devised a dead-simple level loading and animation system. - -An object of type "Level" stores a name, description, location of camera (the viewer) and arrays for stars, black holes and animations. -Though, for creating new levels, you only pass the first three: - -```javascript -var level1 = new Level( - "Star passing behind black hole", // Level title - "The black hole warps the light", // Level description - [1000,0,650]); // Initial coordinates of camera -``` - -Adding stars or black holes requires going through two member functions: `addStar` and `addBlackHole`. -Both take the center of the object, as well as it's radius, alongside an animation function. -The latter has two parameters: current time in TODO(seconds,milliseconds,?) from the beginning and the current object that will be created. -This function is called on each frame with the appropriate arguments, so inside you'll have to "manually" modify the object's properties. - -For example, a simple star going forwards could be added like this (`vecSum` is just [componentwise vector summation](TODO)): - -```javascript -level1.addStar([1070,0,1000], // Coordinates of center - 10, // Radius - (t, star) => vecSum(star.center, [-t,0,0])); // Move from left to right -``` - -Or one which rotates around a point: - -```javascript -var speed = Math.PI / 20, rad = 40; -level1.addStar([1000+rad,0,900], - 3, - (t, star) => vecSum([1000,0,900], [Math.cos(t*speed) * rad, - Math.sin(t*speed) * 5, - Math.sin(t*speed) * rad])); -``` - -For black holes it's the same. -If you want the object to not move, you could just pass `undefined` as the function: - -```javascript -level1.addBlackHole([1000,0,900], 30, undefined); -``` - -### Movement - -It wouldn't be fun without the ability to move around in the scene, so I added a simple system for that too. -WASD moves the camera position forward, left, backward and right, shift moves down and space moves up, all relative to the current direction the camera is looking towards. -Those are all done with relatively simple analytic geometry: we store three vectors, one pointing up, one pointing forward and one pointing left (which can be calculated from the other two with a cross product). -To move forward, add to the position the forward vector times some constant, to move backwards subtract and so on. - -Looking around with the mouse was kinda tricky, since I decided to use [spherical coordinates](TODO). -You store two angles, the "up" and "left" angle, moving the mouse forwards adds to the "up" angle, moving it downwards subtracts and so on. -The tricky part was what to do after - -TODO - -## Shaders - -As a gentle reminder, in OpenGL we have a vertex shader and a fragment shader: - -- The vertex shader is ran on every point of every object in our scene -- The fragment shader is ran on every pixel of your screen, with the added bonus that depending on the pixel, certain values are passed down from the vertex shader. - - This includes interpolated points: a line is made up of two points, the vertex shader is ran on both of them, then the line is interpolated and the fragment shader is ran on each pixel, corresponding to a point on the line. - The vertex shader values are also passed down interpolated, so if one end of the line is the color red, while the other end is green, then the fragment shader corresponding to the pixel, which shows the middle of the line, will have the color yellow. - -### Vertex shader - -As already mentioned, black holes aren't rendered, so the only objects with special rendering are the stars. -To simplify my life, I chose to do a simple [diffusion reflection](https://learnopengl.com/Lighting/Basic-Lighting), with the light source emminating from the camera, something which was already made in lectures: - -![](TODO) - -The result isn't amazing, but you can clearly make out the sphere as a 3D object (not a flat circle). - -### Fragment shader - -This is the meat of our logic, this is where we'll implement our algorithm: - -![](./img/algorithm.png) - -In real life, every star emits light, which then travells some distance, until it reaches our eyes. -However, computing it this way is incredibly inefficient, for every star we'll have to create hundreds or thousands of light rays (corpiscules), most of which probably wont reach us. -We want performance, so this is a no-go. - -The alternative is to do the opposite, assume every pixel was hit by a "ray" and trace back it's steps, if it came out of a star then it has some specific color (it was an actual ray), but if it didn't then show it as black (no ray hit us). -Taking it further, how do we "trace back" those steps? -Well, we can find the precise coordinate of every pixel inside the 3D scene, and move each point in the direction we're looking (though this image is about raytracing, just look at the two top red vectors): - -![](https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Ray_trace_diagram.png/800px-Ray_trace_diagram.png?20080214101526) -*Image by Timrb on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=3553478)* - -In the context of computer graphics, this is called [ray marching](TODO). - -Now, how do we detect if the ray hit something? -The dumb way is to move the ray forward a bit and check with every object whether the ray intersects it. -However, since all of our objects are spheres, there is a very easy optimization and simplification - imagine the ray as an infinitely long line and just get the shortest (perpendicular) distance between it and the center of the sphere: - -TODO custom image #1 - -For this we can implement a simple distance function: - -![](https://wikimedia.org/api/rest_v1/media/math/render/svg/42c53741fd3d8765e56ea652369a512a2cd09eac) - -```glsl -float linePointDistance(vec3 a, vec3 n, vec3 p) { - return length((p - a) - dot(p - a, n) * n); -} -``` - -Where `a` is the coordinate of our ray (pixel), `n` is the direction it will be travelling in and `p` is the sphere center we're comparing with. - -However, there is a huge problem: our line extends in both directions, so a check like `linePointDistance(ray, step, center) <= radius` would also detect if the ray interects the point behind us (when ray is going in the opposite direction)! -A very simple solution is to just add a sign to our distance: if positive then the distance is in reference to a point in front, while negative means it's behind. -The simplest way to get this information is by taking the [dot product](TODO) between our "forwards" direction and the direction from our coordinates to the [projection](TODO) of our point on the line: - -TODO custom image #2 - -```glsl -float linePointDistance(vec3 a, vec3 n, vec3 p) { - vec3 projection = dot(p - a, n) * n; - float dist = length((p - a) - projection); - - if (dot(projection, n) < 0.0) return -dist; - return dist; -} -``` - -Since all of our objects are spheres, we can just iterate through all of them and do this check. - ## Appendix ##### LaTeX source for equations @@ -535,10 +383,8 @@ The images for my custom LaTeX equations were created on [latexeditor.lagrida.co ``` [^matter-together]: Technically, it's more accurate to say "matter apart", since after the collapse matter is as close together as physically possible, and the nuclear forces keep everything in order but also separated. However, considering the intuitive approach I'm striving for, "matter together" is simpler to understand. -[^parallels-of-latitude]: You might think about the latituginal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest. -[^geodesics-are-local]: This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purpopses. More info can be found on [wikipedia](https://en.wikipedia.org/wiki/Geodesic#Introduction). -[^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](TODO) is zero. These are way outside of my understanding and our purposes, so I skiped them for simplicity. [^isco]: It's not really true that gravity stopps affecting spacetime after the ISCO, even though things can orbit Earth that doesn't mean that Earth doesn't bend spacetime. However, for the purposes of a simple shader, this assumption produces perfectly useable results. [^hitting-trains]: Of course, I'm asuming the trains are strong enough they won't break upon the collision. [^angular-momentum]: Angular momentum is actually [defined using the cross product](https://en.wikipedia.org/wiki/Specific_angular_momentum#Definition) [^light-has-no-mass]: Actually, light has no mass, so this version of the formula wouldn't work. You might think that makes no sense, since we cannot divide by zero, so the specific angular momentum shouldn't exist, but then with the cross product we find a value for it. You would be correct: Antonelli does some funky approximations, combining Newtonian physics with General theory of relativity, to make the formula that simple. Someone in physics will probably vomit looking at it, but for our purposes it's more than perfect. +[^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](TODO) is zero. These are way outside of my understanding and our purposes, so I skiped them for simplicity. -- cgit v1.3.1-26-gb76a From f0891b5efc6b4fc65c64d4a84b0df08eea3bec0e Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sun, 6 Oct 2024 10:46:08 +0300 Subject: (blog/tpbhs) Completed with wording fixes --- .../index.md | 234 ++++++++++++--------- 1 file changed, 129 insertions(+), 105 deletions(-) (limited to 'src') diff --git a/src/blog/the-physics-behind-a-black-hole-shader/index.md b/src/blog/the-physics-behind-a-black-hole-shader/index.md index a517cdf..2c1084f 100644 --- a/src/blog/the-physics-behind-a-black-hole-shader/index.md +++ b/src/blog/the-physics-behind-a-black-hole-shader/index.md @@ -14,22 +14,22 @@ 5. [Appendix](#appendix) Back in August 2023 I had to submit a project for an elective WebGL programming course in university. -I chose to create an interractive and animated black hole demo. +I chose to create an interactive and animated black hole demo. The primary idea was to show how the gravitational pull of black holes "bends" light and how the result looks from different points of view. -Then in the December of that same year, I sat down and started writing a blogpost, explaning how some of the more complicated parts were made. +Then in the December of that same year, I sat down and started writing a blog post (as you may notice from the "Created" date), explaining how some of the more complicated parts were made. Funnily enough, I started finding errors... a *lot* of errors. As it turned out, my implementation was completely wrong, but somehow I fudged the formulas around in just the right way to make it *look* correct. So the post got delayed and sparsely rejuvenated over the following months. -For this reason I chose to take up two related electives this year: one on general relativity and one on raytracing, with the hopes of gaining enough understanding of the material to rework the original solution into something proper. +For this reason I chose to take up two related electives this year: one on general relativity and one on ray tracing, with the hopes of gaining enough understanding of the material to rework the original solution into something proper. This article represents the first of a two-part series about this very shader. Here, we'll talk about physics and how to generally model them. -In the second part, we'll explore raytracing and computer graphics with WebGL. +In the second part, we'll explore ray tracing and computer graphics with WebGL. -I'll assume you don't know much about physics, but are familiar with mathematics and at the very least vectors. +I'll assume you don't know much about physics, but are familiar with mathematics and at the very least some linear algebra. ## What do the physics say? @@ -39,21 +39,23 @@ Using [Einstein's field equations](TODO), we can precisely calculate the curvatu Obviously we're going to use [Schwarzschild metric](TODO) on a (Schwarzschild) black hole. To further simplify our calculations, we can make approximations using [celestial mechanics](TODO). +This is not *necessary* to understand, but it will make our goal **much** clearer. + Now, let's try and unravel everything. ### What is gravity? Everything with mass applies a "pulling" force to everything else with mass. -It's easy to see this is true, but we get into trouble when trying to find formula which predict/calculate that pulling force. +It's easy to see this is true, but we get into trouble when trying to find a formula which predicts/calculates that force. Newton gave it a good shot, with his [3 laws of motion](https://en.wikipedia.org/wiki/Newton%27s_laws_of_motion), which proved to be correct for about a century and a half. They even helped the discovery of Neptune, since measurements showed that the orbit of Uranus didn't meet expectations if there wasn't another planet meddling with things. -The real crux of the issue came when the same problem occured with [Mercury's orbit](https://en.wikipedia.org/wiki/Mercury_%28planet%29#Advance_of_perihelion), but no new planet was found. +The real crux of the issue came when the same problem occurred with [Mercury's orbit](https://en.wikipedia.org/wiki/Mercury_%28planet%29#Advance_of_perihelion), but no new planet was found. As it turned out, Newton's formulae had only been approximations, they worked when light (and therefore [causality, or the speed at which changes propagate](https://www.youtube.com/watch?v=msVuCEs8Ydo)) had infinite speed. Albert Einstein's general theory of relativity showed that gravity wasn't a "force which pulled", it was actually an effect which **bent** space. -And that only happened because the speed of light wasn't infinite. +And that only happened because the (**constant**) speed of light wasn't infinite. ### What does it mean to bend space? @@ -77,47 +79,48 @@ On a flat surface, we can define it as "following a (straight) line segment", on Better yet, in geometry there are [geodesics](TODO), the general term for a curve on any surface which is the shortest[^geodesics-are-local] path between any two points. So now we can say "going forwards means going along a geodesic". -[^geodesics-are-local]: This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purpopses. More info can be found on [wikipedia](https://en.wikipedia.org/wiki/Geodesic#Introduction). +[^geodesics-are-local]: This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purposes. More info can be found on [Wikipedia](https://en.wikipedia.org/wiki/Geodesic#Introduction). It's important to note that an arbitrary geodesic doesn't have most properties you might be used to. For example, on a flat surface, we can have parallel lines, but on our sphere, great circles will always intersect[^parallels-of-latitude]. -[^parallels-of-latitude]: You might think about the latituginal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest. +[^parallels-of-latitude]: You might think about the latitudinal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest. + +This is what gravity does, it doesn't pull or push, it *bends*, and more precisely, it **bends geodesics**. +Furthermore, we live in three spacial dimensions, so we can move in three *different*[^colinearity] *directions*. -Another important effect is that every N-dimentional object can be curved in N+1-dimentions. -Meaning, a 1D line can be bent into a 2D squigle. -A 2D plane can be bent into a 3D curvature. -But what that really means is, for the N-dimentional being, it can view the effects of this change, without begin able to percieve the entire change. +[^colinearity]: TODO -Imagine a flatlander, some creature living in a 2D plane, which can only look at thing on the X and Y coordinates. -If we fold this flat plane into a 3D sphere[^sphere-plane-homeomorphism], that creature can calculate the change, but it can't understand or imagine what a 3D sphere is, since it only thinks and percieves in 2D. +The resultant effect is that if you travel perfectly forwards in a spaceship and pass by an object with mass (like a planet) from a close enough distance, your path will be curved, without you steering your ship. -[^sphere-plane-homeomorphism]: In reality, [math shows this cannot be done](https://old.reddit.com/r/math/comments/152kfq/is_it_possible_to_form_a_flat_plane_into_a_sphere/c7iqo6p/) without making important changes to the plane. But this serves as a decent-enough intuitive example. +Although not yet mentioned, you need to know that **photons** (light) **don't have mass**! +In effect, in a universe where there is only light bouncing around, Newton's equations still work. -This means the same thing can happen with our 3D space. -It can get bent into a more-complicated 4D shape, we can calculate the exact object and understand it on a mathematical level, but we cannot truly envision it. +On that note, the point that light **doesn't** travel at an infinite speed is significant. +When the opposite is true, General Theory of Relativity collapses into the Newtonian equations! -This is what gravity does, it *somehow* changes the curvature of space. -We can't really imagine or see it, but we can understand and work with it in practice as the **bending of our geodesics**. +Going back on track, Einstein gives us the necessary equations for those geodesics, the [Einstein Field Equations](TODO). -The resultant effect is that if you travel perfectly forwards in a spaceship and pass by an object with mass (like a planet) from a close enough distance, your path will be curved, without you steering your ship. +### How to handle the EFEs? -Einstein gives us the necessary equations for those geodesics, the [Einstein Field Equations](TODO). +Although they're called equations the result/output we get from solving them isn't a number! +It's a function, which *more or less* takes the parameters of objects in the universe and returns *how* they will all behave. +To be more precise, the output isn't *really* a function, it's a "metric", which is a distinctly different mathematical object. -### How to solve the EFEs? +In the 1910s Schwarzschild solved the equations for a universe where there is only one non-rotating[^schwm-assumptions] particle with mass, then in the 1960s the equations were solved when that particle could rotate, that's it. +There are plenty of other mathematical solutions, but we have been able to relate the "real" world to only those two. -This problem of not being able to see or imagine 4D space is quite significant, since we have our equations, but it's incredibly difficult to assign them to reality. -Schwartzchild solved them for a universe where there is only one particle with mass in the 1910s, then in the 1960s the equations were solved with one spinning particle with mass, and that's it. +[^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](TODO) is zero. -There are plenty of mathematical solutions, but these are the only ones which have been connected to the physical phenomena. -Generally we call a solution a metric, since that's the main mathematical "function" we get. +This may sound unsatisfactory, but in practice, it's quite enough. +In the solar system, [>99.86% of mass is in the Sun](TODO), so assuming all other objects are massless, we get enough precision to explain Mercury's orbit. +We can apply the same idea to our simulation, leaving all objects which aren't our black hole without mass. -That's why we'll work with that initial Schwartzschild metric, which assumed a non-rotating single mass. -And that's what defines Schwartzchild blackholes too. +Schwarzschild's metric and accompanying black hole properties are the simplest possible solution, so we'll use that. -### What is a black hole +### What is a black hole? -Let's imagine atoms as a set of marbles, scattered on a table: +Let's imagine atoms as a set of glass marbles, scattered on a table: ![](https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Marbles_from_Indonesia.jpg/1280px-Marbles_from_Indonesia.jpg) *Image from By Okkisafire on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=30338734)* @@ -129,54 +132,56 @@ At that point (assuming they all stay flat on the table), the glass will keep th By increasing the force with which you push on them, after a certain threshold, the glass will break, turning the marbles into shards. Those shards will still have some fight in them, so after increasing your force by another level, you'll turn all of those shards into tiny glass granules. -A similar occurence happens with atoms. -Normally atoms are spread apart, by pushing them together, at a certain point (ignoring the orbiting electrons) all nuclei will be "touching" and the [nuclar force](TODO) will keep them together. -By increasing your pushing force you can overwhelm the nuclear force and "shatter" the nuclei into their subatomic particles. +A similar occurrence happens with atoms. +Normally atoms are spread apart, by pushing them together, at a certain point (ignoring the orbiting electrons) all nuclei will be "touching" and the [nuclear force](TODO) will keep them together. +By further increasing your pushing force you can overwhelm the nuclear force and "shatter" the nuclei into their subatomic particles. -Assuming an enormus explosion doesn't happen, and you can keep increasing your force, it's also possible to overwhelm the "subatomic forces" that keep those subatomic particles "together"[^matter-together]. +Assuming an enormous explosion doesn't happen, and you can keep increasing your force, it's also possible to overwhelm the "subatomic forces" that keep those subatomic particles "together"[^matter-together]. However, those subatomic particles are more commonly referred to as [elementary particles](https://en.wikipedia.org/wiki/Elementary_particle), meaning there are no "granules" into which the elementary particles can break down. -It doesn't make sense if subatomic particles wouldn't be "breakable", since that would require dealing with potentially infinite amounts of force and such an assumption would destroy all of humanity's physics. -Then that leaves us with only one solution: laws of matter break. -If nothing can keep the elementary particles "together", so keep matter "together", then the result is a sort of "collapse", all of that matter just "deflates" into a single, infinetly small point (but the amount of mass isn't infinite, it's the sum of mass from the particles that collapsed). -That point is called a **black hole**. +[^matter-together]: Technically, it's more accurate to say "matter apart", since after the collapse matter is as close together as physically possible, and the nuclear forces keep everything in order but also separated. However, considering the intuitive approach I'm striving for, "matter together" is simpler to understand. + +It's not possible for those particle to be completely unbreakable, since that would mean they could theoretically sustain infinite amounts of force. +Such an assumption is unthinkable. -This object is very bizzare, generally it doesn't have too much properties, but the ones it has are really unique. -In my case of computer graphics, the only important part is it's effect on light. +Then that leaves us with only one solution: laws of matter "break". +If nothing can keep the elementary particles "together", so keep matter "together", then the result is a sort of "collapse", all of that matter just "deflates" into a single, infinitely small point (but the amount of mass isn't infinite, it's the sum of mass from the particles that collapsed). +That point is called a **black hole**. +This object is very bizarre, generally it doesn't have too much properties, but the ones it has are really unique. +In our case, the only important part is it's effect on gravity, and more precisely, light. -Since a black hole is a single infinetly small point, then all of it's mass is concentrated on that point, making it bend a relatively small are of space **a lot**. -Strong enough in fact, that if you get too close, you will not be able to overwhelm gravity and "merge" into that infinitessimal point (the white lines are our "geodesics"): +Since a black hole is a single infinitely small point, then all of it's mass is concentrated on that point, making it alter the geodesics in a relatively small area of space **a lot**. +So much so, if you get too close, you will not be able to overwhelm gravity and "merge" into that infinitesimal point: ![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/CNX_UPhysics_13_07_spacetime.png/800px-CNX_UPhysics_13_07_spacetime.png?20171124170318) +*The white lines are our geodesics* *Image by OpenStax University Physics on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=64307901)* -An interesting effect from gravity is that light (which always travells "forwards", so along a geodesic) also gets "bent", allowing an observer to view otherwise obstructed objects. -We call that [graviational lensing](TODO). -Though not unique to black holes, thats when the effect is strongest: +A fascinating realization is that light always travels along geodesics ("forwards"), therefore this extreme bending allows us to view otherwise obstructed objects. +We call that effect [gravitational lensing](TODO). +Though not unique to black holes, that's when the effect is strongest: ![](https://upload.wikimedia.org/wikipedia/commons/0/02/Gravitational_lens-full.jpg) -*(notice how the gray arrows show the path light travels from a galaxy that is behind (obstructed by) the black hole)* +*Notice how the gray arrows show the path light travels from a galaxy that is behind (obstructed by) the black hole* -I'll abstrain from explaining light, but you may think of it as a small particle, "similar" to an electron, travelling through space. -In fact, Newton understood light to be just that, and called the underlying particle a "corpiscule". -For our purpopses, this approximation will serve us well. +I'll abstain from explaining the specifics of light, but you may think of it as a small particle, "similar" to an electron, travelling through space. +In fact, Newton understood light to be just that, and called the underlying particle a "corpuscle". +This approximation will serve us well. -The distinction that gravity doesn't change the direction or speed of an object "directly" is at upmost importance for physics, since this way we preserve two very important properties of light: it's constant speed and straight travelling path. -However, in our simulation, it would be significantly simpler to assume the opposite, since to an outside observer (like the "player") the difference is indistinguishable. +### What about speed and time? -Therefore, in our simulation, we'll have light rays, but when they approach a black hole, their speed and direction would change. -This will be determined by some physics equations. +Two of the most significant things Einstein's theory shows, which I've left out thus far, is that time is just another point in space (a fourth "spacial" direction in a way) and everything is relative. +Which also signifies that our geodesics are actually four dimensional, or in other words, gravity also bends the observed passage of time! -## Finding a formula +This is relevant for light, since it's speed is constant and it always travels along a geodesic, but to an outside observer it doesn't look that way. +However, in our simulation, we **only** care about how thing look, so it will make our live much simpler if we try to ignore reality wherever we can. -Now, how do we calculate the exact curvature a black hole produces? -General theory of relativity provides us with the (really complicated) [Einstein field equations](https://en.wikipedia.org/wiki/Einstein_field_equations) for this exact problem. -[Schwartzschild](TODO) solved these equations, assuming that the body with mass doesn't spin[^schwm-assumptions]. -This solution is called the [Schwarzschild metric](https://en.wikipedia.org/wiki/Schwarzschild_metric), and a black hole for which this assumption is true is called a "Shwartzschild black hole". +Therefore, to calculate by how much light will move and change, we'll start with the EFEs and then simplify and approximate until we get something useable. + +## Finding a formula -The Shwarzschild black hole is the symplest of it's type, so using the Schwarzschild metric should give us the least trouble. -Now, here is the metric in Schwartzschild coordinates: +Let's get down to business, our starting point, the [Schwarzschild metric](https://en.wikipedia.org/wiki/Schwarzschild_metric), in Schwarzschild coordinates, looks like this: ![](./img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png) @@ -184,36 +189,42 @@ Now, here is the metric in Schwartzschild coordinates: The variables themselves aren't that bad: `c` is the speed of light, τ is time, Ω, `t` and `r` are Schwarzschild coordinates. -However, as you can see, there are two big problems: we have to calculate derivatives (that's what the `d` signifies) and convert from Schwarzschild coordinates to normal (eucledian) coordinates, that the computer understands natively. -Both of those operations are **incredibly slow**, the average computer doesn't standa a chance at rendering anything in a reasonable amount of time. +However, as you can see, there are two big problems: we have to calculate derivatives (that's what the `d` signifies) and convert from Schwarzschild coordinates to normal (euclidean) coordinates, that the computer understands "natively". +This would be **too slow** to render in real time. -Thankfully [Riccardo Antonelli](http://rantonels.github.io/starless/) was able to do all of our coordinate conversions and simplify the living crap out of that monster (using some approximations with celestial mechanics), turning it into something digestible: +Thankfully [Riccardo Antonelli](https://github.com/rantonels) was able to do all of our coordinate conversions and use Newton's ideas to simplify the living crap out of that monster, turning it into something digestible: ![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png) -I will not be trying to explain why or how the Schwarzschild metric and this formula work, that's way way beyond my elementary understanding and the scope of this post. +Explaining his steps and the formula is way beyond the scope of my understanding and this post. +He explains it in more mathematical detail [here](http://spiro.fisica.unipd.it/~antonell/schwarzschild/). + +But now, finally, we can get a plan for our simulation: + +- represent light as particles +- move each particle in a direction and amount specified by the EFE-based formula +- rinse and repeat until the light hits something Question now is: what do all of those letters represent? -This turned out to be a much harder problem than it should have, I actually had to refer [Ricardo Antonelli's](https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py) and [Dmitry Brant's](https://dmitrybrant.com/2018/12/11/ray-tracing-black-holes) implementation in their projects, alongside copus articles on wikipedia to fully grasp how to put it to work. +This turned out to be a much harder problem than it should have, I actually had to refer [Ricardo Antonelli's](https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py) and [Dmitry Brant's](https://dmitrybrant.com/2018/12/11/ray-tracing-black-holes) implementation in their projects, alongside copious articles on Wikipedia to fully grasp how to put it to work. ## Applying the formula to "bend" light's path -Our plan for simulating gravitational lensing is to move the corpiscule by a tiny amount in a certain direction by a certain amount, update the direction and amount according to gravity, rince and repeat. -The direction, alongside the amount by which the particle moves, can be represented with a single vector, which we'll call light's "velocity". +The direction, alongside the amount by which the particle moves, can be represented with a single vector, which we'll call light's velocity. Referring to the formula again: ![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png) -The F→ returns a force vector (`F` for "force" and → for "vector"): any force acting on an object has a strength (magnitude) and a direction. +F→ returns a force vector (`F` for "force" and → for "vector"): any force acting on an object has a strength (magnitude) and a direction. Imagine you are pushing a box: you are applying some force to it in a "forward" direction. If you pull the box, you'll apply some force in a "backward" direction. -This force vector conveys how much and in what direction exactly the black hole is "pulling" on the corpiscule. +This force vector conveys how much and in what direction exactly the black hole is "pulling" on the corpuscle. Although the function takes in only one argument, `r`, that doesn't mean that `h` or r\^ aren't also arguments: -- `r` is the distance from the center of the black hole (the singularity) to the **current** position of the corpiscule. +- `r` is the distance from the center of the black hole (the singularity) to the **current** position of the corpuscle. - `h` is the magnitude of the ["specific angular momentum"](https://en.wikipedia.org/wiki/Specific_angular_momentum) of the light "particle". @@ -226,26 +237,33 @@ Although the function takes in only one argument, `r`, that doesn't mean that `h Alternatively, you can "launch" something against the train, meaning you can put a second train, moving in the opposite direction of the first train, so they hit head-on. Since the second train would also be moving, if it's travelling at the same speed and has the same mass as the first train, upon collision they would both stop[^hitting-trains]. - If the second travells at twice the speed, then it can have half of the mass of the first to produce the same effect. + If the second travels at twice the speed, then it can have half of the mass of the first to produce the same effect. The property with which we can "prove" why both a larger mass at no speed, and a smaller mass at a faster speed, can stop the train, is the momentum. - Angular momentum specifies how much "force" at what speed it takes to stop (or change) the speed and directino of a rotating object. + Angular momentum specifies how much "force" at what speed it takes to stop (or change) the speed and direction of a rotating object. Imagine the train scenario but on a circular track. The specific angular momentum is the angular momentum of an object, divided by it's mass. It's magnitude kind of tells us which property is more prevalent in the momentum, the mass or the speed. - For the same angular momentum, a long (big magnitutde) *specific* angular momentum means our object is small and moves fast, while for a short (small magnitutde) *specific* angular momentum out object is large and moves slowly. - - In our case a light "particle" is being pulled by a stationary object of large mass (a Shwarzschild black hole), so rather than finding the angular momentum[^angular-momentum] and then dividing by the mass[^light-has-no-mass], we'll use another formula: + For the same angular momentum, a long (big magnitude) *specific* angular momentum means our object is small and moves fast, while for a short (small magnitude) *specific* angular momentum out object is large and moves slowly. + Another simplification we need to is **make our black hole stationary**! + Then, rather than finding the angular momentum[^angular-momentum] and dividing by the mass[^light-has-no-mass], we'll use another formula: + ![](./img/specific-angular-momentum-wikipedia.png) - where **in this specific formula only** `r` is the vector from the center of the big mass (the singularity of the black hole) to the light "particle" and `v` is the velocity (direction and amount of speed) the light is travelling with. + where **in this specific formula only** `r` is the vector from the singularity to the corpuscle and `v` is light's velocity. - The cross product returns a vector, so we'll need to take the magnitutde of the result and plug that into the formula. + The cross product returns a vector, so we'll need to take the magnitude of the result and plug that into the formula. It's also important that **we calculate it only once, in the beginning**. So, we shouldn't be calculating the magnitude of the specific angular momentum every time the light "particle" is moved, rather we calculate it once, after it gets close enough to be affected by the black hole. + +[^hitting-trains]: Of course, I'm assuming the trains are strong enough they won't break upon the collision. +[^angular-momentum]: Angular momentum is actually [defined using the cross product](https://en.wikipedia.org/wiki/Specific_angular_momentum#Definition) +[^light-has-no-mass]: As mentioned, light has no mass, so this version of the formula wouldn't work. + You might think that makes no sense, since we cannot divide by zero, so the specific angular momentum shouldn't exist, but then with the cross product we find a value for it. + You would be correct: Antonelli does some funky approximations, combining Newtonian physics with General theory of relativity, to make the formula that simple. - r^ is the normalized ([unit](https://en.wikipedia.org/wiki/Unit_vector), hence the `^` on top) vector from the center of the black hole to the light particle: @@ -255,11 +273,11 @@ Finally, putting all needed variables together in one proper function, we get: ![Refer to "Antonelli’s formula - explained" in the Appendix](./img/variables-expanded.png) -As you may notice, this can be simplified, if we substitude r^: +As you may notice, this can be simplified, if we substitute r^: ![Refer to "Antonelli’s formula - simplified" in the Appendix](./img/antonelli-formula-expanded.png) -In effect, we pass the distance from the black hole to the corpiscule and the function returns how light's velocity changes. +In effect, we pass the distance from the black hole to the corpuscle and the function returns how light's velocity changes. Finally, we know what to give the formula, and what it will return. The task at hand is making an algorithm which utilises it. @@ -267,13 +285,15 @@ For that we'll need to get even more familiar with black holes. ### Properties of a black hole -As stated, we'll be working with non-rotating stationary black holes, Schwarzschild black holes. -From the [no-hair conjecture](https://en.wikipedia.org/wiki/No-hair_theorem) we know that such a black hole has only three distinct properties: mass, electric charge and angular momentum. -The last one doesn't apply for our case, and the second is irrelevant. +To summarize, we're working with a stationary Schwarzschild black hole. +Meaning our black hole has only one property: mass[^no-hair-theorem]. +Everything else can be derived from it. + +[^no-hair-theorem]: The [no-hair theorem](https://en.wikipedia.org/wiki/No-hair_theorem) states that stationary black holes are characterized by only their mass, angular momentum and electric charge. By definition of a Schwarzschild black hole, the last two are null. -Meaning, from the mass alone, we can derive the gravitational "forces", alongside three radii, which will be the backbone of our black hole: the event horizon, the photon sphere and [ISCO](https://en.wikipedia.org/wiki/Innermost_stable_circular_orbit). +There are three radii, which will be the backbone of our black hole: the event horizon, the photon sphere and [ISCO](https://en.wikipedia.org/wiki/Innermost_stable_circular_orbit). -The event horizon, also called the Schwarzschild radius, is the distance from the center of the black hole (singularity), which once passed, cannot be passed again (you cannot escape the black hole). +The event horizon, also called the Schwarzschild radius, is the distance from the singularity, which once passed, nothing can return and escape. The formula for it is: ![r_s = (2GM)/(c^2)](./img/Schwarzschild-radius-wikipedia.png) @@ -285,12 +305,14 @@ Formula: ![r = r_s * 3/2](./img/photon-sphere-wikipedia.png) -where `G` and `M` are the same as before, `c` is the speed of light in vacuum and rs is the afroementioned Schwarzschild radius. +where `G` and `M` are the same as before, `c` is the speed of light in vacuum and rs is the aforementioned Schwarzschild radius. Finally, the innermost stable circular orbit (ISCO), formally it's the distance, before which you can orbit the black hole, but once passed, you'll get sucked in and either get shot out or be forever lost past the event horizon. -For our purposes, it's fine to approximate it as the maximum radius after which spacetime isn't bent[^isco] and objects aren't affected. +For our purposes, it's fine to approximate it as the maximum radius after which space-time isn't bent[^isco] and objects aren't affected. Formula: +[^isco]: It's not really true that gravity stopps affecting spacetime after the ISCO, even though things can orbit Earth that doesn't mean that Earth doesn't bend spacetime. However, for the purposes of a simple shader, this assumption produces perfectly useable results. + ![](./img/isco-wikipedia.png) Putting them all together, we should expect light to travel like this: @@ -299,35 +321,43 @@ Putting them all together, we should expect light to travel like this: ## Light-bending algorithm -Finally, now we have everything we need to divise an algorithm for our light. -For light we'll store two vectors: one for it's position and one for it's velocity. -For a black hole we'll store a vector and a quantity: the position of the black hole's center and it's mass. -For convinience, we could just store the Schwarzschild radius, since all of our radii depend only on it. +Finally, now we have everything we need to devise an algorithm for our simulation. + +- For light we'll store two vectors: one for it's position and one for it's velocity. +- For the black hole we'll store a vector and a quantity: the position of the black hole's center and it's mass. + For convenience, we could just store the Schwarzschild radius, since all of our radii can be expressed only by it. -Once the distance between the light and the center is less than or equal to the ISCO, we can begin augmenting light's velocity. +Once the distance between a corpuscle and the center is less than or equal to the ISCO, we can begin augmenting light's velocity. On small steps, we move the light forward a bit with the velocity and then update the velocity with the black hole's pull. If light enters the event horizon, then we know it cannot escape, and stop moving it. If it passes the ISCO then it has left the black hole and will never approach it again. -If light enters the photon sphere, then we'll have to "track" how long it's been there, if it decides to orbit in a stable manner, then it will stay there indefinetly. +If light enters the photon sphere, then we'll have to "track" how long it's been there, if it decides to orbit in a stable manner, then it will stay there indefinitely. The simplest way to "track" this is just to limit how many times we can move the light forward. An algorithm doing this would look a bit like this (in pseudocode, inspired by Python): ![Refer to "Algorithm" section of the Appendix](./img/algorithm.png) -as a reminder, here is the definiton of F→: +as a reminder, here is the definition of F→: ![](./img/antonelli-formula-expanded.png) +
+ +That's it! +We have all of our theoretical background, formulae and algorithm to start work on our actual program. + +To Be Continued! + ## Appendix -##### LaTeX source for equations +### LaTeX source for equations The images for my custom LaTeX equations were created on [latexeditor.lagrida.com](https://latexeditor.lagrida.com/), by using Firefox's built-in ability to screenshot HTML nodes, in particular the [MathJax](https://www.mathjax.org/) node with the equation. -###### Antonelli's formula - explained +#### Antonelli's formula - explained ```latex \begin{align*} @@ -340,7 +370,7 @@ The images for my custom LaTeX equations were created on [latexeditor.lagrida.co \end{align*} ``` -###### Antonelli's formula - simplified +#### Antonelli's formula - simplified ```latex \begin{align*} @@ -352,7 +382,7 @@ The images for my custom LaTeX equations were created on [latexeditor.lagrida.co \end{align*} ``` -###### Algorithm +#### Algorithm ```latex \begin{align*} @@ -382,9 +412,3 @@ The images for my custom LaTeX equations were created on [latexeditor.lagrida.co \end{align*} ``` -[^matter-together]: Technically, it's more accurate to say "matter apart", since after the collapse matter is as close together as physically possible, and the nuclear forces keep everything in order but also separated. However, considering the intuitive approach I'm striving for, "matter together" is simpler to understand. -[^isco]: It's not really true that gravity stopps affecting spacetime after the ISCO, even though things can orbit Earth that doesn't mean that Earth doesn't bend spacetime. However, for the purposes of a simple shader, this assumption produces perfectly useable results. -[^hitting-trains]: Of course, I'm asuming the trains are strong enough they won't break upon the collision. -[^angular-momentum]: Angular momentum is actually [defined using the cross product](https://en.wikipedia.org/wiki/Specific_angular_momentum#Definition) -[^light-has-no-mass]: Actually, light has no mass, so this version of the formula wouldn't work. You might think that makes no sense, since we cannot divide by zero, so the specific angular momentum shouldn't exist, but then with the cross product we find a value for it. You would be correct: Antonelli does some funky approximations, combining Newtonian physics with General theory of relativity, to make the formula that simple. Someone in physics will probably vomit looking at it, but for our purposes it's more than perfect. -[^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](TODO) is zero. These are way outside of my understanding and our purposes, so I skiped them for simplicity. -- cgit v1.3.1-26-gb76a From fa583c163561fb88240c2a3cddcfb7241e869a72 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sun, 6 Oct 2024 10:53:48 +0300 Subject: [blog/tpbhs] Fixed all TODOs --- .../index.md | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/blog/the-physics-behind-a-black-hole-shader/index.md b/src/blog/the-physics-behind-a-black-hole-shader/index.md index 2c1084f..964b65f 100644 --- a/src/blog/the-physics-behind-a-black-hole-shader/index.md +++ b/src/blog/the-physics-behind-a-black-hole-shader/index.md @@ -2,15 +2,16 @@ ## Contents -1. [What do the physics say?](TODO) - 1. [What is gravity?](TODO) - 2. [What does it mean to bend space?](TODO) - 3. [How to solve the EFEs?](TODO) - 4. [What is a black hole?](TODO) -2. [Finding a formula](TODO) -3. [Applying the formula to “bend” light’s path](TODO) - 1. [Properties of a black hole](TODO) -4. [Light-bending algorithm](TODO) +1. [What do the physics say?](#what-do-the-physics-say) + 1. [What is gravity?](#what-is-gravity) + 2. [What does it mean to bend space?](#what-does-it-mean-to-bend-space) + 3. [How to handle the EFEs?](#how-to-handle-the-EFEs) + 4. [What is a black hole?](#what-is-a-black-hole) + 5. [What about speed and time?](#what-about-speed-and-time) +2. [Finding a formula](#finding-a-formula) +3. [Applying the formula to “bend” light’s path](#applying-the-formula-to-bend-lights-path) + 1. [Properties of a black hole](#properties-of-a-black-hole) +4. [Light-bending algorithm](#light-bending-algorithm) 5. [Appendix](#appendix) Back in August 2023 I had to submit a project for an elective WebGL programming course in university. @@ -35,9 +36,11 @@ I'll assume you don't know much about physics, but are familiar with mathematics The "big words" version of what we're going to explore is: -Using [Einstein's field equations](TODO), we can precisely calculate the curvatures in space(time) at every point around a black hole. -Obviously we're going to use [Schwarzschild metric](TODO) on a (Schwarzschild) black hole. -To further simplify our calculations, we can make approximations using [celestial mechanics](TODO). +Using [Einstein's field equations][EFE], we can precisely calculate the curvatures in space(time) at every point around a black hole. +Obviously we're going to use [Schwarzschild metric](https://en.wikipedia.org/wiki/Schwarzschild_metric) on a (Schwarzschild) black hole. +To further simplify our calculations, we can make approximations using [celestial mechanics](https://en.wikipedia.org/wiki/Celestial_mechanics). + +[EFE]: https://en.wikipedia.org/wiki/Einstein_field_equations This is not *necessary* to understand, but it will make our goal **much** clearer. @@ -76,7 +79,7 @@ Obviously, it's an arc of a circle and extending it to it's maximum possible len Now, what does it mean to go "forwards"? On a flat surface, we can define it as "following a (straight) line segment", on our sphere we can say "following an arc of a great circle". -Better yet, in geometry there are [geodesics](TODO), the general term for a curve on any surface which is the shortest[^geodesics-are-local] path between any two points. +Better yet, in geometry there are [geodesics](https://en.wikipedia.org/wiki/Geodesic), the general term for a curve on any surface which is the shortest[^geodesics-are-local] path between any two points. So now we can say "going forwards means going along a geodesic". [^geodesics-are-local]: This actually isn't completely true, a geodesic is the "locally shortest distance", I've skipped the details since they aren't really that important for our purposes. More info can be found on [Wikipedia](https://en.wikipedia.org/wiki/Geodesic#Introduction). @@ -87,9 +90,7 @@ For example, on a flat surface, we can have parallel lines, but on our sphere, g [^parallels-of-latitude]: You might think about the latitudinal lines on a globe, they are indeed parallel (equidistant), but if you take any two points on the same such line, the distance between them won't be the smallest. This is what gravity does, it doesn't pull or push, it *bends*, and more precisely, it **bends geodesics**. -Furthermore, we live in three spacial dimensions, so we can move in three *different*[^colinearity] *directions*. - -[^colinearity]: TODO +Furthermore, we live in three spacial dimensions, so we can move in three *different directions*. The resultant effect is that if you travel perfectly forwards in a spaceship and pass by an object with mass (like a planet) from a close enough distance, your path will be curved, without you steering your ship. @@ -99,7 +100,7 @@ In effect, in a universe where there is only light bouncing around, Newton's equ On that note, the point that light **doesn't** travel at an infinite speed is significant. When the opposite is true, General Theory of Relativity collapses into the Newtonian equations! -Going back on track, Einstein gives us the necessary equations for those geodesics, the [Einstein Field Equations](TODO). +Going back on track, Einstein gives us the necessary equations for those geodesics, the [Einstein Field Equations][EFE]. ### How to handle the EFEs? @@ -110,10 +111,10 @@ To be more precise, the output isn't *really* a function, it's a "metric", which In the 1910s Schwarzschild solved the equations for a universe where there is only one non-rotating[^schwm-assumptions] particle with mass, then in the 1960s the equations were solved when that particle could rotate, that's it. There are plenty of other mathematical solutions, but we have been able to relate the "real" world to only those two. -[^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](TODO) is zero. +[^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](https://en.wikipedia.org/wiki/Cosmological_constant) is zero. This may sound unsatisfactory, but in practice, it's quite enough. -In the solar system, [>99.86% of mass is in the Sun](TODO), so assuming all other objects are massless, we get enough precision to explain Mercury's orbit. +In the solar system, [>99.86% of mass is in the Sun](https://en.wikipedia.org/wiki/Solar_System), so assuming all other objects are massless, we get enough precision to explain Mercury's orbit. We can apply the same idea to our simulation, leaving all objects which aren't our black hole without mass. Schwarzschild's metric and accompanying black hole properties are the simplest possible solution, so we'll use that. @@ -133,7 +134,7 @@ By increasing the force with which you push on them, after a certain threshold, Those shards will still have some fight in them, so after increasing your force by another level, you'll turn all of those shards into tiny glass granules. A similar occurrence happens with atoms. -Normally atoms are spread apart, by pushing them together, at a certain point (ignoring the orbiting electrons) all nuclei will be "touching" and the [nuclear force](TODO) will keep them together. +Normally atoms are spread apart, by pushing them together, at a certain point (ignoring the orbiting electrons) all nuclei will be "touching" and the [nuclear force](https://en.wikipedia.org/wiki/Nuclear_force) will keep them together. By further increasing your pushing force you can overwhelm the nuclear force and "shatter" the nuclei into their subatomic particles. Assuming an enormous explosion doesn't happen, and you can keep increasing your force, it's also possible to overwhelm the "subatomic forces" that keep those subatomic particles "together"[^matter-together]. @@ -159,7 +160,7 @@ So much so, if you get too close, you will not be able to overwhelm gravity and *Image by OpenStax University Physics on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=64307901)* A fascinating realization is that light always travels along geodesics ("forwards"), therefore this extreme bending allows us to view otherwise obstructed objects. -We call that effect [gravitational lensing](TODO). +We call that effect [gravitational lensing](https://en.wikipedia.org/wiki/Gravitational_lens). Though not unique to black holes, that's when the effect is strongest: ![](https://upload.wikimedia.org/wikipedia/commons/0/02/Gravitational_lens-full.jpg) @@ -411,4 +412,3 @@ The images for my custom LaTeX equations were created on [latexeditor.lagrida.co & \quad \text{return "Light stuck in photon sphere, never escapes"} \end{align*} ``` - -- cgit v1.3.1-26-gb76a From 6fe00c6ec76028fc055084a3398004fbbefac0be Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sun, 6 Oct 2024 10:56:19 +0300 Subject: [blog/tpbhs] Release --- src/blog/index.md | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/blog/index.md b/src/blog/index.md index 4a711c3..435014a 100644 --- a/src/blog/index.md +++ b/src/blog/index.md @@ -4,6 +4,11 @@ Articles detailing personal experiences or exploration of certain topics.
+&&gb 06 Oct   [The physics behind a black hole shader](/blog/the-physics-behind-a-black-hole-shader) +: `Deep dive` | `Physics` | `General theory of relativity` `Celestial mechanics` `Gravity` `Black Hole` `Algorithm` + +#### *2023* + &&gb 30 Aug   [ThinkPad X270 - my favorite machine](/blog/thinkpad-x270-my-favorite-machine) : `Medium dive` | `Review` | `Lenovo` `ThinkPad` `Yoga` -- cgit v1.3.1-26-gb76a