Missing the vertex!

Started by
9 comments, last by Ubermeowmix 10 years, 3 months ago

I'm not from a coding background originally so some of these concepts are hard for me to pick up, I need a little clarity if you can help.

When creating different vertex & index buffer objects, how do I load multiple objects into the same IASetVertexBuffers call.

How do I seperate say a Quad and a cube into different functions/classes and then draw them to:

d3d11DevCon->IASetVertexBuffers( 0, 1, &pVertexBuffers, &stride, &offset );

I'm a little lost on how to implement this bit.

If you get near a point, make it!
Advertisement

You need to use a single vertex buffer large enough to contain both sets of geometry. Then, you write one set of geometry to the start of the buffer, followed by the other set of geometry. If you are using index buffers, you'll need to do something similar with the index buffer.

When you draw the geometry, you need to use offsets to indicate the first vertex in the buffer to draw, and the number of vertices to draw.

Eric Richards

SlimDX tutorials - http://www.richardssoftware.net/

Twitter - @EricRichards22

You would consider learning arrays in C and C++. There is a difference between a pointer to pointer and a pointer to the array of your variables.

Good luck.

Nice one, thanks for the replies.

If you get near a point, make it!

I know i'm still mixed up with how I'm creating different objects.

Here is a snippet from an instancing example, I initially thought this was where I was headed to create seperate objects ready for drawing. But this just points to different instances of the same object.


// Set the buffer strides.

strides[0] = sizeof(VertexType);

strides[1] = sizeof(InstanceType); </pre>



// Set the buffer offsets.

offsets[0] = 0;

offsets[1] = 0;



// Set the array of pointers to the vertex and instance buffers.

bufferPointers[0] = m_vertexBuffer;    

bufferPointers[1] = m_instanceBuffer;



// Set the vertex buffer to active in the input assembler so it can be rendered.

deviceContext->IASetVertexBuffers(0, 2, bufferPointers, strides, offsets);

How do I create and pass


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),



    };







    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;



    



    D3D11_SUBRESOURCE_DATA vertexBufferData2;







    ZeroMemory( &vertexBufferData2, sizeof(vertexBufferData2) );



    vertexBufferData2.pSysMem = v;



   



    hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData2, &cube1VertBuffer);







    UINT stride = sizeof( Vertex );



    UINT offset = 0;



    //d3d11DevCon->IASetVertexBuffers( 0, 1, &cube1VertBuffer, &stride, &offset );



    d3d11DevCon->IASetVertexBuffers( 0, 1, &pVertexBuffers, &stride, &offset );







    //Create the Input Layout



    hr = d3d11Device->CreateInputLayout( layout, numElements, VS_Buffer->GetBufferPointer(),



        VS_Buffer->GetBufferSize(), &vertLayout );







    //Set the Input Layout



    d3d11DevCon->IASetInputLayout( vertLayout );







    //Set Primitive Topology



    d3d11DevCon->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

And the next one:


    VertexSquare v2[] =

    {

        VertexSquare(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f),

        VertexSquare(-1.0f,  1.0f, -1.0f, 0.0f, 0.0f),

        VertexSquare( 1.0f,  1.0f, -1.0f, 1.0f, 0.0f),

        VertexSquare( 1.0f, -1.0f, -1.0f, 1.0f, 1.0f),

    };



    D3D11_BUFFER_DESC vertexBufferDescSquare;

    ZeroMemory( &vertexBufferDescSquare, sizeof(vertexBufferDescSquare) );

    vertexBufferDescSquare.Usage = D3D11_USAGE_DYNAMIC;

    vertexBufferDescSquare.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

    vertexBufferDescSquare.BindFlags = D3D11_BIND_VERTEX_BUFFER;

    const int sizeOfSprite = sizeof( VertexSquare ) * 6;

    vertexBufferDescSquare.ByteWidth = sizeOfSprite * ciMaxLetters;

    //vertexBufferDesc.MiscFlags = ciMaxLetters;



    D3D11_SUBRESOURCE_DATA vertexBufferDataSquare;

    ZeroMemory( &vertexBufferDataSquare, sizeof(vertexBufferDataSquare) );

    vertexBufferDataSquare.pSysMem = v2;

    hr = d3d11Device->CreateBuffer( &vertexBufferDescSquare, &vertexBufferDataSquare, &pVertexBuffers);

    

    if( FAILED( hr ) ) { MessageBox( 0, L"In LoadSquares, failed to create vertex buffer!", L"Error", MB_OK ); return 0; }



    //Create the Input Layout

    hr = d3d11Device->CreateInputLayout( layoutSquare, numElementsSquare, VS_Buffer->GetBufferPointer(),

        VS_Buffer->GetBufferSize(), &vertLayoutSquare );    



    UINT stride = sizeof( VertexSquare );

    UINT offset = 0;



    d3d11DevCon->IASetInputLayout( vertLayoutSquare );

    d3d11DevCon->IASetVertexBuffers( 0, 2, &pVertexBuffers, &stride, &offset );

    d3d11DevCon->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

And pass them both to the d3dDeviceContext for drawing, it's really confusing and it never seems to be outlined if I'm doing this call seperately for each object, or where I need to be looking to implement seperate object calls.

Your help would br greatly appreciated as I am running out of hair!

If you get near a point, make it!

Instancing is a method to draw the same geometry at different positions with one draw call. This is a little bit more advanced and now you have made your life unnecessarily hard working from such an example. Drawing subsets (that's what you're after) is simpler. Though one can of course combine instancing and subset drawing.

The offsets eric was talking about are parameters of the draw call. Take e.g. that cube. I assume the full cube is drawn with DrawIndexed(36, 0, 0) (no instancing). Now look at it as if that cube has "several geometries", namely the individual faces. If you want to draw just the first face (two triangles) you use DrawIndexed(6,0,0). For the second it would be DrawIndexed(6,6,0), for the third DrawIndexed(6,12,0) and so on...

All draw calls have such parameters where you can control what part of the index or vertex buffer is used. Also, I think subsets only make sense with triangle lists.

Alternatively, one can use offsets when binding the buffers already.

This post duplicated, see below

If you get near a point, make it!

Right that's what I already had a basic grasp of, as the program I am running is generating 6 cubes & includes clockwise & counter clockwise culling to acheive transparency. Plus each has their own texture, and is affected by the transforms of world space so they all do silly movements.

So I understand that the same object can be essentially tweaked and modified within reason.

I don't think that this is going to work with the font engine that I have modified to take large text blocks from my Directx 11 game programming book:


bool DrawString( const char* message, float startX, float startY )



{



    // size in bytes for a single sprite



    const int sizeOfSprite = sizeof( VertexSquare ) * 6;







    int length = strlen( message );







    //clamp for strings too long



    if( length > ciMaxLetters )



        length = ciMaxLetters;







    //chars width on screen



    // this could be pulled in for the height of the loaded font if it's a single line, or even divided by itself if it can be squared.



    //float charWidth = 32.0f / Width;



    //float charHeight = 32.0f / Height;



    float charWidth = 256.0f / Width;



    float charHeight = 256.0f / Height;







    //chars texel width



    // this could be pulled in for the width of the loaded font



    float texelWidth = 32.0f / 1024.0f;



    float texelHeight = 32.0f / 96.0f;







    //verts per-triangle (3) * total triangles (2) = 6



    const int verticesPerLetter = 6;







    D3D11_MAPPED_SUBRESOURCE mapResource;



    HRESULT hr = d3d11DevCon->Map( pVertexBuffers,



                                          0,



                                          D3D11_MAP_WRITE_DISCARD,



                                          0,



                                          &mapResource );







    if( FAILED( hr ) ) { DXTRACE_MSG( L"Failed to map resource." ); return false; }







    //point to our vertex buffer's internal data.



    VertexSquare *spritePtr = ( VertexSquare* )mapResource.pData;







    const int indexStart = static_cast<char>( ' ' );



    const int indexEnd = static_cast<char>( '~' );







    int iCurrLetterInc = 0;



    int iLineCount = 0;



    int iLineReset = 0;



    int iCurrCrop = 45;



    



    std::stringstream wss;



    for( int i = 0; i < length; ++i )                                        //FOR LOOP to check each character in message



    {



        //if current char count is over #



            //then increment the line number to X



            //reset the current startX to zero



                //increment the values of startY to incorporate an extra multiple of height



        //set the code going again







        if(iCurrLetterInc >= iCurrCrop)                                    //if i is greater than iCurrCrop, increment the line



        {



            iLineCount++;



            iCurrLetterInc = 0;



        }







        int newX = iLineCount * iCurrCrop;



        



        float thisStartX = startX + ( charWidth * static_cast<float>( i - newX ) );



        float thisEndX = thisStartX + charWidth;







        float thisStartY = startY - ( iLineCount * charHeight );                    //because of multiple lines the thisStartY will be lower everytime we start a new line



        float thisEndY = ( startY + charHeight ) - ( iLineCount * charHeight );        //VERY IMPORTANT... the second brackets mean that they are doubling up the x value in the down direction, otherwise it will turn the polygon away from the camera.







        spritePtr[0].pos = XMFLOAT3( thisEndX,        thisEndY,        1.0f );



        spritePtr[1].pos = XMFLOAT3( thisEndX,        thisStartY,        1.0f );



        spritePtr[2].pos = XMFLOAT3( thisStartX,    thisStartY,        1.0f );



        spritePtr[3].pos = XMFLOAT3( thisStartX,    thisStartY,        1.0f );



        spritePtr[4].pos = XMFLOAT3( thisStartX,    thisEndY,        1.0f );



        spritePtr[5].pos = XMFLOAT3( thisEndX,        thisEndY,        1.0f );







        int texLookup = 0;



        int letter = static_cast<char>( message[i] );







        if( letter < indexStart || letter > indexEnd )



        {



            texLookup = indexStart;                                    //if it's out of bounds use a space



        } else {



            texLookup = ( letter - indexStart ) ;



        }







        float tuStart    = 0.0f;



        float tuEnd        = 0.0f;



        float tuTop        = 0.0f;



        float tuBottom    = 0.0f;







        if( letter > 63 )                                            //if letter is > ?(1024 pixel width 1st line ends) but less than ~ (third row's start)



        {



            if ( letter > 95 )



            {



                tuStart = 0.0f + ( texelWidth * static_cast<float>( texLookup ) );



                tuEnd = tuStart + texelWidth;







                tuTop = 0.0f + ( texelHeight * 2 );



                tuBottom = tuTop + texelHeight;                        //OutputDebugString( "THIRD LINE LOADED!\n" );



            } else {



                tuStart = 0.0f + ( texelWidth * static_cast<float>( texLookup ) );



                tuEnd = tuStart + texelWidth;







                tuTop = 0.0f + ( texelHeight * 1 );



                tuBottom = tuTop + texelHeight;                        //OutputDebugString( "SECOND LINE LOADED!\n" );



            }



        } else {



            tuStart = 0.0f + ( texelWidth * static_cast<float>( texLookup ) );



            tuEnd = tuStart + texelWidth;







            tuTop = 0.0f;



            tuBottom = tuTop + texelHeight;                            //OutputDebugString( "FIRST LINE LOADED!\n" );



        }







        spritePtr[0].texCoord = XMFLOAT2( tuEnd, tuTop );



        spritePtr[1].texCoord = XMFLOAT2( tuEnd, tuBottom );



        spritePtr[2].texCoord = XMFLOAT2( tuStart, tuBottom );



        spritePtr[3].texCoord = XMFLOAT2( tuStart, tuBottom );



        spritePtr[4].texCoord = XMFLOAT2( tuStart, tuTop );



        spritePtr[5].texCoord = XMFLOAT2( tuEnd, tuTop );







        spritePtr += 6;



        iCurrLetterInc++;



    }



    //OutputDebugString( wss.str().c_str()  );



    



    d3d11DevCon->Unmap( pVertexBuffers, 0 );



    d3d11DevCon->Draw( 6 * length, 0 );  // 6 vertices * the length of the font







    return true;



}

Where do I start adding models and other geometric primitives?

Is that what the offset is about?

Is it basically, rough sudo code example follows:



Buffer* cubeObject;
Buffer* treeModelObject;
Buffer* carModelObject;
(and an index buffer for each)
 
//Then each one gets loaded
UINT stride = sizeof( VertexCube );

UINT offset = 0;


d3d11DevCon->IASetVertexBuffers( 0, 1, &cubeObject, &stride, &offset );
 
UINT stride = sizeof( VertexTree );

UINT offset = ???;
 
d3d11DevCon->IASetVertexBuffers( 0, 1, &treeModelObject, &stride, &offset );
 
UINT stride = sizeof( VertexCar );

UINT offset = ???;
 
d3d11DevCon->IASetVertexBuffers( 0, 1, &carModelObject, &stride, &offset );
 
//and then the draw calls follow

There's nowhere that explains what to do when offsetting to outline what to put where and why!?

I don't understand where different models are saved in memory to be presented after their draw calls have been actioned. If I make multiple calls to IASetVertexBuffers then everything goes south.

If you get near a point, make it!
Now I think I finally get your confusion. You're probably not even after subsets at all. If it's just about drawing different objects, it's even simpler: Bind the buffers for one object, draw, bind another, draw...

IASetVertexBuffers/IASetIndexBuffer don't "stack" like you probably suspect. When issuing a draw call, only the latest call to them matters. Buffers and their content also don't get lost/destroyed after drawing, if I get your meaning. They stay alive until you did your final Release() call (or more precise: when their reference counter reaches 0).

The purpose for binding multiple buffers at once is rather for e.g. instancing (where one buffer defines the geometry, another the transformations) or if you want to split vertex attributes (e.g. one buffer could hold positions, another normals. In that case, they still define the same object).

So after creating this:

    //Set the vertex buffer
    UINT stride = sizeof( Vertex );
    UINT offset = 0;
    d3d11DevCon->IASetVertexBuffers( 0, 1, &squareVertBuffer, &stride, &offset );

    //Create the Input Layout
    hr = d3d11Device->CreateInputLayout( layout, numElements, VS_Buffer->GetBufferPointer(),
        VS_Buffer->GetBufferSize(), &vertLayout );

    //Set the Input Layout
    d3d11DevCon->IASetInputLayout( vertLayout );

    //Set Primitive Topology
    d3d11DevCon->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

Where do I then access this information at a later time, as several things need to happen in between.

Initialization of further objects, and setting their own unique IA details.

Update of scene, variables need to be adjusted.

Then the draw call comes after that, this is where I'm getting 1 triangle of a cube drawn which is weird colours & my text is some how taking on the coordinates of the cubes :S

If you get near a point, make it!

This topic is closed to new replies.

Advertisement