2008/05/10

gluPerspective error


ロボットを作っているとき、どうしても隠面消去がうまくいかず、後で描画した図形が常に手前に見えます。原因を調べるのに丸一日かかりました。ああ、疲れた。上のような変な絵が出るのです。
When I made a simple humanoid, I found a problem in hidden-surface-removal. Polygons deawn late is always displayed. I spent whole one day to identify the source of the issue. Strange picture like above is always displayed.

こちらは正常な隠面消去行われた様子です。原因が分かれば簡単でして、何度も読んだ”OpenGL入門”(エドワード・エンジェル著)にも次のように書いてあるのです。
"Alert! 前方クリッピング面にカメラをあまり近づけると、透視ビューに関するデプス計算で数値エラーにつながりかねない。”
This is the right one. "OpenGL, a PRIMER (Edward Angel)" said arithmetic error would heppen in depth calculation when the near clopping surface was too close from camera.

原因はまさにこれだったのですが、私はてっきり数値エラーでクラッシュするか、またはエラーメッセージが出るとばかり思っていました。しかし実際にはエラーは報告されず、ただ黙って隠面消去しない絵が表示されていたのでした。
I thought some messages should be reported when arithmetic errors happened. However, no errors reported and simply wrong picture was drawn.

GL_PROJECTIONにおける透視投影の設定にはgluPerspective()を使っていたのですが、これだけうまく動かないのです。glOrtho()やglFrustum()を使うとうまくいくのです。なのでgluPerspective()の設定だとばかり思っていました。確かにそうだったのですが、エラーが出ないので前方クリッピングの問題ではないと思い込んでいたのでした。ちなみに、glOrtho()やglFrustum()ではうまく行った理由は次の通りです。
- glOrtho() 直投影には前方クリッピング面は関係ありません
- glFrustum() 前方クリッピング面を慎重に調整しないとまともに絵が出ません。
それに引き替え、gluPerspective()は直観的で、すぐに絵が出るので、間違いに気づきにくかったのです。
OpenGL provide three ways to set camera. I used gluPerspective() which didn't work and other two worked fine because:
- glOrtho() near clipping surface doesn't mean enything
- glFrustum() I should adjust near clipping surface very carefully, otherwise no picture.

まあ、とにかく、
gluPerspective(3, 1.0, 0.0, 100.0)  絵は出るが隠面消去が間違っている
gluPerspective(3, 1.0, 1.0, 100.0) 正しい
ということがわかったのでした。
Anyway,
gluPerspective(3, 1.0, 0.0, 100.0) = wrong picrure diaplayed silently
gluPerspective(3, 1.0, 1.0, 100.0) = right picture

import sys
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

def Draw():
glEnable(GL_DEPTH_TEST)

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

glMatrixMode(GL_PROJECTION)
glLoadIdentity()

#glOrtho(-1.0, 1.0, -1.0, 1.0, -0.5, 1000.0) #good
#glFrustum(-1.0, 1.0, -1.0, 1.0, 40.0, 200.0) #good
#gluPerspective(3, 1.0, 0.0, 100.0) #bad hidden surface
gluPerspective(3, 1.0, 1.0, 100.0)

glMatrixMode(GL_MODELVIEW)
gluLookAt(30.0, 30.0, 0.0, 0.0, 0.0, -30.0, 0.0, 1.0, 0.0)

glBegin(GL_TRIANGLES)
glColor3f(0.0, 0.0, 1.0)
glVertex3f( 0.9, -0.9, -30.0)
glVertex3f( 0.9, 0.9, -30.0)
glVertex3f(-0.9, 0.0, -30.0)
glEnd()

glTranslatef(0.0, 0.0, -30.0)
glColor3f(0.5, 0.5, 0.5)
glutSolidSphere(0.7, 10, 10)

glColor3f(0.8, 0.5, 0.5)
glutSolidCube(1.0)
glFlush();

glutInit(sys.argv)
glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_SINGLE)
glutInitWindowSize(300, 300)
glutCreateWindow("Depth Test")
glutDisplayFunc(Draw)
glutMainLoop()



0 件のコメント: