人工知能に関する断創録

このブログでは人工知能のさまざまな分野について調査したことをまとめています(更新停止: 2019年12月31日)

惑星

恒星のまわりを回る惑星とその衛星です。太陽と地球と月をイメージしてますが縮尺はめちゃくちゃです。実際、太陽はもっとずっと大きいです。月を太陽ではなく地球を中心にして回すのに苦労しました・・・座標変換は慣れないと難しい。このプログラムはOpenGLプログラミングガイド第5版(p.148)太陽系を参考に作成しました。「月も追加しろ」っていう例題がありますね。

planet.py
f:id:aidiary:20100814105746p:plain

惑星

#!/usr/bin/env python
#coding:utf-8
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import sys

earth_angle = 0.0
moon_angle = 0.0

def main():
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH)
    glutInitWindowSize(500, 500)
    glutInitWindowPosition(100, 100)
    glutCreateWindow("惑星")
    init()
    glutDisplayFunc(display)
    glutReshapeFunc(reshape)
    glutIdleFunc(idle)
    glutMainLoop()

def init():
    glClearColor(0.0, 0.0, 0.0, 0.0)
    glEnable(GL_DEPTH_TEST)

def display():
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glColor3f(1.0, 1.0, 1.0)
    glLoadIdentity()
    gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
    
    # 太陽の描画
    glColor3f(1.0, 0.0, 0.0)
    glutSolidSphere(1.0, 50, 50)
    
    # 地球の描画
    # 下の2つのRotateとTranslateは月にも影響する
    glRotatef(earth_angle, 0.0, 1.0, 0.0)
    glTranslatef(2.5, 0.0, 0.0)
    glColor3f(0.0, 0.0, 1.0)
    glutSolidSphere(0.2, 20, 20)
    
    # 月の描画
    glColor3f(1.0, 1.0, 0.0)
    glRotatef(moon_angle, 0.0, 1.0, 0.0)
    glTranslatef(0.5, 0.0, 0.0)
    glutSolidSphere(0.1, 20, 20)
    
    glutSwapBuffers()
    
def reshape(width, height):
    glViewport(0, 0, width, height)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(60.0, width/height, 1.0, 20.0)
    glMatrixMode(GL_MODELVIEW)

def idle():
    global earth_angle, moon_angle
    earth_angle += 0.01  # 地球の回転角を更新
    moon_angle += 0.1    # 月の回転角を更新
    glutPostRedisplay()

if __name__ == "__main__":
    main()

座標変換はコードの下から上へ向かって適用されるというのがポイントでしょうか。平行移動・回転・拡大縮小(2008/9/14)参照。なのでdisplay()は下から見ていく必要があります。

  1. 月を原点に描画
  2. 平行移動してmoon_angleだけ回転
  3. 原点に地球を描画(この時点で原点に地球、その周りに月が描画されてる)
  4. 地球と月をまとめて平行移動してearth_angleだけ回転
  5. 原点に太陽を描画

コメントでも書きましたが、地球の平行移動と回転は月にも適用されるので地球と月がまとめて移動するのがポイントでしょうか。もしまとめて移動させたくなかったら地球と月の平行移動・回転をする前にglPushMatrix()、glPopMatrix()を使って行列を保存する必要があります。

    # 太陽の描画
#    glColor3f(1.0, 0.0, 0.0)
#    glutSolidSphere(1.0, 50, 50)

    # 地球の描画
    glPushMatrix()
    glRotatef(earth_angle, 0.0, 1.0, 0.0)
    glTranslatef(2.5, 0.0, 0.0)
    glColor3f(0.0, 0.0, 1.0)
    glutSolidSphere(0.2, 20, 20)
    glPopMatrix()
    
    # 月の描画
    glPushMatrix()
    glColor3f(1.0, 1.0, 0.0)
    glRotatef(moon_angle, 0.0, 1.0, 0.0)
    glTranslatef(0.5, 0.0, 0.0)
    glutSolidSphere(0.1, 20, 20)
    glPopMatrix()

こうすると地球も月も太陽を中心に回ります。ただし、月は太陽に飲み込まれて見えないので太陽は描画しないようにしてます。慣れないとちょっととっつきにくいなぁ。