This Initialize method can
get a little
long, also to do this kind of initialization to all the objects in a
scene is not practical. In an advanced application you will create the
objects in a content creation tool like Blender and load the objects
ready to be drawn (which is exactly what will be done in a later
tutorial!).
You can take a look at the
initialization of the base color and lightning effect composition parts
at [1.1.6] and [2.1.3]. To learn about the creation of a cube, see
[1.3.4].

Now we will discuss
what a material
is and how to create it. The main components of a material are diffuse,
specular and ambient. The diffuse component of a material reacts to
light that 'hit' the object directly, in the figure the diffuse
component of the material is blue. The specular component of a material
is that shinny little spot that reflects light directly to the camera,
in the figure, this component is red. Finally, the ambient component is
the light that has bounced in the scene so many times, that is
impossible to tell where it came from; in the figure, this component is
green. Notice that the part of the sphere not illuminated by the light
is green, the directly illuminated is blue and the one that reflects
the light most directly to the camera is red.
A material like the one in the figure is very rare; it was created to
explain what a material is.
In general, all three components of a material tend to have the
same color. The call that constructs the material in this tutorial is
as follows:
BCMaterialBase material = new
BCMaterialBase();
material.specRange = 0.8f;
material.diff = Color.White;
material.spec = Color.White;
material.amb = Color.LightGray;
It's a nice white base to apply the texture on. In order to apply the
material, the following visitor [1.2.4] is created:
BCMaterialVisitor materialVisitor = new
BCMaterialVisitor(material);
After the material visitor, the color setter visitor [1.2.4] and the
light setter visitor [2.1.3] are created.
Now let's talk about texture coordinates.
Remember that a vertex
can have
multiple information? well, a kind of information that a vertex can
have are texture coordinates.
In the upper left part of the
figure we have a 2D image, this is the texture that we are willing to
apply. Notice that the positions of the vertices won't work for us to
describe how to apply the texture to the face because they are in 3D
(X,Y and Z) and the texture is in 2D, so we need to specify how to
apply the texture in 2D.
The way to do that is to specify a new
set of information per vertex called the texture coordinate; that has a
U and a V component. The U component goes from left to right and the V
component goes from up to down. Both U and V range from 0 to 1. A pixel
in a texture described by a UV pair is called a texel.
In
the figure, the UV coordinates for vertex 0 are (0.5,0) because is in
the middle of the image from left to right (U=0.5) and in the beginning
of the image from top to bottom (V=0). vertex 1 and 2 have (0,1) and
(1,1) texture coordinates respectively.
Now that we understand what texture coordinates are, let's discuss the
sampler object.
The sampler is the
responsible of
returning a color given a texture coordinate. What you need to know is
that depending on how you construct the sampler, the end results will
vary.
Once a triangle with a texture is drawn in the screen,
we can have the scenario where the drawn triangle is bigger than the
texture that is applied to it; creating ugly artifacts like the ones
shown in the upper left part of the figure.
That's where the
definition of the sampler can help us; we can create a sampler that
returns a color by averaging the neighbor texels of the resultant
texel, creating a smooth transition like the one shown in the lower
right part of the figure.
The code that creates the sampler is:
BCSampler sampler = new BCSampler(
"LINEAR", "LINEAR", "LINEAR", "4",
"WRAP",
"WRAP", "0xffffffff"
);
A
detailed discussion of the parameters is out of the scope of this
tutorial and can be found in "Introduction to 3D Game Programming, A
Shader Approach" by
Frank Luna, for the experienced reader, the first parameter is the
minification filter, the second is the magnification filter, the third
is the mipmap filter, the fourth is the anisotropic level, the fifth is
the address mode in the U coordinate, the sixth is the address mode in
the V coordinate and the last one is the color of the border.
A more
casual reader should know that minification means when the texture in
greater than the resultant triangle, magnification means the opposite,
also that the filters are
POINT
(no filtering, fast),
LINEAR
normal filtering and
Anisotropic
which is a filter that helps viewing the ground but requires
more computation (slow).
Now, we must create the texture effect. The effect feeder for texture
effects is created with the following line:
BCTextureFeeder texFeeder = new
BCTextureFeeder();
Now we need to associate the sampler with the effect; this is done with
this line:
texFeeder.addSampler("tex", sampler);
Notice
that we add the sampler with the name 'tex', that's because the
basic texture effect, which is the one that we will be using,
expects the texture to have that name.
The next step is to
create the effect composition part that represents basic texturing,
which is obtained from the feeder [1.1.6] in the following way:
BCFunction texturePart =
texFeeder.getFunction("Shader.Texture.Texture");
Now we create the visitor [1.2.4] to apply the texture to a mesh's
effect.
BCDynamicEffectVisitor
textureEffectSetter = new BCDynamicEffectVisitor(
texturePart, texFeeder,
BCDynamicEffect.MAX_FUNCTIONS);
Now we are going to create the cube [1.3.4].
cube =
ProceduralModelers.CUBE_MODELER.createCube(
10, 10, 10, new BCVertexPosNorTexContainer());
BCMeshGraphicUtil.init(cube, device);
Now
we are going to load the texture. In BetaCell the mesh has the
responsibility of holding it's textures, so instead of setting the
texture to the effect, we are going to set a texture in
the mesh
with the name 'tex' which is the name expected by the effect and the
feeder.
First we must load the texture:
Texture2D crateTexture =
content.Load<Texture2D>("Content/gameAssets/crate");
This
is the way textures are loaded in XNA, note that the path starts
relative to the content folder and that there's no extension at the end
of the file name (crate instead of crate.jpg).
Then we create a
texture strategy with the texture; texture strategies are an advanced
topic that are not going to be covered by this particular tutorial, you
can think of them as a generic representation of a texture or take a
look at the documentation.
BCTextureStrategy memory = new
BCMemoryTextureStrategy(crateTexture);
After
that, we create a visitor [1.2.4] that sets the texture to all the
parts of the mesh. Notice that the constructor of the visitor takes the
name that the texture will have in the mesh and the texture strategy.
BCTextureVisitor crateTex = new
BCTextureVisitor("tex", memory);
At this point we have a bunch of visitors, all that's left is
apply them all to the cube.
cube.visit(crateTex);
cube.visit(materialVisitor);
cube.visit(colorSetter);
cube.visit(lightSetter);
cube.visit(textureEffectSetter);