Chapter 5. Quick Tips

Table of Contents

5.1. Modifying UV
5.2. Build things slowly and Modularly
5.3. Thread Safety
5.4. Inherit from AbstractTexture and AbstractSignal
5.5. Some quick suggestions

This section offers some quick ideas on building textures and navigating the built-in textures.

5.1. Modifying UV

You can modify the UV values a number of ways, scaling will make the texture or signal change faster or slower over your texture. Displacing UV values puts a different piece of the texture in the original UV space and can be useful for layering similar textures with the same scale so there is no similarity to the textures. Texture UV values can be translated, rotated and scaled using the textures in the package org.texgen.textures.uv . There are also other textures which can be used to alter the UV values. The UVNoiseTranslate texture takes a texture and calls it with UV values that have been 'jiggled' around using a noise function. This can roughen the soft edges of some of the textures if needed. You can usually chain textures together making it easy to create textures with modified UV values i.e. texture = new UVScale(texture,2,2); . This takes the original texture and 'zooms out' of it by a scale of 2.

For signals, the org.texgen.signals.modifier package contains a number of UV modification signals ( SignalUv Scale/Rotate/Translate ). There are also a number of other functions that can be applied to the output signals such as scaling, multiplying, clamping and inverting the output signal value.

5.2. Build things slowly and Modularly

It is often best to build complex textures or signals slowly with a continual lookout for making the texture modular. It is often fairly easy to refactor a texture to remove a fixed calculation and put it in either another texture or a signal. In general, if you pass a color to a texture, consider passing a texture instead with an overload for passing in a color which creates a solid color texture. Similarly, if you pass a constant float value, consider letting the user pass in a channel signal since it can be computed each time you need a color value. With the marble texture, instead of taking a color as the input, it was changed so that you can pass a texture instead. With the Mandelbrot texture, rather than having the fractal calculation in the actual texture, we put it in the channel signal so we can re-use it in different places. Refactoring is often easy and allows for easier testing in many ways. If you have a texture made up of multiple internal textures, you can make those textures parameters and evaluate them outside of the main texture. This will also make the final texture more flexible and promote re-usability.

5.3. Thread Safety

Keeping things thread safe is fairly easy. Declare your private member variables as final and initialize them in the constructor only. If you pass a color in to the texture, defensively copy it, unless you are planning on wrapping it in a SolidTexture texture since this texture defensively copies the color anyway.

The goal is to make the class immutable so it cannot be changed once created. Once it is immutable to the outside world, ensure that you don't write code to change the class internally which would break the thread safety.

5.4.  Inherit from AbstractTexture and AbstractSignal

These two classes contain some helpful functions which can be used by your code. They both contain a static reference to an instance of the PerlinNoise class which is often used. There are also functions such as calculateValue , calculateColorFromTexture and calculateValueFromSignal which take signals or textures as input, as well as a UV pair and returns the value. It also handles null checks and returns sensible results in case they are null.

The org.texgen.textures.ChainedChannelSignal can be useful when you are using one channel signal as input to another. This class will take a signal as a construction parameter, which you can then call in your own signal using the getSource() method to obtain the instance. For an example on using this mechanism, check out the org.texgen.signals.modifier.ClampSignal or the org.texgen.signals.modifier.InvertSignal .

5.5. Some quick suggestions

Use the AlphaSignal texture to take a color or texture and make it transparent according to a ChannelSignal . Similarly, to get this texture on a colored background, use the org.texgen.textures.color.Background texture as it overlays a texture on top of a solid color (or texture). If you want to see what a signal looks like, or just want to create a heightmap from a signal, use the ChannelSignalTexture texture with just one signal as the parameter. This will create a grayscale image representing the signal values between 0 and 1.

Using the Dirty texture can add an element of realism to a texture by scuffing it up a little. Use the scale parameter to control how much noise is applied to the final texture.

When parameters for noise are specified they are usually in the order of scale , octaves , and then scale . If they are not in that order let me know and I'll change it. Scale is usually in the range 0 to 1, often 1.

I only just switched from my own noise implementation to the one defined in ImprovedNoise.java but I still wrap it in the PerlinNoise class. The improved noise uses three dimensions, whereas we mostly use only two, so we can probably optimise the function for two dimensions. This is something I'll try and look at in the future.

Lastly, if you come up with cool textures, or channel signal implementations, let me know and I'll include them in the final package. Enjoy!