Laden...

SharpDX: Wie Shader auf Screenshot anwenden?

Erstellt von gagagu vor 8 Jahren Letzter Beitrag vor 8 Jahren 3.715 Views
G
gagagu Themenstarter:in
5 Beiträge seit 2015
vor 8 Jahren
SharpDX: Wie Shader auf Screenshot anwenden?

Hallo ich habe ein Virtual Reality Programm geschrieben das die Bildschirmausgabe von Spielen (im Fenstermodus) als Bitmap läd und an das iPhone sendet. Zum ermitteln der Screenshots verwende ich SharpDX und folgenden Beispielcode ScreenCapture

Nun möchten einige User das ich eine Linsenkorrektur einfüge. Prinzipiell ist das ein Barrel Distortion Algorithmus den ich als Shader auf die Bitmap anwenden möchte da ich einen Shader für die schnellste Methode halte und Zeit ein ganz wichtiger Faktor in der App ist.

Dieses bereitet mir aber als DirectX Neuling erhebliche Schwierigkeiten.

Erster Versuch
In den Beispieldateien für Sharpdx gibt es ein Projekt im dem ein Build In Effect offline auf eine Bitmap angewendet wird hier. Dies geht ja schon in meine Richtung, allerdings müsste ich einen Custom Effect einbinden. Ein solches Beispiel winde ich (leider) nur bei den Store Apps Beispielen hier.
Da ich aber eine reine Desktop App (ohne XNA) mache versuche ich den Custom Effect in die Desktop App zu integrieren.
Dazu habe ich die Ripple.cso, Ripple.hlsl, RippleEffect.cs und RippleProperties.cs in mein Projekt eingefügt und die *.cso und *.hlsl Datei auf kopieren gestellt.

Ich bekomme aber beim Erzeugen des Effects einen Fehler:> Fehlermeldung:

SharpDX.SharpDXException wurde nicht behandelt.
HResult=-2147023728
Message=HRESULT: [0x80070490], Module: [Unknown], ApiCode: [Unknown/Unknown], Message: not found.

Source=SharpDX
StackTrace:
bei SharpDX.Result.CheckError()
bei SharpDX.Direct2D1.DeviceContext.CreateEffect(Guid effectId, Effect effect)
bei SharpDX.Direct2D1.Effect..ctor(DeviceContext deviceContext, Guid effectId)
bei SharpDX.Direct2D1.Effect 1..ctor(DeviceContext deviceContext, Guid effectId)
bei SharpDX.Direct2D1.Effect 1..ctor(DeviceContext deviceContext)
bei OfflineImageProcessingApp.Program.Main() in c:\SharpDX\Samples\Desktop\Direct2D1\OfflineImageProcessingApp\Program.cs:Zeile 127.
bei System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
bei System.Threading.ThreadHelper.ThreadStart()
InnerException:

bei der Zeile wo der ripple effect mit new erzeugt werden soll.


            var x = new RippleEffect();
            var factory = new d2.Factory1();
            factory.RegisterEffect<RippleEffect>();
            Guid[] effect = factory.RegisteredEffects;

            SharpDX.Direct2D1.Effect _rippleEffect = new d2.Effect<RippleEffect>(d2dContext);
            
            _rippleEffect.SetInputEffect(0, bitmapSourceEffect);

Ich denke das es damit zusammenhängt das die Initialize() Methode vom Ripple Effekt nicht aufgerufen wird, aber warum, weiß ich nicht. Alle Versuche diese Manuell aufzurufen sind gescheitert.

Zweiter Versuch
In meinem zweiten Projekt habe ich versucht ein Viereck zu erzeugen un das mit der Bitmap zu texturieren und dann den Shader drauf anzuwenden. Hier bleibt aber der Bildschirm schwarz.


var form = new RenderForm("Test sample");

        // SwapChain description
        var desc = new SwapChainDescription()
                       {
                           BufferCount = 1,
                           ModeDescription= 
                               new ModeDescription(form.ClientSize.Width, form.ClientSize.Height,
                                                   new Rational(60, 1), Format.R8G8B8A8_UNorm),
                           IsWindowed = true,
                           OutputHandle = form.Handle,
                           SampleDescription = new SampleDescription(1, 0),
                           SwapEffect = SwapEffect.Discard,
                           Usage = Usage.RenderTargetOutput
                       };

        // Create Device and SwapChain
        Device device;
        SwapChain swapChain;
        Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.None, desc, out device, out swapChain);
        var context = device.ImmediateContext;

        // Ignore all windows events
        var factory = swapChain.GetParent<Factory>();
        factory.MakeWindowAssociation(form.Handle, WindowAssociationFlags.IgnoreAll);

        // New RenderTargetView from the backbuffer
        var backBuffer = Texture2D.FromSwapChain<Texture2D>(swapChain, 0);
        var renderView = new RenderTargetView(device, backBuffer);

        // Compile Vertex and Pixel shaders
        var vertexShaderByteCode = ShaderBytecode.CompileFromFile("MiniTri.fx", "VS", "vs_4_0", ShaderFlags.None, EffectFlags.None);
        var vertexShader = new VertexShader(device, vertexShaderByteCode);


        Texture2D chessboard = TextureLoader.CreateTex2DFromFile(device, @"D:\temp\Chess_Board.png");
        ShaderResourceView resourceView = new ShaderResourceView(device, chessboard);

        var sampler = new SamplerState(device, new SamplerStateDescription()
        {
            Filter = Filter.MinMagMipLinear,
            AddressU = TextureAddressMode.Wrap,
            AddressV = TextureAddressMode.Wrap,
            AddressW = TextureAddressMode.Wrap,
            BorderColor = Color.Black,
            ComparisonFunction = Comparison.Never,
            MaximumAnisotropy = 16,
            MipLodBias = 0,
            MinimumLod = -float.MaxValue,
            MaximumLod = float.MaxValue
        });

        var pixelShaderByteCode = ShaderBytecode.CompileFromFile("MiniTri.fx", "PS", "ps_4_0", ShaderFlags.None, EffectFlags.None);
        var pixelShader = new PixelShader(device, pixelShaderByteCode);


        var layout = new InputLayout(
            device,
            ShaderSignature.GetInputSignature(vertexShaderByteCode),
            new[]
                {
                    new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
                    new InputElement("textcoord", 0, Format.R32G32_Float, 12, 0)
                });


        var vertices = SharpDX.Direct3D11.Buffer.Create(device, BindFlags.VertexBuffer, new[]
                              {
                                  // 3D coordinates              UV Texture coordinates
                                  -1.0f, -1.0f, -1.0f, 1.0f,     0.0f, 1.0f, // Front
                                  -1.0f,  1.0f, -1.0f, 1.0f,     0.0f, 0.0f,
                                   1.0f,  1.0f, -1.0f, 1.0f,     1.0f, 0.0f,
                                  -1.0f, -1.0f, -1.0f, 1.0f,     0.0f, 1.0f,
                                   1.0f,  1.0f, -1.0f, 1.0f,     1.0f, 0.0f,
                                   1.0f, -1.0f, -1.0f, 1.0f,     1.0f, 1.0f,
                        });

        // Prepare All the stages
        context.InputAssembler.InputLayout = layout;
        context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
        context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertices, 32, 0));

        context.VertexShader.Set(vertexShader);
        context.Rasterizer.SetViewport(new Viewport(0, 0, form.ClientSize.Width, form.ClientSize.Height, 0.0f, 1.0f));

        context.PixelShader.SetShaderResource(0, resourceView);
        context.PixelShader.SetSampler(0, sampler);
        context.PixelShader.Set(pixelShader);

        context.OutputMerger.SetTargets(renderView);

        // Main loop
        RenderLoop.Run(form, () =>
                                  {
                                      context.ClearRenderTargetView(renderView, Color.Black);
                                      context.Draw(6, 0);
                                      swapChain.Present(0, PresentFlags.None);
                                  });

        // Release all resources
        vertexShaderByteCode.Dispose();
        vertexShader.Dispose();
        pixelShaderByteCode.Dispose();
        pixelShader.Dispose();
        vertices.Dispose();
        layout.Dispose();
        renderView.Dispose();
        backBuffer.Dispose();
        context.ClearState();
        context.Flush();
        device.Dispose();
        context.Dispose();
        swapChain.Dispose();
        factory.Dispose();

Der Shader:


Texture2D <float4> xTexture;
sampler TextureSampler;

struct VS_IN
{
    float4 pos : POSITION;
    float2 cords :textcoord;
};

struct PS_IN
{
float4 pos : SV_POSITION;
float2 cords :textcoord;
};

PS_IN VS( VS_IN input )
{
    PS_IN output = (PS_IN)0;    
    output.pos = input.pos;        
    output.cords =input.cords;  
    return output;
}

float4 PS( PS_IN input ) : SV_Target
{
float2 temp;
temp  = float2(input.cords[0],input.cords[1]);  
return   xTexture.Sample(TextureSampler,temp );
}

technique10 Render
{
pass P0
{
    SetGeometryShader( 0 );
    SetVertexShader( CompileShader( vs_4_0, VS() ) );
    SetPixelShader( CompileShader( ps_4_0, PS() ) );
}
}

Ich gebe zwar nicht schnell auf aber langsam gehen mir die Optionen aus. Ich wäre für einwenig Hilde sehr dankbar!

189 Beiträge seit 2014
vor 8 Jahren

Auch wenn ich dir leider bei DirectX nicht helfen kann, ein kleiner Hinweis.
Ich denke, dass es den wissenden Helfern helfen kann, wenn du konkrete Fragen stellst. (Siehe auch [Hinweis] Wie poste ich richtig? Punkt 5) 😉

Edit: Hinweis No. 2: Verwende usings um gezielt Objekte zu erstellen und zu zerstören.

