前回のWebGLではなく、OpenGL3.3を使って今度は3D表示をしてみました。3Dになるとカメラ位置の計算で行列演算が入り、急に数学的な手法が多用されるようになります。
参考 : http://www.opengl-tutorial.org/jp/beginners-tutorials/tutorial-3-matrices/
ここにあるチュートリアルを参考にさせていただきました。
Windowsでのビルドがうまくいったので、VisualStudio 2013 でテストしました。
参考 : http://www.opengl-tutorial.org/jp/beginners-tutorials/tutorial-1-opening-a-window/
内容は、四面体の頂点の色をフラグメンシェーダに処理をさせることと、座標変換による見え方の違いを確認することです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
// Include standard headers #include <stdio.h> #include <stdlib.h> #include <GL/glew.h> #include <glfw3.h> GLFWwindow* window; #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> using namespace glm; #include <common/shader.hpp> int main( void ) { // Initialise GLFW glfwInit(); glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); window = glfwCreateWindow(640, 480, "Test", NULL, NULL); glfwMakeContextCurrent(window); // Initialize GLEW glewExperimental = true; // Needed for core profile glewInit(); // Ensure we can capture the escape key being pressed below glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); // Dark blue background glClearColor(0.0f, 0.0f, 0.4f, 0.0f); GLuint VertexArrayID; glGenVertexArrays(1, &VertexArrayID); glBindVertexArray(VertexArrayID); // Create and compile our GLSL program from the shaders GLuint programID = LoadShaders( "vertexshader.glsl", "fragmentshader.glsl" ); // Get a handle for our "MVP" uniform GLuint MatrixID = glGetUniformLocation(programID, "MVP"); // Projection matrix : 45ー Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f); // Camera matrix glm::mat4 View = glm::lookAt( glm::vec3(0.5,0.8,2), // Camera is at (4,3,3), in World Space glm::vec3(0,0,0), // and looks at the origin glm::vec3(0,1,0) // Head is up (set to 0,-1,0 to look upside-down) ); // Model matrix : an identity matrix (model will be at the origin) glm::mat4 Model = glm::mat4(1.0f); // Our ModelViewProjection : multiplication of our 3 matrices glm::mat4 MVP = Projection * View * Model; // Remember, matrix multiplication is the other way around static const GLfloat g_vertex_buffer_data[] = { -1.0f, -1.0f, 0.0f, //1 1.0f, -1.0f, 0.0f, //2 0.0f, 1.0f, 0.0f, //3 -1.0f, -1.0f, 0.0f, //1 1.0f, -1.0f, 0.0f, //2 0.0f, 0.0f, 1.0f, //4 -1.0f, -1.0f, 0.0f, //1 0.0f, 0.0f, 1.0f, //4 0.0f, 1.0f, 0.0f, //3 1.0f, -1.0f, 0.0f, //2 0.0f, 1.0f, 0.0f, //3 0.0f, 0.0f, 1.0f, //4 }; GLuint vertexbuffer; glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW); static const GLfloat g_color_buffer_data[] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, }; GLuint colorbuffer; glGenBuffers(1, &colorbuffer); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW); do{ // Clear the screen glClear( GL_COLOR_BUFFER_BIT ); // Use our shader glUseProgram(programID); // Send our transformation to the currently bound shader, // in the "MVP" uniform glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); // 1rst attribute buffer : vertices glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, // attribute. No particular reason for 0, but must match the layout in the shader. 3, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)0 // array buffer offset ); // 2nd attribute buffer : colors glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glVertexAttribPointer( 1, // attribute. No particular reason for 1, but must match the layout in the shader. 3, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)0 // array buffer offset ); // Draw the triangle ! glDrawArrays(GL_TRIANGLES, 0, 3*4); // 3 indices starting at 0 -> 1 triangle glDisableVertexAttribArray(0); // Swap buffers glfwSwapBuffers(window); glfwPollEvents(); } // Check if the ESC key was pressed or the window was closed while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && glfwWindowShouldClose(window) == 0 ); // Cleanup VBO and shader glDeleteBuffers(1, &vertexbuffer); glDeleteProgram(programID); glDeleteVertexArrays(1, &VertexArrayID); // Close OpenGL window and terminate GLFW glfwTerminate(); return 0; } |
今回はGLSLがシンプルです。バージョンがかわりattributeのかわりにinが使われるようになりましたが、基本的な文法は同じです。
バーテックスシェーダ
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#version 330 core layout(location = 0) in vec3 vPosition; layout(location = 1) in vec3 vColor; uniform mat4 MVP; out vec3 fColor; void main(){ gl_Position = MVP * vec4(vPosition,1); //gl_Position = vec4(vPosition,1); fColor = vColor; } |
フラグメントシェーダ
1 2 3 4 5 6 7 8 9 10 |
#version 330 core in vec3 fColor; out vec3 color; void main() { //color = vec3(1,0,0); color = fColor; } |
バーテックスが持っている色情報をフラグメントにわたしています。自動的に中間値が計算され補間されます。(GPUが全部やってくれる)
シェーダ部分は別ファイルになっていて、これを読み込んで設定する関数が用意されています。
四面体をカメラ座標の変換をするものとしないもの両方出力してみました。(切り替えはバーテックスシェーダのコメントで)
とても基本的なテストですが、VisualStudioでセットアップできたことが、自分の開発環境的に有意義でした。(Compute Shaderに備えて・・)
頂点増やしたり、いろいろと数値を変えて試してみると理解も深まります。