Archiv verlassen und diese Seite im Standarddesign anzeigen : Vorgehen .NET + OpenGL?
Kennung Eins
2006-10-18, 14:32:40
Hallo,
ich will grad ein bisschen mit .NET (C#) und OpenGL spielen. Bin dabei auf zwei Wrapper gestoßen: CsGL (http://csgl.sourceforge.net/) und SharpGL (http://www.codeproject.com/cs/media/sharpgl.asp), wobei ich CsGL brauchbarer finde.
In den CsGL Tutorials funktioniert die Anzeige von statischem OpenGL (ein Bild) problemlos, jedoch gibt es Schwierigkeiten, wenn ich Bewegung ins Spiel bringe.
Hier erstmal ein Codeschnipsel:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using CsGL.OpenGL;
namespace SimpleOpenGL
{
public class OurView : OpenGLControl
{
float fRotate = 0.0f;
public bool running = true;
public override void glDraw()
{
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
GL.glLoadIdentity();
GL.glTranslatef(0.0f,0.0f, -6); // viewport = 0 0 0 and 6 deep
GL.glRotatef(fRotate, 1.0f, 1.0f, 1.0f);
GL.glColor3f (0.0f,1.0f,0.0f);
GL.glBegin(GL.GL_TRIANGLES); // Drawing Using Triangles
GL.glVertex3f( 0.0f, 1.0f, 0.0f); // Top
GL.glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
GL.glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
GL.glEnd();
GL.glFlush();
fRotate += 1.5f;
this.SwapBuffer();
//this.OnPaint(null);
//this.Refresh();
//this.Update();
Thread.Sleep(1);
}
protected override void InitGLContext()
{
GL.glShadeModel(GL.GL_SMOOTH); // Enable Smooth Shading
GL.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
GL.glClearDepth(1.0f); // Depth Buffer Setup
GL.glEnable(GL.GL_DEPTH_TEST); // Enables Depth Testing
GL.glDepthFunc(GL.GL_LEQUAL); // The Type Of Depth Testing To Do
GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); // Nice Perspective Calculations
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
Size s = Size;
GL.glMatrixMode(GL.GL_PROJECTION);
GL.glLoadIdentity();
GL.gluPerspective(45.0f, (double)s.Width /(double) s.Height, 0.1f, 100.0f);
GL.glMatrixMode(GL.GL_MODELVIEW);
GL.glLoadIdentity();
}
}
public class MainForm : System.Windows.Forms.Form // Will show us the OpenGL window
{
private SimpleOpenGL.OurView view;
int i = 0;
public MainForm()
{
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(688, 590);
this.Name = "MainForm";
this.Text = "OpenGL with CsGL using SharpDevelop (by Joachim Rohde aka Marilyn)";
this.view = new SimpleOpenGL.OurView();
this.view.Parent = this;
this.view.Dock = DockStyle.Fill; // Will fill whole form
this.Show();
/* while (true)
{
this.OnPaint(null);
//this.Refresh();
//this.Update();
Thread.Sleep(1);
}*/
}
static void Main()
{
Application.Run(new MainForm());
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
Size s = Size;
double aspect_ratio = (double)s.Width /(double) s.Height;
GL.glMatrixMode(GL.GL_PROJECTION); // Select The Projection Matrix
GL.glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
GL.gluPerspective(45.0f, aspect_ratio, 0.1f, 100.0f);
GL.glMatrixMode(GL.GL_MODELVIEW); // Select The Modelview Matrix
GL.glLoadIdentity();// Reset The Modelview Matrix
}
}
}
Folgendes Problem habe ich: benutze ich in glDraw() die Methode this.Refresh() dann zeigt er zwar meine bewegte Szene an, jedoch sehr stockend und mit hoher CPU-Last. Als Ausweichmöglichkeit kann ich OnPaint(null) direkt aufrufen, dann zeigt er das Bild korrekt an, jedoch wird die Anwendung unbedienbar (Fenster kann nicht verschoben / Fokus geändert werden usw). Die wichtigen Stellen im Code habe ich rot markiert.
Hat jemand eine Idee, wie ich besser vorgehen kann?
In deinem Code sind so viele "so macht man das schon mal gar nicht", dass ich lieber folgenden Ratschlag raushaue: Lade dir die freie Basis-Version des http://www.csharpopenglframework.com/ herunter. Ausprobieren, Source-Code lesen, alles rauschmeissen, was du nicht brauchst und dafür deinen Code einfügen. Fertig!
Kennung Eins
2006-10-18, 22:02:45
Ok.
Dann interessiert mich dennoch: Aus welchem Grund verwenden die CsGL-Leute dann diesen Quellcode als Tutorial?
Ich kenne CsGL nicht und weiss nur, dass es uralt ist.
Das Windows UI-API ist Event-gesteuert. While (true) { ... } ist schlicht debil. Render-Code gehört ausserdem in OnPaint und nicht in glDraw. Und was macht eigentlich OnPaint(null) dort (erinnert irgendwie an Rekursion) bzw. wozu ist das gut und sinnvoll? Neuzeichnen löst man mit Invalidate() aus und die Basis-Methode ruft man mit base.OnPaint(parameter) in der eigenen overridden OnPaint-Methode auf. Was soll Update? Mehr als Invalidate und evtl. Refresh braucht man nicht. Wozu Flush, wenn direkt danach ein SwapBuffer kommt? Warum wird für die Rotation nicht versuchsweise ein Timer benutzt?
Windows ist kein Realtime-System. Thread.Sleep(1) ist Unsinn, weil die Windows-Genauigkeit ohenhin nur bei 16 ms liegt. Warum überhaupt nur 1 ms? Mit SwapBuffer wird die FPS auf die wesentlich höhere Monitor-VSync-Wiederholrate festgelegt (falls nicht explizit abgeschaltet). Wenn ich mich nicht irre, dann kann mit Sleep auch nicht auf andere, eigene Threads umschalten, sondern nur auf andere Windows-Threads.
ScottManDeath
2006-10-19, 04:06:54
Ich nutze Tao, das u.A. auch Bindings für CG hat.
SgtTynis
2006-10-19, 09:07:02
Windows ist kein Realtime-System. Thread.Sleep(1) ist Unsinn, weil die Windows-Genauigkeit ohenhin nur bei 16 ms liegt. Warum überhaupt nur 1 ms?
Eine Windows Eigenwilligkeit, damit ein Thread nicht 100% des Systems an sich reisst, ich glaube sogar ein Thread.Sleep(0) reicht schon aus, damit die Resourcen an einen anderen Thread weitergegeben werden.
Kennung Eins
2006-10-19, 09:17:10
SgtTynis, genau deswegen verwende ich es.
Ich buddel mich heute mal durch eure Infos ...
BTW: While (true) ist nicht umsonst auskommentiert ... ich musste ja irgendwie testen, ob das Refresh irgendwo ohne Probleme funktioniert (Basisklasse / Objekt).
Kennung Eins
2006-10-19, 09:35:34
In deinem Code sind so viele "so macht man das schon mal gar nicht", dass ich lieber folgenden Ratschlag raushaue: Lade dir die freie Basis-Version des http://www.csharpopenglframework.com/ herunter. Ausprobieren, Source-Code lesen, alles rauschmeissen, was du nicht brauchst und dafür deinen Code einfügen. Fertig!LOL:
Basic Edition source code
October 10, 2006: Basic Edition source code is no longer available. Please consider buying one of the commercial versions. Mal sehen, ob ichs woanders auftreiben kann ...
While (true) { ... } ist schlicht debil. Render-Code gehört ausserdem in OnPaint und nicht in glDraw.
Vollkommener Unsinn! OnPaint ist viel zu ungenau und genau deswegen verwendet man eine while Schleife, damit man mehr FPS bekommt. Oder zumindest PeekMessage.
Kommt auf die Anwendung drauf an. Wenn sich ohne Interaktion nichts bewegt wie bei einem 3D-Modeller kann man durchaus OnPaint verwenden.
Bei einer Realtime-Anwendung wie einem Spiel natürlich mit der Schleife.
Kommt auf die Anwendung drauf an. Wenn sich ohne Interaktion nichts bewegt wie bei einem 3D-Modeller kann man durchaus OnPaint verwenden.
Bei einer Realtime-Anwendung wie einem Spiel natürlich mit der Schleife.
einverstanden :-)
Eine Windows Eigenwilligkeit, damit ein Thread nicht 100% des Systems an sich reisst, ich glaube sogar ein Thread.Sleep(0) reicht schon aus, damit die Resourcen an einen anderen Thread weitergegeben werden.
Windows schaltet als Multi-Tasking-Betriebssystem ohnehin selbstständig auf andere Programme/Threads um. Und ausserdem...
While (true) { ... } ist schlicht debil. Render-Code gehört ausserdem in OnPaint und nicht in glDraw.Vollkommener Unsinn! OnPaint ist viel zu ungenau und genau deswegen verwendet man eine while Schleife, damit man mehr FPS bekommt. Oder zumindest PeekMessage.
Zunächst zitiert man vollständig, also "Das Windows UI-API ist Event-gesteuert. While (true) { ... } ist schlicht debil." Es geht ganz allgemein um den widersprüchlichen Ansatz. Wenn man Windows-Messages automatisch empfangen und verarbeiten will, was Kennung Eins deutlich gamacht hat mit der sogar doppelt implementierten overriden OnSizeChanged-Methode, dann kann man nicht While (true) { ... } verwenden, sondern muss alles in der Endlos-Schleife selber machen, was allerdings fehlt, weil eben nicht beabsichtigt.
OnPaint ist schon sehr brauchbar. Man könnte es natürlich z.B. auch ganz ohne Timer oder Endlosschleife machen, indem man in OnPaint sein Zeug rendert und dann Invalidate UND Refresh aufruft. Damit ist man quasi in einer schnellen Schleife, aber die wichtigen Messages werden trotzdem bearbeitet.
Basic Edition source code
October 10, 2006: Basic Edition source code is no longer available. Please consider buying one of the commercial versions.
Das ist Pech. Aber zum Thema .Net und OpenGL findet sich schon Einiges im Internet.
Nachtrag: "auch ganz ohne Timer oder Endlosschleife" oder Sleep().
Ansonsten macht halt bessere Vorschläge. Viele Wege führen nach Rom...
Wenn man Windows-Messages automatisch empfangen und verarbeiten will, was Kennung Eins deutlich gamacht hat mit der sogar doppelt implementierten overriden OnSizeChanged-Methode, dann kann man nicht While (true) { ... } verwenden, sondern muss alles in der Endlos-Schleife selber machen, was allerdings fehlt, weil eben nicht beabsichtigt.
Natürlich geht das, es fehlt nur ein Application.DoEvents() in der Schleife. Das würde dann so aussehen:
form.Show();
while (form.QuitApplication == false)
{
form.Update();
Application.DoEvents();
}
Aber selbst das ist nicht die effizienteste Möglichkeit, da DoEvents() wohl Speicher reserviert. Tom Miller schlägt folgendes vor:
http://blogs.msdn.com/tmiller/archive/2005/05/05/415008.aspx
OnPaint ist schon sehr brauchbar. Man könnte es natürlich z.B. auch ganz ohne Timer oder Endlosschleife machen, indem man in OnPaint sein Zeug rendert und dann Invalidate UND Refresh aufruft.
Das umgeht das Problem aber nicht, dass nicht so viele Events von Windows zurückkommen, wenn man den effizientesten Weg möchte, also die meisten FPS.
PS. Die frm.Update() ruft dann die Render MEthode auf oder du ersetzt frm.Update() gleich durch eine eigene Render Methode. Aber der effizienteste Weg ist der von Tom Miller. Der Ineffizienteste über GetMessage/WMPaint.
Ich habe nicht den Eindruck, dass Kennung Eins z.Z. eine aufwendige Game-Engine schreiben will. DoEvents() ist bekanntermassen eine problematische Notlösung und wird auch von Hern Miller nicht benutzt.
Das umgeht das Problem aber nicht, dass nicht so viele Events von Windows zurückkommen, wenn man den effizientesten Weg möchte, also die meisten FPS.Funktioniert bei mir sehr gut. Erreiche mit Doublebuffering die maximale FPS meines Monitors (120 FPS), bleibt interaktiv und läuft sehr rund/flüssig, wenn mir Windows mit anderen laufenden Programmen nicht kurz dazwischen funkt (was aber auch Spiele nicht verhindern können).
Kennung Eins
2006-10-19, 12:46:07
Tao rockt. Ist zwar eigentlich zu "bloated" für das, was ich machen will, aber es funktioniert wenigstens anständig.
Arokh
2006-10-19, 12:57:55
Vollkommener Unsinn! OnPaint ist viel zu ungenau und genau deswegen verwendet man eine while Schleife, damit man mehr FPS bekommt. Oder zumindest PeekMessage.Application.DoEvents() heißt das in .NET ;)
while(true)
{
glDraw();
Application.DoEvents();
}
Oder du registrierst glDraw() als Idle-Funktion, das sollte die gleiche Wirkung haben:
// in der Klassendeklaration von MainForm
protected void OnIdle(Object sender, EventsArgs e)
{
glDraw();
}
// z.B. in der Create-Routine von MainForm
Application.Idle += new EventHandler(this, MainForm.OnIdle);
Falls es meinem Code an syntaktischer Korrektheit mangelt: ich komme eigentlich von C++ und habe nur notdürftig nach C# übersetzt ;)
Aber andere Frage: angenommen, ich möchte auf solche Wrapper verzichten und lieber selber mit wglCreateContext & co Hand anlegen. Dann benötige ich ja einen Handle (Win32 Handle, nicht .NET Handle) vom Typ HDC, wie bekomme ich denn den? Ich hab schon folgendes versucht (das ist jetzt C++):
void EnableGL(Form ^GLWindow)
{
// das hier sollte so was wie GetDC(hwnd) sein:
Graphics^ GLGraphics = GLWindow->CreateGraphics();
// HDC extrahieren
HDC hDC = (HDC) GLGraphics->GetHdc();
// GL rendering context
HGLRC hRC = wglCreateContext(hDC);
}
das scheitert daran, daß GetHdc() als Rückgabetyp IntPtr hat, was nicht nach HDC konvertiert werden kann. Ich habe auch probiert, erst nach int und von da nach HDC zu konvertieren, das wird vom Compiler auch akzeptiert, es liefert aber zur Laufzeit kein brauchbares Ergebnis (hRC bleibt immer 0).
Die Programmierer dieser Wrapper müssen das doch auch irgendwie hinkriegen?
Edit: Mist, mit dem DoEvents war einer schneller als ich. Was ist denn das "bekanntermaßen problematische" daran?
Edit: Mist, mit dem DoEvents war einer schneller als ich. Was ist denn das "bekanntermaßen problematische" daran?
Es geht wohl nur darum, dass Instanzen der EventArgs Klasse mit der Zeit (über mehrere tausende Frames) viel Speicher abzweigt, auch wenn keine Events groß passieren. Wobei ich dazu keine Messungen gemacht habe. Wenn in deiner Render-Funktion wahrscheinlich immer etwas halbwegs aufregendes passiert, so dass der GC öfters in Kraft tritt, kann sich das vielleicht auch wieder relativieren.
Kennung Eins
2006-10-19, 13:33:31
Aber andere Frage: angenommen, ich möchte auf solche Wrapper verzichten und lieber selber mit wglCreateContext & co Hand anlegen. Dann benötige ich ja einen Handle (Win32 Handle, nicht .NET Handle) vom Typ HDC, wie bekomme ich denn den? Ich hab schon folgendes versucht (das ist jetzt C++):
void EnableGL(Form ^GLWindow)
{
// das hier sollte so was wie GetDC(hwnd) sein:
Graphics^ GLGraphics = GLWindow->CreateGraphics();
// HDC extrahieren
HDC hDC = (HDC) GLGraphics->GetHdc();
// GL rendering context
HGLRC hRC = wglCreateContext(hDC);
}
das scheitert daran, daß GetHdc() als Rückgabetyp IntPtr hat, was nicht nach HDC konvertiert werden kann. Ich habe auch probiert, erst nach int und von da nach HDC zu konvertieren, das wird vom Compiler auch akzeptiert, es liefert aber zur Laufzeit kein brauchbares Ergebnis (hRC bleibt immer 0).
Die Programmierer dieser Wrapper müssen das doch auch irgendwie hinkriegen?
Edit: Mist, mit dem DoEvents war einer schneller als ich. Was ist denn das "bekanntermaßen problematische" daran?Schau mal in die Nehe Lessons rein .. da wird ziemlich viel mit HDCs & Co. rumgemurkelt.
Arokh
2006-10-19, 13:36:05
Schau mal in die Nehe Lessons rein .. da wird ziemlich viel mit HDCs & Co. rumgemurkelt.aber unter Win32. Es gibt zwar eine Visual Studio .NET Version, die nutzt aber die .NET Klassen nicht, sondern auch nur Win32.
SgtTynis
2006-10-20, 12:59:20
Windows schaltet als Multi-Tasking-Betriebssystem ohnehin selbstständig auf andere Programme/Threads um. Und ausserdem...
aus MSDN zu Thread.Sleep: "Geben Sie null (0) an, um anzugeben, dass dieser Thread angehalten werden soll, sodass andere wartende Threads ausgeführt werden können."
Kennung Eins
2006-10-26, 16:17:36
Jetzt muss ich doch nochmal was fragen.
Ich habe ein Problem beim Laden von Texturen. Diese Texturen liegen nicht als Datei vor, sondern sollen aus einem Bitmap-Objekt direkt auf ein Quad gemappt werden.
Mit dem unten aufgeführten Code kriege ich jedoch nur folgendes Bild:
http://img150.imageshack.us/img150/1157/leeree0.jpg (http://imageshack.us)
Das sieht ja für mich so aus, als ob da kein Bild ankommen würde, sprich als ob "bitmap" leer wäre. Nun habe ich jedoch "bitmap" mal per bitmap.Save() auf die Platte gespeichert, das funktioniert tadellos und das Bild enthält auch, was es enthalten soll.
Also muss es irgendwie an den Parametern der roten Zeile (unten) liegen. Ich habe ein bisschen probiert und das passiert, wenn ich die fett markierte Stelle (m_width, m_height) durch 512, 512 ersetze:
http://img239.imageshack.us/img239/8057/512ve5.jpg (http://imageshack.us)
Das ist _nicht_ das, was ich erhalten will .. aber immerhin schon besser, als das erste (weiße) Bild.
Weiß jemand, wo das Problem liegen könnte? Sind irgendwelche meiner Parameter falsch?
Hier nun abschließend mein Code:
if (b != null)
{
Bitmap bitmap;
bitmap = (Bitmap)b.Clone(); // Input bitmap kopieren
int m_Width = bitmap.Width;
int m_Height = bitmap.Height;
int[] handle = new int[1];
Gl.glGenTextures(handle.Length, handle);
int m_Handle = handle[0];
handle = null;
Rectangle rect = new Rectangle(0, 0, m_Width, m_Height);
BitmapData bdata = bitmap.LockBits(rect,ImageLockMode.ReadOnly, bitmap.PixelFormat);
Gl.glBindTexture(Gl.GL_TEXTURE_2D, m_Handle);
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGB, m_Width, m_Height, 0, Gl.GL_BGR, Gl.GL_UNSIGNED_BYTE, bdata.Scan0);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
Gl.glEnable(Gl.GL_TEXTURE_2D);
Gl.glColor3f(1f,1f,1f);
Gl.glBegin(Gl.GL_QUADS);
Gl.glTexCoord2f(0.0f, 0.0f);
Gl.glVertex3f(-1.0f, -1.0f, 0.0f);
Gl.glTexCoord2f(0.0f, 1.0f);
Gl.glVertex3f(-1.0f, 1.0f, 0.0f);
Gl.glTexCoord2f(1.0f, 1.0f);
Gl.glVertex3f(1.0f, 1.0f, 0.0f);
Gl.glTexCoord2f(1.0f, 0.0f);
Gl.glVertex3f(1.0f, -1.0f, 0.0f);
Gl.glEnd();
Gl.glDisable(Gl.GL_TEXTURE_2D);
bitmap.UnlockBits(bdata);
bitmap.Dispose();
du weißt, daß in OpenGL Texturen quadratisch sein müssen? Und daß als Breite/Höhe nur Potenzen von 2 zulässig sind? Also z.B. 128, 256, 512, ...? Und daß, wenn du als Pixeldatenformat GL_RGB und als Pixeldatentyp GL_UNSIGNED_BYTE angegeben hast, das die Pixeldaten enthaltene Array das Format
{pixel0_red, pixel0_green, pixel0_blue, pixel1_red, pixel1_green, pixel1_blue, ...}
haben muß? Wobei jedes Element des Arrays vom Typ unsigned byte (is dasselble wie unsigned char) sein muß?
Und daß natürlich das verwendete Bitmap dieselbe Größe in Pixeln haben muß, wie du als width und height angibst (in deinem Fall 512*512)?
Ungetestet, Kommentare im Code
if (b == null)
return;
//// Ohne wichtigen Grund machen wir sowas nicht
// Bitmap bitmap;
// bitmap = (Bitmap)b.Clone(); // Input bitmap kopieren
//// redundant, also weg damit
// int m_Width = bitmap.Width;
// int m_Height = bitmap.Height;
// wirres Doppel-Gemoppel, das vereinfachen wir mal
// dabei aber nicht vergessen: uint[] m_handle;
Gl.glGenTextures(m_handle.Length, m_handle);
//// das ziehen wir vor, gehoert zusammen
Gl.glBindTexture(Gl.GL_TEXTURE_2D, m_Handle);
// jetzt kommt was neues
// kannn man sich schenken, wenn man nur ein Format verwendet
// kann man auch noch besser machen, aber egal
int bitmapBytes;
PixelFormat fomat;
if (b.PixelFormat == PixelFormat.Format32bppArgb ||
b.PixelFormat == PixelFormat.Format32bppPArgb)
{
format = PixelFormat.Format32bppArgb;
bitmapBytes = 4;
}
else
{
format = PixelFormat.Format24bppRgb;
bitmapBytes = 3;
}
// nur das neue PixelFormat verwenden
Rectangle rect = new Rectangle(0, 0, b.Width, b.Height);
BitmapData bdata = b.LockBits(rect,ImageLockMode.ReadOnly,format);
// jetzt aber
if (bitmapBytes ==3)
{
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGB, b.Width, b.Height, 0, Gl.GL_BGR, Gl.GL_UNSIGNED_BYTE, bdata.Scan0);
}
else
{
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, b.Width, b.Height, 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, bdata.Scan0);
}
//// der Treiber hat die Texture im Hauptspeicher und in der Grafikkarte gespeichert, wir brauchen die bitmap nicht mehr
b.UnlockBits(bdata);
//// ok
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
//// das Rendern gehoert nun wirklich nicht hier her
//// aber gut...
Gl.glEnable(Gl.GL_TEXTURE_2D);
Gl.glColor3f(1f,1f,1f);
Gl.glBegin(Gl.GL_QUADS);
Gl.glTexCoord2f(0.0f, 0.0f);
Gl.glVertex3f(-1.0f, -1.0f, 0.0f);
Gl.glTexCoord2f(0.0f, 1.0f);
Gl.glVertex3f(-1.0f, 1.0f, 0.0f);
Gl.glTexCoord2f(1.0f, 1.0f);
Gl.glVertex3f(1.0f, 1.0f, 0.0f);
Gl.glTexCoord2f(1.0f, 0.0f);
Gl.glVertex3f(1.0f, -1.0f, 0.0f);
Gl.glEnd();
Gl.glDisable(Gl.GL_TEXTURE_2D);
//// hat sich erledigt
// bitmap.UnlockBits(bdata);
// bitmap.Dispose();
du weißt, daß in OpenGL Texturen quadratisch sein müssen?
Keineswegs. Dann bräuchte man ja nicht Breite und Höhe.
Und daß als Breite/Höhe nur Potenzen von 2 zulässig sind? Also z.B. 128, 256, 512, ...?
Nicht wenn die Grafikkarte ARB_texture_non_power_of_two unterstützt (NVidia ab GeForce 6).
Wobei jedes Element des Arrays vom Typ unsigned byte (is dasselble wie unsigned char) sein muß?
In C# ist char kein Byte und byte ist unsigned, aber letztlich kommt es nur darauf an dass die Bitmap-Instanz das richtige PixelFormat verwendet.
Keineswegs. Dann bräuchte man ja nicht Breite und Höhe.
Nicht wenn die Grafikkarte ARB_texture_non_power_of_two unterstützt (NVidia ab GeForce 6).meine GF 7600 fabriziert nur Blödsinn (etwa vergleichbar dem Pixelsalat im zweiten Screenshot von Kennung Eins), wenn ich was anderes als Breite = Höhe = 2^n, wobei n eine natürlich Zahl ist, mache.
Must halt auch die entsprechende Extension benützen dann...
Must halt auch die entsprechende Extension benützen dann...
Da gibt es nichts zu benutzen. ARB_texture_non_power_of_two definiert weder neue Funktionen noch Konstanten, sondern hebt lediglich die NPOT-Beschränkungen auf.
Gast,
das klingt nach einem Treiberbug, da es aber auch Spiele gibt die rechteckige Texturen verwenden kann ich mir das nicht so recht vorstellen. Sicher dass es nicht an der Anordnung der Quelldaten liegt?
Kennung Eins
2006-11-03, 15:43:13
Ok, Problem gelöst - es war wirklich das non-power-of-two Problem. Die Programmstruktur habe ich inzwischen angepasst.
(Das mit dem Bild-kopieren hatte übrigens seinen Grund: das Source-Objekt wird von einem weiteren Thread gelesen/geschrieben, darum muss ich es mir in meinen laufenden Thread sichern (Clone) um nicht plötzlich ein halb überschriebenes Bild anzufassen)
vBulletin®, Copyright ©2000-2024, Jelsoft Enterprises Ltd.