2017-07-16 3 views
1

私のプログラムは私に単純な赤い三角形を描くと思っています。頂点シェーダとフラグメントシェーダは、loadShader()関数を介して外部ファイルからロードされることになっていますが、loadShader()関数は非ASCII文字を読み込んでシェーダのコンパイルエラーが発生するという奇妙な理由があります。fgetc()が非ASCII文字を読み取るのはなぜですか? (GLSLシェーダーを読み込もうとしています)

here(Notepad ++を使用)の手順に従って、シェイダーファイルをASCII形式に変換しようとすると、結果は同じです。つまり、ASCII以外の文字に関するシェーダーコンパイラエラーです(スクリーンショットを参照)。 )と、予想される赤い三角形の代わりに白(シェーダがコンパイルされていないため)。

さらにトラブルシューティングの試み:

重要なコード部分が14〜44から行く - 私のloadShader機能(注私は、さらに簡単に行番号を参照するためPastebinに私のソースコードをアップロードしました。) 。 デバッグ出力(25行目)がWindowsエクスプローラで提供されているファイルサイズと同じバイト数になっているため、22行目から始まる「tell file size」セクションが以下のスクリーンショットで示されているように正しく動作しています。 さらに、バッファー(28行目)は、41行目のデバッグ出力(スクリーンショット参照)に示されているように、シェーダーファイルサイズに正確に対応しています。 最後に、2つのシェーダのシンタックスは正しいです。前にハードコーディングしていて、結果が望ましい赤い三角レンダリングだったからです。

スクリーンショット:

enter image description here

ソースコード:

// Expected result: Draws a simple red colored triangle to the screen 
// Problem to debug: Why does my loadShader function read non-ASCII characters? 

#include <glad/glad.h> 
#define GLFW_DLL 
#include <GLFW\glfw3.h> 
#include <cstdio> 
#include <iostream> 

// TODO: Debug 
/* Loads shader text files from a given file name (extension required) 
* and returns the shader code as a null terminated string from that file. 
*/ 
const char * loadShader(const char * shaderFileName) { 
    FILE * shaderFile{}; 
    fopen_s(&shaderFile, shaderFileName, "r"); 
    if (!shaderFile) { 
     std::cerr << "ERROR: Cannot open file" << std::endl; 
     return "\0"; 
    } 
    // Tell file size 
    fseek(shaderFile, 0L, SEEK_END); 
    unsigned long shaderFileSize{}; 
    shaderFileSize = ftell(shaderFile); 
    std::cout << "DEBUG: shaderFileSize: " << shaderFileSize << std::endl; // Debug output 
    rewind(shaderFile); 
    // Read from file 
    char * buffer = (char *)malloc(sizeof(char)*(shaderFileSize+1UL)); 
    if (!buffer) { 
     std::cerr << "ERROR: Failed to allocate memory" << std::endl; 
     return "\0"; 
    } 
    int c{}; 
    int i = 0; 
    while ((c = fgetc(shaderFile))!= EOF) { 
     buffer[i++] = c; 
    } 
    // Put '\0' at the end of the buffer (required for OpenGL) 
    buffer[shaderFileSize] = '\0'; 
    std::cout << "DEBUG: buffer: " << buffer << std::endl; // Debug output 
    std::cout << "DEBUG: strlen: " << strlen(buffer) << std::endl; // Debug output 
    fclose(shaderFile); 
    return buffer; 
} // end of loadShader() 

