Це відео не доступне.
Перепрошуємо.
Fast Houdini to UE5 Particle Export | Unreal Engine 5 / Houdini Tutorial (Pt. 1/2)
Вставка
- Опубліковано 15 сер 2024
- Support on Patreon: / dannylaursen
Learn an advanced workflow to export up to two million particles from Houdini to Unreal. It works similarly to SideFX Labs' Houdini to Niagara. Instead of exporting the Houdini particle data to a json file that Unreal Engine reads, we export to an exr sequence. This exports much faster from Houdini and it can be loaded on the GPU, making the simulation run far better in UE5. We will go over how the system works, and walk step-by-step through building it yourself. At the end, you will know how the system works, and how to prepare it for high quality VFX / motion graphics rendering. One small caveat: The larger (in coordinate space) the simulation, the more imprecisions will happen because of 16-bit data precision.
In the next video of this series, we will work with our Houdini simulation and build shaders and set up studio lighting in Unreal Engine 5. We will also deal with some artifacts you might run into when rendering in UE5, and discover some neat tips and tricks for getting around it.
UE5 and Houdini project files and assets available here. Free with code: UERENDER dannylrsn.gumr...
Junichiro Horikawa: "Houdini to UE5 - How to Send Geometries with Attributes - Tutorial"
• Houdini to UE5 - How t...
phire de: "How to render dynamic point clouds in Unreal Engine 4.25 with Niagara"
• How to render dynamic ...
Medium post that inspired this experiment: "How To Play Back Volumetric Point Cloud Animations In UE4"
/ how-to-play-back-volum...
(Thanks to Kim Strandli for getting me hooked on this idea)
The Houdini simulation is inspired by Tactyc Studios: www.behance.ne...
Chapters:
00:00 - Intro
00:30 - Overview
01:05 - Houdini Alembic Export
01:34 -Transform to UE Space
01:49 - Points to Grid (VEX)
03:29 - COPs Points to Texture
06:09 - Export EXR Sequence from Houdini
06:44 - UE5 Project Setup
07:30 - Niagara Preparation
09:36 - Niagara Read Particle Data
12:35 - Niagara Optimization
14:15 - Import EXR Sequence to UE5
15:12 - Setup Level Sequence
16:43 - Niagara Mesh Renderer
17:50 - Import Alembic Cache to UE5
18:29 - Recap
19:14 - Next Steps
thank you bro! we will wait more tutorials about unreal-houdini!
Of course. Hope to get something out again soon!
I love your content man! Also, you sound exactly like Jared from Silicon Valley
Thank you for the kind words!
this is incredibly cool and useful, thank you!!
Thanks for your comment! I'm glad you found it useful
Hi, amazing video! There is some chance to change position or scale of particles after import in unreal? Anyone knows a work around for that?
Thank you!
You can translate by adding a position vector to your position before plugging it into the particle position. You can also multiply the position, this will scale the points, while the mesh size will control the scale of each sphere instanced across the points. Hope that's helpful
Hey Danny! Great tutorial! Would you consider making a tutorial for importing point clouds with color information (Rendered to textures) into Niagara with this same technique?
Thank you! There isn't really a huge difference in workflow, but I will consider running through another project using this technique.
@@DannyLrsn Awesome! It would be an instant patreon subscription from me if you did!
@@DannyLrsn Revisiting this project. So I have managed to export the colour information based on your tips, but unsure if I am merging the colour info correctly back when adding it into UE5. Are you adding this to the material like you normally would when sampling a static or skinned mesh through the related texture in the material properties?
@@havardtveito4070 I use the same workflow as for transferring the position attribute. Then in the material you can get a Particle Color node to use particle color in your material
@@DannyLrsn Thank you for the fast reply! That worked! One last question, where would I change the amount of points on the Houdini end? For now I looks like it works the best with the exact same amount of points as in your simulation?
Hi! great tutorial! thanks for sharing!
May I have some help please ? I am stuck at setting up the image size.
At COP, I put down the colour node, use the same expression u used detail("../../OUT_PTS" , "textureSize",0) , but for some reason, instead of giving me the point number (931), the number returned was just 1. I am not sure what went wrong.
Thanks
Thank you for your comment! Many things could be the problem. I would start by checking that the expression is in fact connecting to the right node, then I would check that the detail attribute "textureSize" on the OUT_PTS node equals what you would expect it to.
You can download the project files for free from my Gumroad, that might also help you see where your setup differs from mine.
Hope that helps!
this is crazy! How well would this workflow translate using 3D gaussian splat instead of a scan? Do you think it can be done all within UE5?
I'm pretty sure the workflow would be the same using a gaussian splat as long as you're just looking to get the point cloud represented.
I'm not sure if Unreal has some custom tools to read gaussian splats - maybe they will allow you to do all of this and more inside UE.
Hi there, anyone knows what I should change in the setup if the number of particles change? and the frame range is different?
You can't have a sim with changing particle count, but if the particle count is the same throughout, the setup automatically reads how many particles are in your sim.
At 6:15 you see the answer to your frame range question.
Great! Been looking for a production ready workflow for Houdini - Unreal for years. Any update on Unreal 5.2 with pushing particle count above 2 million?
Hey Joel, thank you. I think Niagara is still limited to 2 million so I don't think you can go above with this method unfortunately
@@DannyLrsn Thanks for the reply, still a great way to get 2 million particles. Probably good enough for most applications. I wonder if this could be the start of a workflow for film VFX guys to work with Unreal better, there is no clear pipeline still. I feel Unreal could be handlining millions of particles.
@@joelbergfx yes, it's unfortunate because they could easily implement a shader solution where you can instance primitives onto your points for very cheap which could go far beyond 2 mil, but they have not done so yet
hi there, how would you go around and import color data from the particle sim? im not so sure if i should export just the points without the color attrib, or if theres a way to import both pos and cd at the same time, first time using cop2net and im a little lost
Hi, you would have to export one texture for P and one for Cd, but the process is exactly the same, just different names. I think I set it up in the example file, but I don't remember for certain
Unreal is only loading in one particle in the viewport, then the sphere bounces around to all the particles positions but only one a a time
Try to load up my example files and see if they work for you. If they do, you can troubleshoot by comparing each step of your setup with my setup to see what's different.
If it doesn't work, they might have changed something since UE 5.1 and in that case I can't really help, unfortunately.
How does this change if the particle sim has a varying number of particles?
Good question! I don't know how to deal with that yet. I tried figuring it out, but hit a dead end trying to make it work nicely in Niagara.
From the Houdini side: Make sure that your texture size stays the same for all frames and that it is based on the frame which has the largest amount of particles. That way any particle that isn't currently being used has a value of 0,0,0.
In Niagara: So far my best bet is to just use a boolean to affect the particle scale so if the pos value == 0,0,0, multiply particle scale by 0. It's horribly optimized this way, but I didn't find a better way yet.
That is awesome, can we use same technic for magic effects as well (particles I mean)
Absolutely! In the end of the video, I change the rendering to mesh renderer, but if you wanted to render magical effects, you would stick with the sprite renderer.
@@DannyLrsn Great! thanks a lot man... Keep up awesome job!
@@omidmehdipour4912 thanks man! Glad you're finding it useful
i thought i´ll switch to the source VIdeo.
so in order to preserve color data, you mentioned i should just switch all positional references to color ones. and export second texture.
honestly, i have no clue how to do it - major problem, in your tutorial, you quite often just say how you connect nodes, not why. so basically i have to guess and try to figure out overall puprope of every function on my own.
should i change the code in houdini?
the first gridify wrangle, as far as i understand just moves the points into the grid form. so i shouldn´t change anything here since the color data is preserved and we just move points around.
on other hand, here we define position data and the second part is just coding/decoding so it would make sence to define the color data here.
so i should change
v@pos = v@P;
...
@P = set(x, 0, y);
to
v@col = v@Cd;
...
@Cd = set(x, 0, y);
which doesn´t really work.
or since the color data is still inside points, i encode the color data insead the positional data? how do i do that? logically it would be just connecting the rgb input into rgb output - there are no data changes, so i´m actually not really sure how and why we should encode them.
same for the niagara part - so i have to get another texture sample which just transfers color data - what decoding will look like and where do i actually pug it in?
also getting another Media source, media player, and media texture with all the frames seems very ineffitient - a plan to load a lot of pointclouds, and i fear it will crash performance quite heavily.
sorry for sounding bit frustrated, but i´m dealing with this topic for weeks now. all i got so far are bits and pieces which are either unfunctional or uneffective, or people trying to sell me their old overpriced plugins for ue4.
Hey, so I had multiple iterations of that gridify code and forgot that it just moves the points into grid positions now.
If the Cd attribute is already on your "gridified" points, just follow the steps to export the exr texture sequence and make sure to get the color attribute instead of the position.
In terms of performance, as long as you're not aiming for a real-time application, it's not that bad to be loading 2 16-bit exr texture sequences side by side. But if your color data doesn't change at all throughout your animation, I would recommend only exporting one frame and loading it into Unreal as a regular texture rather than a media texture.
Hope it helps.
Looks good! Does this work as a game effect too? (not just rendering in sequencer) - Like shooting a moving object, that disappears and Niagara activates and creates the illusion of blown up pieces - particles flying everywhere?
Thanks, Norbert. As it causes issues with motion blur and is very heavy, I would not use it for an interactive experience
@@DannyLrsn Is it still lighter than exporting a .json?
@@NorbFuchs I can only say that it runs faster in my editor than the .Json export from LABS, but I can't say if other things could influence it when packaged as a game or if it would run reliably
This is so awesome. I was wondering, do you think its possible to use this method to make waterfall simulations in houdini and export them into a large scale unreal environment? Or do you think it may be too heavy..
Thanks
Thank you! Since waterfalls are usually meshed particles, this method doesn't make sense. I would recommend using alembic files instead.
Hey Danny, very clever technique, nice one!
Would this work with importing other arbitrary point attributes, such as pscale, orient, etc? Would you do it by storing those on extra EXR channels?
If so, since orient is a quaternion, do you know if you could save it as RGBA of a separate EXR layer?
I'm about to do some experiments myself, but wanted to ask in case you've already figured it out :)
Keep up the good work, your tuts are great, and very concise
Thanks for your comment, Mark!
Yes, any attribute can be imported this way. I usually import Cd and pscale like this. You can store an extra float such as pscale in the alpha channel of the position texture or you can load in another exr sequence. The more you can pack them, the better.
I don't know if Niagara can use an orient quaternion for mesh orientation or if it needs a matrix. Although if you know the math, I'm sure you can infer the full matrix from the quaternion? I have thought about it, but didn't get around to trying it yet.
Please let me know what you find, would love to hear it!
Thanks you!
@@DannyLrsn cool man, thanks for the reply.
I tried it quickly yesterday but couldn’t work out how to use the media player object to read in extra channels that weren’t in the default RGBA layer.
When you bring in Cd attr that way, do you have to make a separate exr sequence? Or are you able to store it as an extra layer/channel along with position, pscale etc?
Thanks again for your time :)
@@mchataway You can store four floats per texture since UE can only read the RGBA channels. I was trying to say that after the three XYZ position floats have occupied the RGB channels, you can use the A channel to store pscale :)
@@DannyLrsn ah I see, thanks again mate!
Looking forward to more tuts :)
Hi how did you get your alembic cache balloons to have different materials get assigned in unreal? I have a similar setup, an alembic with 2 vellum/cloth sims but when I import into unreal and add a material it applies to the whole alembic (both pieces of cloth) even though the alembic file has 4 material slots like yours.
Hey feel free to check out this video I made where I cover that in more detail: ua-cam.com/video/_RqRsHvpFE0/v-deo.htmlsi=w5NjfRAFfka5i1lq
is this going to work with emmiting source? generally if the point count is constantly changing ?
Not straight away. I ran into some issues with killing and spawning particles in UE based on the information from the textures so it's not included in this setup.
ugh so annoying yet so weird there is no way to achieve that simple FX inside unreal @@DannyLrsn
@@scaduxx9040 agreed. There comes a point where it's more trouble than it's worth
did you found any way
@@DannyLrsn i am haveing so much trouble
Nice video! Unless I'm wrong, it seems this method doesn't support spawning particles during the animation since my media texture in Unreal would have to have a dynamic size?
By the way, I love your presentation format. Clean and concise!
Thank you! You're right, I didn't find a way to spawn particles throughout the animation. You could have all the particles present and use the kill particles boolean with some condition to determine when the particle would be spawned. It probably wouldn't be great for performance, but you could try if you wanted to
@@wabakii_irl Great to hear. Thank you!
Is this different than the Labs VAT Export?
Yes. The base idea is the same, each pixel represents a point position. Labs creates one EXR texture where the frame number is taken into account. This method creates one EXR texture per frame allowing you to have much higher point count. Labs also works through the UE shader while I'm choosing to work through Niagara to be able to instance geometry on each point.
Let me know if that answered your question!
@@DannyLrsn Yep that makes total sense. I'm going to try it out. Thanks for the video!
@@ModelWhatYouSee Good luck! Let me know if any questions come up along the way.
Hi! i have some problems! what parameter is responsible for the size of the texture?
yours is 833x833 but mine is 61x61! I know that I do not necessarily have to come out exactly like you! but what exactly will increase the size of the texture? number of particles or animation time?
Number of particles determine the texture size. Each frame is one texture file. Hope that helps!
@@DannyLrsn my particles from flip object!
flip object particle separation is = 0.1
import with DOP I/O particles and cached
transformed for unreal
and vex code from your file
when i change particle separation texture size still 61x61!
Am I missing an error somewhere?
@@flexcg675 check if your point count is the same for all frames.
And ensure that your point count does change when you change particle separation.
The texture size is determined by the point count so if that doesn't update, then neither will the texture size
@@DannyLrsn haha understandable! so the number of particles must be static! should not have the attributes of life! did I understand correctly?
@@flexcg675 yes, exactly!
Anyone knows how to transfer color data?
If you download the sample files it should be pretty easy to make it out from there :)
@@DannyLrsn All what I had to do is just change the ropnet1 network's composite target from pos to Cd 😅
Btw thank you so much for this wonderful tutorial
@@artby3d yes, exactly! Glad it was useful! :))
At 3:47 when I do this it only shows 1 pixel. What could be the cause?
So the override size x and y values become 1? Either you have only 1 point or something went wrong in creating the attribute in the wrangle or calling it in the override size channel. I would check your "gridify" wrangle in the geo spreadsheet to see if the detail attribute you're making contains the value you expect it to and then go from there.
@@DannyLrsn Found the issue. Popnet start frame was at 1 while my file cache was set to 2200-2640 because I wanted to capture the waterfall I'm simulating at that point so I recached it correctly and now the "Override Size" is showing 45 in copnet color node with around 950,000 points in the gridify att wrangle node info, the grid is showing variation in the viewport as well. Does this sound right?
@@Joshcruzfilms Ah alright. 45 sounds low for 950,000. You would expect the override size value to be the square root of your point count rounded up.
@@DannyLrsn ok I’ll keep tweaking.. the project not the other thing lol
@@DannyLrsn so everything looks right in the geometry sheet for point count. I am thinking it is the file path in the color node or detail("../../OUT_PTS", "textureSize", 0) the "../" before "OUT_PTS" maybe the geo1 it is referencing is the wrong one?