Jump to content
[[Template core/front/profile/profileHeader is throwing an error. This theme may be out of date. Run the support tool in the AdminCP to restore the default theme.]]

Alain2131 last won the day on April 9

Alain2131 had the most liked content!

Community Reputation

44 Excellent

1 Follower

About Alain2131

  • Rank

Personal Information

  • Name
  • Location

Recent Profile Visitors

1,403 profile views
  1. Maze Generator: Recursive VEX code

    If you could provide your scene so we know the setup that needs to go before the solver, then we could help better. I assume it's just a group where you set the "current" group to a single point, but I don't know for sure. Anyways, I would use a For Each Number loop, set to Feedback Each Iteration and Fetch Feedback. Iterations would be the max iteration amount. Basically, how long you are willing to wait for. There is a Stop Condition. That would be an expression to fetch a detail attribute, set with the wrangle. I'd make a "stop" detail attribute, and set it to 1 when you want to stop the loop. Then, just reference it directly with the detail() expression. What you can then do is just put a big number in Iterations (but not too large that if there's an issue, it doesn't take forever to stop), and check at each iteration if the maze is done. In the example, I just check visitedlist's length, and if it's bigger than 100, I stop. // Arbitrary stop condition, for testing int list[] = detail(0,"visitedlist"); if(len(list) > 100) setdetailattrib(0, "stop", 1); You can see that in this case, the loop ran 158 times before it stopped. The downside with this compared to a Solver is that you cannot see the path it takes through each iterations. To solve that, you could store the iteration number on the "current" point, so that it gives you the path to visualize after. Then, you could make a visualizer wrangle that sets the colors based on the "iteration" value on each point, based on the current frame. stop_condition.hipnc
  2. assemble/unpack kills attributes?

    Hi, read this answer for more detail Tl;DR : You do not need to "Transfer Attributes" when you pack your geometry. That transfers attributes on the "shell", but the content still has the original data, regardless.
  3. Blurring Point Attributes

    Try to untick Pin Border Points, and set the Influence Type to Proximity.
  4. [SOLVED] Pack object node UV problems

    Hi, the issue is that you are transferring UV to your packed geo. That "promotes" the UV to a single value for the entire packed fragment. Then, when you unpack it, it transfers that single value to the entire packed fragment, messing up your UV. You do not need to "Transfer Attributes" when you pack your geometry. That transfers attributes on the "shell", but the content still has the original data, regardless. If you isolate a single piece, for debug, and look at the vertices in the spreadsheet, you can see that the first UV value is transferred on your packed geo. Then, when unpacking, that value is copied on every vertices for that packed fragment. Just remove the * in the "Transfer Attributes", and it'll work.
  5. Python Performance Issues

    Well, bummer. I don't know much about compiled .vex library, but I was able to have a very simple example work. Here are the resources I found : https://forums.odforce.net/topic/26970-creating-vex-libraries/?do=findComment&comment=155341 https://www.sidefx.com/docs/houdini/vex/vcc https://www.sidefx.com/docs/houdini/hom/hou/runVex.html#example Basically, you'll need to place the generated .vex file in this path "%userprofile%\Documents\houdini19.0\vex\include" (you'll need to create the folders "vex" and "include") (Although, now that I think about it, this is only really needed for .vfl to be included in VEX. For python, that's not relevant, and can be anywhere you like) I created a code.vfl file with this content. (the path of the .vfl does not matter, but I put it in the same vex/include folder) cvex add(float x=0; float y=0; export float out=0) { out = x + y; } Then, in a Command Prompt window, I typed : C:\Users\alain>cd C:\Program Files\Side Effects Software\Houdini 19.0.531\bin C:\Program Files\Side Effects Software\Houdini 19.0.531\bin>vcc -o C:\Users\alain\Documents\houdini19.0\vex\include\code.vex C:\Users\alain\Documents\houdini19.0\vex\include\code.vfl That creates a code.vex in the same folder, which can be referenced in Houdini. I used a simple python sop with this code codeFile = r"C:/Users/alain/Documents/houdini19.0/vex/include/code.vex" result = hou.runVex(codeFile, {"x":1.0, "y":0.5}) print(result) Here's an image with all the info. 1. Path to put stuff into 2. The code.vfl file 3. Compiling code.vex 3.5 Showing code.vex's insides (not relevant) 4. Calling hou.runVex() in Houdini And this successfully runs vex code. Yay. The lack of enthusiasm is because we need much more than that, and I'm not able to get any further than that. We need to be able to call "primpoints()" in there, but that requires having access to a geometry stream, which I don't know how to pass through. This page says I don't know the difference between cvex and sop, but that might be relevant. I'm sorry I can't help you more than that, but that might be a dead end. HDK sounds like the all around best way to go about this. That said, I'd love if someone more knowledgeable than me could shed light on this. Or come up with another solution that doesn't require VEX !
  6. Python Performance Issues

    Is loading the geometry directly from Python a requirement ? If no, then here's what I did. I used a file node to load the geo, then with a Wrangle I pre-process the pts[] array on each prim. i[]@pts = primpoints(0, @primnum); // In a Wrangle set to run over Primitives, with the File as an input Then, instead of "[pt.number() for pt in pr.points()]", I do "pr.intListAttribValue("pts")" node = hou.pwd() geo = node.geometry() # Need to load the input geo instead of directly from the disk primPoints = [pr.intListAttribValue("pts") for pr in geo.prims()] I did some performance testing Original speed is 21s, if we load with the File node (but keep the same primPoints line), it's 19s, but with the aforementioned method the time it takes goes down to 4s. python_performance_example.hipnc
  7. Dynamic strings

    Take a look at the documentation for detail(). detail(surface_node, attrib_name, attrib_index) You have "surface_node", but you are missing "attrib_name" and "attrib_index". Which makes sense to have, since how is it supposed to know which attribute to get from the node otherwise ? `detail("../foreach_count1/", "iteration", 0)` // When fetching int or float attributes, attrib_index needs to be 0
  8. Turn string values into numbers

    Here's a revisit of this topic, with a better and simpler answer. The enumerate node does exactly what you need. It's fast, more than 10x faster than the wrangle method I used. (Maybe my code was not optimal, but that's another story) The result is the exact same as the wrangle, though. uniqueValueByName.hipnc
  9. VEX: extract distance travelled

    Hello, What you need to do is for each frame (aka "sample", in CHOPs), calculate the distance delta upto the current sample. For instance, let's say we are calculating sample 12. You want to know how much distance has been traveled until then. You cannot look only at frame 11, because who knows what kind of crazy movement there has been before ? Which means, we need to look at every frames, starting from the first one, until frame 12. But what do we need to look for ? We want to know the total distance that was traveled. So, we can look at the distance delta between each frame, and sum it up. In other words, for each frame, compute the distance between it and the previous frame, and add that to a total, rinse and repeat, until the current frame. For our example frame 12, that would be something a bit like that : We need f0 pos; // the position at frame 0 f1 pos; // the position at frame 1 distance delta = distance(f0, f1); // the distance that was traveled between the two frames. distance TOTAL += delta That was for 1 frame let's wrap that in a loop (with better variable names, but this is not the actual code) vector fetchP(int sample) // "sample" is basically the frame number { return positionAtSample; // Not writing the actual code for this just yet, not relevant for the logic. } float totalDistance = 0; // Initialize the totalDistance outside of the loop, since we want to accumulate it foreach(int i=firstFrame; i<currentFrame; i++) // In the example of the frame 12, firstFrame=0 and currentFrame=12 { vector P0 = fetchP(i); // "i" is the "current frame". It will go from 0 to 12 (not inclusive, so 11) vector P1 = fetchP(i-1); // Here, we fetch the previous frame float delta = distance(P0, P1); // Distance delta for the current frame of the loop totalDistance += delta; // Accumulate totalDistance } // Then, if we are in CHOPs, we can assign totalDistance to V (which stands for "V"alue) V = totalDistance; How do we know if our logic is sound ? With simple animations for which we know the actual distance traveled ! I took the liberty to modify your animation in a line to have easier values to work with. It now animates in Z from 2.5 to 9.5 over 100 frames. That means, it has traveled a total of 7 meters. That should translate to the last sample in CHOP being 7. NOTE - Since we are accumulating the distance over time, the result in CHOPs should NEVER go down. It can only go up, or plateau. That means we can middle click on the chop node in the node editor, and look at the Max value. (It's not exactly 7, I assume this is due to float precision issue, but it's close enough) Another "more complex" example that we can still calculate the exact distance for, is to animate two channels, one after the other. I added a corner_anim node, which I applied the following animation : z : 2.5[f1] -> 9.5[f50] x : 0.9[f50] -> 5.9[f100] In z, it's the same animation, over a shorter period, so that's 7 meters. In x, it's 5 more meters. In total, it should be 12 meters total. Behold, 11.994078 meters (basically 12 meters). I hope that makes sense ! Here's the actual VEX I used vector fetchP(int sample) { float x = chinput(1, "tx", sample); float y = chinput(1, "ty", sample); float z = chinput(1, "tz", sample); return set(x, y, z); } // At each "frame" (aka sample), // compute the distance delta // and accumulate it upto the current sample. // For instance, // if the Wrangle is computing sample 12, // then the loop will run 12 times, // summing all the previous samples' deltas. float totalDist = 0; for(int i=S; i<I; i++) // If you wonder what S and I are, look here https://www.sidefx.com/docs/houdini/vex/contexts/chop.html#globals { vector P = fetchP(i); vector P1 = fetchP(i-1); float delta = distance(P, P1); totalDist += delta; } V = totalDist; Hope that helps ! VEX_extract_distance_travelled.hipnc
  10. I meant the points in the line, not the fracture. I'm glad this is working out for you though !
  11. Hi Kilian, If I understand correctly, you want to "apply" the simulation where there are peaks in the curve, correct ? You already have a line with the correct animation applied to it. Doesn't that look like a ramp already ?.. What I would do is sample directly from the line instead of using chramp. (This code requires the "channel_audio_import" node to be the third input of your wrangle) float end = 50.0; float frame = (@Frame + v@P.z*10) % end ; float pos = fit(frame , 1, end, 0.0, 1.0); pos = chramp("AnimCurve", pos); // These two lines are the only difference float sample = 1 - relbbox(0, @P).z; // You can visualize this with "v@Cd = sample;". A 0 to 1 value in the relative bounding box. pos = primuv(2, "audio", 0, set(sample, 0, 0)); // Sample the audio attribute of the line based on sample v@P = primuv(1, "P", @ptnum, set(pos, 0, 0)); [...] // rest of the code is untouched Now, the result might not be what you expected. This clamps when "audio" is higher than 1, so you might want to do some post-process on the audio. retime_sim_with_chops.hipnc Hopefully that's what you want ! P.S. I found that reducing the amount of points in the line yields a better result, you might want to try that (50 points instead of 498). Try it to see if you like that.
  12. Filecache with attribute name

    To fetch an attribute from geometry in HSCRIPT, you can use the various point(), prim(), detail() functions. Note that the syntax is different from their VEX counterparts. Also, and this is important for you, you need to use a different function for string attributes. points(), prims(), details(). (it reads as : point string, prim string, detail string) So, for you, this would be the code `prims(0, 0, "name")`.bgeo.sc // primString(input 0, primitive 0, attribute "name")
  13. rbd active only as of frame 10

    You need to enable "Overwrite Attribute" on the rbdpackedobject Also, in the wrangle, @Frame should be a capital F And finally, you can use a single input for both the bottom and top part, and animate the activation on the bottom alone. active.hipnc
  14. Vector with array[x] doesn't work

    Hello Killian, The error is at line 8. vector test = { 0,list[c], 0}; This is because VEX doesn't allow you to put variables into curly brackets {}. I don't know the reason, but I would guess it has something to do with optimisation and knowing the value beforehand. Don't quote me on that. Use the set() function instead, it takes care of that. vector test = set( 0, list[c], 0);
  15. Bayer Dithering

    Huh, the result is pretty neat. You're basically there, but with a few issues. Sorry if I ramble a bit, I tend to be quite lengthy in my explanations. The error message from your code says "No matching function for float Bayer2(float). Candidates are: float Bayer2(vector2 &)" This shows that VEX has an issue with a variable type. If we comment everything and leave only this float Bayer2(vector2 a) { a = floor(a); return frac(a.x / 2.0 + a.y * a.y * .75); } float dithering = (Bayer2(@uv * 0.25) * 2.0 - 1.0) * 0.5; The same issue occurs. But that code doesn't do anything with #define and whatnot. So there's an issue with how we call Bayer2. Basically, VEX doesn't like "@uv". Bayer2 takes a vector2. But how are we passing @uv ? Is it a vector3, or a float ? Either way that's a problem, we specifically need a vector2. The fix is to tell VEX the type we want, with a "u" for vector2. float Bayer2(vector2 a) { a = floor(a); return frac(a.x / 2.0 + a.y * a.y * .75); } float dithering = (Bayer2(u@uv * 0.25) * 2.0 - 1.0) * 0.5; Great. Now we have a different error. "Error: Read-only expression given for read/write parameter." This is because we are trying to modify the variable "a" in the Bayer2 function. VEX doesn't like that for some reasons. The fix is simple enough - make a temporary variable (and replace the subsequent references of a). float Bayer2(vector2 a) { vector2 b = floor(a); return frac(b.x / 2.0 + b.y * b.y * .75); } float dithering = (Bayer2(u@uv * 0.25) * 2.0 - 1.0) * 0.5; Cool, so we are now error-free. Let's bring back the #defines and use one of them instead of Bayer2. float Bayer2(vector2 a) { vector2 b = floor(a); return frac(a.x / 2.0 + a.y * a.y * .75); } #define Bayer4(a) (Bayer2 (.5 *(a)) * .25 + Bayer2(a)) #define Bayer8(a) (Bayer4 (.5 *(a)) * .25 + Bayer2(a)) #define Bayer16(a) (Bayer8 (.5 *(a)) * .25 + Bayer2(a)) #define Bayer32(a) (Bayer16(.5 *(a)) * .25 + Bayer2(a)) #define Bayer64(a) (Bayer32(.5 *(a)) * .25 + Bayer2(a)) float dithering = (Bayer8(u@uv * 0.25) * 2.0 - 1.0) * 0.5; Alright, no error, looking good. Now for the last part of your code.. float myscale = 0.4; float Bayer2(vector2 a) { vector2 b = floor(a); return frac(a.x / 2.0 + a.y * a.y * .75); } #define Bayer4(a) (Bayer2 (.5 *(a)) * .25 + Bayer2(a)) #define Bayer8(a) (Bayer4 (.5 *(a)) * .25 + Bayer2(a)) #define Bayer16(a) (Bayer8 (.5 *(a)) * .25 + Bayer2(a)) #define Bayer32(a) (Bayer16(.5 *(a)) * .25 + Bayer2(a)) #define Bayer64(a) (Bayer32(.5 *(a)) * .25 + Bayer2(a)) float dithering = (Bayer8(u@uv * 0.25) * 2.0 - 1.0) * 0.5; vector2 uv = set(@P.x, @P.z) / myscale; @uv.x += dithering; @Cd = @uv.x; Cool, no error again, and something happens in the viewport.. Something that is evidently not Bayer Dithering. Hmm, alright, what's up with that. Now that you are unblocked, if you want to figure it out by yourself, now's the time to do it. Alright ? Cool. Here's the solution. In your code, you assumed that "fragCoord" from the HLSL code was the same as UVs. That is slightly incorrect. In shadertoy, if you map fragColor to fragCoord, you'll find out that fragCoord actually represents the canvas size in pixel. In my case, max(fragCoord) == (1200, 675) (those numbers were taken from the information at the bottom-left of the canvas) To test that out, I wrote the following in shadertoy, and got the classic UV black, red, green, orange and yellow result. fragColor = vec4(fragCoord.x / 1200.0, fragCoord.y / 675.0, 0, 0); (actually I started with fragCoord.x only, saw that it was SUUUPER red, then tried dividing by 255, saw the gradient appearing in only a small portion of the canvas, then tried dividing with the X resolution, and got a full gradient in red, and thus I understood what I just mentioned) SO ANYWAY All of that is to say that you have to multiply the u@uv by the resolution of your grid. Here's what I added vector2 fragCoord = u@uv * set(ch("../grid1/rows"), ch("../grid1/cols")); float dithering = (Bayer8(fragCoord * 0.25) * 2.0 - 1.0) * 0.5; We now have a different result, but still a broken one. Hooray. Let's focus on the last three lines, one after the other. vector2 uv = set(@P.x, @P.z) / myscale; That is wrong. The HLSL reference is We know that fragCoord is u@uv * resolution And that line is basically doing (u@uv * resolution) / resolution. In our case, this line is simply vector2 uv = u@uv; But let's add the scale parameter you had vector2 uv = u@uv / chf("scale"); Next line @uv.x += dithering; The fix is simple enough, we want to modify the uv variable, and not the uv attribute. uv.x += dithering; Final line @uv.x += dithering; Same thing, we want to use the uv variable. Also, the HLSL does a comparison So let's do that @Cd = uv.x < 0.5; All put together, here's the final code float Bayer2(vector2 a) { vector2 b = floor(a); return frac(b.x / 2.0 + b.y * b.y * 0.75); } #define Bayer4(a) (Bayer2 (.5 *(a)) * .25 + Bayer2(a)) #define Bayer8(a) (Bayer4 (.5 *(a)) * .25 + Bayer2(a)) #define Bayer16(a) (Bayer8 (.5 *(a)) * .25 + Bayer2(a)) #define Bayer32(a) (Bayer16(.5 *(a)) * .25 + Bayer2(a)) #define Bayer64(a) (Bayer32(.5 *(a)) * .25 + Bayer2(a)) vector2 fragCoord = u@uv * set(ch("../grid1/rows"), ch("../grid1/cols")); float dithering = (Bayer8(fragCoord * 0.25) * 2.0 - 1.0) * 0.5; vector2 uv = u@uv / chf("scale"); uv.x += dithering; @Cd = uv.x < 0.5; So yeah, sorry for the gigantic answer, it could have been only the last snippet, but I hope this is more useful to you than just the answer. Cheers !