Jump to content
  • Advertisement
Sign in to follow this  
scippie

Combine two streams, but not for instancing (DX9)

This topic is 2992 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

I have created a cilinder, 45 vertices per slice, 10 + 1 slices, on the Z-axis. The slices are interconnected with the use of an index buffer (so no double points).

This gives me a tube. Now I want to "bend" this tube at runtime and preferably with a lot of GPU acceleration.

So I thought using multiple stream sources would be ideal here: I'd create an extra vertex buffer (dynamic) of size 11 with each "vertex" containing a matrix (4 float4's) for a transformation to be done in the vertex shader. The buffer could be changed at every frame if I want to create a bending-animation.

But that doesn't seem to work. Am I correct that the streamsources can only be used for instancing? I used to use it also for terrain generation where stream 0 was a grid of x-z coordinates and stream 1 was the y coordinate (and more). It was a 1 on 1 combination and it worked perfectly.

But now I need the frequency to be that every 45 vertices of stream 0 are combined with the one vertex from stream 1.

Can anyone tell me if this is possible, and if not if there is another way to do what I want to do?

At this moment, I am trying to use a texture of format A32B32G32R32 (44 x 1) to store the matrices in and then tex2dlod-ding them at vertex shading time but at this moment the results are terrible. But anyway, using a texture for these kind of things always seem very "wrong" to me.

It's so bad that I need to use DX9 because I have done far more difficult things in DX10.

So, can anyone help me?

Share this post


Link to post
Share on other sites
Advertisement
In general for this kind of skinning you can use the vertex shader constants to store the skinning matrices. The vertex data then will contain for each vertex the matrix indices that should be used and the weight. For a good quality people tend to use up to 4 matrices per vertex.

The texture solution would work too but it’s not supported by every hardware. Therefore it would depend on your target hardware if you can go this way.

Share this post


Link to post
Share on other sites
Quote:
Original post by scippie
At this moment, I am trying to use a texture of format A32B32G32R32 (44 x 1) to store the matrices in and then tex2dlod-ding them at vertex shading time but at this moment the results are terrible. But anyway, using a texture for these kind of things always seem very "wrong" to me.


There's really nothing "wrong" with using a texture for skinning. It's pretty simple, flexible, and plenty fast on hardware that has good support for vertex texture fetch (basically any DX10-capable hardware from Nvidia or ATI). In fact it can be faster than indexing into constant registers, since that has its own performance problems (constant waterfalling). Plus in DX9 you have a limited number of constant registers, which limits the number of bones that you can use.

Oh and keep in mind that typically you don't need the full 4x4 matrix for skinning, since the last column is usually just [0 0 0 1]. So you can probably just pack 4x3 matrices.

Share this post


Link to post
Share on other sites
Ok, thanks, you guys put me on track!

I now seem to have some results with the constant matrix table. I don't know why it didn't work before as I had tried this approach. Now it sort of work.

But when I try it with the texture it doesn't work at all, the matrices seem to be corrupt.

Can someone tell me what's wrong here?


...
m_pD3DDev->CreateTexture(11 * 4, 1, 1, D3DUSAGE_DYNAMIC, D3DFMT_A32B32G32R32F, D3DPOOL_DEFAULT, &m_txTubeTrans, 0);
...

D3DLOCKED_RECT lr;
m_txTubeTrans->LockRect(0, &lr, 0, 0);
for (int x = 0; x < 11; ++x)
{
D3DXMATRIX m;
D3DXVECTOR3 p;
D3DXVECTOR3 r;
GetTrajectoryPoint(((float)x / 20.0f), p, r); // (x / 20) is just a temporary test here
D3DXMatrixTranslation(&m, p.x, p.y, p.z);
((D3DXMATRIX*)lr.pBits)[x] = m;
}
m_txTubeTrans->UnlockRect(0);
...

m_fxTube->SetTexture("texTrans", m_txTubeTrans);
...





