OpenGL红宝书与Mac OS X

3
我希望能够通过OpenGL红皮书《OpenGL编程指南》第8版,在Mac OS X上使用Xcode进行工作。
我无法运行第一个代码示例triangles.cpp。 我尝试了包含Xcode附带的GLUT和GL框架,并且已经搜索了足够多的内容,发现自己不可能自己解决这个问题。
假设我有一个全新的Mac OS X安装,并且我已经使用Xcode命令行工具进行了全新安装,请提供逐步说明以在该环境中运行triangles.cpp。
问题不同,我的首选项不是使用Cocoa、Objective-C或Swift。我的首选项是只使用C++/C。只有当我能够按照逐步说明并最终获得运行中的triangles.cpp程序时,答案才是正确的。
我偏好的系统是Mac OS X 10.9,但正确的答案可以假定为10.9、10.10或10.11。
谢谢。
///////////////////////////////////////////////////////////////////////
//
// triangles.cpp
//
///////////////////////////////////////////////////////////////////////

#include <iostream>
using namespace std;

#include "vgl.h"
#include "LoadShader.h"

enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };

GLuint  VAOs[NumVAOs];
GLuint  Buffers[NumBuffers];

const GLuint  NumVertices = 6;

//---------------------------------------------------------------------
//
// init
//

void
init(void)
{
    glGenVertexArrays(NumVAOs, VAOs);
    glBindVertexArray(VAOs[Triangles]);

    GLfloat  vertices[NumVertices][2] = {
        { -0.90, -0.90 },  // Triangle 1
        {  0.85, -0.90 },
        { -0.90,  0.85 },
        {  0.90, -0.85 },  // Triangle 2
        {  0.90,  0.90 },
        { -0.85,  0.90 }
    };

    glGenBuffers(NumBuffers, Buffers);
    glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices),
                 vertices, GL_STATIC_DRAW);

    ShaderInfo  shaders[] = {
        { GL_VERTEX_SHADER, "triangles.vert" },
        { GL_FRAGMENT_SHADER, "triangles.frag" },
        { GL_NONE, NULL }
    };

    GLuint program = LoadShaders(*shaders);
    glUseProgram(program);

    glVertexAttribPointer(vPosition, 2, GL_FLOAT,
                          GL_FALSE, 0, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(vPosition);
}

//---------------------------------------------------------------------
//
// display
//

void
display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArray(VAOs[Triangles]);
    glDrawArrays(GL_TRIANGLES, 0, NumVertices);

    glFlush();
}

//---------------------------------------------------------------------
//
// main
//

int
main(int argc, char** argv)
{



     glutInit(&argc, argv);
     glutInitDisplayMode(GLUT_RGBA);
     glutInitWindowSize(512, 512);
     glutInitContextVersion(4, 3);
     glutInitContextProfile(GLUT_CORE_PROFILE);
     glutCreateWindow(argv[0]);

     glewExperimental = GL_TRUE;

     if (glewInit()) {
         cerr << "Unable to initialize GLEW ... exiting" << endl;
         exit(EXIT_FAILURE);
     }

     init();

     glutDisplayFunc(display);

     glutMainLoop();
}

编辑 1: 回复第一条评论,这是一个朴素的尝试。

  • 在 Mac OS X 10.9.5 上打开 Xcode 5.1.1。
  • 创建一个新的 C++ 命令行项目。
  • 用 triangles.cpp 的内容覆盖 main.cpp 的内容。
  • 单击项目 -> Build Phases -> Link Binary with Libraries
  • 添加 OpenGL.framework 和 GLUT.framework

结果:“/Users/xxx/Desktop/Triangles/Triangles/main.cpp:10:10: 找不到 'vgl.h' 文件”

编辑 2: 添加了 vgh 翻译单元和 LoadShaders 翻译单元,还将 libFreeGlut.a 和 libGlew32.a 添加到我的项目编译/链接中。将所有 OpenGL 书籍的包含内容移动到我的项目源目录中。不得不更改几个 include 语句,以使用带引号的 include 替代带角括号的 include。感觉离成功更近了,但无法找到 LoadShader.h。请注意,OpenGL 下载中的翻译单元称为 LoadShaders(复数)。将 triangles.cpp 更改为引用 LoadShaders.h 可以解决 include 问题,但该翻译单元的内容似乎与从 triangles.cpp 调用的签名不匹配。


你遇到了什么问题?有编译器错误或链接器错误吗?它无法启动吗? - BDL
我不倾向于使用我的锤子来关闭这个问题(我目前无法验证它是否解决了问题),但我认为这个问题已经在这里得到了回答:https://dev59.com/VHPYa4cB1Zd3GeqPoN1Y#17799973。 - Dietmar Kühl
我现在正在跟进这些线索,同时请不要关闭这个问题。这两个链接都不是逐步指南,以后可能对其他人有价值。 - Matthew James Briggs
看起来vgl.h和LoadShader.h不是OpenGL或GLUT的一部分。它们似乎是OpenGL红皮书使用的第三方库的一部分。请参见此答案获取更多信息。 - Marc Khadpe
1
我认为调用LoadShaders()应该只是LoadShaders(shaders)shaders已经是类型为ShaderInfo*的变量。 - Marc Khadpe
显示剩余4条评论
5个回答

2

源代码和oglpg-8th-edition.zip文件存在一些问题:

triangles.cpp使用了非标准的GLUT函数,这些函数未包含在glut中,而是仅作为freeglut实现的一部分(glutInitContextVersionglutInitContextProfile)。freeglut并不真正支持OS X,构建它取决于额外的X11支持。我将修改源代码以便使用OS X的GLUT框架进行构建,而不是告诉你如何操作。

该代码依赖于GLEW,并且书籍的源代码下载似乎没有包含可用的二进制文件,因此您需要自行构建它。

使用以下命令构建GLEW:

git clone git://git.code.sf.net/p/glew/code glew
cd glew
make extensions
make

