{"id":1464,"date":"2024-11-11T00:23:48","date_gmt":"2024-11-10T15:23:48","guid":{"rendered":"https:\/\/heyyocg.link\/?p=1464"},"modified":"2024-11-11T00:23:49","modified_gmt":"2024-11-10T15:23:49","slug":"ue4-26-niagara-adavanced-simulation-stage-basic","status":"publish","type":"post","link":"https:\/\/heyyocg.link\/en\/ue4-26-niagara-adavanced-simulation-stage-basic\/","title":{"rendered":"Niagara Advanced Guide &#8211; Basics of the Simulation Stage"},"content":{"rendered":"\n<p>Epic Games distributes a project called &#8220;Content Examples,&#8221; which is a collection of various sample projects showcasing different features of Unreal Engine. Since UE4.26, there is a map called <em>Niagara Advanced<\/em>.<\/p>\n\n\n\n<p>This map contains a wealth of useful samples, including examples of new Niagara features and practical applications. Upon reviewing the implementations, there&#8217;s a lot to learn.<\/p>\n\n\n\n<p>This article will break down these samples into multiple parts for detailed explanations.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"621\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2024\/11\/image-2-1024x621.png\" alt=\"\" class=\"wp-image-1466\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2024\/11\/image-2-1024x621.png 1024w, https:\/\/heyyocg.link\/wp-content\/uploads\/2024\/11\/image-2-300x182.png 300w, https:\/\/heyyocg.link\/wp-content\/uploads\/2024\/11\/image-2-768x466.png 768w, https:\/\/heyyocg.link\/wp-content\/uploads\/2024\/11\/image-2-1536x932.png 1536w, https:\/\/heyyocg.link\/wp-content\/uploads\/2024\/11\/image-2-2048x1242.png 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>By the way, <em>Content Examples<\/em> can be downloaded from <a href=\"https:\/\/www.fab.com\/listings\/4d251261-d98c-48e2-baee-8f4e47c67091\">this link<\/a> in Fab. Please note that the content may vary depending on the version of UE.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">TLDR;)<\/h2>\n\n\n\n<ul>\n<li>The Simulation Stage is like a &#8220;Particle Update that can iterate within a single frame.<\/li>\n\n\n\n<li>The Simulation Stage can process not only particles but also specific Data Interfaces.<\/li>\n\n\n\n<li>The Simulation Stage is a fundamental feature, so how you use it is what matters.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p>In this article, I will provide a basic explanation of a new feature called <em>Simulation Stage<\/em> added since UE4.26, based on the &#8220;1.1 Simulation Stage Fill Render Target&#8221; sample from <em>Niagara Advanced<\/em>.<\/p>\n\n\n\n<p>The Simulation Stage is a core feature used in many other samples in <em>Niagara Advanced<\/em>. The concept itself is simple, but its use cases are important. First, let&#8217;s focus on understanding what the Simulation Stage is.<\/p>\n\n\n\n<p>\u203b Note: this article is written with UE4.26 Content Example data. So it might differ from the latest version of UE at some point, but the basic concept of the Simulation Stage must be the same.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is the Simulation Stage?<\/h2>\n\n\n\n<p>Simply put, the Simulation Stage is &#8220;a Particle Update that can iterate multiple times within a single frame.&#8221; It allows you to run the specified process multiple times within one frame.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img decoding=\"async\" width=\"600\" height=\"400\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/repeat.jpg\" alt=\"\" class=\"wp-image-308\" style=\"width:300px;height:200px\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/repeat.jpg 600w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/repeat-300x200.jpg 300w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/figure>\n\n\n\n<p>Before UE4.26, iterating processes required writing HLSL code inside the Scratch Pad or using the experimental &#8220;Map For&#8221; node. Now, this is much simpler to implement, and it is even possible to use existing Particle Update modules within iterative processes.<\/p>\n\n\n\n<p>What\u2019s innovative about the Simulation Stage is that it allows not only Particle updates but also processing on specific Data Interfaces, such as a 2D Render Target.<\/p>\n\n\n\n<p>Although we don\u2019t yet know all the possible Data Interfaces, such as Grid2D Collection, that can be used in this context, the potential seems infinite depending on the types of Data Interfaces available.<\/p>\n\n\n\n<p>For Unity users, this might feel somewhat similar to how Compute Shaders are implemented in Visual Effect Graph, but note that they are GPU-accelerated and can only be used in GPU Sim mode.<\/p>\n\n\n\n<p>Now that we\u2019ve covered the concept of the Simulation Stage, let&#8217;s take a look at a specific example from the <em>Niagara Advanced<\/em> &#8220;1.1 Simulation Stage Fill Render Target&#8221; sample to understand it better.<\/p>\n\n\n\n<p>At a glance, here are the key points to remember about the Simulation Stage:<\/p>\n\n\n\n<ol>\n<li>It allows for repeated processing within a single frame.<\/li>\n\n\n\n<li>It can be used to process not only particles but also specific Data Interfaces.<\/li>\n\n\n\n<li>It is only available in GPU Sim mode.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">1.1 Simulation Stage Fill Render Target Explanation<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"838\" height=\"458\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_01.png\" alt=\"\" class=\"wp-image-282\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_01.png 838w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_01-300x164.png 300w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_01-768x420.png 768w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_01-816x446.png 816w\" sizes=\"(max-width: 838px) 100vw, 838px\" \/><\/figure>\n\n\n\n<p>This is the first sample in the <em>Niagara Advanced<\/em> map.<\/p>\n\n\n\n<p>At first glance, it may seem like just a Sprite with a Texture applied, but internally, it uses the Simulation Stage to fetch the color of each texel from the texture and write it to a 2D Render Target. This Render Target is then passed to a Material for rendering.<\/p>\n\n\n\n<p>Let\u2019s dive into the details.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"246\" height=\"469\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_02.png\" alt=\"\" class=\"wp-image-284\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_02.png 246w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_02-157x300.png 157w\" sizes=\"(max-width: 246px) 100vw, 246px\" \/><\/figure>\n\n\n\n<p>When you open the <em>FillRenderTarget<\/em> Niagara System, you&#8217;ll see an emitter called <em>EmitterLevelSpriteRenderer<\/em>. The setup is simple: it initializes several variables and performs processing in a single Simulation Stage.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"502\" height=\"791\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_03-1.png\" alt=\"\" class=\"wp-image-286\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_03-1.png 502w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_03-1-190x300.png 190w\" sizes=\"(max-width: 502px) 100vw, 502px\" \/><\/figure>\n\n\n\n<p>To enable the Simulation Stage, switch to GPU Sim in the Emitter Properties, check <em>Fixed Bounds<\/em>, and also check <em>Enable Simulation Stages (Experimental GPU Only)<\/em> under the Simulation Stages section.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"528\" height=\"576\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_04.png\" alt=\"\" class=\"wp-image-287\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_04.png 528w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_04-275x300.png 275w\" sizes=\"(max-width: 528px) 100vw, 528px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"523\" height=\"212\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_05.png\" alt=\"\" class=\"wp-image-288\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_05.png 523w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_05-300x122.png 300w\" sizes=\"(max-width: 523px) 100vw, 523px\" \/><\/figure>\n\n\n\n<p>The Emitter Spawn and Emitter Update initialize the Position, Texture Sample, Render Target 2D, and Sprite Size. The Sprite Size is initialized in Emitter Update, but it could also be done in Emitter Spawn without issue.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"333\" height=\"124\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_06.png\" alt=\"\" class=\"wp-image-289\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_06.png 333w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_06-300x112.png 300w\" sizes=\"(max-width: 333px) 100vw, 333px\" \/><\/figure>\n\n\n\n<p>To add the Simulation Stage, click the plus sign next to <em>Add Simulation Stage<\/em> and choose <em>Generic Simulation Stage<\/em>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"483\" height=\"215\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_07.png\" alt=\"\" class=\"wp-image-290\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_07.png 483w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_07-300x134.png 300w\" sizes=\"(max-width: 483px) 100vw, 483px\" \/><\/figure>\n\n\n\n<p>In the <em>Iteration Source<\/em> dropdown, you can select either Particle or Data Interface. Since this example involves writing to a Render Target 2D, you choose Render Target 2D as the Data Interface.<\/p>\n\n\n\n<p><em>Iterations<\/em> defines the number of iterations to perform.<\/p>\n\n\n\n<p>Check <em>Emitter Reset Only<\/em> if you want the processing to occur only during the first frame when the Emitter is reset.<\/p>\n\n\n\n<p>The name you enter in <em>Simulation Stage Name<\/em> will appear as the stack&#8217;s name.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"277\" height=\"100\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_08.png\" alt=\"\" class=\"wp-image-291\"\/><\/figure>\n\n\n\n<p>C<em>opy Texture To Render Target<\/em> is just a renamed Scratch Pad module. Let\u2019s double-click to explore its contents.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"348\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_09-1024x348.png\" alt=\"\" class=\"wp-image-292\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_09-1024x348.png 1024w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_09-300x102.png 300w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_09-768x261.png 768w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_09-816x277.png 816w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_09.png 1036w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"831\" height=\"664\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_10.png\" alt=\"\" class=\"wp-image-293\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_10.png 831w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_10-300x240.png 300w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_10-768x614.png 768w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_10-816x652.png 816w\" sizes=\"(max-width: 831px) 100vw, 831px\" \/><\/figure>\n\n\n\n<p>The inputs are Render Target 2D and Texture Sample. Here, the important part is the <em>Execution Index<\/em>. Since we\u2019ve set Render Target 2D as the Data Interface, the Execution Index corresponds to the texel index of the 2D Render Target. Since we initialized the Render Target 2D with a 512&#215;512 size, the Execution Index will range from 0 to 262,143.<\/p>\n\n\n\n<p>We then use <em>Linear to Index<\/em> to map the 0-262,143 range into 2D indices like (0,0), (0,1), (511,510), and (511,511).<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"832\" height=\"336\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_11.png\" alt=\"\" class=\"wp-image-294\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_11.png 832w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_11-300x121.png 300w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_11-768x310.png 768w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_11-816x330.png 816w\" sizes=\"(max-width: 832px) 100vw, 832px\" \/><\/figure>\n\n\n\n<p>Next, we use <em>Get Render Target Size<\/em> to obtain the width and height of the 2D Render Target, and divide the 2D indices to convert it into UV values ranging from 0 to 1 (Although (0.5, 0.5) is added, this is incorrect, so it&#8217;s more accurate without it. It&#8217;s just a small error, so it shouldn&#8217;t cause much of an issue). <\/p>\n\n\n\n<p>Then we sample the texture at those UV values using <em>Sample Texture 2D<\/em> to retrieve the color information of each texel.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"668\" height=\"374\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_12.png\" alt=\"\" class=\"wp-image-295\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_12.png 668w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_12-300x168.png 300w\" sizes=\"(max-width: 668px) 100vw, 668px\" \/><\/figure>\n\n\n\n<p>Finally, the color information is written back to the corresponding texels of the Render Target 2D.<\/p>\n\n\n\n<p>At this point, the Texture Sample has been successfully copied to the Render Target 2D.<\/p>\n\n\n\n<p>Next, this Render Target 2D is passed to a Material, but there&#8217;s a new feature in UE4.26 related to this.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"458\" height=\"574\" src=\"http:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_13.png\" alt=\"\" class=\"wp-image-297\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_13.png 458w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_13-239x300.png 239w\" sizes=\"(max-width: 458px) 100vw, 458px\" \/><\/figure>\n\n\n\n<p>In the <em>Sprite Renderer<\/em>\u2019s <em>Bindings<\/em> section, you\u2019ll see an option called <em>Material Parameter Bindings<\/em>. This allows you to assign values to parameters exposed by the Material.<\/p>\n\n\n\n<p>You might think, &#8220;Does this mean we don\u2019t need Dynamic Parameters anymore?&#8221; However, it seems that this can only be used for Emitter or System attributes, so if you want to change values per Particle (like per-particle color), you\u2019ll still need to use Dynamic Parameters.<\/p>\n\n\n\n<p>In any case, here we use it to pass the Render Target 2D to the Material. The Material\u2019s processing is straightforward, as it simply displays the received texture.<\/p>\n\n\n\n<p>Now, one thing we haven\u2019t discussed yet is why the sprite is displayed even though no particles are emitted. This is another new feature in UE4.26: you can now display particles based on Emitter information.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"443\" height=\"90\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_14-1.png\" alt=\"\" class=\"wp-image-299\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_14-1.png 443w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_14-1-300x61.png 300w\" sizes=\"(max-width: 443px) 100vw, 443px\" \/><\/figure>\n\n\n\n<p>If you look closely, you\u2019ll see that the number of particles is set to 0.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"461\" height=\"796\" src=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_15.png\" alt=\"\" class=\"wp-image-301\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_15.png 461w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_15-174x300.png 174w\" sizes=\"(max-width: 461px) 100vw, 461px\" \/><\/figure>\n\n\n\n<p>By changing the <em>Source Mode<\/em> in the Sprite Renderer to <em>Emitter<\/em>, the bindings will use Emitter attributes, allowing you to spawn a single particle based on those attributes. This is why the Emitter&#8217;s attributes, like position and sprite size, were initialized earlier in the process.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Bonus<\/h2>\n\n\n\n<p>The <em>Simulation Stage Fill Render Target<\/em> example might seem trivial, but I will demonstrate an example of how easily certain tasks can be achieved with the Simulation Stage.<\/p>\n\n\n\n<p>By simply reducing the size of the Render Target 2D from 512&#215;512 to 32&#215;32, you can instantly get a pixel-art-like appearance.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"594\" height=\"395\" src=\"http:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_16.png\" alt=\"\" class=\"wp-image-303\" srcset=\"https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_16.png 594w, https:\/\/heyyocg.link\/wp-content\/uploads\/2021\/02\/simulation_stage_basic_16-300x199.png 300w\" sizes=\"(max-width: 594px) 100vw, 594px\" \/><\/figure>\n\n\n\n<p>This is just one of the ways you can manipulate and display original images using the Simulation Stage. By combining it with <em>Grid2D Collection<\/em>, you can perform even more complex operations. I\u2019ll go over that in a future article.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>This concludes our explanation of the Simulation Stage. It\u2019s a core feature of Niagara\u2019s new functionality, and I personally think it\u2019s quite innovative.<\/p>\n\n\n\n<p>In future articles, I\u2019ll go into more detail on its use in 2D fluid simulations, Position-Based Dynamics, Neighbor Grid 3D, and more. The possibilities are endless depending on how you approach it, so I encourage you to experiment and explore the many applications yourself!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Epic Games distributes a project called &#8220;Content Examples,&#8221; which is a collection of various sample projects showcasing different features of Unreal Engine. Since UE4.26, there is a map called Niagara Advanced. This map contains a wealth of useful samples, including examples of new Niagara features and practical applications. Upon reviewing the implementations, there&#8217;s a lot [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":303,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"no","_lmt_disable":"","_mi_skip_tracking":false,"footnotes":"","_locale":"en_US","_original_post":"http:\/\/heyyocg.link\/?p=277"},"categories":[17,31],"tags":[32,15,30],"modified_by":"yohanashima","_links":{"self":[{"href":"https:\/\/heyyocg.link\/wp-json\/wp\/v2\/posts\/1464"}],"collection":[{"href":"https:\/\/heyyocg.link\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/heyyocg.link\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/heyyocg.link\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/heyyocg.link\/wp-json\/wp\/v2\/comments?post=1464"}],"version-history":[{"count":4,"href":"https:\/\/heyyocg.link\/wp-json\/wp\/v2\/posts\/1464\/revisions"}],"predecessor-version":[{"id":1477,"href":"https:\/\/heyyocg.link\/wp-json\/wp\/v2\/posts\/1464\/revisions\/1477"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/heyyocg.link\/wp-json\/wp\/v2\/media\/303"}],"wp:attachment":[{"href":"https:\/\/heyyocg.link\/wp-json\/wp\/v2\/media?parent=1464"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/heyyocg.link\/wp-json\/wp\/v2\/categories?post=1464"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/heyyocg.link\/wp-json\/wp\/v2\/tags?post=1464"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}