OpenGL ES 2.0(专门针对 iPhone)渲染略有偏差。最好的猜测是投影矩阵问题

发布于 2024-09-26 10:24:37 字数 5357 浏览 2 评论 0原文

因此,我购买了 O'reilly 的 Iphone 3D 编程,并发现了我认为其中代码中的错误。但是我无法弄清楚问题是什么,除非我弄清楚,否则我无法继续使用我自己的代码。

我将把我认为合适的代码粘贴到这篇文章中,但幸运的是所有代码都可以在线获取: http://examples.oreilly.com/9780596804831/HelloCone/

我遇到的问题是使用他们的 OpenGL ES 2.0 渲染器,它不会出现在他们的 ES 1.1 渲染器中。

所以我注意到圆锥体没有完全渲染在正确的位置。为了测试这一点,我更改了 ModelViewMatrix 以准确地在 FrustumNear 平面上渲染。所以圆锥体应该看起来完全被切成两半。当我使用 ES 1.1 渲染执行此操作时,情况就是这样,当我在 OpenGL ES 2.0 中执行相同操作时,情况却并非如此。圆锥体的大部分都在那里,但稍微被削掉了。这意味着它没有准确落在锥台的近表面上。

这是创建和设置投影矩阵的初始化代码:

void RenderingEngine2::Initialize(int width, int height)
{
const float coneRadius = 0.5f;
const float coneHeight = 1.0f;
const int coneSlices = 40;

{
    // Allocate space for the cone vertices.
    m_cone.resize((coneSlices + 1) * 2);

    // Initialize the vertices of the triangle strip.
    vector<Vertex>::iterator vertex = m_cone.begin();
    const float dtheta = TwoPi / coneSlices;
    for (float theta = 0; vertex != m_cone.end(); theta += dtheta) {

        // Grayscale gradient
        float brightness = abs(sin(theta));
        vec4 color(brightness, brightness, brightness, 1);

        // Apex vertex
        vertex->Position = vec3(0, 1, 0);
        vertex->Color = color;
        vertex++;

        // Rim vertex
        vertex->Position.x = coneRadius * cos(theta);
        vertex->Position.y = 1 - coneHeight;
        vertex->Position.z = coneRadius * sin(theta);
        vertex->Color = color;
        vertex++;
    }
}

{
    // Allocate space for the disk vertices.
    m_disk.resize(coneSlices + 2);

    // Initialize the center vertex of the triangle fan.
    vector<Vertex>::iterator vertex = m_disk.begin();
    vertex->Color = vec4(0.75, 0.75, 0.75, 1);
    vertex->Position.x = 0;
    vertex->Position.y = 1 - coneHeight;
    vertex->Position.z = 0;
    vertex++;

    // Initialize the rim vertices of the triangle fan.
    const float dtheta = TwoPi / coneSlices;
    for (float theta = 0; vertex != m_disk.end(); theta += dtheta) {
        vertex->Color = vec4(0.75, 0.75, 0.75, 1);
        vertex->Position.x = coneRadius * cos(theta);
        vertex->Position.y = 1 - coneHeight;
        vertex->Position.z = coneRadius * sin(theta);
        vertex++;
    }
}

// Create the depth buffer.
glGenRenderbuffers(1, &m_depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER,
                      GL_DEPTH_COMPONENT16,
                      width,
                      height);

// Create the framebuffer object; attach the depth and color buffers.
glGenFramebuffers(1, &m_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                          GL_COLOR_ATTACHMENT0,
                          GL_RENDERBUFFER,
                          m_colorRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                          GL_DEPTH_ATTACHMENT,
                          GL_RENDERBUFFER,
                          m_depthRenderbuffer);

// Bind the color buffer for rendering.
glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);

// Set up some GL state.
glViewport(0, 0, width, height);
glEnable(GL_DEPTH_TEST);

// Build the GLSL program.
m_simpleProgram = BuildProgram(SimpleVertexShader, SimpleFragmentShader);
glUseProgram(m_simpleProgram);

// Set the projection matrix.
GLint projectionUniform = glGetUniformLocation(m_simpleProgram, "Projection");
mat4 projectionMatrix = mat4::Frustum(-1.6f, 1.6, -2.4, 2.4, 5, 10);
glUniformMatrix4fv(projectionUniform, 1, 0, projectionMatrix.Pointer());
}

这是渲染代码。正如您所看到的,我更改了 ModelVieMatrix,将圆锥体放置在近视锥体面的左下角。

void RenderingEngine2::Render() const
{
GLuint positionSlot = glGetAttribLocation(m_simpleProgram, "Position");
GLuint colorSlot = glGetAttribLocation(m_simpleProgram, "SourceColor");

glClearColor(0.5f, 0.5f, 0.5f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnableVertexAttribArray(positionSlot);
glEnableVertexAttribArray(colorSlot);

mat4 旋转(m_animation.Current.ToMatrix()); mat4 翻译 = mat4::Translate(-1.6, -2.4, -5);

// Set the model-view matrix.
GLint modelviewUniform = glGetUniformLocation(m_simpleProgram, "Modelview");
mat4 modelviewMatrix = rotation * translation;
glUniformMatrix4fv(modelviewUniform, 1, 0, modelviewMatrix.Pointer());

// Draw the cone.
{
  GLsizei stride = sizeof(Vertex);
  const GLvoid* pCoords = &m_cone[0].Position.x;
  const GLvoid* pColors = &m_cone[0].Color.x;
  glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, stride, pCoords);
  glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, m_cone.size());
}

// Draw the disk that caps off the base of the cone.
{
  GLsizei stride = sizeof(Vertex);
  const GLvoid* pCoords = &m_disk[0].Position.x;
  const GLvoid* pColors = &m_disk[0].Color.x;
  glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, stride, pCoords);
  glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);
  glDrawArrays(GL_TRIANGLE_FAN, 0, m_disk.size());
}

glDisableVertexAttribArray(positionSlot);
glDisableVertexAttribArray(colorSlot);
}

So I bought O'reilly's Iphone 3D programming and found what I believe to be a bug in there code. However I can't figure out what the problem is, and unless I do I can't move forward with my own code.

I will paste what I consider to be the appropriate code into this post but luckily all the code is available online at:
http://examples.oreilly.com/9780596804831/HelloCone/

The problem I am having is with their OpenGL ES 2.0 renderer, it does not show up in their ES 1.1 renderer.

So what I have been noticing is that the cone does not render exactly in the correct position. To test this I changed the ModelViewMatrix to render exactly on the FrustumNear plane. So the cone should appear cut completely in two. When I do this with the ES 1.1 render this is the case, when I do the same in OpenGL ES 2.0 however it is not. The cone is for the most part there, but slightly shaved off. Meaning it is not landing exactly on the fustrum's near face.

Here is the initialization code where the projection matrix is created and set up:

void RenderingEngine2::Initialize(int width, int height)
{
const float coneRadius = 0.5f;
const float coneHeight = 1.0f;
const int coneSlices = 40;

{
    // Allocate space for the cone vertices.
    m_cone.resize((coneSlices + 1) * 2);

    // Initialize the vertices of the triangle strip.
    vector<Vertex>::iterator vertex = m_cone.begin();
    const float dtheta = TwoPi / coneSlices;
    for (float theta = 0; vertex != m_cone.end(); theta += dtheta) {

        // Grayscale gradient
        float brightness = abs(sin(theta));
        vec4 color(brightness, brightness, brightness, 1);

        // Apex vertex
        vertex->Position = vec3(0, 1, 0);
        vertex->Color = color;
        vertex++;

        // Rim vertex
        vertex->Position.x = coneRadius * cos(theta);
        vertex->Position.y = 1 - coneHeight;
        vertex->Position.z = coneRadius * sin(theta);
        vertex->Color = color;
        vertex++;
    }
}

{
    // Allocate space for the disk vertices.
    m_disk.resize(coneSlices + 2);

    // Initialize the center vertex of the triangle fan.
    vector<Vertex>::iterator vertex = m_disk.begin();
    vertex->Color = vec4(0.75, 0.75, 0.75, 1);
    vertex->Position.x = 0;
    vertex->Position.y = 1 - coneHeight;
    vertex->Position.z = 0;
    vertex++;

    // Initialize the rim vertices of the triangle fan.
    const float dtheta = TwoPi / coneSlices;
    for (float theta = 0; vertex != m_disk.end(); theta += dtheta) {
        vertex->Color = vec4(0.75, 0.75, 0.75, 1);
        vertex->Position.x = coneRadius * cos(theta);
        vertex->Position.y = 1 - coneHeight;
        vertex->Position.z = coneRadius * sin(theta);
        vertex++;
    }
}

// Create the depth buffer.
glGenRenderbuffers(1, &m_depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER,
                      GL_DEPTH_COMPONENT16,
                      width,
                      height);

// Create the framebuffer object; attach the depth and color buffers.
glGenFramebuffers(1, &m_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                          GL_COLOR_ATTACHMENT0,
                          GL_RENDERBUFFER,
                          m_colorRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                          GL_DEPTH_ATTACHMENT,
                          GL_RENDERBUFFER,
                          m_depthRenderbuffer);

// Bind the color buffer for rendering.
glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);

// Set up some GL state.
glViewport(0, 0, width, height);
glEnable(GL_DEPTH_TEST);

// Build the GLSL program.
m_simpleProgram = BuildProgram(SimpleVertexShader, SimpleFragmentShader);
glUseProgram(m_simpleProgram);

// Set the projection matrix.
GLint projectionUniform = glGetUniformLocation(m_simpleProgram, "Projection");
mat4 projectionMatrix = mat4::Frustum(-1.6f, 1.6, -2.4, 2.4, 5, 10);
glUniformMatrix4fv(projectionUniform, 1, 0, projectionMatrix.Pointer());
}

And here is the Render code. As you can see I have changed the ModelVieMatrix to place the cone on the bottom left corner of the near Frustum face.

void RenderingEngine2::Render() const
{
GLuint positionSlot = glGetAttribLocation(m_simpleProgram, "Position");
GLuint colorSlot = glGetAttribLocation(m_simpleProgram, "SourceColor");

glClearColor(0.5f, 0.5f, 0.5f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnableVertexAttribArray(positionSlot);
glEnableVertexAttribArray(colorSlot);

mat4 rotation(m_animation.Current.ToMatrix());
mat4 translation = mat4::Translate(-1.6, -2.4, -5);

// Set the model-view matrix.
GLint modelviewUniform = glGetUniformLocation(m_simpleProgram, "Modelview");
mat4 modelviewMatrix = rotation * translation;
glUniformMatrix4fv(modelviewUniform, 1, 0, modelviewMatrix.Pointer());

// Draw the cone.
{
  GLsizei stride = sizeof(Vertex);
  const GLvoid* pCoords = &m_cone[0].Position.x;
  const GLvoid* pColors = &m_cone[0].Color.x;
  glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, stride, pCoords);
  glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, m_cone.size());
}

// Draw the disk that caps off the base of the cone.
{
  GLsizei stride = sizeof(Vertex);
  const GLvoid* pCoords = &m_disk[0].Position.x;
  const GLvoid* pColors = &m_disk[0].Color.x;
  glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, stride, pCoords);
  glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);
  glDrawArrays(GL_TRIANGLE_FAN, 0, m_disk.size());
}

glDisableVertexAttribArray(positionSlot);
glDisableVertexAttribArray(colorSlot);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

嘿嘿嘿 2024-10-03 10:24:39

看来我找到了自己问题的答案。

O'Reilly 代码中的投影矩阵计算不正确。

在他们的代码中,他们有:

T a = 2 * near / (right - left);
T b = 2 * near / (top - bottom);
T c = (right + left) / (right - left);
T d = (top + bottom) / (top - bottom);
T e = - (far + near) / (far - near);
T f = -2 * far * near / (far - near);
Matrix4 m;
m.x.x = a; m.x.y = 0; m.x.z = 0; m.x.w = 0;
m.y.x = 0; m.y.y = b; m.y.z = 0; m.y.w = 0;
m.z.x = c; m.z.y = d; m.z.z = e; m.z.w = -1;
m.w.x = 0; m.w.y = 0; m.w.z = f; m.w.w = 1;
return m;

但这不是投影矩阵。 mww 应该是 0 而不是 1。

Matrix4 m;
m.x.x = a; m.x.y = 0; m.x.z = 0; m.x.w = 0;
m.y.x = 0; m.y.y = b; m.y.z = 0; m.y.w = 0;
m.z.x = c; m.z.y = d; m.z.z = e; m.z.w = -1;
m.w.x = 0; m.w.y = 0; m.w.z = f; m.w.w = 0;
return m;

Looks like I found the answer to my own question.

The projection matrix in the O'Reilly code is being calculated incorrectly.

In their code they have:

T a = 2 * near / (right - left);
T b = 2 * near / (top - bottom);
T c = (right + left) / (right - left);
T d = (top + bottom) / (top - bottom);
T e = - (far + near) / (far - near);
T f = -2 * far * near / (far - near);
Matrix4 m;
m.x.x = a; m.x.y = 0; m.x.z = 0; m.x.w = 0;
m.y.x = 0; m.y.y = b; m.y.z = 0; m.y.w = 0;
m.z.x = c; m.z.y = d; m.z.z = e; m.z.w = -1;
m.w.x = 0; m.w.y = 0; m.w.z = f; m.w.w = 1;
return m;

However this is not the projection matrix. m.w.w should be 0 not 1.

Matrix4 m;
m.x.x = a; m.x.y = 0; m.x.z = 0; m.x.w = 0;
m.y.x = 0; m.y.y = b; m.y.z = 0; m.y.w = 0;
m.z.x = c; m.z.y = d; m.z.z = e; m.z.w = -1;
m.w.x = 0; m.w.y = 0; m.w.z = f; m.w.w = 0;
return m;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文