Jump to content

  • Log In with Google      Sign In   
  • Create Account


Directx9: Problem using index buffer to draw simple triangles


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
8 replies to this topic

#1 Pasihukka   Members   -  Reputation: 131

Like
0Likes
Like

Posted 30 January 2014 - 05:38 AM

Hello,

 

I am new to directx and trying to study it's concepts from a scratch. So far I have managed to render geometries using vertex buffers. This has worked fine from the beginning. However, now I am trying to convert my application to use index buffers together with vertex buffers. But now I am facing a strange problem with index buffers. I just can't figure out what is wrong

 

The problem is that the DrawIndexedPrimitive method seems to behave oddly, especially the PrimitiveCount parameter.

 

Here is the problem:

 

I am trying to render one triangle with vertices:

0, 0, 0,

100, 0, 0,

0, 100, 0

 

Indices being 0,1,2 this is how I try to render my triangle:

 

DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 3, 0, 1);

 

But strangely, nothing is rendered! However, when I change my primitive count to 2:

 

DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 3, 0, 2);

 

my triangle is rendered.

 

Puzzled about this I decided to try how it works with two triangles:

0, 0, 0,

100, 0, 0,

0, 100, 0,

100, 0 ,0,

100, 100, 0,

0, 100, 0,

 

Now, indices being 0,1,2,3,4,5. The result is:

 

DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 6, 0, 1); -> Nothing is rendered

DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 6, 0, 2); -> Nothing is rendered

DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 6, 0, 3); ->  The first triangle is rendered

DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 6, 0, 4); -> Now both triangles are rendered

 

When I switch DrawIndexedPrimitive to DrawPrimitive it works as expected. I have absolutely no clue what is happening. Do you have any ideas? I know it may be hard without seeing the actual code, but you also may know right a way what's the problem.

 

Thanks!

 



Sponsor:

#2 Eck   Members   -  Reputation: 1712

Like
0Likes
Like

Posted 30 January 2014 - 10:21 AM

I don't use DirectX 9, but if you're seeing the triangles sometimes it probably has something to do with back face culling.

 

By default, a lot of renderers require you to specify triangle vertices in a particular order. Draw the vertices Clockwise and they'll show up. Draw them counter-clockwise and the render skips it. The reason for this is that the renderer only draws one side of the triangle to save work.

 

Consider a tetrahedron (a 4-sided die). When you draw it a certain way, you can guarantee that the sides that would be normally visible to the camera are drawn clockwise while the ones hidden from the user are drawn counter clockwise. As the model rotates, the ones that wind up being hidden by the front faces of the tetrahedron wind up being hit in a counter-clockwise order. For an easier to visualize example, you can draw a triangle on a piece of paper, number the vertices clockwise 1, 2, 3. Now flip the paper over. If you hit 1, 2, 3 from this side you'll see it's counter-clockwise

 

You've probably seen the results of this in video games. When there's a bug that allows the camera to poke through a wall, you'll see through the "backs" of other walls but can see the floor/walls on the opposite side.

 

- Eck



#3 Pasihukka   Members   -  Reputation: 131

Like
0Likes
Like

Posted 30 January 2014 - 12:07 PM


I don't use DirectX 9, but if you're seeing the triangles sometimes it probably has something to do with back face culling.

 

Thanks for your response. I am familiar with back face culling and winding order of triangles. In this case, this is most certainly not the problem. I have tested with both culling on and off and the result is the same. The problem is that primitivecount parameter in DrawIndexedPrimitive call seems to make absolutely no sense at all. When I pass the same vertex information to DrawPrimitive it works ok. None of the calls I make return any error code but it just won't work.



#4 SeanMiddleditch   Members   -  Reputation: 3858

Like
0Likes
Like

Posted 30 January 2014 - 02:12 PM

I am new to directx and trying to study it's concepts from a scratch.


DirectX 9 is 12 years old. If you're trying to understand graphics and DirectX concepts, you should _really_ start with D3D 11. The concepts it'll teach you are much more relevant to modern hardware and the design is much closer to how all graphics APIs are built now.

D3D9 was built for the long-gone transitional era from fixed-function to programmable pipelines. Modern hardware often can't even run D3D9 natively anymore (because things like the fixed-function pipeline is gone) and support for D3D9 on said hardware requires a lot of emulation in the driver to make it work (which means you might learn some concept that looks like it's fine but ends up being a performance or architectural problem when you try to apply it to modern graphics code). There's also a lot of things missing in D3D9 that are essential to really understanding modern graphics architecture. Plus there's obnoxious things in D3D9 like how gets into the LOST_DEVICE state every time you sneeze.

If your hardware is old, just remember that Direct3D 11 has a mechanism called "feature levels" that lets you use the new API with older, less-capable hardware; it lets you use the newer base API but disables some of the newer stuff that requires more recent hardware. If your OS is old, upgrade. If for some reason you want to support XP, consider using GL instead; it gives you access to newer hardware features and lets you port more easily to OSX/Linux/iOS/Android (the proprietary console APIs are more similar to D3D11). There's no good reason that I can think of for anyone to ever write new Direct3D 9 code today.

#5 Pasihukka   Members   -  Reputation: 131

Like
0Likes
Like

Posted 30 January 2014 - 02:47 PM


DirectX 9 is 12 years old. If you're trying to understand graphics and DirectX concepts, you should _really_ start with D3D 11.

 

Hi. Thank you for your thoughts. I agree with you. I probably should have chosen D3D 11. The reason I chose 9 is that WPF D3DImage works only with D3D9. I am not trying,to build a game so I need a rich set of UI controls. I'll probably need to take another look if I can make WPF work with 11.

 

 

 

Nevertheless, I am not able to sleep my nights before I figure out what's the deal with the original problem. Any suggestions?



#6 Buckeye   Crossbones+   -  Reputation: 3790

Like
0Likes
Like

Posted 30 January 2014 - 04:17 PM

To find out what the problem may be:

 

1. Is your vertex buffer setup as you list it? That is: (0, 0, 0); (100, 0, 0); (0, 100, 0);

2. How is the index buffer set up? As you have it: { 0,1,2,} ?

3. How do you have the view setup? Where is the eyepoint and what is the lookat point?

4. What cullmode do you have set? If none, then CCW (clockwise) culling is the default.

 

IF you have the vertices and indices as indicated, the triangles have a CCW winding order and would be culled.

 

For fun, try setting the indices for those vertices to { 1, 0, 2 } and see if that solves the problem.

 

Or, change the vertices to be in CW order ( 100, 0, 0 ); (0, 0, 0); (0, 100, 0) and leave the indices as 0, 1, 2.

 

[EDIT] Do you set the vertex declaration or FVF when you set the stream source and the indices?

 

[EDIT] By the way, the purpose of using index buffers is to reduce the number of vertices. Note that you've specified (100, 0, 0) and ( 0, 100, 0) twice.


Edited by Buckeye, 30 January 2014 - 07:56 PM.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.


#7 Pasihukka   Members   -  Reputation: 131

Like
0Likes
Like

Posted 31 January 2014 - 12:43 AM

Thanks for your help!

 


1. Is your vertex buffer setup as you list it? That is: (0, 0, 0); (100, 0, 0); (0, 100, 0);

 

Yes, it is.

 


2. How is the index buffer set up? As you have it: { 0,1,2,} ?

 

Index buffer is set {0,1,2}

 


3. How do you have the view setup? Where is the eyepoint and what is the lookat point?

 

I have implemented camera mouse navigation. No matter what view I have, the triangle is not there.

 


4. What cullmode do you have set? If none, then CCW (clockwise) culling is the default.

 

Tried with both D3DCULL_CCW and D3DCULL_NONE

 


For fun, try setting the indices for those vertices to { 1, 0, 2 } and see if that solves the problem.

 

Tried, it no difference.

 


[EDIT] Do you set the vertex declaration or FVF when you set the stream source and the indices?

 

Yes.


[EDIT] By the way, the purpose of using index buffers is to reduce the number of vertices. Note that you've specified (100, 0, 0) and ( 0, 100, 0) twice.

 

True! I was just trying to make the simplest possible case work :)

 

Maybe you can see from here what's the problem. This is the code I use to render my triangle:

 

    int vertexBufferSize = 3 * 6 * sizeof(float);
    int triangleBufferSize = 1 * 3 * sizeof(int);
    int streamNumber = 0;
    int offsetInBytes = 0;

    HRESULT hr = 0;
    
    // Positions and their normals
    float vertices[] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
                        100.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
                        0.0f, 100.0f, 0.0f, 0.0f, 0.0f, 1.0f};

    int indices[] = {0,1,2};

    hr = m_pd3dDevice->CreateVertexBuffer(vertexBufferSize,
                                          D3DUSAGE_WRITEONLY,
                                          D3DFVF_CUSTOMVERTEX,
                                          D3DPOOL_DEFAULT,
                                          &m_pd3dVB,
                                          NULL);

    hr = m_pd3dDevice->CreateIndexBuffer(triangleBufferSize,
                                        D3DUSAGE_WRITEONLY,
                                        D3DFMT_INDEX32,
                                        D3DPOOL_DEFAULT,
                                        &m_pd3dIB,
                                        NULL);

    void* pVertices = nullptr;
    hr = m_pd3dVB->Lock(vertexBufferSize, 0, &pVertices, 0);
    memcpy(pVertices, vertices, vertexBufferSize);
    m_pd3dVB->Unlock();

    void* pIndices = nullptr;
    hr =  m_pd3dIB->Lock(triangleBufferSize, 0, &pIndices, 0);
    memcpy(pIndices, indices, triangleBufferSize);
    m_pd3dIB->Unlock();   

    hr = m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); 
    hr = m_pd3dDevice->SetStreamSource(streamNumber, m_pd3dVB, offsetInBytes, sizeof(CUSTOMVERTEX));  
    hr = m_pd3dDevice->SetIndices(m_pd3dIB);
    
    // This works
    //hr = m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);   
    // This does not work!
    hr = m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 3, 0, 1);
    // Strange enough, this works!
    //hr = m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 3, 0, 2);



#8 Pasihukka   Members   -  Reputation: 131

Like
0Likes
Like

Posted 03 February 2014 - 01:15 AM

Found it!

 

It turned out my lock calls were wrong.

 

hr = m_pd3dVB->Lock(vertexBufferSize, 0, &pVertices, 0);

hr =  m_pd3dIB->Lock(triangleBufferSize, 0, &pIndices, 0);

 

should be

 

hr = m_pd3dVB->Lock(0, vertexBufferSize, &pVertices, 0);

hr =  m_pd3dIB->Lock(0, triangleBufferSize, &pIndices, 0);

 

Damn, it took long to figure out this simple thing!



#9 Krohm   Crossbones+   -  Reputation: 2960

Like
0Likes
Like

Posted 03 February 2014 - 01:50 AM


By default, a lot of renderers require you to specify triangle vertices in a particular order
As a side note: HW by itself does not require this. It is a feature built in graphics API pretty much since day zero. The HW has little preference for one setting over another and you can even change the visible winding if you want with no performance penalty at all.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS