Table of Contents
This section introduces the concepts and ideas of procedural textures and how they relate to the key parts of the framework.
Put simply, a procedural texture is a procedure which takes input values derived from the point on the surface being textured, and returns a color value for that point on the surface. When the surface is considered as a whole (i.e. the collection of individual points), we end up with a textured surface.
Note that we can apply procedural textures in 2 or 3 dimensions, but for now, we are only considering 2 dimensions. The third dimension can often be represented by time creating an animated surface texture that changes over time.
Since we are only dealing in 2 dimensions, our textures will mostly consist of 2D rectangles. In this case, our input points consist of 2 values, one going across the rectangle and one going down forming cartesian coordinates for any point on the rectangle.

Our procedural texture takes a
(u,v)
coordinate as an input parameter and returns a color
based on the position on the surface.
The colors that we return are composed of values
representing the red, green and blue components. We
have an
RGBAColor
class that we use to represent a color. The 'A' part
refers to the Alpha channel which indicates how
transparent this color is. Transparency ranges from
0 to 1 with 0 being totally transparent and 1 being
totally opaque. Colors can be specified using
integers 0..255 or fractional values from 0..1. In
both cases, the alpha is always specified as ranging
from 0 to 1.
We start with a
Texture
interface that encapsulates the concepts so far. Our
interface contains methods to return a color based on
the input values.
public interface Texture {
RGBAColor getColor(double u, double v);
void getColor(double u, double v, RGBAColor value);
}
We have two methods because rather than keep creating
RGBAColor
instances to return from the texture, we just pass in a
single
RGBAColor
instance that we re-use each time. If you consider a 100
X 100 image calls the texture 10,000 times, and since we
could be chaining textures together, we could end up
creating tens of thousands of
RGBAColor
instances. By re-using the same one and passing it
around, we only create one and we get a 10-15% speedup.
One goal is to make the texture generation view
independent. For example, we might display the texture
in a small window when developing and testing it, but if
we wanted to generate a texture for printing or saving,
we would want to make it high resolution, and we
probably don't want to display it. However, we do want
to end up with the same image, but at a higher
resolution. Therefore we decouple the view from the
texture generation and render textures in view
independent terms. We should be able to call our
textures using any
(u,v)
values and it should be able to calculate the color from
that point. It is this de-coupling that lets us render
the texture at any size, rather than define the texture
in terms of on screen pixels.
There is an abstract class called
AbstractTexture
which implements the
Texture
interface and contains a number of helper functions. The
most important one is
calculateColorFromTexture
which takes the
(u,v)
coordinates, a texture and checks for null textures and
puts the texture value in the target result color.
Let's take a look at writing our first simple texture which is just a solid color.
public class SolidBlue extends AbstractTexture {
public void getColor(double u, double v, RGBAColor value) {
value.setColor(0,0,255);
}
}
Our simple example here just returns the same constant
color no matter what we pass in. In order to view this
texture, we use a class called
TextureWindow
which is a Swing window that lets you render textures in
it.
import org.texturemaker.gui.TextureViewer;
import org.texturemaker.textures.tester.SolidBlue;
public class SolidBlueDemo {
public static void main(String[] args) {
TextureViewer.show(new SolidBlue());
}
}
This class can be run from the console or an IDE and should give you a Swing window which can be resized. Clicking the Start button starts the rendering process. Render Gradually produces really quick low res images which can be handy for complex textures. The anti-alias checkbox will use multiple samples per pixel. Neither of these effects can be seen in this demo because our texture is a single solid color.

Not much really to look at here. Let's try something a
bit fancier. Change our demo to use a different texture
by passing a different texture to the
TextureViewer
class. Let's try the
org.texturemaker.textures.composite.ComplexMarble
class which is composed of a number of different
textures to produce a nice marble effect.
public class SolidBlueDemo {
public static void main(String[] args) {
TextureViewer.show(new ComplexMarble());
}
}

This is much more interesting! It also took much longer to create as it is more complex. If you resize the window, you will notice that the pattern stays the same, it scales to the window size and adds more detail to fill the space. Now when you generate a high resolution texture, you know you will get the same basic image, but with more detail.
Here is another view of the same texture. This time, we expanded the window to fill the screen causing the texture to be rendered at a higher resolution. The picture below shows the top left hand corner of the texture. If you compare to the previous full image of the marble, we can see that where we have zoomed in at a higher resolution, our procedural texture has produced more artifacts and details.

This means that if we write our textures properly, we can make them resolution independent. In which case, we can produce very high resolution versions which can be printed or used in other situations where we need high resolution detailed textures.
We use a decorator type of pattern quite often when we want to transform the inputs to and outputs from signals or textures. We can wrap another signal or texture around the existing one, and adjust the inputs or outputs to the signal or texture. For example, we might have a signal from 0 to 1 which is passed to a gradient texture. We can wrap the signal in a noisy signal so the output from the signal is jiggled around to produce not such a smooth gradient.
So now we have an easy way to test and view our textures, lets start looking at how we write them.