Cube描画
キューブが回転します。
シェーダプログラム
シェーダプログラムは次のようになります。
教科書どおりの書き方です。
教科書どおりの書き方です。
- simple.vert
#version 130
uniform mat4 modelMatrix; // モデル・マトリックス
uniform mat4 viewMatrix; // ビュー・マトリックス
uniform mat4 projectionMatrix; // 射影・マトリックス
in vec3 a_vertex;
in vec3 a_normal;
out vec3 v_fragmentNormal;
void main(void)
{
v_fragmentNormal = (viewMatrix*modelMatrix*vec4(a_normal, 0.0)).xyz;
gl_Position = projectionMatrix*viewMatrix*modelMatrix*vec4(a_vertex.xyz, 1.0);
}
viewMatrix*modelMatrixをシェーダ側で計算させています。
CPU側とGPU側で負荷を分散させたいならば、CPU側で計算させてもよいかもしれません。
あと、projectionMatrix*viewMatrix*modelMatrixもCPU側であらかじめ計算させておく方法もあると思います。
CPU側とGPU側で負荷を分散させたいならば、CPU側で計算させてもよいかもしれません。
あと、projectionMatrix*viewMatrix*modelMatrixもCPU側であらかじめ計算させておく方法もあると思います。
ちなみに、法線ベクトルをModelViewマトリックスで計算するのはどうも間違いのようです。
法線ベクトルはオブジェクトはことなり、ModelViewマトリックスの逆転置行列(逆行列の転置)で計算するべきのようです。よくわかりませんが。
ということは、transpose(inverse(viewMatrix*modelMatrix))*normalということになるでしょうか。???不明。
法線ベクトルはオブジェクトはことなり、ModelViewマトリックスの逆転置行列(逆行列の転置)で計算するべきのようです。よくわかりませんが。
ということは、transpose(inverse(viewMatrix*modelMatrix))*normalということになるでしょうか。???不明。
- simple.frag
#version 130
in vec3 v_fragmentNormal;
out vec4 fragColor;
void main(void)
{
float intensity;
intensity = max(dot(v_fragmentNormal, vec3(0.0,0.0,1.0)),0.0);
fragColor = vec4(0.0,1.0,0.0,1.0)*intensity;
}
Cube.h
#include <GL/glew.h>
#include "Transform.h"
class Cube
{
private:
GLuint vid[3];
GLint vertexLocation;
GLint normalLocation;
GLuint numIndices;
GLfloat matrix[16];
float angle;
public:
void setup(GLuint programObj)
{
angle = 0.0;
GLfloat vertices[] = {
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, +0.5f,
+0.5f, -0.5f, +0.5f,
+0.5f, -0.5f, -0.5f,
-0.5f, +0.5f, -0.5f,
-0.5f, +0.5f, +0.5f,
+0.5f, +0.5f, +0.5f,
+0.5f, +0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, +0.5f, -0.5f,
+0.5f, +0.5f, -0.5f,
+0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, +0.5f,
-0.5f, +0.5f, +0.5f,
+0.5f, +0.5f, +0.5f,
+0.5f, -0.5f, +0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, +0.5f,
-0.5f, +0.5f, +0.5f,
-0.5f, +0.5f, -0.5f,
+0.5f, -0.5f, -0.5f,
+0.5f, -0.5f, +0.5f,
+0.5f, +0.5f, +0.5f,
+0.5f, +0.5f, -0.5f
};
GLfloat normals[] = {
+0.0f, -1.0f, +0.0f,
+0.0f, -1.0f, +0.0f,
+0.0f, -1.0f, +0.0f,
+0.0f, -1.0f, +0.0f,
+0.0f, +1.0f, +0.0f,
+0.0f, +1.0f, +0.0f,
+0.0f, +1.0f, +0.0f,
+0.0f, +1.0f, +0.0f,
+0.0f, +0.0f, -1.0f,
+0.0f, +0.0f, -1.0f,
+0.0f, +0.0f, -1.0f,
+0.0f, +0.0f, -1.0f,
+0.0f, +0.0f, +1.0f,
+0.0f, +0.0f, +1.0f,
+0.0f, +0.0f, +1.0f,
+0.0f, +0.0f, +1.0f,
-1.0f, +0.0f, +0.0f,
-1.0f, +0.0f, +0.0f,
-1.0f, +0.0f, +0.0f,
-1.0f, +0.0f, +0.0f,
+1.0f, +0.0f, +0.0f,
+1.0f, +0.0f, +0.0f,
+1.0f, +0.0f, +0.0f,
+1.0f, +0.0f, +0.0f
};
GLuint indices[] = {
0, 2, 1,
0, 3, 2,
4, 5, 6,
4, 6, 7,
8, 9, 10,
8, 10, 11,
12, 15, 14,
12, 14, 13,
16, 17, 18,
16, 18, 19,
20, 23, 22,
20, 22, 21
};
numIndices = sizeof(indices)/4;
vertexLocation = glGetAttribLocation(programObj, "a_vertex");
normalLocation = glGetAttribLocation(programObj, "a_normal");
glGenBuffers(3, vid);
glBindBuffer(GL_ARRAY_BUFFER, vid[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices)*sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vid[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(normals)*sizeof(GLfloat), normals, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vid[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices)*sizeof(GLuint), indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void render()
{
glBindBuffer(GL_ARRAY_BUFFER, vid[0]);
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*3, 0);
glBindBuffer(GL_ARRAY_BUFFER, vid[1]);
glVertexAttribPointer(normalLocation, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*3, 0);
glEnableVertexAttribArray(vertexLocation);
glEnableVertexAttribArray(normalLocation);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vid[2]);
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, 0);
}
void update() {
sl_LoadIdentityf(matrix);
//sl_Translatef(matrix, 0.0f,0.0f,1.0f);
sl_Rotatef(matrix, angle, 0.0f, 1.0f, 0.0f);
angle += 1.0;
}
GLfloat* m() {
return matrix;
}
};
メインプログラム
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <GL/glew.h>
#include <GL/glut.h>
#include "Transform.h"
#include "Cube.h"
GLuint programObject;
GLuint vertexShader;
GLuint fragmentShader;
GLint modelLocation;
GLint viewLocation;
GLint projectionLocation;
GLfloat viewMatrix[16];
GLfloat projectionMatrix[16];
Cube cube;
void display();
void reshape(int w, int h);
void timer(int t);
void init();
bool initGlsl();
GLuint LoadShader(GLenum type, const char *fileName);
void display()
{
cube.update();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programObject);
glUniformMatrix4fv(modelLocation, 1, GL_FALSE, cube.m());
glUniformMatrix4fv(viewLocation, 1, GL_FALSE, viewMatrix);
glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, projectionMatrix);
cube.render();
glUseProgram(0);
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
sl_LoadIdentityf(projectionMatrix);
sl_Perspectivef(projectionMatrix, 30, (GLfloat)w/(GLfloat)h, 1.0f, 100.0f);
}
void timer(int t)
{
glutPostRedisplay();
glutTimerFunc(t, timer, 17);
}
void init()
{
glClearColor(0.5, 0.5, 0.5, 1.0);
glClearDepth(1.0f);
sl_LoadIdentityf(viewMatrix);
sl_LookAtf(viewMatrix, 3.0f, 4.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
}
bool initGlsl()
{
programObject = glCreateProgram();
if (programObject == 0) return false;
vertexShader = LoadShader(GL_VERTEX_SHADER, "simple.vert");
glAttachShader(programObject, vertexShader);
fragmentShader = LoadShader(GL_FRAGMENT_SHADER, "simple.frag");
glAttachShader(programObject, fragmentShader);
GLint linked;
glLinkProgram(programObject);
glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
if (!linked) {
GLint infoLen = 0;
glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = new char[sizeof(char)*infoLen];
glGetProgramInfoLog(programObject, infoLen, NULL, infoLog);
std::cerr << "Error linking program:\n" << infoLog << "\n";
delete [] infoLog;
}
glDeleteProgram(programObject);
return false;
}
glBindFragDataLocation(programObject, 0, "fragColor");
modelLocation = glGetUniformLocation(programObject, "modelMatrix");
viewLocation = glGetUniformLocation(programObject, "viewMatrix");
projectionLocation = glGetUniformLocation(programObject, "projectionMatrix");
cube.setup(programObject);
return true;
}
GLuint LoadShader(GLenum type, const char *fileName)
{
GLuint shader;
GLint compiled;
std::fstream inputFile(fileName);
std::istreambuf_iterator<char> dataBegin(inputFile);
std::istreambuf_iterator<char> dataEnd;
std::string fileData(dataBegin, dataEnd);
const char *file = fileData.c_str();
shader = glCreateShader(type);
if (shader == 0) return 0;
glShaderSource(shader, 1, &file, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char* infoLog = new char[sizeof(char)*infoLen];
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
std::cerr << "Error compiling shader: " << fileName << "\n" << infoLog << "\n";
delete [] infoLog;
}
glDeleteShader(shader);
return 0;
}
return shader;
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(600, 400);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("test");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutTimerFunc(100, timer, 17);
GLenum err;
err = glewInit();
if (err != GLEW_OK) {
std::cerr << "GLEW error : " << glewGetErrorString(err) << "\n";
std::exit(1);
}
init();
initGlsl();
glutMainLoop();
return 0;
}
座標系と変換マトリックス
座標系
座標系:coordinate system(空間:space)には次のようなものに分かれる。
- オブジェクト座標系(object space)
- モデリング座標系、ローカル座標系とも言う
- ワールド座標系(world space)
- グローバル座標系とも言う
- 視点座標系座標系(eye space)
- 眼点座標系とも書かれる
- クリップ座標系(clip space)
- 正規化デバイス座標系(normalized device space)
- ウィンドウ座標系(window space)
変換方法
ModelMatrix
オブジェクト座標系からワールド座標系に変換するマトリックス。
WorldMatrixとも呼ぶ。
WorldMatrixとも呼ぶ。
OpenGLのAPIで言うならば、
- glScale
- glRotate
- glTranslate
がそれにあたると思われます。
ViewMatrix
ワールド座標系から視点座標系に変換するマトリックス。
OpenGLのAPIで言うならば、
- gluLookAt
がそれにあたると思われます。
ProjectionMatrix
視点座標系からクリップ座標系に変換するマトリックス。
射影変換をすること。
射影変換には、
射影変換をすること。
射影変換には、
- 正射影変換
- 透視変換
があると思います。
OpenGLのAPIで言うならば、
- glFrustum
- glOrtho
- gluPerspective
がそれにあたると思われます。
perspective divide
クリップ座標系から正規化デバイス座標系に変換する。
クリップ座標系の各点の同次座標の x, y, z 成分を w で割ると正規化デバイス座標系になる?
クリップ座標系の各点の同次座標の x, y, z 成分を w で割ると正規化デバイス座標系になる?
OpenGLでは、固定パイプラインなので、ユーザは意識する必要はない。
ビューポート変換&デプス・レンジ
正規化デバイス座標系からウィンドウ座標系に変換すること。
OpenGLのAPIで言うならば、
- glViewport
がそれに当たると思われます。
添付ファイル