Document

BerkeleyX: CS184.1x Foundations of Computer Graphics
Homework 2: OpenGL 日本語訳(主要部のみ)
https://courses.edx.org/courses/BerkeleyX/CS_184.1x/3T2014/courseware/Unit_2/Homework_2/
文責:NAIST Computer Graphics 担当 舩冨 卓哉 2015.05.13
 Transform.cpp: HW1 の Transform.cpp と似
ているが,並進・スケール変換・透視投影の
実装すべき関数が追加されている.
Introduction
 readfile.cpp: 入力ファイルを読むためのプロ
グラムである.構文解析部はある程度実装さ
れているが,いくつかのことをやらなければ
この homework では,完全なシーンビューワを
ならない.
OpenGL で構成する.(Course Updates タブの)
 display.cpp: シーンを表示するためのプログ
ハンドアウトにある OpenGL や GLSL の資料を参
ラムである.
照するとよい. homework 1 より発展的な課題に
 shaders/light.frag.glsl: 実際の fragment
なっているが 2 週間しか割り当てられていない.1
shader に相当する.
Homework 2: OpenGL
日 2 日で終わるものではないので,早く取り掛か
るように.課題の全てのページ,特に FAQ やヒン
トを最後まで読むこと.
この課題では,カメラ,画像のサイズ,最大 10 個
までの光源,物体の幾何形状(簡単のため球,テ
ィーポット,立方体に限る),材質など,シーンに関
する記述を入力として受け付けることを目標とす
る.プログラムは正しいカメラ位置・光源環境に従
ってシーンをレンダリングしなければならない.ま
た,前回の課題同様,カメラの視点位置を回転さ
せるだけでなく,並進やスケール変換も実現する.
Homework 2: Assignment
Specification
2 つのシーンファイル hw1.txt と demo.txt がある
が,前者は HW1 のシーンに対応し,後者は
OpenGL プログラムのデモに(だいたい)対応す
る.
OpenGL and GLM Limitations
できるだけ非推奨の機能を使わず,新しい
OpenGL でプログラムを作成すること,およびコン
セプトを学ぶことが目標であるため,下記以外の
OpenGL,GLM 関数は使ってはならない.


Assignment Overview
完全なスケルトンコードが提供されている.
homework 1 よりも複雑であり,まずはこれらがど
のように機能するかを把握することが最初の課題
である.スケルトンコードにコメントされているよう
に,下記 4 つのファイルを変更しなければならな
い.

homework 1 同様,OpenGL の低レベルな描画
関数.これはバッファ,ウィンドウ管理,キーボ
ードイベントに対する glut 関数に相当する.
行列やベクトルの積算,正規化,転置,内積,外
積といった基本的な GLM 関数.積算について
は,スケルトンコード内にいくつかの有用な処理
が用意されている(例えば rightmultiply な
ど).ただし,GLM の行列積算をしっかり理解し
ているならば,この利用は必須ではない
(OpenGL も GLM も column-major である).
最小限の OpenGL 行列スタック.特に,
perspective, modelview, load a matrix といった
OpenGL matrix mode は利用してよい.(GLM
からは mat4 を用いればよい).しかし,他の
OpenGL の標準コマンドである pushing and
popping transforms, translating, rotating,
multiplying the matrix stack などは利用しては
ならない.また,GLM での等価な関数も同様で
ある.この課題の目標の 1 つは,実際に新しい
OpenGL で要求されているのと同じく,自分自身
で行列スタックを管理することである.
特に, OpenGL と GLM では,カメラの配置,透
視投影,並進,回転,スケール変換などの関数が
用意されている.この課題の目標は,この流れを
理解し,再現することであるため,これらのコマン
ドを使用することは認められない.さらに,これら
のほとんどは新しい OpenGL では推奨されておら
ず,利用すべきではない.
析部のコアが含まれており,数カ所埋めるだけで
よい.



Submission
HW0/1 と同様,スクリーンショットの提出が求めら
れる.現状では画像による評価しか行っていない
が,homework 1 と同様,ソースコード(上記 4 ファ
イル)の提出も求められる.
HW2 の回答を "demo.txt input.txt" を引数として
実行する.1 つ目の引数ではシーンを指定し,2 つ
目の引数では検証のためのコードである.2 つ目
の引数は,検証画像を出力する場合にのみ必要
である.
Visual Studio のスケルトンでは,コマンドライン引
数は既に設定されている (Project > Properties >
Configuration Properties > Debugging > Command
Arguments ).スケルトンには"input.txt"と
"demo.txt"が正しい位置に含まれている.
OSX/Linux では, ./transforms demo.txt input.txt
を実行すればよい.
プログラムを実行したら,i キーを入力すればよ
い.自動的に提出に必要な画像
("demo.txt.input.txt.001.png"…) が出力される.
<本講義では,課題は edX 宛ではなく,指定され
た方法で提出すること.>
File Format
プログラムは 1 つの引数:シーンファイルを指定す
るだけでも実行できるはずである.(2 つ目の引数
は評価のための画像を出力する時のみ使用され
る.)シーンファイルの各行は個別に扱われ,以下
の形式に従っている.スケルトンコードは構文解
Blank line: 空行は(空白が含まれていて
も)無視せよ.
# comment line: #で始まる行はコメントで
あり,無視せよ.
command parameter1 parameter2 ...: 行の
最初は必ずコマンドである(読みやすさの
ため,空白が行頭に含まれていることがあ
る).コマンドによっていくつかのパラメータ
を取る.もしパラメータ数がコマンドに合っ
ていなかった場合,あるいはコマンドが不
正であった場合,エラーメッセージを出力
し,その行は無視する.
一般的に,プログラムは入力内のエラーにきちん
と対応しなければならないが,この課題では構文
解析はポイントではないため,きちんとした入力の
みを想定すればよい.プログラムが受け付けるべ
きコマンドは以下の通りである.まずは一般的なコ
マンドから述べる(これらのコマンドは入力ファイル
の最初の方で使用されると仮定してよいが,必ず
しもそうでなくても実行できるようにすべきである.
いずれにせよ,スケルトンの構文解析部を利用す
れば OK である):


size width height シーンの幅と高さを指定
する
camera lookfromx lookfromy lookfromz
lookatx lookaty lookatz upx upy upz fovy
カメラを指定する.zmin と zmax はプログ
ラム中で指定されている.これは透視投影
変換 (アスペクト比 width/height と fovy
で指定される) と モデルビュー変換の両
方を規定する.
次に,光源コマンドについて述べる.光源は最大
10 個までとし,光源コマンドをファイルに追加する
だけで光源を追加できる.(光源コマンドが含まれ
なければ,光源なしの状態をレンダリングしなけれ
ばならないが,スケルトンコードは既にこれにも対
応している):

light x y z w r g b a 8 つのパラメータを持
ち,最初の 4 つは光源の同次座標である.
w = 0 の時は平行光源で,それ以外の時
は点光源である.これに光源色が続く.た
だし,3 次元ベクトルではなく,4 次元ベクト
ルである(ここでは a,つまり alpha は 1 と
してよい).
ユーザが 11 以上の光源を指定した場合,それ以
降の指定を無視し,最初の 10 個のみを入力とし
て受け付けるだけでよい.
光源に対しても適用される.(つまり,OpenGL で
は光源もモデルビュー行列の影響を受ける)しか
し,キーボードによって指定されるシーン全体の並
進,カメラの回転やスケールは光源に対して影響
を与えない.シーンファイル内に記述された変換
のみが,幾何形状と光源の両方に適用される.
ここでは幾何変換のほとんどすべてを実装する.
シェーディングには材質の指定が必要である.こ
の材質は物体によって異なる.プログラムは材質
の指定状況を保持し(初期値は黒とする),その都
度適切な材質パラメータを更新していく形を取る
(ただし,ここでの状態保持は単に上書きされてい
くだけでよく,幾何変換の push/pop などのコマン
ドに対応する必要はない).物体が追加されると
き,そのときの現状の材質を設定する.例えば,
物体を複数追加する際,その間で diffuse コマンド
によって拡散反射色のみを変更すれば,鏡面反
射色はそれらの物体では同一とする.





ambient r g b a 環境光色を指定する
diffuse r g b a 物体表面の拡散反射色を
指定する
specular r g b a 物体表面の鏡面反射色を
指定する
emission r g b a 物体表面の発光色を指定
する
shininess s 表面の光沢度を指定する
次に,物体の幾何形状を指定するコマンドについ
て述べる.単純のため,物体の最大個数は仮定し
てよい(これは最低 10 とする,そんなに大量の物
体を扱う必要はない).ここでは glut のコマンドを
使うため,コマンドは単に



teapot size 指定されたサイズでティーポッ
トを生成する
sphere size 指定されたサイズで球を生成
する
cube size 指定されたサイズで立方体を生
成する
球に対しては,glutSolidSphere 関数を用いる際に
テッセレーション(面への分割数)を指定する必要
があるが,ここでは 20 とする.各プリミティブ形状
がどのように描画されるかはスケルトンコードを参
照すればよいが,基本的には問題ない.
最後に,上述の物体のコマンドが指定されたとき
に適用されるべき,幾何変換について述べる.た
だし,標準的な OpenGL と同様,この幾何変換は



translate x y z 3 次元並進
rotate x y z θ x y z 軸周りの θ 度回
転
scale x y z 非一様スケール変換
ただし,例えば translation, rotation, translation,
scale といったようにコマンドを並べることで幾何変
換は連結することができるものとする.OpenGL の
慣習に従い,幾何変換のコマンドは現在の変換に
対して右から積算するものとする.コードの最後に
記述された変換が最初に適用される変換となる
(物体コマンドに最寄りの変換から適用される)た
め,この慣習は紛らわしい.例えば,(従来の順番
で言うところの)translation, rotation, scale の順に
コマンドが与えられた場合,まずスケール変換を
行い,次に回転,最後に並進となる.右からの積
算については,スケルトンコードの補助関数を参
照すれば,理解の助けになるかもしれない.
シーンの階層的な定義を可能にするため,さらに
以下を定める


pushTransform 現在の変換をスタックに
"push"する(いくつか変換を適用したのち,
pop することでもう一度この変換に復帰す
ることができる)
popTransform スタックから返還を"pop"す
る(つまり,現状の変換を破棄し,スタック
の top 要素に戻る)
プログラムは幾何変換のスタックに単位行列を初
期設定しなければならない.明示的に幾何変換の
初期値を単位行列や特定の行列に設定するコマ
ンドは必要ない.要するに,例にあるように,各物
体へのコマンドは pushTransform ... popTransform
のブロック内にあるべきで,このブロックはネスト
(入れ子にすること)もできるようになっている.
User Interaction
プログラムにシーンファイルを与えて実行すると,
上述の通り解釈し,シーンを描画しなければなら
ない.ユーザインタラクションのほとんどすべては
既にスケルトンコードに実装されている.特に,プ
ログラムは homework 1 と同じキー入力を受け付
け (h, +,-,ESC),さらに下記の通り拡張する:





g は前回と同様, glm::lookAt と自作関数
とを切り替える.また今回は同様に
glm::Perspective と自作関数とを切り替え
る.デフォルトでは自作関数を呼び出すよ
うになっている.
r は初期シーンへと幾何変換をリセットす
る.キーボード入力に対する幾何変換の量
も同じくリセットする.
v はカメラの回転に対応する動作に設定
する(homework 1 でやったのと同じく,これ
がデフォルトの設定になっている).ただ
し,カメラは原点を中心として描画し続ける
必要はないが,原点を中心に動くとしてよ
い.
t はシーンを並進する動作に設定する.こ
の場合,矢印キーはシーンを x, y 方向に
並進させる.移動量は 0.01 倍するものとす
る.(移動量の初期値は 5 とする.)
s はシーンを x, y 方向にスケール変換す
る動作に設定する.同様に,変換量は 0.01
倍するものとする.t か v か s を入力する
ことで,制御を並進,視点,スケール変換
へ変更することができる.視点が変更さ
れ,続いて並進が変更された場合,システ
ムは視点変更を保持しておかなければな
らず,初期視点に戻ってはならない.
Homework 2: Basic
Implementation Hints
スケルトンコード,例,課題の仕様は以上である.
続いて,この課題にどう取り組むかのヒントを 1 つ
ずつ説明していく(2 つめと 3 つめはかなり独立し
ているのでどちらから取り組んでもよい).この通り
に進めることを強く勧めるが,この通りに進める必
要はない.
去の受講生 Kolega and hekimgil からのより詳細
なヒントがある.1
Additional Transforms
まずは homework 1 に追加の変換から実装せよ.
スケルトンコードは基本的な機能を実装済みであ
る;Transform クラスに並進とスケール変換を実
現する適切な処理を追加すればよい.さらに透視
投影変換を実装せよ.これらの実装はそんなに難
しくない.homework 1 で,それ以外の変換は既に
実装済みのはずである.(もし HW2 でティーポット
が表示できなければ,代わりに HW1 のフレームワ
ークを利用してデバッグせよ.後ほどデバッグ済
みの Transform.cpp を HW2 で用いればよい.)
Lighting
次は光源を実装せよ.まずは,light コマンドを処
理できるよう構文解析部に追記せよ.重要なの
は,fragment shader の開発である.homework 0
と homework 1 には既に点光源と平行光源を扱う
のに必要な基本的な機能が実装されている.あと
は,10 個のライト全てを保持できるよう uniform を
用い,光源に対して繰返し処理を構成して,色を
出力する部分を追加すればよい.スケルトンコー
ドは fragment shader の大枠を既に実装してある.
shader は材質についても uniform が必要であ
る.実装すべきシェーディングの式は下記の通り
である.
I=A+E+∑iLi[Dmax(N⋅L,0)+Smax(N⋅H,0
)s]
ここで,I は最終的な輝度,A は環境光の項,E
は自己発光,拡散反射 D と鏡面反射 S は全光
源 i に対する輝度 Li について挿話を取らなけれ
ばならない.N は表面の法線,L は光源方向,
H はハーフアングル,s は光沢度である.光源
方向,ハーフアングルは自前で計算する必要があ
る.最後に,点光源の減衰についてはここでは考
慮しなくてよい.
Geometry and Transforms
これは講師からの実装に対する基本的なアドバイ
スである.次章に,より参考になると思われる,過
1
本稿では割愛する
最後に,シーンファイルの仕様を完全に実装しな
ければならない.scene と camera のコマンドは
とても簡単に実装できる.ただ単に引数の値を設
定し,初期化処理の部分でその値を処理すれば
よい.(ほとんどはスケルトンコードで既に実装さ
れており,また追記が必要な部分も明確に記載さ
れている.)ただし,カメラの up ベクトルは視点と
中心を結ぶ方向に直交するとは限らないため,自
分で完全な coordinate frame を構成する必要が
ある(この部分については既に Transform.cpp に
補助関数が実装されている).材質パラメータは,
現状態を保持し,必要に応じてそれを更新していく
ように実装すればよい.
自分で実現し,OpenGL 上に load せよ.最後に,
幾何変換のコマンドに対しては,スタックの管理が
必要である.C++ standard template library の利
用を強く勧める(知らなければ,調べよ).特に,ス
ケルトンコードの中には下記がある.
if ((str.find_first_not_of("\t\r\n") !=
string::npos) && (str[0] != '#'))
stack <mat4>
transfstack; transfstack.push(mat4(1.0))
;
これは mat4 のスタックを定義し,その初期値に単
位行列を設定している.あとは,幾何変換が来た
時に,対応する glm 行列を設定し,スタックに右か
ら積算すればよい.
mat4 & T = transfstack.top() ; T = T * M ;
ここで,M は幾何変換の行列である.幾何変換の
Push と pop は,スタックにそれらの処理を実行
するだけである.スケルトンコードには既に実装さ
れている.
以上の全ては物体や光源が定義されるときに適
切に設定されていなければならない.物体に対し
ては,この幾何変換と材質を配列に保持しなけれ
ばならない.ただし,この幾何変換は camera コマ
ンドによる変換を含んでいない.そのかわり,これ
は display() 関数内で処理されている.光源に対
しては,単に変換行列を積算し,変換された光源
を保持しておけばよい.
最後に, display 処理は camera の look at 行列
を読み出し,光源を設定し,これらを行列によって
変換している.次に,各物体に対して,材質と正し
い変換行列をシェーダに設定することを繰り返す.
正しい変換行列を設定するためには,カメラ行列
や物体への幾何変換はもちろん,(キーボードか
ら入力された)並進,スケール変換もすべて考慮
し,これらを正しく統合しなければならない.これを
glutSolidCube, glutSolidSphere, glutSolidTeapot
関数を使って実際に描画することになる(描画自
体は既にスケルトンコードに実装されている).
最後に残っているのは,スケルトンコードではすで
に提供されている,シーンファイルの構文解析の
部分である.この部分はどんな方法を用いてもよ
いが,本課題の重要な部分ではない.各行を C++
の string stream に変換し,下記コマンドで空行や
コメント行を処理している.
そして,stringstream s(str) ; s >> cmd ; を
実行すれば,cmd にコマンドの文字列が格納され
る.これに if 文の羅列が続く.残りのパラメータを
取り出すため,単に文字列から数値を取出し,失
敗した場合にはエラーを返している.
Homework 2: FAQ
Below are some FAQs collected from previous
iterations of the local Berkeley class and the Fall
EdX class.
Feedback System
As in homework 1, the autograder is also intended
for use as a feedback system, with the difference
images it outputs helping you to pinpoint
problems and debug. As with all the assignments,
you can submit as many times as you want for
feedback; only your final submission will count
towards the grade.
GLSL Function Restrictions
The restrictions on OpenGL and GLM functions
do not apply to the use of GLSL in GLSL
shaders. There are currently no restrictions on
using glsl functions in the fragment shader.
Initial Skeleton Code
Until you actually parse the input via readfile.cpp
the program doesn't really know what to do, and
may not show anything. If you can't yet get the
teapot to display with the HW 2 framework, you
may want to use the HW 1 framework instead for
now so you can actually see it.
glUniform with arrays
Perpsective fovy
Near and Far plane values
The perspective fovy should be specified in
degrees.
The near and far plane values have been set for
you to use in main.cpp as zNear=0.1 and
zFar=99.0
Take a look at this.
Passing Lights to Shader
Initializing shader values
There are two kinds of data being passed to
shader program: uniforms and attributes.
Attributes are things attached per vertex,
whereas uniforms are more like a constant, so
things like lights, modelview and projection
transforms, or some switches you defined are
uniforms.
When you declare a uniform in shader program, to
access them from the CPU program you need
first get a handle = glGetUniformLocation, and
then when you want to set values(mostly during
display, especially if you have multiple objects
whose model transforms are different), you use
that handle to specify which variable in the
shader program to work with using glUniform()
Please initialize shader values, such as using:
vec4 finalcolor = vec4(0,0,0,1);
If you are experiencing issues with shaders on
either your local machine or on the feedback
server.
How to Debug
Debugging HW 2 can be a bit tricky. If you're
having difficulties and don't know how to start
debugging, our best advice to you is to proceed
systematically . Here are some suggestions to get
you started
See this for documentation.

Directional vs point lights and w

For point lights, the homogeneous coordinate w
will be non-zero (usually w = 1). For directional
lights (infinitely far away), the w coordinate will be
0. This is how you can distinguish them in the
input.


for loop issues

Some students have complained about for loops
not working properly in shaders. Most likely you
have a bug and are not passing uniforms properly
from the main program to the shader. However,
if problems persist and/or you get errors related
to loop unrolling, you may need to explicitly loop
over all 10 max possible lights, instead of only
those that are in use (so the loop bounds are
constant and known beforehand).
First, debug your transformations using
the HW 1 as much as possible.
Try to draw one object at a time with
minimal or no transforms and a simple
shader (that only returns a constant color
or a color calculated from normals only)
Make sure the silhouette (overall shape) of
the scene matches the feed back server
Then slowly add more transformations and
objects, again matching geometry before
attempting to match the lighting
Add the lighting. Try with one light first,
then build up from there. Try to match the
HW 1 scene first.