Spektrum-Analyzing-Monitor: Qual der Wahl
-
Ok ich hatte etwas falsch verstanden was ihr wollt, aber nachdem ich mir euren Testscreenshot angeschaut hab isses mir klar denk ich. Ihr wollt also nicht sowas sondern sowas.
Nun, natürlich könnte man die FFT direkt auf der GPU rechnen, was performancemäßig vielleicht auch interessant sein könnte, aber ich nehme mal an ihr wollt das aus bestimmten Gründen auf der CPU lassen. D.h. ihr braucht einen Weg einfach immer nur unten in das Bild eine neue Zeile zu bekommen.
Für eine effiziente Implementierung in Direct3D9 würde ich folgendes vorschlagen: Baut euch eine Art Ringbuffer. D.h. das ganze Bild kommt in eine Textur, gerendert wird indem diese Textur auf ein Quad gespannt wird das über den ganzen Viewport geht.
Ihr braucht dazu zwei Texturen, eine im SystemMemory Pool und eine im Default Pool. Die sysmem Textur ist jener Buffer in den die CPU schreibt. Wenn eine neue Zeile aufgebaut wird, wird immer die entsprechende Zeile der sysmem Textur gelocked und die Werte reingeschrieben. Ist die Zeile fertig so wird die Textur kurz geunlocked und per UpdateTexture() die Default Pool Textur geupdated. Nach dem UpdateTexture() kann die CPU gleich die nächste Zeile angehen während die Grafikkarte unter Verwendung der Default Pool Textur (die liegt im VRAM der Grafikkarte) das Bild rendert. Der Trick ist nun dass, wenn ihr in der letzten Zeile angelangt seid, ihr einfach wieder in der ersten Zeile anfangen könnt (damit überschreibt ihr immer die ältesten Werte). Um die neue Zeile immer unten im Bild zu halten müsst ihr einfach nur die Texturkoordinaten so wählen dass der untere Rand des Quad die Texturkoordinaten der aktuellen Zeile hat und die v-Koordinate des oberen Randes entsprechend die des unteren - 1 ist. Die Grafikhardware macht automatisch die notwendige Modulo Operation sodass die beiden Enden der Textur "verklebt" werden.
Das Verfahren erlaubt es CPU und GPU weitgehend autonom zu arbeiten (die Framerate ist relativ entkoppelt von der Geschwindigkeit mit der die FFT berechnet wird, das UpdateTexture() ist praktisch der einzige Synchronisationspunkt) und kommt ohne unnötiges kopieren und mit minimalem Datenstransfer zwischen CPU und GPU aus. Man könnte den Datentransfer und die Last auf der CPU Seite sogar noch weiter verringern indem man z.B. in der Textur gar keine Farbdaten sondern nur direkt die FFT Werte ablegt und dann die Färbung in einem PixelShader direkt beim Rendern von der GPU berechnen lässt. Von einer einfachen Lookup Table bis hin zu irgendwelchen komplexeren Berechnungen, Animationen, etc. ist da alles möglich ohne dass die CPU auch nur einen Takt dafür verschwendet.Das klingt jetzt am Anfang alles vielleicht ziemlich kompliziert aber das ist es in Wirklichkeit nicht. Wenn ihr direkt in C# mit Direct3D arbeiten wollt empfehle ich SlimDX.
-
Hi Dot
Danke vielmals für die schnelle und kompetente Antwort.
Hab mich gleich reingestürzt und bis Feierabend ^^'' was gemacht.
Kannst du mir mit dem Quad weiterhelfen?
Das hab ich schon:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; using System.Diagnostics; using System.Threading; namespace dx { public partial class Form1 : Form { private Device device; private Texture cpuTexture; private Texture gpuTexture; private Size texSize; private CustomVertex.TransformedTextured[] vertices; private Rectangle drawRectangle; public Form1() { InitializeComponent(); texSize = new Size(1024, 1024); } public void InitGraphics() { drawRectangle = new Rectangle(0, texSize.Height - 1, texSize.Width, 1); PresentParameters present_params = new PresentParameters(); present_params.Windowed = true; present_params.BackBufferFormat = Format.A8R8G8B8; present_params.SwapEffect = SwapEffect.Discard; present_params.BackBufferWidth = texSize.Width; present_params.BackBufferHeight = texSize.Height; present_params.BackBufferCount = 1; device = new Device(0, DeviceType.Hardware, this, CreateFlags.HardwareVertexProcessing, present_params); Viewport p = device.Viewport; cpuTexture = new Texture(device, texSize.Width, texSize.Height, 1, 0, Format.A8R8G8B8, Pool.SystemMemory); gpuTexture = new Texture(device, texSize.Width, texSize.Height, 1, 0, Format.A8R8G8B8, Pool.Default); vertices = new CustomVertex.TransformedTextured[4]; vertices[0] = new CustomVertex.TransformedTextured(0, 0, 0, 0, 0, 0); vertices[1] = new CustomVertex.TransformedTextured(0, texSize.Height - 1, 0, 0, 0, 0); vertices[2] = new CustomVertex.TransformedTextured(texSize.Width - 1, texSize.Height - 1, 0, 0, 0, 0); vertices[3] = new CustomVertex.TransformedTextured(texSize.Width - 1, 0, 0, 0, 0, 0); //???? Wie die Textur auf das Quad mappen? } private void renderToCPUTex(byte[] newdata) { // falls die daten, die wir kriegen müll sind if (newdata.Length != texSize.Width) return; // wenn wir oben rausgeflogen sind, d.h nicht mehr auf der textur, fange unten wieder an. if (drawRectangle.Y < 0) { drawRectangle.Offset(0, texSize.Height); } // zeile locken uint[] data = (uint[])cpuTexture.LockRectangle(typeof(uint), 1, drawRectangle, LockFlags.None); // bemalen for (int i = 0; i < texSize.Width; i++) { data[i] = (uint)Color.FromArgb(newdata[i], newdata[i], newdata[i]).ToArgb(); } // unlocken cpuTexture.UnlockRectangle(1); // in andere textur kopieren device.UpdateTexture(cpuTexture, gpuTexture); // für den nächsten Durchlauf eins nach oben drawRectangle.Offset(0,-1); } protected override void OnPaint(PaintEventArgs e) { device.Clear(ClearFlags.Target, System.Drawing.Color.FromArgb(0, 0, 255).ToArgb(), 1.0f, 0); device.BeginScene(); //???? Quad hier zeichnen? device.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, vertices); device.EndScene(); device.Present(); Invalidate(); } protected override void OnPaintBackground(PaintEventArgs e) { } } }
-
Das schaut ja schon gar nicht mal so schlecht aus, Kompliment. Nachdem ihr gesagt habt keine Erfahrung mit Direct3D zu haben hätt ich nicht erwartet dass ihr gleich so genau umsetzen würdet was ich oben beschrieben hab. Ich würde dir nur wirklich empfehlen SlimDX zu benutzen und nicht Managed DirectX, letzteres ist hoffnungslos veraltet.
Zum Updaten der Textur willst du Level 0 locken und nicht Level 1, deine Textur hat (korrekterweise) nur einen Level.
Wie du das Quad zeichnest ist prinzipiell egal (für die Performance fällt das in dem Fall wohl praktisch nicht ins Gewicht). Wenn du transformierte Vertices verwendest willst du allerdings ein rhw von 1 haben. Um die Textur draufzumappen musst du eben die Texturkoordinaten entsprechend wählen:
vertices[0] = new CustomVertex.TransformedTextured(p.X , p.Y + p.Height - 1, 0.0f, 1.0f, 0.0f, 1.0f); vertices[1] = new CustomVertex.TransformedTextured(p.X , p.Y , 0.0f, 1.0f, 0.0f, 0.0f); vertices[2] = new CustomVertex.TransformedTextured(p.X + p.Width - 1, p.Y + p.Height - 1, 0.0f, 1.0f, 1.0f, 1.0f); vertices[3] = new CustomVertex.TransformedTextured(p.X + p.Width - 1, p.Y , 0.0f, 1.0f, 1.0f, 0.0f); // Und zum Rendern dann device.Clear(ClearFlags.Target, System.Drawing.Color.FromArgb(0, 0, 255).ToArgb(), 1.0f, 0); device.BeginScene(); device.VertexFormat = CustomVertex.TransformedTextured.Format; device.SetTexture(0, gpuTexture); device.SetSamplerState(0, SamplerStageStates.MinFilter, TextureFilter.Linear); device.SetSamplerState(0, SamplerStageStates.MagFilter, TextureFilter.Linear); device.DrawUserPrimitives(PrimitiveType.TriangleStrip, 2, vertices); device.EndScene(); device.Present();
Beachte dass die Koordinaten des Quad dem aktuellen Viewport entsprechen. Wenn der Viewport andere Abmessungen hat als die Textur dann wird die Textur automatisch gestreckt/gestaucht, die Hardware kann (wie in meinem Code da oben) z.B. auch bilineares Filtering anwenden sodass du das was ich denke dass du vorhin mit "Interpolation" gemeint hast automatisch und praktisch ohne Performanceeinbußen bekommst. Bei der Größe des BackBuffer würde ich beachten dass das Bild im Fenstermodus in das Fenster hinengestreckt wird (falls das ein Problem ist) und der Clientbereich des Fensters normal ein wenig kleiner als das Fenster selbst ist (Titelzeile, Border, etc.).
Damit solltest du jetzt erstmal einfach den Updatevorgang durch das Bild laufen sehen.
Es sollte außerdem reichen das Fenster nur neu zu zeichnen wenn sich was geändert hat (also das Invalidate() aus dem OnPaint() ins renderToCPUTex() geben) um nicht sinnlos CPU Cycles zu verbraten.
Als kleiner Debug Tip vielleicht auch der Hinweis dass dem DirectX SDK ein Tool beiliegt das sich DirectX Control Panel nennt (dxcpl.exe). Dort lässt sich für Direct3D 9 zwischen der Debug und Retail Runtime umschalten. Es empfielt sich die Debug Runtime zu aktivieren mit einem Warning Level im oberen Bereich. Direct3D schreibt dann sehr wertvolle Informationen in den Output des Debuggers (kommt in Visual Studio ins Output Window rein).
-
Danke für das Kompliment
Bin jetzt auf SlimDX umgestiegen, hab aber noch ein Problem.
Leider existiert hier die Klasse CustomVertex nicht und struct TransformedTextured gibts schon gar nicht.
Hab mal versucht sie nachzubilden, aber bin nicht sicher ob das stimmt.
Gibt auf jeden Fall keine Fehler beim Ausführen.Hier mal der Code für CustomVertex:
using System; using System.Collections.Generic; using System.Text; using SlimDX; using SlimDX.Direct3D9; using System.Runtime.InteropServices; namespace dx { public class CustomVertex { public struct TransformedTextured { public const VertexFormat Format = VertexFormat.PositionRhw | VertexFormat.Texture1; public float Rhw; public float Tu; public float Tv; public float X; public float Y; public float Z; public TransformedTextured(float xvalue, float yvalue, float zvalue, float rhwvalue, float u, float v) { X = xvalue; Y = yvalue; Z = zvalue; Rhw = rhwvalue; Tu = u; Tv = v; } public Vector4 Position { get { return new Vector4(X, Y, Z, Rhw); } set { X = value.X; Y = value.Y; Z = value.Z; Rhw = value.W; } } public static int StrideSize { get { return Marshal.SizeOf(typeof(TransformedTextured)); } } } } }
Hier noch der neue Code
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.Threading; using SlimDX; using SlimDX.Direct3D9; namespace dx { public partial class Form1 : Form { private Device device; private Texture cpuTexture; private Texture gpuTexture; private Size texSize; private CustomVertex.TransformedTextured[] vertices; private Rectangle drawRectangle; private Thread thread; private bool threadRunning; public Form1() { InitializeComponent(); texSize = new Size(1024, 1024); FormClosing += new FormClosingEventHandler(Form1_FormClosing); } void Form1_FormClosing(object sender, FormClosingEventArgs e) { threadRunning = false; } public void InitGraphics() { drawRectangle = new Rectangle(0, texSize.Height - 1, texSize.Width, 1); PresentParameters present_params = new PresentParameters(); present_params.Windowed = true; present_params.BackBufferFormat = Format.A8R8G8B8; present_params.SwapEffect = SwapEffect.Discard; present_params.BackBufferWidth = texSize.Width; present_params.BackBufferHeight = texSize.Height; present_params.BackBufferCount = 1; Direct3D d3d = new Direct3D(); device = new Device(d3d, 0, DeviceType.Hardware, this.Handle, CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded, present_params); Viewport p = device.Viewport; cpuTexture = new Texture(device, texSize.Width, texSize.Height, 1, 0, Format.A8R8G8B8, Pool.SystemMemory); gpuTexture = new Texture(device, texSize.Width, texSize.Height, 1, 0, Format.A8R8G8B8, Pool.Default); vertices = new CustomVertex.TransformedTextured[4]; vertices[0] = new CustomVertex.TransformedTextured(p.X, p.Y + p.Height - 1, 0.0f, 1.0f, 0.0f, 1.0f); vertices[1] = new CustomVertex.TransformedTextured(p.X, p.Y, 0.0f, 1.0f, 0.0f, 0.0f); vertices[2] = new CustomVertex.TransformedTextured(p.X + p.Width - 1, p.Y + p.Height - 1, 0.0f, 1.0f, 1.0f, 1.0f); vertices[3] = new CustomVertex.TransformedTextured(p.X + p.Width - 1, p.Y, 0.0f, 1.0f, 1.0f, 0.0f); thread = new Thread(new ThreadStart(feedGarbage)); threadRunning = true; thread.Start(); } private void feedGarbage() { byte[] data = new byte[texSize.Width]; Random rand = new Random(); while (threadRunning) { rand.NextBytes(data); renderToCPUTex(data); } } private void renderToCPUTex(byte[] newdata) { // falls die daten, die wir kriegen müll sind if (newdata.Length != texSize.Width) return; // wenn wir oben rausgeflogen sind, d.h nicht mehr auf der textur, fange unten wieder an. if (drawRectangle.Y < 0) { drawRectangle.Offset(0, texSize.Height); } // zeile locken DataRectangle data = cpuTexture.LockRectangle(0, drawRectangle, LockFlags.None); // bemalen for (int i = 0; i < texSize.Width; i++) { data.Data.Write<uint>((uint)Color.FromArgb(newdata[i], newdata[i], newdata[i]).ToArgb()); } // unlocken cpuTexture.UnlockRectangle(0); // in andere textur kopieren device.UpdateTexture(cpuTexture, gpuTexture); // für den nächsten Durchlauf eins nach oben drawRectangle.Offset(0,-1); Invalidate(); } protected override void OnPaint(PaintEventArgs e) { device.Clear(ClearFlags.Target, System.Drawing.Color.FromArgb(0, 0, 255).ToArgb(), 1.0f, 0); device.BeginScene(); device.VertexFormat = CustomVertex.TransformedTextured.Format; device.SetTexture(0, gpuTexture); device.SetSamplerState(0, SamplerState.MinFilter, TextureFilter.Linear); device.SetSamplerState(0, SamplerState.MagFilter, TextureFilter.Linear); device.DrawUserPrimitives(PrimitiveType.TriangleStrip, 2, vertices); device.EndScene(); device.Present(); } protected override void OnPaintBackground(PaintEventArgs e) { } } }
Ich seh jetzt ein blaues Fenster, ohne das sich was bewegt.
Auf der Console wiederholt sich folgende Meldung:
Direct3D9: (WARN) :Ignoring redundant SetSamplerState. Sampler: 0, State: 6
Direct3D9: (WARN) :Ignoring redundant SetSamplerState. Sampler: 0, State: 5
Danke für die Hilfe
-
Die Reihenfolge deiner Member ist verkehrt, sollte besser so aussehen:
[StructLayout(LayoutKind.Sequential)] struct TransformedTextured { public float X; public float Y; public float Z; public float Rhw; public float Tu; public float Tv; public TransformedTextured(float X, float Y, float Z, float Rhw, float Tu, float Tv) { this.X = X; this.Y = Y; this.Z = Z; this.Rhw = Rhw; this.Tu = Tu; this.Tv = Tv; } ... }
Ansonsten schaut das auf den ersten Blick mal ganz gut aus. Die Warnings da kannst du in dem Fall ignorieren, die sagen nur dass du den SamplerState nicht immer setzen müsstest weil er sich inzwischen nicht geändert hat. Es ist außerdem natürlich nicht notwendig das Vertex struct in eine CustomVertex Klasse zu packen, aber ich denke dass ist dir eh klar, das kannst du natürlich hinschreiben wo auch immer du es haben willst.
Was mir sonst noch aufgefallen ist: Ins Form_Closing event würde ich noch ein thread.Join() reinpacken nachdem der bool auf false gesetzt wurde. Und du könntest dort gleich auch alle Direct3D Objekte Disposen. Und in die Schleife in deinem Thread würd ich ein Thread.Sleep() oder zumindest ein Thread.Yield() machen damit der Thread nicht komplett durchdreht
(wenn du 40fps willst hast du immerhin 25ms pro Durchlauf). Das initialisieren von Direct3D kannst du im Prinzip automatisch im Form_Load Ereignis machen.
-
JUHUUUUUUUU es funktioniert!
CPU-Zeit: Nur 40%Ok, jetzt nur noch das Scrolling...
Wenn ich das richtig verstehe muss ich jetzt bei den Vertices die V-Koordinaten für die unteren beiden Ecken und die oberen beiden Ecken setzen.
Das ganze soll nach unten scrollen...Das funktioniert schon mal nicht:
vertices[1].Tv = drawRectangle.Y; vertices[3].Tv = drawRectangle.Y; vertices[0].Tv = drawRectangle.Y - 1; vertices[2].Tv = drawRectangle.Y - 1;
Wie lautet die richtige Zuweisung und wo soll ich sie am besten einfügen?
Gruss Nitroxleecher
-
Wunderbar
Nitroxleecher schrieb:
Wenn ich das richtig verstehe muss ich jetzt bei den Vertices die V-Koordinaten für die unteren beiden Ecken und die oberen beiden Ecken setzen.
Richtig. Allerdings sind Texturkoordinaten keine Pixelkoordinaten. Versuchs mal so:
float v = (float)drawRectangle.Y / (float)(texSize.Height - 1); vertices[1].Tv = v; vertices[3].Tv = v; vertices[0].Tv = v + 1.0f; vertices[2].Tv = v + 1.0f;
Ich würd das einfach direkt im OnPaint() vor dem Rendern machen.
-
Es funktioniert! Danke!
Jetzt noch zwei Sachen:
1. Das ganze ruckelt in regelmässigen Abständen und von Auge sind komische Streifen sichtbar. Doublebuffering?
2. Und wie benutzt man PixelShading?
Wenn ich das richtig verstehe definiert man in der Grafikkarte Regeln für Wertebereiche und gibt dann nur noch Werte in die Textur.
z.Bsp: Werte unter 128 sind blau, Werte darüber sind rot.
Danach gebe ich Werte von 0-255 in die Textur und die GraKa wandelt diese in ein blaurotes Muster um.Hab mal das ganze Projekt hochgeladen.
http://birdchicken.dyndns.org/dx.rar
Hier der Haupt-Sourcecode
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.Threading; using SlimDX; using SlimDX.Direct3D9; namespace dx { public partial class Form1 : Form { private Device device; private Texture cpuTexture; private Texture gpuTexture; private Size texSize; private CustomVertex.TransformedTextured[] vertices; private Rectangle drawRectangle; private Direct3D d3d; private float v; private UInt32[] colorTable; private byte[] datafeed; private AverageFilter filter; private System.Threading.Timer timer; private bool isRunning; public Form1() { InitializeComponent(); texSize = new Size(1024, 1024); FormClosing += new FormClosingEventHandler(Form1_FormClosing); Load += new EventHandler(Form1_Load); } void Form1_Load(object sender, EventArgs e) { InitGraphics(); } void Form1_FormClosing(object sender, FormClosingEventArgs e) { isRunning = false; if (timer != null) { timer.Change(Timeout.Infinite, Timeout.Infinite); timer.Dispose(); } cpuTexture.Dispose(); gpuTexture.Dispose(); device.Dispose(); d3d.Dispose(); } private void InitGraphics() { drawRectangle = new Rectangle(0, texSize.Height - 1, texSize.Width, 1); PresentParameters present_params = new PresentParameters(); present_params.Windowed = true; present_params.BackBufferFormat = Format.A8R8G8B8; present_params.SwapEffect = SwapEffect.Discard; present_params.BackBufferWidth = texSize.Width; present_params.BackBufferHeight = texSize.Height; present_params.BackBufferCount = 1; d3d = new Direct3D(); device = new Device(d3d, 0, DeviceType.Hardware, this.Handle, CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded, present_params); Viewport p = device.Viewport; cpuTexture = new Texture(device, texSize.Width, texSize.Height, 1, 0, Format.A8R8G8B8, Pool.SystemMemory); gpuTexture = new Texture(device, texSize.Width, texSize.Height, 1, 0, Format.A8R8G8B8, Pool.Default); vertices = new CustomVertex.TransformedTextured[4]; vertices[0] = new CustomVertex.TransformedTextured(p.X, p.Y + p.Height - 1, 0.0f, 1.0f, 0.0f, 1.0f); vertices[1] = new CustomVertex.TransformedTextured(p.X, p.Y, 0.0f, 1.0f, 0.0f, 0.0f); vertices[2] = new CustomVertex.TransformedTextured(p.X + p.Width - 1, p.Y + p.Height - 1, 0.0f, 1.0f, 1.0f, 1.0f); vertices[3] = new CustomVertex.TransformedTextured(p.X + p.Width - 1, p.Y, 0.0f, 1.0f, 1.0f, 0.0f); Color4 startColor = new Color4(Color.Blue); Color4 middleColor = new Color4(Color.Yellow); Color4 endColor = new Color4(Color.Red); colorTable = new UInt32[256]; for (int i = 0; i < 192; i++ ) { colorTable[i] = (UInt32)Color4.Lerp(startColor, middleColor, 1f / 192 * i).ToArgb(); } for (int i = 0; i < 64; i++) { colorTable[i + 192] = (UInt32)Color4.Lerp(middleColor, endColor, 1f / 64 * i).ToArgb(); } datafeed = new byte[texSize.Width]; filter = new AverageFilter(200, texSize.Width); isRunning = true; timer = new System.Threading.Timer(new TimerCallback(feedGarbage), null, 10, 10); } private void feedGarbage(object state) { if (isRunning) { Random rand = new Random(); rand.NextBytes(datafeed); filter.AddData(datafeed); renderToCPUTex(filter.GetData()); } } private void renderToCPUTex(byte[] newdata) { // falls die daten, die wir kriegen müll sind if (newdata.Length != texSize.Width) return; // wenn wir oben rausgeflogen sind, d.h nicht mehr auf der textur, fange unten wieder an. if (drawRectangle.Y < 0) { drawRectangle.Offset(0, texSize.Height); } // zeile locken DataStream data = cpuTexture.LockRectangle(0, drawRectangle, LockFlags.None).Data; data.Position = 0; // bemalen for (int i = 0; i < texSize.Width; i++) { data.Write<UInt32>(colorTable[newdata[i]]); } // unlocken cpuTexture.UnlockRectangle(0); // in andere textur kopieren device.UpdateTexture(cpuTexture, gpuTexture); v = (float)drawRectangle.Y / (float)texSize.Height; vertices[1].Tv = v - 1.0f; vertices[3].Tv = v - 1.0f; vertices[0].Tv = v; vertices[2].Tv = v; // für den nächsten Durchlauf eins nach oben drawRectangle.Offset(0,-1); Invalidate(); } protected override void OnPaint(PaintEventArgs e) { device.Clear(ClearFlags.Target, System.Drawing.Color.FromArgb(0, 0, 255).ToArgb(), 1.0f, 0); device.BeginScene(); device.VertexFormat = CustomVertex.TransformedTextured.Format; device.SetTexture(0, gpuTexture); device.SetSamplerState(0, SamplerState.MinFilter, TextureFilter.Linear); device.SetSamplerState(0, SamplerState.MagFilter, TextureFilter.Linear); device.DrawUserPrimitives(PrimitiveType.TriangleStrip, 2, vertices); device.EndScene(); device.Present(); } protected override void OnPaintBackground(PaintEventArgs e) { } } }
-
Das Ruckeln kommt daher dass dein Thread das Update in unregelmäßigen Abständen macht und die Streifen werden verursacht weil dein Client Bereich nicht 1024x1024 ist sondern kleiner was dazu führt dass das Bild in die Form gestreckt und vor allem in der Höhe gestaucht wird.
Ein PixelShader ist ein kleines Programm das von der GPU für jeden Pixel ausgeführt wird um dessen Farbe zu berechnen. Ich hab dir einfach mal schnell Shader eingebaut und das ganze so gemacht dass der BackBuffer beim Resizen der Form auch resized wird. Außerdem hab ich das Update in einen Timer gesteckt statt direkt einen Thread zu verwenden damit das Ruckeln weg ist. Wenn du selbst direkt Kontrolle über den Thread brauchst musst du in den Thread ein genaues Timing einbauen um das Ruckeln loszuwerden.
http://dl.dropbox.com/u/1722583/dx.zip
Nur um es erwähnt zu haben: Die Shader setzen natürlich eine Grafikkarte voraus die das unterstützt. Auf Hardware die älter ist als 8 Jahre oder so wird es da Probleme geben...
EDIT: Hab noch einen Bug in der Texturkoordinatenberechnung ausgebessert und das scrollen in den VertexShader gepackt.
-
Das Wrap-Around mit den Texturkoordinaten von der Grafikkarte machen zu lassen ist ein cooler Trick. Kannte ich noch nicht.
Dass/wie/warum es geht ist natürlich sofort klar, wenn man sich ein wenig mit 3D APIs auskennt, aber ich wäre von allein vermutlich nicht so schnell aus die Idee gekommen.
Danke @dot, wieder nen neuen Trick gelernt
-
Hehe, bei mir läuft das ganze jetzt mit 0,5 ms pro Frame bei 10% CPU Last. Ich denke mal das ist performant genug für eure Anwendung
-
Hi Dot
Wir machen einen Break bis nächste Woche Dienstag / Mittwoch und stürzen uns dann wieder rein. Melden uns dann wieder, wenn wir fertig sind, oder Probleme haben.
An dieser Stelle möchte ich mich nochmals herzlich bedanken.
Du hast schnell geantwortet!
Du hast sehr kompetent Auskunft gegeben.
Du scheinst dich in diesem Bereich wirklich gut auszukennen
und ich konnte viel lernen.