Vexember 2023
For now just some rough notes on how I approached each day, if people really expect more stuff (images, hips), I can add them later. Trying to get the right balance of just giving clues vs giving full code solutions, for now I'll attempt more vague hints and tips. Set aside 50 mins (or play it faster) and watch Make It Stick, trust me, its a super interesting course, and its a proven way to learn.
The high level summary is test yourself, get uncomfortable, feel like you're not making progress. These are all good things, and will help you learn more effectively!
Day 01 Sine waves
Covered pretty well in Joy of Vex. Get the distance to another point, feed that to sin(). Work out where you'd include Time to make the sine waves animate, how you'd affect the colours, and how'd change the number of lines/waves.
Day 02 push by nearby points
Find the nearest point, get the distance to it, then use that distance to push the points. I tied myself in knots initially thinking of how to find the plane to push the points towards, then to my surprise found the base solution was a LOT simpler than I expected.
Day 03 character parts bounce down into position
Crag is easiest to work with here because he (or she) is already made up of packed fragments. Some folk might have an intuition of how to setup motion like this, I rarely do, but I can iterate through the steps I need quickly. My thought process was something like this, each step will get increasingly vague as it gets closer to the final code... 😃
- I need to lift up all the pieces, obviously, so @P.y += 2;, yes, it all lifts.
- Now I need to animate this, so @P.y += 2+@Time, oh no, it lifts up.
- @P.y += 2 - @Time;, ok this lowers into place, but keeps lowering below the ground plane
- @P.y = clamp(2-@Time, 0, 2); yep, can lift as high as an extra 2 units, but can't go below their original y position, this is good
- Now to offset the timing, basically if you add some offset to time for each piece, they'll land at a different time... @P.y += clamp(2-@Time+@P.y,0,2); ie, adding @P.y to time
- If I break that P.y out to a variable, say float o, then I can multiply it by some slider to affect the offset
- Now I've got a linear value, I could run that height offset to a ramp, and then draw in a springy looking curve to get that oscillating thing in the original ref
- Instead I thought it'd be more interesting to rotate the pieces into a spiral, which you can do by driving P.x and P.z with sin() and cos()
- To make the actual pieces rotate, I cheated and setup an @orient attribute, then appended a 'transform by attribute' to do the actaul rotating, because updating packed intrinsics is boring.
Day 04 bounce and knock over and under in a line
Nice chewy one this. Again my initial attempts were to try and do it all in a single wrangle. This meant putting the points in an array, shuffling the array, and transforming the points in that randomised array order. I got somewhat deep into this and realised I was trying to keep 3 separate arrays locked together, and this was too much work.
Instead I did what all good lazy houdini people do, pre-process the geo before the wrangle to make the wrangle logic easier. A sort sop can be used to randomise the order. So now I just had to process the points in @ptnum order, and they'd bounce around as expected.
The actual movement is based on querying point(0,'P', @ptnum+1), ie the position of the next point, lerping to that position, but also affecting the height through a ramp. The up/down motion is driven by modulo, if the current ptnum is even, multiply P.y by -1, otherwise leave it alone.
Something I didn't get to was adjusting the timing so that you can clearly see the previous point knock the new point out of position.
Day 05 braiding
Super simple, super fun. I mentioned earlier that you can use sin() and cos() to define a circular motion, the trick here was to look closer at only the horizontal motion, and only the vertical motion, and see how they relate. When you crack that, and can make a single point move in a figure 8, the next trick is to work out the timing offset so that if you have the 3 points, that they remain an equal distance apart. Everything else I did was just silly tricks, so defining trails, making braids of braids, but the core is to get that basic offset figure-8 motion.
Day 06 lerped scatter to voxel
I used the z component of each point position relative to the bounding bbox, to drive a position change. The position lerps between the original position, and a quantized position. Quantizing is covered in joy of vex somewhere, find it.
Once the basic motion was figured out, I used the same value that drives the lerp, to drive a rotation, which (s)lerped between a random orient and a clean orient.
Day 07 click clack lines
Similar logic to day 4, offset points in time, driving lerps and rotations.
Day 08 noise
Mainly experimenting with layers of noise that looked cool. I missed the intent a little of John's challenge, where he's using layers of noise that builds up on itself, creating shapes and folds you don't get from vanilla noise. The pseudocode (can't give away all the clues!) Is something like
create variable 'pos'
set pos from @P
in a loop:
add noise(pos)*0.1 to pos
set @P from pos
create variable 'pos'
set pos from @P
in a loop:
add noise(pos)*0.1 to pos
set @P from pos
By playing with the amount that gets added within the loop, the number of times you loop, offset pos a little within the loop, you can get all sorts of really interesting shapes.
Day 09 dented voronoi
Very similar to day 2. Get distance to a point, use that to move and rotate packed geometry. The trick here that caught a few people was making the shapes tilt to aim towards the target point when its close by, but be aimed flat when far away. My take was to use dihedral, which if given 2 vectors, will calculate a quaternion that will make vector a line up with vector b. By then applying that quaternion through a lerp, you can blend from the flat to the tilted rotation based on distance.
Day 10 scale prims
In sops you can use a primitive sop to translate and scale prims, to do it in vex requires a bit of vector maths. Scaling a quad polygon smaller is equivalent to translating the corners of the quad towards the center of the quad. So if you can calculate that quad center, you can create a vector that points from each point towards the center, and move the points along it by a certain amount.
You can do the finding-of-the-prim-center in vex if your'e keen, or do my usual trick, promote P from points to prim in average mode, then prim to point again, and rename it.
My value add here was to offset the timing of the points.
Day 11 walking shapes
Lots of hints from Rich Lord himself steered me towards the solution. Even then I'm still not 100% sure I get it (I had to open the hip to remind myself what I did), and I also realised I cheated; the pieces aren't rotating properly, but reset back to 0 rotation on each step. Hmm.
Anyway, the core ideas in my attempt are based on a few fairly big assumptions:
- I'm rotating low res circles (ie a circle with 3 sides, 4 sides, 5 sides etc)
- The only move in one direction
- I can hide the rotation reset
- This isn't running in a solver
I further made life easy for myself by prepping the geo before the wrangle; on the first frame the geo is moved so that the first point is at the origin, and one side of the shape is flat on the ground.
From here you can do some year 7 level trig/geometry to work out what you need. The angle to rotate is easy enough to figure out. The distance to move for each step is the length of one of the sides. I used the maketransform()
function to say 'rotate the right amount over 1 second, and translate along z by a distance of 1 side, but do that exactly at the start of every frame, ie snap forward by one side-length at the start of each second'.
Others were able to do full proper setups with arbitrary geo, and properly accumulating rotation over time. I wasn't clever enough to do any of that. 😃
Day 12 ortho dancing boxes
My one! I'd been staring at some great bees and bombs gifs before attempting this. Few moving parts here:
- Use an ortho camera view to help hide the seams, lighting disabled mode to keep it looking clean
- Everything is being driven by lerps/slerps, and the lerp is driven by distance from the origin
- There's an additional component of being driven by the angle around the origin, which you can get with atan2()
- The boxes have lerps for their height, rotation, scale.
- The controlling lerp variable is also run through either a chramp or a smooth() to give it a nice ease.
Day 13 warpy noise
Another great John Kunz special, and a reminder of something I hadn't played with in a while; warping positions that drive other things. In my case its just vanilla noise driving a heightfield, but before using P, I run P.x and P.z through a low frequency animated sin/cos, which warps into very cool looking shapes.
Day 14 click clack circle
Again reusing ideas from previous days, modulo to flip the rotation direction on every second piece, a trail to generate the coloured line, offsetting timing based on either point number or curveu.
Day 15 push pins
Relatively straightforward, but took a few goes to remember how to set it up. Have a pig underneath the grid of points, and have each point fire a ray straight down to see how far away it is from the pig, use that to drive its height. A few ways to do this, I used intersect(). I didn't like how glitchy it looked in its default state, so I used a solver sop afterwards to give the pins a slowish fade to reset to their default height.
Day 16 noisy rotate
Didn't quite nail this, but the motion was kind of nice. Tried to do this all in the single wrangle rather than pre-process, learned a few things. Lots of imagining vector directions, hand gestures, adding and subtracting things. Start with a circle. Push points along their 'normal' to get an offset circle. Then work out how to twist that push direction so you can push points into a spiral. Then layer orients driven by noise to rotate the final copy-to-points boxes around. Lots of points, small twist values, will layer up into a warpy tube thing.
Day 17 pig pipes
Wasn't sure how to do this until someone mentioned kinefx rig wrangle, then it was relatively easy. Lookup the kinefx page on this wiki for details. The other trick was to play with the scale inheritance, so that when parent pieces are scaled up or down, child pieces don't inherit crazy scales.
Day 18 inset shapes
I did one attempt, then Rich Lord dropped a handy hint to get a better result. At first I was scaling the shapes, but the scale amount would drift, and the shapes wouldn't align on each other. The second attempt is more focused on just translating points around. Each point can lookup the next point within its shape, subtract one from the other, that defines a vector that aims down the polygon side. Push the point a little bit in that direction. Do that for all the points, make each shape be slid in the direction of its parent shape, you get these cool results.
Day 19 2d silhouettes
Once again I missed a key part of the brief, to project results onto a 2d plane, but I still dig the result I got. My take was related to day 10, but the thing driving the scale was a dot product. Compare the prim normal to the vector towards an outside point, that gives you a crude lighting amount. Use that clamped dot value to scale the prims, you get a weird pseudo lighting result.
Day 20 lerp scatter points
Lerp is simple, adding flair was hard, only to see others added way more flair than I did. Oh well. The twist is just rotating points around the origin, but with a timing offset driving by the length of P, so points near the origin move first, points further away move later, which looks like a swirl.
Day 21 twisting octahedra
Pretty vanilla offset twist setup, most of my time was spent splitting the bigger shape into smaller shapes! I used a loop subdivide mode, then polyextruded the triangles into pseudo tets.
Day 21 bonus, hilbert curve queue
We were discussing the great work of Etienne Jacob, when I thought I'd have a go at one of his setups.
I'm simultaneously proud and ashamed to say I didn't build the line layout in vex. Instead I had a hunch that the lsystem sop could do this, a few google searches later I found a hilbert curve rule set I could plugin. I then used the preset for a kosch curve, and later found a 3d hilbert curve setup, the vex code to do the animation worked on all of them.
The setup is very simple, and once again builds on ideas from previous challenges. Each point looks up the position of the next point, lerps towards it. By controlling the timing offset through ptnum/curveu, you can get a pleasing pulse of action.
Day 22 noise
Gave up here, and just used John Kunz's example code. Same idea as before, just layered noise in a loop that looks really cool.
Day 23 snowflake
Similar to day 12. Measure distance to the origin, as well as atan2, lerp things based on that. The snowflake shape was generated with an lsystem sop, this is actually driving a blendshape sop in a for loop. The honeycomb layout comes from a points from volume sop in tet layout mode.
Day 24 unwrapping ribbons
Ashamed to say it took much longer than it should have, mainly because I refused for a long time to read my own kinefx notes, force that uncomfortable learning and all that. Kinefx wrangles here, using a sweep sop to define the torus shape that includes a twist, and convert those torus edges into paths, resample, convert to kinefx, and manipulate their localtransforms.