1. ホーム

vs-OpenGLプログラミング入門編

2022-02-24 07:07:20

最近、c言語で絵を描く必要があり、使用したコンパイラはvs2013で、openglライブラリを使用するよう勧められました。

この記事は http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html から取得しました。

---------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------

グラフィックのプログラミングといえば、TCの#include <graphics.h> を思い出す人も多いのではないでしょうか?

しかし、あの豪華なPCゲームがどのように書かれているのか、不思議に思ったことはありませんか?TCの哀れな640*480の解像度と16色に頼って、それを行うこと?明らかに違いますよね。

この投稿の目的は、TCの古いグラフィック・インターフェースを捨てて、新しいものに触れてもらうことです。

OpenGLは現在主流のグラフィックスAPIの1つで、様々な文脈でDirectXより優れた機能を備えています。

1. C言語との緊密な統合。

OpenGLのコマンドはもともとCの関数で記述されており、Cを学んだ人にはOpenGLはわかりやすく、学びやすい。TCのgraphics.hを扱ったことがある人なら、OpenGLでグラフィックスを使うことはTCよりさらに簡単だとわかるはずです。

2. 強力な移植性。

マイクロソフトのDirect3Dも非常に優れたグラフィックスAPIですが、Windows(と現在はXBOXコンソール)でのみ利用可能です。OpenGLはWindowsだけでなく、Unix/Linuxなど他のシステムにも対応しており、メインフレームコンピュータや様々な特殊コンピュータ(医療用ディスプレイなど)でも利用されています。そして、OpenGLの基本コマンドは、ハードウェアに依存せず、プラットフォームにも依存しないのです。

3. 高性能なグラフィックスレンダリング。

OpenGLは、時代とともに変化する業界標準です。現在、どのグラフィックカードメーカーもOpenGLを強力にサポートしており、熾烈な競争によってOpenGLの性能は常に最先端を走っています。

つまり、OpenGLは非常に強力なグラフィックス・ソフトウェア・インターフェースなのです。NBがどの程度のものかは、DOOM3やQUAKE4などのプロ用ゲームを見ていただければわかると思います。

OpenGLの公式サイト(英語)

http://www.opengl.org

WindowsでのOpenGLプログラミングを紹介します。

OpenGLを学ぶための準備

最初のステップは、コンパイル環境を選択することです

現在、Windowsの主なコンパイル環境は、Visual Studio、Broland C++ Builder、Dev-C++などですが、いずれもOpenGLをサポートしています。しかし、ここではOpenGLを学ぶための環境としてVisual Studio 2005を選択します。

ステップ2:GLUTツールキットのインストール

GLUTはOpenGLに必須ではありませんが、学習に多少の利便性をもたらすので、インストールすることをお勧めします。

Windows環境用のGLUTをダウンロードします。(サイズ 約150k)

http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip

上記アドレスからダウンロードできない場合は、以下のリンクをご利用ください。

http://upload.programfan.com/upfile/200607311626279.zip

Windows環境にGLUTをインストールする手順。

1. ダウンロードしたzipパッケージを解凍すると、5つのファイルがあります。

2、"My Computerで"gl.h"を検索し、そのフォルダ(VisualStudio2005であれば、インストールディレクトリ下の"VCPlatformSDKentaglフォルダ)を探します。PlatformSDK Phincludegl folder")にあります。解凍したglut.hをこのフォルダーに入れる。

3. 3. 解凍したglut.libとglut32.libをstatic libraryフォルダ(VisualStudio2005の場合はインストールディレクトリ下の "VClib")に入れてください。

4. 解凍したglut.dllとglut32.dllをOSディレクトリの下にあるsystem32フォルダに入れる。(典型的な場所は C:\WindowsSystem32 です。)

ステップ3:OpenGLプロジェクトの作成

ここでは、VisualStudio2005を例にしています。

File->New->Project を選択し、Win32 Console Application を選択し、名前を決めて、OKを押してください。

表示されたダイアログボックスで、左側のアプリケーション設定をクリックし、Empty project を見つけてチェックを入れ、Finish を選択します。

次に、プロジェクトに "OpenGL.c" という名前のコードファイルを追加し、ファイルの末尾に .c を使用します。

これで完成です。他のプロジェクトと同じように使えます。

最初のOpenGLプログラム

簡単なOpenGLのプログラムは以下の通りです。(コンパイルと実行が必要な場合、上記のようにGLUTが適切にインストールされている必要があることに注意してください)

#include <GL/glut.h>

void myDisplay(void)

{ <未定義

     glClear(GL_COLOR_BUFFER_BIT)を使用します。

     glRectf(-0.5f, -0.5f, 0.5f, 0.5f)を使用します。

     glFlush()を実行します。

}

int main(int argc, char *argv[])

{ <未定義

     glutInit(&argc, argv)です。

     glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE)です。

     glutInitWindowPosition(100, 100);

     glutInitWindowSize(400, 400);

     glutCreateWindow("最初のOpenGLプログラム")。

     glutDisplayFunc(&myDisplay);

     glutMainLoop()。

     0を返します。

}

このプログラムの機能は、黒いウィンドウの中央に白い四角形を描くことである。以下、各行のステートメントを説明します。

まず、GLUTのヘッダファイルである#include <GL/glut.h> をインクルードする必要があります。

本来、OpenGLのプログラムでは、 <GL/gl.h> と <GL/glu.h> もインクルードするのが普通ですが、この2つのファイルはGLUTヘッダーファイルに自動的に含まれるため、改めてインクルードする必要はないそうです。

次にmain関数を見てください。

int main(int argc, char *argv[]), これはコマンドライン引数のmain関数ですが、見たことがあるはずですよね?見たことがない人は、本を見て、理解してから読んでください。

main関数の文は、最後のreturnを除いて、すべてglutで始まっていることに注意してください。glutで始まる関数はすべてGLUTツールキットで提供されており、以下、使用されている関数の一部を紹介します。

1, glutInit, GLUTの初期化,この関数は他のGLUTを使用する前に一度は呼ばなければならない.形式はかなり厳密ですが,一般的にはその上にglutInit(&argc, argv)という文章をコピーしてください.

2. glutInitDisplayMode, 表示モードを設定する。GLUT_RGBはRGB色を使うことを意味し、GLUT_INDEX(インデックス色を使うこと)は、glut_SINGLEはシングルバッファ、GLUT_DOUBLE(ダブルバッファを使うこと)は、glut_singleとなります。より詳しい情報は、自分でググってください。もちろん、後でチュートリアルがあります。

3. glutInitWindowPosition, これは単純で、画面内のウィンドウの位置を設定します。

4. glutInitWindowSize, これも単純で、ウィンドウの大きさを設定します。

5. glutCreateWindow: 先に設定された情報に基づいてウィンドウを作成する。パラメータはウィンドウのタイトルとして使用される.注意:ウィンドウが作成された後,すぐに画面に表示されるわけではありません.ウィンドウを見るためには,glutMainLoopの呼び出しが必要である.

6. glutDisplayFunc、描画が必要な時に呼び出される関数を設定する。(これは正確性に欠けるが、正確な記述は初心者によく分からないかもしれないので、とりあえずそうしておこう)。

7. glutMainLoop、メッセージループを実行する。(これは初心者の方にはよくわからないかもしれませんが、今はこの関数がウィンドウを表示し、ウィンドウが閉じるのを待ってから戻ることができるということだけ知っていただければ十分です)

glutDisplayFunc関数では、"絵を描く必要があるときにmyDisplay関数を呼び出す"と設定しています。つまり、myDisplay関数は絵を描くために使われるわけです。myDisplayの3つの関数呼び出しを見ると、すべてglで始まっていることがわかります。これらのglで始まる関数はOpenGLの標準的な関数で、使用される関数は以下の通りです。

1.glClear、クリア gl_COLOR_BUFFER_BITは色をクリアすることを意味します。glClearは他にもクリアできますが、ここでは説明しません。

2. glRectf:矩形を描画します。4つの引数は、対角線上に位置する2点の水平・垂直座標を表します。

3. glFlush: 直前の OpenGL コマンドを(バッファで待機させるのではなく)直ちに実行するようにします。その役割は、fflush(stdout)に似ています。
OpenGL入門[II]編
この講座でお話するのは、簡単な幾何学図形を描くことです。実際に描く前に、いくつかの概念に慣れ親しんでおきましょう。
<スパン I. 点・線・多角形
点、線、多角形という概念は数学(具体的には幾何学)で知っているが、コンピュータではこれらの概念は異なるだろう。
数学でいう点とは、あくまで位置であって、大きさではない。しかし、コンピュータの中では、いくら計算精度を上げても、無限に小さい点を表現することはできません。一方、グラフィックス出力装置(モニターなど)がどんなに精度を上げても、無限に小さい点を出力することはできない。一般にOpenGLでは、点は1ピクセル(ピクセルの概念は各自検索してください〜)として描かれ、十分に小さいかもしれませんが、無限に小さくなるわけではありません。同じピクセル上に、OpenGLは座標がわずかに異なるだけの点を多数描くことができますが、そのピクセルの正確な色はOpenGLの実装に依存します。もちろん、あまり細かいことにこだわると大変なことになるので、"同じピクセルに複数の点を描く方法"にあまり労力を使う必要はないでしょう。
同様に、数学的に直線は幅を持ちませんが、OpenGLの直線には幅があります。また、OpenGLの線は、数学的な概念でいうところの無限ではなく、有限の長さでなければなりません。OpenGLの線という概念は、数学的な線分という概念に近く、2つの端点で定義することができます。
OpenGLでは、ポリゴンは凸型ポリゴンでなければならないと規定されています(任意の2点で定義される線分がポリゴンの内部にあるポリゴンと定義され、ひいては凸型ポリゴンは中空であってはならないとされています)。多角形は、その辺の端点(ここでは頂点と呼ぶこともある)で識別することができる。(注意: 使用される多角形が凸多角形でない場合、最終的な出力は不定です - OpenGLは効率のためにチェックを緩和しており、表示エラーにつながる可能性があります。このエラーを避けるには、すべて凸多角形である三角形を使うようにします)
点、線、多角形によって、さまざまな幾何学的形状を組み合わせることができると考えられる。円弧は、長さが1ピクセルの幅より短い直線を何本もつないだものと考えることもできます。このように、円弧や円も表現することができます。また、小さな多角形を異なる平面でつなげることで、「面」を形成することもできます。
<スパン II. OpenGLでの頂点の指定
以上の議論から、quot;point"がすべての基本であることがわかります。
OpenGLは、点を指定するための一連の関数を提供しています。これらはすべて glVertex で始まり、その後に数字と 1 文字または 2 文字が続きます。たとえば
glVertex2d
glVertex2f
glVertex3f
glVertex3fv
その他
数字はパラメータの数を表し、2は2つ、3は3つ、4は4つという意味です(ちょっと語弊がありますね~)。
文字は引数の型を示し,sは16ビット整数(OpenGLはこの型をGLshortと定義している).
                   i は32ビット整数を表します(OpenGLではGLintおよびGLsizeiとして定義されています).
                   f は 32 ビット浮動小数点数(OpenGL では GLfloat および GLclampf として定義されています)です.
                   d は 64 ビット浮動小数点数を表します(OpenGL ではこの型を GLdouble および GLclampd として定義しています).
                   v は、渡されるいくつかのパラメータがポインタの形式であることを示します(以下の例を参照してください)。
これらの関数は、引数の型と数を除けば、機能的には同一である。例えば、次の5つのコード・スニペットは機能的に同等です。
(i) glVertex2i(1, 3);
(ii) glVertex2f(1.0f, 3.0f);
(iii) glVertex3f(1.0f, 3.0f, 0.0f)です。
(iv) glVertex4f(1.0f, 3.0f, 0.0f, 1.0f)。
(v) GLfloat VertexArr3[] = {1.0f, 3.0f, 0.0f};
      glVertex3fv(VertexArr3)を使用します。
後ほど、この一連の関数を表現するためにglVertex*を使用します。
注意事項 OpenGLの関数の多くはこの形式をとっており、同一の接頭辞にパラメータ説明のマーカを加えたものですが、これは学習すればするほどありがたみが増すでしょう。
III. 描画開始
今、私が頂点の数を指定したとしましょう。OpenGLは、私がこれらの頂点に対して何をしたいのか、どうやって知るのでしょうか?1つ1つ描くのか、それとも線につなげるのか?あるいは多角形を形成するのか?あるいは何か他のことをするのか?
この問題を解決するために、OpenGLは次のことを要求します:頂点を指定するコマンドは、glBegin関数の後、glEnd関数の前に含まれなければなりません(さもないと、指定した頂点が無視されます)。そして、これらの点をどのように使用するかを指定するのは、glBeginに任されています。
例えば、こう書きます。
glBegin(GL_POINTS);
     glVertex2f(0.0f, 0.0f)を使用します。
     glVertex2f(0.5f, 0.0f)となります。
glEnd();
すると、2つの点は別々に描画されます。GL_POINTSをGL_LINESに置き換えると、2点は直線の2つの端点とみなされ、OpenGLは直線を描画します。
また、さらに頂点を指定して、より複雑な形状を描くこともできる。
一方、glBeginは、GL_POINTS、GL_LINESに加えて、GL_LINE_STRIP、GL_LINE_LOOP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN等をサポートしています。それぞれのおおよその効果は次の図の通りです。

免責事項:この画像は、www.opengl.org。この画像は、書籍 "OpenGL Programming Guide" の添付画像であり、この書籍の古いバージョン(1994年の初版)がウェブ上で流通していますので、著作権の問題に触れられていないことを祈ります。
glBeginにはいろいろな使い方があるのですが、今回はその中でも特に 自分でglBeginのやり方や頂点の位置を変えてみて、面白いパターンを生成することができます。
プログラムコードです。
void myDisplay(void)
{ <未定義
     glClear(GL_COLOR_BUFFER_BIT)を使用します。
     glBegin(  /* ここに好きなパターンを記入してください */。  );
/* ここではglVertex*関数ファミリーを使用します */
/* 欲しい頂点の位置を指定します */
     glEnd()を使用します。
     glFlush()。
}
このコードを好きなように変更して、レッスン1のmyDisplay関数に置き換えてコンパイルし、実行してみてください。
2つの例
例1.円を描く
/*
四角形、五角形、六角形、......と、n辺の図形までで、nが大きくなると円に近い図形になります
nが十分に大きいと、人間の目では本当の円と区別がつかなくなる
この時点で、円を描くことに成功しました。
(注:円を描くには多くの方法がありますが、ここで使用したのはより単純な方法ですが、効率は良くありません)
以下のconst int nの値を変更してみて、n=3,4,5,8,10,15,20,30,50などの値が異なるときに出力がどう変化するかを観察してください。
GL_POLYGONをGL_LINE_LOOP、GL_POINTSなど他のものに変更し、出力がどのように変わるかを観察してください。
*/
#include <math.h>
const int n = 20;
const GLfloat R = 0.5f;
const GLfloat Pi = 3.1415926536f;
void myDisplay(void)
{ <未定義
     int i;
     glClear(GL_COLOR_BUFFER_BIT)を使用します。
     glBegin(GL_POLYGON)。
     for(i=0; i<n; ++i)
         glVertex2f(R*cos(2*Pi/n*i), R*sin(2*Pi/n*i)) を使用します。
     glEnd();
     glFlush()。
}
例2.五芒星を描く
/*
五芒星の5つの頂点が次のような関係で分布しているとする。
      A
E B
    D C
まず、五芒星の中心から頂点aまでの距離を余弦定理に基づく式で計算します。
(五芒星は辺の長さが0.0の正五角形に対応すると仮定する)。
a = 1 / (2-2*cos(72*Pi/180)) となります。
次に、サインとコサインの定義に基づいて、B の x 座標 bx と y 座標 by、および C の y 座標を計算します。
(五芒星の中心が座標の原点にあると仮定して)。
bx = a * cos(18 * Pi/180);
by = a * sin(18 * Pi/180);
cy = -a * cos(18 * Pi/180);
そして、5点の座標は、上記の4つの量といくつかの定数で簡単に表現することができます。
*/
#include <math.h>
const GLfloat Pi = 3.1415926536f;
void myDisplay(void)
{ <未定義
     GLfloat a = 1 / (2-2*cos(72*Pi/180));
     GLfloat bx = a * cos(18 * Pi/180);
     GLfloat by = a * sin(18 * Pi/180);
     GLfloat cy = -a * cos(18 * Pi/180);
     GLfloat
         PointA[2] = { 0, a },
         PointB[2] = { bx, by },
         PointC[2] = { 0.5, cy },
         PointD[2] = { -0.5, cy },
         PointE[2] = { -bx, by };
     glClear(GL_COLOR_BUFFER_BIT)を使用します。
     // 五芒星は、A->C->E->B->D->Aの順で一筆書きで描くことができる。
     glBegin(GL_LINE_LOOP)を使用します。
         glVertex2fv(PointA)。
         glVertex2fv(PointC);
         glVertex2fv(PointE);
         glVertex2fv(PointB);
         glVertex2fv(PointD)。
     glEnd();
     glFlush()。
}
例3:正弦関数のグラフを描く
/*
OpenGLのデフォルトの座標値は-1から1までしかないので、(これは変更可能ですが、その方法は後に回します。)
そこで、すべての座標値を均等にスケーリングするファクターfactorを設定します。
こうすることで、より多くのサイン周期を描画することができます
ファクター値を変更してみて、変化を観察する
*/
#include <math.h>
const GLfloat factor = 0.1f;
void myDisplay(void)
{ <未定義
     GLfloat x;
     glClear(GL_COLOR_BUFFER_BIT);
     glBegin(GL_LINES);
         glVertex2f(-1.0f, 0.0f)を使用します。
         glVertex2f(1.0f, 0.0f); // 上記2点はX軸を描画することができます。
         glVertex2f(0.0f, -1.0f)を使用します。
         glVertex2f(0.0f, 1.0f); // 上記の2点は、Y軸上に描画することが可能です。
     glEnd()を実行します。
     glBegin(GL_LINE_STRIP)を使用します。
     for(x=-1.0f/factor; x<1.0f/factor; x+=0.01f)
     { <未定義
         glVertex2f(x*factor, sin(x)*factor);
     }
     glEnd()。
     glFlush()。
}
概要
このレッスンでは、点、線、多角形の概念と、OpenGLを使って点を表現する方法、点を使って幾何学的形状を表現する方法を学びました。
想像力を働かせて、あらゆる幾何学的形状を描くことができるのです。もちろん、GL_LINE_STRIPを使って、同じような位置にあるたくさんの点を結んで、関数画像を形成することもできます。もし興味があれば、もっと美しいイメージの関数を探してきて、自分でやって、OpenGLで描画することもできます。
レッスン2終了 ======================================================================================================= レッスン2終了
=====================続きはこちら。
OpenGL入門[III]編

レッスン2では、幾何学的な図形を描く方法を学びましたが、もう少しプログラムを書いてみると、実はまだ鬱陶しいことがあることに気がつきます。例えば、点が小さすぎてよく見えない、線が細すぎて違和感がある、想像上の線を描きたいのに、短い線がたくさんあるだけでやり方がわからない、点の組み合わせもわからない、などなど。

これらの問題は、このレッスンで解決されます。

以下、点、線、多角形と分けて説明します。

1. ポイントについて

点の大きさのデフォルトは1ピクセルですが、変更することができます。変更するためのコマンドはglPointSizeで、以下の関数プロトタイプを持っています。

void glPointSize(GLfloat size);

sizeは0.0fより大きくなければなりません。デフォルトは1.0f("pixels")です。

注意:特定のOpenGLの実装では、ポイントのサイズに制限があるため、最大を超えるサイズを設定すると、設定に問題が発生する場合があります。

void myDisplay(void)

{ <未定義

     glClear(GL_COLOR_BUFFER_BIT)を使用します。

     glPointSize(5.0f)。

     glBegin(GL_POINTS)を使用します。

         glVertex2f(0.0f, 0.0f)を使用します。

         glVertex2f(0.5f, 0.5f)を使用します。

     glEnd()を実行します。

     glFlush()を使用します。

}

2. 直線について

(1) 直線は、幅を指定することができます。

void glLineWidth(GLfloat width)。

使い方は、glPointSizeと同様です。

(2) 破線を描画する。

まず、glEnable(GL_LINE_STIPPLE);を使って破線モードを有効にします(オフにするにはglDisable(GL_LINE_STIPPLE)を使ってください)。

次に、glLineStipple を使って破線のスタイルを設定します。

void glLineStipple(GLint factor, GLushort pattern);

pattern は長さ 16 の 1 と 0 の並びで、最下位ビットから順に、1 なら線上の次の因子点を実数で、0 なら線上の次の因子点を虚数で描画します。

以下はその例です。

免責事項:この画像は、www.opengl.org、書籍「"OpenGL Programming Guide"」の添付画像です。この書籍の古いバージョン(1994年の初版)がウェブ上に出回っていますので、著作権の問題には触れていないことを祈念します。

コード例です。

void myDisplay(void)

{ <未定義

     glClear(GL_COLOR_BUFFER_BIT)を使用します。

     glEnable(GL_LINE_STIPPLE)を使用します。

     glLineStipple(2, 0x0F0F)を使用します。

     glLineWidth(10.0f)となります。

     glBegin(GL_LINES)を使用します。

         glVertex2f(0.0f, 0.0f)。

         glVertex2f(0.5f, 0.5f)を使用します。

     glEnd()を実行します。

     glFlush()を使用します。

}

3. ポリゴンについて

ポリゴンには他にもいろいろありますが、ここでは以下の4つの領域についてお話します。

(1) 多角形の2辺とその描き方。

3次元座標を使った作図はまだあまりしませんが、ある程度の3次元の概念を確立しておく必要があります。

3次元的に見ると、ポリゴンは2つの面を持っています。それぞれの面は、塗りつぶし、辺の輪郭のみ、頂点のみという異なる方法で描くことができ、"fill"がデフォルトとなります。2つの面それぞれに異なる方法を設定することも可能です。

glPolygonMode(GL_FRONT, GL_FILL); // 前面を塗りつぶすように設定する。

glPolygonMode(GL_BACK, GL_LINE); // 裏面をエッジ描画に設定する。

glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 両面を頂点描画に設定する。

(2) 反転

一般に、画面上で頂点が反時計回りに並んでいる面を「前面」、それ以外の面を「背面」と呼びます。このような「表」と「裏」で表現することができます(比較的透明なミネラルウォーターのボトルを見つけて表に当て、裏を表にして同じように円を描き、「表」と「裏」を体験してください)。自分に向いている方向、ボトルの外側が表で、自分に向いている方向、ボトルの内側が表であることがわかると思います。向かっている瓶の内側と向いている瓶の外側は反対側です。(つまり、同じ面が"ボトルの外側"ですが、ある場所はプラス、ある場所はマイナスと考えられます)

しかし、もっと変わった面もあります。例えば、メビウスの帯(Googleで検索してみてください)は、すべて前面(quot;front")またはすべて背面(quot;back")として表現することが可能です。

glFrontFace関数で"front"と"back"の概念を交換することができます。

glFrontFace(GL_CCW); // CCW方向を"front"に設定、CCWはCounterClockWise、反時計回りの方向です。

glFrontFace(GL_CW); // CW方向を"front"に設定、CWはClockWise(時計回り)

ここでは、レッスン1のmyDisplay関数を置き換えて、glFrontFace(GL_CCW)をglFrontFace(GL_CW)に変更し、結果の変化を見るサンプルプログラムです。

void myDisplay(void)

{ <未定義

     glClear(GL_COLOR_BUFFER_BIT)を使用します。

     glPolygonMode(GL_FRONT, GL_FILL); // 前面を塗りつぶしモードに設定する。

     glPolygonMode(GL_BACK, GL_LINE); // 裏面をラインモードに設定する。

     glFrontFace(GL_CCW); // 反時計回りに正面に設定する。

     glBegin(GL_POLYGON); // 左下に反時計回りで四角を描く

         glVertex2f(-0.5f, -0.5f)を使用します。

         glVertex2f(0.0f, -0.5f)となります。

         glVertex2f(0.0f, 0.0f)を使用します。

         glVertex2f(-0.5f, 0.0f)となります。

     glEnd()を実行します。

     glBegin(GL_POLYGON); // 右上に時計回りに正方形を描きます。

         glVertex2f(0.0f, 0.0f)を使用します。

         glVertex2f(0.0f, 0.5f)となります。

         glVertex2f(0.5f, 0.5f)を使用します。

         glVertex2f(0.5f, 0.0f)となります。

     glEnd()を実行します。

     glFlush()を使用します。

}

(3) ポリゴン面を削除する

3次元空間では、ポリゴンは2つの面を持っていますが、裏側のポリゴンは見えませんし、表側のポリゴンでも他のポリゴンに隠されて見えないものもあります。このような見えないポリゴンを見えるポリゴンと同等に扱うと、グラフの処理効率が落ちることは間違いない。そのような時には、不要な面を排除することができる。

まず、glEnable(GL_CULL_FACE);を使ってカリングを有効にします(オフにするにはglDisable(GL_CULL_FACE)を使います)。

次に、glCullFace を使ってカリングを行います。

glCullFace のパラメータは GL_FRONT、GL_BACK、または GL_FRONT_AND_BACK で、それぞれ前面をカリング、背面をカリング、前面と背面のポリゴンをカリングすることを意味します。

注:カリング機能はポリゴンに対してのみ作用し、ポイントやラインには作用しません。例えば、glCullFace(GL_FRONT_AND_BACK)を使用すると、すべてのポリゴンがカリングされ、ポイントとラインだけが表示されます。

(4) スケルトンポリゴン

直線は破線で、多角形はスケルトンで描くことができる。

まず、glEnable(GL_POLYGON_STIPPLE);を使ってスケルトン化モードを有効にします(オフにするにはglDisable(GL_POLYGON_STIPPLE)を使ってください)。

次に、glPolygonStipple を使用して、スケルトンのスタイルを設定します。

void glPolygonStipple(const GLubyte *mask);

ここで、パラメータ mask は長さ 128 バイトの空間を指し、32*32 の矩形がどのようにスケルトン化されるべきかを示す。最初のバイトは、下部の左端8ピクセルを左から右へ(または右から左へ、変更可能)スケルトン化するかどうかを示し(1はスケルトン化せずピクセルを表示、0はスケルトン化して後ろの色を表示)、最後のバイトは上部の右端8ピクセルがスケルトン化されるかどうかを示します。

しかし、このマスク配列を直接定義すると、このようになります。

静的GLubyteマスク[128]=。

{ <未定義

     0x00, 0x00, 0x00, 0x00, // これが最下段です。

     0x00, 0x00, 0x00, 0x00,

     0x03, 0x80, 0x01, 0xC0, // ヘンプ

     0x06, 0xC0, 0x03, 0x60, // うざい

     0x04, 0x60, 0x06, 0x20, // の。

     0x04, 0x30, 0x0C, 0x20, // 初期値

     0x04, 0x18, 0x18, 0x20, // 始まり

     0x04, 0x0C, 0x30, 0x20, // トランスフォーメーション

     0x04, 0x06, 0x60, 0x20, // ,

     0x44, 0x03, 0xC0, 0x22, // 無し

     0x44, 0x01, 0x80, 0x22, // ビルド

     0x44, 0x01, 0x80, 0x22, // プロポーザル

     0x44, 0x01, 0x80, 0x22, // 作る

     0x44, 0x01, 0x80, 0x22, // 使用する

     0x44, 0x01, 0x80, 0x22,

     0x44、0x01、0x80、0x22。

     0x66, 0x01, 0x80, 0x66,

     0x33、0x01、0x80、0xCC。

     0x19, 0x81, 0x98,

     0x0C、0xC1、0x83、0x30。

     0x07、0xE1、0x87、0xE0。

     0x03、0x3F、0xFC、0xC0。

     0x03、0x31、0x8C、0xC0。

     0x03、0x3F、0xFC、0xC0。

     0x06、0x64、0x26、0x60。

     0x0C, 0xCC, 0x33, 0x30,

     0x18, 0xCC, 0x33, 0x18,

     0x10、0xC4、0x23、0x08。

     0x10、0x63、0xC6、0x08。

     0x10、0x30、0x0C、0x08。

     0x10, 0x18, 0x08, 0x18。

     0x10, 0x00, 0x00, 0x08 // これが最上行

};

このようなデータの束は非常に直感的でなく、ハエを表していることに気づくには、大変な労力をかけて分析する必要があります。

このようなデータは、画像として保存し、専用のツールで編集する方がはるかに簡単なのは明らかです。ここでは、その方法を紹介します。

まず、Windows独自のペイントブラシ・プログラムでmask.bmpという新しい画像を作成し、保存するときに"Monochrome Bitmap"を選択することに注意してください。画像のプロパティ]ダイアログボックスで、画像の高さと幅を32に設定します。

虫眼鏡で画像を見て、編集してください。黒は2値0(スケルトン)、白は2値1(スケルトンでない)に対応し、編集して保存します。

そして、次のコードでこのMask配列を取得します。

static GLubyte Mask[128];

FILE *fp;

fp = fopen("mask.bmp", "rb");

if( !fp )

     exit(0);

// ファイルポインタをこの位置に移動し、ファイルの終端に到達するまでに、さらに sizeof(Mask) バイト読み込むようにします。

// -(int)sizeof(Mask) の書き方は良くないが、ここでは正しく動作することに注意すること

// -sizeof(Mask) を直接書くと、sizeof が符号なしを取得するため、負の符号を取ることが問題になります。

if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )

     exit(0);

// Maskにsizeof(Mask)バイトを読み込む

if( !fread(Mask, sizeof(Mask), 1, fp) )

     exit(0);

fclose(fp)です。

さて、今度は自分で画像をマスクとして編集し、上記の方法でMask配列を取得して実行し、その効果を観察してみましょう。

注)点線描画の場合はファクター係数を設定できますが、ポリゴンスケルトンの場合はファクター係数を設定することはできません。マウスでウィンドウの大きさを変えて、スケルトン効果の変化を観察してください。

#include <stdio.h>

#include <stdlib.h>

void myDisplay(void)

{ <未定義

     static GLubyte Mask[128];

     FILE *fp;

     fp = fopen("mask.bmp", "rb");

     if( !fp )

         exit(0);

     if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )

         exit(0);

     if( !fread(Mask, sizeof(Mask), 1, fp) )

         exit(0);

     fclose(fp)です。

     glClear(GL_COLOR_BUFFER_BIT)を使用します。

     glEnable(GL_POLYGON_STIPPLE);

     glPolygonStipple(Mask)を使用します。

     glRectf(-0.5f, -0.5f, 0.0f, 0.0f); // 左下にスケルトン効果のある正方形を描画する。

     glDisable(GL_POLYGON_STIPPLE)を使用します。

     glRectf(0.0f, 0.0f, 0.5f, 0.5f); // 右上にスケルトン効果なしの四角を描く。

     glFlush()を使用します。

}

概要

このレッスンでは、幾何学的な形を描くことについて、いくつかの詳細を学びました。

点の大きさを設定することができる。

直線は幅を設定することができ、破線として描画することができます。

ポリゴンの2面の描画方法を別々に設定できる、3次元空間で見えないポリゴンを消すことができる、塗りつぶしたポリゴンをスケルトンとして描画することができる。

これらの詳細を理解することで、より快適に図面を描くことができるようになるものもあります。

また、あるデータをプログラムの外のファイルに書き込んで、専用のツールで編集する方が簡単に思えることもあります。

レッスン3終了 =================================================================================================================

=====================続きです。


OpenGL入門[IV]編
2008-10-06 21:26
<テーブル
今回は、色の選択について学んでいます。やっと白黒の世界から抜け出せた~~。
OpenGLは、RGBAモードとカラーインデックスモードの2つのカラーモードをサポートしています。
どちらのカラーモードでも、コンピュータは各ピクセルに対して何らかのデータを保存しなければなりません。RGBAモードでは、データは直接色を表しますが、カラーインデックスモードでは、データはインデックスを表し、実際の色を得るためには、インデックステーブルも見に行かなければならないという違いがあります。
<スパン 1. RGBAカラー
RGBAモードでは、各画素に次のデータが保存されます。R値(赤色成分)、G値(緑色成分)、B値(青色成分)、A値(アルファ成分)です。赤、緑、青を組み合わせて必要な様々な色を得るところ、アルファは色に直接影響しないので、後回しにします。
RGBAモードでの色の選択は非常に簡単で、1つの関数があればよいのです。
色の設定にはglColor*関数群を使用し、3パラメータ版ではR、G、Bの値を指定でき、A値はデフォルトを使用します。4パラメータ版ではR、G、B、Aの値をそれぞれ指定できます。例
void glColor3f(GLfloat red, GLfloat green, GLfloat blue);
void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
(覚えてる?3fは浮動小数点数の引数が3つあることを意味します~レッスン2のglVertex*関数の説明を参照してください)
は浮動小数点数を引数にとり、0.0はその色を使用しない、1.0はその色をできるだけ使用することを意味します。例
glColor3f(1.0f, 0.0f, 0.0f); 緑と青は使わず、赤を最も多く使うという意味です。
glColor3f(0.0f, 1.0f, 1.0f); は、緑と青を最大限に使い、赤を省くことを意味します。ブレンドの効果は水色です。
glColor3f(0.5f, 0.5f, 0.5f); は、各色を半分ずつ使用し、その効果は灰色です。
注)浮動小数点数が小数点以下数桁の精度を持つからと言って、コンピュータがそれほど多くの色を表示できるわけではありません。実際、コンピュータが表示できる色数は、ハードウェアによって決まります。もしOpenGLが正確な色を見つけることができなければ、"rounding"のようなことをします。
以下のコードでglColor3fの値を変更することで、異なる色の矩形を描画することができます。
void myDisplay(void)
{
     glClear(GL_COLOR_BUFFER_BIT)を使用します。
     glColor3f(0.0f, 1.0f, 1.0f)を使用します。
     glRectf(-0.5f, -0.5f, 0.5f, 0.5f)を使用します。
     glFlush()を実行します。
}
注:関数のglColorファミリーは、引数のタイプが異なる場合、"max"の色に異なる値を設定します。
接尾辞としてfとdを使用する関数で、1.0が最大使用量を示す。
サフィックスにbを使用する関数で、127を最大使用量とするもの。
サフィックスにubを使用する関数で、最大使用数は255です。
サフィックスとしてsを使用する関数。最大使用数は32767。
サフィックスにusを使用する関数で、65535が最大使用量を示す。
一見面倒そうなルールですが、慣れれば実使用に支障はありません。
<スパン 2. インデックスカラー
インデックスドカラーモードでは、OpenGLはカラーテーブルを必要とします。このテーブルは画家のパレットに相当します。多くの色を混ぜることができますが、同時にパレット上に存在する色の数はパレット上のセルの数を超えることはありません。カラーテーブルの各項目は、パレット上のグリッドと同じように、色を保持していると考えてください。
インデックスドカラーモードで描画するとき、「i色をso-and-soに設定します」と言いますが、これは実はパレットのiグリッドをso-and-soにするのと同じことなのです。また、「k番目の色を塗りたい」と言ったら、パレットのk番目の枠に筆を入れる。
カラーテーブルのサイズは非常に限られており、通常は256から4096で、必ず2の整数乗になります。インデックスカラー方式で描画する場合は、必ずカラーテーブルを先に設定してから、色を選択するようにしてください。
<スパン 2.1. 色の選択
glIndex* 関数のファミリーを使用すると、カラーテーブルの色を選択することができます。これらのうち、おそらく最もよく使われるのは glIndexi で、これはシェイプシフトの引数を取ります。
void glIndexi(GLint c);
はい、これは確かにとてもシンプルです。
2.2. カラーテーブルを設定する
OpenGLはカラーテーブルを設定する方法を直接提供していないので、カラーテーブルの設定はOSのサポートを利用する必要があります。私たちが使っているWindowsや、他のほとんどのグラフィックOSにもこの機能はありますが、使われている関数が異なります。Windowsでウィンドウを作成するコードを自分で書く方法を教えなかったのと同じように、Windowsでカラーテーブルを設定する方法もここでは教えません。
GLUTツールキットはカラーテーブルを設定する関数glutSetColorを提供しますが、私はいつもそれをテストするのに問題がありました。さて、インデックス付きの色を味わってもらうために、別のOpenGLツールキット:auxを紹介します。 このツールキットはVisualStudioに付属しているので、別にインストールする必要はありませんが、時代遅れなので、ここでは味見程度にして、深入りしないようにしましょう。
#include <windows.h>
#include <GL/gl.h>
#include <GL/glaux.h>
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glaux.lib")
#include <math.h>
const GLdouble Pi = 3.1415926536;
void myDisplay(void)
{
     int i;
     for(i=0; i<8; ++i)
         auxSetOneColor(i, (float)(i&0x04), (float)(i&0x02), (float)(i&0x01)) を使用します。
     glShadeModel(GL_FLAT)を使用します。
     glClear(GL_COLOR_B)