개발 · 컴퓨터공학 / / 2024. 11. 21. 11:06

Mac 환경에서 OpenGL 프로젝트 세팅 visual studio code (vscode)

728x90
반응형

 

맥북 opengl

필자는 윈도우 환경에서 opengl을 많이 사용했었는데, 

학회 같은 곳에 가게되면 데스크탑을 들고갈 순 없으니

배터리가 오래가는 mac 북으로 작업을 할 수 있으면 좋겠다고 생각했다.

 

맥북에서는 visual studio를 사용하지 못하는데 xcode? vscode? 어떻게 opengl 프로젝트를 설치하고 실행하면 될지

오픈소스 opengl 프로젝트를 가지고 실행하는 세팅을 해보려 한다. 

 

vscode 방법

https://www.youtube.com/watch?v=7-dL6a5_B3I

 

vscode에서 clang 컴파일러를 선택하는 방법으로 진행할 수도 있다. 

 

우선 맥북에는 패키지 관리 툴인 homebrew가 설치되어있어야한다.

 

프로젝트 폴더에 include, library, dependencies 세 디렉토리 구조를 만든다.

 



brew install glfw

brew로 glfw를 설치해주고

 

brew --prefix glfw

설치경로를 확인하고 접근해서 라이브러리를 가져오자. 

 

glfw 경로 안에는 lib 폴더가 있고

그 안에 lib파일들이 있으니 이를 가져오는 것이다.

이중 libglfw.3.x.dylib 파일만 가져와서 library 디렉토리로 복사한다.

 

cpp파일을 하나 만들어주고, 컴파일러를 설정한다.

 

원래 이렇게 떠야하는데, 이게 안떠서 컴파일러가 왜 없나 싶었다.

 

아무래도 Xcode Command Line Tools를 설치하면 함께 설치되는 모양이다. 

xcode-select --install

음.. 하지만 이미 설치되어있다고 나온다. 이 문제는 아닌 것 같다. 

 

vscode를 다시 켜보니 이렇게 C++파일을 인지하고 clang을 설치할거냐고 물어보는데 설치해본다. 

 

이 extension을 설치하고, 또 C++확장에 대해서 설정할거냐는 알림이 뜨는데,

그걸 yes하고 설치해주면

 

이제서야 컴파일러를 설정할 수 있게 되었다.

clang++에 대한 tasks.json 설정을 가져오도록 하자.

 

이 tasks 코드에 추가적인 설정을 넣어주자.

 

{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "cppbuild",
			"label": "C/C++: clang++ 활성 파일 빌드",
			"command": "/usr/bin/clang++",
			"args": [
				"-std=c++17", 
				"-Wall", //# ignore warnings
				"-I${workspaceFolder}/dependencies/include", //# specify path to our include files with -I
				"-L${workspaceFolder}/dependencies/library", //# specify the path to our library so with -L flag add path to our library
				"${workspaceFolder}/*.cpp", //# execute all the cpp files so write *.cpp
				"${workspaceFolder}/dependencies/library/libglfw.3.3.dylib",
				"${workspaceFolder}/app", //# famework 추가
				"-framework", 
				"OpenGL",
				"-framework",
				"CoCoa",
				"-framework",
				"IOKit",
				"-framework",
				"CoreVideo",
				"-framework",
				"CoreFoundation", //# disable the warning about warning no the deprecated 
				"-Wno-deprecated",
			],
			"options": {
				"cwd": "${fileDirname}"
			},
			"problemMatcher": [
				"$gcc"
			],
			"group": {
				"kind": "build",
				"isDefault": true
			},
			"detail": "컴파일러: /usr/bin/clang++"
		}
	]
}

그리고 cpp 파일 샘플 코드도 넣어서 실행해보자.

 

#include <GLFW/glfw3.h>

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

 

근데 왠지 모르게 include에서 에러가 나네

 

..생각해보니 glfw 코드를 include 경로에 넣는걸 깜박했다;;

 

이렇게 경로에 잘 넣었는데도 오류가 난다.

에러로그를 보니 glfw library를 3.3 버전을 찾고 있었다. 

현재 내가 넣은 버전은 3.4인데 명시를 잘못 해놓은건가 싶다. 

 

"${workspaceFolder}/dependencies/library/libglfw.3.4.dylib",
 

tasks.json에서

glfw library에 대한 버전 명시를 3.4 버전으로 바꾸고 해보자. 

 

에러가 하나 지워졌지만, 여전히 하나의 에러가 남앗는데

app이라는 파일이 없다고 말하고 있다. 

 

{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "cppbuild",
			"label": "C/C++: clang++ 활성 파일 빌드",
			"command": "/usr/bin/clang++",
			"args": [
				"-std=c++17",
				"-fdiagnostics-color=always",
				"-Wall",
				"-g",
				"-I${workspaceFolder}/dependencies/include",
				"-L${workspaceFolder}/dependencies/library",
				"${workspaceFolder}/*.cpp",
				"${workspaceFolder}/dependencies/library/libglfw.3.4.dylib",
				"-o",
				"${workspaceFolder}/app",
				"-framework",
				"OpenGL",
				"-framework",
				"Cocoa",
				"-framework",
				"IOKit",
				"-framework",
				"CoreVideo",
				"-framework",
				"CoreFoundation",
				"-Wno-deprecated-declarations"
			],
			"options": {
				"cwd": "${fileDirname}"
			},
			"problemMatcher": [
				"$gcc"
			],
			"group": {
				"kind": "build",
				"isDefault": true
			},
			"detail": "컴파일러: /usr/bin/clang++"
		}
	]
}

tasks.json 코드를 잘못 적은 것 같아서 참고 자료를 따라 다시 적어보고 실행해보았다.

그러니 정상 빌드가 되었고

 

./app 명령어로 빌드된 앱을 실행하면

이렇게 창이 띄워진다. 

 

https://glad.dav1d.de

 

https://glad.dav1d.de

gl Version 1.0Version 1.1Version 1.2Version 1.3Version 1.4Version 1.5Version 2.0Version 2.1Version 3.0Version 3.1Version 3.2Version 3.3Version 4.0Version 4.1Version 4.2Version 4.3Version 4.4Version 4.5Version 4.6None

glad.dav1d.de

 

다음으로 glad 라이브러리를 사이트에서 다운받아준다. 

 

gl과 profile 설정만 해주고 밑에 generate로 만들어주고 zip파일을 다운받는다.

 

압축을 풀고 안에있는 include 디렉토리 내부 폴더들을 프로젝트의 include 경로에 넣어준다. 

 

그리고 src 파일에 있던 스크립트는 프로젝트 위치에 소스로 추가해준다.

 

tasks.json 파일을 수정해서 glad.c 소스를 사용하도록 추가해준다. 

 

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\0";
const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";

int main()
{
    // glfw: initialize and configure
    // ------------------------------
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

    // glfw window creation
    // --------------------
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // glad: load all OpenGL function pointers
    // ---------------------------------------
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }


    // build and compile our shader program
    // ------------------------------------
    // vertex shader
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    // check for shader compile errors
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // fragment shader
    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    // check for shader compile errors
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // link shaders
    unsigned int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    // check for linking errors
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // set up vertex data (and buffer(s)) and configure vertex attributes
    // ------------------------------------------------------------------
    float vertices[] = {
        -0.5f, -0.5f, 0.0f, // left  
         0.5f, -0.5f, 0.0f, // right 
         0.0f,  0.5f, 0.0f  // top   
    }; 

    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    glBindVertexArray(0); 


    // uncomment this call to draw in wireframe polygons.
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        // input
        // -----
        processInput(window);

        // render
        // ------
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // draw our first triangle
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
        glDrawArrays(GL_TRIANGLES, 0, 3);
        // glBindVertexArray(0); // no need to unbind it every time 
 
        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // optional: de-allocate all resources once they've outlived their purpose:
    // ------------------------------------------------------------------------
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteProgram(shaderProgram);

    // glfw: terminate, clearing all previously allocated GLFW resources.
    // ------------------------------------------------------------------
    glfwTerminate();
    return 0;
}

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}

이번에는 이 예제 코드로 opengl 삼각형을 띄워보자. 

빌드를 해보면 warning이 뜨긴 하는데 정상적으로 빌드는 된 모양이다. 

 

성공이다!

맥북에서 opengl을 사용할 수는 있는 모양이다.

하지만 이걸로 프로젝트를 했을 때 windows 라이브러리에 의해서 막히지 않게 할 수 있을까?

728x90
반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유