2010-10-07 49 views
0

所以我買了O'reilly的Iphone 3D編程,發現我認爲是代碼中的一個bug。但是我無法弄清楚問題所在,除非我這樣做,否則我無法繼續使用自己的代碼。OpenGL ES 2.0(專門用於iPhone)渲染稍微偏離。最好的猜測是它是一個投影矩陣問題

我會粘貼什麼,我認爲是適當的代碼到這個職位,但幸運的是,所有的代碼可在網上: 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以將錐體放置在近Frustum面的左下角。

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

回答

2

看起來像我找到了我自己的問題的答案。

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; 

然而,這不是投影矩陣。 m.w.w應該是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; 
+0

幹得好。很高興看到你沒有放棄,並一直在尋找解決方案。並感謝對修復問題的明確解釋。 – 2010-10-07 23:03:36

+0

這是學習OpenGL ES的好方法。一定要讓他們知道這個錯誤,以便他們糾正它以備未來打印。 – 2010-10-08 17:18:09

+0

是的,我昨天給作者發了電子郵件。希望他會改變在線代碼。 – Alex 2010-10-08 18:17:06