In traditional studio modeling, making a model look like a giant spaceship instead of the plastic simulacrum it is requires a number of illusory tricks. Complex surface detail is one way, but another trick is to provide features of relatable scale that imply size. We are all familiar with the approximate size of a window and how large it is in comparison to a person, which makes windows a reliable method for implying scale. With CG, we can even set simple (or complex!) rooms behind these windows to imply depth and volume of our spaceship.

Putting windows into a polygonal mesh isn't terribly difficult, but it can be tedious. Be patient and diligent, because the visual payoff is well worth it.

Windows represent a structural weakness in any surface. A "real" spaceship is not likely to have very many and those that it does have are likely to be pretty small. Further, never ever put windows in a spaceship that don't have rounded corners. As we learned when trying to put square-shaped windows into airplanes, any hard corner is a focal point for stress, meaning it's that much more likely to break, fracture, or otherwise compromise its structural integrity. For something that's already a structural weakness, this compounds the issue. The reason all airplane windows are round is to spread out these stresses and the same logic applies to spacecraft. It has nothing to do with air and everything to do with acceleration forces. TL;DR, make sure your windows have rounded corners or I will disown you!

The first step in creating windows is to create a window profile template. This is a 2D representation of the shape your window will take when set into the ship's hull. If you want circular portholes, just create a Circle or a Cylinder with no height. If you want long or wide windows (with rounded edges!), we still start with a Circle, but we need to be deliberate in how many vertices we choose.

For Trek-style windows, the general form is often a line capped on either end by a semi-circle. An easy way to make one is to create a filled circle, rotate it, and pull the bottom verts "down." For this example, I have windows that are 0.5 meters across (radius = 25 cm), and 1 meter tall. Since this is a small feature for a large ship, but I still want it to stand up to pretty close shots, I went with 34 vertices. Also, note the 90° X rotation to orient it vertically.

Why 34 and not the default 32? That trick I mentioned above about pulling verts "down." With 32, you have verts at 0°, 90°, 180°, and 270°. The verts at 90° and 270° mean you'll have some ugly tapering if you try to just pull on the bottom verts. By adding two more verts, you get a pair of edge verts that can be evenly divided between the top and bottom. This isn't a killer issue, of course. You can always split the circle and then separate the two halves to achieve the same result. This is just faster.

Next, extrude (e, y for extruding along the Y axis) your window profile by a fair amount, so that one side of the extrusion rests outside of your hull and the other side sits well inside it. In the example here, we're dealing with a large saucer section of a starship, so the extrusion is about 20m.

Presumably, you're not putting in a single window, but a number of them. Blender makes this easy with the Array modifier, coupled with an Offset Object. For this particular example, I have a circular saucer section from a Trek ship, so I want to create an array of windows that goes around the entire saucer perimeter.

First, put the origin of the window object at the radial axis of your saucer. This step doesn't apply to non-radial situations in the same way, but positioning your window object's origin in particular ways can net you all sorts of interesting effects. To do this, assuming your saucer's center is at its axial origin:

  1. Select the saucer in Object Mode.
  2. Position the cursor at its center (Shift S, 3 or Shift S, C).
  3. Select the window object in Object Mode.
  4. Set the window object's origin to the cursor (Ctrl Alt Shift C, t or Ctrl Alt Shift C, 3).

If your saucer's center isn't at its axial origin:

  1. Reset the saucer's origin (Ctrl Alt Shift C, o or Ctrl Alt Shift C, 2).
  2. Set the cursor to the object's center (Shift S, 3 or Shift S, C).
  3. Select the single vertex at the top of the saucer
  4. Copy its X location to the cursor's X location (in the Properties panel of the 3D View; (n) opens it if it's not already open).
  5. Set the saucer's origin to the cursor (Ctrl Alt Shift C, t or Ctrl Alt Shift C, 3).
  6. Follow the steps above.

Next, with the cursor still at the saucer's center, add an Empty and name it something like Rotator.Window or some other easily recognizable name.

Even if you don't want a window in the dead center of your saucer's midline, leave this initial window object there. You can delete any that you don't want later. For the sake of simplicity, I'm also going to assume that you're left-right mirroring your model, so you only have to work on half of it.

The next thing you need to do is decide at what minimum interval you want your windows. This is a bit tricky to explain, and you can wing it if you want to, but your results will be more reliable if you don't.

Math Time

For my particular example, I had 32 panels per 90° segment of the saucer, which meant I had grid lines every 90° ÷ 32 = 2.8125°. I wanted to have as many as three windows per panel, which meant that each window would be at minimum 0.703125° apart. Why that number? Because 2.8125° represents the angle span between two grid lines, and I wanted three additional bits within those lines. One of the grid lines counts as "0" but the other counts as n+1, where n is the number of bits I want. Net result: 2.8125° ÷ (3 bits + 1) = 0.703125°. If this doesn't make sense, don't worry; just remember to divide your panel arc by the maximum number of windows you want in it plus one.

Alternately, suppose you want to have two or three windows per panel, but you don't want those two-window panels to be confined to being in one of the three-window panel positions, which is a constraint you'd have with the above method. In this case, you sum them. Rather than figuring out the angle for 2 or 3-window panels, you do it for a 5-window panel, and then remove the extra window profiles it generates.

Back to the Windows

Based on whatever minimum interval you settled on, apply this rotation value to the Empty rotator's Z rotation. At this point, you should also apply any Rotation or Scale that's applied to your window object (Ctrl A, 4 or Ctrl A, o).

Now, add the Array modifier to your window object. You'll have to uncheck Relative Offset, which is checked by default, if you're following the radial explanation. (If you're doing something else, feel free to experiment with the various options to your heart's content.) Instead, check Object Offset and select your Rotator.Window Empty from the field below the Object Offset checkbox. If everything went well, you should see two copies of your window, one in the original position and one rotated a small amount around the saucer object's axis!

Increase the Count until you have as many window object copies as you need. When working with radial saucers like this, it's often advantageous to just do one "wedge" worth and then copy the result of all of our labor, but sometimes there are differences in each wedge, precluding this. With my example numbers, I needed 257 to get 180° around the saucer.

Image coming soon.

Once you're happy, Apply the Array modifier to create the copies of the window. Now that you have an array of too many windows, it's time to go through and delete the ones you don't need. The easiest way to do this is to go into Face mode (Ctrl Tab, f) and use Lasso Select to select the middle faces of the window objects you don't want. Then select linked faces (Ctrl l), and hit Delete.

Image coming soon.

We're going to cut the windows into the hull, which means a Boolean operation. Boolean operations are slow, cumbersome, and expensive. The less data we feed into the calculation, the better. As such, select only the faces on your hull that are going to be affected by the windows and then Separate (p, 1) them into their own mesh. We'll rejoin them to the main hull later.

Image coming soon.

With the separated hull faces selected, go to the Modifier panel and add a Boolean modifier at the top of the list. Generally, Intersect is the proper setting; one of the settings will be correct, and it's usually not intuitive (ideally, it would be Subtract, but this is rarely the case in practice). Set the Object to your window object. If all goes well, you should now see your hull panels will windows cut into them and the remaining window profile either sticking into the hull or jutting out.

Image coming soon.

The very next thing to do is go into Vertex mode (Ctrl Tab, v), Lasso Select (Ctrl LMB) the inset/outset vertices that are left over from the Boolean operation, and delete them. This will leave you with your be-windowed hull panels. However, there's more to clean up!

Image coming soon.

You'll have to inspect each window one at a time for errant vertices. Sometimes, the boolean operation will be clean and there won't be any. Other times, many errant vertices will be around. Errant vertices are especially problematic along the top/bottom arches of the window. They can be identified as vertices that sit along an edge, but don't alter the shape of the edge. Select each vert that qualifies and drag-snap (Shift Tab to enable snapping, Ctrl Shift Tab, v for Vertex mode; use g to move verts) to the nearest non-errant vert. Once you're done, Remove Doubles (w, r).

Image coming soon.

There may also be errant verts along the long edges of the window, but if you've Booleaned across a bend in the hull, be careful about identifying them!

Image coming soon.

Once all of the errant verts are gone, the next step is to clean up the probably-ugly triangulation left behind. Notice that each window in my sample has a "hull panel" of polygons around it that is unique to it. This may not always be the case, but when it is, it's advantages to use it. Select every other hull panel around each window and perform the following sequence:

Image coming soon.

Repeat the above steps for the hull panels we skipped the first time around. The reason to do it in two passes is to prevent Beautify Fill from getting over-zealous about reshaping our hull geometry.

As a final step, make sure there are no non-manifold polygons along the inner edge of the windows. They can sometimes creep in during this optimization pass.

Image coming soon.

Finally, select one long edge of each window. This can be sped up by doing a Select Similar with Length (Shift g, l), but it's not always reliable. Once they're all selected, select Edge Loop (Ctrl e, l) to select the entire window frame and then create a polygon (f). With your new window polygons still selected, apply a new Material to them called something like Window Frame.

Image coming soon.

Use Inset Polygon (i) to inset the window frame slightly. I used values of 0.015m and 0.025m for depth and thickness, respectively. This gives a nice beveled edge to the window frame. Make sure you uncheck Select Outer, so that the window panel itself is still selected, rather than the beveled edge.

Image coming soon.

Next, Extrude with 0 length (e, 0, Enter) and then Shrink/Fatten (Alt s) or scale with Z locked (s, Shift z) in Cursor mode, with the Cursor at the center of your object a distance that seems appropriate to you. I tend to use 0.5m or so.

Image coming soon.

If you're going to create rooms behind your windows, delete the end polygon. Otherwise, apply a new Material called something like "Window Interior". Join the separated object back into your main hull object (in Object Mode, select both, hit Ctrl j), switch to Edit Mode and Remove Doubles.

All done!

Going Further: Creating Rooms

Coming soon: tutorial on creating rooms.

Alternate Methods

Coming soon: alternate method, by snap to face/shrink-wrap, deleting polygons and creating new ones.