Table of Contents
This section offers some quick ideas on building textures and navigating the built-in textures.
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.
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.
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.
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
.
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!