Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

24.01.2019, 10:17

C# HLSL - Texel hat mehrere Farben

Hallo zusammen,

ich habe ein 10x10 Image - normalerweise kommt dieses von einer Kamera (1024x1024), verwende jedoch zu Testzwecken einen kleinen Teilausschnitt dessen, welchen ich separat in ein .png abgespeichert habe.

Das Pixelformat liegt im sogenannten "Bayer GB 8" vor (bekomme daher erstmal nur Grauwerte), weshalb ich den Pixelshader anwenden möchte, um daraus RGBA zur Anzeige zu bringen.
Allerdings haben die einzelnen Texel am Ende einen Farbverlauf :hmm: , keine Ahnung wie man dieses Phänomen nennt. Hab auch einen Screenshot davon gemacht. Zeile 1 zeigt, wie es tatsächlich aussehen soll.

Wie bekomme ich diesen Farbverlauf (oder was zur Hölle das auch ist) raus?
»Fexis« hat folgendes Bild angehängt:
  • result.png

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

24.01.2019, 10:21

Willkommen im Forum!
Wie sieht denn dein Shader aus? Und wie sieht die Textur aus?

3

24.01.2019, 10:48

Danke, der Shader sieht wie folgt aus:

HLSL-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
sampler2D implicitInput : register(s0);

float4 GetNeighborPixel(float2 uv, float2 pixelOffset)
{
    float2 PixelSize = float2(10.0, 10.0);
    float2 normalizedPixel = 1.0 / PixelSize;
    return tex2D(implicitInput, uv + normalizedPixel * pixelOffset);
}

float GetIntensity(float4 pixel)
{
    float intensity = (pixel.r + pixel.g + pixel.b) / 3.0;
    return intensity;
}

float4 main(float2 uv : TEXCOORD) : COLOR
{
    float2 PixelSize = float2(10.0, 10.0);
    float2 normalizedPixel = 1.0 / PixelSize;
    int2 position = uv / normalizedPixel;
    
    float3x3 pixelMatrix;
    pixelMatrix._11 = GetIntensity(GetNeighborPixel(uv, float2(-1.0,-1.0)));
    pixelMatrix._21 = GetIntensity(GetNeighborPixel(uv, float2(-1.0, 0.0)));
    pixelMatrix._31 = GetIntensity(GetNeighborPixel(uv, float2(-1.0, 1.0)));
    
    pixelMatrix._12 = GetIntensity(GetNeighborPixel(uv, float2( 0.0,-1.0)));
    pixelMatrix._22 = GetIntensity(GetNeighborPixel(uv, float2( 0.0, 0.0)));
    pixelMatrix._32 = GetIntensity(GetNeighborPixel(uv, float2( 0.0, 1.0)));
    
    pixelMatrix._13 = GetIntensity(GetNeighborPixel(uv, float2( 1.0,-1.0)));
    pixelMatrix._23 = GetIntensity(GetNeighborPixel(uv, float2( 1.0, 0.0)));
    pixelMatrix._33 = GetIntensity(GetNeighborPixel(uv, float2( 1.0, 1.0)));
    
    float4 result = pixelMatrix._22;
    
    if (((int)position.x % 2) == 1 && ((int)position.y % 2) == 0)
    {
        // Position: Blue
        result.r = (pixelMatrix._11 + pixelMatrix._13 + pixelMatrix._33 + pixelMatrix._31) / 4.0;
        result.g = (pixelMatrix._21 + pixelMatrix._12 + pixelMatrix._23 + pixelMatrix._32) / 4.0;
        result.b = pixelMatrix._22;
    }
    else if (((int)position.x % 2) == 0 && ((int)position.y % 2) == 1)
    {
        // Position: Red
        result.r = pixelMatrix._22;
        result.g = (pixelMatrix._21 + pixelMatrix._12 + pixelMatrix._23 + pixelMatrix._32) / 4.0;
        result.b = (pixelMatrix._11 + pixelMatrix._13 + pixelMatrix._33 + pixelMatrix._31) / 4.0;
    }
    else if (((int)position.x % 2) == 0 && ((int)position.y % 2) == 0)
    {
        // Position: Green
        result.r = (pixelMatrix._12 + pixelMatrix._32) / 2.0;
        result.g = (pixelMatrix._11 + pixelMatrix._13 + pixelMatrix._33 + pixelMatrix._31) / 4.0;
        result.b = (pixelMatrix._21 + pixelMatrix._23) / 2.0;
    }
    else if (((int)position.x % 2) == 1 && ((int)position.y % 2) == 1)
    {
        // Position: Green
        result.r = (pixelMatrix._21 + pixelMatrix._23) / 2.0;
        result.g = (pixelMatrix._11 + pixelMatrix._13 + pixelMatrix._33 + pixelMatrix._31) / 4.0;
        result.b = (pixelMatrix._12 + pixelMatrix._32) / 2.0;
    }
    
    if (position.y == 0)
    {      
        if(position.x == 0)         { return float4(0.63, 0.79, 0.20, 1); }
        else if(position.x == 1)    { return float4(0.62, 0.80, 0.20, 1);   }
        else if(position.x == 2)    { return float4(0.62, 0.82, 0.21, 1);   }
        else if(position.x == 3)    { return float4(0.62, 0.83, 0.21, 1);   }
        else if(position.x == 4)    { return float4(0.62, 0.80, 0.20, 1);   }
        else if(position.x == 5)    { return float4(0.62, 0.82, 0.21, 1);   }
        else if(position.x == 6)    { return float4(0.61, 0.79, 0.21, 1);   }
        else if(position.x == 7)    { return float4(0.61, 0.78, 0.21, 1);   }
        else if(position.x == 8)    { return float4(0.63, 0.79, 0.21, 1);   }
        else if(position.x == 9)    { return float4(0.63, 0.80, 0.20, 1);   }
       
    }
    
    return float4(result.rgb, 1);
}


Die Pixeldaten kommen in C# als byte[], wobei Alpha immer 255 ist. Das byte[] landet dann im WriteableBitmap, und der Shader wird anschließend darauf angewendet. Im Shader allerdings hat Alpha irgendetwas, nur nicht 1, weshalb ich diesen dann auch noch manuell mit 1 belegen muss. Warum ist das so?
»Fexis« hat folgendes Bild angehängt:
  • grabResult_rgba_10x10.png

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

4

24.01.2019, 10:57

Das ist mir jetzt ehrlich gesagt zu kompliziert, um da einen Fehler zu suchen, darum die Frage: Warum machst du das im Shader, also warum konvertierst du die Textur nicht einfach vorher in ein normales RGB-Format?

5

24.01.2019, 11:24

Ich habe massive Performance-Einbrüche, wenn ich spätestens mit einer 4K-Kamera Bilder unter C# anzeigen möchte (loop). Die Konvertierung unter C# von Grau zu RGBA dauert dann mal gute 50ms, was die FPS um fast 60% reduziert. Der Grundgedanke ist daher, ein Bild mit den Rohdaten zu verwenden, woraufhin der Shader dann diese Farblich darstellt.

Um aus dem Bild dann Farben zu zaubern, müssen die Nachbarpixel mit einbezogen werden. Je nach Position werden die RGB-Werte anders interpretiert.

Das byte[] sieht für die ersten 10x5 Pixel wie folgt aus: (Grau-Werte!!)
Ich hab jetzt die entsprechenden Positionen eingefärbt, so wie der Shader anschließend die Farben berechnen muss.
[241][074][250][068][251][068][242][071][244][070]
[186][249][188][254][185][246][185][243][189][250]
[240][070][247][071][245][070][242][071][246][066]
[188][247][189][247][186][250][185][249][188][247]
[251][068][243][072][245][071][242][071][242][069]

Mal angenommen wir möchten wissen, welche RGB-Werte Pixel 2/2 hat:
Dieser hat den Grauwert [249].
R = ([186] + [188] / 2.0 = 187
G = ([241] + [250] + [247] + [240]) / 4.0 = 244.5
B = ([74] + [70]) / 2.0 = 72

Dies entspricht in HLSL einen float4(0.73, 0.96, 0.28, 1) für den Pixel 2/2;
Würde das Ergebnis jetzt im Shader stimmen, hätte ich ein schönes RGB-Bild.. gut, es gibt auch noch andere Verfahren wie man das jetzt berechnet, aber für den Anfang macht es der Algorithmus auch :D
Wie ganz oben im Screenshot zu sehen, stimmt das Ergebnis jetzt aber nicht wirklich mit den Werten überein. Mach ich hier irgendwas im Shader falsch?

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Fexis« (24.01.2019, 14:19)


Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

6

24.01.2019, 19:14

Wie sehen deine SamplerStates aus? Point Clamping Sampling aktiviert?

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Sylence« (24.01.2019, 20:00)


David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

7

24.01.2019, 19:38

Point Sampling meinst du?

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

8

24.01.2019, 19:59

Äh ja. Natürlich :crazy:

9

28.01.2019, 12:56

Hab ich auch schon versucht. Der Effekt bleibt jedoch aus, liegt aber evtl. an der WPF-Applikation.
Ich habe jetzt das Image inkl. den Shader-Effect in ein WriteableBitmap gerendert, in ein byte-Array kopiert und festgestellt, dass ich nach wie vor Grauwerte erhalte ?( :cursing: . Errechne ich den Nachbarpixel falsch (...kann ja auch nicht sein :dash: )? Gibt es denn keine Möglichkeit einen PixelShader zu debuggen?
Hab mal das Original-Image-File hinzugefügt.

Um die richtigen Pixeldaten zu bekommen, musste ich die PixelShader-Version auf PS_2_0 ändern.
Wenn ich das ganze jetzt in ein Rectangle rendere und ausgebe, ist alles so, wie gewünscht...

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
WriteableBitmap ImageStream = img;
Rectangle r = new Rectangle();
r.Fill = new ImageBrush(ImageStream);
r.Effect = new SDK.Media.Effect.DebayeringEffect()
{
    PixelSize = new Size(ImageStream.Width, ImageStream.Height)
};
Size sz = new Size(ImageStream.PixelWidth, ImageStream.PixelHeight);
r.Measure(sz);
r.Arrange(new Rect(sz));

RenderTargetBitmap rtb = new RenderTargetBitmap(ImageStream.PixelWidth, ImageStream.PixelHeight, ImageStream.DpiX, ImageStream.DpiY, PixelFormats.Pbgra32);
rtb.Render(r);

byte[] pixelData = new byte[ImageStream.PixelWidth * ImageStream.PixelHeight * 4];
rtb.CopyPixels(pixelData, ImageStream.PixelWidth * 4, 0);

ImageStream.Lock();
ImageStream.WritePixels(new Int32Rect(0, 0, ImageStream.PixelWidth, ImageStream.PixelHeight), pixelData, ImageStream.BackBufferStride, 0);
ImageStream.AddDirtyRect(new Int32Rect(0, 0, ImageStream.PixelWidth, ImageStream.PixelHeight));
ImageStream.Unlock();


Funktioniert jedoch nicht, wenn ich ohne diesen Rendervorgang arbeite. Desweiteren dauert das Rendering dann ca. 200ms, zu lange..

ich habe auch schon versucht die RenderOptions in C# vom Image-Control zu ändern. Nur wird das Ergebnis auch nicht besser. Ebenso der SamplingMode innerhalb vom DependencyProperty

Wenn ich im Shader selbst die sampler_state ändere passiert rein gar nichts

HLSL-Quelltext

1
2
3
4
5
6
sampler2D implicitInput : register(s0) = sampler_state
{
    MipFilter = POINT;
    MagFilter = POINT;
    MinFilter = POINT;
};


Ist es sinnvoll auf SharpDX zu setzen oder habe ich dort die gleichen Probleme?
»Fexis« hat folgendes Bild angehängt:
  • grabResult_raw.png

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Fexis« (28.01.2019, 15:18)


10

29.01.2019, 23:14

Versuch mal Texture.Load() mit Integer-Koordinaten. Die Fehler kommen vermutlich durch Rundungsfehler zustande.

https://docs.microsoft.com/en-us/windows…cs-hlsl-to-load
Cube Universe
Entdecke fremde Welten auf deiner epischen Reise durchs Universum.

Werbeanzeige