2.2 Texture Loading and Shaders
When
texturing a 3D object, the texture and the method used to load it is
very similar to the way textures were loaded for sprites. First the
texture itself needs to be loaded into an ID3D10Texture2D object and a resource view created from it.
Secondly,
the shader needs to know how to gain access to the texture you just
loaded in. Letting the shader know to expect a texture is simply a
matter of creating a named variable that is set as external using the extern keyword.
// Set up a named variable within the shader to hold the texture.
extern Texture2D baseTexture;
The variable is then accessible to the runtime portion of your code through binding.
// Bind the texture variable
ID3D10EffectShaderResourceVariable* pBaseTextureVariable = NULL;
pBaseTextureVariable = modelObject->pEffect->
GetVariableByName("baseTexture")->AsShaderResource();
The pBaseTextureVariable is now bound to the baseTexture
variable declared in the shader. Similar to the matrix and float
variables you’ve bound before, this gives you access to change and
update the values used by the shader.
The texture can be updated using the SetResource method available through the pBaseTextureVariable.
// Set the texture resource view
pBaseTextureVariable->SetResource(pTextureRV);
Note
Shaders make use of the texture resource view, not the actual texture object.
2.3 Texturing Coordinates and Sampling
Since
the texture coordinates were added to the vertex format previously, the
shader now needs to be updated to handle them as well. Since all the
vertices pass through the vertex shader portion first, the input
parameters need to be changed. Additionally, the PS_INPUT structure must support the inclusion of texture coordinates to pass on to the pixel shader.
The new versions of the PS_INPUT structure and vertex shader are shown next.
////// This structure is created and filled in by the
// vertex shader
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float4 Color : COLOR0;
float2 Tex : TEXCOORD0;
};
////////////////////////////////////////////////
// Vertex Shader - Main Function
///////////////////////////////////////////////
PS_INPUT VS(float4 Pos : POSITION, float2 Tex: TEXCOORD)
{
PS_INPUT psInput;
psInput.Pos = Pos;
psInput.Color = float4(1.0f, 1.0f, 1.0f, 1.0f);
psInput.Tex = Tex;
return psInput;
}
The
vertex shader isn’t responsible for doing anything to the texture
coordinates other than just setting them and passing them along to the
pixel shader.
Texturing is performed in
the pixel shader portion of an effect. Instead of the pixel shader
returning a preset color as its output, the shader returns a color
based on the texture coordinate location in the texture file; this
process is called sampling.
Sampling
uses the texture coordinates to determine which area of the texture is
going to be used as the output color. How the texture is sampled is
controlled by the SamplerState. The SamplerState is
a named section within the shader file that contains information as to
how the texture is to be filtered as well as how the texture should be
mapped. There are three ways the texture can be mapped:
Wrap— The texture repeats across the surface.
Clamp— If the texture does not completely map to the area, the edge color will be repeated causing the texture to look streaked.
Mirror— The texture is repeated but reversed each time it is drawn.
Figure 2 shows an example of each type of mapping.
An example SamplerState is shown next. It uses linear filtering and wraps the texture during sampling.
SamplerState samLinear
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
The SamplerState
is needed within the pixel shader during the actual sampling process.
The ability to sample a texture is built-in to Direct3D and uses the
shader function Sample.
Sample is one of the functions made available through the Texture2D object and takes two parameters. The first parameter is a SamplerState object. The second parameter is the pair of texture coordinates to be sampled. The Sample function uses the input texture coordinates to do a lookup in a texture and then uses the SamplerState to determine the color to be mapped.
///////////////////////////////////////////////
// Pixel Shader
///////////////////////////////////////////////
float4 PS(PS_INPUT psInput) : SV_Target
{
return baseTexture.Sample(samLinear, psInput.Tex) * psInput.Color;
}
Note
Previous versions of HLSL used the tex2D function for sampling from 2D textures. The Sample function was introduced in Shader Model 4.0 and has the advantage of supporting 2D and 3D textures based on the texture object.