In order to model light interaction, what do we care about?
Do we care about the shape? Only how it interacts with light?
Golf ball: dimples just mean that there is a different geometric relationship with light source and viewer.
Cloth: very complex shape, very difficult to model, but to render...
Hair: to make one image we do not care how it moves. Still difficult to model. How does the surface interact with light?
Disco ball: properties of surface make these objects interesting
How does the material reflect light?
Light also has properties that interact with material properties in reasonable ways.
Red light is not reflected by a blue object.
Light does not have direction
In real life, ambient light intensity varies over space, but is often ignored
var lightPosition = Vector4([1.0, 1.0, 1.0, 0.0]); var lightAmbient = Vector4([0.2, 0.2, 0.2, 1.0]); var lightDiffuse = Vector4([1.0, 1.0, 1.0, 1.0]); var lightSpecular = Vector4([1.0, 1.0, 1.0, 1.0]); var materialAmbient = Vector4([1.0, 0.0, 1.0, 1.0]); var materialDiffuse = Vector4([1.0, 0.8, 0.0, 1.0]); var materialSpecular = Vector4([1.0, 0.8, 0.0, 1.0]); var materialShininess = 100.0;
Note: in general, light does not have independent ambient, diffuse, and specular components. We define it this way to provide nice controls.
Recall that computing diffuse reflection has a cosine as a factor.
\[\textrm{diffuse} = \textrm{lightDiffuse} * \textrm{materialDiffuse} * (n \cdot l)\]
In shader:
vec3 diffuse = lightDiffuse * materialDiffuse * nDotL;
Ambient term is computed similarly, only without the cosine
\[\textrm{ambient} = \textrm{lightAmbient} * \textrm{materialAmbient}\]
In shader:
vec3 ambient = lightAmbient * materialAmbient;
Rather than a_Color
being [0.1, 0.1, 0.1]
(dark white), we could separate the color and intensity to provide more flexibility.
a_Color = [1.0, 1.0, 1.0]; k_Diffuse = 0.1;
How do we pass light and material properties to shader?
attribute vec3 a_VertexPosition; attribute vec3 a_VertexNormal; uniform vec4 u_MaterialDiffuse; uniform mat4 u_MVMatrix; uniform mat4 u_PMatrix; uniform mat4 u_NMatrix; uniform vec3 u_LightDirection; uniform vec4 u_LightDiffuse; varying vec4 v_FinalColor;
void main(void) { vec3 N = normalize(vec3(u_NMatrix * vec4(a_VertexNormal, 1.0))); vec3 L = normalize(u_LightDirection); float lambertTerm = dot(N,-L); vec4 Id = u_MaterialDiffuse * u_LightDiffuse * lambertTerm; v_FinalColor = Id; v_FinalColor.a = 1.0; gl_Position = u_PMatrix * u_MVMatrix * vec4(a_VertexPosition, 1.0); }
Intensity of point light incident to a point on a surface depends not only on direction, which varies across surface, but also on the distance.
There is now an \(r^2\) fall-off.
Normal is interpolated across triangle, and the color is calculated in fragment shader.
varying v_SurfaceNormal; // blinn-phong specular reflection vec3 blinnphong(vec3 viewdir, vec3 normal, vec3 lightdir, vec3 lightcol, vec3 matspecular, float matspecexp) { vec3 halfdir = normalize(viewdir + lightdir); float specAng = max(dot(halfdir, normal),0.0); //float specAng = abs(dot(halfdir, normal)); float specular = pow(specAng, matspecexp); return matspecular * lightcol * specular; } void main() { // ... gl_FragColor = vec4(diffuse + ambient + specular, v_Color.a); }
Intensity of reflection is related to the angle of viewer and angle of reflection (depends on surface normal and lighting direction)