G
gagagu Themenstarter:in
5 Beiträge seit 2015
vor 8 Jahren

Auch wenn ich dir leider bei DirectX nicht helfen kann, ein kleiner Hinweis.
Ich denke, dass es den wissenden Helfern helfen kann, wenn du konkrete Fragen stellst. (Siehe auch
>
Punkt 5) 😉

Hi, sry aber ich dachte das wäre aus meinem Post klar ersichtlich. Ich möchte gerne einen Shader auf eine Bitmap anwenden (im Hindergrund, ohne Anzeige). Ich bekomme es aber nicht hin. Ich habe mehrere Wege versucht und die Probleme mit den zwei vielversprechensten Wege oben beschrieben.

Wenn mir jemand eine Möglichkeit aufzeigen kann wie ich ich ein Barrel Dirstortion Effekt auf eine Bitmap anwenden kann der fast genauso schnell ist wie ein Shader wäre ich da auch brennend dran Interessiert.

Mehr zum Hintergrund:
Ich habe einen Server geschrieben der die Bildschirmausgabe von Spielen (im Fenstermodus) als Einzelbilder aufzeichnet und per Netzwerk an ein iPhone sendet. Dieses wird dann ich eine VR Brille (z.b. Google Cardboard) gesteckt und kann dann zum Spielen verwendet werden. Gleichzeitig habe ich ein Opentrack (Head Tracking Software) geschrieben um die Kopfbewegungen an das Spiel zu senden. Das funtkioniert soweit sehr gut.
Um nun den VR Effekt zu verbessern sollte man noch eine sog. Linsenkorrektur einfügen. Diese verzerrt das Bild einwenig, aber durch die Linsen sieht alles wieder korrekt aus und man kann dadurch ein dem Screen Door Effekt entgegenwirken. Diese Linsenkorrektur ist nichts anderes als ein Barrel Distortion (ähnlich Fischaugeneffekt) Effekt. Diesen möchte ich auf das Bild anwenden. Dabei darf vom Aufnehmen des Bildes bis zur Übertragung aufs Handy so wenig Zeit wie möglich vergehen damit dem User nicht schlecht wird. Deswegen ist es so wichtig das ich den schnellsten Weg finden den Effekt zu berechnen den es gibt und das scheint mir ein Shader zu sein.

Danke und Gruß

742 Beiträge seit 2005
vor 8 Jahren

Das Stichwort ist: Render to texture oder RenderTarget

z.B. http://sharpdx.org/forum/5-api-usage/107-render-target-texture

Du erstellst ein RenderTarget mit der Größe deines Bilds, darin zeichnest du ein Rechteck mit deiner Textur, welches das ganze Bild einnimmt und wendest den Shader an. Das RenderTarget kannst du dann abspeichern.

Die selbe Methode wird auch bei Reflexionen und Schatten und PostProcessing angewendet.

G
gagagu Themenstarter:in
5 Beiträge seit 2015
vor 8 Jahren

Hallo,
danke für Deine Hilfe. Es ist sehr schwer als DirectX Neuling in dieses Thema rein zu kommen. Es gibt zwar viele Dokumentationen, diese beziehen sich aber meistens auf C++ oder XNA. Prinzipiell verstehe ich die Thematik auch (glaube ich) aber mit der Codeumsetzung habe ich Schwierigkeiten.

Ich habe jetzt ein schönes Beispiel gefunden das mir eine Bitmap in einem fenster darstellt und einen Shader drauf rendert (siehe Anhang).... juhu...

Was muss ich den machen damit er das im Hintergrund rendert und ich das al Bild auslesen kann?

5.658 Beiträge seit 2006
vor 8 Jahren

Die Antwort hat dir doch malignate schon gegeben. 🤔

Christian

Weeks of programming can save you hours of planning

G
gagagu Themenstarter:in
5 Beiträge seit 2015
vor 8 Jahren

Hi, danke für die Hilfe. Die Infos haben mich auf jeden Fall soweit gebracht das ich ein Tutorial gefunden habe das auf mein Projekt passt. Ich konnte erfolgreich meinen Shader programmieren. Ich werde nun versuchen das Render Target zu ändern und alles zu kürzen.

Vielen lieben Dank!

Für alle späteren Leser und Interessenten: bei Erfolg wird der Code auf github verfügbar sein unter https://github.com/gagagu

Gruss

G
gagagu Themenstarter:in
5 Beiträge seit 2015
vor 8 Jahren

Hallo, ich wollte mich nochmal melden um den Stand der Dinge zu posten.

Ich habe nun eine WPF Dll geschrieben und dort eine Methode entworfen die mit WPF Mitteln einen PixelShader auf die Bitmap anwendet (Stichwort: RenderTargetBitmap). Das funktioniert (fast) wie gewünscht. Derzeit versuche ich noch eine Art Antialiasing auf das Bild anzuwenden. da es einwenig pixelig wirkt. Das kann am Shader oder auch an der Auflösung liegen.

Gruß