【问题标题】:Drawing a 2D texture in OpenGL [closed]在 OpenGL 中绘制 2D 纹理 [关闭]
【发布时间】:2014-06-18 14:49:09
【问题描述】:

我有一个名为 DrawImage 的绘图函数,但它确实令人困惑,并且只使用特定形式的重塑函数,所以我有 2 个问题:

  1. 如何在 OpenGL 中绘制纹理?我只想创建一个函数来获取纹理、x、y、宽度、高度,也许还有角度,然后根据参数对其进行绘制和绘制。我想定期将其绘制为 GL_QUAD 但我不知道该怎么做.-。人们说我应该使用 SDL 或 SFML 这样做,是否推荐?如果是,你能给我一个加载纹理和绘制纹理的简单函数吗?我目前正在使用 SOIL 加载纹理。

函数如下:

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();
}

有人跟我说你不能在glBeginglEnd之间打电话给glDisableglPopMatrixglMatrixMode。问题是 - 没有它,代码将无法工作。知道如何让它在没有它的情况下工作吗? 2.关于 glutReshapeFunc,文档说它获得了一个指向具有 2 个参数、宽度和高度的函数的指针 - 我创建了(到目前为止)一个变得无效的函数 - 知道如何编写一个获取宽度和高度,实际上做了 reshape 需要做的事情。

还有一个小问题:对于像 OpenGL 这样的 GUI,C++ 比 C 好多少?正如我所看到的,只有 OOP 才是问题所在,我没有解决任何 OOP 可以解决而 C 不能解决的问题(我的意思是在 OpenGL 中)。

无需回答所有问题 - 问题 1 对我来说基本上是最重要的:P

【问题讨论】:

  • 问题太多了,其中一些是题外话/观点。请当时只问一个问题。并始终添加您编写的相关代码,并解释它的错误或问题。
  • @user694733 抱歉,完成:P
  • @user3745476 那么为什么它被称为文件名? ://
  • @BartekBanachewicz 你是对的,我在 mycdoe 中更改了它

标签: c opengl


【解决方案1】:
  1. 您的 DrawImage 函数看起来非常不错。虽然,是的,你不应该在glEnd 之前打电话给glMatrixMode 等,所以删除它们。我相信这个问题只是与设置你的投影矩阵有关,而添加的调用恰好解决了一个原本不应该存在的问题。 glutReshapeFunc 用于捕获窗口调整大小事件,因此在您需要它之前,您不必使用它。

  2. SDL 让您可以更好地控制事件和过剩,但需要更长的时间来设置。 GLFW 也是一个不错的选择。我想除非您看到您需要的功能,否则更改并不那么重要。这些是用于创建 GL 上下文并进行一些事件处理的库。 SOIL 都可以用。

  3. OpenGL 是一种图形 API,它提供了一个用于执行硬件加速 3D 图形的通用接口,而不是一个 GUI 库。不过也有为 OpenGL 编写的 GUI 库。

  4. 是的,我相信很多人都将 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

确实可以在任何地方调用它,但由于唯一影响变量是窗口宽度/高度,因此通常将其放入一些初始化代码中,或者,如果您打算调整窗口大小,则可以使用调整大小事件处理程序,例如:

void reshape(int x, int y) {... do stuff with x/y ...}
...
glutReshapeFunc(reshape); //give glut the callback

这将使屏幕的左下角成为原点,传递给glVertex 的值现在可以以像素为单位。

还有一些事情:你可以在之后使用glVertex2f(0,0) 而不是glTranslatef(-xx,-yy,0.0);。 Push/pop 矩阵应始终在函数中配对,以免调用者匹配它。

我将以一个完整的例子结束:

#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;
}

【讨论】:

  • 非常感谢!!!!我知道问题不在于 DrawImage,而是在某些鼠标 x、y 坐标检测中我做了:P
【解决方案2】:

如果您可以使用 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。我只是在这里创建/销毁它以使代码自包含。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-20
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    相关资源
    最近更新 更多