GLSL #5: テクスチャマッピング
目標
前回のプログラムをベースに,今度はテクスチャマッピングを実装する.より具体的には,画面いっぱいに四角形を描き,そこに任意の画像をテクスチャマッピングする.
実装環境
- GLEW 3.2.1
- 設定方法はこちらを参照
- GLEW 1.13.0
- 設定方法はこちらを参照
- GLM
- 設定方法はこちらを参照
- DevIL
- 画像の読み込みに利用
- Windows 10 64bit
- Visual Studio 2015
DevILのダウンロード
- ここから「DevIL-Windows-SDK-1.8.0.zip」をダウンロード
- 「C:\Libraries\」に「DevIL Windows SDK」フォルダを解凍
- フォルダ名が分かりにくいので「DevIL-1.8.0」とする
- 以降,この「C:\Libraries\DevIL-1.8.0」を「Path」と呼ぶ
Visual Studioのプロジェクト作成
- Visual Studioを開いて「新しいプロジェクト」を作成
- 「インクルードディレクトリ」に以下を追加
- Path\include
- 「ライブラリディレクトリ」に以下を追加
- Debug: Path\lib\x64\Release
- Release: 同上
- 「追加の依存ファイル」に必要なライブラリを追加
- Debug: DevIL.lib
- Release: 同上
- 3のフォルダに入っている「.dll」ファイルを「C:\Windows\System32」に追加
サンプルプログラム
前回までに作成した以下のプログラムは変更せずそのまま利用します.
- window.h
- window.cpp
- shaderUtil.h
- shaderUtil.cpp
model.h
モデルデータを扱うためのインタフェースを記述したヘッダファイル.
// // model.h // #pragma once #include <glm/glm.hpp> #include <glm/ext.hpp> #include "shaderUtil.h" namespace gl { class model { protected: GLuint prog; glm::mat4 projMat; glm::mat4 viewMat; glm::mat4 modelMat; public: virtual void render() = 0; void setProjMat( glm::mat4 &mat ); void setViewMat( glm::mat4 &mat ); void setModelMat( glm::mat4 &mat ); }; }
model.cpp
モデルデータを扱うためのインタフェースを記述したソースファイル.
// // model.cpp // #include "model.h" namespace gl { void model::setProjMat( glm::mat4 &mat ) { projMat = mat; } void model::setViewMat( glm::mat4 &mat ) { viewMat = mat; } void model::setModelMat( glm::mat4 &mat ) { modelMat = mat; } }
modelTex.h
画像データをDevILを用いて読み込んで,テクスチャとして描画するクラスを記述したヘッダファイル.
// // modelTex.h // #pragma once #include "model.h" #include <IL/il.h> namespace gl { class modelTex : public model { private: static const GLfloat vertData[20]; static const GLshort idxData[6]; static const int numVert; static const int offsetTexUVData; GLuint texID; GLuint MVPMatLoc; GLuint vao; // Vertex array object GLuint vbo; // Vertex buffer object GLuint ibo; // Index buffer object public: modelTex( const string &texFileName, const string &vertShaderName, const string &fragShaderName ); ~modelTex(); void render(); }; }
modelTex.cpp
画像データをDevILを用いて読み込んで,テクスチャとして描画するクラスを記述したソースファイル.
// // modelTex.cpp // #include "modelTex.h" namespace gl { const GLfloat modelTex::vertData[20] = { // Vertex position +1.0f, +1.0f, 0.0f, // #0: Upper right -1.0f, +1.0f, 0.0f, // #1: Upper left -1.0f, -1.0f, 0.0f, // #2: Lower left +1.0f, -1.0f, 0.0f, // #3: Lower right // Texture uv position 1.0f, 1.0f, // #0: Upper right 0.0f, 1.0f, // #1: Upper left 0.0f, 0.0f, // #2: Lower left 1.0f, 0.0f // #3: Lower right }; const GLshort modelTex::idxData[6] = { 0, 1, 2, 0, 2, 3 }; const int modelTex::numVert(4); const int modelTex::offsetTexUVData(sizeof(float) * 3 * numVert); modelTex::modelTex( const string &texFileName, const string &vertShaderName, const string &fragShaderName ) { // ----- Initialize shader programs initializeProgram(prog, vertShaderName, fragShaderName); // ----- Generate buffers // VBO glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertData), vertData, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); // IBO glGenBuffers(1, &ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idxData), idxData, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // ----- Load an image and create a texture of the image ilInit(); ILuint imgID; ilGenImages(1, &imgID); glGenTextures(1, &texID); ilBindImage(imgID); ilEnable(IL_ORIGIN_SET); ilOriginFunc(IL_ORIGIN_LOWER_LEFT); try { ILboolean isLoaded = ilLoadImage((ILstring)texFileName.c_str()); if (isLoaded) { ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE); glBindTexture(GL_TEXTURE_2D, texID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT), 0, GL_RGBA, GL_UNSIGNED_BYTE, ilGetData()); } else { throw "Could not load image: " + texFileName; } } catch (string e) { cerr << "Error: " << e.c_str() << endl; exit(EXIT_FAILURE); } ilDeleteImages(1, &imgID); // ----- Get a uiform location MVPMatLoc = glGetUniformLocation(prog, "MVPMat"); // ----- VAO glGenVertexArrays(1, &vao); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); // 3 elements per vertex glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)offsetTexUVData); // 2 elements per color glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBindVertexArray(0); } modelTex::~modelTex() { glDeleteVertexArrays(1, &vao); glDeleteTextures(1, &texID); glDeleteBuffers(1, &vbo); glDeleteBuffers(1, &ibo); glDeleteBuffers(1, &MVPMatLoc); } void modelTex::render() { glUseProgram(prog); { // Send matrix data to GPU glUniformMatrix4fv(MVPMatLoc, 1, GL_FALSE, glm::value_ptr(projMat * viewMat * modelMat)); // Texture glBindTexture(GL_TEXTURE_2D, texID); // VAO glBindVertexArray(vao); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); glBindVertexArray(0); } glUseProgram(0); } }
main.cpp
// // main.cpp // #include <glm/glm.hpp> #include <glm/ext.hpp> #include "OpenGLWrapper/window.h" #include "OpenGLWrapper/shaderUtil.h" #include "OpenGLWrapper/modelTex.h" class MyWindow : gl::window { private: gl::modelTex *myTex; public: MyWindow( int w, int h, const string &name, const string &texFileName, const string &vertShaderName, const string &fragShaderName ): window(w, h, name) { myTex = new gl::modelTex(texFileName, vertShaderName, fragShaderName); } ~MyWindow() { if (myTex) delete myTex; } void render() { // Rendering loop glClearColor(0.3f, 0.5f, 0.8f, 0.0f); while (!glfwWindowShouldClose(wnd)) { // Clear color and depth buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Draw myTex->render(); // Swap front and back buffers glfwSwapBuffers(wnd); // Poll for and process events glfwPollEvents(); } } }; int main() { MyWindow wnd( 512, 512, "GLFW 3 Window", "../data/me.jpg", "../shader/modelTex.vert", "../shader/modelTex.frag" ); wnd.render(); return 0; }
modelTex.vert
#version 330 layout(location = 0) in vec3 position; layout(location = 1) in vec2 uv; uniform mat4 MVPMat; out vec2 texCoord; void main() { gl_Position = MVPMat * vec4(position, 1.0); texCoord = uv; }
modelTex.frag
#version 420 layout(binding = 0) uniform sampler2D texLoc; in vec2 texCoord; void main() { gl_FragColor = texture(texLoc, texCoord); }
結果
動いた!目標達成です.
