 Howdy, guys. All right. So in this video, I wanted to walk through how to import points from a JSON file. So I've shown a couple ways already on YouTube and also on the Patreon site of how to export out your point clouds to a JSON file and you know make it you know specific or make it really generic. But what I want to show now is how do we get all that data back in. So let's say I've been given a JSON file that describes a point cloud and it's got a bunch of attributes on it. How do we go and generically import all of the all of that data from the JSON file? All right. So what I'm going to do, I've already gone ahead and created a Houdini project here. Let me actually save this as import points video here. All right. And what I'm going to do is just get myself set up with a point cloud. So I'm going to call this GeoNode export point cloud and I'm going to dive inside and create a grid. I'm not going to do anything fancy here. I just want to get some data to work with here and I'm going to toggle off my normals there and I'm going to drop down a scatter node and this will give me some points to export and I'm just going to leave you like that. No reason to go crazy. And then I want to add some attributes to this. So let's go to attribute randomized and let's create a random p scale. So let's do p scale We'll name it here. So p scale and I'm going to use the custom ramp and just set my min and max. Min will be 0.5, max will be 1.5 like so. And then I want to do another one of those. I'm just going to grab it from my history there and This one's going to be type. I think I'm just kind of setting this up just to show you how generic this can be So I'm going to name this type and in this case, I want to set this to a custom discrete. All right, this allows me to give it a bunch of just values and so I'm going to set this to a string value and for these values, I'm going to say I'm going to give it a type. Let's say we're you know producing some sort of like foliage system or something like that. And I want to give all these points a specific type. So some are large trees, some are small trees, some are large rocks. And some are small rocks. All right, you can use these little sliders to say, you know, I want less, you know, large trees, maybe more small trees, less large rocks, more small rocks, so on and so forth. Cool, so that sets me up with some some values or some extra attributes. So now what I'm going to do is I'm going to drop down my generic JSON exporter here. Again, that was in a previous video. So if you need a little refresher, I highly recommend watching the video. And so for this to work, I've already gone ahead and just set up a folder on my desktop here. So for this work, you need to assign the director you wanted to go to and then we want to give it a file name. So I'm just going to call this foliage points. And then these these attributes multi-part here allows me to tell this exporter to look for the p-scale and type attribute. This is what makes it generic. All right, so I want to do p-scale because you can have any number of attributes and all you got to do is just tell the exporter here which ones you want to export. So that way it's not, you know, hard-coded or anything like that. All right, so with that done, I'm going to select my JSON exporter and hit export points and if we go to my desktop now and we go to my point clouds folder, you can see I have this foliage points JSON file. Looks great. So we have our type and our p-scale. And so now what we want to do is we want to import all this back into Houdini, right? I want to recreate this point cloud with all those particular attributes on it. And so let's do that. I'm going to create another geometry node and I'm going to call this import point cloud. There we go. And then inside of here, I'm going to create a subnet. This is going to become an HDA. We'll call this import points from JSON. There we go. And I want to turn it into an HDA. So I'm just going to right click on it, say create HDA. And I'm going to give it my namespace here and we'll do 1.0. There we go. And then I just go and name these guys. And obviously you can name this whatever you want. There we go. Now I want to save it into my project directory. Actually, you know what I'm going to do? Well, for now I'll just keep it here in my job. I was going to send it to my global folder, but yeah, I'm just going to save it here. Hit accept. Perfect. And so all we really need for this is a file chooser. All right. So I'm just going to call this JSON file for the name, the internal name. And then for the label, it'll just be JSON file, like so. Hit apply and accept. And this will allow me then to go and assign whichever JSON file I want. And so I'm going to hit that little file button there and go to my desktop and choose my foliage points there. There we go. Cool. All right. So the next thing, I'm going to actually do this one a little different. I'm going to utilize a Python node here. So we're going to utilize a Python node. I'm just going to put a null at the top, not totally necessary, but I tend to just do that. And we don't really need to do that. We'll call this import points. All right. And so inside of this Python node, the reason why I'm going to be using the Python node and not just embedded into the Python module into the HDA is because right off the bat, I get access to the geo portion of the node. So I can start adding points to it. Right. All right. So we are going to need a couple of things up here. So I want to import OS so I can work with the OS and look for files and stuff like that. And then I also want to import JSON. That way I can load up JSON data or write it out if I wanted to. Okay. So then below this guy, and honestly, you don't need to keep this here. This is just what Houdini puts in there by default. And we can put in our own. So we'll get main nodes and geo. And then we're going to get our parent. So we want to get the parent node here. And the reason why I want to get the parent node is because I need to get access to this parameter right here that we created. All right. So we want to go and say parent is equal to node parent. So that basically means that we now have access to this particular node up here. And you can prove that by doing a print. We'll just say parent name. And there you go. So I got import points from Jason. Cool. And so with that, now we can get the JSON path. So I'm going to do JSON path. And this is going to be equal to our parent.parm. And it was called JSON file. We're going to say eval as a string. Just so we know it's actually a string. So let's see what that is. I'm going to say print JSON path. And look at that. We have our path. Cool. So the next step in all this is to read the file. So read JSON file like so. And really, you know, to make this a little bit more robust, we should check. We should say if the length of our JSON path is greater than zero, then we're cool. And if os.path.is file, we want to make sure it's an actual file. So we're going to say JSON path. I don't want to import anything that's not a file. But that's true. Let's print. We have a file. Look at that. We have a file. Let's get rid of this print up here. Cool. So that means I passed both these checks. So it just makes it a little bit safer, right? We don't want to try to read some empty file, but maybe it's a text file or JSON file. And so there we go. Now we have that. And so now I want to loop through each of the points. I'm going to say loop through point data like so. So we're going to say four point in, and actually we need, before we do that, we need to read it. Hold on one second. I've got ahead of myself here. So if we have a file, let's get the data. So let's say get data. So I'm going to say I'm going to initialize a new dictionary. It's going to be equal to a new dictionary like so. All right. And then we're going to say with open, and we're going to send in that JSON path as f. All right. So we're going to store the results into that f variable here. We're going to say that data is equal to JSON.load from f. So that will actually put all of the information that's in our JSON file, all this stuff, into this dictionary here that we can read through. So now we can say, so actually now we can do a check. Let's do a check. We'll do f length of data. It's greater than zero. That means we actually have data. So now we can do four each point or four points in points, or in data, sorry, points. There we go. So I'm going to access that guy out of the dictionary. Let's print point and just see what we get. There we go. So now we've got all of the data pulled off of the, or pulled out of the JSON file. All right. So we have our type, we have our ID, we have our p scale and our position. Awesome. So with that, the first thing we could do right off the bat is actually create each point. And I highly recommend just doing that. The generic exporter that I created over here, basically defaults to just exporting the position and just the ID of the point. And honestly, you don't really need the ID because Houdini is going to assign the ID anyways. But the one thing we can do right off the bat here with this is get the position. And so I'm going to declare a new variable called pause. And we're going to say it's equal to the point and pause variable. All right. So this guy right here, it's going to be equal to that, that list. Very cool. And then once we have that, we can say that we need a, we actually need to format it into a vector. So position is going to be equal to who dot vector three. And I'm going to put in, I'm going to make sure I cast these to floats, because they're all going to come in as a string, right? All right. So we need to do a cast here. And we're going to say pause zero for the exposition. And then let's go over here and do pause one for the Y and pause two for the Z. So that gives us our actual point value or our position for each point. And so we could kick this off by creating a new variable called new point, and we'll say geo dot create point like so. And then with that new point created, we can set its position, we can say set position and set it with that position variable. And there you go. So we got our point cloud back. So that's super cool. Now what we need to do is we need to basically roll through all the data and pull off things like type and our p scale. And I don't want to hard code it. I don't want to specifically look for, you know, type, the variable name type or the variable name or attribute name p scale, right? And so we need to actually do that in a little bit more of a generic way. All right. So let's do that. All right. So the way that I'm going to do this, it's pretty cool. You can actually have two values for your for loops. So in this case, I'm going to say name and then value in our point.items like so. Okay, this basically will give us both of those values. So I can say print name plus semicolon there plus let's just do str value. So we're casting it to a string. There you go. So you can see that we have pause and ID. So basically in your for loops, you can have two of these values and then basically iterate through a dictionary element. Makes it much easier. Less code. I like it a lot so. So one thing that we're going to have to do is I don't want to have to set up these attributes ID or pause because those are just inferred and we've already taken care of pause. So I just want to skip those guys. So I need another f check in here. So I'm going to say if the name does not equal pause and the name does not equal ID, so name does not equal ID, we're going to skip those. And remember, the generic exporter always puts in pause and ID. So I can, I know that I can just skip those guys because those ones are already set up by this code. And then Houdini also already goes and adds an ID to them by default. So we don't need to do that. All right. So the next thing we need to do is we need to make sure that we don't already have an attribute of that name. So I'm going to do check for attribute exists, like so. And to do that, we're going to say attrib is equal to geo.findattribvalue, like so. And we're just going to pass in the name. All right. So with that, we now are looking to see if an attribute art with that same name already exists. And if it doesn't, then we should go and create it. So we're going to say if attrib is equal to none, all right, then let's go and create it. But we also have to make sure that we checked the type, right, because we're going to have to go and set the attribute type when we go and create it. So in this case, I'm just going to do two of them and you guys can add the rest later. But the way that we do this is to say if type of value is equal to list, like so, then we're going to say attrib is equal to geo.addattrib, like so. And then the type, in this case, is going to be point. So we want to attribute type of points, dot points. Like so, the name is going to be name, and the value is just going to be the value that we currently have. And then for all strings, so if we come across a type of string, right, so this one works for lists, which our p scale currently is. But if our value is equal to, in this case, it'll be Unicode, right, that means it's string, then we want to also add that same thing, right. So there we go. You probably just run that through, I prefer to actually check to make sure because I might, you know, set certain things specifically for different attribute types. But that's a quick way to go and make sure that you are specifically setting the right type. All right, cool. So with that done, we should do one more check. We say if attrib does not equal none, then we can go and set it. We can say that new point dot set attrib value. There you go. And we're going to say attrib and value. There we go. And it looks like we are getting an error. Must be some syntax error up here. Find attrib value. Let's see what's going on with that guy. Oh, sorry, it's find point attrib. Sorry about that. Find point attrib. And let's see what else we got. Add attrib. We need an R in there. Moving too fast. There we go. And with that, we just have created a generic point cloud or JSON point cloud importer, right. There's lots of ways you could do this, but that is the code to go and set up a generic importer for your point clouds. All right, so now we've covered generic exporter. Now we have a generic importer. So last thing always to do with your HDAs, go and save it. And there you go. Yep. So anyways, that's what I wanted to show you guys in this particular video. Hope you liked it. Thanks so much.