Welcome to Physics Patch-a-day, part of our spotlight on the Max physics engine and some of its capabilities. We are following the script of the previous patch-a-day series; we ask various members of our staff (and sometimes outside participants) to try their hand at a technology, then see where they take us. Some of the posters will be experts with OpenGL and/or the physics engine, but others may be from other disciplines, and work on matching the tech to their interests.
We hope that you will find something interesting in each of these posts, and that it opens your mind to some of the options provided by the physics system. -- [ddg]
Today's physics patch features a set of musical walls and three equally musical spheres that make noise whenever they collide. Each sphere has its own "collision" subpatch that calculates whether the sphere has collided with another sphere (which produces a low note), or one of the walls (each of the 6 walls that makes up the "world" is associated with a note in a pentatonic scale - hit the wall and the note sounds).
The patch demonstrates the use of jit.phys world dictionaries, which contain all the data necessary to detect collisions, and even to determine when objects collide for the first time (think of it as a sort of equivalent to "debouncing").
The interesting twist on this patch is that it contains a set of 3d LFOs controlled using standard ITM objects. These x/y/z vectored LFOs run quietly in the background as the spheres drift and interact and let you "teleport" them - that is, move them immediately to the location specified by the 3d LFO at a time interval you choose. Whenever the spheres are teleported, they move immediately to their new location and continue with their original momentum for interesting results.
Of course, this patch can be modified to do all kinds of other things. It just felt like a pentotonic tune kind of day here. Beam me up/sideways, Scottie! -- Gregory
Hello fizz-fans! For today's patch-a-day, we've got a fun demonstration of constraints between rigid-bodies, and enabling motors on those constraints. The patch creates a structure of 5 rigid-bodies, held together with hinge-constraints. I'm calling it a racer.
The racer has 1 main body shape and 4 "limbs". Each limb is constrained to the main body with a hinge constraint, and each hinge constraint is motorized, allowing the racer to travel across the ground. The limb objects are each stored in their own bpather, found on the right side of the patch.
The ground (contained inside the "ground" sub-patcher) is made up of some static bodies (bodies with @mass 0). jit.phys.multiple is used to give some random obstacles to the ground.
The camera view can be controlled (via jit.anim.drive) by dragging in the window with the mouse, and pressing the w,a,s,d,q,z keys.
When you first start the patch, the racer's main-body has @kinematic mode enabled, causing it to remain in place (rather than fall to the ground from gravity). This allows you to adjust properties of the body, limbs, and hinges, without the racer bouncing around in the world. Once you've adjusted those properties, you can disable kinematic mode to see your racer in action. The patch comes with two presets for different body, limb, and hinge properties.
You can now propel the racer forward (or backward) by enabling the limb-hinge-motors (motorvelocity and motorstrength). What tends to happen at this point is the racer tips over, so we want to add another constraint to the main-body, using the jit.phys.6dof, to prevent this. The 6dof constraint is adjusted so that there are no limitations on linear movement (the lowerlimit_lin values are greater than the upperlimit_lin), allowing the body to move anywhere in the world. The only thing we constrain is the angular orientation of the body, thereby preventing the tip-over. As a side-effect, we can now adjust the racer's direction by adjusting the world-space y-rotation of this "up" constraint. The patch allows you to use the up and down arrow keys to adjust the motorvelocity and left and right arrow keys to adjust the constraint y-rotation, thereby driving the racer.
If you are feeling mirthful, comment out the lines of code that add the "up" constraint, and watch hilarity ensue as the little guys struggle to cross the terrain. Happy racing! -- Rob
Hello, and time for another patch (or two) a day! I'm exploring the jit.phys.multiple system, and particularly the use of constraints and impulses within the multiple set. My first patch - AngryHuddle - I pay homage to the complete anarchy that has become of the NFL (National Football League) with the use of replacement referees. Not only are players fighting their opponents, but they've begun fighting each other as well. I've created a simple "huddle" of 11 spheres, each constrained to an overhead 6dof that keeps them in place, with impulses that cause them to "knock heads" every once in a while.
Two important points in this patch: first, the use of the @name attribute to give names to the individual bodies that are then used by the jit.phys.6dof object. By giving the name "hangers" to the multiple set, I can access bodies with a 'hangers_n' name, where n is the body number (starting at 0). If I was using a 2-dimensional array for multiple setup, I would use 'hangers_x_y' to access the row and column of the multiple set. This gives me the ability to directly access the individual bodies by my constraints.
The second interesting feature is the use of a force matrix to impulse individual bodies. This is done by creating a matrix with a single force entity, then turning it off (by zeroing out the matrix) 100 ms later. In this way, I can have the random objects properly select and pulse one of the objects, rather than impulsing them all (which is what happens when we sent an impulse message to the jit.phys.multiple).
The jit.phys.multiple can also have an embedded constraint, where these constraints are automatically connected from body to body within the multiple set. With his permission, I am including a patch by forum user matmat (Mathieu Constans): the NurbsSheet patch, which shows a simple use of 6dof constraints within the multiple set, and using nurbs rendering to create a cool, smooth sheet-in-the-wind model that is mesmerizing to watch. You can see how using a multiple-constraint makes patching a lot simpler; as long as body-to-body constrains are what you want, you will find it much easier to accomplish using the built-in multiple mechanism.
Today's patch combines a couple of things together to make a fun time-waster. The important thing to note are the bodies using @kinematic 1. This prevents the physics of other bodies from knocking those objects around. This is useful for things where you want to control exactly where they are and move them around. With @kinematic 1, the moving walls can actually kick things around a little when they move too. I couldn't help throwing in a little GL Camera feedback in the backdrop for good measure. -- Andrew B.
A while back I was interested in creating a mini particle system that had points of force exerting themselves on the particles. After I got into it a bit, things became a little too complex to manage, and I abandoned it. Then along came Jitter Physics! Using jit.phys.multiple and jit.phys.ghost, was able to prototype this idea in about an hour, and I really love the results. Its endlessly tweakable, and as I have attempted to keep it simple, there is lots of room for expanding the idea. The patterns that emerge are really mesmerizing, and playing with various colors, materials, shapes, and positions of everything can provide some great visuals.
The set up for this patch is that there are four "force points" in a diamond shape. These are jit.phys.ghost objects. They can be attractors or repellers. Then, in the middle, there is a moveable force point, which is a combination of a jit.phys.body and a jit.phys.ghost. This gives the effect of having a body which also can attract or repel. The functionality is achieved by using the 'kinematic' attribute of the jit.phys.body, and handling all of the positioning of the object (and force), by mouse tracking in the jit.window. A jit.gl.sketch object is used to visualize the center ghost/body position.
The "particles" are all handled by the combination of jit.phys.multiple and jit.gl.multiple. In this patch, there are 400 bodies generated, and their color, torque, scale and mass are all generated by a single jit.noise object. The random matrix is then scaled by the use of jit.expr objects. Another even easier way to do it is in jit.gen, where you have the 'scale' operator. Depending on your computer, you may have to alter the amount of bodies to maintain smooth performance.
Try changing the central_force of all of the jit.phys.ghost objects. Positive repels and negative attracts. Setting the central_force to 0 effectively disables the ghost force. Sending central_impulse messages to the ghost objects create single shockwave-like forces through the physics world. Move the central "Moveable Force" around by click-dragging in the jit.window. See how the spheres are colliding with it, but also attracted or repelled.
This is just the tip of the jit.phys iceberg, so experiment and enjoy! -- Ben B.
As fun and easy as jit.phys.ghost is, it's not the only way to apply forces to multiple rigid-bodies. There is also the jit.phys.multiple force matrix.
One of the benefits to using jit.phys.multiple is that since it takes matrices, we can use all the great matrix tools jitter has to offer to generate those matrices.
For today's patch, I wanted to demonstrate how we can use jit.phys.multiple with jit.path and jit.gen, to simulate bodies in a vortex or tornado.
Disclaimer: In no way is this simulation intended to be scientifically accurate.
So what kind of forces are involved in this?
Well, first a tornado has a long spiral shape, and objects are pulled along the shape of the spiral. And second objects are sucked upward into the spiral shape.
To create a spiral, the patch uses jit.expr and jit.path. I simply copied the jit.expr from the jit.gl.path help-file, and slightly modified the expr. I then used the "outputeval" message to jit.path to send a matrix containing the path points to a jit.gen.
The jit.gen simply takes the path matrix, and the phys.multiple position matrix, and tries to find the closest point on the path to each body. A jit.gen attribute @steps will determine how many path-points are iterated to find the closest. The more steps, the more cpu is consumed. Once the closest point is found, a tangent is calculated by subtracting the previous path point from the current. This tangent will pull bodies along the path, so in order to pull bodies toward the path, we mix the tangent with the distance from the body position to the path point (adjusted by the jit.gen @fade attribute).
That's it! The force matrix is then sent to phys.multiple to apply the forces to each of the bodies. We also send the force matrix to gl.multiple color matrix, mainly for debugging. There is also a jit.phys.ghost that can be enabled to add more forces to the equation.
The real fun happens when you interpolate between presets, so a pattrstorage is provided to get you started with that. -- Rob R.
Today's fizzy patch-a-day explores the use of the jit.phys.body object to create non-rectangular bounding regions for rigid bodies.
It uses the matrixoutput attribute of the jit.gl.gridshape object to feed into the jit.phys.body object, but any 3 plane float32 matrix can be used. By setting the shape attribute to concave, we can place objects inside the rigid body, allowing us to contain objects within any type of static or even dynamic bounding space. While this example is not perfect (some objects have a tendency to escape!) I found the implications very exciting.
Some things to play with are: the xfade amount between the primary gridshape and noise; selecting different gridshapes as boundaries; showing and hiding the bounding form and vector indicators using enable on the jit.gl.physdraw object; the difference between concave and convex hulls; amount of gravity; your own dynamic meshes (3 plane, float matrices). Have fun! --Cory
We've already seen some good usage of jit.phys.ghost to push things around in a physics world. Taking inspiration from the "ghost" part (and maybe spending too much time indoors), today's patch uses jit.phys.ghost to animate a bunch of boxes as a big mass that shifts around and smashes into the walls. To add a little more liveliness to things, we also have a some force being applied to the individual boxes to make them shake and wiggle via the force matrix of jit.phys.multiple. To top it all off, the scene is surrounded by jit.gl.camera objects that are feeding their captured view onto the walls. Look inside the camera subpatches to manipulate how those are set up. -- Andrew B.
Today's PAD shows two different ways to do the same type of thing, create a 3D simulation of a snake erratically twitching about in a zero gravity environment, just the thing that everyone needs more of in their life!
The first method involves connecting a bunch of gridshape/body pairs with 6dof constraints, and driving them with impulses for movement and torque. This method is perhaps more descriptive of what is going on, but it also gets a little cumbersome to patch together all of these objects.
As I was building this version, Rob R. pointed out that you could do something similar with jit.phys.multiple. In addition, you can create a snake-like form by using jit.gl.path, and a "head" to the snake with another gridshape that is being driven by the rotation and position matricies from the phys.multiple object. In addition, using a two-level jit.anim.node hierarchy allows for an offset for the "head" position.
There are some interesting differences in both simulations, and both have their advantages and disadvantages. But, it helped me understand a few features I hadn't played with before. It gets really fun when you add a few more snakes to the pit and see how they interact. I've placed a jit.phys.picker object in the patch so you can toss around the snakes too.
Extra credit: how would you add a "tail" to the phys.multiple snake? How would you include the "head" to be part of the rest of the physics body? -- Ben B.
For our final patch-a-day, I demonstrate how to create Inverse Kinematics (IK) with jit.phys and jit.gl.model. You can read more about IK here, but basically it allows you to pose a model using single position values, rather than by orienting each joint individually. eg, You can pose a model by positioning its wrist, and the elbow and shoulder angles will be calculated automatically.
You can take this even further to create an entire skeleton structure using rigid-bodies and constraints, but in this patch we just stick to the arms. There is a sub-patcher that contains the gory details for those interested brave souls.
This wraps up our physics spotlight, and I hope that you got a taste for what can be done using ole Newton's laws. More so, I hope you got a taste for what can be done by abusing those laws. This is really the tip of the iceberg, so please dive in to these objects and show us what crazy things you come up with.
Thanks for following along with us as we explored "making things bounce", and see you on the forums! -- Rob R.
Very inspiring tutorials and examples. I was wondering if there is a patch that gives an example of simplest case with the IK on that model. I found it very difficult to follow what was going on in the example patch with all the extra features - "rag doll" etc.
If I just want to e.g. grab the hand and have the arm move along with it via IK, what command or message do I send to what object in that example patch?
to keep thinks simpler, i didn't include a phys.body for the hands in that patch. however you can either add another phys.body and constraint for the hands, or adjust the scale of the lower-arm phys.body so that it encloses the hand.
in it's current state, you can click the lower arm with the mouse and drag the arm around, or you can attach a phys.point2point constraint to the lower-arm phys.body, and set the @position2 attribute of this constraint to move the arm around.
feel free to continue this conversation on the forum.