{"id":51653,"date":"2020-06-21T12:58:24","date_gmt":"2020-06-21T10:58:24","guid":{"rendered":"http:\/\/entertainmentengineers.net\/?p=51653"},"modified":"2020-09-08T18:06:45","modified_gmt":"2020-09-08T16:06:45","slug":"liquid-emulation-2","status":"publish","type":"post","link":"https:\/\/entertainmentengineers.net\/?p=51653","title":{"rendered":"Fake liquid shader simulation explained step by step"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<div class=\"is-layout-flex wp-container-4 wp-block-columns alignfull has-black-color has-white-background-color has-text-color has-background\">\n<div class=\"is-layout-flow wp-block-column\" style=\"flex-basis:15%\"><\/div>\n\n\n\n<div class=\"is-layout-flow wp-block-column background: #FFFFFF\" style=\"flex-basis:50%\">\n<p class=\"has-black-color has-white-background-color has-text-color has-background\">This is a bit of a write up and documentation about a shader experiment I did a few weeks ago, so here we go.<br>To recall what this actually looked like, here the original outcome.<\/p>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Liquid emulation\" width=\"520\" height=\"390\" src=\"https:\/\/www.youtube.com\/embed\/SBBMI90svY0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<h4 class=\"has-black-color has-text-color\">Principle<\/h4>\n\n\n\n<p class=\"has-black-color has-text-color\">What you are looking at is not a fluid simulation. <br>That comes to no surprise, as high fidelity simulation of liquids on current consumer graphics hardware at interactive frame rates might still be a couple of years away.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">So what I built is something that emulates the same outcome, based on a whole lot of assumptions and constraints, that will make the result look kinda like it&#8217;s the real thing.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">This write-up is not a step-by-step tutorial, more a train of thought to potentially get your own inspirations going on how to implement a system like this by yourself.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">I&#8217;ve coded this demo in Unity &#8211; it would work in any other platform that allows you to render anything with a custom shader. <br>This shader is used to figure out what color the pixels need to have, when looking at the sphere. That in return is done by a a simple ray marching algorithm to &#8220;look inside the sphere&#8221; to find out.<br>But let&#8217;s start at the beginning.<\/p>\n\n\n\n<h4 class=\"has-black-color has-text-color\">Setup<\/h4>\n\n\n\n<p class=\"has-black-color has-text-color\">Let&#8217;s start with the base shape. <br>My initial inspiration to attempt this came from Ryan Brooks (@shaderbits) amazing tech demo with the <a rel=\"noreferrer noopener\" href=\"https:\/\/twitter.com\/ShaderBits\/status\/1268918230632054784\" target=\"_blank\">liquid in a bottle<\/a>.<br>But I did not find myself with a lot of spare time, so I swapped the more complex bottle shape to something that is analytically simplifying all the steps that have to follow later. <br>I made the glass container to be a sphere.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/bottle_sphere-1024x1024.jpg\" alt=\"\" class=\"wp-image-51654\" width=\"520\" height=\"520\" srcset=\"https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/bottle_sphere.jpg 1024w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/bottle_sphere-300x300.jpg 300w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/bottle_sphere-150x150.jpg 150w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/bottle_sphere-768x768.jpg 768w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/bottle_sphere-400x400.jpg 400w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/bottle_sphere-800x800.jpg 800w\" sizes=\"(max-width: 520px) 100vw, 520px\" \/><figcaption>Figure 1: spheres are easier to analytically express than bottles<\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"has-black-color has-text-color\">Finding where the sphere is at and its dimensions &#8211; easy. It&#8217;s just defined by a position and a radius.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">Knowing if you are inside or outside &#8211; also easy. <br>Any point which is further apart from the center than the radius, is outside.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/sphere-1-1024x1024.jpg\" alt=\"\" class=\"wp-image-51655\" width=\"520\" height=\"520\" srcset=\"https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/sphere-1.jpg 1024w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/sphere-1-300x300.jpg 300w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/sphere-1-150x150.jpg 150w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/sphere-1-768x768.jpg 768w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/sphere-1-400x400.jpg 400w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/sphere-1-800x800.jpg 800w\" sizes=\"(max-width: 520px) 100vw, 520px\" \/><figcaption>Figure 2: all that&#8217;s needed to know everything important about a sphere<\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"has-black-color has-text-color\">The actual render shape of the sphere is&#8230; well&#8230; a sphere. <br>Since I am using unity, it&#8217;s just a game object with the default sphere mesh. Anything interesting will happen inside of that.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">Just plugging the default shader, you get &#8211; no surprises here &#8211; a solidly shaded sphere.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/shadedsphere-1.jpg\" alt=\"\" class=\"wp-image-51657\" width=\"520\" height=\"482\" srcset=\"https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/shadedsphere-1.jpg 894w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/shadedsphere-1-300x279.jpg 300w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/shadedsphere-1-768x713.jpg 768w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/shadedsphere-1-400x371.jpg 400w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/shadedsphere-1-800x743.jpg 800w\" sizes=\"(max-width: 520px) 100vw, 520px\" \/><figcaption>Figure 3: a sphere with a standard shader<\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"has-black-color has-text-color\">Now looking at this a little closer, what is actually happening is this:<br>The render engine rasterizes the surface of the sphere mesh through the camera view. We end up with every pixel that is covering the sphere being shaded by its material shader &#8211; which by default is usually some matte solid gray.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">The following image shows all the interesting bits involved in that process.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"886\" src=\"http:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/spherelookat.jpg\" alt=\"\" class=\"wp-image-51658\" srcset=\"https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/spherelookat.jpg 1024w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/spherelookat-300x260.jpg 300w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/spherelookat-768x665.jpg 768w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/spherelookat-400x346.jpg 400w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/spherelookat-800x692.jpg 800w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Figure 4: Camera rasterizing schematic<\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"has-black-color has-text-color\">Now I won&#8217;t go into all the details that are involved with an entire rasterizer pipeline. There is plenty of reading on the internet, that will explain it at length a lot better than I can scribble down here.<br>But in essence our problem boils down to what color we should give those pixels in Figure 4, so the sphere looks from our camera as if it&#8217;s transparent with something inside of it that resembles a sloshing liquid.<\/p>\n\n\n\n<h4 class=\"has-black-color has-text-color\">Emulated Liquid<\/h4>\n\n\n\n<p class=\"has-black-color has-text-color\">Before we &#8211; quite literally &#8211; peek into the sphere, let&#8217;s talk about emulating a liquid. What we are after is a function, that tells us if a point inside the sphere is either part of the liquid or not. <\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">First step for this is to establish a flat liquid level, that tells us how much liquid is inside the container.<br>Any point below the liquid level will be inside of the liquid, any point above is outside.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">There are a few things we can assume about how any liquid behaves, when trapped in a glass ball. <br>It will naturally slosh around with the <em>momentum <\/em>of the movement of its container but will <em>dampen <\/em>down and level out again after being static for a while.<br>To emulate <em>momentum <\/em>and <em>dampening <\/em>I went and implemented a little imaginary pendulum.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"886\" src=\"http:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/pendulum.jpg\" alt=\"\" class=\"wp-image-51667\" srcset=\"https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/pendulum.jpg 1024w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/pendulum-300x260.jpg 300w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/pendulum-768x665.jpg 768w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/pendulum-400x346.jpg 400w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/pendulum-800x692.jpg 800w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Figure 5: simple pendulum setup<\/figcaption><\/figure>\n\n\n\n<p class=\"has-black-color has-text-color\">This pendulum constantly evaluates and with every movement of the container in my game setup, I pull out the imaginary ball from its rest point by applying an imaginary force in the opposite direction.<br>So moving the container will pull it out and over time it will swing back and forth until coming to rest.<br>Luckily the math of pendulums isn&#8217;t very hard, so I&#8217;d refer you to the details somewhere on YouTube.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">For keeping it simple, I left the pendulum to be a simple 2D representation, so a single angular value \u03b8 tells me how far it&#8217;s away from it&#8217;s equilibrium. <br>This is the first property driving my shader, which schematically looks kinda like this.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"598\" src=\"http:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/slosh.jpg\" alt=\"\" class=\"wp-image-51668\" srcset=\"https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/slosh.jpg 1024w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/slosh-300x175.jpg 300w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/slosh-768x449.jpg 768w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/slosh-400x234.jpg 400w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/slosh-800x467.jpg 800w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Figure 6: schematic how pendulum motion drives liquid oscillation<\/figcaption><\/figure>\n\n\n\n<p class=\"has-black-color has-text-color\">It happens that the sloshing liquid itself seems to be somewhat related to the direction of the container&#8217;s movement as well. <br>If I move the container left\/right, the liquid sloshes right\/left. If I move it forward\/back, the container moves back\/forward. See that the sloshing always happens around an axis perpendicular to the movement direction. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"589\" src=\"http:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/3dslosh.jpg\" alt=\"\" class=\"wp-image-51669\" srcset=\"https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/3dslosh.jpg 1024w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/3dslosh-300x173.jpg 300w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/3dslosh-768x442.jpg 768w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/3dslosh-400x230.jpg 400w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/3dslosh-800x460.jpg 800w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Figure 7: sloppy attempt to visualize forward movement causing slosh in sideways axis and sideways <br>movement in respective forward axis<\/figcaption><\/figure>\n\n\n\n<p class=\"has-black-color has-text-color\">I capture this in a second property with an accumulated and slightly dampened velocity of the container.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">Now looking at liquids in containers, we kinda notice that apart from the momentum and the dampening, the movement &#8211; while complex &#8211; is also somewhat nondescript and &#8211; well &#8211; &#8220;sloshy&#8221;. There is so much physics going on, that the actual shape is increasingly indiscernible the more it moves.<br>This we can turn to our advantage to add the last missing part to the surface description, some liquid-esk surface distortion.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">To emulate this distorted liquid surface, I just stacked a bunch of trigonometric functions on top of each other. In this case I used three.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"455\" src=\"http:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/layered-1024x455.jpg\" alt=\"\" class=\"wp-image-51670\" srcset=\"https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/layered-1024x455.jpg 1024w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/layered-300x133.jpg 300w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/layered-768x341.jpg 768w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/layered-400x178.jpg 400w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/layered-800x355.jpg 800w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/layered.jpg 1240w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Figure 8: three layers of liquidy slosh distortion<\/figcaption><\/figure>\n\n\n\n<p class=\"has-black-color has-text-color\">The first layer is a basic sinus function across the world position in x and z.<br>The second layer is also a sinus function with a higher frequency for some smaller ripples.<br>The third layer is a sinus function based on the distance to the center of the sphere. This makes it look a little like there are tiny waves bouncing off its sides.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">The involved base frequencies and amplitudes for those functions are literally magic numbers that I obtained with good old trial and error until I liked the result (and ran out of time). <br>Not to forget that their amplitude is multiplied by the speed of motion\/extend of pendulum angle, to make large movements make large waves and vice versa.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">All three functions also have a time-based offsets, to make the waves evolve over time. So the current game time is another property used by the shader.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">The liquid level, the pendulum and movement based sloshing as well as the fake stack of waves all contribute to a function called <em>liquid(&#8230;)<\/em>, which returns the height of the liquid at any given world position. No magic happens there, it&#8217;s really just the sum of all the contributing parts.<\/p>\n\n\n\n<h4 class=\"has-black-color has-text-color\">Raymarching<\/h4>\n\n\n\n<p class=\"has-black-color has-text-color\">We now know all about our sphere and we can analytically describe how the liquid looks on its inside.<br>We have a value that tells us how much the liquid is sloshing (<em>pendulum angle<\/em>) and also which direction the movement of the container goes (<em>container velocity<\/em>).<br>So lets look how we figure out how to make use of that.<\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">At the core of the shader is something called a ray marcher. <br>It&#8217;s a common principle &#8211; again Google will help, but essentially I&#8217;m following the gaze of the camera through the rasterized pixel into the inside of the sphere.<br>Luckily a sphere is wonderfully simple to ray march, as we can find the in and out point reliably and fast, and keep the number of steps reasonable.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"607\" src=\"http:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/raymarch-1024x607.jpg\" alt=\"\" class=\"wp-image-51672\" srcset=\"https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/raymarch-1024x607.jpg 1024w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/raymarch-300x178.jpg 300w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/raymarch-768x456.jpg 768w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/raymarch-400x237.jpg 400w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/raymarch-800x475.jpg 800w, https:\/\/entertainmentengineers.net\/wp-content\/uploads\/2020\/06\/raymarch.jpg 1224w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Figure 9: ray marching the liquid sphere, green is inside the liquid, red outside. <\/figcaption><\/figure>\n\n\n\n<p class=\"has-black-color has-text-color\">As shown in the picture we are marching along the view ray from the camera through the fragment position into the volume of the sphere.<br>Each point on the way we are evaluating our liquid function to find out if we have crossed over from the outside to the inside of the liquid. <br>If we have so, then we have hit our actual surface. Bingo!<br>In case your liquid is not see-through (which is easier!) &#8211; you can stop here. Otherwise there is a bit of logic needed to define how transparent the liquid is and how to accumulate that density over distance while stepping all the way to the other end of the sphere.<br>The last thing missing is to sample the surroundings of the first hit point to calculate a new normal to use for the actual surface shading part that calculates lights etc.<\/p>\n\n\n\n<h4 class=\"has-black-color has-text-color\">Conclusion<\/h4>\n\n\n\n<p class=\"has-black-color has-text-color\">Well I do those things from time to time, when i get inspired by something that I find in one of the many streams of the internet &#8211; and try it out myself just to wrap my head around what&#8217;s involved. <\/p>\n\n\n\n<p class=\"has-black-color has-text-color\">The main learnings from this excercise are the interesting amount of hackery you can get away with in a system like this, as well as some more boilerplate insights in coding surface shaders with to be used in Unity.<br>I hope this write-up was somewhat informative, if you have any questions\/commentary or want more of this kind of write-ups, please hit me up on twitter <a rel=\"noreferrer noopener\" href=\"https:\/\/twitter.com\/richterteer\" target=\"_blank\">@richterteer<\/a>.<br>And now, slosh, slosh away!<\/p>\n<\/div>\n\n\n\n<div class=\"is-layout-flow wp-block-column\" style=\"flex-basis:15%\"><\/div>\n<\/div>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a bit of a write up and documentation about a shader experiment I did a few weeks ago, so here we go.To recall what this actually looked like, here the original outcome. Principle What you are looking at is not a fluid simulation. That comes to no surprise, as high fidelity simulation of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":51657,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"cybocfi_hide_featured_image":"yes"},"categories":[14],"tags":[16,21,15],"_links":{"self":[{"href":"https:\/\/entertainmentengineers.net\/index.php?rest_route=\/wp\/v2\/posts\/51653"}],"collection":[{"href":"https:\/\/entertainmentengineers.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/entertainmentengineers.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/entertainmentengineers.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/entertainmentengineers.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=51653"}],"version-history":[{"count":13,"href":"https:\/\/entertainmentengineers.net\/index.php?rest_route=\/wp\/v2\/posts\/51653\/revisions"}],"predecessor-version":[{"id":51681,"href":"https:\/\/entertainmentengineers.net\/index.php?rest_route=\/wp\/v2\/posts\/51653\/revisions\/51681"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/entertainmentengineers.net\/index.php?rest_route=\/wp\/v2\/media\/51657"}],"wp:attachment":[{"href":"https:\/\/entertainmentengineers.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=51653"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/entertainmentengineers.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=51653"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/entertainmentengineers.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=51653"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}