3D Compass Implementation

Introduction Preparation Steps Highlights Texture Map Vertex Shader Fragment Shader Summary

Compass Rotations

Compass Rotations

Introduction

This tutorial includes some optimization tips with steps to prepare a 3D model for display online with WebGL lighting. A trade off exists between loading small indexed files with normal data for lighting. Indexed, eight bit files, are often simple with small file sizes. Normal data increases overall initialization size and time. Yet normal data's required for shader highlights.

Indexed files may appear bland with minimal lighting and shadows. Normal data with shader lighting provides form and highlights, even with eight bit texture maps. This lesson covers model preparation, vertex and fragment shaders, which process highlights and rendering for the Virtual Compass. The Virtual Compass uses an eight bit indexed texture map but requires normal data to display lighting with the shaders. The lightweight texture map comes alive with shader lighting.

Preparation Steps

The original compass model was provided by a third party. However the model required some repairs to render well. Seven Thunder Software filled holes in the geometry with 3ds Max Cap Holes, Border and Cap features.

With 3ds Max, Seven Thunder Software combined all textures into one texture. Most 3D modeling and rendering applications include a render to texture feature which prepares one image map to cover the entire model. In other words render to texture combines a set of maps, including lighting, into one image. It takes less time to download and initialize one texture than multiple textures. The faster the initialization the more likely visitors will stay to see the compass.

The compass was mapped with diffuse colors, rendered to texture, then exported as a DAE file. The baked texture was modified with Photoshop and saved as an eight bit GIF file.

Seven Thunder Software exported the model to DAE format then ran the DAE file through the free WebGL Translator. WebGL Translator extracts vertices, texels, and normals, from a Collada DAE file, then saves a set of arrays for upload to the GPU with WebGL. Normals are required to render highlights with WebGL shaders.

Highlights

The Virtual Compass displays interactive highlights as users swipe to rotate the model. The highlights are generated with vertex normals which require extra initialization time. However the compass loads a lightweight texture map which can speed download time. Shader highlighting provides interactive light to display the compass with shiny metal. In other words, highlighting and other shader features allow the use of very simple texture maps. Lightweight texture maps download and initialize faster than complex images.

Additional processing for normal data might offset download and initialization time with the eight bit graphic. Upload vertex normals once to a vertex buffer object, during initialization. Prepare and upload a normal matrix for every animation frame. Prepare the normal matrix from the inverted and transposed model view matrix.

the Virtual Compass uses a baked texture map which includes some lighting. Rotate the Virtual Compass. For the most part, lighting remains stationary and glints off the compass' metal. In other words, the compass rotates, but the lighting location remains the same, as we might expect in the real world.

Texture Map

The following graphic displays the texture mapped to the Virtual Compass.

Compass Eight Bit Indexed Texture Map

Simple Compass Texture

Vertex Shader

The following vertex shader processes as much as possible. It's better to process values in the vertex shader, than the fragment shader. The fragment shader runs many times more often than the vertex shader.

The following three values, within the vertex shader, process normal data. Attribute a_normal represents a vertex normal, uniform um3_nmatrix represents a normal matrix, and varying v_normal_transform passes normal data through the GPU to the fragment shader.

Please see the Point Light Tutorial for details regarding point light shaders. The following vertex shader processes highlights for the Virtual Compass.

attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_tex_coord0;

uniform mat4 um4_matrix;
uniform mat4 um4_pmatrix;
uniform mat3 um3_nmatrix;

varying vec2 v_tex_coord0;
varying vec3 v_normal_transform;
varying vec4 v_position;

void main(void) {
v_position = um4_matrix * vec4(a_position, 1.0);

gl_Position = um4_pmatrix * v_position;

v_tex_coord0 = a_tex_coord0;
        
// Vertex normal times
// transposed inverted model matrix.
v_normal_transform = um3_nmatrix * a_normal;
}

Fragment Shader

Please see the Point Light Tutorial for details regarding point light shading. The following fragment shader completes processing highlights for the Virtual Compass.

precision mediump float;

varying vec2 v_tex_coord0;
varying vec3 v_normal_transform;
varying vec4 v_position;

const float c_shine_amount = 4.0;
// A little more blue.
const vec3 c_ambient = vec3(0.25,0.26,0.3);

const vec3 c_light_location = vec3(0.5,0.8,-2.0);
const vec3 c_light_dcolor = vec3(0.8,0.8,0.9);
const vec3 c_light_scolor = vec3(0.7,0.8,0.8);

uniform sampler2D u_sampler0;

void main(void) {
 
// Difference between the light's position
// and the current vertex position.  
vec3 v3_light_vector = normalize(
 c_light_location - v_position.xyz
);
 
// Normal times transposed inverted model matrix.
vec3 v3_normalized_normal = normalize(
 v_normal_transform
);

// Will receive the
// amount of highlight.
float f_specular_weight = 0.0;
 
// Line between view point 
// and current vertex           
vec3 v3_direction_eye = normalize(
 -v_position.xyz
);
 
// Reflection of the opposite 
// of the light vector
// and the normal.
vec3 v3_direction_reflection = reflect(
 -v3_light_vector, 
 v3_normalized_normal
);

f_specular_weight = pow(
max(
 dot(
   v3_direction_reflection, 
   v3_direction_eye
 ), 
  0.0
 ), 
 c_shine_amount
);       

float f_diffuse_weight = max(
 dot(v3_normalized_normal, v3_light_vector), 
 0.0
);

vec3 v3_light_weight = c_ambient
 + c_light_scolor * f_specular_weight
 + c_light_dcolor * f_diffuse_weight;

vec4 color0 = texture2D(
 u_sampler0,
 v_tex_coord0
);

gl_FragColor = vec4(
 color0.rgb * v3_light_weight, 
 color0.a
);
}

Summary

This tutorial included some optimization tips with steps to prepare a 3D model for display online with WebGL lighting. A trade off exists between loading small indexed files with normal data for lighting. Indexed, eight bit files, are often simple with small file sizes. Normal data increases overall initialization size and time. Yet normal data's required for shader highlights.

Indexed files may appear bland with minimal lighting and shadows. Normal data with shader lighting provides form and highlights, even with eight bit texture maps. The lesson covered model preparation, vertex and fragment shaders, which process highlights and rendering for the Virtual Compass. The Virtual Compass uses an eight bit indexed texture map but requires normal data to display lighting with the shaders. The lightweight texture map comes alive with shader lighting.

Copyright © 2015 Seven Thunder Software. All Rights Reserved.