Posts Tagged ‘University’

Well, day 1 didn’t get a blog entry, because I figured I’d combine them. There’s not much to say about day 1 except we flew and it was quite cool – my first time flying anywhere. Not scary at all, surprisingly.

Day 2 started off with a basic introduction to the event and a discussion of what “ambient intelligence” means. It’s a term to describe the idea of having thousands of artificially intelligent devices all attached in some way to one person – and the devices can interact.

After lunch, we had a lecture on Knowledge engineering, but it was covering things that myself and Alex Marshman have already covered in the final year of our degree. The second year students who are also here with me seemed to catch some of it though and maybe it will act as a good “taster” for the Modelling Intelligence module.

To get to and from the University I have to catch a ferry. It feels quite strange to casually catch a ferry every morning like a bus, but it’s a more entertaining way to travel than on the bus that’s for sure.

After catching the ferry home (well, back to Deutsch-Nordische Burse, which is where I’m staying) I caught the bus and went into town to get some food and stuff to wash with. The german bus system is very efficient (in Kiel at least), you don’t have to show anybody your ticket (same as the ferry) if you have one, you can just get on and ride. There are random bus checks and a large fine if you’re caught without a ticket instead. They also have maps of the entire bus route at every stop, along with a timetable, a display box of the predicted arrival times for the next few buses, and a “next stop” screen on the bus, with the name, plus a voice announcer for the next stop.

So anyway I succesfully found where I’m staying, attended the first days lectures, and travelled to town and back, so far. Hopefully tomorrow will go smoothly too.

Procedural Cylinder

First things first, the cylinder in this demo is procedurally generated within the C++ code, rather than a mesh that is loaded in.

The cylinder is rendered by means of a “D3DPT_LINELIST”, which means the vertices are treated as a list of individual lines, each one having a beginning and an end.

Nested for loops are then used to position the vertices, with the outer loop setting the initial position for each circle, the inner loop generating point pairs for each “slice” of the circle to end up with a solid unbroken line and the Y coordinate being incremented in the outer loop after the inner loop completes.


void DX::InitVertexBuffer()
{
Vertex pt;

float angle;    //angle between two points (based on NUMPOINTS)
float theta;    //theta of the angle
float w1=0.0f;
float w2=1.0f;
float w3=0.0f;
float w4=0.0f;

//Precompute angle
angle = (float) ((2*D3DX_PI) / NPOINTS);

//Preset values for the centre start point.
pt.x = 0.0f;
pt.y = -1.0f;
pt.z = 0.0f;
pt.identity[0] = 0.0f;
pt.identity[1] = 1.0f;
pt.identity[2] = 2.0f;
pt.identity[3] = 3.0f;
pt.weights[0] = w1;
pt.weights[1] = w2;
pt.weights[2] = w3;
pt.weights[3] = w4;
pt.color = 0xff00ff00;

for(int y = 0; y<CIRCLES; y++)
{
//First set the initial point
//Calculate theta for this vertex
theta = angle;

//Compute X and Z locations
circle[(y*VERTICES)].x = (float)(pt.x + RADIUS * cos(theta));
circle[(y*VERTICES)].z = (float)(pt.z - RADIUS * sin(theta));
circle[(y*VERTICES)].y = (float)(pt.y);
circle[(y*VERTICES)].color = pt.color;

//bone1
circle[(y*VERTICES)].identity[0] = 0.0f;
circle[(y*VERTICES)].weights[0] = w1;
//bone2
circle[(y*VERTICES)].identity[1] = 1.0f;
circle[(y*VERTICES)].weights[1] = w2;
//bone1
circle[(y*VERTICES)].identity[2] = 2.0f;
circle[(y*VERTICES)].weights[2] = w3;
//bone2
circle[(y*VERTICES)].identity[3] = 3.0f;
circle[(y*VERTICES)].weights[3] = w4;

//Then set the subsequent points for the circle.
for(int i=1; i<VERTICES; i+=2)
{
//Calculate theta for this vertex
theta = i * angle;

//Compute X and Z locations
circle[i+(y*VERTICES)].x = (float)(pt.x + RADIUS * cos(theta));
circle[i+(y*VERTICES)].z = (float)(pt.z - RADIUS * sin(theta));
circle[i+(y*VERTICES)].y = (float)(pt.y);
circle[i+(y*VERTICES)].color = pt.color;

circle[i+(y*VERTICES)+1].x = (float)(pt.x + RADIUS * cos(theta));
circle[i+(y*VERTICES)+1].z = (float)(pt.z - RADIUS * sin(theta));
circle[i+(y*VERTICES)+1].y = (float)(pt.y);
circle[i+(y*VERTICES)+1].color = pt.color;

//bone1
circle[i+(y*VERTICES)].identity[0] = pt.identity[0];
circle[i+(y*VERTICES)+1].identity[0] = pt.identity[0];
circle[i+(y*VERTICES)].weights[0] = w1;
circle[i+(y*VERTICES)+1].weights[0] = w1;
//bone2
circle[i+(y*VERTICES)].identity[1] = pt.identity[1];
circle[i+(y*VERTICES)+1].identity[1] = pt.identity[1];
circle[i+(y*VERTICES)].weights[1] = w2;
circle[i+(y*VERTICES)+1].weights[1] = w2;
//bone3
circle[i+(y*VERTICES)].identity[2] = pt.identity[2];
circle[i+(y*VERTICES)+1].identity[2] = pt.identity[2];
circle[i+(y*VERTICES)].weights[2] = w3;
circle[i+(y*VERTICES)+1].weights[2] = w3;
//bone3
circle[i+(y*VERTICES)].identity[3] = pt.identity[3];
circle[i+(y*VERTICES)+1].identity[3] = pt.identity[3];
circle[i+(y*VERTICES)].weights[3] = w4;
circle[i+(y*VERTICES)+1].weights[3] = w4;
}
pt.y += 0.1f;
w1 += 0.05;
w2 = 1-w1;
}

pDirectXDevice->CreateVertexBuffer(sizeof(circle), D3DUSAGE_WRITEONLY, fvf, D3DPOOL_DEFAULT,&pVertexBuffer, NULL);

void *pVertices = NULL;

pVertexBuffer->Lock(0, sizeof(circle), (void**)&pVertices, 0);

memcpy(pVertices, circle, sizeof(circle));

pVertexBuffer->Unlock();
}

