3D Gallery with Great Artwork Imagine Logo with Three Colors Beach Cabin 3D Android Tablet with Different Screens Studio Apartment Red Figured Greek Vase on Blue Background Silver and Gold Flashlight Lake on Fire

Shader Lighting Tutorial

GLSL Shaders for WebGL Lights

Introduction Diffuse Light Directional Light Point Light Spot Light Summary

Introduction

This short WebGL shader lighting tutorial discusses diffuse, directional, point light and spot light shaders. Vertex and fragment shaders for the diffuse and spot light shaders are included.

Diffuse Light

Diffuse light represents light with no clear direct light source. Diffuse light reflects off the surface of surrounding objects or shines through semi transparent objects, such as gauze curtains. Diffuse light generally helps define the shape of a three dimensional object, yet with gentle gradation between light and shadow.

Swipe to rotate a ball with diffuse light. The vertex and fragment shaders for diffuse lighting follow.

Diffuse Light: Vertex Shader

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

uniform mat4 um4_matrix;
uniform mat4 um4_pmatrix;

varying vec2 v_tex_coord0;
varying vec3 v3_normal;
varying vec3 v_position; 

void main(void) {

// Position of the vertex with
// perspective projection.
gl_Position = um4_pmatrix * um4_matrix * vec4(
 a_position, 1.0
);
      
v3_normal =  a_normal;
v_position = a_position;

// Texel corresponding to the vertex.
v_tex_coord0 = a_tex_coord0;

}

Diffuse Light: Fragment Shader

precision mediump float;

varying vec2 v_tex_coord0;
varying vec3 v3_normal;
varying vec3 v_position; 

const vec3 c_light_position = vec3(
 0.5,0.5,0.5
);

const vec3 c_light_intensity = vec3(
 0.7,0.7,0.9
);

// Transposed in inverted matrix.
uniform mat3 um3_nmatrix; 
uniform sampler2D u_sampler0;
uniform mat4 um4_model;

void main(void) {

vec3 normal = normalize(um3_nmatrix * v3_normal);

vec3 v4_fragment_pos = vec3(
 um4_model * vec4(v_position, 1.0)
);

vec3 v3_surface = c_light_position - v4_fragment_pos;

float f_brightness = dot(
 normal, v3_surface) 
 / 
 (length(v3_surface) * length(normal)
);

f_brightness = clamp(f_brightness, 0.0, 1.0);

vec4 color0 = texture2D(
 u_sampler0, v_tex_coord0
); 

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

Directional Light

A directional light emits rays of light in one direction. The rays are parallel to each other. Distance doesn't modify the appearance of light on a mesh. For example a violet ball displays the same lighting when it's ten units from a directional light as well as when it's one hundred units from the same directional light.

Point Light

A point light sends rays of light in all directions, from one specified point, similar to a lamp without a lamp shade.

Spot Light

A spot light sends light in one specific direction, fanning out in the shape of a cone. Imagine spot lights as cones of light. The cone's apex represents the spot light's location. The cone's base represents the end of the light's reach. Therefore objects only receive light within the cone's area. The more direct the ray strikes an object's surface, the brighter the light. Less direct rays, near the cone's edges, receive less light. Therefore when the light's ray's perpendicular to the surface (parallel to the normal), then the light's at it's brightest.

The terms specular and spot lights have similar meanings. Specular lighting provides a bright spot of light, where a ray of light from the cone meets the surface at right angles. In other words, the light shines directly on the surface of a mesh. If the light glances off the surface of a mesh, the surface doesn't directly face the light, then less light reflects off that portion of the surface.

Swipe to view specular light on a ball. The following WebGL vertex and fragment shaders process specular lighting. The amount of light rendered, depends on the angle of a surface normal to the direction of a light vector.

Specular Light: Vertex Shader

// Attributes for
// the vertex coordinates,
// normal coordinates,
// texel coordinates.
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_tex_coord0;

// Matrices for the
// model transformation,
// perspective,
// and normals.
uniform mat4 um4_matrix;
uniform mat4 um4_pmatrix;
uniform mat3 um3_nmatrix;

// Texel
varying vec2 v_tex_coord0;

// Normal
varying vec3 v_normal_transform;

// Vertex
varying vec4 v_position;


void main(void) {

v_position = um4_matrix * vec4(
 a_position, 
 1.0
);

// Perspective matrix times
// transformed vertex:
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;

}

Specular Light: Fragment Shader

precision mediump float;

// Texel
varying vec2 v_tex_coord0;

// Transformed normal
// coordinates.
varying vec3 v_normal_transform;

// Vertex.
varying vec4 v_position;

// Highlight
const float c_shine_amount = 32.0;

// Ambient color
const vec3 c_ambient = vec3(
 0.2,
 0.2,
 0.2
);

// Location of light.
const vec3 c_light_location = vec3(
 -10.0,
 -10.0,
 20.0
);

// Color of light.
const vec3 c_light_dcolor = vec3(
 0.8,
 0.8,
 0.8
);

// Specular color.
const vec3 c_light_scolor = vec3(
 0.8,
 0.8,
 0.8
);


// Texture
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
);

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_coor0
);
       
gl_FragColor = vec4(
 color0.rgb * v3_light_weight, 
 color0.a
);
}

Summary

This short WebGL shader lighting tutorial discussed diffuse, directional, point light and spot light shaders. Vertex and fragment shaders for the diffuse and spot light shaders were included.


Ads >
Create 3D Games: Learn WebGL Book 2 Simple Shaders: Learn WebGL Book 4
3D Programming for Beginners: Learn WebGL Book 1

for Web graphics!

Copyright © 2022 Amy Butler. All Rights Reserved.