0
\$\begingroup\$

I need help with a image processing task... I'm using SharpDX which I am very new to. I have a device3D, device3DContext... I have a Texture2D for off-screen rendering... I have a RenderTargetView...

Here is what I cannot figure out... I need to create a Quad aligned to the target dimensions... based on a TriangleStrip... I need to load an image onto said Quad... I need to be able to apply a Pixel Shader to it...

Here is my prototype so far...

public event Action OnInitialized;

    public ImageProcessor()
    {

    }

    public void Initialize(System.Drawing.Size size)
    {
        try
        {

            var bestAdapter = DisplayAdapters.GetBestAdapter(SharpDX.Direct3D.FeatureLevel.Level_10_0);

            using (
                var device = new SharpDX.Direct3D11.Device(bestAdapter,
                    SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport, bestAdapter.FeatureLevel()))
            {
                Device = device.QueryInterface<SharpDX.Direct3D11.Device1>();
            }

            using (var dxgiDevice = Device.QueryInterface<SharpDX.DXGI.Device>())
            {
                GPUDescription = dxgiDevice.Adapter.Description.Description;
            }

            DeviceContext = AddDisposable(Device.ImmediateContext.QueryInterface<SharpDX.Direct3D11.DeviceContext1>());

            var colorFormat = SharpDX.DXGI.Format.R8G8B8A8_UNorm;

            var bufferDescription = new SharpDX.Direct3D11.Texture2DDescription()
            {
                ArraySize = 1,
                BindFlags = SharpDX.Direct3D11.BindFlags.RenderTarget | SharpDX.Direct3D11.BindFlags.ShaderResource,
                CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.None,
                Format = colorFormat,
                Height = size.Height,
                Width = size.Width,
                MipLevels = 1,
                OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.None,
                SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
                Usage = SharpDX.Direct3D11.ResourceUsage.Default
            };

            Target = new SharpDX.Direct3D11.Texture2D(Device, bufferDescription);

            RenderTargetView = new SharpDX.Direct3D11.RenderTargetView(Device, Target);

            OnInitialized?.Invoke(this);

        }
        catch (SharpDX.SharpDXException ex)
        {

            var desc = ex.ResultCode;
        }
    }

    public System.Drawing.Image ProcessImage(string filename)
    {

        Device.ImmediateContext.ClearRenderTargetView(RenderTargetView, SharpDX.Color.Gray);

        Target = TextureLoader.CreateTexture2DFromFile(Device, filename);

        Device.ImmediateContext.Flush();

        var memoryStream = new MemoryStream();

        CopyTexture.ToImage(DeviceContext, Target, memoryStream);
        memoryStream?.Flush();

        var processedImage = System.Drawing.Image.FromStream(memoryStream);
        memoryStream?.Dispose();

        return processedImage;
    }

    private SharpDX.Direct3D11.Device1 Device;
    private SharpDX.Direct3D11.DeviceContext1 DeviceContext;

    private SharpDX.Direct3D11.Texture2D Target;
    private SharpDX.Direct3D11.RenderTargetView RenderTargetView;

    public string GPUDescription = string.Empty;

Please explain code in detail...

I've asked a similar question and someone provided a HLSL file which didn't require vertices however, I have no idea how to apply it... So I figured I'd provide the code and ask for more detailed help.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Hey mate so there are a few ways to draw on screen, you can draw a full screen triangle and do some fancy shader math or you can render a full quad.

Ill show you how to do both.

Full Screen Quad Render:

This is the full quad renderer class, its a bit of setup but it works well, I pulled it out of my code base so you will have to remove all my stuff.

Public Class QuadRenderer
Private _vertexBuffer As VertexPositionTexture() = Nothing
Private _indexBuffer As Integer() = Nothing
Private instdata As DataStream
Private vertexBuffer As Buffer
Private indexBuffer As Buffer
Private QuadInputlayout As InputLayout
Private QuadVertexBinding As VertexBufferBinding()


Public Sub New(_device As LowLevelDevice, ShaderInput As ShaderBytecode)
  'setting up the indexbuffer
    _indexBuffer = New Integer() {0, 3, 2, 0, 1, 3}
    instdata = New DataStream(_indexBuffer.Count * 4, True, True)
    instdata.WriteRange(_indexBuffer, 0, _indexBuffer.Count)
    instdata.Position = 0
    indexBuffer = _device.CreateBuffer(instdata, _indexBuffer.Count * 4, ResourceUsage.Immutable, BindFlags.IndexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0)

'setting up the quad verts
    _vertexBuffer = New VertexPositionTexture(3) {}
    _vertexBuffer(0) = New VertexPositionTexture(New Vector3(-1.0!, 1.0!, 0!), New Vector2(0!, 0!))
    _vertexBuffer(1) = New VertexPositionTexture(New Vector3(1.0!, 1.0!, 0!), New Vector2(1.0!, 0!))
    _vertexBuffer(2) = New VertexPositionTexture(New Vector3(-1.0!, -1.0!, 0!), New Vector2(0!, 1.0!))
    _vertexBuffer(3) = New VertexPositionTexture(New Vector3(1.0!, -1.0!, 0!), New Vector2(1.0!, 1.0!))

  'setting up the vertexbuffer
    instdata = New DataStream(_vertexBuffer.Count * VertexPositionTexture.Stride, True, True)
    instdata.WriteRange(_vertexBuffer, 0, _vertexBuffer.Count)
    instdata.Position = 0

    vertexBuffer = _device.CreateBuffer(instdata, New BufferDescription(_vertexBuffer.Count * VertexPositionTexture.Stride, ResourceUsage.Immutable, BindFlags.VertexBuffer, 0, 0, 0))
    QuadVertexBinding = New VertexBufferBinding() {New VertexBufferBinding(vertexBuffer, VertexPositionTexture.Stride, 0)}

  'setting up the inputlayout
    Dim PosColor As InputElement() = {New InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0, InputClassification.PerVertexData,
    0), New InputElement("TEXCOORD", 0, Format.R32G32_Float, InputElement.AppendAligned, 0, InputClassification.PerVertexData, 0)}

    QuadInputlayout = _device.CreateInputLayout(ShaderInput, PosColor)
End Sub



Public Sub RenderQuad(ByRef _Context As DeviceContext,srv as shaderresourceview)
  'setting renderstate
    _Context.PixelShader.SetShaderResource(0, srv)' srv= the texture you want to draw
    _Context.InputAssembler.InputLayout = QuadInputlayout
    _Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList
    _Context.InputAssembler.SetVertexBuffers(0, QuadVertexBinding)
    _Context.InputAssembler.SetIndexBuffer(indexBuffer, Format.R32_UInt, 0)
    _Context.DrawIndexed(6, 0, 0)
End Sub

End Class

_device.CreateInputLayout is a custom inputlayout builder so you just pass it a vertex shader and it gives you the correct inputlay but you will have to start a new question for that.

HLSL: This is the shader for the full screen quad.

Texture2D colorMap; //DeviceContext.PixelShader.SetShaderResource(0, srv) sets this on the cpu
sampler colorSampler = sampler_state
{

AddressU = Clamp;
AddressV = Clamp;
Filter = MIN_MAG_MIP_POINT;
};
struct VertexInput
{
float3 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
VertexShaderOutput VSQuad2(VertexInput input)
{
VertexShaderOutput result;

result.Position = float4(input.Position,1); //reading vertex data from the stream
result.TexCoord = input.TexCoord; 

return result;
}
PixelShaderOutput PShader(VertexShaderOutput input) 
{
 PixelShaderOutput output = (PixelShaderOutput)0;  

 float4 Color= colorMap.Sample(colorSampler , input.TexCoord);//the texture you want to draw


 return output;
}

Full Screen Triangle:

The cool thing about this one is that there is no CPU side set up, the DX runtime will generate the vertex data for you.

Use this bit of code to draw the full screen triangle.

    DeviceContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList
    DeviceContext.PixelShader.SetShaderResource(0, srv)' srv= the texture you want to draw
    DeviceContext.InputAssembler.SetVertexBuffers(Nothing)
    DeviceContext.InputAssembler.SetIndexBuffer(Nothing, Nothing, Nothing)
    DeviceContext.Rasterizer.State = Nothing
    DeviceContext.Draw(3, 0)

HLSL:

This is where the magic happens, you take your 3 verts and then position them in a way that covers the whole view port.

Texture2D colorMap; //DeviceContext.PixelShader.SetShaderResource(0, srv) sets this on the cpu
sampler colorSampler = sampler_state
{

AddressU = Clamp;
AddressV = Clamp;
Filter = MIN_MAG_MIP_POINT;
};



struct VertexShaderOutput
{
float4 Position : SV_Position;
float2 TexCoord : TEXCOORD0;

};
struct PixelShaderOutput
{
float4 Color : SV_Target0;

};



// outputs a full screen triangle with screen-space coordinates
// input: three empty vertices
VertexShaderOutput VSQuad( uint vertexID : SV_VertexID )
{
VertexShaderOutput result;
result.TexCoord = float2((vertexID << 1) & 2, vertexID & 2);
result.Position  = float4(result.TexCoord  * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f); // compute the position data
return result;
}


PixelShaderOutput PShader(VertexShaderOutput input) 
{
 PixelShaderOutput output = (PixelShaderOutput)1;
float4 Color = colorMap.Sample(colorSampler, input.TexCoord); //the texture you want to draw
output.Color =Color;    
 return output;
}


technique11 Render
{
pass P0
{

    SetVertexShader( CompileShader( vs_5_0, VSQuad() ) );
    SetPixelShader( CompileShader( ps_5_0, PShader() ) );
}
}

I just had a look at the other question you asked and I need to say that the guy who wrote the answer there explains of the full screen triangle stuff works much better.

\$\endgroup\$
1
  • \$\begingroup\$ I thank you so much for you help. The other answer just wasn't detailed enough. You have given me great detail. I just didn't know how to use his answer... If you can educate me I'd love to learn what he was trying to teach me... I'm just too new as SharpDX... \$\endgroup\$
    – Reaper
    Commented Jan 31, 2017 at 3:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .