First of all, thank you for everybody (espeically our potentially confused non-American forum-goers :V) for being patient while we all enjoyed our Thanksgiving break ^^ Since more holidays are coming up again soon, I'll be posting one more devlog this year after this post. My last devlog of 2017 will be two weeks from today, on Friday, December 15th. After that, my devlogs will resume again on a normal two-week schedule on Friday, January 12th.
Josh and Adam don't have exact devlog plans like this, but I would expect them to be similarly interrupted by the holidays. Although I can tell you that y'all will probably be quite pleased by the progress they've been making during this devlog silence. ;00 We always appreciate your patience <3
If you need a daily shot of LT, you can follow me on Twitter, where I post screenshots almost daily. In addition I'll also link every LT tweet on these devlog threads. That way, those of you who don't have a Twitter can check back here for those screenshots Although the tweets will be more frequent than devlogs, expect my LT-related tweeting to be sparse around Christmas through New Year's Eve.
Speaking of screenshots...
Limit Theory Devlog Gallery - Lindsey 12.01.17
Now, on with the words!!!
11.10.17 - 12.01.17
- Added more data to Joints
- Added up vector
- Added scale
- Added function to generate a JointField from a Shape
- Added AABB function to Shape
- Cleaned up all basic Shape functions
- Ensured all shapes are manifold
- Ensured no basic shape functions create bad polys
- NEW SHAPE: 5-faced pyramid
- NEW WARP: Bevel
- NEW WARP: Smarter tessellation
- Refactored tessellate() to tesselate quads INTO quads
- Refactored tessellate() to produce 0 duplicate verticies
- NEW WARP: Greeble!!!
- Implemented a policy for protecting against crashes & bad geometry as a result of trying to apply a warp on a bad poly.
- Began work on Style
Boring Architecture Stuff
Joints, as y'all remember, are used to define patterns of shapes and create clusters of shapes. I added two crucial pieces of data to this to really bring out the strength of Joints: a Scale and an Up vector. Joints now store Position, Direction, Up, and Scale. (If you're familiar with Unity, they're basically Transforms at this point that don't have any other components like a mesh.) The Scale allows the user to define how a Shape will grow or shrink in size when placed on the Joint. The Up vector is a mathy thing that gives more strength (and prevents errors) when using the Direction property to define what direction the shape will face in when placed on the Joint. To complement this, I made sure that all of the basic Shape creation functions (like ellipsoid, box, and icosahedron) as plain as possible. They just give you a shape, and require no input regarding rotation, translation, or scale, as all of that is handled by Joints now. I also ensured that all basic shape functions return a shape that fits inside a (1,1,1) box, and added an AABB function to get size information about shapes. All of this work combined means that we now have more intelligent ways to combine shapes based not only on some abstract position, but also on a position relative to a shape's scale.
Here's a small demonstration of AABBs & the new scaling system working. The scaffolding blocks to the left of the sphere are using the sphere's AABB information to be placed perfectly at the edge of the sphere and span the length of the sphere.
Here are two demonstrations of the new Joint properties. Both images use the function to generate JointFields from a shape; they generated a Joint for every quad on the large box, then added smaller boxes to every one of those joints. The second one demonstrates using the Joint's new Scale property to scale the size of each smaller box based on its Y-location on the larger box.
I also spent a day ensuring that every basic shape function produced perfect data. Specifically, I eliminated any 'bad' polys and ensured all of the shapes are manifold. (A 'bad' poly is defined here as having a zero-length normal and/or fewer than 3 verticies.) The Irregular Prism was creating one bad poly, so I got rid of it. The Box was non-manifold, so I re-wrote it to be manifold. For the purposes of fixing the Box, the mesh being 'manifold' means that there are no duplicate verticies with the same location. Put another way, two indicies in a poly may refer to the same vertex, but all verticies with a unique position have only one listing in the Vertex list. This isn't the complete definition of manifold, just to be clear!!!, but it worked for the purposes of fixing the Box algorithm.
After ensuring that no basic shapes generated bad data, I implemented a new policy for protecting against attempting to warp invalid polys. This is a bit of a tricky situation, because while I can guaruntee that the original input to a slew of warping functions is perfect, I fear that our infinite universe with its random combination of warps could still create bad polys. For example, tessellations greatly reduce the size of each poly every time they're applied, since you're splitting one poly into multiple pieces. This could theoretically create a situation where a triangle became narrow enough that it was essentially a line, and therefore had a 0-length normal. So, for the purpose of preventing crashes & junk shapes in release, we SKIP performing any operations on invalid polys. From the testing I did, this 1) creates shapes that only have 'good' polys operated on, which still look good, and 2) prevents potential crashes and ugliness from the spreading of NANs and other unwanted mesh data. I'm going to continue thinking about this problem further, as it's a rather dry, but still suuper-important one in the world of limitless procedural geometry.
Before the break, I had begun working on Style. Style is the object to generate and store all of the properties that make a faction's aesthetic unique. Honestly, I'm not super happy with how my first implementation of Style worked out. I think my biggest struggle with it is that I don't have a good foundation to test it on yet. It'll be more useful to start iterating on Style when I have at least one complete station part or one complete ship type to work on. Before Thanksgiving break, I had been working on building station parts from a perspective of starting with extreme randomness, and THEN trying to refine it. Josh had also previously tried this method, and we both found it to be ineffective. Instead, next time I attempt building functional-looking parts, I'm going to start with a low randomness/ high functionality algorithm and THEN stretch the algorithms until I reach the limits of what still looks recognizable. I believe that I'll have much better results with both making recognizable parts AND iterating on the Style architecture if I come from that perspective.
Fun Shapes & Warp Stuff
I added a 5-faced pyramid shape. I also contemplated n-faced pyramids, which would also allow cones, but then got distracted by something else I think. Now that I'm here writing about it, I'll probably do that tonight & update y'all later. LOL.
Josh, in his spare time, wrote a bevel function, because, of course, Josh. It's quite incredible- it can take ANY shape and round ALL of the edges by an arbitrary amount. The 'amount' is a number between 0-1 which describes how rounded the corners will be- 0 leaves them sharp, and 1 rounds them all the way to the next edge.
Here's a bevel on a basic cube.
The same cube, with a higher amount of bevel.
The same cube, with a bevel amount of 1.0.
A bevel on a cube whose faces have been extruded.
A prism that's been beveled, extruded, and then beveled again.
I added a few different variants on tesselation, and generally made the algorithms & their uses smarter. We now have several options for tesselation & triangulation:
- A fan-shaped triangulation, which creates 0 new verticies. This doesn't preserve the angles of the original poly, and thus is currently only applied at the last step of shape creation, right before the shape is converted into an engine-level mesh, which is used for rendering.
- A centroid-based triangulation, which doesn't preserve angles, and is used to break up polys with >3 indicies.
- A triforce-shaped triangulation, which preserves the angles of the original poly. Currently, it can only be applied to tris, so right now a centroid-based triangulation is applied to any polys with >3 indicies before applying the triforce triangulation. This is great for creating detail is meshes before applying warps like greeble().
- A tesselation for quads that splits them into smaller quads. A quad is a poly with 4 indicies- basically a rectangle or square. Tessellating quads into more quads preserves the original intention of the poly better than splitting it into tris. It's used in our shape:tessellate() algorithm in conjuction with the triforce-shaped triangulation to create more detail on shapes before applying ceratin warps.
Here's a hand-drawn picture from yours truly to show what the different triangulations look like:
Aaaaand finally, I wrote a Greeble function!!! w00t!!! Greebles are small, repeated details added to the surface of a mesh to give it the appearance of detail and scale. For a classic example, think Star Wars ships:
Here's a box, in LT, beveled, extruded, then greebled:
And here's a long, greebled tunnel:
My plan moving forward is quite exciting: between now and the new year, I want to jam on generating a complete bomber-sized ship. I feel pretty good about the library of shapes, warps, and tools to use and combine them that I have built up. Previously, I wanted to work on station parts first, but I hit a wall with them because of their complexity. Station parts need to look extremely functional, which leaves little room for experimentation and a lot of room to get frustrated about whether something looks 'real' enough or not. I can leave that frustration for later, once I have a grasp on generating something small & have built a more robust Style system. A small ship would just be more exciting and a bit simpler. In addition, this would give me a more solid base to work on to iterate on the Style implementation.
Expect exciting devlogs coming up! Thank y'all so much for joining me in the 3rd devlog of my LT journey. Remember that I've got one last devlog after this until 2018! But you can always catch me on the forums, Twitter, or the IRC in the meantime
Gallery link again, because DUH.
Here are the tutorials on procedural greebles and tessellation and triangulation!