Operators and Functions

One of the major advantages of GLSL and ESSL are the powerful built-in mathematical operators. ESSL provides many useful operators and functions that simplify vector and matrix operations. According to the specifications, the arithmetic binary operators add (+), subtract (-), multiply (*), and divide (/) operate on integer and floating-point typed expressions, including vectors and matrices. The two operands must be the same type, or one can be a scalar float and the other a float vector or matrix, or one can be a scalar integer and the other an integer vector. Additionally, for multiply (*), one can be a vector and the other a matrix with the same dimensional size as the vector. These result in the same fundamental types (integer or float) as the expressions they operate on. If one operand is a scalar and the other is a vector or a matrix, the scalar is applied component-wise to the vector or the matrix, with the final result being of the same type as the vector or the matrix. It's important to note that dividing by zero does not cause an exception, but it does result in an unspecified value. Let's see a few examples of these operations:

  • -x: The negative of the x vector. It produces the same vector in the exact opposite direction.
  • x + y: Sum of the x and y vectors. Both vectors need to have the same number of components.
  • x - y: Subtraction of the x and y vectors. Both vectors need to have the same number of components.
  • x * y: If x and y are both vectors, this operator yields a component-wise multiplication. Multiplication applied to two matrices returns a linear algebraic matrix multiplication, not a component-wise multiplication.
  • matrixCompMult(matX, matY): Component-wise multiplication of matrices. They need to have the same dimensions (mat2mat3, or mat4).
  • x / y: The division operator behaves similarly to the multiplication operator.
  • dot(x, y): Returns the dot product (scalar) of two vectors. They need to have the same dimensions.
  • cross(vecX, vecY): Returns the cross product (vector) of two vectors. They must both be vec3.
  • normalize(x): Returns a vector in the same direction but with a length of 1.
  • reflect(t, n): Reflects the t vector along the n vector.

Shaders offer many more functions, including trigonometric and exponential functions. We will refer to them as needed in the development of different lighting models.

Let's see a quick example of the shader's ESSL code for a scene with the following properties:

  • Goraud shading: We will interpolate vertex colors to obtain fragment colors. Therefore, we need one varying to pass the vertex color information from the vertex shader to the fragment shader.
  • Lambertian reflection model: We account for the diffuse interaction between one light source and our scene. This means that we will use uniforms to define the light properties that is, the material properties. We will follow Lambert's Emission Law to calculate the final color for every vertex.

First, let's dissect what the attributes, uniforms, and varyings will be.