使用OpenGL和GLKit在iOS中绘制一个多维数据集

时间:2015-06-15 20:05:10

标签: ios opengl-es glkit

我正在关注本教程http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/以了解查看的工作原理,但当我尝试将其应用到我的iOS应用程序时,我遇到了很多麻烦

基本上我理解的是:

  1. 模型最初位于原点,相机也是
  2. 然后我们使用glm :: lookAt将相机移动到正确的位置 (在iOS中这相当于什么?)
  3. 应用投影变换以从相机空间移动到同质单位立方体空间
  4. 从基本的iOS教程中我发现了以下投影矩阵的计算

    float aspect = fabs(self.view.bounds.size.width / self.view.bounds.size.height);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);
    _modelViewProjectionMatrix = projectionMatrix;
    

    我真的不明白......例如他们怎么想出65?

    另一个教程做到了这一点:

    glViewport(0, 0, self.view.bounds.size.width,self.view.bounds.size.height);
    

    实现: 我当前的应用只显示一个蓝色的屏幕(基本上是我的立方体的颜色) 我假设是因为相机目前处于原点

    我有以下数据集

    static const GLfloat cubeVertices[] = {
        -1.0f,-1.0f,-1.0f, // triangle 1 : begin
        -1.0f,-1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f, // triangle 1 : end
        1.0f, 1.0f,-1.0f, // triangle 2 : begin
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f, // triangle 2 : end
        1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f, 1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,
        1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
        1.0f,-1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f, 1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f,-1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f,
        1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
        1.0f,-1.0f, 1.0f
    };
    

    这是我的设置,非常基本的iOS教程

    - (void)setupGL {
        [EAGLContext setCurrentContext:self.context];
        [self loadShaders];
    
        glGenBuffers(1, &_vertexBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW);
    
        glVertexAttribPointer (GLKVertexAttribPosition,
                               3,
                               GL_FLOAT, GL_FALSE,
                               0,
                               BUFFER_OFFSET(0));
        glEnableVertexAttribArray(GLKVertexAttribPosition);
        //glBindVertexArrayOES(0);
    }
    

    和我的drawInRect和更新方法

    - (void)update {
        //glViewport(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
        float aspect = fabs(self.view.bounds.size.width / self.view.bounds.size.height);
        GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);
        _modelViewProjectionMatrix = projectionMatrix;
    
    }
    
    - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
        glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        glUseProgram(_program);
        glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
        glDrawArrays(GL_TRIANGLES, 0, 12*3);
    }
    

    和我的顶点着色器

    attribute vec4 position;
    uniform mat4 modelViewProjectionMatrix;
    
    void main() {
        gl_Position = modelViewProjectionMatrix * position;
    }
    

    和我的片段着色器

    void main() {
        gl_FragColor = vec4 (0.165, 0.427, 0.620, 1.0);
    }
    

1 个答案:

答案 0 :(得分:4)

要从答案开始,您正在寻找和缺少的是 GLKMatrix4MakeLookAt。剩下的就是你对更深入的理解感兴趣。

您的假设似乎是正确的,但我认为您无法理解矩阵系统和openGL是如何工作的。你似乎也明白如何使用它。首先,我们通常看到的是3个矩阵组件,然后可以作为产品插入到着色器中,或者作为每个组件传递到着色器并在那里相乘。

第一个组件是投影矩阵。该组件反映了屏幕上的投影,通常设置为" ortho"或"视锥体"。 " ortho"是一种正投影,这意味着无论距离如何,物体都会呈现相同的尺寸。 "视锥体"将创建一个效果,使对象看起来更大或更小,具体取决于距离。在你的情况下,你正在使用" frustum"具有便利功能GLKMatrix4MakePerspective。第一个参数描述视野,在样品中为65度角,第二个参数是应反映屏幕/视图比的纵横比,后两个是剪裁平面。使用"视锥体"将是:

    GLfloat fieldOfView = M_PI_2;
    GLfloat near = .1f;
    GLfloat far = 1000.0f;
    GLfloat screenRatio = 1.0f/2.0f;

    GLfloat right = tanf(fieldOfView)*.5f * near; // half of the tagens of field of view
    GLfloat left = -right; // symetry
    GLfloat top = right*screenRatio; // scale by screen ratio
    GLfloat bottom = -top; // symetry

    GLKMatrix4MakeFrustum(left, right, bottom, top, near, far);

第二个是视图矩阵,通常用作"相机"。要使用这个,最简单的方法是调用某种形式的" lookAt"在你的情况下是GLKMatrix4MakeLookAt。这应该回答你的问题"在iOS中这相当于什么?"。

第三个是描述坐标系中物体位置的模型矩阵。这通常用于您可以将模型放置到所需位置,设置特定旋转并根据需要进行缩放。

所以如何将它们结合在一起就是你在某种程度上将所有矩阵相乘并称之为模型 - 视图 - 投影矩阵。然后使用该矩阵乘以每个顶点位置来描述它的屏幕投影。

glViewport完全没有这个部分。此函数将定义您要绘制的缓冲区的哪个部分,仅此而已。尝试将所有值分成一半,看看会发生什么(比任何其他解释更好)。

为了解释一下从数学角度来看会发生什么,openGL实现如下:openGL将只绘制所有轴中框[-1,1]内的片段(像素)。这意味着投影中没有魔法覆盖它,但顶点位置被转换,因此正确的值适合那里。

对于frustum个实例,它将需要4个边框值(leftrighttopbottom),near和远{{ {1}}飞机。定义此方法,以便clipping值等于Z的任何顶点位置将转换为-1,并且near值等于Z的每个位置都将转换为1.所有中间都采用线性插值。对于farX,它们将根据转换的Y值进行缩放,以便{0}处的Z缩放0,Z at Z乘以1.0,然后将其余部分线性推断。

near实际上与模型矩阵非常相似,但是相反。如果向后移动相机,则与向前移动物体相同,如果向左旋转,物体将会移动并向右旋转,等等......

模型矩阵将使用基矢量和平移简单地变换所有顶点位置。该矩阵的相关部分是顶部3x3部分,它们是基础矢量,底部(或在某些实现中右边)是3x1矢量(1x3),它是平移。想象的最简单方法是在坐标系内定义的坐标系:零值(原点)位于矩阵的平移部分,X轴是3x3矩阵的第一行(列),Y是第二行和Z第三。这3个向量的长度代表了受尊重坐标的比例......它们都是一致的。