Sunday, May 24, 2009

Take the picture

I'm a sucker for a scene. Whether it be a frozen moment in time or a short sequence of events. I'm referring to the kinds of things you'd see in a good picture album or in a movie.

Something you'd want to remember or capture in some way. Something
evocative.

Emotions, events, or any notion of specifics don't matter; as long as it causes the person experiencing it to pause for even the briefest moment.

I have one of these moments after nearly every one of my daughter's violin lessons. The adjacent instruction room provides it for me. I think it's the light at that time of day. Or the arrangement of the empty furniture. Or the open violin case. Or the numerous other random details.

I liken it to walking into an empty dimly lit lecture hall or into a building or business after hours.

Luckily, one of the days the room was not in use, I had a camera on me. Under the chagrined gaze of another parent, randomly peering up from his Thinkpad, I managed to get a few exposures.

I wish the picture was sharper. My Canon EF 50mm 1:1.8 II lens seriously needs a digital body to attach itself to.

~Elmer

Friday, May 22, 2009

A stroll around the lake. End.

These photos are a continuation of photos found in a previous post.







~Elmer

Macaroni & Cheese - a lesson in futility


I'd like to talk about something very important. Macaroni & Cheese. Specifically, the Kraft variety.

I have no qualms with the taste; after all, it is "The Cheesiest." What is a source of befuddlement for me, however, is the opening mechanism.

It seems so alluringly simple. One would assume that "TO OPEN PUSH SIDE FLAP AND TEAR BACK" and "TO OPEN PUSH HERE" would combine for an easy entrance to cheesy yummy goodness.

But try as I might, a successful execution of this strategy eludes me. No amount of staring, pinching, or pulling seems to help.

And so, I resort to the default. The ripping, rending, and utter destruction of the boreal opening. Eventually, I am victorious and yet I feel defeated.

Perhaps, someday Kraft will fix the perforations or abandon the madness of this method altogether.

Until that day... Doh, the water for the macaroni and cheese is boiling. Next time. Next time.

~Elmer

Thursday, May 21, 2009

A stroll around the lake. Begin.

We managed to run the 2.8 mile inner loop of Greenlake several times this week.

Here's some pictures I snapped along the way.






More photos to follow in a later post.

~Elmer

Monday, May 18, 2009

A visit to the vet

What does a visit to the Veterinarian mean for the family dog?

He gets to come home with a bottle of eye drops and a fashionable new cone-collar.

His usual display of exuberance when presented with a hallway is dulled. And by dulled, I mean totally snuffed out. As we walk away, he plants his bottom on the ground and waits patiently for his amused owners to come back and pick him up.

A whimper or two later, we do.

~Elmer

Thursday, May 14, 2009

DirectX10 Tutorial 3 - Shaders and Effect System

The text in the SDK offers very clear and succint explanations of the topics in this tutorial.

To supplement the SDK information, I have included diagrams of what I believe to be happening at certain points in the program.

The location of certain elements in the diagram may not be exactly correct. But I believe the hierarchal information as well as the general idea of what is occuring is correct.

Click each picture to an elarged version.






I hope these were helpful. As usual, if there are any errors, please let me know and I will make the necessary corrections.

~Elmer

------
DirectX10 SDK Location: DirectX Graphics->Tutorials and Samples ->Tutorials->Basic Tutorials
Source Code Location: (SDK root)\Samples\C++\Direct3D10\Tutorials\Tutorial02
------

Thursday, May 7, 2009

DirectX10 Tutorial 2 - Rendering a Triangle

Now that we have a blank canvas, let's put something on there. We'll use the ubiquitous workhorse of computer graphics, the triangle!

Variables of note added for Tutorials 2 and 3:
ID3D10Effect* g_pEffect = NULL;
ID3D10EffectTechnique* g_pTechnique = NULL;
ID3D10InputLayout* g_pVertexLayout = NULL;
ID3D10Buffer* g_pVertexBuffer = NULL;

A triangle is made up of 3 unique points in space. Each point is referred to as a vertex. In Direct3D, the GPU accesses vertex information via the, appropriately named, vertex buffer.

Input Layout - It's all Greek to me!
Data in a vertex buffer is just a long string of bits. For the GPU to work with this data, it must be able to interpret the bits in a meaningful way. This is accomplished via an input layout.

Let's first examine the anatomy of a vertex. A vertex can have many properties. In addition to position, it can have a normal, color(s), texture coordinates, etc. For our purposes, a vertex will just have a position. We will describe the vertex using a struct with one property.

struct SimpleVertex
{
D3DXVector3 pos;// Position
// other possible attributes
};

The data for the vertices will be stored in the vertex buffer. An input layout is what allows the GPU to interpret the string of bits in the vertex buffer as data for individual vertices.

Like we have seen before, before a resource can be created and set, a decription must be filled out. In this case, the description will not be for the input layout as a whole; rather a description will be filled out for each property in the vertex structure.

These descriptions will be in the form of a D3D10_INPUT_ELEMENT_DESC structure. An application must define an array of one more of these structures. In our case, because our vertex only has one property, our array will consist one description.

// Define the input layout
D3D10_INPUT_ELEMENT_DESC layout[] =
{
{ L"POSITION", // SemanticName
0, // SemanticIndex
DXGI_FORMAT_R32G32B32_FLOAT, // Format
0, // InputSlot
0, // AlignedByteOffset
D3D10_INPUT_PER_VERTEX_DATA, // InputSlotClass
0 }, // InstanceDataStepRate
// {...}, another description if needed
// {...}, another description if needed
};
UINT numElements = sizeof(layout)/sizeof(layout[0]);

In addition to the description(s) of the property in the vertex, an input signature of the associated vertex shader is required to create the input layout. With the required information in hand, the input layout is created and set on the device.

// Create the input layout
D3D10_PASS_DESC PassDesc;
g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );

if( FAILED (g_pd3dDevice->CreateInputLayout(
layout,
numElements,
PassDesc.pIAInputSignature,
PassDesc.IAInputSignatureSize,
&g_pVertexLayout ) ) )
return FALSE;

// Set the input layout
g_pd3dDevice->IASetInputLayout( g_pVertexLayout );

Searches in the SDK for D3D10_PASS_DESC and CreateInputLayout will shed some light on the specifics. A more indepth explanation of "the technique object and the associated shaders" will be found in the next tutorial.

