OpenGL ES 无法正常工作

Posted

技术标签:

【中文标题】OpenGL ES 无法正常工作【英文标题】:OpenGL ES not working as desired 【发布时间】:2012-12-30 23:33:13 【问题描述】:

我有一个 GLKView,它几乎可以显示我想要的形状,但是有些东西仍然无法按预期工作。

      3_______________________2
      |\                     /|
      | \_ _ _ _ _ _ _ _ _ _/ |
      | /4                 5\ |
      |/_____________________\|
      0                       1

纹理映射在正面起作用,其他两个面没有真正起作用,缺少三角形

当我使用颜色时,表面看起来像想要的那样,但是背面没有在点 4 和 5 形成的边缘处连接(请看我提供的图纸以上)。 我想要(如果你从侧面看的话)三个面形成一个等边三角形。

我暂时注释掉了代码的纹理映射部分,以便您可以根据需要进行测试。

在这里我设置了我的视图(注意我的视图的尺寸。坐标系统工作正常,无需摆弄低值。面部看起来不错,但它们不好看,正如我在后面所说的加入):

    EAGLContext * context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    OpenGLShape *view = [[OpenGLShape alloc] initWithFrame:CGRectMake(0, 200, 320, 80) context:context];
    view.delegate = view;
    [view setupGL];
    [self.view addSubview:view];

- (void)setupGL 

    [EAGLContext setCurrentContext:self.myContext];

    //glEnable(GL_CULL_FACE);


    self.effect = [[GLKBaseEffect alloc] init];

    BOOL useTexture = NO;

    // Create default framebuffer object.
    glGenFramebuffers(1, &defaultFrameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, defaultFrameBuffer);

    if(useTexture)
        NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
                              [NSNumber numberWithBool:YES],
                              GLKTextureLoaderOriginBottomLeft,
                              nil];

        NSError * error;
        NSString *path = [[NSBundle mainBundle] pathForResource:@"blogcell@2x" ofType:@"png"];
        GLKTextureInfo * info = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
        if (info == nil) 
            NSLog(@"Error loading file: %@", [error localizedDescription]);
        
        self.effect.texture2d0.name = info.name;
        self.effect.texture2d0.enabled = true;

        glGenBuffers(1, &texArray);
        glBindBuffer(GL_ARRAY_BUFFER, texArray);
        glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
        glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 0,0);
        glBufferData(GL_ARRAY_BUFFER, sizeof(TexCoords), TexCoords, GL_STATIC_DRAW);


    else

        glGenBuffers(1, &colArray);
        glBindBuffer(GL_ARRAY_BUFFER, colArray);
        glEnableVertexAttribArray(GLKVertexAttribColor);
        glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, 0, 0);
        glBufferData(GL_ARRAY_BUFFER, sizeof(Color), Color, GL_STATIC_DRAW);
    

    glGenRenderbuffers(1, &depthBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 320.0f, 80.0f);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);

    glEnable(GL_DEPTH_TEST);

    glGenBuffers(1, &vertexArray);
    glBindBuffer(GL_ARRAY_BUFFER, vertexArray);
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition,3,GL_FLOAT,GL_FALSE,0,0);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);




    self.effect.transform.projectionMatrix = GLKMatrix4MakePerspective(51.4f,4.0f, 0.1f, 10.75f);
   rotMatrix = GLKMatrix4Translate(self.effect.transform.modelviewMatrix,0, 0, -3);







- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect 

    self.opaque = NO;
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    [self.effect prepareToDraw];

    glDrawArrays(GL_TRIANGLES, 0, sizeof(Vertices));

红色 = 正面(由点 0123 组成)

蓝色 = 背面(顶部 - 由 4523 点组成)

绿色 = 背面(底部 - 由点 0154 组成)

白色 = 背景

为了查看它们是否混合/剔除等,我还将这些面设为半透明 (alpha = 0.5)。

【问题讨论】:

你考虑过Cocos2d吗?这可以使使用 OpenGL ES 分配更简单,并减少您遇到的问题。 是的,过去两年我一直在使用 cocos2d,但我真的很想深入研究 OpenGL。问题是,我主要是通过自己做一些事情来学习,尤其是从我提出的问题中学习。因此,如果有人能说出我犯的错误,我会非常高兴。 您能否详细说明“不工作”?图片? 正如我在问题中所说的,这两个问题是:1)纹理没有正确映射到我的脸上,2)两个背面没有在它们应该相遇的边缘处相遇z 值为 -1.73。我用勾股定理计算了它,所以每个面都有相同的边长。 我对OpenGL的经验很少,所以我什至不知道我是否正确设置了顶点。如果我只使用颜色(没有纹理映射),那么它看起来很好(背面仍然没有在后面相遇)。但是一旦我使用纹理,形状似乎就缺少一些三角形的脸。我已经实现了一些旋转形状的代码,每当我旋转它时,我都会假设剔除效果搞砸了。 【参考方案1】:

在 OpenGL 中,相机始终位于 0,0,0,改变位置的是 3D 世界。

对于正交投影,投影矩阵由下式给出:

self.effect.transform.projectionMatrix = GLKMatrix4MakeOrtho(left, right, bottom, top, front, back);

正交投影中的对象在靠近或远离相机时看起来大小相同。

透视投影中的对象在远离相机时看起来更小。

对于透视投影,投影矩阵由下式给出:

self.effect.transform.projectionMatrix = GLKMatrix4 GLKMatrix4MakePerspective (fov, aspect, front, back);
);

对于透视投影,视场 (fov) 的工作原理与真实相机上的一样,对于较小的值,透视几乎不明显,对于较大的值,由于透视投影造成的失真很大。

fov 角度以弧度为单位,可以调整直到场景看起来适合您的应用程序

aspect是水平和垂直查看区域的屏幕纵横比。

出于实际原因,fov 以度为单位指定,因此可以按如下方式使用

GLKMatrix4MakePerspective(fov * M_PI / 180.0f,
                                          screenWidth / screenHeight,
                                          front, back);

透视投影中的近剪裁平面需要大于零,因此您需要向模型视图矩阵添加一个平移,将世界与相机稍微分开。

这个平移是在模型视图矩阵中指定的

self.effect.transform.modelviewMatrix = GLKMatrix4MakeTranslation(0, 0, -frontClippingPlane);

更新

裁剪体积需要包含所有顶点以避免z-fighting与前裁剪平面,在这种情况下,透视投影中的最终平移需要更远一些

self.effect.transform.modelviewMatrix = GLKMatrix4MakeTranslation(0, 0, -frontClippingPlane - 0.1f);

要旋转模型并将其转换到最终位置,您需要将两个转换组合如下:

GLKMatrix4 rotation = GLKMatrix4MakeRotation(angle*M_PI/180, 1, 0, 0); // angle in degrees and x,y, and z coordinates for the rotation axis
GLKMatrix4 translation = GLKMatrix4MakeTranslation( 0, 0, -front - 0.1f);
self.effect.transform.modelviewMatrix = GLKMatrix4Multiply(rotation, translation); // the order matters

以下是OpenGL的旋转轴和方向,即right-handed

这是最终效果

【讨论】:

非常好的答案,非常感谢rraallvv。但是现在正面不存在,如果我关闭剔除,我只会看到两个背面。我假设我的模型视图矩阵沿 z 轴的平移不起作用,因为我的视角没有考虑正面。旋转也很尴尬,因为我的形状不是围绕我的视野中间旋转。我非常感谢您的回答,即使您帮助我更接近我的目标,它看起来仍然完全不是我想要的样子。 好吧,我在 touchesMoved 方法中弄乱了模型视图矩阵,它基本上没有考虑到我之前添加的翻译,因此翻译根本没有任何效果。所以,现在我看到了所有的面孔,但不是全部。所以现在好像我的正面被剔除,而背面却不是真的......哦,我的上帝,这东西正在杀死我...... 太棒了。非常感谢。但是还有一件事:即使它们明显位于其他面孔后面,似乎也显示了后面的面孔。我该如何解决? 当我启用剔除时——在(几乎)完全旋转时——所有的脸都消失了。我最初是否根据它们的位置指定顶点,即如果它们在后面,则按顺时针顺序排列,因此不可见? @MartinE。 glEnable(GL_DEPTH_TEST);防止 z 值小于屏幕中当前像素的像素被渲染,您可以在 setupGL 方法中启用深度测试。 this 问题也可以通过启用 GL_CULL_FACE 来澄清正在发生的事情【参考方案2】:

您的数据正确吗?我没有看到 Vertices 数组是如何填充的。

如果您的数据与您列出的一样,那么您的顶点上的缠绕可能是一个问题,例如 red front face 0123 就是这样。

默认的绕线通常是逆时针,你已经将你的矩形描述为逆时针方向,需要正确分解为 GL_TRIANGLES:例如 0123 使 013 和 123。

但是,如果您的图表是正确的,那么当其他图表朝外时,红色矩形将面向 进入由 3 个矩形边形成的三棱柱。

要了解我的意思,将一张纸折叠成 2 个水平折痕以形成一个三棱柱,将其粘贴在连接处,并对顶点编号。

如果您在进入“纹理模式”时只为正面定义了纹理,您可能会丢失该正面。

【讨论】:

以上是关于OpenGL ES 无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 纹理无法正常工作

OpenGL正交相机缩放无法正常工作

OpenGL纹理无法正常工作-黑屏[关闭]

OpenGL ES 1.1:无法转换为 VBO

OpenGL Matrix Camera 控件,局部旋转无法正常工作

iOS OpenGL ES 2.0 旋转 1 点笛卡尔 X 弧度关于原点