Shader:

float4x4 mWorldViewProj;

texture texTrans;
sampler smpTrans = sampler_state
{
Texture = texTrans;
MinFilter = POINT;
MagFilter = POINT;
MipFilter = POINT;
};

struct VS_IN
{
float3 pos : POSITION;
float2 tex : TEXCOORD;
float tri : BLENDINDICES;
};

PS_IN vs(VS_IN i)
{
PS_IN o;

float f = 1.0f / 44.0f;
float4x4 mT = float4x4(
tex2Dlod(smpTrans, float4(i.tri + 0 * f, 0, 0, 0)),
tex2Dlod(smpTrans, float4(i.tri + 1 * f, 0, 0, 0)),
tex2Dlod(smpTrans, float4(i.tri + 2 * f, 0, 0, 0)),
tex2Dlod(smpTrans, float4(i.tri + 3 * f, 0, 0, 0))
);

o.pos = mul(mul(mT, mWorldViewProj), float4(i.pos.xyz, 1));

return o;
}
...





The results are totally corrupt while with the same approach with a constant table, like this:


float4x4 mWorldViewProj;
float4x4 mSkin[11];

struct VS_IN
{
float3 pos : POSITION;
float2 tex : TEXCOORD;
float tri : BLENDINDICES;
};

PS_IN vs(VS_IN i)
{
PS_IN o;

float4x4 mT = mul(mSkin[(int)i.tri], mWorldViewProj);

o.pos = mul(mT, float4(i.pos.xyz, 1));

return o;
}






with the correct C++ code with it of course, it almost works, it's not corrupt.
(can anyone tell me why I need to do the cast to (int) on the i.tri? If I don't only the right half of the tube is correct, the left half is flat.

What am I doing wrong in my texture lookup version?

And then, I'm saying it almost works, but it doesn't do what I expect, it doesn't seem to deform at all. If I put something that should really do something inside the matrices instead of the GetTrajectoryPoint function I used, I still see no deformation at all.

I really put a different value in the vertex for the tri-value. To make sure, here's the code I use to generate the tube:


struct vertex {
float x, y, z;
float tx, ty;
float tr;
};

std::vector<vertex> vTube;
std::vector<WORD> iTube;

for (int x = 0; x <= 10; ++x)
{
for (int a = 0; a <= m_nGeometrySteps; ++a)
{
float s = sin((float)D3DX_PI / ((float)m_nGeometrySteps / 2.0f) * (float)a);
float c = cos((float)D3DX_PI / ((float)m_nGeometrySteps / 2.0f) * (float)a);
vertex vv;
vv.x = c;
vv.y = s;
vv.z = (float)x / 10.0f;
vv.tr = (float)x;
vTube.push_back(vv);
}

if (x < 10)
{
for (int a = 0; a <= m_nGeometrySteps; ++a)
{
iTube.push_back(x * (m_nGeometrySteps + 1) + a);
iTube.push_back((x + 1) * (m_nGeometrySteps + 1) + a);
}
}
}

...





And then I put it in a vertex buffer and index buffer.

This is my vertex declaration:

D3DVERTEXELEMENT9 decl[] = {
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0 },
D3DDECL_END()
};





Lots of questions... anyone?

Share this post


Link to post
Share on other sites
Quote:
Original post by MJP
Oh and keep in mind that typically you don't need the full 4x4 matrix for skinning, since the last column is usually just [0 0 0 1]. So you can probably just pack 4x3 matrices.


I will surely implement this when I get things working but I don't want to add extra possible errors.

Share this post


Link to post
Share on other sites
And still, can anyone tell my why it doesn't work with two streams? Are two streams only for instancing?

Share this post


Link to post
Share on other sites
Multiple vertex streams are not just for instancing.

Check out this old thread, still applicable with DX9:

http://www.gamedev.net/community/forums/topic.asp?topic_id=572675&whichpage=1�

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!