Most of the concepts of
this
initialization method where covered in [2.3.5]; this tutorial focuss in
a new texture effect.
The problem that we are
trying to
solve is how to apply different textures to the same surface to
recreate some dirt in the grass or to pass from the ground to a river;
generally, rivers don't have grass in the bottom.
These are the
textures that we are going to be using in this tutorial, the objective
is to have a grass base with the texture in the upper left part, a road
with the texture in the lower part and some stones with the texture in
the upper right part.
The way to do this is specify areas where
each texture has to be applied; notice that there are some areas where
the transition from one texture to the other requires more than one
texture to be applied at the same time.

The idea is to define
a fourth
texture that specifies how to apply the other three; we will call it
the reference texture. In our particular case, we are going to apply
the grass to the red part of the reference texture, the stone
to
the green part and the road to the blue part. Since the reference
texture has a transition from one color to another, for example red
-> purple -> blue, the change from grass to road will
also have a
transition, which is desired.
The code in the tutorial up to the definition of the sampler is the
same as 2.3 and 2.4. First the texture feeder is defined:
BCTextureFeeder texFeeder =
new
BCTextureFeeder();
The next step is to add the sampler for the different textures to the
texture feeder; notice that the names are
gBlendMap
for the reference texture and
gTex0,
gTex1 and
gTex2
for the grass, the road and the stone respectively, also remember
[2.3.4] that we DON'T SET THE TEXTURES TO THE FEEDER, ONLY THE
SAMPLERS, nevertheless, the name of the samplers have to coincide with
the names of the textures that we'll define later in the mesh.
texFeeder.addSampler("gBlendMap",
sampler);
texFeeder.addSampler("gTex0", sampler);
texFeeder.addSampler("gTex1", sampler);
texFeeder.addSampler("gTex2", sampler);
Now we must obtain the effect composition part that represent the
channel blend effect:
BCFunction channelBlendPart =
texFeeder.getFunction("Shader.Texture.ChanelBlend");
Now we create the visitor [1.2.4] that will add this effect part part
to the mesh's effect:
int endOfEffect = BCDynamicEffect.MAX_FUNCTIONS;
BCDynamicEffectVisitor
textureEffectSetter =
new
BCDynamicEffectVisitor(channelBlendPart, texFeeder, endOfEffect);
Notice the
endOfEffect
variable; in BetaCell we can choose the order of the parts in the final
effect; the
BCDynamicEffect.MAX_FUNCTIONS
is a constant of the
BetaCell.Effects.BCDynamicEffect
that indicates "this is the last part to apply to the final effect",
which makes sense because we would like the lightning calculations to
take place before the texturing ones.
We are now ready to load the textures and set them to the plane, for
that we create a visitor per texture:
Texture2D reference =
content.Load<Texture2D>("Content/gameAssets/channelsR");
BCMemoryTextureStrategy
referenceStrategy =
new BCMemoryTextureStrategy(reference);
BCTextureVisitor blendMapTex =
new BCTextureVisitor("gBlendMap",
referenceStrategy);
Another way to define a visitor in a single statement (more confusing
but faster):
BCTextureVisitor grassTex = new
BCTextureVisitor(
"gTex0",
new
BCMemoryTextureStrategy(
content.Load<Texture2D>("Content/gameAssets/grass"))
);
Notice that both definitions are the same code; just that the last one
defines everything inline.
Also, the scale of each texture in the effect can be set with the
following line.
gassTex.strategy.setScale(new Vector2(5, 5));
After all the preparations, the only thing left is to visit the plane:
plane.visit(blendMapTex);
plane.visit(grassTex);
plane.visit(roadTex);
plane.visit(stoneTex);
plane.visit(materialVisitor);
plane.visit(colorSetter);
plane.visit(lightSetter);
plane.visit(textureEffectSetter);