With the basics of scene creation and picking/selection down, I felt it was time to get down to the real reason I’m interested in WebGL: geometry creation. Creation of 3D geometry occurs in many fields, however, the type and structure of geometry created varies depending on the application. Certain kinds of modeling techniques that are good for 3D game animation are not good for engineering purposes and vice versa. In purely visual 3D modeling, like those for 3D animation, only surfaces are needed. The edges of the surface can be tucked under other surfaces, or hidden in a way that is not seen when the model is rendered. Design and engineering applications, however, usually require the creation of “water-tight solids,” or a collection of surfaces where the edges meet and no holes are present. These surfaces are defined by a “mesh” or collection of points, connected by lines that construct faces – usually triangles or quadrilaterals. For renderings or animations, it usually doesn’t matter what shape these faces take, just that the normal direction is set correctly so the renderer will see it properly. In engineering applications, like finite element analysis, the shape of the mesh is very important, where sharply acute angles in the faces of mesh elements causes the engineering equations to produce errors.
In Three.js, mesh elements are oriented more towards the animation/gaming community. Using the GeometryUtils.merge() function, mesh objects can be combined in any number and orientation to create a simplified, and easier to load object. Jerome Etienne has a great post about it on his blog, explaining how to use it.
This is great for creating the high-speed interactive objects that WebGL is famous for, but not great for creating usable geometry for design or engineering. In order to combine two mesh elements and end up with one, solid body mesh object at the end, we have to do what is called Constructive Solid Geometry. This is what CAD programs do, and Three.js does not have a built in function that accomplishes this job. Thanks to the open-source nature of the project, there is a library that does! A library called CSG.js, by Evan Wallace, performs the constructive solid geometry functions for webGL, while Chandler Prall created a Three.js wrapper for the library. In unison, the two libraries combine to enable us to make real solid bodies! See this post for more information, and find the libraries here:
*** UPDATE: As commented by Chandler below, ThreeCSG.js is now a stand-alone library. But please check out all of the links, Evan’s stuff is definitely worth checking out! ***
My first test was to check out the differences…
Click the picture below to see the experiment!
As you can see…using GeometryUtils.merge gives us what we want visually, but clearly allows the mesh to intersect. Trying to upload a mesh like this to 3D printing or CAD software would most likely throw some errors, or at least require further geometric manipulation to create a solid body. Using ThreeCSG.js, however, one mesh is created, yielding a fully enclosed solid body.
So, I took it upon myself to create a geometry-creation tool using the ThreeCSG library. Here’s what I came up with:
Click the picture below to check it out!
In this Experiment, by clicking on the existing geometry, you can create a new growth, which then combines with the existing geometry to form a full solid body. I took advantage of another set of libraries to enable the saving of your geometry straight to your browser. The STL file writing code is the work of Paul Kaplan (who has some really great work here and here), and makes use of the Filesaver.js library by Eli Grey. Here are a couple examples of some things I made:
In creating these larger models, however, I ran into a problem with the ThreeCSG.js geometry library. When the solids are added, the intersection points have to be interpolated so the faces can be merged. During this process, however, it seems that there is no mesh simplification processes performed, so a significant number of new triangles are added with each addition. In my Experiment, take a look at the mesh (by pressing shift) after adding a blob. It will look something like this:
Looking at the edge intersections, you’ll see that the triangles increase in density and become very small. While the CSG library does it’s job well, you’ll notice that after creating a bunch of new blobs, the program starts to lag significantly. In the case of the T-Rex I built, by the end of the construction, each new blob I added took 20-30 seconds to calculate. The “Little Man” ended up having around 18,500 vertices and 35,300 faces, while the “T-Rex” had 134,800 vertices and 264,000 faces! Because ASCII STL files are just a long list of vertices and face normals (explained here), the file sizes increase with number of triangles… making that 10Mb for the “Little Man” and 75Mb for the “T-Rex”! In fact, the models produced this way have so many faces, that I got the following message when I tried to import into Solidworks:
Apparently, Solidworks can only import up to 20,000 surfaces. Now, this is not the end of the world, as luckily there is a relatively robust program named MeshLab that has functions to fix, modify, and simplify the geometry. However, the goal for my project would be to output .stl files that can be readily 3D printed, or used as design files. Looks like I’ve identified some issues that I’ll need to work on.
Another consideration, is that while creating little figurines is fun, it is not exactly great product design. I tried desperately to think of something that I could make with this tool, before it began to lag too badly, and came up with a simple business card holder:
I’m not exactly how well it would function. But after using Meshlab to save the STL as an OBJ file, and imported it into Keyshot and did a quick rendering. Here’s what it would look like:
And here’s one of the other models just for fun:
As you can see… pretty far from revolutionary. Also, you can tell the mesh is a giant mess because of the funny shading on the facets. But… it’s a start. That’s enough rambling for now… thanks for reading!