【问题标题】:OpenGL texture mapping stubbornly refuses to workOpenGL纹理映射顽固地拒绝工作
【发布时间】:2011-06-19 17:58:39
【问题描述】:

我正在使用 D 编程语言中的 SDL 和 OpenGL 编写 2D 游戏。目前它只是尝试将纹理映射的四边形渲染到屏幕上。问题是,整个纹理映射部分似乎不太有效。尽管纹理显然加载良好(分配了一个非零纹理编号,不会导致 glGetError 返回非零值),但使用 glColor 中设置的最后一个颜色渲染四边形,完全忽略纹理。

我查找了纹理映射失败的常见原因,包括this question,但均无济于事。正在加载的图像文件为 64x64,有效的 2 次方大小。

请不要害怕,因为这是在 D 中 - 它几乎完全是 C 风格的 SDL 和 OpenGL 调用。

SDL 初始化代码:

if (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) == -1 ||
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0) == -1)
    throw new Exception("An OpenGL attribute could not be set!");

uint videoFlags = SDL_OPENGL | SDL_HWSURFACE | SDL_ANYFORMAT;

if (threadsPerCPU() > 1)
    videoFlags |= SDL_ASYNCBLIT;

SDL_Surface* screen = SDL_SetVideoMode(800, 600, 32, videoFlags);

if (screen == null)
    throw new Exception("SDL_SetVideoMode failed!");

OpenGL初始化代码:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0., 800, 600, 0., 0., 1.);
glMatrixMode(GL_MODELVIEW);

glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnable(GL_TEXTURE_2D);

glClearColor(0.f, 0.f, 0.f, 0.f);

纹理加载代码:

SDL_Surface* s = IMG_Load(toStringz("hello.png"));

if (s == null)
    throw new Exception("Image file could not be loaded!");

uint texFormat;

switch (s.format.BytesPerPixel)
{
case 4:
    texFormat = (s.format.Rmask == 0x000000ff ? GL_RGBA : GL_BGRA);
    break;
case 3:
    texFormat = (s.format.Rmask == 0x000000ff ? GL_RGB : GL_BGR);
    break;
default:
    throw new Exception("Bad pixel format!");
    break;
}

if ((s.w & (s.w - 1)) != 0)
    throw new Exception("Width must be a power of 2!");
if ((s.h & (s.h - 1)) != 0)
    throw new Exception("Height must be a power of 2!");

uint glName;

glGenTextures(1, &glName);

glBindTexture(GL_TEXTURE_2D, glName);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, s.format.BytesPerPixel, s.w, s.h, 0,
    texFormat, GL_UNSIGNED_BYTE, s.pixels);

SDL_FreeSurface(s);

渲染代码:

glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_QUADS);
    glColor4ub(255, 255, 255, 255);
    glBindTexture(GL_TEXTURE_2D, glName);
    glTexCoord2i(0, 0); glVertex2i(0, 0);
    glTexCoord2i(1, 0); glVertex2i(64, 0);
    glTexCoord2i(1, 1); glVertex2i(64, 64);
    glTexCoord2i(0, 1); glVertex2i(0, 64);
glEnd();

SDL_GL_SwapBuffers();

我的程序使用 Derelict2,这是一个为 D 提供 SDL 和 OpenGL 绑定的库。

关于这里到底出了什么问题有什么想法吗?

编辑:为了将来参考,这是我的问题的解决方案:

http://www.opengl.org/wiki/Common_Mistakes#Creating_a_Texture

我需要在调用glTexImage2D 之前设置几个参数,否则我的纹理在技术上是不完整的。在该调用之前添加以下四行就可以了:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

【问题讨论】:

  • glTexImage 的第三个参数,“格式”不是每像素字节数。历史上,值 1、2、3、4 被 OpenGL-1.0 接受。由于 OpenGL-1.1 及更高版本,格式参数只接受定义明确的标记,如 GL_RGBA、GL_RGB 等,其数值与实际格式无关。
  • 请忘记“OpenGL初始化”的概念。是的,你加载纹理和东西,但在任何现实世界的应用程序中,这不是一次性的,而是按需发生的。所有渲染状态,即投影、清晰颜色、视口等,都应该在渲染过程中需要它们之前设置。您在“OpenGL 初始化代码”部分中放置的所有内容都属于“渲染代码”部分的开头。
  • @datenwolf:得分。关于您的第一条评论,我使用的文档一定已经过时了,所以我将更新调用以改用其中一个 OpenGL 枚举值。关于第二条评论,我认为在我的特定应用程序中将投影、视口等内容集中到初始化代码中是合适的,但这只是因为我的特定应用程序只使用场景的一个视角(只是一个静态 2D 视图,所以我可以做硬件加速的二维绘图)。不过我绝对明白你的意思。
  • 也许我会将所谓的“init”代码的那些部分拆分成一个单独的函数以增加清晰度,而且因为我现在意识到调整视频输出的大小可能需要更改视口在初始化时间之后。

标签: opengl graphics sdl d texture-mapping


【解决方案1】:

一个常见的错误是创建/使用不完整的纹理,请参阅here

您的代码没有显示任何调用:

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR/*or GL_NEAREST*/);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR/*or GL_NEAREST*/);

并且也不显示任何 mipmap 创建。

您的问题可能与您的纹理不完整有关。

【讨论】:

  • 哇,你完全正确。添加链接页面中列出的四行后,纹理现在完全按预期呈现。感谢您带领我朝着正确的方向前进!
  • 我想知道为什么 glGetError 在 glTexImage2D 之后没有指示任何内容;也许它可用的错误代码只是不包括这种事情。无论如何,至少我现在有一些工作,所以我可以在以后担心 mipmap 或其他修改。
  • hm,glTexImage2D 无法指示/检测错误,因为它用于构造纹理,并且在此过程中,它对于不完整的纹理是“合法的”。也许“glBindTexture”可以将其检测为错误,但我不确定,与着色器一样,如果您仅在 mipmap 0 中对纹理进行采样,它可能会起作用(未经测试)。一旦你被这个问题咬过很多次,你就会习惯它;)
【解决方案2】:

这里只是一个模糊的理论:您是否尝试过逆时针而不是顺时针绘制顶点?

glTexCoord2i(0, 0); glVertex2i(0, 0);
glTexCoord2i(0, 1); glVertex2i(0, 64);
glTexCoord2i(1, 1); glVertex2i(64, 64);
glTexCoord2i(1, 0); glVertex2i(64, 0);

【讨论】:

  • 刚改方向重新编译;同样的交易。 :(
  • 纹理加载代码中的 glBindTexture 调用是否有原因(至少在它所在的位置)?我原以为它会在 glTexImage2D 调用之后进行 - 不过自从我使用 OpenGL 以来已经有一段时间了。
  • @Xono:据我所知,glBindTexture 调用告诉 OpenGL 状态机“我们现在正在使用这个纹理”,而 glTexImage2D 调用隐含地理解它应该适用于当前绑定的纹理。当然,如果我错了,请纠正我。
  • 不,你在这方面是对的,去查看 NeHe 的纹理映射教程(如果你有兴趣,nehe.gamedev.net/data/lessons/lesson.asp?lesson=06):P 只有我能想到的其他东西:没有翻译远离相机的多边形,或者调用 glColor4ub 覆盖顶点定义中的纹理数据(不应该)。
  • 是的,我看过 NeHe 关于这个主题的教程(部分是我的代码所基于的)。根据我的经验,删除glColor 调用只会使判断四边形是否绘制变得更加困难,因为通过调用,我可以保证得到一个白色正方形,因此很容易判断四边形绘制了但纹理映射本身并没有发生。
【解决方案3】:

您不需要在paintGL 函数中使用glOrtho(0., 800, 600, 0., 0., 1.); 吗?

【讨论】:

  • 很确定这不是它,因为我肯定会得到一个屏幕上的白色方块。 glOrtho 问题将是场景的位置/方向问题,对吗?
【解决方案4】:

尝试启用GL_COLOR_MATERIAL?我有一段时间没有使用固定功能管道,但我认为这可能会做到。

【讨论】:

  • 我在初始化代码中添加了glEnable(GL_COLOR_MATERIAL),但不幸的是,它似乎没有帮助。
猜你喜欢
  • 1970-01-01
  • 2011-05-04
  • 2011-03-16
  • 1970-01-01
  • 2011-08-25
  • 2012-07-28
  • 2011-05-16
  • 2017-11-26
  • 2014-12-30
相关资源
最近更新 更多