2012-10-19 8 views
1

OpenGL 3.3을 사용하여 렌더링 된 3D 큐브를 얻으려고합니다.OpenGL 3.3과의 정점/인덱스 버퍼 혼동

// Attempt to make a cube in OpenGL 3.3, using GLEW and GLFW 
#include <iostream> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <cmath> 
// Include GLEW (openGL Extension Wrangler) 
#define GLEW_STATIC 
#include <GL/glew.h> 
// Include GLFW (openGL FrameWork) 
#include <GL/glfw.h> 
// Define this helper macro to get an array position 
#define BUFFER_OFFSET(i) ((char *)NULL + (i)) 

static const double PI = 3.14159265358979323846; 

float radians(float inDeg) 
{ 
    return inDeg * PI/180.0 ; 
} 

struct Vertex 
{ // 64 bytes = 16 x 4 bytes per float 
    GLfloat x, y, z ;   // position coordinates 
    GLfloat nx, ny, nz ;  // normal coordinates 
    GLfloat r, g, b, a ;  // color coordinates for vertex shading 
    GLfloat s0, t0 ;   // s and t are the standard texture coordinates 
    GLfloat s1, t1 ;   // (just used as padding) 
    GLfloat s2, t2 ;   // (just used as padding) 
} ; 
// Vertex Attributes 
GLuint  vertexSize  = sizeof(Vertex) ; 
GLuint  positionOffset = 0 ; 
GLuint  colorOffset  = 24 ; 
// Vertex Data - stored dynamically, see BuildCube() 
Vertex  *vertexData ; 
GLuint  *indexData ; 
GLuint  vertexDataLength = 8 ; 
GLuint  indexDataLength = 36 ; 

struct Matrix 
{ // 64 bytes = 16 x 4 bytes per float 
    GLfloat m[16] ; 
} ; 
// Matrix Data 
Matrix  ModelMatrix ; 
Matrix  ViewMatrix ; 
Matrix  ProjMatrix ; 

Matrix IdentityMatrix(void) 
{ // set the diagonal values to one 
    Matrix out ; 
    out.m[0] = 1.0 ; out.m[1] = 0.0 ; out.m[2] = 0.0 ; out.m[3] = 0.0 ; 
    out.m[4] = 0.0 ; out.m[5] = 1.0 ; out.m[6] = 0.0 ; out.m[7] = 0.0 ; 
    out.m[8] = 0.0 ; out.m[9] = 0.0 ; out.m[10] = 1.0 ; out.m[11] = 0.0 ; 
    out.m[12] = 0.0 ; out.m[13] = 0.0 ; out.m[14] = 0.0 ; out.m[15] = 1.0 ; 
    return out ; 
} 

Matrix ZeroMatrix(void) 
{ // set all values to zero 
    Matrix out ; 
    out.m[0] = 0.0 ; out.m[1] = 0.0 ; out.m[2] = 0.0 ; out.m[3] = 0.0 ; 
    out.m[4] = 0.0 ; out.m[5] = 0.0 ; out.m[6] = 0.0 ; out.m[7] = 0.0 ; 
    out.m[8] = 0.0 ; out.m[9] = 0.0 ; out.m[10] = 0.0 ; out.m[11] = 0.0 ; 
    out.m[12] = 0.0 ; out.m[13] = 0.0 ; out.m[14] = 0.0 ; out.m[15] = 0.0 ; 
    return out ; 
} 

Matrix Multiply(const Matrix *m1, const Matrix *m2) 
{ 
    // Since these are note REALLY matrixes, we can get away with a shortcut 
    Matrix out = IdentityMatrix() ; 
    GLuint row, column, row_offset ; 
    for (row = 0; row < 4; row++) 
    { 
     row_offset = row * 4 ; 
     for (column = 0; column < 4; column++) 
     { 
      out.m[row_offset + column] = 
      (m1->m[row_offset + 0] * m2->m[column + 0]) + 
      (m1->m[row_offset + 1] * m2->m[column + 4]) + 
      (m1->m[row_offset + 2] * m2->m[column + 8]) + 
      (m1->m[row_offset + 3] * m2->m[column + 12]) ; 
     } 
    } 
    return out ; 
} 

void Translate(Matrix &inMat, GLfloat dx, GLfloat dy, GLfloat dz) 
{ 
    Matrix TM = IdentityMatrix() ; 
    TM.m[3] = dx ; 
    TM.m[7] = dy ; 
    TM.m[11] = dz ; 
    inMat = Multiply(&inMat, &TM) ; 
} 

void Rotate(Matrix &inMat, GLfloat xAng, GLfloat yAng, GLfloat zAng) 
{ // rotates a vector or point around the origin at the specified angles 
    // create the half-angle values in radians 
    GLfloat rad_x_ang = radians(xAng)/2.0 * -1.0 ;  // multiply by -1 to make the rotation right-handed 
    GLfloat rad_y_ang = radians(yAng)/2.0  ; 
    GLfloat rad_z_ang = radians(zAng)/2.0 ;  // multiply by -1 to make the rotation right-handed 
    // compute sin and cos values, so they're not repeated a LOT 
    GLfloat cosX = cos(rad_x_ang) ; 
    GLfloat sinX = sin(rad_x_ang) ; 
    GLfloat cosY = cos(rad_y_ang) ; 
    GLfloat sinY = sin(rad_y_ang) ; 
    GLfloat cosZ = cos(rad_z_ang) ; 
    GLfloat sinZ = sin(rad_z_ang) ; 
    // create quaternion vector: Q 
    GLfloat q0 = cosZ * cosY * cosX + sinZ * sinY * sinX ; 
    GLfloat q1 = sinZ * cosY * cosX - cosZ * sinY * sinX ; 
    GLfloat q2 = cosZ * sinY * cosX + sinZ * cosY * sinX ; 
    GLfloat q3 = cosZ * cosY * sinX - sinZ * sinY * cosX ; 
    // create rotation matrix 
    Matrix RM ; 
    RM.m[0] = q0*q0+q1*q1+q2*q2+q3*q3 ; RM.m[1] = 0.0      ; RM.m[2] = 0.0      ; RM.m[3] = 0.0      ; 
    RM.m[4] = 0.0      ; RM.m[5] = q0*q0-q1*q1-q2*q2+q3*q3 ; RM.m[6] = 2*q2*q3 - 2*q0*q1  ; RM.m[7] = 2*q1*q3 + 2*q0*q2  ; 
    RM.m[8] = 0.0      ; RM.m[9] = 2*q2*q3 + 2*q0*q1  ; RM.m[10] = q0*q0-q1*q1+q2*q2-q3*q3 ; RM.m[11] = 2*q1*q2 - 2*q0*q3  ; 
    RM.m[12] = 0.0      ; RM.m[13] = 2*q1*q3 - 2*q0*q2  ; RM.m[14] = 2*q1*q2 + 2*q0*q3  ; RM.m[15] = q0*q0+q1*q1-q2*q2-q3*q3 ; 
    // multiply the new rotational matrix with the current incoming matrix 
    inMat = Multiply(&inMat, &RM) ; 
} 

const GLchar* VertexShader = 
{ 
    "#version 330\n"\ 
    "attribute vec3 in_Position;\n"\ 
    "attribute vec4 in_Color;\n"\ 
    "uniform mat4 ModelMatrix;\n"\ 
    "uniform mat4 ViewMatrix;\n"\ 
    "uniform mat4 ProjMatrix ;\n"\ 
    "out  vec4 ex_Color;\n"\ 
    "void main(void)\n"\ 
    "{\n"\ 
    " gl_Position = (ProjMatrix * ViewMatrix * ModelMatrix) * vec4(in_Position, 1.0);\n"\ 
    " ex_Color = in_Color;\n"\ 
    "}\n" 
}; 

const GLchar* FragmentShader = 
{ 
    "#version 330\n"\ 
    "in vec4 ex_Color ;\n"\ 
    "out vec4 out_Color ;\n"\ 
    "void main(void)\n"\ 
    "{\n"\ 
    " out_Color = ex_Color ;\n"\ 
    "}\n" 
}; 