int main() { 
    // Initialize GLFW 
    if (!glfwInit()) { 
     std::cerr << "ERROR: Failed to initialize GLFW3" << std::endl; 
     return -1; 
    } 
    // Create window 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 
    GLFWwindow* window = glfwCreateWindow(640, 480, "OpenGL Game", nullptr, nullptr); 
    if (!window) { 
     std::cerr << "ERROR: Failed to create window with GLFW3" << std::endl; 
     glfwTerminate(); 
     return -1; 
    } 
    glfwMakeContextCurrent(window); 
    // Load all OpenGL function pointers. 
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { 
     std::cerr << "ERROR: Failed to initialize GLAD" << std::endl; 
     return -1; 
    } 
    // Get info from renderer 
    const GLubyte* rendererName = glGetString(GL_RENDERER); 
    const GLubyte* OpenGLVersionSupported = glGetString(GL_VERSION); 
    std::cout << rendererName << std::endl << OpenGLVersionSupported << std::endl; 
    // Enable depth 
    glEnable(GL_DEPTH_TEST); 
    glDepthFunc(GL_LESS); 
    // Define triangle 
    GLfloat points[] = { 0.0f, 0.5f, 0.0f, 
         0.5f, -0.5f, 0.0f, 
         -0.5f, -0.5f, 0.0f }; 
    // Create buffer object 
    GLuint vertexBufferObject = 0; 
    glGenBuffers(1, &vertexBufferObject); 
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW); 
    // Create vertex attribute object 
    GLuint vertexAttributeObject = 0; 
    glGenVertexArrays(1, &vertexAttributeObject); 
    glBindVertexArray(vertexAttributeObject); 
    glEnableVertexAttribArray(0); 
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject); 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); 
    // Load shaders 
    const char * vertexShaderCode = loadShader("VertexShader.glsl"); 
    const char * fragmentShaderCode = loadShader("FragmentShader.glsl"); 
    // Compile shaders 
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); 
    glShaderSource(vertexShader, 1, &vertexShaderCode, nullptr); 
    glCompileShader(vertexShader); 
    // Check vertex shader for compile errors 
    int success = 0; 
    char message[512] = ""; 
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); 
    if (!success) { 
     glGetShaderInfoLog(vertexShader, 512, nullptr, message); 
     std::cerr << "ERROR: Failed to compile vertex shader" << std::endl << message; 
    } 
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 
    glShaderSource(fragmentShader, 1, &fragmentShaderCode, nullptr); 
    glCompileShader(fragmentShader); 
    // Check fragment shader for compile errors 
    success = 0; 
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); 
    if (!success) { 
     glGetShaderInfoLog(fragmentShader, 512, nullptr, message); 
     // TODO: Specify error type in message 
     std::cerr << "ERROR: Failed to compile fragment shader" << std::endl << message; 
    } 
    // Create shader program and link it 
    GLuint shaderProgram = glCreateProgram(); 
    glAttachShader(shaderProgram, vertexShader); 
    glAttachShader(shaderProgram, fragmentShader); 
    glLinkProgram(shaderProgram); 
    // Check for linking errors 
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); 
    if (!success) { 
     glGetShaderInfoLog(shaderProgram, 512, nullptr, message); 
     // TODO: Specify error type in message 
     std::cerr << "ERROR: Failed to link shaders" << std::endl << message; 
    } 
    // Render loop 
    while (!glfwWindowShouldClose(window)) { 
     // Wipe the drawing surface clear 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
     // Use shader program and vertex attribute object 
     glUseProgram(shaderProgram); 
     glBindVertexArray(vertexAttributeObject); 
     // Draw from the currently bound vertex attribute object 
     glDrawArrays(GL_TRIANGLES, 0, 3); 
     glfwPollEvents(); 
     glfwSwapBuffers(window); 
    } 
    // Exit program 
    glfwTerminate(); 
    return 0; 
} // end of main() 
+3

提案::

代わりに、とあなたのコードを置き換えまず、シェーダファイルの文字コードを確認してください。 ASCIIファイルではない場合は、おそらく問題が見つかりました。次に、謎の印刷不可能な文字または非ASCII文字の16進エディタでファイルを調べて、ファイルに驚きがないことを確認します。 – user4581301

+1

なぜ 'fgetc'を使用していますか?あなたは行って、ファイルの長さとすべてを計算しました。どうして 'fread'を使って一度に読むだけではないのですか? –

答えて

3

0xcd初期化されていないメモリを埋めるためにMSVC CRTで使用される値です。あなたのファイルは\r\nの行末を使用していますが、テキストモードで開くと、CRTは行の末尾を\nに変換します。結果として、ftellによって返されるサイズよりも小さいバイトがbufferに読み込まれ、iの最後の値がshaderFileSizeより小さくなります。したがって、最後の値がbuffer[i]に書き込まれ、ヌルターミネーターの間に未初期化バイトがいくつかあります。

FILE * shaderFile{}; 
fopen_s(&shaderFile, shaderFileName, "rb"); // <-------- HERE !!!! 
fseek(shaderFile, 0L, SEEK_END); 
unsigned long shaderFileSize = ftell(shaderFile); 
rewind(shaderFile); 
char * buffer = (char *)malloc(shaderFileSize+1); 
fread(buffer, shaderFileSize, 1, shaderFile); 
buffer[shaderFileSize] = '\0'; 
関連する問題