Domanda

I am trying to find an efficient way to pan a 2D image in place using DirectX 9

I've attached a picture below that hopefully explains what I want to do. Basically, I want to scroll the tu and tv coordinates of all the quad's vertices across the texture to produce a "scrolling in place" effect for a 2D texture.

The first image below represents my loaded texture. The second image is the texture with the tu,tv coordinates of the four vertices in each corner showing the standard rendered image. The third image illustrates what I want to happen; I want to move the vertices in such a way that the box that is rendered straddles the end of the image and wraps back around in such a way that the texture will be rendered as shown with the two halves of the cloud separated. The fourth image shows my temporary (wasteful) solution; I simply doubled the image and pan across until I reach the far right edge, at which point I reset the vertices' tu and tv so that the box being rendered is back on the far right.

Is there a legitimate way to do this without breaking everything into two separate quads?

Panning Clouds

I've added details of my set up and my render code below, if that helps clarify a path to a solution with my current design.

I have a function that sets up DirectX for 2D render as follows. I've added wrap properties to texture stage 0 as recommended:

VOID SetupDirectXFor2DRender()
{
    pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
    pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
    pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_POINT );

    // Set for wrapping textures to enable panning sprite render
    pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP );
    pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP );

    pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
    pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 0 );

    pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true );
    pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, false );

    pd3dDevice->SetRenderState( D3DRS_SRCBLEND , D3DBLEND_SRCALPHA );
    pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA) ;

    pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
    pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
    pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );

    pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
    pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
    pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );

    pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
    pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
    pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );

    return;
}

On each frame, I render things as follows:

VOID RenderAllEntities()
{
    HRESULT hResult;
    // Void pointer for DirectX buffer locking
    VOID* pVoid;

    hResult = pd3dDevice->Clear( 0,
                                 NULL,
                                 D3DCLEAR_TARGET,
                                 0x0,
                                 1.0f,
                                 0 );

    hResult = pd3dDevice->BeginScene();

    // Do rendering on the back buffer here
    hResult = pd3dDevice->SetFVF( CUSTOMFVF );

    hResult = pd3dDevice->SetStreamSource( 0, pVertexBuffer, 0, sizeof(CUSTOM_VERTEX) );

    for ( std::vector<RenderContext>::iterator renderContextIndex = queuedContexts.begin(); renderContextIndex != queuedContexts.end(); ++renderContextIndex )
    {
        // Render each sprite
        for ( UINT uiIndex = 0; uiIndex < (*renderContextIndex).uiNumSprites; ++uiIndex )
        {
            // Lock the vertex buffer into memory
            hResult = pVertexBuffer->Lock( 0, 0, &pVoid, 0 );
            // Copy our vertex buffer to memory
            ::memcpy( pVoid, &renderContextIndex->vertexLists[uiIndex], sizeof(vertexList) );
            // Unlock buffer
            hResult = pVertexBuffer->Unlock();

            hResult = pd3dDevice->SetTexture( 0, (*renderContextIndex).textures[uiIndex]->GetTexture() );   
            hResult = pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 6 );
        }
    }

    // Complete and present the rendered scene
    hResult = pd3dDevice->EndScene();
    hResult = pd3dDevice->Present( NULL, NULL, NULL, NULL );

    return;
}

To test SetTransform, I tried adding the following (sloppy but temporary) code block inside the render code before the call to DrawPrimitive:

{
    static FLOAT di = 0.0f;
    static FLOAT dy = 0.0f;

    di += 0.03f;
    dy += 0.03f;
    // Build and set translation matrix
    D3DXMATRIX ret;

    D3DXMatrixIdentity(&ret);
    ret(3, 0) = di;
    ret(3, 1) = dy;
    //ret(3, 2) = dz;

    hResult = pd3dDevice->SetTransform( D3DTS_TEXTURE0, &ret );
}

This does not make any of my rendered sprites pan about. I've been working through DirectX tutorials and reading the MS documentation to catch up on things but there are definitely holes in my knowledge, so I hope I'm not doing anything too completely brain-dead.

Any help super appreciated.

Thanks!

È stato utile?

Soluzione

This should be quiet easy to do with one quad.

Assuming that you're using DX9 with the fixed function pipeline, you can translate your texture with IDirect3DDevice9::SetTransform (doc) with the properly texture as D3DTRANSFORMSTATETYPE(doc) and a 2D-Translation Matrix. You must ensure that your sampler state D3DSAMP_ADDRESSU and D3DSAMP_ADDRESSV (doc) is set to D3DTADDRESS_WRAP (doc). This tiles the texture virtually, so that negativ uv-values or values greater 1 are mapped to an infinit repetition of your texture.

If you're using shaders or another version of directx, you can translate you texture coordinate by yourself in the shader or manipulate the uv-values of your vertices.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top