前回書こうと思っていた内容が思ったよりも長くなってしまいました。
なので今回はGLSLの説明の続きとなります。
CGは必要な知識が多くて大変です。
だから楽しいんですけどね。
GLSLの組み込み変数
OpenGL3.2以前の公式資料が見つからなかったので、OpenGL3.3の資料を見てみると、組み込み変数は以下のようになっています。
まあ、おおむね同じです。
バーテックスシェーダー(入力)
vec4 gl_Color;
vec4 gl_SecondaryColor;
vec3 gl_Normal;
vec4 gl_Vertex;
vec4 gl_MultiTexCoord{0-7};
float gl_FogCoord;
バーテックスシェーダー(出力)
gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
vec4 gl_ClipVertex;
};
vec4 gl_FrontColor;
vec4 gl_BackColor;
vec4 gl_FrontSecondaryColor;
vec4 gl_BackSecondaryColor;
vec4 gl_TexCoord[];
float gl_FogFragCoord;
フラグメントシェーダー(入力)
vec4 gl_FragCoord;
bool gl_FrontFacing;
float gl_ClipDistance[];
vec2 gl_PointCoord;
int gl_PrimitiveID;
フラグメントシェーダー(出力)
float gl_FragDepth;
気づいた方もおられるかもしれませんが、フラグメントシェーダーの出力に、gl_FragColorがありません。
実はgl_FragColorは新しいGLSLでは廃止されています。
「じゃあ、勉強しても無駄じゃないか」と思われるかもしれませんが、そんなことは無くて、新しいGLSLではgl_FragColorの書き方が変わっただけです。
ですので今回の知識はほとんどそのまま新しいGLSLを書く時にも使えますので安心してください。
C++プログラムからGLSLにデータを渡すglVertexやglNormal系の組み込み変数は実質使われてません。
これらに関しては代用の機能が、OpenGL2.1でも使えるのでVBOに合わせて説明していきます。
Zバッファ法とgl_Positionのz値
zバッファ法(デプスバッファー法)とは、視点から見えている色を描画していく手法です。
必要なメモリ領域が大きかったり、半透明な物体の透過処理が苦手などデメリットもありますが、非常に高速です。
前回説明したローカル座標系ですが、実はz軸も存在しています。 xyzの範囲はそれぞれ(-1,1)だと思うのですが、z=1の時は描画されなかったのでzは(-1,1]になるのかもしれないです。
GLSLのgl_Positionに設定されたz値が深さになるわけですね。 ちなみにwには1.0が入ってます。
前回作ったプログラムですが、OpenGLはデフォルトではこのz値は有効になっていません。
試しに前回のプログラムのglColor4f();glBegin;~glEnd();の部分を以下の様に変えてみてください。
色と頂点座標の違うポリゴンを2つGLSLに転送しています。
//赤いポリゴン
glColor4f(1.0, 0.0, 0.0, 1.0);
glBegin(GL_TRIANGLES);
glVertex3f(0.0, 0.5, -1.0);
glVertex3f(-0.5, -0.5, -1.0);
glVertex3f(0.5, -0.5, -1.0);
glEnd();
//黄色いポリゴン
glColor4f(1.0, 1.0, 0.0, 1.0);
glBegin(GL_TRIANGLES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(-1.0, -0.5, 0.0);
glVertex3f(0.5, -0.8, 0.0);
glEnd();
するとこのようになります。
z値の小さい赤いポリゴンのほうが手前に来ないといけないのに黄色いポリゴンが手前に来てしまっています。
これはGLSLに送ったポリゴンの順番に描画されたからです。
深さ情報を描画に反映さしていきます。
// デプステストを有効にする
glEnable(GL_DEPTH_TEST);
// 前のものよりもカメラに近ければ、フラグメントを受け入れる
glDepthFunc(GL_LESS);
glClearColor(0.2f, 0.2f, 0.2f, 0.0f);
// スクリーンをクリアする
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
プログラム全体です。
次回から省略したいので初期設定系をinitGLFW()関数にまとめています。 ポインタを使ってますが、ただポインタを返り値に設定しているだけです。
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <gl/glew.h>
#include <GLFW/glfw3.h>
GLFWwindow* initGLFW(int width, int height)
{
// GLFW初期化
if (glfwInit() == GL_FALSE)
{
return nullptr;
}
// ウィンドウ生成
GLFWwindow* window = glfwCreateWindow(width, height, "OpenGL Sample", NULL, NULL);
if (!window)
{
glfwTerminate();
return nullptr;
}
// バージョン2.1指定
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwMakeContextCurrent(window);
glfwSwapInterval(0);
// GLEW初期化
if (glewInit() != GLEW_OK)
{
return nullptr;
}
return window;
}
int readShaderSource(GLuint shaderObj, std::string fileName)
{
/*以前の記事参照*/
}
GLint makeShader(std::string vertexFileName, std::string fragmentFileName)
{
/*以前の記事参照*/
}
int main()
{
GLint width = 640, height = 480;
GLFWwindow* window = initGLFW(width, height);
GLint shader = makeShader("shader.vert", "shader.frag");
// フレームループ
while (glfwWindowShouldClose(window) == GL_FALSE)
{
glUseProgram(shader);
// デプステストを有効にする
glEnable(GL_DEPTH_TEST);
// 前のものよりもカメラに近ければ、フラグメントを受け入れる
glDepthFunc(GL_LESS);
glClearColor(0.2f, 0.2f, 0.2f, 0.0f);
// スクリーンをクリアする
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//glClear(GL_COLOR_BUFFER_BIT);
//赤いポリゴン
glColor4f(1.0, 0.0, 0.0, 1.0);
glBegin(GL_TRIANGLES);
glVertex3f(0.0, 0.5, -1.0);
glVertex3f(-0.5, -0.5, -1.0);
glVertex3f(0.5, -0.5, -1.0);
glEnd();
//黄色いポリゴン
glColor4f(1.0, 1.0, 0.0, 1.0);
glBegin(GL_TRIANGLES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(-1.0, -0.5, 0.0);
glVertex3f(0.5, -0.8, 0.0);
glEnd();
// ダブルバッファのスワップ
glfwSwapBuffers(window);
glfwPollEvents();
}
// GLFWの終了処理
glfwTerminate();
return 0;
}
きちんと視点からの深さが反映されているのがわかります。