Sign Up NOW to get 100 free credits, used to download 3D Models, Textures, Sound Effects and Music!

Lesson 11: Direct3D 11 Textures

Introduction

Here we will learn how to map textures to our objects. This lesson modifies the Transformations lesson, so if you get lost here, you might want to backtrack to the lesson on transformations to see if you missed something. I will try my best to explain every new and modified line here. I want to mention, we have changed the code to explicitly define the box, by adding vertices to define every triangle. Although this adds a little more code in creating the box and vertex structure, it should make things easier when it comes to texture mapping.

In Direct3D, we use a 2D (u,v) coordinate system to map the texture onto an object. The u-axis runs horizontaly to the image, and the v-axis runs vertically, where u is 0-1 (0 being the start of the lenth of the image, and 1 being the end of the length of the image). So half the image's horizontal length is at .5, even if the actual image lenth is 256 pixels.

Now what would happen if we changed the value of u and v to over one? say, 2? You guessed it! it would repeat the texture, like shown below.


Global Declarations

The first new interface is an object which will hold our texture we load from the file. The second will hold our sampler state information, which will be explained soon.


ID3D11ShaderResourceView* CubesTexture;
ID3D11SamplerState* CubesTexSamplerState;

Vertex Structure/Input Layout

Lets look at our vertex structure. We have removed the color member, and replaced it with a texture coordinate member. Texture coordinates for 2D textures only need a u and v value, however, there are 3D textures which we will use for a skymap, which uses an extra "w" value. We have also modified the input layout to include a two float element for the texture coordinates, which replaces our color element.


struct Vertex	//Overloaded Vertex Structure
{
	Vertex(){}
	Vertex(float x, float y, float z,
		float u, float v)
		: pos(x,y,z), texCoord(u, v){}

	XMFLOAT3 pos;
	XMFLOAT2 texCoord;
};

D3D11_INPUT_ELEMENT_DESC layout[] =
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },  
	{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },  
};

Vertex Structure/Buffer, Indice List

If we do not separate texture coordinates for each triangles vertice, Only the Top and Bottom might be correctly mapped out, this is why we have added vertices for every triangle in our cube, so we can set each of their texture coordinates. You can try to set the texture coordinates with only the 8 vertices we used in the last lesson, but like i said, the texture will not be mapped out correctly on all six sides.

Since we have added more vertices, we need to also update the vertex buffer to hold 24 vertices instead of the 8 we had before.


	Vertex v[] =
	{
		// Front Face
		Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f),
		Vertex(-1.0f,  1.0f, -1.0f, 0.0f, 0.0f),
		Vertex( 1.0f,  1.0f, -1.0f, 1.0f, 0.0f),
		Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 1.0f),

		// Back Face
		Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 1.0f),
		Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 1.0f),
		Vertex( 1.0f,  1.0f, 1.0f, 0.0f, 0.0f),
		Vertex(-1.0f,  1.0f, 1.0f, 1.0f, 0.0f),

		// Top Face
		Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f),
		Vertex(-1.0f, 1.0f,  1.0f, 0.0f, 0.0f),
		Vertex( 1.0f, 1.0f,  1.0f, 1.0f, 0.0f),
		Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 1.0f),

		// Bottom Face
		Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f),
		Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f),
		Vertex( 1.0f, -1.0f,  1.0f, 0.0f, 0.0f),
		Vertex(-1.0f, -1.0f,  1.0f, 1.0f, 0.0f),

		// Left Face
		Vertex(-1.0f, -1.0f,  1.0f, 0.0f, 1.0f),
		Vertex(-1.0f,  1.0f,  1.0f, 0.0f, 0.0f),
		Vertex(-1.0f,  1.0f, -1.0f, 1.0f, 0.0f),
		Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f),

		// Right Face
		Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f),
		Vertex( 1.0f,  1.0f, -1.0f, 0.0f, 0.0f),
		Vertex( 1.0f,  1.0f,  1.0f, 1.0f, 0.0f),
		Vertex( 1.0f, -1.0f,  1.0f, 1.0f, 1.0f),
	};

	DWORD indices[] = {
		// Front Face
		0,  1,  2,
		0,  2,  3,

		// Back Face
		4,  5,  6,
		4,  6,  7,

		// Top Face
		8,  9, 10,
		8, 10, 11,

		// Bottom Face
		12, 13, 14,
		12, 14, 15,

		// Left Face
		16, 17, 18,
		16, 18, 19,

		// Right Face
		20, 21, 22,
		20, 22, 23
	};

	D3D11_BUFFER_DESC indexBufferDesc;
	ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) );

	indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	indexBufferDesc.ByteWidth = sizeof(DWORD) * 12 * 3;
	indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	indexBufferDesc.CPUAccessFlags = 0;
	indexBufferDesc.MiscFlags = 0;

	D3D11_SUBRESOURCE_DATA iinitData;

	iinitData.pSysMem = indices;
	d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &squareIndexBuffer);

	d3d11DevCon->IASetIndexBuffer( squareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);


	D3D11_BUFFER_DESC vertexBufferDesc;
	ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) );

	vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 24;
	vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vertexBufferDesc.CPUAccessFlags = 0;
	vertexBufferDesc.MiscFlags = 0;

Loading the Texture from a File
( D3DX11CreateShaderResourceViewFromFile() )

Here, towards the bottom of our init scene function, we are loading our texture from a file using the function D3DX11CreateShaderResourceViewFromFile(), which is defined like this:


HRESULT D3DX11CreateShaderResourceViewFromFile(
  __in   ID3D11Device *pDevice,
  __in   LPCTSTR pSrcFile,
  __in   D3DX11_IMAGE_LOAD_INFO *pLoadInfo,
  __in   ID3DX11ThreadPump *pPump,
  __out  ID3D11ShaderResourceView **ppShaderResourceView,
  __out  HRESULT *pHResult
);

Where each parameter is described below:

pDevice -
Pointer to our D3D Device.

pSrcFile -
The name of our file (and location if its not in the same folder as the exe).

pLoadInfo -
A pointer to a D3DX11_IMAGE_LOAD_INFO structure which defines how the texture should be loaded. We can set this to NULL.

pPump -
A pointer to a ID3DX11ThreadPump Interface, used only if we wanted multi-threading, and have the program continue running even while this file is being loaded. Putting NULL here makes this function return only when its completed.

ppShaderResourceView -
This is a pointer a shader resource view (ID3D11ShaderResourceView) which will hold the data from this texture.

pHResult -
This is a returned pointer which will store the result of this function. We talked about HRESULT's before.


	hr = D3DX11CreateShaderResourceViewFromFile( d3d11Device, L"braynzar.jpg",
		NULL, NULL, &CubesTexture, NULL );

Describing the Sample State
( D3D11_SAMPLER_DESC )

Here we can describe the sampler state, or how the shader will render the texture. We create a D3D11_SAMPLER_DESC object:


typedef struct D3D11_SAMPLER_DESC {
  D3D11_FILTER               Filter;
  D3D11_TEXTURE_ADDRESS_MODE AddressU;
  D3D11_TEXTURE_ADDRESS_MODE AddressV;
  D3D11_TEXTURE_ADDRESS_MODE AddressW;
  FLOAT                      MipLODBias;
  UINT                       MaxAnisotropy;
  D3D11_COMPARISON_FUNC      ComparisonFunc;
  FLOAT                      BorderColor[4];
  FLOAT                      MinLOD;
  FLOAT                      MaxLOD;
} D3D11_SAMPLER_DESC;

Where each member is described below:

Filter -
A D3D11_FILTER enumerated type describing the filtering method to use.

AddressU -
A D3D11_TEXTURE_ADDRESS_MODE enumerated type describing what to do if the u value is larger than 1 or less than 0.

AddressV -
A D3D11_TEXTURE_ADDRESS_MODE enumerated type describing what to do if the v value is larger than 1 or less than 0.

AddressW -
A D3D11_TEXTURE_ADDRESS_MODE enumerated type describing what to do if the w value is larger than 1 or less than 0.

MipLODBias -
Offset from the calculated mipmap level. For example, if Direct3D calculates that a texture should be sampled at mipmap level 3 and MipLODBias is 2, then the texture will be sampled at mipmap level 5.

MaxAnisotropy -
Clamping value used if D3D11_FILTER_ANISOTROPIC or D3D11_FILTER_COMPARISON_ANISOTROPIC is specified in Filter. Valid values are between 1 and 16.

ComparisonFunc -
An enumerated type D3D11_COMPARISON_FUNC . This will compare sampled mipmap data with another mipmaps sampled data for this texture.

BorderColor[4] -
If D3D11_TEXTURE_ADDRESS_BORDER was specified for any of the AddressU,V, or W, Then this is the color of the space between the texture and the edge of the triangle, if u, v or w was greater than 1 or less than 0.

MinLOD -
This is the lowest mipmap level to use, where 0 is the most detailed and largest one.

MaxLOD -
This is the largest mipmap level to use, where 0 is the most detailed and largest. To use all the mipmaps, you would want to specify a very large number, like FLT_MAX.

If any of the members are not filled out, the default values will be used:


Filter			MIN_MAG_MIP_LINEAR
AddressU		Clamp
AddressV		Clamp
AddressW		Clamp
MinLOD			-3.402823466e+38F (-FLT_MAX)
MaxLOD			3.402823466e+38F (FLT_MAX)
MipMapLODBias	0.0f
MaxAnisotropy	16
ComparisonFunc	Never
BorderColor		float4(0.0f,0.0f,0.0f,0.0f)


	D3D11_SAMPLER_DESC sampDesc;
	ZeroMemory( &sampDesc, sizeof(sampDesc) );
	sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    sampDesc.MinLOD = 0;
    sampDesc.MaxLOD = D3D11_FLOAT32_MAX;

Vertex Structure/Input Layout ( ID3D11Device::CreateSamplerState() )

After we have described our sampler, we need to create it. We can do this by using the CreateSamplerState() method, where the first parameter is our described sampler state, and the second is an interface to put the sampler state into.


	hr = d3d11Device->CreateSamplerState( &sampDesc, &CubesTexSamplerState );

Sending the Sampler State and Texture to the Shader
( ID3D11DeviceContext::PSSetShaderResources() )
( ID3D11DeviceContext::PSSetSamplers() )

If we wanted, we only need to send the sampler state and texture to the pixel shader only once per group of objects that use that same sampler state and texture, but a lot of times the objects will have more than one texture, so you will not be able to set it only once per object. Anyway, Since it is the PS that will be using this information, we will be sending it there. We can do this by calling the methods ID3D11DeviceContext::PSSetShaderResources() and ID3D11DeviceContext::PSSetSamplers().

The first parameter of the PSSetShaderResources() method is the slot number we are sending the shader into. The second parameter is the number of elements in our texture array. We set this to one since we are only sending one texture, but we can actually send an array of textures to the shader. The third parameter is an array of ID3D11ShaderResourceView.

The PSSetSamplers is similar, except instead of sending an array of ID3D11ShaderResourceView, we are sending an array of ID3D11SamplerState. We only have one sampler state though, so we only need to send one.


void DrawScene()
{
	//Clear our backbuffer
	float bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)};
	d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);

	//Refresh the Depth/Stencil view
	d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0);

	//Set the WVP matrix and send it to the constant buffer in effect file
	WVP = cube1World * camView * camProjection;
	cbPerObj.WVP = XMMatrixTranspose(WVP);	
	d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
	d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
	///////////////**************new**************////////////////////
	d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture );
	d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );
	///////////////**************new**************////////////////////

	//Draw the first cube
	d3d11DevCon->DrawIndexed( 36, 0, 0 );

	WVP = cube2World * camView * camProjection;
	cbPerObj.WVP = XMMatrixTranspose(WVP);	
	d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
	d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
	///////////////**************new**************////////////////////
	d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture );
	d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );
	///////////////**************new**************////////////////////

	//Draw the second cube
	d3d11DevCon->DrawIndexed( 36, 0, 0 );

	//Present the backbuffer to the screen
	SwapChain->Present(0, 0);
}

Now we can load a texture!

Exercise:

1. Add a small border to your image.

1. Find what the best quality filter is by playing with the sampler description.

>> Download Source Code <<
<<-- Render States
Blending -->>



- Comments will not be seen by public -

- Please be sure to put your email in the message if you'd like a response -

What's 8 + 2?
Name:
Message: