• Login
  • Register

Work for a Member organization and need a Member Portal account? Register here with your official email address.

Project

Red-Braised Pork Generation and Simulation with the Dither Programming Language

Groups

Realistic simulation of red-braised pork has always been an important challenge in the history of computer science. The bouncy, succulent, vibrantly-colored delicacy enveloped in lustrous, viscous juice presents an almost irresistible temptation for gluttons and programmers alike. Can it be tackled with Lingdong's shiny new programming language for creative coding? Let's find out!

The full source code of this project is available here. Some sections are followed by links to a relevant code listings.

Red-braised pork is typically chopped into roughly rectangular cuboids of various dimensions. Therefore, it makes sense (or so I thought) to start with a subdivided box. We create such a mesh by specifying vertices, indices and normals, and pass it to Dither's 3D rendering pipeline, Rdr. The medium-level API gives the programmer much control over how exactly things will look, yet does not expose them to the verbose nitty-gritty details of the underlying backend. [Listing 1.1]

To get a better (debug) view of the subject matter, we write a simple normal shader. One benefit of learning Dither is that you won't need to learn another language for writing shaders: any part of your Dither codebase can be compiled to shaders automatically given an entry function. [Listing 1.2]

Next, we modify the shape of the subdivided cuboid along its Y (up) axis to create the three main sections of red-braised pork: the rind, the fat, and the lean, as well as their respective textures using math and noise functions. [Listing 1.3]

One of the most memorable properties of red-braised pork (besides redness) its tender bounciness. Therefore, we must add a springy bending animation to evoke this feeling. To do so, we imagine the cuboid to be part of an arc of a circle, and fix the chord and change the radius in an oscillating manner. Next we re-compute the vertex positions by mapping their original X (horizontal) coordinate to the central angle along the arc. Luckily, Rdr allows us to update a custom selection of the attributes of a mesh in real time, and in this case, vertex positions and normals. A further optimization involves analytically computing the new normals based on the central angle and original normals, instead of re-computing the normals from vertex adjacency. [Listing 1.4]

Once we have the basic shape and animation working, it's time to add more details with a bump map and a corresponding shader for it. Bump maps create illusion of fine geometry without bloating up the mesh data. We generate the bump map by writing another shader in Dither, run it once, and store the result in a texture. Notice that all the required helper functions called by the shader entry point are automatically extracted and compiled!

Oh no! a very problematic problem is becoming more apparent as we refine our rendering. Due to the fact we started from a cuboid, we get some sharp-looking edges from the original primitive. This contradicts with the spirit of red-praised pork, which is organic and soft around the edges. In theory, we could patch it up by computing the required normals at the edges and modifying the vertex positions and bump map to create rounded edges and hide the geometry's henious origins, but it is not at all convenient or elegant to do so. It is time to scratch the cuboid model and start from a better primitive.

If we think about the parameterization of a sphere, it is very nice and smooth everywhere, and the math is so elegant. Unfortunately, we're not making a meatball today. So how to make a sphere more like a cube? Now we know that to make something of a cross between a square and a circle, we have the "squircle": instead of x=cos(t) and y=sin(t), we apply a power to get x=cos^n(t) and y=sin^n(t). Turns out we can also generalize it into 3D: we basically take the UV-sphere parameterization, and apply the power to distort both the profile and the cross section, and voila! a 3D squircle! [Listing 2.1]

It is such a nice shape. However, as we tweak the exponent to increase square-ness too much, the floating point math can get a bit unhinged. Also, uniform sampling of the angles results in non-uniform samples along the surface (in other words, the edges and corners get more vertices). This might be quite desired depending on your use case, but for our situation, it only complicates UV and bump mapping, and we actually do need ample amounts of vertices even on the flat areas for the bending animation. For these reasons, we resample the squircle into an evenly spaced polyline first before using the data.

Now, we apply the triad of rind, fat, lean back onto the 3D squircle, and what we get is a nicely organic-looking piece of pork. 

Next, we generate the colors to another texture so the "red"-braised pork can live up to its name. Finally, everything is tied together in a shiny Blinn-phong shader. [Listing 2.2]

Look at the pork in all its glory, bouncy, succulent and juicy. But you know what would be even better than a piece of bouncy, succulent, juicy, red-braised pork? Lots of pieces of bouncy, succulent, juicy and red-braised pork! Imagine a bunch of them dropping from the heaven onto a pile, bouncing against each other, rolling, flapping... pure bliss.

Now to accomplish that, we need some collision detection and some physics. For this particular situation, we might just be able to roll out our own -- but the Dither programming language can actually benefit from a proper physics library. Therefore, I took it as an opportunity write a wrapper to port the esteemed (albeit a bit long in the tooth) Open Dynamics Engine (ODE) to Dither. Thanks to its good ol' C API and (relatively) simple build setup, it hasn't been a complete nightmare (compared to some other, more popular, C++ based library named after a typographical symbol). Since Dither advertises as working both on the web and the desktop OSes, I also used emscripten to port ODE to webassembly, and wrapped that for the JavaScript compile target of Dither. The complete library is now available as an optional plugin for Dither.

We model the physical representation of each piece of pork as five boxes connected by four hinges, like a folding screen, or five doors somehow attached to one another in series. This allows the meat to bend, flap, and drape over each other naturally in a performant manner without introducing soft bodies (which ODE doesn't support anyways). [Listing 3.1]

The interesing problem now is how to smoothly interpolate the pork over the five rigid segments. I fitted two cubic bezier curves over them (one for each side), resampled uniformly, and used the resultant polyline to drive the bending animation, in place of the arc that was originally used in the single-pork version. You can think of it as a really simple form of rigging and skinning, which I believe are the terms used by the animation folks.

By tweaking the dimensions of the boxes, we can create some very long pork (not to be confused with long pork). It looks like some cross between fried bacon and red-braised pork. What fun.

Anyways, my advisor Zach and I thought it would be a nice post to celebrate the Chinese New Year, so here you go! Hope you enjoyed it and are persuaded to give the new programming language a try (and the dish too, unless you're a vegetarian, then don't, but do try the language).