Unity本机OpenGL纹理显示四次

时间:2019-02-26 11:39:22

标签: android c++ unity3d opengl-es

我目前遇到一个我根本不理解的问题。 我聘用ARCore进行由内而外的跟踪任务。由于我需要执行其他一些图像处理,因此我使用Unitys功能来加载本机c ++插件。在每一帧的最后,我将YUV_420_888格式的图像作为原始字节数组传递给我的本机插件。

在组件初始化的开始就创建了一个纹理句柄:

private void CreateTextureAndPassToPlugin()
{

    Texture2D tex = new Texture2D(640, 480, TextureFormat.RGBA32, false);

    tex.filterMode = FilterMode.Point;
    tex.Apply();
    debug_screen_.GetComponent<Renderer>().material.mainTexture = tex;

    // Pass texture pointer to the plugin
    SetTextureFromUnity(tex.GetNativeTexturePtr(), tex.width, tex.height);
}

因为我只需要灰度图像,所以我基本上忽略了图像的UV部分,而仅使用y坐标,如下所示:

uchar *p_out;
int channels = 4;
for (int r = 0; r < image_matrix->rows; r++) {
    p_out = image_matrix->ptr<uchar>(r);
    for (int c = 0; c < image_matrix->cols * channels; c++) {
        unsigned int idx = r * y_row_stride + c;
        p_out[c] = static_cast<uchar>(image_data[idx]);
        p_out[c + 1] = static_cast<uchar>(image_data[idx]);
        p_out[c + 2] = static_cast<uchar>(image_data[idx]);
        p_out[c + 3] = static_cast<uchar>(255);
    }
}

然后将图像数据的每一帧放入GL纹理:

GLuint gltex = (GLuint)(size_t)(g_TextureHandle);
glBindTexture(GL_TEXTURE_2D, gltex);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 640, 480, GL_RGBA, GL_UNSIGNED_BYTE, current_image.data);

我知道我通过创建纹理并将其作为RGBA传递来使用了太多内存,但是由于OpenGL ES3不支持GL_R8,并且GL_ALPHA总是会导致内部OpenGL错误,因此我只是将灰度值传递给每个颜色分量。

但是最终渲染纹理,如下图所示:

image

起初我以为,原因可能是其他通道具有相同的值,但是将除第一个通道以外的所有其他通道设置为任何值都没有影响。

我缺少明智的OpenGL纹理创建方法吗?

1 个答案:

答案 0 :(得分:1)

YUV_420_888是一种多平面纹理,其中亮度平面每个像素仅包含一个通道。

for (int c = 0; c < image_matrix->cols * channels; c++) {
    unsigned int idx = r * y_row_stride + c;

您的循环边界假定c在4个通道的倍数中,这对输出曲面是正确的,但是在计算输入曲面索引时,也可以使用它。您正在使用的输入平面仅包含一个通道,因此idx是错误的。

通常,您还会多次写入同一内​​存-循环每次迭代将c递增1,但是随后您写入cc+1c+2 ,和c+3,因此将覆盖您上次写入的三个值。

更简短的答案-您的OpenGL ES代码很好,但我认为您是用错误的数据填充纹理。

未经测试,但我认为您需要:

for (int c = 0; c < image_matrix->cols * channels; c += channels) {
    unsigned int idx = (r * y_row_stride) + (c / channels);