Question

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++;
            }
        }
    }
Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top