我有一个名为
DrawImage
的绘图函数,但它确实令人困惑,并且仅适用于特定形式的重塑函数,所以我有两个问题:
GL_QUAD
,但我不知道该怎么做。功能如下:
void DrawImage(char filename, int xx, int yy, int ww, int hh, int angle)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, filename);
glLoadIdentity();
glTranslatef(xx,yy,0.0);
glRotatef(angle,0.0,0.0,1.0);
glTranslatef(-xx,-yy,0.0);
// Draw a textured quad
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(xx,yy);
glTexCoord2f(0, 1); glVertex2f(xx,yy + hh);
glTexCoord2f(1, 1); glVertex2f(xx + ww,yy + hh);
glTexCoord2f(1, 0); glVertex2f(xx + ww,yy);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glEnd();
}
有人对我说,在
glDisable
和glPopMatrix
之间不能打电话给glMatrixMode
、glBegin
或glEnd
。问题是——没有它,代码将无法工作。知道如何让它在没有它的情况下工作吗?
glutReshapeFunc
:您的 DrawImage 函数看起来非常好。虽然,是的,你不应该在
glMatrixMode
之前调用 glEnd
等,所以删除它们。我相信这个问题只是与设置投影矩阵有关,而添加的调用恰好解决了一个本来不应该存在的问题。 glutReshapeFunc
用于捕获窗口调整大小事件,因此在需要之前您不必使用它。SDL 使您可以更好地控制事件和过剩,但需要更长的时间来设置。 GLFW 也是一个不错的选择。我想除非你看到你需要的功能,否则更改并不那么重要。这些是用于创建 GL 上下文并执行一些事件处理的库。土壤可以用于所有这些。
OpenGL 是一个图形 API,提供了用于执行硬件加速 3D 图形的通用接口,而不是 GUI 库。不过有为 OpenGL 编写的 GUI 库。
是的,我相信很多人都将 OOP 发挥到了极致。我喜欢 C++ 这个术语,因为它是更好的 C,而不是完全重构编码方式。也许继续使用 C,但使用 C++ 编译器。然后,当您看到您喜欢的功能时,请使用它。最终,您可能会发现自己使用了很多,然后对它们存在的原因以及何时使用它们有更好的认识,而不是盲目地遵循编码实践。只是在我看来,这都是非常主观的。
所以,投影矩阵...
要在 2D 屏幕上绘制 3D 内容,您需要将 3D 点“投影”到平面上。我相信你一定见过这样的图片:
这允许您定义任意 3D 坐标系。除了在 2D 中绘制东西之外,很自然地想要直接使用像素坐标。毕竟这就是您监控显示的内容。因此,您想要使用一种旁路投影,它不进行任何透视缩放并在比例和纵横比上匹配像素。
默认投影(或“查看体积”)是正交 -1 比 1 立方体。要改变它,
glMatrixMode(GL_PROJECTION); //from now on all glOrtho, glTranslate etc affect projection
glOrtho(0, widthInPixels, 0, heightInPixels, -1, 1);
glMatrixMode(GL_MODELVIEW); //good to leave in edit-modelview mode
确实可以在任何地方调用它,但由于唯一影响的变量是窗口宽度/高度,因此通常将其放入某些初始化代码中,或者,如果您计划调整窗口大小,则可以使用调整大小事件处理程序,例如:
void reshape(int x, int y) {... do stuff with x/y ...}
...
glutReshapeFunc(reshape); //give glut the callback
这将使屏幕的左下角成为原点,并且传递给
glVertex
的值现在可以以像素为单位。
还有一些事情:您可以在之后使用
glTranslatef(-xx,-yy,0.0);
而不是 glVertex2f(0,0)
。推入/弹出矩阵应始终在函数内配对,因此调用者不会匹配它。
我将以一个完整的示例结束:
#include <GL/glut.h>
#include <GL/gl.h>
#include <stdio.h>
int main(int argc, char** argv)
{
//create GL context
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA);
glutInitWindowSize(800, 600);
glutCreateWindow("windowname");
//create test checker image
unsigned char texDat[64];
for (int i = 0; i < 64; ++i)
texDat[i] = ((i + (i / 8)) % 2) * 128 + 127;
//upload to GPU texture
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 8, 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, texDat);
glBindTexture(GL_TEXTURE_2D, 0);
//match projection to window resolution (could be in reshape callback)
glMatrixMode(GL_PROJECTION);
glOrtho(0, 800, 0, 600, -1, 1);
glMatrixMode(GL_MODELVIEW);
//clear and draw quad with texture (could be in display callback)
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, tex);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glTexCoord2i(0, 0); glVertex2i(100, 100);
glTexCoord2i(0, 1); glVertex2i(100, 500);
glTexCoord2i(1, 1); glVertex2i(500, 500);
glTexCoord2i(1, 0); glVertex2i(500, 100);
glEnd();
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glFlush(); //don't need this with GLUT_DOUBLE and glutSwapBuffers
getchar(); //pause so you can see what just happened
//System("pause"); //I think this works on windows
return 0;
}
如果您可以使用 OpenGL 3.0 或更高版本,则绘制纹理的更简单方法是
glBlitFramebuffer()
。它不支持旋转,但仅将纹理复制到帧缓冲区内的矩形,包括必要时的缩放。
我还没有测试过这段代码,但它看起来像这样,
tex
是你的纹理ID:
GLuint readFboId = 0;
glGenFramebuffers(1, &readFboId);
glBindFramebuffer(GL_READ_FRAMEBUFFER, readFboId);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tex, 0);
glBlitFramebuffer(0, 0, texWidth, texHeight,
0, 0, winWidth, winHeight,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &readFboId);
如果你想重复绘制纹理,你当然可以重复使用相同的FBO。我只是在这里创建/销毁它以使代码独立。