➩ Add an extra number per pixel: color buffer (RGB) and z-buffer (Z).
➩ Start with all pixels at max distance (far distance of the camera).
➩ When drawing a pixel \(\left(x, y\right)\) with color \(c\) at depth \(z\), if \(z\) value is smaller than the current \(\left(x, y\right)\) z-value (closer to the camera), replace the pixel color with \(c\) and z-value with \(z\).
📗 Some uniforms and attributes are built-in (no need to declare them in shader programs): Doc.
Type
Variable
Math
Note
Vertex shader
uniform mat4 modelMatrix
4 x 4 matrix
-
-
uniform mat4 modelViewMatrix
4 x 4 matrix
viewMatrix * modelMatrix
-
uniform mat4 projectionMatrix
4 x 4 matrix
-
-
uniform mat4 viewMatrix
4 x 4 matrix
-
-
uniform mat3 normalMatrix
3 x 3 matrix
inverse transpose of modelViewMatrix
-
uniform vec3 cameraPosition
3 x 1 vector
-
-
attribute vec3 position
3 x 1 vector
-
-
attribute vec3 normal
3 x 1 vector
-
-
attribute vec3 uv
3 x 1 vector
-
📗 There are some uniforms and attributes that are conditional depending on the material and geometry.
📗 For other built-in uniform, for example THREE.UniformLib['lights'], there is a list: Link.
Math Note
📗 Suppose the model view matrix is \(M\) and a tangent vector is \(t\), then the tangent vector in the view space is \(M t\).
📗 Now given normal vector \(n\) perpendicular to \(t\), that is \(n^\top t = 0\), the normal vector in the view space, say \(N n\), should still be perpendicular to \(M t\), that is \(\left(N n\right)^\top \left(M t\right) = 0\)
📗 Combine the two equations, \(n^\top t = 0 = n^\top N^\top M t\) for all \(t\), meaning \(N^\top M = I\), which mean \(N = \left(M^{-1}\right)^\top\), which is the normal matrix.
📗 Affine transformations in 2D were represented by linear transformations in 3D (3 by 3 matrices in HTML Canvas \(\begin{bmatrix} a & c & e \\ b & d & f \\ 0 & 0 & 1 \end{bmatrix}\)), similarly affine transformations in 3D can be represented by linear transformations in 4D (modelMatrix is 4 by 4).
➩ Translation in 3D can be viewed as shearing in 4D on the \(z = 1\) hyperplane.
➩ Rotation and scaling in 3D can still be rotation and scaling in 4D.
➩ A 3D point \(\begin{bmatrix} x \\ y \\ z \end{bmatrix}\) can be represented by 4D point with \(w = 1\), \(\begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix}\) (homogeneous coordinate system)
➩ Arbitrary 4D linear transformations can be applied to \(\begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix}\), and the result can be projected back onto \(w = 1\) hyperplane (\(\begin{bmatrix} x' \\ y' \\ z' \\ w' \end{bmatrix}\) can be projected back as \(\begin{bmatrix} \dfrac{x'}{w'} \\ \dfrac{y'}{w'} \\ \dfrac{z'}{w'} \\ 1 \end{bmatrix}\)).
📗 The simplest (the one used by THREE.js) vertex shader computes the position of a vertex projected onto the screen: gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0).
➩ projectionMatrix projects a point in 3D camera space onto 2D screen space.
➩ modelViewMatrix projects a point in the 3D scene space onto 3D camera space.
➩ vec4(position, 1.0) is the homogeneous coordinates of the position attribute of the vertex.
📗 Note: 1.0 is a float and 1 is an int, they are different in shader program.
📗 For most of the workbook exercises, vertex shader does not need to be changed.
📗 Another use of vertex shader is to create a larger version of the geometry by moving all vertices in the normal direction and render only the back faces or set side: THREE.BackSide.
➩ smoothstep: smoothstep(t1, t2, x) is the smooth version of step, goes from 0.0 to 1.0 smoothly for x between t1 and t2. This is useful to get smooth transition between two colors.
Math
📗 smoothstep performs smooth Hermite interpolation: for x between t1 and t2, t = (x - t0) / (t1 - t0); and smoothstep(t1, t2, x) = t * t * (3.0 - 2.0 * t).
📗 The simplest fragment shader uses a constant color for every fragment (pixel): gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) colors every pixel of the object (group of triangles), the last 1.0 is transparency.
📗 Interesting appearances (shading) can be created using changing the way the pixels are colored: all of these happen in the fragment shader.
📗 Uniforms can be created by JavaScript and passed in the THREE.ShaderMaterial, for example, THREE.ShaderMaterial(uniforms = {t: {value: 0.0}, u: {value: 0.0}}, ...).
📗 Attributes can be created and set for THREE.BufferGeoemtry bg too, for example, bg.setAttribute("v", ...).
📗 Change the vertex displacement or fragment color as a function of t (time) or u (slider value).
📗 Notes and code adapted from the course taught by Professor Michael Gleicher.
📗 Please use Ctrl+F5 or Shift+F5 or Shift+Command+R or Incognito mode or Private Browsing to refresh the cached JavaScript: Code.
📗 You can expand all the examples and demos: , or print the notes: .
📗 If there is an issue with TopHat during the lectures, please submit your answers on paper (include your Wisc ID and answers) or this Google Form at the end of the lecture.