【问题标题】:Displaying texture from raw data in Open GL native Android在 Open GL 原生 Android 中显示来自原始数据的纹理
【发布时间】:2014-09-08 17:05:54
【问题描述】:

我正在尝试从原始数据中绘制纹理,其中元素是无符号字符(或无符号整数),每个 3 个后续元素(RGB)代表像素数据。 我想要的是 *在我的手机屏幕 (1920*1080)* 上显示这个 rgb 原始数据 (width=640 ,height =480)。 这是我的代码! 我正在使用 egl 准备图形环境,如下所示:

bool Render::initializing(ANativeWindow* window)
{
const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE,
        8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE };
EGLDisplay display;
EGLConfig config;
EGLint numConfigs;
EGLint format;
EGLSurface surface;
EGLContext context;
EGLint width;
EGLint height;
GLfloat ratio;

Log::info("Initializing context");

if ((display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) {
    Log::error("eglGetDisplay() returned error %d", eglGetError());
    return false;
}
if (!eglInitialize(display, 0, 0)) {
    Log::error("eglInitialize() returned error %d", eglGetError());
    return false;
}

if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs)) {
    Log::error("eglChooseConfig() returned error %d", eglGetError());
    destroy();
    return false;
}

if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) {
    Log::error("eglGetConfigAttrib() returned error %d", eglGetError());
    destroy();
    return false;
}
Log::info("Setting buffer geometry");
ANativeWindow_setBuffersGeometry(window, 0, 0, format);
Log::info("End Setting buffer geometry");
if (!(surface = eglCreateWindowSurface(display, config, window, 0))) {
    Log::error("eglCreateWindowSurface() returned error %d", eglGetError());
    destroy();
    return false;
}

if (!(context = eglCreateContext(display, config, 0, 0))) {
    Log::error("eglCreateContext() returned error %d", eglGetError());
    destroy();
    return false;
}

if (!eglMakeCurrent(display, surface, surface, context)) {
    Log::error("eglMakeCurrent() returned error %d", eglGetError());
    destroy();
    return false;
}

if (!eglQuerySurface(display, surface, EGL_WIDTH, &width)
        || !eglQuerySurface(display, surface, EGL_HEIGHT, &height)) {
    Log::error("eglQuerySurface() returned error %d", eglGetError());
    destroy();
    return false;
}
//If Landscape
/*if (!eglQuerySurface(display, surface, EGL_WIDTH, &width) ||
 !eglQuerySurface(display, surface, EGL_HEIGHT, &height)) {
 Log::error("eglQuerySurface() returned error %d", eglGetError());
 destroy();
 return false;
 }*/

//
_display = display;
_surface = surface;
_context = context;

} }

这用于绘制 rgb 原始数据: void Render::drawRGBData(unsigned char *rgb) {

glEnable(GL_TEXTURE_2D);
glGenTextures(1, &gl_rgb_tex);
glBindTexture(GL_TEXTURE_2D, gl_rgb_tex);

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);


//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 640, 480, 0, GL_RGB,
        GL_UNSIGNED_BYTE, (GLubyte*) rgb);

//**Drawing***/

float tricoords[12] = { 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0,
        1.0, 0.0 };
float texcoords[12] = { 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0,
        1.0, 0.0 };

/*float tricoords[12] = { -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0,
 1.0, -1.0 };
 float texcoords[12] = { 0-1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0,
 1.0, -1.0 };*/


glBindTexture(GL_TEXTURE_2D, gl_rgb_tex);
glEnableClientState(GL_VERTEX_ARRAY); //enable gl vertex pointer to be used in draw fct
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glVertexPointer(2, GL_FLOAT, 0, tricoords);
glTexCoordPointer(2, GL_FLOAT, 0, texcoords);

glDrawArrays(GL_TRIANGLES, 0, 8);

glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

} 

最后一个方法在循环中调用,对于每个新接收到的 rgb 数据。 我这样做是为了交换缓冲区:

if (!eglSwapBuffers(renderer->_display, renderer->_surface)) {
Log::error("eglSwapBuffers() returned error %d", eglGetError());
        }

这是我在手机屏幕上看到的截图,分辨率为 1080x1920。

http://s1.postimg.org/hh4z4j2gv/Screenshot_2014_07_17_17_55_17_Convert_Image.jpg

问题出在绘制纹理的过程中,并将像素从原始数据正确映射到要显示的纹理。

