How can I draw many objects on screen instead of just one?

SirYakalot
  • How can I draw many objects on screen instead of just one? SirYakalot

    Like many beginner graphics programmers I followed a tutorial which showed me how to set up buffer descriptions and fill out the vertex buffer etc... - the steps involved in drawing a simple indexed cube on the screen. There is a leap however when it comes to drawing more than one of these cubes. My code below is the original cube drawing code, if called more than once, each call overwrites the vertex buffer and only one object is drawn - the last one.

    So what are the options for drawing many of these cubes?

    Cube::Cube(D3DXCOLOR colour, D3DXVECTOR3 min, D3DXVECTOR3 max)
    {
    // create eight vertices to represent the corners of the cube
    VERTEX OurVertices[] =
    {
        {D3DXVECTOR3(min.x, max.y, max.z), colour},
        {D3DXVECTOR3(min.x, max.y, min.z), colour},
        {D3DXVECTOR3(min.x, min.y, max.z), colour},
        {min, colour},
        {max, colour},
        {D3DXVECTOR3(max.x, max.y, min.z), colour},
        {D3DXVECTOR3(max.x, min.y, max.z), colour},
        {D3DXVECTOR3(max.x, min.y, min.z), colour},
    };
    
    // create the vertex buffer
    D3D10_BUFFER_DESC bd;
    bd.Usage = D3D10_USAGE_DYNAMIC;
    bd.ByteWidth = sizeof(VERTEX) * 8;
    bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    bd.MiscFlags = 0;
    
    device->CreateBuffer(&bd, NULL, &pBuffer);
    
    void* pVoid;    // the void pointer
    
    pBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid);    // map the vertex buffer
    memcpy(pVoid, OurVertices, sizeof(OurVertices));    // copy the vertices to the buffer
    pBuffer->Unmap();
    
    // create the index buffer out of DWORDs
    DWORD OurIndices[] = 
    {
        0, 1, 2,    // side 1
        2, 1, 3,
        4, 0, 6,    // side 2
        6, 0, 2,
        7, 5, 6,    // side 3
        6, 5, 4,
        3, 1, 7,    // side 4
        7, 1, 5,
        4, 5, 0,    // side 5
        0, 5, 1,
        3, 7, 2,    // side 6
        2, 7, 6,
    };
    
    // create the index buffer
    // D3D10_BUFFER_DESC bd;    // redefinition
    bd.Usage = D3D10_USAGE_DYNAMIC;
    bd.ByteWidth = sizeof(DWORD) * 36;
    bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
    bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    bd.MiscFlags = 0;
    
    device->CreateBuffer(&bd, NULL, &iBuffer);
    
    iBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid);    // map the index buffer
    memcpy(pVoid, OurIndices, sizeof(OurIndices));    // copy the indices to the buffer
    iBuffer->Unmap();
    
    //this is simply a single call to the update method that sets up the scale, rotation
    //and translation matrices, in case the cubes are static and you don't want to have to 
    //call update every frame
    Update(D3DXVECTOR3(1, 1, 1), D3DXVECTOR3(0, 0, 0), D3DXVECTOR3(0, 0, 0));
    }
    

  • If you want to draw many identical cubes, you would typically create the vertex and index buffer once - for a cube at the origin - and then re-use it for multiple draw calls. The vertex shader for the cube would include a local-to-world transformation matrix set via a shader parameter, and you'd change the transform for each draw, causing the cubes to appear in different locations and orientations.

    Another way is to use instancing. For instancing you'd have two vertex buffers, one containing a single cube at the origin as before, and the other containing a list of matrices, one for each cube. With the correct vertex shader and input layout set-up you can then do a single draw call to render all the cubes. The "inner" vertex buffer (the single cube) would be static, and if you wanted the cubes to move around, the "outer" vertex buffer (the transforms) would be dynamic, and you'd update it once per frame using D3D10_MAP_WRITE_DISCARD.

    Instancing is more efficient for drawing large numbers of small objects, but it takes a bit more code to set up. I'd recommend starting by drawing one cube at a time, setting the matrix via a shader parameter. Get that working first; you can worry about instancing later.

Tags
c++ directx graphics-programming directx10
Related questions and answers
  • ; bd.ByteWidth = sizeof(DWORD) * 36; bd.BindFlags = D3D10_BIND_INDEX_BUFFER; bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; bd.MiscFlags = 0; device->CreateBuffer(&bd, NULL, &iBuffer); // void...) * 8; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; bd.MiscFlags = 0; device->CreateBuffer(&bd, NULL, &pBuffer); void* pVoid; // the void pointer...; bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; bd.MiscFlags = 0; device->CreateBuffer(&bd, NULL, &iBuffer); // void* pVoid; // redefinition iBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid

  • ; bd.ByteWidth = sizeof(VERTEX) * 8; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; bd.MiscFlags = 0; device->CreateBuffer(&bd, NULL, &pBuffer); void* pVoid... = D3D10_USAGE_DYNAMIC; bd.ByteWidth = sizeof(DWORD) * 36; bd.BindFlags = D3D10_BIND_INDEX_BUFFER; bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; bd.MiscFlags = 0; device->CreateBuffer(&bd, NULL... pBuffer->Unmap(); // create the index buffer out of DWORDs DWORD OurIndices[] = { 0, 1, 2, // side 1 2, 1, 3, 4, 0, 6, // side 2 6, 0, 2, 7, 5, 6, // side 3 6, 5, 4

  • , but why? what's the solution? D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DYNAMIC; bd.ByteWidth = sizeof(VERTEX) * temporary2DVerts.size();// THIS LINE bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; bd.MiscFlags = 0; device->CreateBuffer(&bd, NULL, &pBuffer); void* pVoid; pBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid); //HERE memcpy(pVoid...(D3D10_PRIMITIVE_TOPOLOGY_LINELIST); UINT stride = sizeof(VERTEX); UINT offset = 0; device->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); screenPass->Apply(0

  • : temp2DVerts.size(); bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; bd.MiscFlags = 0; device->CreateBuffer(&bd, NULL, &pBuffer); void* pVoid; // the void pointer pBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid); // map the vertex buffer memcpy(pVoid, &temporary2DVerts[0], sizeof(temporary2DVerts[0... it all separately? Basically how would I extend this code to include more vectors of vertices? if (temporary2DVerts.size() > 0) { // create the vertex buffer and store the pointer into pBuffer

  • UINT stride = sizeof(LINE); UINT offset = 0; device->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); device->IASetIndexBuffer(iBuffer, DXGI_FORMAT_R32_UINT, 0); allLines... UINT stride = sizeof(VERTEX); UINT offset = 0; device->IASetVertexBuffers(0, 1, mesh.PBuffer(), &stride, &offset); device->IASetIndexBuffer(mesh.IBuffer(), DXGI_FORMAT_R32_UINT, 0...); pRotation->SetMatrix(&temporaryLines[i].rotation._11); // set the rotation matrix in the effect pPass->Apply(0); device->DrawIndexed(2, 0, 0); } temporaryLines.clear

  • : D3D10_TEXTURE2D_DESC desc; ZeroMemory(&desc, sizeof(D3D10_TEXTURE2D_DESC)); desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE; desc.Usage = D3D10_USAGE_DYNAMIC; desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; Step 2 of my plan is to use CopyResource or CopyResourceSubregion to copy data from the disk..._INVALIDARG: D3D10_MAPPED_TEXTURE2D mapped; HRESULT hr = spTexture->Map( 0, D3D10_MAP_READ, 0, &mapped ); So I'm thinking that this fails because the texture can't be read from by the CPU. So

  • theScreen("ascreen"); string splashScreen[24] = { // HERE"S THE SPLASH ! // 1 2 3 4 5 6 7 8... */ "|______________________________________________________________________________|",}; string _lines_[56] = { // 1 2 3 4 5 6 7 8 // 123456789 123456789 123456789... /////////////////////////// void Refresh(int command= ALL, int transition= NONE) { //old_map = new_map; // update the old map for(int r= 0; r< nrows; r++){ move(r,0); addstr

  • ("Couldn't load one or more sprites..."); return 0; } buffer = create_bitmap(WIDTH, HEIGHT); if (buffer == NULL) { allegro_message("Couldn't create buffer...;at(index)-&gt;Kill(); } } } void DrawBullets(BITMAP* buffer, BITMAP* sprite) { for(unsigned int index = 0; index < bullets-&gt;size(); index++) { if (bullets-&gt;at(index... = (WIDTH / 2) - 64; allegro_message("Initialzing ship class"); s-&gt;Init(x); int frame = 0; BITMAP* buffer = NULL; BITMAP* background = NULL; BITMAP* ship = NULL; SceCtrlData

  • (); } // present the back buffer contents to the display pd3dDevice -&gt; Present(NULL, NULL, NULL, NULL); } void cleanUp (void) { // release the device and the Direct3D object if (pd3dDevice...i think i just found the solution. 1) the problem is that backbuffer surface and source surface are of different formats - that is why exception was thrown. 2) the image path needed double slash "C..., Info.Format, D3DPOOL_SYSTEMMEM, &amp;Surface, NULL); D3DXLoadSurfaceFromFile(Surface, NULL, NULL, wsPath.c_str(), NULL, D3DX_FILTER_NONE, 0, NULL); pd3dDevice -&gt; GetBackBuffer(0, 0

Data information