# Vectors - Double Cross Product

We start with two vectors `@N`

(yellow) – which is the primitive’s normal from a Normals SOP, and `{0,1,0}`

– the global up (gray). When the primitive is not rotated, these two vectors are parallel.

By using a buncha `cross`

, we can derive our main axes:

```
vector pink = cross(@N, {0, 1, 0}); // First cross product
vector green = cross(pink, @N); // Second cross product, the "double cross"
```

**Note 1**: The green vector is essentially an “up-ish” vector that is always parallel to the plane and never points downwards.

**Note 2**: The pink vector gives us a notion of “sided-ness”. The `sign`

of `pink.z`

– whether `+/-`

– tells us which side the normal is on.

**Note 3**: Assuming the “red” side of the grid is the “top”, we can use the above to figure out its direction through the entire rotation. When `pink.z > 0`

(pointing at us) – the green vector is `@up`

. When `pink.z < 0`

(pointing away) – then the inverse of `green`

is `@up`

.

### Double Cross Products as Vector Fields

A sphere with “typical” normals:

Using `{0,-1,0}`

in a double cross product has the effect of “directing” the vectors in the `-Y`

direction.

```
@N = cross(cross(@N, {0,-1,0}), @N);
```

Also note, just like our “up-ish” vectors before, the new vectors are parallel to the plane from which they originate, which causes this “combed downwards” look to happen. The vectors at the top “shoot out” almost horizontally because the faces are almost flat at the top. As they converge on the equator, the faces tilt outwards. After the equator, they tilt towards the south pole.

We can use this as a trick to create velocity vectors that are pointed in a certain direction and are *always parallel to the surface* – essentially sticking them to the surface.

To show this, let’s wrangle over the primitives:

```
vector2 uv = rand(@primnum);
@v = sample_direction_uniform(uv);
```

Which gives us a bunch of random vectors shooting off the sphere:

Now, instead of `{0,-1,0}`

, we’ll feed the original vector `@v`

into the cross product:

```
@v = cross(cross(@N, @v), @N);
```

What we get are vectors that – instead of being “down-ish” – are “ish” in the direction of the original `@v`

*and* are parallel to the surface:

Now let’s move some particles With an Advect By Volumes, which gets us: