OpenGL红皮书与Mac OS X

OpenGL Red Book with Mac OS X

本文关键字:Mac OS OpenGL      更新时间:2023-10-16

我想在Mac OS X上使用Xcode来完成OpenGL红皮书,OpenGL编程指南,第8版。

我无法运行第一个代码示例triangles.cpp。我已经尝试将Xcode附带的GLUT和GL框架包括在内,我已经搜索了足够多的内容,发现我不太可能独自解决这个问题。

假设我新安装了Mac OS X,并且使用Xcode命令行工具新安装了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的属性上
  • 点击项目->构建阶段->链接二进制与库
  • 添加OpenGL.framework和GLUT.framework

结果:"/Users/xxx/Desktop/Triangles/Tariangles/main.cpp:10:10:'vgl.h'文件未找到"

编辑2:添加了vgh翻译单元和LoadShaders翻译单元,还将libFreeGlut.a和libGlew32.a添加到我的项目编译/链接中。已将OpenGL Book的所有Include内容移动到我的项目源目录中。不得不将几个include语句更改为使用带引号的include,而不是带角度的include。感觉这更接近工作,但找不到LoadShader.h。请注意,OpenGL下载中的翻译单元称为LoadShaders(复数)。将triangles.cpp更改为引用LoadShaders.h修复了include问题,但该翻译单元的内容似乎与triangless.cpp中调用的内容的签名不匹配。

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

triangles.cpp使用了不包含在GLUT中的非标准GLUT函数,而这些函数只是freeglut实现(glutInitContextVersionglutInitContextProfile)的一部分。freeglut并不真正支持OSX,构建它依赖于额外的X11支持。与其告诉你如何做到这一点,我只想修改源代码,用OSX的GLUT框架构建。

代码依赖于glew,而这本书的源代码下载显然不包括你可以使用的二进制文件,所以你需要自己构建它。

使用以下命令构建GLEW:

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

现在:

  • 创建C++命令行Xcode项目

  • 将可执行文件设置为与OpenGL和GLUT框架以及您刚刚构建的glew-dylib链接。

  • 修改项目"Header Search Paths"以包括您构建的库的glew标头的位置,然后是指向oglpg-8th-edition/include 的路径

  • 将oglpg-8th-edition/lib/LoadShaders.cpp添加到您的xcode项目

  • 将triangles.cpp源代码粘贴到Xcode项目的main.cpp中

  • 修改来源:将#include "vgl.h"替换为:

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

    此外,请确保您在问题中包含的triangle.cpp版本中的拼写错误已得到修复:您包含了"LoadShader.h",而它应该是"LoadShaders.h",而LoadShaders(*shaders);应该是LoadShaders(shaders)。(我这本书的代码中没有这些错误。)

  • 删除对glutInitContextVersionglutInitContextProfile的调用。

  • 将参数从glutInitDisplayMode更改为GLUT_RGBA | GLUT_3_2_CORE_PROFILE

在这一点上,代码构建、链接和运行,但是运行程序会为我显示一个黑色窗口,而不是预期的三角形。

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

  1. 按照bames53的回答
  2. 将着色器定义为字符串

    const char*pTriangleVert="#版本410核心\n\vec4vPosition中的布局(位置=0);\n\无效\n\main()\n\{\n\gl_Position=v位置;\n\}";

    const char*pTriangleFrag="#版本410核心\n\out vec4fColor;\n\无效\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. 稍微修改loadShader函数注释有关从文件读取着色器的代码

        /*
    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;*/
    

    进入

    glShaderSource(着色器,1,&entry->source,NULL);

你最好打开DEBUG,以防出现一些着色器编译错误

你可以使用这个链接中的示例。这几乎是一样的。它使用glfw而不是供过于求。

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;
}

我在这里为MAC调整了项目:https://github.com/badousuan/openGLredBook9th

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

我使用本教程中的代码: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 GLFW3n");
        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 GLFW3n");
        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: %sn", renderer);
    printf("OpenGL version supported %sn", 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 400n"
    "in vec3 vp;"
    "void main() {"
    "  gl_Position = vec4(vp, 1.0);"
    "}";
    const char* fragment_shader =
    "#version 400n"
    "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;
}