MULTIMEDIA

iPhone 3D Programming : Adding Shaders to ModelViewer (part 2)

1/14/2011 2:39:55 PM

2. Per-Pixel Lighting

When a model has coarse tessellation, performing the lighting calculations at the vertex level can result in the loss of specular highlights and other detail, as shown in Figure 1.

Figure 1. Tessellation and lighting (from left to right: infinite tessellation, vertex lighting, and pixel lighting)


One technique to counteract this unattractive effect is per-pixel lighting; this is when most (or all) of the lighting algorithm takes place in the fragment shader.


Warning:

Shifting work from the vertex shader to the pixel shader can often be detrimental to performance. I encourage you to experiment with performance before you commit to a specific technique.


The vertex shader becomes vastly simplified, as shown in Example 6. It simply passes the diffuse color and eye-space normal to the fragment shader.

Example 6. PixelLighting.vert
attribute vec4 Position;
attribute vec3 Normal;
attribute vec3 DiffuseMaterial;

uniform mat4 Projection;
uniform mat4 Modelview;
uniform mat3 NormalMatrix;

varying vec3 EyespaceNormal;
varying vec3 Diffuse;

void main(void)
{
EyespaceNormal = NormalMatrix * Normal;
Diffuse = DiffuseMaterial;
gl_Position = Projection * Modelview * Position;
}

The fragment shader now performs the burden of the lighting math, as shown in Example 7. The main distinction it has from its per-vertex counterpart  is the presence of precision specifiers throughout. We’re using lowp for colors, mediump for the varying normal, and highp for the internal math.

Example 7. PixelLighting.frag
varying mediump vec3 EyespaceNormal;
varying lowp vec3 Diffuse;

uniform highp vec3 LightPosition;
uniform highp vec3 AmbientMaterial;
uniform highp vec3 SpecularMaterial;
uniform highp float Shininess;

void main(void)
{
highp vec3 N = normalize(EyespaceNormal);
highp vec3 L = normalize(LightPosition);
highp vec3 E = vec3(0, 0, 1);
highp vec3 H = normalize(L + E);

highp float df = max(0.0, dot(N, L));
highp float sf = max(0.0, dot(N, H));
sf = pow(sf, Shininess);

lowp vec3 color = AmbientMaterial + df * Diffuse + sf * SpecularMaterial;

gl_FragColor = vec4(color, 1);
}


Note:

To try these, you can replace the contents of your existing .vert and .frag files. Just be sure not to delete the first line with STRINGIFY or the last line with the closing parenthesis and semicolon.


Shifting work from the vertex shader to the fragment shader was simple enough, but watch out: we’re dealing with the normal vector in a sloppy way. OpenGL performs linear interpolation on each component of each varying.  Pragmatically speaking, simply renormalizing the incoming vector is often good enough.

3. Toon Shading

Mimicking the built-in lighting functionality in ES 1.1 gave us a fairly painless segue to the world of GLSL. We could continue mimicking more and more ES 1.1 features, but that would get tiresome. After all, we’re upgrading to ES 2.0 to enable new effects, right? Let’s leverage shaders to create a simple effect that would otherwise be difficult (if not impossible) to achieve with ES 1.1.

Toon shading (sometimes cel shading) achieves a cartoony effect by limiting gradients to two or three distinct colors, as shown in Figure 2.

Figure 2. Toon shading


Assuming you’re already using per-pixel lighting, achieving this is actually incredibly simple; just add the bold lines in Example 8.

Example 8. ToonShading.frag
varying mediump vec3 EyespaceNormal;
varying lowp vec3 Diffuse;

uniform highp vec3 LightPosition;
uniform highp vec3 AmbientMaterial;
uniform highp vec3 SpecularMaterial;
uniform highp float Shininess;

void main(void)
{
highp vec3 N = normalize(EyespaceNormal);
highp vec3 L = normalize(LightPosition);
highp vec3 E = vec3(0, 0, 1);
highp vec3 H = normalize(L + E);

highp float df = max(0.0, dot(N, L));
highp float sf = max(0.0, dot(N, H));
sf = pow(sf, Shininess);

if (df < 0.1) df = 0.0;
else if (df < 0.3) df = 0.3;
else if (df < 0.6) df = 0.6;
else df = 1.0;

sf = step(0.5, sf);

lowp vec3 color = AmbientMaterial + df * Diffuse + sf * SpecularMaterial;

gl_FragColor = vec4(color, 1);
}

Other  
  •  iPhone 3D Programming : Adding Depth and Realism - Shaders Demystified
  •  Programming with DirectX : Transformation Demo
  •  Programming with DirectX : View Transformations
  •  Programming with DirectX : World Transformations
  •  Programming with DirectX : Projection Transformations
  •  iPhone 3D Programming : Adding Depth and Realism - Lighting Up (part 2)
  •  iPhone 3D Programming : Adding Depth and Realism - Lighting Up (part 1)
  •  iPhone 3D Programming : Adding Depth and Realism - Surface Normals (part 2)
  •  iPhone 3D Programming : Adding Depth and Realism - Surface Normals (part 1)
  •  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
  •  
    Most View
    Rosewill Launches Armor Evolution Mid-Tower Case
    Keep Kids Online Safely (Part 1)
    Extending the Real-Time Communications Functionality of Exchange Server 2007 : Installing OCS 2007 (part 2)
    Buyer’s Guide: e-Readers That Fits Your Needs Best (Part 1)
    Thunderbolt External Drives (Part 1)
    Apple iPhone 5 - Fails To Return To The Top (Part 2)
    Syncing And Streaming (Part 2) - Apple TV, The remote app
    Preparing Your Windows 8 PC : Adding Devices in Windows 8 (part 1) - Viewing Installed Devices
    Group Test: Free Office Suites (Part 3) - LibreOffice
    Turn An Old Computer Into A Server Using Ubuntu (Part 2)
    Top 10
    The NZXT Kraken X40 Compact Liquid Cooler Review (Part 3)
    The NZXT Kraken X40 Compact Liquid Cooler Review (Part 2)
    T-Mobile’s Samsung Galaxy Note II Review (Part 6)
    T-Mobile’s Samsung Galaxy Note II Review (Part 5)
    T-Mobile’s Samsung Galaxy Note II Review (Part 4)
    T-Mobile’s Samsung Galaxy Note II Review (Part 3)
    T-Mobile’s Samsung Galaxy Note II Review (Part 2)
    T-Mobile’s Samsung Galaxy Note II Review (Part 1)
    Sony Cybershot DSC-TF1 - Affordable Water-Resistant Camera
    Buffalo MiniStation Slim 500GB External Hard Drive