如何旋转iPhone相机输出OpenGLES纹理

时间:2012-08-06 11:56:01

标签: opengl-es opengl-es-2.0

我无法在OpenGLES 2.0的简单平面上映射iPhone相机输出。出于某种原因,通过CVOpenGLESTextureCacheCreateTextureFromImage生成的OpenGL纹理被翻转并旋转。

这是我的情况:我制作了一个解析这个简单平面对象的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];
}

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

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

CamerTextureMaterial:

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

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

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

2 个答案:

答案 0 :(得分:2)

老实说,我没有看到将OBJ用于这种简单几何体的好处。最后,我们只讨论了2个三角形:),它们很容易在您的代码中即时创建。

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

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

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

这应该可以帮到你并节省大量的计算能力。

干杯 莫里吉奥

答案 1 :(得分: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. 在渲染循环中,绑定到这个新的帧缓冲区并渲染场景。
  5. 一些示例代码:

    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);
    }
    
相关问题