3D Objects: Mesh Modeling & File Formats
CS 493
Lecture, Dr. Lawlor
You can use mathematical functions or hand coordinate entry to make
simple shapes. But to model real-world objects, you need
better tools.
- 3D scanners are getting fairly cheap--the Microsoft Kinect is
fairly low resolution, but approaching $100. One universal
issue with scanners is the need to grab 3D scans from several
different directions, and integrate them together.
- Photometric modeling is another option. Autodesk's 123D Catch does this
semi-automatically from a few dozen ordinary digital camera
photos. The resulting model is a bit lumpy, and the
matching can be problematic if there isn't much texture on the
object for automated cross-correlation.
- For manufactured objects, a CAD program like Solidworks,
Inventor, or FreeCAD can make a 3D object with precise
dimensions and angles.
- 3D modeling programs, like Blender below, are used to import,
clean up, and generate models from scratch. UAF's Miho
Aiko teaches ART 472, Visualization and Animation, where you
learn the commercial program Maya (available for free from Autodesk
for students).
Blender is
a
pretty capable free 3D modeling program. It's available for
all platforms. The only downside is the bizarre, utterly
unique user interface. This is typical for 3D modeling
programs, even pro versions--they're just each their own weird
thing. Start with the official installer (use the .zip
option on the Chapman lab machines, since the .exe installer needs
admin access).
Check out the Blender Tutorials and Blender Doc Wiki. Here's my
super-compressed cheat sheet:
- Left-click manipulates the currently selected object with the
current tool. It often does nothing.
- Middle-click (or left and right simultaneously) rotates in
3D. Control-middle-click zooms in.
- Right-click selects. Shift right-click selects several
objects or vertices, so you can move them at the same time.
- Spacebar brings up a context-sensitive menu.
There's a "mode" popup menu directly in the middle of the
screen.
- "Object mode" lets you translate, scale, and rotate entire
objects (arrange models).
- "Edit mode" lets you translate, scale, rotate, extrude
vertices and faces (edit polygons one at a time).
- Pressing the Tab key cycles between Edit and Object mode,
because they're so common.
- Shift-right-click to select vertices one at a time.
Translate, scale, or rotate them like in Object mode.
- Press 'A' to deselect, then toggle selection between
All/None.
- Press 'B' then click out the corners of a selection box
(rectangle).
- Press 'C' to get a continuous drag-select tool.
- Press 'D' to duplicate the currently selected face.
- Press 'E' to extrude the currently selected face.
- (See the problem with keyboard shortcuts? Too
many to remember!)
- "Limit selection to visible" is a useful icon, switching
between X-ray mode and only selecting the topmost geometry.
- "Sculpt mode" lets you push and pull groups of faces (smoosh
polygons like clay).
- "Vertex paint" lets you apply colors to polygon vertices.
Blender starts you out with a cube.
To model anything with this, we need more polygons. Press the
bottom-right icon to switch from Timeline to Properties, select the
wrench icon to get Object Modifiers, and hit Add Modifier ->
Generate column -> Multiresolution. Scroll down and hit
"Subdivide" six times, to generate 2^6 smaller polygons on each
face. Zoom into the now-smoothed high-poly sphere with scroll
wheel or control-middle-click. Switch to "Sculpt
Mode". The "Brush" tab on the left shows your sculpting
options. Scroll down to Symmetry, and turn on symmetry about
the X axis. Use the "Add", "Grab", and "Smooth" tools to
sculpt the object into something meaningful, like a potato.
Note you can switch back to "Edit" mode, and deform the original
(non-subdivided, non-sculpted) cube, and everything works nicely.
Save the original as a .blend file. Export as a .obj
file. To save a low-poly triangle version in a nice ASCII
format, go back to Object Mode and find Object Modifiers
again. Add the Modifer "Decimate", and set the decimation
ratio to 0.1 or so. Hit Apply, and File->Export as a RAW or
Wavefront .obj file.
Exporting from 3D modelers to "Real Code"
So 3D modeling programs make it pretty easy to generate cool
geometry. The trick is then you've got to somehow move that
geometry into your application (game, visualization app, etc).
The easiest way to do this is skip it entirely--just do all your
modeling and rendering inside the 3D modeling program! But the
modeling performance of these programs usually isn't that good, and
you often need to add some complicated features that would be easy
in C++, but tricky in the 3D program.
The standard way to exchange data between programs is of course
files. We've looked at several very simple file formats, like
the OBJ file format, but modeling programs usually support more than
the very simplest "just the polygons" formats, because the modeling
programs support way more than just polygons--they have colors,
textures, "instanced" sub-pieces (like function calls), and
transforms.
Blender supports a bunch of decent file formats:
- Blender internal format, extension ".blend". A
Blender-proprietary binary file format.
- RAW triangles, which really are just "X Y Z X Y
Z X Y Z \n". Very simple to read, but the
triangles aren't even indexed, so the files are huge.
Plus, there's no way to add normals or texture coordinates.
- Wavefront .obj
format, which consists of vertex lines starting with "v X
Y Z", vertex texture coordinates like "vt S T", vertex normals
"vn X Y Z", and faces, which list the 1-based index of their
vertices. Faces can be either triangles (three vertices)
or quads (four vertices). Face lines either have the
simple format "f I J K" (I J and K are a 1-based vertex index),
or with texture coordinates "f I/TI J/TJ K/TK" (TI TJ and TK are
a vertex texture coordinate index), or finally if you included
normals each face has separate normals, like "f I//NI J//NJ
K//NK" (NI NJ and NK are vertex normal index). For
example, here's a two-triangle OBJ file: the vertices are
numbered 1-4, and then used by the two faces.
# written by foolib v3.7
v 0.0 0.0 0.0
v 0.0 0.1 0.0
v 0.1 0.1 0.0
v 0.1 0.0 0.0
f 1 2 3
f 2 3 4
- VRML 1.0,
extension ".wrl". It's all ASCII, but with a strange
XML-like nested structure. VMRL can represent object
instances and transforms.
- Videoscape
format, extension ".obj". This format came from the
1980's Amiga program "Videoscape 3D". This is NOT the same
as the OBJ format we've been using, but it is a very simple
ASCII format:
"3DG1"
<number of vertices>
List of vertices:
<x y z coordinates for each vertex>
List of faces:
<number of vertices for this face> <1-based vertex numbers...> <face RGB color, in hex>
Example 3-vertex, 1-face file:
3DG1
3
0.0 0.1 0.0
0.1 0.0 0.0
0.0 0.0 0.1
3 1 2 3 0xff0000
- STL
(binary) format, extension ".stl". This format is
used by 3D printers to generate hardcopy models. This is a
binary file format, but it's pretty simple: it's an 80-byte
header, followed by one little-endian 32-bit triangle count,
followed by a set of "triangle records". Each triangle
record has 12 floats: an XYZ normal (sometimes all-zeros) and
three XYZ vertices in little-endian 32-bit IEEE floating-point,
followed by two zero bytes.
- STL (ascii) format, extension ".stl". Typically a set of
"facet" records, giving the XYZ coordinates of each vertex like
so:
facet normal 0 0 0
outer loop
vertex -0.099739 -0.086973 1.836396
vertex -0.054167 -0.390427 1.914516
vertex -0.055830 -0.220691 1.952528
endloop
endfacet
One annoyance with STL files is the same vertex gets written
many times,
because they don't send a vertex list, just the XYZ
positions. This uses much more memory than an indexed
format.
- DXF (ascii) format,
extension ".dxf". This is AutoCad's "Drawing eXchange
Format", but it also supports 3D models (barely!). It's
basically a long series of AutoCad commands, and so isn't very
easy to read.
- To export a fully-rigged model, preserving all the animation
and bone info, takes an industrial-strength file format, the 3D
analog of a complicated image file format like JPEG/EXIF.
There's a recent XML-based standard called COLLADA that attempts to be
that format; the extent of my experience with this is that the
XML looks pretty unreadable, and so does the code that reads it.
Typically, when reading a new 3D object file format, I will:
- Research and use a hex dump tool to figure out how the file is
organized.
- Try to read and dump some XYZ coordinates to the screen.
This usually takes a few tries, and tells me what the scale
factors are (e.g., all coordinates between -0.00001 and
+0.00003, or -1000 and +30000).
- Splat some GL_POINTS at the XYZ coordinates of the
vertices. This usually takes some tweaking to get the
scale factor correct (meters, inches, or millimeters?), and
here's where I need to fight the Y/Z up axis question.
- Draw GL_TRIANGLES at the face indices. There are often
issues with things like 0-based versus 1-based numbering (which
makes a spiky-looking glob instead of a smooth object).
- Try to recover the existing normals, or compute my own
normals. I usually need to compute my own.
- Try to figure out texture coordinates. By this point,
I'll likely just bodge something together!
Loading Models in THREE.js
In THREE.js, there are a whole set of file format loaders in threejs/examples/js/loaders/.
Generally, these are objects with a "load" function that fetches the
mesh data from a web server. The loaded mesh data is passed to
a "parse" function that converts it to a THREE.Geometry object like
this:
parse: function ( data ) {
var geometry = new THREE.Geometry();
while ( --data has more faces -- ) {
if ( -- face has a normal -- ) {
var normal = new THREE.Vector3( -- XYZ normal -- );
}
while (-- face has more vertices --) {
geometry.vertices.push( new THREE.Vector3( -- XYZ vertex -- ) );
}
var len = geometry.vertices.length;
geometry.faces.push( new THREE.Face3( len - 3, len - 2, len - 1, normal ) );
}
geometry.computeCentroids();
geometry.computeBoundingSphere();
return geometry;
}
The STLLoader currently returns a THREE.Geometry object, and you
create your own THREE.Mesh.
The OBJLoader is supposed to return a THREE.Object3D, but had a bug
before 2013-02-01 where it missed the last mesh, even if it was the
only mesh!
The ColladaLoader returns a custom object with a ".scene"
field.
Aside from figuring out the return value, it's really pretty
straightforward. One annoying part is the data gets loaded
using an XMLHttpRequest, which sadly is subject to the "same-origin"
rule: it can only fetch data from the same server, not a local file
(this is to protect your computer from random JavaScript reading
your files).
Model
Loader Demo