// Shader Attribute IDs 
GLuint  attribute_in_Position ; 
GLuint  attribute_in_Color ; 
GLuint  uniform_ModelMatrix ; 
GLuint  uniform_ViewMatrix ; 
GLuint  uniform_ProjMatrix ; 
// OpenGL Object IDs 
GLuint  VertShaderID ; 
GLuint  FragShaderID ; 
GLuint  GLSLProgID ; 
GLuint  vaoID ; 
GLuint  vboID ; 
GLuint  iboID ; 

// Forward declare functions 
void  BuildCube(void) ; 
void  CreateShaders(void) ; 
void  DestroyShaders(void) ; 
void  InitStuff(void) ; 
bool  DrawStuff(int) ; 
void  KillStuff(void) ; 

void BuildCube(void) 
{ 
    vertexData = new Vertex[8] ; // create a dynamic memory array of 8 vertices 
    indexData = new GLuint[36] ; 
    // specify only 8 vertices (ignore texture and normals for now) 
    vertexData[0].x = 0.5 ; vertexData[0].y = 0.5 ; vertexData[0].z = 0.5 ; 
    vertexData[1].x = -0.5 ; vertexData[1].y = 0.5 ; vertexData[1].z = 0.5 ; 
    vertexData[2].x = -0.5 ; vertexData[2].y = -0.5 ; vertexData[2].z = 0.5 ; 
    vertexData[3].x = 0.5 ; vertexData[3].y = -0.5 ; vertexData[3].z = 0.5 ; 
    vertexData[4].x = 0.5 ; vertexData[4].y = 0.5 ; vertexData[4].z = -0.5 ; 
    vertexData[5].x = -0.5 ; vertexData[5].y = 0.5 ; vertexData[5].z = -0.5 ; 
    vertexData[6].x = -0.5 ; vertexData[6].y = -0.5 ; vertexData[6].z = -0.5 ; 
    vertexData[7].x = 0.5 ; vertexData[7].y = -0.5 ; vertexData[7].z = -0.5 ; 
    // specify all triangles 
    indexData[0] = 0 ; indexData[1] = 1 ; indexData[2] = 2 ; // top 
    indexData[3] = 2 ; indexData[4] = 3 ; indexData[5] = 0 ; 
    indexData[6] = 4 ; indexData[7] = 6 ; indexData[8] = 5 ; // bottom 
    indexData[9] = 6 ; indexData[10] = 4 ; indexData[11] = 7 ; 
    indexData[12] = 2 ; indexData[13] = 1 ; indexData[14] = 5 ; // left 
    indexData[15] = 5 ; indexData[16] = 6 ; indexData[17] = 2 ; 
    indexData[18] = 0 ; indexData[19] = 3 ; indexData[20] = 4 ; // right 
    indexData[21] = 3 ; indexData[22] = 7 ; indexData[23] = 4 ; 
    indexData[24] = 1 ; indexData[25] = 0 ; indexData[26] = 5 ; // front 
    indexData[27] = 0 ; indexData[28] = 4 ; indexData[29] = 5 ; 
    indexData[30] = 3 ; indexData[31] = 2 ; indexData[32] = 6 ; // back 
    indexData[33] = 6 ; indexData[34] = 7 ; indexData[35] = 3 ; 
    // specify the colors 
    for (unsigned int ii = 0; ii < 8; ii++) 
    { // 
     vertexData[ii].r = vertexData[ii].x + 0.5 ; 
     vertexData[ii].g = vertexData[ii].y + 0.5 ; 
     vertexData[ii].b = vertexData[ii].z + 0.5 ; 
     vertexData[ii].a = 1.0 ; 
    } 
    // end BuildCube() 
} 

