我有一个名为DrawImage
的绘图功能,但它确实令人困惑,只能使用特殊形式的重塑功能,所以我有2个问题:
功能如下:
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
。问题是 - 如果没有它,代码就无法运行。知道如何让它没有它吗?
2.关于glutReshapeFunc,文档说它获得了一个指向具有2个args,width和height的函数的指针 - 我创建(到现在为止)一个无效的函数 - 任何想法如何编写一个获得宽度的重塑函数高度,实际上做重塑需要做的事。
和一个小问题:在涉及像OpenGL这样的GUI时,C ++比C更好?正如我所看到的,只有OOP才是问题而我没有解决OOP可以解决的任何问题而且C不能(我认为是OpenGL)。
无需回答所有问题 - 问题1对我来说基本上是最重要的:P
答案 0 :(得分:9)
你的DrawImage功能看起来很不错。虽然,是的,您不应该致电glMatrixMode
等glEnd
,所以请删除它们。我认为这个问题只是与设置投影矩阵有关,而添加的调用恰好可以解决首先不应存在的问题。 glutReshapeFunc
用于捕获窗口大小调整事件,因此在您需要它之前,您不必使用它。
SDL让您可以更好地控制事件和过剩,但需要更长时间才能设置。 GLFW也是一个不错的选择。我想除非你看到你需要的功能,否则改变并不重要。这些是用于创建GL上下文并执行某些事件处理的库。 SOIL可以用于所有人。
OpenGL是一个图形API,它提供了一个用于执行硬件加速3D图形的通用接口,而不是GUI库。虽然有针对OpenGL编写的GUI库。
是的,我相信很多人将OOP推向极致。我喜欢用C ++这个术语作为更好的C,而不是完全重构你的编码方式。也许只是继续使用C,但使用C ++编译器。然后,当您看到自己喜欢的功能时,请使用它。最终你可能会发现你正在使用很多,然后更好地了解它们存在的原因以及何时使用它们而不是盲目地遵循编码实践。只是imo,这都是非常主观的。
所以,投影矩阵......
要在2D屏幕上以3D形式绘制内容,您可以将3D点“投影”到平面上。我相信你看过这样的图像:
这允许您定义任意3D坐标系。除了在2D中绘制内容之外,它自然希望直接使用像素坐标。毕竟这是你监控显示的内容。因此,您希望使用一种旁路投影,它不会进行任何透视缩放并匹配比例和宽高比中的像素。
默认投影(或“观看体积”)是正交-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
真的在任何地方调用它,但由于唯一影响的变量是窗口宽度/高度,将它放在一些初始化代码中是正常的,或者,如果你打算调整窗口大小,可以使用resize事件处理程序,例如:
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;
}
。推/弹矩阵应始终在函数内配对,这样调用者就不会与它匹配。
我将以一个完整的例子结束:
{{1}}
答案 1 :(得分:5)
如果您使用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。我只在这里创建/销毁它以使代码自包含。