Ich möchte ein Spiel erstellen, das intern 320 x 240 Pixel groß ist, aber auf dem Bildschirm mit ganzzahligen Vielfachen davon dargestellt wird (640 x 480, 960.720 usw.). Ich gehe für Retro-2D-Pixelgrafiken.
Ich habe dies erreicht, indem ich die interne Auflösung über glOrtho() eingestellt habe:
glOrtho(0, 320, 240, 0, 0, 1);
Und dann skaliere ich die Ausgabeauflösung um den Faktor 3, wie folgt:
Es funktioniert perfekt bei 320×240 (nicht skaliert):
Wenn ich auf 960 x 720 hochskaliere, funktioniert das Pixel-Rendering einwandfrei! Es scheint jedoch, dass der GL_Line_Loop nicht auf einer 320×240-Leinwand gezeichnet und vergrößert wird, sondern auf der endgültigen 960×720-Leinwand gezeichnet wird. Das Ergebnis sind 1px-Linien in einer 3px-Welt 🙁
Wie zeichne ich Linien auf die glOrtho-Leinwand mit 320 x 240 statt auf die Ausgabe-Leinwand mit 960 x 720?
Wenn FBOs nicht Ihre Szene sind, gibt es immer breite DIY-Linien mit Dreiecken.
– Genpfault
1. Januar 2017 um 3:57 Uhr
Es gibt keine “320×240 glOrtho-Leinwand”. Es gibt nur die tatsächliche Auflösung des Fensters: 960×720.
Sie skalieren lediglich die Koordinaten der Primitive, die Sie rendern. Ihr Code sagt also, dass Sie eine Zeile von beispielsweise (20, 20) bis (40, 40) rendern sollen. Und OpenGL skaliert (schließlich) diese Koordinaten in jeder Dimension um 3: (60, 60) und (120×120).
Aber das ist nur der Umgang mit der Endpunkte. Was in der Mitte passiert, basiert immer noch auf der Tatsache, dass Sie mit der tatsächlichen Auflösung des Fensters rendern.
Auch wenn Sie angestellt sind glLineWidth um die Breite Ihrer Linien zu ändern, würde das nur die Linienbreiten fixieren. Es würde nicht die Tatsache beheben, dass die Rasterung von Linien auf der tatsächlichen Auflösung basiert, mit der Sie rendern. Diagonale Linien haben also nicht das pixelige Aussehen, das Sie wahrscheinlich möchten.
Der einzige Weg, dies richtig zu machen, ist, es richtig zu machen. Rendern Sie zu einem Bild, das tatsächlich 320 x 240 groß ist, und zeichnen Sie es dann mit der tatsächlichen Auflösung des Fensters.
Sie müssen eine Textur dieser Größe erstellen und sie dann an a anhängen Framebuffer-Objekt. Binden Sie das FBO zum Rendern und rendern Sie es (wobei das Ansichtsfenster auf die Größe des Bildes eingestellt ist). Lösen Sie dann das FBO und zeichnen Sie diese Textur in das Fenster (wobei das Ansichtsfenster auf die Auflösung des Fensters eingestellt ist).
Ja, ich stimme zu, muss aber hinzufügen, dass Intel-Grafikkarten nicht wie erwartet oder überhaupt nicht funktionieren werden, wenn Sie in Textur rendern möchten, bis sie die Treiber reparieren, was für ältere Grafikkarten niemals auf Erfahrung basiert … in solchen Fall könnten Sie versuchen glReadPixels stattdessen …
– Spektre
26. April 2017 um 8:27 Uhr
@Spektre: Wenn Sie eine Antwort hinzufügen möchten, in der bestimmte Treiberfehler erörtert werden, können Sie dies gerne tun. Ich weiß nicht, von welchen Fehlern genau Sie sprechen oder auf welche Hardware Sie sich beziehen, daher bin ich nicht qualifiziert, darüber zu diskutieren.
– Nicol Bolas
26. April 2017 um 13:47 Uhr
Ich habe das langsame hinzugefügt OpenGL 1.0 Ansatz, der sogar auf Intel funktioniert.
– Spektre
27. April 2017 um 9:55 Uhr
Gespenst
Wie ich in meinem Kommentar erwähnt habe Intel-OpenGL Treiber hat Probleme mit dem direkten Rendern in Textur und ich kenne keine Problemumgehung, die funktioniert. In einem solchen Fall hilft nur die Nutzung glReadPixels Bildschirminhalte hineinkopieren Zentralprozessor Speicher und kopieren Sie es dann zurück Grafikkarte als Textur. Das ist natürlich viel langsamer als das direkte Rendern in Textur. Also hier ist der Deal:
Ansicht mit niedriger Auflösung einstellen
Ändern Sie nicht die Auflösung Ihres Fensters, nur die glViewport Werte. Rendern Sie dann Ihre Szene in niedriger Auflösung (auf nur einem Bruchteil der Bildschirmfläche).
Kopieren Sie den gerenderten Bildschirm in die Textur
Zielauflösungsansicht einstellen
Rendern Sie die Textur
verwenden nicht vergessen GL_NEAREST Filter. Das Wichtigste ist, dass Sie die Puffer erst danach tauschen, nicht vorher !!! sonst hättest du flackern.
Hier C++ Quelle dafür:
void gl_draw()
{
// render resolution and multiplier
const int xs=320,ys=200,m=2;
// [low res render pass]
glViewport(0,0,xs,ys);
glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
// 50 random lines
RandSeed=0x12345678;
glColor3f(1.0,1.0,1.0);
glBegin(GL_LINES);
for (int i=0;i<100;i++)
glVertex2f(2.0*Random()-1.0,2.0*Random()-1.0);
glEnd();
// [multiply resiolution render pass]
static bool _init=true;
GLuint txrid=0; // texture id
BYTE map[xs*ys*3]; // RGB
// init texture
if (_init) // you should also delte the texture on exit of app ...
{
// create texture
_init=false;
glGenTextures(1,&txrid);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,txrid);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST); // must be nearest !!!
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_COPY);
glDisable(GL_TEXTURE_2D);
}
// copy low res screen to CPU memory
glReadPixels(0,0,xs,ys,GL_RGB,GL_UNSIGNED_BYTE,map);
// and then to GPU texture
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,txrid);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, xs, ys, 0, GL_RGB, GL_UNSIGNED_BYTE, map);
// set multiplied resolution view
glViewport(0,0,m*xs,m*ys);
glClear(GL_COLOR_BUFFER_BIT);
// render low res screen as texture
glBegin(GL_QUADS);
glTexCoord2f(0.0,0.0); glVertex2f(-1.0,-1.0);
glTexCoord2f(0.0,1.0); glVertex2f(-1.0,+1.0);
glTexCoord2f(1.0,1.0); glVertex2f(+1.0,+1.0);
glTexCoord2f(1.0,0.0); glVertex2f(+1.0,-1.0);
glEnd();
glDisable(GL_TEXTURE_2D);
glFlush();
SwapBuffers(hdc); // swap buffers only here !!!
}
Und Vorschau:
Ich habe das bei einigen getestet Intel-HD Grafiken (Gott weiß welche Version) habe ich zur Verfügung gestellt und es funktioniert (während Standard-Render-to-Texture-Ansätze es nicht sind).
9141500cookie-checkOpenGL Scale Single Pixel Lineyes
Wenn FBOs nicht Ihre Szene sind, gibt es immer breite DIY-Linien mit Dreiecken.
– Genpfault
1. Januar 2017 um 3:57 Uhr