Bone Set Creation

In Mesh skinning, a “Bone” is merely a matrix, which can affect different vertices of the model in varying amounts.

Each vertex fed to the graphics card for processing has an associated list of weights that determine which bones (matrices) affect it and by how much.

If you’re unclear on the basics of mesh skinning, a good guide is available from Nvidia here.

Although four bones are allowed for in the code, only two are actually used, one weighted towards either end of the cylinder. The other two bones consist of an identity matrix and a weighting of zero.

Of the two bones in use, one of the bones is a rotation matrix and is weighted to affect the top portion of the cylinder to a greater extent, the second bone is a translation matrix and allows you to move the base of the cylinder around in 3 dimensional space.

There is no reason the bottom bone cannot be a rotation and translation matrix, or just a rotation matrix like the top bone. Similarly the top bone can be any kind of transformation matrix. The choice of one rotation and one translation is merely the way I decided to do it.

The code to set the weighting for each vertex of the circle can be seen on the code sample above.

The code to initially set the bones up goes along with the setup code for the worldviewprojection matrix:


D3DXMATRIX matTrans1,matTrans2;
D3DXMATRIX matRot1;

D3DXMATRIX matWorldViewProj;

D3DXMatrixTranslation(&matTrans1, 0.0f, 0.0f, 4.0f);
D3DXMatrixTranslation(&matTrans2, bx, by, bz);

D3DXMatrixRotationYawPitchRoll(&matRot1, yaw, pitch, roll);

matWorld = matTrans1;

//combined world view projection matrix
matWorldViewProj = matWorld*matView*matProj;

Bones[0] = matRot1;
Bones[1] = matTrans2;
D3DXMatrixIdentity(&Bones[2]);
D3DXMatrixIdentity(&Bones[3]);

//set the shader matrix
pEffect->SetMatrix("WorldViewProj", &matWorldViewProj);

pEffect->SetMatrixArray("Bones",Bones,4);

Bone Weight Generation

Initially there are four bone weights, one, two, three and four, affecting bones one, two, three and four respectively. Bone two is set initially to 1.0 and all the others to 0.0.

As you loop through the circles you’re rendering, for each circle weight one is increased by 0.05, and weight two is set to one minus weight one, to produce a gradual swap between the two weights.

Weights three and four are set to zero and left that way for the duration, as they’re merely there for demonstration purposes (to demonstrate that this technique can be pushed further than two bones easily, even though it isn’t in this example).

The code to generate these weights is viewable above in the first code-sample, on lines 92-94, but I’ll repeat it here for ease of reading.


pt.y += 0.1f;
w1 += 0.05;
w2 = 1-w1;

This code is executed (as can be seen) every time the Y value of the circle being generated is incremented.