【问题讨论】:

  • 您提交了 6 个顶点,前 3 个是顺时针三角形,后 3 个不是有效三角形。您的 texcoords 似乎也不正确。当您只有 6 个索引时,您正在为 8 个索引调用 glDrawArrays... 注释掉的 tricoords 似乎是正确的。

标签: android c++ opengl-es texture2d


【解决方案1】:

首先让我们确保您的三角形正确渲染。

你似乎提交了无效的三角形,所以试试这个:

float tricoords[12] = { 0.0, 0.0, 
                        1.0, 0.0, 
                        1.0, 1.0, 
                        0.0, 0.0, 
                        1.0, 1.0, 
                        0.0, 1.0 };
float texcoords[12] = { 0.0, 0.0, 
                        1.0, 0.0, 
                        1.0, 1.0, 
                        0.0, 0.0, 
                        1.0, 1.0,
                        0.0, 1.0 };

接下来您尝试绘制 8 个顶点...两个三角形应该是 6:

glDrawArrays(GL_TRIANGLES, 0, 6);

确保你的三角形在没有纹理的情况下渲染,所以传递一个颜色数组:

glDisable(GL_TEXTURE_2D);
glEnableClientState(GL_COLOR_ARRAY);
float colors[18] = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 
                     0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0 }; 
glColorPointer(3, GL_FLOAT, 0, colors);

现在您已经确认三角形可以正确渲染,这里有一个用于加载和显示 .bmp 文件的资源:

http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/#Loading__BMP_images_yourself

【讨论】:

    【解决方案2】:

    纹理出现在屏幕上的事实表明您的设置代码是正确的。

    最有可能的问题是传递给 glTexImage2D 的有关原始数据大小或格式的错误信息。我会尝试的第一件事是交换宽度和高度,因为纹理在内存中的排列方式可能与 OpenGL 的预期不同。

    【讨论】:

      【解决方案3】:

      不要忘记纹理必须是 2 的幂。虽然我很惊讶你在屏幕上能看到任何东西。我会创建一个 1k x 1k 的纹理,然后传入校正后的纹理坐标。

      【讨论】:

        【解决方案4】:

        感谢大家的回答。 现在,我已经使用 Pondwater 代码来显示简单的彩色三角形我已经更改了颜色表(每种颜色应该在 4 个通道上):

        float tricoords[12] = { -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0,
                1.0, -1.0, 1.0 };
        float texcoords[12] = { -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0,
                1.0, -1.0, 1.0 };
        
        float colors[24] = { 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
                0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 };
        

        它按预期完美运行。

        现在很清楚 fentelia 说问题与我的原始数据的组织方式有关,因为当我返回原始数据时,我得到了奇怪的结果,我需要帮助,如何在原生 android 中正确读取 bmp 图像,并通过glTexImage2D或glSubTexImage2D正确传输到opengl缓冲区。 谢谢..

        【讨论】:

        • 这里是加载和显示 .bmp 图像的资源:@​​987654321@
        • 我使用了这个 tuto,并在我的屏幕上得到了这个 nce 结果,用于 8 位灰度图像。
        • 我使用了这个 tuto,我在屏幕上得到了一个 8 位灰度图像的不错结果。著名的 lena drive.google.com/file/d/… 仍然是如何在 512x512 像素上获得它的问题,而不是将其调整为 1080x1080像素显示。我使用 glTexImage2D 与 RGBA 和 512 作为宽度和高度。
        • 现在只需将其加载到图像原生尺寸的 glTexImage2D 中,大多数现代硬件并不关心它是否不是 2 的幂(尽管对于性能和 mipmapping 它确实有帮助)。要以 1080x1080 像素显示它,您需要将四边形光栅化到屏幕上的该尺寸。您提供的纹理坐标不正确,它们应该是左下角的 0,0 和右上角的 1,1。这将导致图像被插值到四边形的大小。
        • 将 tex 坐标更改为 { 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0 }; GL_TEXTURE_WRAP_S 和 GL_TEXTURE_WRAP_T 参数告诉光栅化器如何解释 0 到 1 范围之外的纹理坐标。在您的情况下,这会导致重复。但是,您应该已经获得了 4 张图片...您可以编辑您的 OP 并发布您当前的代码吗?
        猜你喜欢
        • 2016-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-15
        • 2014-11-07
        • 2019-10-14
        • 2016-12-04
        • 1970-01-01
        相关资源
        最近更新 更多