【问题标题】:How to rotate a iPhone camera output OpenGLES texture如何旋转 iPhone 相机输出 OpenGLES 纹理
【发布时间】:2012-09-28 21:04:34
【问题描述】:

我在 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];
}

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

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

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

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

【问题讨论】:

    标签: opengl-es opengl-es-2.0


    【解决方案1】:

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

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

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

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

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

    干杯 毛里齐奥

    【讨论】:

    • 感谢您的回答。平面 .obj 文件只是为了让我的问题简短。实际形状是一个更复杂的半球形物体。我也在寻找 OpenGL 2.0 的解决方案。
    • 我认为你有两个选择。第一:你实时翻转图像。这是相当昂贵的,有时可能会给表演带来问题。第二:翻转四边形纹理的坐标。
    • 我目前正在尝试将相机输入渲染到新纹理并将该纹理应用于对象。如果成功了,我会告诉你的;)
    【解决方案2】:

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

    我使用的坐标:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多