Table 3.1 includes the operators, in order of precedence, available in the OpenGL Shading Language. The precedence and associativity are consistent with C.
Indexing a vector returns scalar components. This allows giving components numerical names of 0, 1, . . . and also enables variable selection of vector components, should that be needed. For example,
vec4 v = vec4(1.0, 2.0, 3.0, 4.0); float f = v; // f takes the value 3.0
Here, v is the floating-point scalar 3.0, which is then assigned into f.
Indexing a matrix returns columns of the matrix as vectors. For example,
mat4 m = mat4(3.0); // initializes the diagonal to all 3.0 vec4 v; v = m; // places the vector (0.0, 3.0, 0.0, 0.0) into v
Here, the second column of m, m is treated as a vector that is copied into v.
Behavior is undefined if an array, vector, or matrix is accessed with an index that is less than zero or greater than or equal to the size of the object.
The normal structure-member selector (.) is also used to SWIZZLE components of a vectorthat is, select or rearrange components by listing their names after the swizzle operator (.). Examples:
vec4 v4; v4.rgba; // is a vec4 and the same as just using v4, v4.rgb; // is a vec3, v4.b; // is a float, v4.xy; // is a vec2, v4.xgba; // is illegal - the component names do not come from // the same set.
The component names can be out of order to rearrange the components, or they can be replicated to duplicate the components:
vec4 pos = vec4(1.0, 2.0, 3.0, 4.0); vec4 swiz = pos.wzyx; // swiz = (4.0, 3.0, 2.0, 1.0) vec4 dup = pos.xxyy; // dup = (1.0, 1.0, 2.0, 2.0)
At most, four component names can be listed in a swizzle; otherwise, they would result in a nonexistent type. The rules for swizzling are slightly different for R-VALUES (expressions that are read from) and L-VALUES (expressions that say where to write to). R-values can have any combination and repetition of components. L-values must not have any repetition. For example:
vec4 pos = vec4(1.0, 2.0, 3.0, 4.0); pos.xw = vec2(5.0, 6.0); // pos = (5.0, 2.0, 3.0, 6.0) pos.wx = vec2(7.0, 8.0); // pos = (8.0, 2.0, 3.0, 7.0) pos.xx = vec2(3.0, 4.0); // illegal - 'x' used twice
For R-values, this syntax can be used on any expression whose resultant type is a vector. For example, getting a two-component vector from a texture lookup can be done as
vec2 v = texture1D(sampler, coord).xy;
where the built-in function texture1D returns a vec4.
3.7.3. Component-wise Operation
With a few important exceptions, when an operator is applied to a vector, it behaves as if it were applied independently to each component of the vector. We refer to this behavior as component-wise for short.
vec3 v, u; float f; v = u + f;
is equivalent to
v.x = u.x + f; v.y = u.y + f; v.z = u.z + f;
vec3 v, u, w; w = v + u;
is equivalent to
w.x = v.x + u.x; w.y = v.y + u.y; w.z = v.z + u.z;
If a binary operation operates on a vector and a scalar, the scalar is applied to each component of the vector. If two vectors are operated on, their sizes must match.
Exceptions are multiplication of a vector times a matrix and a matrix times a matrix, which perform standard linear-algebraic multiplies, not component-wise multiplies.
Increment and decrement operators (++ and --) and unary negation (-) behave as in C. When applied to a vector or matrix, they increment or decrement each component. They operate on integer and floating-point-based types.
Arithmetic operators of addition (+), subtraction (-), multiplication (*), and division (/) behave as in C, or component-wise, with the previously described exception of using linear-algebraic multiplication on vectors and matrices:
vec4 v, u; mat4 m; v * u; // This is a component-wise multiply v * m; // This is a linear-algebraic row-vector times matrix multiply m * v; // This is a linear-algebraic matrix times column-vector multiply m * m; // This is a linear-algebraic matrix times matrix multiply
All other operations are performed component by component.
Logical not (!), logical and (&&), logical or (||), and logical inclusive or (^^) operate only on expressions that are typed as scalar Booleans, and they result in a Boolean. These cannot operate on vectors. A built-in function, not, computes the component-wise logical not of a vector of Booleans.
Relational operations (<, >, <=, and >=) operate only on floating-point and integer scalars and result in a scalar Boolean. Certain built-in functions, for instance, lessThanEqual, compute a Boolean vector result of component-wise comparisons of two vectors.
The equality operators (== and !=) operate on all types except arrays. They compare every component or structure member across the operands. This results in a scalar Boolean, indicating whether the two operands were equal. For two operands to be equal, their types must match, and each of their components or members must be equal. To compare two vectors in a component-wise fashion, call the built-in functions equal and notEqual.
Scalar Booleans are produced by the operators equal (==), not equal (!=), relational (<, >, <=, and >=), and logical not (!) because flow-control constructs (if, for, etc.) require a scalar Boolean. If built-in functions like equal are called to compute a vector of Booleans, such a vector can be turned into a scalar Boolean with the built-in functions any or all. For example, to do something if any component of a vector is less than the corresponding component of another vector, the code would be
vec4 u, v; . . . if (any(lessThan(u, v))) . . .
Assignment (=) requires exact type match between the left- and right-hand side. Any type, except for arrays, can be assigned. Other assignment operators (+=, -=, *=, and /=) are similar to C but must make semantic sense when expanded, as in
a *= b a = a * b
where the expression a * b must be semantically valid, and the type of the expression a * b must be the same as the type of a. The other assignment operators behave similarly.
The ternary selection operator (?:) operates on three expressions: exp1 ? exp2 : exp3. This operator evaluates the first expression, which must result in a scalar Boolean. If the result is true, the operator selects to evaluate the second expression; otherwise, it selects to evaluate the third expression. Only one of the second and third expressions will appear to be evaluated. The second and third expressions must be the same type, but they can be of any type other than an array. The resulting type is the same as the type of the second and third expressions.
The sequence operator (,) operates on expressions by returning the type and value of the rightmost expression in a comma-separated list of expressions. All expressions are evaluated, in order, from left to right.