void CreateShaders(void) 
{ 
    GLenum ErrorCheckValue = glGetError(); 
    // establish vertex shader 
    VertShaderID = glCreateShader(GL_VERTEX_SHADER); 
    glShaderSource(VertShaderID, 1, &VertexShader, NULL); 
    glCompileShader(VertShaderID); 
    // establish fragment shader 
    FragShaderID = glCreateShader(GL_FRAGMENT_SHADER); 
    glShaderSource(FragShaderID, 1, &FragmentShader, NULL); 
    glCompileShader(FragShaderID); 
    // set the GLSL program ID 
    GLSLProgID = glCreateProgram(); 
     // link the vertex and fragment shaders 
     glAttachShader(GLSLProgID, VertShaderID); 
     glAttachShader(GLSLProgID, FragShaderID); 
    glLinkProgram(GLSLProgID); 
    glUseProgram(GLSLProgID); 
    // check for errors before continuing 
    ErrorCheckValue = glGetError(); 
    if (ErrorCheckValue != GL_NO_ERROR) 
    { 
     fprintf(
      stderr, 
      "ERROR: Could not create the shaders: %s \n", 
      gluErrorString(ErrorCheckValue) 
     ); 
     exit(-1); 
    } 
} 

void DestroyShaders(void) 
{ 
    if (!glfwGetWindowParam(GLFW_OPENED)) { return ; } 
    GLenum ErrorCheckValue = glGetError(); 
    glUseProgram(0); 
    glDetachShader(GLSLProgID, VertShaderID); 
    glDetachShader(GLSLProgID, FragShaderID); 
    glDeleteShader(FragShaderID); 
    glDeleteShader(VertShaderID); 
    glDeleteProgram(GLSLProgID); 
    // check for errors last 
    ErrorCheckValue = glGetError(); 
    if (ErrorCheckValue != GL_NO_ERROR) 
    { 
     fprintf(
      stderr, 
      "ERROR: Could not destroy the shaders: %s \n", 
      gluErrorString(ErrorCheckValue) 
     ) ; 
     exit(-1) ; 
    } 
} 

void InitStuff(void) 
{ 
    // Initialise GLFW extension 
    if(!glfwInit()) 
    { // If the extension failed to initialize, then error out and leave. 
     fprintf(stderr, "Failed to initialize GLFW\n") ; 
     return ; 
    } 
    // Establish OpenGL version 3.3 
    glfwOpenWindowHint(GLFW_FSAA_SAMPLES, 4); 
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3); 
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 3); 
    glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 
    glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE); // This compensates for the bug in GLEW 
    // Open a window and create its OpenGL context 
    if(!glfwOpenWindow(512, 512, 0,0,0,0, 0,0, GLFW_WINDOW)) 
    { 
     fprintf(stderr, "Failed to open GLFW window.\n") ; 
     glfwTerminate() ; 
     exit(-1) ; 
    } 
    // Initialize GLEW extension 
    if (glewInit() != GLEW_OK) 
    { 
     fprintf(stderr, "Failed to initialize GLEW\n") ; 
     exit(-1) ; 
    } 
    // Set the title on the upper left of the window 
    glfwSetWindowTitle("Test Window") ; 
    // Ensure we can capture the escape key being pressed below 
    glfwEnable(GLFW_STICKY_KEYS) ; 
    // Clear Screen And Depth Buffer 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ; 

    // Establish the matrixes 
    int width, height ; 
    glfwGetWindowSize(&width, &height);  // assess window size 
    height = height > 0 ? height : 1;   // avoid div/0 error 
    // calculate the projection matrix values 
    GLfloat  fov_y   = 45.0 ; 
    GLfloat  aspect_ratio = (GLfloat) width/(GLfloat) height ; 
    GLfloat  near_plane  = 1.0 ; 
    GLfloat  far_plane  = 100.0 ; 
    GLfloat  y_scale  = 1.0/tan(radians(fov_y/2.0)) ; 
    GLfloat  x_scale  = y_scale/aspect_ratio ; 
    GLfloat  frustum_length = far_plane - near_plane ; 
    ProjMatrix = ZeroMatrix() ; 
    ProjMatrix.m[0] = x_scale ; 
    ProjMatrix.m[5] = y_scale ; 
    ProjMatrix.m[10] = -((far_plane + near_plane)/frustum_length) ; 
    ProjMatrix.m[11] = -1.0 ; 
    ProjMatrix.m[14] = -((2.0 * near_plane * far_plane)/frustum_length) ; 

    // Establish the model and view matrixes as identity matrixes 
    ModelMatrix = IdentityMatrix() ; 
    ViewMatrix = IdentityMatrix() ; 

    Translate(ViewMatrix, 0.0, 0.0, -2.0) ; 
    // Creat the error enumeration 
    GLenum ErrorCheckValue = glGetError(); 

    // Create the vertex and fragment shaders 
    CreateShaders() ; 
    // Bind the vertex shader attributes to their IDs 
    attribute_in_Position = glGetAttribLocation(GLSLProgID, "in_Position") ; 
    attribute_in_Color = glGetAttribLocation(GLSLProgID, "in_Color" ) ; 
    uniform_ModelMatrix = glGetUniformLocation(GLSLProgID, "ModelMatrix") ; 
    uniform_ViewMatrix = glGetUniformLocation(GLSLProgID, "ViewMatrix") ; 
    uniform_ProjMatrix = glGetUniformLocation(GLSLProgID, "ProjMatrix") ; 

    // upload the projection matrix data to the GPU 
    glUniformMatrix4fv(uniform_ModelMatrix, 1, GL_TRUE, ModelMatrix.m); 
    glUniformMatrix4fv(uniform_ViewMatrix , 1, GL_TRUE, ViewMatrix.m); 
    glUniformMatrix4fv(uniform_ProjMatrix , 1, GL_TRUE, ProjMatrix.m); 

    // Build the Cube Geometry 
    BuildCube() ; 

    // Initialize the Vertex Buffer Object in OpenGL 
    glGenBuffers(1, &vboID); 
    glBindBuffer(GL_ARRAY_BUFFER, vboID); 
    glBufferData(GL_ARRAY_BUFFER, vertexSize * vertexDataLength, NULL, GL_STATIC_DRAW); 
    glBufferSubData(GL_ARRAY_BUFFER, 0, vertexSize * vertexDataLength, vertexData); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    // Initialize the Index Buffer Object in OpenGL 
    glGenBuffers(1, &iboID); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexDataLength, NULL, GL_STATIC_DRAW); 
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(GLuint) * indexDataLength, indexData); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 



    // Check for errors, then done 
    ErrorCheckValue = glGetError() ; 
    if (ErrorCheckValue != GL_NO_ERROR) 
    { 
     fprintf(
      stderr, 
      "ERROR: Could not complete initialization: %s \n", 
      gluErrorString(ErrorCheckValue) 
     ) ; 
     exit(-1) ; 
    } 
    // end InitStuff() 
} 

