MULTIMEDIA

iPhone 3D Programming : Adding Depth and Realism - Surface Normals (part 1)

1/7/2011 9:10:09 AM
Before we can enable lighting, there’s yet another prerequisite we need to get out of the way. To perform the math for lighting, OpenGL must be provided with a surface normal at every vertex. A surface normal (often simply called a normal) is simply a vector perpendicular to the surface; it effectively defines the orientation of a small piece of the surface.

1. Feeding OpenGL with Normals

You might recall that normals are one of the predefined vertex attributes in OpenGL ES 1.1. They can be enabled like this:

// OpenGL ES 1.1
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, stride, offset);
glEnable(GL_NORMALIZE);

// OpenGL ES 2.0
glEnableVertexAttribArray(myNormalSlot);
glVertexAttribPointer(myNormalSlot, 3, GL_FLOAT, normalize, stride, offset);


I snuck in something new in the previous snippet: the GL_NORMALIZE state in ES 1.1 and the normalize argument in ES 2.0. Both are used to control whether OpenGL processes your normal vectors to make them unit length. If you already know that your normals are unit length, do not turn this feature on; it incurs a performance hit.

Warning:

Don’t confuse normalize, which refers to making any vector into a unit vector, and normal vector, which refers to any vector that is perpendicular to a surface. It is not redundant to say “normalized normal.”


Even though OpenGL ES 1.1 can perform much of the lighting math on your behalf, it does not compute surface normals for you. At first this may seem rather ungracious on OpenGL’s part, but as you’ll see later, stipulating the normals yourself give you the power to render interesting effects. While the mathematical notion of a normal is well-defined, the OpenGL notion of a normal is simply another input with discretionary values, much like color and position. Mathematicians live in an ideal world of smooth surfaces, but graphics programmers live in a world of triangles. If you were to make the normals in every triangle point in the exact direction that the triangle is facing, your model would looked faceted and artificial; every triangle would have a uniform color. By supplying normals yourself, you can make your model seem smooth, faceted, or even bumpy, as we’ll see later.

2. The Math Behind Normals

We scoff at mathematicians for living in an artificially ideal world, but we can’t dismiss the math behind normals; we need it to come up with sensible values in the first place. Central to the mathematical notion of a normal is the concept of a tangent plane, depicted in Figure 1.

The diagram in Figure 1 is, in itself, perhaps the best definition of the tangent plane that I can give you without going into calculus. It’s the plane that “just touches” your surface at a given point P. Think like a mathematician: for them, a plane is minimally defined with three points. So, imagine three points at random positions on your surface, and then create a plane that contains them all. Slowly move the three points toward each other; just before the three points converge, the plane they define is the tangent plane.

The tangent plane can also be defined with tangent and binormal vectors (u and v in Figure 1), which are easiest to define within the context of a parametric surface. Each of these correspond to a dimension of the domain; we’ll make use of this when we add normals to our ParametricSurface class.

Finding two vectors in the tangent plane is usually fairly easy. For example, you can take any two sides of a triangle; the two vectors need not be at right angles to each other. Simply take their cross product and unitize the result. For parametric surfaces, the procedure can be summarized with the following pseudocode:

p = Evaluate(s, t)
u = Evaluate(s + ds, t) - p
v = Evaluate(s, t + dt) - p
N = Normalize(u × v)

Figure 1. Normal vector with tangent plane


Don’t be frightened by the cross product; I’ll give you a brief refresher. The cross product always generates a vector perpendicular to its two input vectors. You can visualize the cross product of A with B using your right hand. Point your index finger in the direction of A, and then point your middle finger toward B; your thumb now points in the direction of A×B (pronounced “A cross B,” not “A times B”). See Figure 2.

Figure 2. Righthand rule


Here’s the relevant snippet from our C++ library (see the appendix for a full listing):

template <typename T>
struct Vector3 {
// ...
Vector3 Cross(const Vector3& v) const
{
return Vector3(y * v.z - z * v.y,
z * v.x - x * v.z,
x * v.y - y * v.x);
}
// ...
T x, y, z;
};
Other  
  •  iPhone 3D Programming : Adding Depth and Realism - Filling the Wireframe with Triangles
  •  iPhone 3D Programming : Adding Depth and Realism - Creating and Using the Depth Buffer
  •  iPhone 3D Programming : Adding Depth and Realism - Examining the Depth Buffer
  •  iPhone 3D Programming : HelloCone with Fixed Function
  •  iPhone 3D Programming : Vector Beautification with C++
  •  jQuery 1.3 : An image carousel
  •  jQuery 1.3 : Headline rotator
  •  Silverlight : Print a Document
  •  Silverlight : Capture a Webcam
  •  Silverlight : Make Your Application Run out of the Browser
  •  Silverlight : Put Content into a 3D Perspective
  •  Silverlight : Response to Timer Events on the UI Thread
  •  Silverlight : Build a Download and Playback Progress Bar
  •  Silverlight : Play a Video
  •  C# 4.0 : Add a Static Constructor and Initialization
  •  C# 4.0 : Add a Constructor
  •  .NET Compact Framework : Font Selection
  •  .NET Compact Framework : Drawing Text
  •  Programming the Service Bus
  •  WCF Services : Generics
  •  
    Top 10
    Has Apple Lost It? (Part 2)
    Has Apple Lost It? (Part 1)
    Sony Computer Entertainment (Part 3)
    Sony Computer Entertainment (Part 2)
    Sony Computer Entertainment (Part 1)
    Sony's 4K Ultra World - Ready For Yet Another Resolution Revolution
    Analyze This - Wi-Fi Nets Via Smartphone (Part 2)
    Analyze This - Wi-Fi Nets Via Smartphone (Part 1)
    Devolo dLAN 500 AV Wireless + Starter Kit
    The Slithery World Of Hybrid Cloud Security
    Most View
    Windows Server 2008 R2 : Manage Remote Desktop Services (part 2) - Configure Remote Desktop Gateway, Configure Remote Desktop Connection Broker
    .NET Debugging : PowerDbg (part 2) - Send-PowerDbgCommand & Extending PowerDbg
    SAM PowerPC With AmigaOS 4.1
    A Trio From HIS: 7970 IceQ X² GHz Edition, 7950 IceQ X² Boost Clock And 7850 IceQ Turbo X Graphics Cards Review (Part 6)
    Windows Server 2008 Server Core : Working with Scripts - Creating a Basic Script
    Noctua NH-L12 - Low-Profile And Low Noise
    Focal XS Book Music System
    The Tie That Binds
    The best browser hacks (part 1) - Mozilla Firefox
    EX-05 Multi-Format Wireless Headset - In The Army
    WCF Services : Data Contract - Attributes
    AR.Drone 2.0. Parrot New Wi-Fi Quadricopter
    Nokia Lumia 822 Windows Phone 8 Smartphone (Part 2)
    SQL Azure : Tuning Techniques (part 3) - Indexing
    Adobe Photoshop CS5 : Choosing the Right Process Version
    Fujifilm X-E1 - The Perfect Travel Camera
    Share and stream media (Part 2) - Stream away to an Android device
    Sharepoint 2007: Specify Your Colleagues
    Meet Intel’s Core i7-3820 (Part 3)
    Connectivity Matters