The XOR texture is a simple pattern that's very easy to generate. It's useful for testing texture renderers and learning how to generate images.
This page will be shorter than the others, but the XOR texture just can't be left out in a series of texture generation lessons.
The XOR texture is generated by performing a bitwise XOR operation on the current pixel. The '^' operator in JavaScript is the XOR operator.
var canvas = document.createElement("canvas");
canvas.width = 256;
canvas.height = 256;
var ctx = canvas.getContext("2d");
var imageData = ctx.createImageData(canvas.width, canvas.height);
var w = imageData.width;
var h = imageData.height;
for (let y = 0; y < h; y++) {
for (let x = 0; x < w; x++) {
let id = (y * w + x) * 4;
let c = x ^ y;
imageData.data[id] = c;
imageData.data[id+1] = c;
imageData.data[id+2] = c;
imageData.data[id+3] = 255;
}
}
ctx.putImageData(imageData, 0, 0);
document.body.appendChild(canvas);
And that should be it. If you run it, you'll see something like this:
There are some things you should keep in mind, though:
1) The width and height of the canvas should be powers of two. If they aren't, the texture will appear incomplete:
2) Each value ranges from 0 to 255. The maximum color value generated using each XOR operation is the same as the dimensions of the canvas if they are powers of two. Because of this, if the size of the canvas is smaller than 256x256, you may not get the desired color, as seen in the image on the left. Luckily, this can be corrected by multiplying the XOR-ed value. For example, multiplying the values in a 64x64 XOR texture by 4 will result in the image on the right:
3) On the other hand, if the size of the canvas is larger than 256x256, for example, 512, you'll have to make sure the color is limited to a maximum value of 256. The quickest way to do this is to modulo divide the values by 256, although if you're familiar with multiples of 256, regular division works fine. In any case, creating an XOR texture larger than 256x256 doesn't really increase the quality; if properly configured, it just gives you more XOR texture.
Bitwise XOR operations work by taking the binary value of two integers, iterating through each bit, and evaluating two corresponding bits in each iteration. If both bits are different, it returns 1, but if the bits are the same, it returns 0. In other words, bit A is 1 or bit b is 1, but not both.
This is visualized in the following truth table:
XOR | ||
---|---|---|
Bit_a | Bit_b | Result |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
This is done with every bit of the integers, creating many possible values.
For example, 10 XOR 25 = 19, because in binary 1010 XOR 11001 = 10011.
You can also apply different colors to your XOR texture by modifying the individual R, G, and B values. For example:
var canvas = document.createElement("canvas");
canvas.width = 256;
canvas.height = 256;
var ctx = canvas.getContext("2d");
var imageData = ctx.createImageData(canvas.width, canvas.height);
var w = imageData.width;
var h = imageData.height;
for (let y = 0; y < h; y++) {
for (let x = 0; x < w; x++) {
let id = (y * w + x) * 4;
let c = x ^ y;
imageData.data[id] = 255 - c;
imageData.data[id+1] = c % 128;
imageData.data[id+2] = c / 2;
imageData.data[id+3] = 255;
}
}
ctx.putImageData(imageData, 0, 0);
document.body.appendChild(canvas);
Using HSV for the color instead of RGB also produces some interesting results:
var canvas = document.createElement("canvas");
canvas.width = 256;
canvas.height = 256;
var ctx = canvas.getContext("2d");
var imageData = ctx.createImageData(canvas.width, canvas.height);
var w = imageData.width;
var h = imageData.height;
for (let y = 0; y < h; y++) {
for (let x = 0; x < w; x++) {
let id = (y * w + x) * 4;
let c = hsvToRgb((x ^ y) / 256, 1, 1);
imageData.data[id] = c;
imageData.data[id+1] = c;
imageData.data[id+2] = c;
imageData.data[id+3] = 255;
}
}
ctx.putImageData(imageData, 0, 0);
document.body.appendChild(canvas);
The AND and OR operators generate similar patterns.
The XOR operator returns 1 if both bits are different.
XOR | ||
---|---|---|
Bit_a | Bit_b | Result |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
The AND operator returns 1 if, and only if, both bits are 1. (bit a AND bit b are true)
AND | ||
---|---|---|
Bit_a | Bit_b | Result |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
The OR operator returns 1 if any or both bits are 1. (bit a OR bit b are true)
OR | ||
---|---|---|
Bit_a | Bit_b | Result |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
The AND operator is denoted '&' in JavaScript, and the OR operator '|', replace the '^' operator in your code with one of these to use the new operators. Here are the results of generating patterns with XOR, AND, and OR, respectively:
As you can clearly see, the AND texture is darker than the others, since the AND operator returns 1 in only one case, making higher color values rare. Meanwhile, the OR operator returns 1 very often, so the resulting texture from it is brighter.
In this lesson, it was shown how easy it was to generate an XOR texture, making it great for testing texture renderers.
In this image, an XOR texture was used to test a basic tunnel effect.