bool DrawStuff(int frame) 
{ 
    int width, height ; 
    glfwGetWindowSize(&width, &height) ; // First, re-assess the window size 
    height = height > 0 ? height : 1 ;  // avoid div/0 error 
    // for now, vary the background color so we know it's updating 
    GLfloat phase_offset = 125.0f ; 
    GLfloat speed_mult = 0.01f ; 
    GLfloat bgColorR = 0.5f * (sin((frame-0)*speed_mult) + 1.0f); 
    GLfloat bgColorG = 0.5f * (sin((frame-phase_offset)*speed_mult) + 1.0f); 
    GLfloat bgColorB = 0.5f * (sin((frame-2*phase_offset)*speed_mult) + 1.0f); 
    glClearColor(bgColorR, bgColorG, bgColorB, 0.0f); 
    // Handle projection stuff 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glViewport(0, 0, width, height); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    // 
    GLenum ErrorCheckValue = glGetError(); 

    glEnable(GL_DEPTH_TEST) ; 
    glDepthFunc(GL_LESS) ; 
    glEnable(GL_CULL_FACE) ; 
    glCullFace(GL_BACK) ; 
    glFrontFace(GL_CCW) ; 

    ErrorCheckValue = glGetError(); 
    if (ErrorCheckValue != GL_NO_ERROR) 
    { 
     fprintf(
      stderr, 
      "ERROR: Could not set OpenGL culling options: %s \n", 
      gluErrorString(ErrorCheckValue) 
     ) ; 
     exit(-1) ; 
    } 


    // switch to model view mode 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 

    // Assume I have multiple VBOs, but streamline for only one for now 
    glPushMatrix() ; 

     // re-bind the VBO data into the buffer 
     glBindBuffer(GL_ARRAY_BUFFER, vboID) ; 
     glVertexAttribPointer(attribute_in_Color, 4, GL_FLOAT, GL_FALSE, vertexSize, BUFFER_OFFSET(colorOffset)) ; 
     glEnableVertexAttribArray(attribute_in_Color) ; 

     glBindBuffer(GL_ARRAY_BUFFER, vboID) ; 
     glVertexAttribPointer(attribute_in_Position, 3, GL_FLOAT, GL_FALSE, vertexSize, BUFFER_OFFSET(positionOffset)) ; 
     glEnableVertexAttribArray(attribute_in_Position) ; 

     // bind the indexes of the vertices to the buffer 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID) ; 

     Rotate(ModelMatrix, 0.0, 0.0, 0.5) ; 
     glUniformMatrix4fv(uniform_ModelMatrix, 1, GL_TRUE, ModelMatrix.m); 

     ErrorCheckValue = glGetError(); 
     if (ErrorCheckValue != GL_NO_ERROR) 
     { 
      fprintf(
       stderr, 
       "ERROR: Could not prep for draw: %s \n", 
       gluErrorString(ErrorCheckValue) 
      ) ; 
      exit(-1) ; 
     } 

     glDrawArrays(GL_TRIANGLES, 0, indexDataLength); 

     glDisableVertexAttribArray(attribute_in_Color) ; 
     glDisableVertexAttribArray(attribute_in_Position) ; 
     glBindBuffer(GL_ARRAY_BUFFER, 0) ; 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) ; 

    glPopMatrix(); 
    // lastly, swap buffers, then return the status 
    glfwSwapBuffers(); 
    return !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED); 
} 

void KillStuff(void) 
{ 
    DestroyShaders(); 
    glfwTerminate(); 
} 

int main() 
{ 
    int  frame = 0 ; 
    bool running = true; 
    InitStuff() ; 
    while(running) 
    { 
     frame++; 
     running = DrawStuff(frame) ; 
    } 
    KillStuff() ; 
    return 0; 
} 

결과는 정말 적절한 색인을 따르지 않는 약 3 부분적으로 형성된 삼각형이다 : 나는 여기 Chapter 4 of the OpenGL book

에서 코드 떨어져 거의 내 코드를 기반으로 작성하는 것은 내 코드입니다. 나는 문제가 인덱스 버퍼에 있다고 생각하지만 실제로 인덱스와 버텍스 버퍼를 잘못 사용하고 있는지 이해하는 데 도움이 될 수 있습니다. 나는 내가 뭘 잘못하고 있는지 오히려 혼란 스럽다.

답변

3

glDrawArrays은 정점 인덱스를 읽지 않으며 GL_ARRAY_BUFFER에서 순서대로 정점을 그립니다. 인덱스 버퍼를 사용하려면 대신 glDrawElements을 사용해야합니다.

앞으로도 관련 코드 섹션 만 게시하십시오. 관련성이 있는지 확실하지 않은 경우 포함 측면에 오류가 있지만 행렬 조작 함수, 셰이더 연결 함수 등을 파헤 치지 않고도 중요한 것을 찾을 수는 없습니다. 간결하게 게시하면 더 나은 답변을 얻을 수 있습니다. 암호.

+0

제 사과, 나는 "compileable"코드를 게시하려고했습니다. 나는 아직도 간결한 OpenGL 응용 프로그램을 만드는 방법을 배우고있다. – user1731740

+0

오 오케이, 그건 고귀한 노력이라고 생각합니다. 불행하게도 실제로는 현대식 OpenGL 응용 프로그램을 작성하는 간결한 방법이 없습니다. 많은 프레임 워크가 필요합니다. 가독성과 컴파일 가능성의 절충안이라고 생각합니다. 문제에 가장 적합한 것으로 생각하는 것을 선택할 수 있지만, 제 의견은 작은 코드 덩어리가 더 쉽고 대답하기 쉽다는 것입니다. – Tim

+0

거룩한 와우! 나는 당신이 말했듯이 glDrawElements로 바꾸었고 지금은 큐브입니다. 고맙습니다! – user1731740