现在:

  • Create a C++ command line Xcode project

  • Set the executable to link with the OpenGL and GLUT frameworks and the glew dylib you just built.

  • Modify the project "Header Search Paths" to include the location of the glew headers for the library you built, followed by the path to oglpg-8th-edition/include

  • Add oglpg-8th-edition/lib/LoadShaders.cpp to your xcode project

  • Paste the triangles.cpp source into the main.cpp of your Xcode project

  • Modify the source: replace #include "vgl.h" with:

    #include <GL/glew.h>
    #include <OpenGL/gl3.h>
    #include <GLUT/glut.h>
    #define BUFFER_OFFSET(x)  ((const void*) (x))
    

    Also make sure that the typos in the version of triangle.cpp that you include in your question are fixed: You include "LoadShader.h" when it should be "LoadShaders.h", and LoadShaders(*shaders); should be LoadShaders(shaders). (The code printed in my copy of the book doesn't contain these errors.)

  • Delete the calls to glutInitContextVersion and glutInitContextProfile.

  • Change the parameter to glutInitDisplayMode to GLUT_RGBA | GLUT_3_2_CORE_PROFILE

目前为止,代码已经构建、链接并运行,但是在我的电脑上运行程序时,显示的是黑色窗口,而不是预期的三角形。


谢谢,这非常有帮助。我也遇到了同样的空白窗口。 - Matthew James Briggs
1
非常感谢bames53的帮助! GLEW似乎对我无效(在输入make后出现一些编译错误)。因此,我从“git clone https://github.com/nigels-com/glew.git glew”克隆了一个新副本。黑色窗口的原因是缺少triangle.vert和triangle.frag文件,其内容将被发送到opengl shade编译中。我最终得出了正确的结果,并将提供另一个答案!再次感谢您的帮助! - gonglong

1
你可以使用此链接中的示例。它几乎相同,只是使用了glfw而不是glut。

http://www.tomdalling.com/blog/modern-opengl/01-getting-started-in-xcode-and-visual-cpp/

/*
 main

 Copyright 2012 Thomas Dalling - http://tomdalling.com/

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

//#include "platform.hpp"

// third-party libraries
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>

// standard C++ libraries
#include <cassert>
#include <iostream>
#include <stdexcept>
#include <cmath>

// tdogl classes
#include "Program.h"

// constants
const glm::vec2 SCREEN_SIZE(800, 600);

// globals
GLFWwindow* gWindow = NULL;
tdogl::Program* gProgram = NULL;
GLuint gVAO = 0;
GLuint gVBO = 0;


// loads the vertex shader and fragment shader, and links them to make the global gProgram
static void LoadShaders() {
    std::vector<tdogl::Shader> shaders;
    shaders.push_back(tdogl::Shader::shaderFromFile("vertex-shader.txt", GL_VERTEX_SHADER));
    shaders.push_back(tdogl::Shader::shaderFromFile("fragment-shader.txt", GL_FRAGMENT_SHADER));
    gProgram = new tdogl::Program(shaders);
}


// loads a triangle into the VAO global
static void LoadTriangle() {
    // make and bind the VAO
    glGenVertexArrays(1, &gVAO);
    glBindVertexArray(gVAO);

    // make and bind the VBO
    glGenBuffers(1, &gVBO);
    glBindBuffer(GL_ARRAY_BUFFER, gVBO);

    // Put the three triangle verticies into the VBO
    GLfloat vertexData[] = {
        //  X     Y     Z
         0.0f, 0.8f, 0.0f,
        -0.8f,-0.8f, 0.0f,
         0.8f,-0.8f, 0.0f,
    };
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);

    // connect the xyz to the "vert" attribute of the vertex shader
    glEnableVertexAttribAxrray(gProgram->attrib("vert"));
    glVertexAttribPointer(gProgram->attrib("vert"), 3, GL_FLOAT, GL_FALSE, 0, NULL);

    // unbind the VBO and VAO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}


// draws a single frame
static void Render() {
    // clear everything
    glClearColor(0, 0, 0, 1); // black
    glClear(GL_COLOR_BUFFER_BIT);

    // bind the program (the shaders)
    glUseProgram(gProgram->object());

    // bind the VAO (the triangle)
    glBindVertexArray(gVAO);

    // draw the VAO
    glDrawArrays(GL_TRIANGLES, 0, 3);

    // unbind the VAO
    glBindVertexArray(0);

    // unbind the program
    glUseProgram(0);

    // swap the display buffers (displays what was just drawn)
    glfwSwapBuffers(gWindow);
}

void OnError(int errorCode, const char* msg) {
    throw std::runtime_error(msg);
}

// the program starts here
void AppMain() {
    // initialise GLFW
    glfwSetErrorCallback(OnError);
    if(!glfwInit())
        throw std::runtime_error("glfwInit failed");

    // open a window with GLFW
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    gWindow = glfwCreateWindow((int)SCREEN_SIZE.x, (int)SCREEN_SIZE.y, "OpenGL Tutorial", NULL, NULL);
    if(!gWindow)
        throw std::runtime_error("glfwCreateWindow failed. Can your hardware handle OpenGL 3.2?");

    // GLFW settings
    glfwMakeContextCurrent(gWindow);

    // initialise GLEW
    glewExperimental = GL_TRUE; //stops glew crashing on OSX :-/
    if(glewInit() != GLEW_OK)
        throw std::runtime_error("glewInit failed");

    // print out some info about the graphics drivers
    std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
    std::cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
    std::cout << "Vendor: " << glGetString(GL_VENDOR) << std::endl;
    std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl;

    // make sure OpenGL version 3.2 API is available
    if(!GLEW_VERSION_3_2)
        throw std::runtime_error("OpenGL 3.2 API is not available.");

    // load vertex and fragment shaders into opengl
    LoadShaders();

    // create buffer and fill it with the points of the triangle
    LoadTriangle();

    // run while the window is open
    while(!glfwWindowShouldClose(gWindow)){
        // process pending events
        glfwPollEvents();

        // draw one frame
        Render();
    }

    // clean up and exit
    glfwTerminate();
}


int main(int argc, char *argv[]) {
    try {
        AppMain();
    } catch (const std::exception& e){
        std::cerr << "ERROR: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

1

关于修复Matthew和Bames53评论中提到的黑屏问题

  1. 按照bames53的答案进行操作
  2. 将着色器定义为字符串

    const char *pTriangleVert = "#version 410 core\n\ layout(location = 0) in vec4 vPosition;\n\ void\n\ main()\n\ {\n\ gl_Position= vPosition;\n\ }";

    const char *pTriangleFrag = "#version 410 core\n\ out vec4 fColor;\n\ void\n\ main()\n\ {\n\ fColor = vec4(0.0, 0.0, 1.0, 1.0);\n\ }";

我的iMac支持OpenGl 4.1,所以我将版本更改为410

ShaderInfo  shaders[] = {
    { GL_VERTEX_SHADER, pTriangleVert},
    { GL_FRAGMENT_SHADER, pTriangleFrag },
    { GL_NONE, NULL }
};
  1. 稍微修改ShaderInfo结构体 将

typedef struct { GLenum type; const char* filename; GLuint shader; } ShaderInfo;

改为

typedef struct { GLenum type; const char* source; GLuint shader; } ShaderInfo;

  1. Modify loadShader function slightly comment the code about reading shader from file

        /*
    const GLchar* source = ReadShader( entry->filename );
    if ( source == NULL ) {
        for ( entry = shaders; entry->type != GL_NONE; ++entry ) {
            glDeleteShader( entry->shader );
            entry->shader = 0;
        }
    
        return 0;
    }
    
    
    glShaderSource( shader, 1, &source, NULL );
    delete [] source;*/
    

    into

    glShaderSource(shader, 1, &entry->source, NULL);

为了防止一些着色器编译错误,最好打开调试模式(DEBUG)


1

我已经在这里适配了MAC项目:

https://github.com/badousuan/openGLredBook9th

该项目可以成功构建,大多数演示可以按预期运行。然而,原始代码基于OpenGL 4.5,而MAC仅支持版本4.1,一些新的API调用可能会失败。如果某些目标表现不佳,您应该考虑这个版本问题并进行适当的调整。


0

我使用了这个教程中的代码 http://antongerdelan.net/opengl/hellotriangle.html ,在我的 Mac 上运行良好。以下是我运行的代码。

#include <GL/glew.h> // include GLEW and new version of GL on Windows
#include <GLFW/glfw3.h> // GLFW helper library
#include <stdio.h>

int main() {
    // start GL context and O/S window using the GLFW helper library
    if (!glfwInit()) {
        fprintf(stderr, "ERROR: could not start GLFW3\n");
        return 1;
    }

    // uncomment these lines if on Apple OS X
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(640, 480, "Hello Triangle", NULL, NULL);
    if (!window) {
        fprintf(stderr, "ERROR: could not open window with GLFW3\n");
        glfwTerminate();
        return 1;
    }
    glfwMakeContextCurrent(window);

    // start GLEW extension handler
    glewExperimental = GL_TRUE;
    glewInit();

    // get version info
    const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
    const GLubyte* version = glGetString(GL_VERSION); // version as a string
    printf("Renderer: %s\n", renderer);
    printf("OpenGL version supported %s\n", version);

    // tell GL to only draw onto a pixel if the shape is closer to the viewer
    glEnable(GL_DEPTH_TEST); // enable depth-testing
    glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"

    /* OTHER STUFF GOES HERE NEXT */

    float points[] = {
        0.0f,  0.5f,  0.0f,
        0.5f, -0.5f,  0.0f,
        -0.5f, -0.5f,  0.0f
    };

    GLuint vbo = 0; // vertex buffer object
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), points, GL_STATIC_DRAW);

    GLuint vao = 0; // vertex array object
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);

    const char* vertex_shader =
    "#version 400\n"
    "in vec3 vp;"
    "void main() {"
    "  gl_Position = vec4(vp, 1.0);"
    "}";

    const char* fragment_shader =
    "#version 400\n"
    "out vec4 frag_colour;"
    "void main() {"
    "  frag_colour = vec4(0.5, 0.0, 0.5, 1.0);"
    "}";

    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, &vertex_shader, NULL);
    glCompileShader(vs);
    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, &fragment_shader, NULL);
    glCompileShader(fs);

    GLuint shader_programme = glCreateProgram();
    glAttachShader(shader_programme, fs);
    glAttachShader(shader_programme, vs);
    glLinkProgram(shader_programme);

    while(!glfwWindowShouldClose(window)) {
        // wipe the drawing surface clear
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glUseProgram(shader_programme);
        glBindVertexArray(vao);
        // draw points 0-3 from the currently bound VAO with current in-use shader
        glDrawArrays(GL_TRIANGLES, 0, 3);
        // update other events like input handling
        glfwPollEvents();
        // put the stuff we've been drawing onto the display
        glfwSwapBuffers(window);
    }

    // close GL context and any other GLFW resources
    glfwTerminate();
    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接