0

我在 OpenGLES 2.0 中的一个简单平面上映射 iPhone 相机输出时遇到问题。由于某种原因,通过 OpenGL 生成的纹理CVOpenGLESTextureCacheCreateTextureFromImage被翻转和旋转。

这是我的情况:我制作了一个解析这个简单平面对象的 Wavefront .obj 加载器:

v -0.5 -0.5 0
v 0.5 -0.5 0
v -0.5 0.5 0
v 0.5 0.5 0

vt 0 0 0
vt 1 0 0
vt 0 1 0
vt 1 1 0

f 4/4 3/3 1/1 
f 2/2 4/4 1/1 

就我而言,我的纹理映射就像它必须的那样工作。我已经通过将一个简单的 png 图像映射到平面上来验证这一点。它正确显示。

(仅作记录:我在 iPhone 坐标系中加载图像,翻转图像像素以匹配 OpenGL 的左上纹理坐标系并映射所有内容)。结果:有效!

因此,在稍微改组我的代码并将相机像素缓冲区输入我的纹理单元之后,出现了问题(或者这可能是预期的行为,我应该以一种或另一种方式来应对这种情况?欢迎任何建议,只要它是不是 CPU 繁重的代码)。

这是我的代码:其中一些受到Brad Larson的 ColorTracking 示例和 Apple 的 GLCameraRipple 示例的启发。

捕获输出的代码:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    [self.delegate processNewCameraFrame:pixelBuffer];
}

在传递图像缓冲区 ref 之后,它会在这里结束:

- (void)updateCameraFrame:(CVImageBufferRef)pCameraFrame
{
    if(cameraTextureMaterial)
    {
        cameraTextureMaterial->updateWithCameraFrame(pCameraFrame);
    }
}

CamerTexture材质:

void CameraTextureMaterial::updateWithCameraFrame(CVImageBufferRef pixelBuffer)
{
    if(!_videoTextureCache)
    {
        cout << "No video texture cache" << endl;
        return;
    }

    cleanup();

    CVReturn err;
    size_t width = CVPixelBufferGetWidth(pixelBuffer);
    size_t height = CVPixelBufferGetHeight(pixelBuffer);

    glActiveTexture(GL_TEXTURE0);

    err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
                                                       _videoTextureCache,
                                                       pixelBuffer,
                                                       NULL,
                                                       GL_TEXTURE_2D,
                                                       GL_RGBA,
                                                       width,
                                                       height,
                                                       GL_BGRA,
                                                       GL_UNSIGNED_BYTE,
                                                       0,
                                                       &_lumaTexture);
    if (err)
    {
        cout << "Error at CVOpenGLESTextureCacheCreateTextureFromImage" << endl;
    }

    glBindTexture(CVOpenGLESTextureGetTarget(_lumaTexture), CVOpenGLESTextureGetName(_lumaTexture));
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}

我不包括纹理缓存的初始化和清理,因为这对我的纹理方向问题无关紧要。

关于如何为我的纹理获得正确方向的任何建议?

4

2 回答 2

2

老实说,我没有看到将 OBJ 用于如此简单的几何图形的好处。最后,我们只是在谈论 2 个三角形 :),它们很容易在您的代码中动态创建。

除了这个“装饰性”注释之外,OpenGL 默认情况下在非翻转图像上工作以进行纹理处理。您从相机链接的纹理很可能默认是翻转的(这在很大程度上取决于格式的互联网数据组织,而不是您打开图片时看到的内容)。

一种快速而肮脏的解决方案可能是使用以下技巧:

glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glScalef(1.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);

这应该为您解决问题并节省大量计算能力。

干杯毛里齐奥

于 2012-08-07T09:50:00.607 回答
0

通过明智地选择纹理坐标,解决这个问题实际上非常容易。我通过将相机纹理映射到下面的坐标来旋转、翻转和裁剪相机纹理,并将正交场景渲染为一个新纹理,然后在我的场景中使用它。

我使用的坐标:

void CameraClipPlaneObject3D::init()
{
    // Create plane object
    vertices = shared_ptr<Vertex3DVector>(new Vertex3DVector());
    vertices->push_back(Vertex3D(1, -1, 0));
    vertices->push_back(Vertex3D(1, 1, 0));
    vertices->push_back(Vertex3D(-1, 1, 0));
    vertices->push_back(Vertex3D(-1, -1, 0));

    // Create texture coords
    textureCoords = shared_ptr<Texture2DVector>(new Texture2DVector());
    textureCoords->push_back(Texture2D(0.875, 0));
    textureCoords->push_back(Texture2D(0.125, 0));
    textureCoords->push_back(Texture2D(0.125, 1));
    textureCoords->push_back(Texture2D(0.875, 1));

    // Create indices
    indices = shared_ptr<IndexVector>(new IndexVector());
    indices->push_back(0);
    indices->push_back(1);
    indices->push_back(2);
    indices->push_back(2);
    indices->push_back(3);
    indices->push_back(0);
}

以下是我将平面渲染为新纹理的方法:

  1. 首先像平常一样创建纹理(不要忘记纹理过滤)
  2. 然后像往常一样创建一个帧缓冲区
  3. 将纹理颜色缓冲区附加到这个新帧缓冲区的颜色附件:
  4. 在您的渲染循环中,绑定到这个新的帧缓冲区并渲染您的场景。

一些示例代码:

void TextureRenderTarget::init()
{
    // Create texture to render to
    texture = new RenderTexture(width, height, GL_LINEAR, GL_LINEAR);

    // Create framebuffer and attach texture to framebuffer
    framebuffer = new Framebuffer(width, height);
    framebuffer->attachTexture(texture);
}

附上代码:

void Framebuffer::attachTexture(Texture *texture) const
{
    glBindFramebuffer(GL_FRAMEBUFFER, handle);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->getHandle(), 0);
}
于 2012-09-28T13:04:34.720 回答