【问题标题】:Drawing a cube in iOS with OpenGL and GLKit使用 OpenGL 和 GLKit 在 iOS 中绘制立方体
【发布时间】:2015-06-15 20:05:09
【问题描述】:

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

所以基本上我的理解是:

  1. 模型最初位于原点,相机也是如此
  2. 然后我们使用 glm::lookAt 将相机移动到正确的位置 (在 iOS 中相当于什么?)
  3. 应用投影变换从相机空间移动到齐次单位立方体空间

从一个基本的 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);
}

【问题讨论】:

    标签: ios opengl-es glkit


    【解决方案1】:

    首先要回答,您正在寻找和缺少的是 GLKMatrix4MakeLookAt。剩下的只是如果您有兴趣深入了解。

    您的假设似乎是正确的,但我认为您未能理解矩阵系统和 openGL 的真正工作原理。不过,您似乎确实了解如何使用它。因此,首先我们通常查看的是 3 个矩阵分量,然后可以将它们作为乘积插入到着色器中,或者作为每个分量传递给着色器并在那里相乘。

    第一个组件是投影矩阵。该组件反映屏幕上的投影,通常设置为“正交”或“平截头体”。 “正交”是一种正交投影,这意味着无论距离多远,对象都将呈现相同的大小。 “平截头体”将产生一种效果,使对象根据距离显得更大或更小。在您的情况下,您正在使用具有便利功能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 个边框值(left、right、top、bottom)、near 和远 clipping 平面。此方法的定义是,任何具有Z 值等于near 的顶点位置都将被转换为-1,而Z 值等于far 的每个位置都将被转换为1。所有中间值将取线性插值。至于X 和Y,它们将根据转换后的Z 值进行缩放,因此对于Z 0 将缩放0,Z near 将缩放1.0,其余为1.0线性外推。

    lookAt 实际上与模型矩阵非常相似,但相反。如果你向后移动相机,它与向前移动物体是一样的,如果你向左旋转,物体会看起来像被移动和向右旋转等等......

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

    【讨论】:

    • 很有帮助的解释比你这么多!它为我连接了点,因为我在这里和那里阅读文章而无法连接它们
    • 是的,这些系统可能非常令人沮丧,因为有些系统很难理解。您可以找到数百个示例,而不是其中 2 个看起来相同的示例。我很高兴我的解释对您有所帮助,尽管这对于该领域的非专家来说是相当多的。我很高兴它对你有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多