Operators

Arithmetic, Relational and Logical Operators

GLSL's operators follow C's precedence. From highest to lowest:

GLSL ES 3.00 operators in order of precedence
Levels Operators, highest first
1-3 () [] . postfix ++ --, then prefix ++ -- + - ! ~
4-8 * / %, + -, << >>, < > <= >=, == !=
9-14 &, ^, |, &&, ^^, ||
15-17 ?:, then = and compound assignments (right to left), then ,

GLSL ES 3.00 adds the integer operators %, <<, >>, &, |, ^ and ~, reserved in 1.00; ^^ is a logical exclusive or. Operands must share a type, though a scalar may combine with a vector. < takes scalars only; compare vectors with lessThan() and reduce with any() or all():

Integer, logical and vector comparison operatorsJavaScript
show('int i = 7; result = vec4(i / 2, -i / 2, i % 3, i << 2);');
show(`uint flags = 5u;   // binary 101
      result = vec4(flags & 4u, flags | 2u, flags ^ 1u, float(true ^^ true));`);
show(`bvec3 below = lessThan(vec3(1.0, 5.0, 3.0), vec3(2.0));
      result = vec4(below, any(below));`);
Output
3, -3, 1, 28
4, 7, 4, 0
1, 0, 0, 1

Integer division truncates toward zero, and % works only on integers; use mod() for floats.

Patterns built from GLSL's integer, bitwise, logical-xor and vector comparison operatorsHTMLLive
<!doctype html>
<style>
  body { margin: 0; font: 12px system-ui, sans-serif; background: #f7f4ee; color: #333; }
  canvas { display: block; width: 100%; max-width: 600px; }
  .names { display: flex; max-width: 600px; text-align: center; font-family: monospace; font-size: 11px; }
  .names div { flex: 1; padding: 4px 2px; }
</style>
<canvas id="view" width="600" height="150"></canvas>
<div class="names">
  <div>(x ^ y) &amp; 16</div><div>(x / 12) % 3</div><div>inA ^^ inB</div><div>any(lessThan(p, t))</div>
</div>
<script>
const gl = document.getElementById('view').getContext('webgl2');
const vs = `#version 300 es
void main() { gl_Position = vec4(gl_VertexID == 1 ? 3.0 : -1.0, gl_VertexID == 2 ? 3.0 : -1.0, 0.0, 1.0); }`;
const fs = `#version 300 es
precision highp float; precision highp int;
uniform float uTime;
out vec4 outColor;
const vec3 ink = vec3(0.12, 0.37, 0.55), paper = vec3(0.93, 0.9, 0.84);
void main() {
  int tile = int(gl_FragCoord.x) / 150;             // integer division truncates
  ivec2 ip = ivec2(gl_FragCoord.xy) % 150;           // % works on integers only
  vec2 p = vec2(ip) / 150.0;                         // 0..1 inside the tile
  bool on;
  if (tile == 0) {
    int scroll = int(uTime * 20.0);                 // float -> int conversion must be explicit
    on = (((ip.x + scroll) ^ ip.y) & 16) != 0;     // bitwise xor and mask
  } else if (tile == 1) {
    int band = (ip.x + ip.y) / 12 % 3;               // same precedence as C: / before %
    outColor = vec4(band == 0 ? ink : band == 1 ? vec3(0.88, 0.6, 0.06) : paper, 1.0);
    return;
  } else if (tile == 2) {
    float t = sin(uTime) * 0.15;
    bool inA = distance(p, vec2(0.38 + t, 0.5)) < 0.28;
    bool inB = distance(p, vec2(0.62 - t, 0.5)) < 0.28;
    on = inA ^^ inB;                                 // logical exclusive or
  } else {
    // < only takes scalars: compare vectors component-wise, then reduce with any().
    vec2 threshold = vec2(0.5 + 0.3 * sin(uTime), 0.5 + 0.3 * cos(uTime));
    bvec2 below = lessThan(p, threshold);
    on = any(below) && !all(below);
  }
  outColor = vec4(on ? ink : paper, 1.0);
}`;
const program = gl.createProgram();
for (const [type, src] of [[gl.VERTEX_SHADER, vs], [gl.FRAGMENT_SHADER, fs]]) {
  const s = gl.createShader(type);
  gl.shaderSource(s, src); gl.compileShader(s);
  if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(s));
  gl.attachShader(program, s);
}
gl.linkProgram(program);
gl.useProgram(program);
gl.bindVertexArray(gl.createVertexArray());
const uTime = gl.getUniformLocation(program, 'uTime');
function frame(ms) {
  gl.uniform1f(uTime, ms * 0.001);
  gl.drawArrays(gl.TRIANGLES, 0, 3);
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
</script>