The Vertex Shader

The data is transferred to the shader in the form of a vertex structure, as defined by the flexible vertex format macro. The macro is defined as:

//Flexible Vertex Format
//
//
(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2 | D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEXCOORDSIZE4(1))

Which translates as, we’re using x, y, z floats to describe the vertex position, a DWORD to detail the colour, two texture coordinate channels, each one filled with an array of four texture coordinates.

In the shader, the matrices are passed through from the render function and the vertex enters the shader in the form of the above mentioned structure.

A temporary vector is created, then the initial value is set to weight one multiplied by the position multiplied by bone one. Then it is increased by weight two multiplied by the position multiplied by bone two.

If the other bones and weights were going to be included, you would add them all together using a “for” loop for flexibility.

The output position is then set to the temporary vector multiplied by the world view projection matrix and the colour is left unchanged.

This has the desired effect of moving each vertex in proportion to its weighting, in the direction indicated by the bone matrix.


float4x4 WorldViewProj : WORLDVIEWPROJ;

float4x4 Bones[4];
//--------------------------------------------------------------

//Structure for data passed into vertex shader
struct VS_IN
{
float3 Pos : POSITION0;
float4 Colour : COLOR0;
float4 Identitys: TEXCOORD0;
float4 Weight: TEXCOORD1;
};

//Structure for data passed out of the vertex shader and into the pixel shader
struct VS_OUTPUT
{
float4 Pos : POSITION;
float4 Colour : COLOR0;
};

//vertex shader
VS_OUTPUT VS( VS_IN vs_in )
{
VS_OUTPUT Out = (VS_OUTPUT)0;

float4 p  = vs_in.Weight.x * mul(float4(vs_in.Pos, 1), Bones[vs_in.Identitys.x]);
p += vs_in.Weight.y * mul(float4(vs_in.Pos, 1), Bones[vs_in.Identitys.y]);

//Lastly move model positions into world view

Out.Pos = mul(p, WorldViewProj);

//do nothing with colour
Out.Colour = vs_in.Colour;

return Out;
}

//pixel shader
float4 PS( VS_OUTPUT ps_in ) : COLOR
{
//do nothing with colour
return ps_in.Colour;
}

//---------------------------------------------------------------
technique BasicShader
{
pass P0
{
//Shaders
VertexShader = compile vs_2_0 VS();
pixelShader = compile ps_2_0 PS();
}
}

Example sourcecode is available here.

So yeah, got my Mesh Skinning coursework back today, 68% =) quite happy with that.

For anyone who doesn’t know (I.e. most of the people likely to read this) mesh skinning is essentially rendering a series of static vertices, which will then be tranformed in some fashion by your bone matrices, according to a weight value associated with each vertex.

Another term for this is skeletal animation. In the case of this coursework, all the transformations take place in the vertex shader, although the initial modelling is done in standard C++.

Final year project is still chuntering along. Had a meeting with Colin earlier today, he doesn’t seem to have given up on me as a student just yet!

Back-propagation still doesn’t work, due to some very strange memory bugs.. previously initialised variables seem to be spontaneously un-initiating themselves. I’m not sure exactly how I messed it up but I plan to re-implement the algorithm from scratch tomorrow, and if that doesn’t solve it, I’ll put that on the back burner and use a library to achieve that functionality for now.

I don’t actually need back-propagation working for my project (the main focus is genetic algorithms), but for a more apples to apples comparison I want back-propagation running on the same network code as the genetic algorithm. Plus implementing it gave me a bit more of a practical take on delta rule learning, which I’ll need for my planned implementation of Cascade Correlation.

Anyways – an in-depth analysis of my final year project will have to happen another night.. I’m rambling now because I’m sleepy.. so I’m going to go sleep.

A new blog!

Author: Snikks

Yes! No longer must you wait in vain my rabid fans!  I have a (new) blog! Revel in the pleasure from this news! REVEL I SAY! *ahem*

So, my final year project is all coming together nicely, probably because that’s all I’ve actually been doing for about three weeks now.. I’ve been working hours that would make 9 year old victorian chimney sweeps gasp in disbelief, I swear.

Today I got my new flexible neural network (by flexible, I mean it can contain any number of layers and any number of perceptrons per layer and the code doesn’t break.. groundbreaking I know) running and indeed learning via loading training data from a file and applying a genetic algorithm.

I hesitate to apply a code profiler because I’m sure it’s haemorrhaging memory in great gushing floods.. but sooner or later my curiousity will get the better of me and I’m sure I’ll investigate.