For now, notice the hint as to the coupled relationship between the layout and the shaders in the code:
From the code for the description of the vertex in Tutorial02.cpp
{ L"POSITION", // SemanticName

From the code for the vertex shader in Tutorial02.fx
float4 VS( float4 Pos : POSITION ) : SV_POSITION

Notice the use of POSITION in both pieces of code. It appears as though the use of POSITION as the SemanticName in the layout description is indicating to the vertex shader that this is the data it will be performing its processing on.

Vertex Buffer - Show me the vertices!
We can now turn to creating the vertex data, creating a vertex buffer that stores that data, and setting the vertex buffer on the device.

The vertices for our triangle will be stored in a SimpleVertex array with 3 elements. Following the usual protocol, before the vertex buffer can be created, descriptions must be filled out.
The D3D10_BUFFER_DESC provides a description for the vertex buffer.
The D3D10_SUBRESOURCE_DATA provides a description for the data that will be in the vertex buffer.

ID3D10Device::CreateBuffer() is then called to create the buffer. This is followed by a call to ID3D10Device::IASetVertexBuffers() to bind the vertex buffer to the input-assembler of the pipeline.

// Define the vertices to be stored in the vertex buffer
SimpleVertex vertices[] =
{ // ( X, Y, Z )
D3DXVECTOR3( 0.0f, 0.5f, 0.5f ),
D3DXVECTOR3( 0.5f, -0.5f, 0.5f ),
D3DXVECTOR3( -0.5f, -0.5f, 0.5f ),
};

// Vertex buffer description
D3D10_BUFFERDESC bd;
bd.Usage = D3D10_USAGE_DEFAULT;
bd.ByteWidth = sizeof( SimpleVertex ) * 3;
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;

D3D10_SUBRESOURCE_DATA InitData;
InitData.pSysMem = vertices;

// Create vertex buffer
if( FAILED( g_pd3dDevice->CreateBuffer (
bd, // buffer description
&InitData, // data to be stored in the vertex buffer
&g_pVertexBuffer ) ) ) // pointer to the newly created buffer

return false;

// Set vertex Buffer
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
g_pd3dDevice->IASetVertexBuffer(
0,
1,
&g_pVertexBuffer,
&stride,
&offset );

Primitive Topology - What do I do with these vertices?
Before the GPU can render the triangle, it must know how to retrieve the vertices from the vertex buffer. Setting the Primitive Topology does this. The Primitive Topology tells the GPU what to render and the order in which it needs to access the vertices in the buffer. In our case of 3 vertices for 1 triangle, the TRIANGLELIST topology will suffice.

// Set primitive topology
g_pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

Render the triangle!
The final step in the process involves using the technique obtained through the effect system to setup the GPU for drawing. First a D3D10FX_TECHNIQUE_DESC description of the technique is obtained via the ID3D10EffectTechnique::GetDesc() function call. The application will then loop through all the passes in the technique.

During each loop, the shaders and render states for that particular pass are bound to the graphics pipeline. This step will be further detailed in the next tutorial. Finally a call to ID3D10Device::Draw() is made. This instructs the GPU to draw using the current shaders, vertex buffer, vertex layout, and primitive topology bound to the pipeline.

// Render the triangle
D3D10_TECHNIQUE_DESC techDesc;
g_pTechnique->GetDesc( &techDesc );
for( UINT p = 0; p <>
{
g_pTechnique->GetPassByIndex( p )->Apply(0);
g_pd3dDevice->Draw( 3, 0 );
}

Cleanup
The following resources were created and need to be released.

if( g_pVertexBuffer ) g_pVertexBuffer->Release();
if( g_pVertexLayout ) g_pVertexLayout->Release();
if( g_pEffect) g_pEffect->Release();

Experiments
-Try different values for the X, Y, and Z positions of the vertices. What does this highlight about the min/max values used for the render window as a whole? What about camera orientation?
-Add more vertices to the vertices[] array and modify the vertex buffer description and the Draw() call to include them.
-Search the SDK for D3D10_PRIMITIVE_TOPOLOGY. Try setting different topologies and observe the results.
-Combine the different topologies with different number of vertices.

Conclusion
There you have it! A triangle drawn onto your screen.

Let's quickly recap what we did.
-Determined what information each of our vertices would contain and the format to represent them.
-Created an input layout to instruct the GPU how to interpret the data in a vertex buffer as vertices.
-Created our vertex data, stored it in a vertex buffer, and bound the buffer to the pipeline.
-Instructed the GPU how to use the vertices in the vertex buffer to render the chosen topology.
-Rendered the triangle using the technique obtained from the effect system.

One thing I wanted to mention was the use of 'input layout' and 'vertex layout' in the SDK tutorials. While each was used as a heading for a specific section, it appeared to me as though their meanings were being used in the text interchangably. I chose to treat them as referring to the same concept. If this is incorrect and they are in fact distinct, please let me know and give me an explanation.

As usual, questions, comments, criticisms, and correction are welcomed!

~Elmer

------
DirectX10 SDK Location: DirectX Graphics->Tutorials and Samples ->Tutorials->Basic Tutorials
Source Code Location: (SDK root)\Samples\C++\Direct3D10\Tutorials\Tutorial02

Attachments(s): Tutorial02.cpp
------

Sunday, May 3, 2009

DirectX10 Tutorial 1 - Direct3D 10 Basics

In this tutorial, we will learn to create the bare minimum Direct3d application. We will create a Direct3D device, set it up to render to the window, and our end result will be a window with a colored background.

Before we get started on creating the device, I'd like to highlight the variables that will be used by the code to follow. Their specific usages will become clearer as we examine the code.

ID3D10Device* g_pd3dDevice = NULL;
IDXGISwapChain* g_pSwapChain = NULL;
ID3D10RenderTargetView* g_pRenderTargetView = NULL;

Setting up the Direct3D 10 Device
We start by creating a device and a swap chain. The device provides us with rendering functionality and the ability to create and manage resources. The swap chain's function is to manage the swapping of two or more buffers. In our case, there will be two: front and back. The front buffer (read only) is what is currently being displayed on the screen. The back buffer is where the device will draw to. After the drawing is complete, the buffers are swapped and the content of the then-backbuffer now-frontbuffer is displayed.

NOTE:
As we progress through this tutorial and subsequent tutorials we'll come across many "SOME_TYPE_DESC typeDesc;" objects. There is a common pattern for how resources are outlined and created in Direct3D. A description object is created, and is either filled out manually or by means of a function. Afterwards, the description, in conjunction with related variables are used in a function call to create or bind a resource.

Before we can create and bind the swap chain, we have to fill out a 'description' for it. A detailed explanation of all of the fields can be found in the SDK. Notice the BufferUsage flag is set to DXGI_USAGE_RENDER_TARGET_OUTPUT. This indicates to the application the backbuffer will be used as a target for render output.

// Create a swap chain description and fill with the appropriate values
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof( sd ) );

// Buffer dimensions, format, and usage
sd.BufferCount = 1;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
// set the buffer as a target for render output
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;

// Refresh Rate
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;

// Multi sampling parameters
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;

// application window
sd.OutputWindow = g_hWnd;
sd.Windowed = TRUE;

With the filled out description in hand, let's create the device and swap chain. Here is the function call in isolation. Notice the description (sd) and related variables (g_pSwapChain and g_pd3dDevice) being used in the function call.

D3D10CreateDeviceAndSwapChain(
NULL,
g_driverType,
NULL,
createDeviceFlags,
D3D10_SDK_VERSION,
&sd, // Swap Chain description
&g_pSwapChain, // pointer to the swap chain
&g_pd3dDevice );// pointer to the device

Armed with a device and swap chain, we need a way to enable the device to write to the backbuffer. In DirectX10, the device accesses resources through a 'view'.

In this case, we create a 2D texture resource pointer and point it to the backbuffer using the GetBuffer function call. The CreateRenderTargetView function is called to bind the backbuffer to the newly created RenderTargetView. OmSetRenderTargets is then called to bind the view to the device's pipeline. Now, render output from the pipeline will be sent to the backbuffer.

ID3D10Texture2D* pBackBuffer;
hr = g_pSwapChain->GetBuffer(
0,
// the type of interface used to manipulate the buffer
__uuidof( ID3D10Texture2D ),
// the pointer that will store the address of the backbuffer
( LPVOID* )&pBackBuffer );

if( FAILED( hr ) )
return hr;

hr = g_pd3dDevice->CreateRenderTargetView(
// the pointer to the resource that will serve as the backbuffer
pBackBuffer,
NULL,
// the pointer that will store the address of the RenderTargetView
&g_pRenderTargetView );

pBackBuffer->Release();

if( FAILED( hr ) )
return hr;

g_pd3dDevice->OMSetRenderTargets(
1,
// the RenderTargetView(s) to be bound to the device
&g_pRenderTargetView,
NULL );

Finally, we create and set the viewport.

D3D10_VIEWPORT vp;
vp.Width = width;
vp.Height = height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pd3dDevice->RSSetViewports( 1, &vp );


Rendering
With the device ready to go, we can now render the scene.

void Render()
{
// Create the color that will be used to fill the backbuffer
float ClearColor[4] = {
0.0f, // RED
0.125f, // GREEN
0.3f, // BLUE
1.0f }; // ALPHA

// Fill the backbuffer with the color
g_pd3dDevice->ClearRenderTargetView(
g_pRenderTargetView,
ClearColor );

// instruct the swapchain to flip the buffers
g_pSwapChain->Present( 0, 0 );
}

Cleanup
We should always cleanup after ourselves! Like we were never there...
This function will set the device to the state it was in when it was first created. In addition any resources being used are released.

void CleanupDevice()
{
if( g_pd3dDevice ) g_pd3dDevice->ClearState();
if( g_pRenderTargetView ) g_pRenderTargetView->Release();
if( g_pSwapChain ) g_pSwapChain->Release();
if( g_pd3dDevice ) g_pd3dDevice->Release();
}

Conclusion:
So there you have it a minimal DirectX 10 application!

I won't be providing an exercise for this Tutorial, but if you feel like fiddling around a little, the fill color for the backbuffer easily tweakable. Check out: http://cloford.com/resources/colours/500col.htm for some nice colors. The values are 0-255 so just divide by 255 to get the 0.0-1.0 value.

I just wanted to mention something about the diagrams and, in general, about writing tutorials based off of other tutorials. The diagrams I draw and the words I write are based off of my understanding and ability to discern what I have read and visualize what is happening. I am fallible, and as such, they may not be correct. If that is the case, please please please let me know. The last thing I want to do is spread incorrect information.

I hope this was helpful to someone! I sure feel like I learned a lot. As always, questions, comments, and criticism are always welcome! Don't be a stranger.

~Elmer

------
DirectX10 SDK Location: DirectX Graphics->Tutorials and Samples ->Tutorials->Basic Tutorials
Source Code Location: (SDK root)\Samples\C++\Direct3D10\Tutorials\Tutorial01

Attachment(s): Tutorial01.cpp
------
The commenting shown in this tutorial is formatted slightly differently than in my own code. Adjustments were made and some were removed to accommodate the blog format.