Chapter 7. Drawing in 3D

3D graphics often looks more impressive than 2D graphics because 3D has unique expressive capabilities, such as depth, perspective, and shading. Also, the third dimension allows objects to interweave and twist in the space in ways that are hard to achieve using 2D graphics. In this chapter we will cover the basics of rendering and animating 3D surfaces and primitive clouds with openFrameworks. We'll cover the following topics:

  • Simple 3D drawing
  • Using ofMesh
  • Enabling lighting and setting normals
  • Texturing
  • Working with vertices

3D basics

Working with 3D means working with objects modeled in the three-dimensional scene, where the dimensions are horizontal (x), vertical (y), and depth (z). The resulting 3D scene is projected either onto a 2D image to show it on the screen, two 2D images for stereoscreen, or even printed as a 3D object using a 3D printer.

Representation of 3D objects

Each 3D object is represented using a number of elementary primitives such as points, line segments, triangles, or other polygons. Methods of the object's representation are as follows:

  • An object is a number of surfaces assembled from polygonal primitives such as triangles and quadrangles (often called quads). This method is used in 3D-modeling software for representing "surface" objects, such as a human body, a car, a building, and also clothes and a rippled water surface.
  • An object is a number of curves assembled from line segments. Such a representation is used for modeling hair and fur.
  • An object is a huge number of small points called particles. This is representation of objects without distinct shape: smoke, clouds, fire, and a waterfall (see Chapter 3, Building a Simple Particle System).

These methods refer to realistic representation of real-world objects. We are interested in experimental 3D, so we can play with representations freely. For example:

  • Triangles can be used to draw some clouds made from triangles but not smooth surfaces
  • Thousands of long curves can interweave inside a volume with specified bounds, creating an evolving "hairy" 3D object
  • Particles can represent a rigid 3D object that suddenly changes its shape in a complex way

In openFrameworks, you can represent and draw 3D objects by yourself; see the Simple 3D drawing section. But normally it is preferable to use a powerful ofMesh class, which lets you represent and draw surfaces, curves, particles, and distinct primitives at the fastest speed; see the Using ofMesh section. Also you can manipulate the static and animated 3D models stored in files such as 3DS; see the Additional topics section.

3D scene rendering

In this chapter we will consider rendering a 3D scene on a 2D screen (and will not consider stereoscreens and 3D printers).

Recall that, when we draw a flat 2D scene, we just imprint objects such as images and curves onto the screen at the specified coordinates. And the order of the object's drawing defines its visibility; the last object is visible as a whole and can occlude the objects drawn before it.

The rendering of a 3D scene differs from the case of a 2D scene because the object's visibility here is defined by its z coordinate (depth). By default, in openFrameworks, points with a zero value for the z coordinate forms an xy plane, which is used for 2D drawing. Increasing and decreasing the value of the z coordinate leads to moving the objects closer or farther correspondingly.

openFrameworks graphics is based on Open Graphics Library (OpenGL), which renders objects using z-buffering technology. This technology just stores z values for each screen pixel in a special buffer, called z-buffer (or depth buffer). During rendering, if the z value of the object's pixel is greater than the z value in the buffer, the pixel is rendered and the z-buffer is updated to this value. Otherwise, the object's pixel is not rendered.

By default, the z-buffering is disabled. To enable it, call the following function:

ofEnableDepthTest();

When enabled, the z-buffer clears automatically at each frame, together with the background drawing (if you do not call ofSetBackgroundAuto( false )). To disable z-buffering, use the ofDisableDepthTest() function.

Tip

There is another 3D rendering technology, called ray tracing. Instead of directly projecting the pixels of primitive onto the screen, it simulates light ray propagation from the light sources to the camera. Such a method is a natural way to construct shadows and other natural-world lighting effects. It is used for the highest quality 3D graphics and is available in 3D animation software. But its real-time implementations are currently very resource intensive, and we do not consider them here.

The volumetric nature of the 3D objects introduces new attributes into the 3D scene. These are lights, the object's materials interacting with lights, the 3D scene perspective, and virtual cameras. See the Enabling lighting and setting normals and Additional topics sections for more information.

Note, the modern approach in 3D that includes advanced lighting and shading, object's shape manipulation, and the rendered scene postprocessing requires using shaders; see Chapter 8, Using Shaders, for further details.

Tip

openFrameworks is a thin wrapper over OpenGL, so it provides low-level functionality, which is great for working with custom-generated 3D graphics. However, if you need to work with 3D worlds consisting of many life-like models and characters, it is probably better to use some other 3D engine, such as Unity 3D. We use Unity 3D for complex 3D world rendering and add interactivity by controlling it from openFrameworks' project, which processes sensors such as depth cameras. openFrameworks and Unity 3D are connected via OSC network protocol; see Chapter 11, Networking.

Now we will consider a simple 3D drawing example with openFrameworks.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset