0
votes

I want to capture each frame and change the position of each pixel according to a lookup table. So for example pixel (30,35) -> (40,50) and so on.

So what I have done is to capturing a frame by RenderTarget2D and going through each pixel and set the new position of each pixel in a new bitmap array. But this has reduced the performance due to the effect of RenderTarget2D.GetColor method.

So I thought Pixel Shader might be the solution: in the Draw method : 1.draw a simple frame 2.capture it by RenderTarget2D 3.and then draw the model by through the shader

But inside the shader I need to access the Texture2D which has been just captured and also the lookup table to read the mapped pixel position. How can I pass these variables to shader?

Edit: This is the code that is in Draw() method, but I can not see why no change is applied to the model

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Textures[0] = ShaderRenderTarget;
        GraphicsDevice.Textures[1] = LookupTexture;

        // Change to our offscreen render target. 
        GraphicsDevice.SetRenderTarget(ShaderRenderTarget); 
        // Render a simple scene.
        DrawAFrame(); 

        // Change back to the back buffer, and get our scene
        // as a texture. 
        GraphicsDevice.SetRenderTarget(null);

        waldramEffect.CurrentTechnique = waldramEffect.Techniques["Waldraam"];
        // Use Immediate mode and our effect to draw the scene
        // again, using our pixel shader. 
        GraphicsDevice.Clear(Color.CornflowerBlue);
        CreateViewMatrix();

        // Copy any parent transforms.
        Matrix[] transforms = new Matrix[myModel.Bones.Count];
        myModel.CopyAbsoluteBoneTransformsTo(transforms);

        // Draw the model. A model can have multiple meshes, so loop.
        foreach (ModelMesh mesh in myModel.Meshes)
        {
            // This is where the mesh orientation is set, as well 
            // as our camera and projection. 
            foreach (ModelMeshPart part in mesh.MeshParts)
            {
                part.Effect = waldramEffect;
                waldramEffect.Parameters["World"].SetValue(Matrix.CreateRotationY(modelRotation) * Matrix.CreateTranslation(modelPosition));
                waldramEffect.Parameters["View"].SetValue(lookAt);
                waldramEffect.Parameters["Projection"].SetValue(projection); 
            }
            // Draw the mesh, using the effects set above.
            mesh.Draw();
        } 
        base.Draw(gameTime);

        int i = 0;
        foreach (ModelMesh mesh in myModel.Meshes)
        {
            foreach (ModelMeshPart part in mesh.MeshParts)
            {
                part.Effect = basicEffects[i];
                i++;
            }
        }
    }
1

1 Answers

1
votes

Make your lookup table into a texture, storing the X and Y offsets in two of the texture channels (eg: red and green).

Set both textures (a render target in XNA is a texture) on the graphics device like so:

GraphicsDevice.Textures[0] = myRenderTarget;
GraphicsDevice.Textures[1] = myLookupTable;

(Note that SpriteBatch will set Texture[0] internally, if you're using that.)

In your shader, declare a sampler for each:

sampler myRenderTarget: register(s0);
sampler myLookupTable: register(s1);

Then modulate the sampled position in your render target by sampling your lookup table:

tex2D(myRenderTarget, inTexCoord.xy + tex2D(myLookupTable, inTexCoord.xy).xy);

Note that I haven't tested the above HLSL code. And you'll need to provide some additional maths if you want to have your offsets work in pixel coordinates and allow for negative offsets.