2017-12-02 264 views
0

我想绘制一些使用OpenGL与VAO和VBO对象的东西。要做到这一点,我只需要分类NSOpenGLView。默认情况下,使用OpenGL v2.1,所以,我放了一个PixelFormat,编写代码,并解决了所有打印错误。目前该应用运行良好,但没有任何东西在窗口绘制,即使glClearColor也没有效果。请帮助我找到并解决问题。我的操作系统是带有OpenGL v4.1的Mac v10.12。OpenGL在Mac上没有绘制任何东西,Objective-C

MyOpenGLView.m,第1部分:

#import "MyOpenGLView.h" 
#include <OpenGL/gl3.h> 
#include "error.h" 

static const char *vertexShaderSource = 
"#version 410\n" 
"in vec3 posAttr;\n" 
"in vec3 colAttr;\n" 
"out vec3 col;\n" 
"void main() {\n" 
" col = colAttr;\n" 
" gl_Position.xyz = posAttr;\n" 
" gl_Position.w = 1.0;\n" 
" col = colAttr;\n" 
"}\n"; 

static const char *fragmentShaderSource = 
"#version 410\n" 
"in vec3 col;\n" 
"out vec4 color;\n" 
"void main() {\n" 
" color.rgb = col;\n" 
" color.a = 1.0;\n" 
//" color = vec4(1,1,1,1);\n" 
"}\n"; 

// Shader properties 
GLuint m_posAttr; 
GLuint m_colAttr; 
GLuint program; 

// Arrays of positions and colors 
float fTriangle[9]; 
float fTriangleColor[9]; 

// Low-level VBOs and VBAs 
GLuint uiVBO[2]; 
GLuint uiVAO[1]; 


GLuint makeShader(GLenum type, const char *source) { 
    GLuint shader; 

    shader = glCreateShader(type); 
    GetError(); 
    glShaderSource(shader, 1, &source, NULL); 
    GetError(); 
    glCompileShader(shader); 
    GetError(); 

#if defined(DEBUG) 
    GLint logLength; 

    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); 
    GetError(); 
    if (logLength > 0) { 
     GLchar *log = malloc((size_t)logLength); 
     glGetShaderInfoLog(shader, logLength, &logLength, log); 
     GetError(); 
     NSLog(@"Shader compilation failed with error:\n%s", log); 
     free(log); 
    } 
#endif 

    GLint status; 
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 
    GetError(); 
    if (0 == status) { 
     glDeleteShader(shader); 
     GetError(); 
     NSLog(@"Shader compilation failed from code!"); 
     assert(0); 
    } 

    return shader; 
} 

MyOpenGLView.m,第2部分:

//// General staff 

@implementation MyOpenGLView 

- (void)awakeFromNib { 
    // Positions and colors of figures 
    fTriangle[0] = -0.4f; fTriangle[1] = 0.1f; fTriangle[2] = 0.0f; 
    fTriangle[3] = 0.4f; fTriangle[4] = 0.1f; fTriangle[5] = 0.0f; 
    fTriangle[6] = 0.0f; fTriangle[7] = 0.7f; fTriangle[8] = 0.0f; 
    fTriangleColor[0] = 1.0f; fTriangleColor[1] = 0.0f; fTriangleColor[2] = 0.0f; 
    fTriangleColor[3] = 0.0f; fTriangleColor[4] = 1.0f; fTriangleColor[5] = 0.0f; 
    fTriangleColor[6] = 0.0f; fTriangleColor[7] = 0.0f; fTriangleColor[8] = 1.0f; 


    NSOpenGLPixelFormatAttribute attrs[] = { 
     NSOpenGLPFADoubleBuffer, 
     NSOpenGLPFADepthSize, 24, 
     NSOpenGLPFAOpenGLProfile, 
     NSOpenGLProfileVersion4_1Core, 
     0 
    }; 
    NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; 
    if (!pf) { 
     NSLog(@"No OpenGL pixel format"); 
    } 
    NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil]; 
    [self setPixelFormat:pf]; 
    [self setOpenGLContext:context]; 
    NSLog(@"%s", glGetString(GL_VERSION)); 
    GetError(); 

    GLuint vertexShader = makeShader(GL_VERTEX_SHADER, vertexShaderSource); 
    GLuint fragmentShader = makeShader(GL_FRAGMENT_SHADER, fragmentShaderSource); 

    program = glCreateProgram(); 
    GetError(); 
    glAttachShader(program, vertexShader); 
    GetError(); 
    glAttachShader(program, fragmentShader); 
    GetError(); 
    glLinkProgram(program); 
    GetError(); 
    GLint status; 
    glGetProgramiv(program, GL_LINK_STATUS, &status); 
    GetError(); 
    if (0 == status) { 
     NSLog(@"Failed to link shader program"); 
     assert(0); 
    } 

    m_posAttr = glGetAttribLocation(program, "posAttr"); 
    GetError(); 
    m_colAttr = glGetAttribLocation(program, "colAttr"); 
    GetError(); 

    glGenVertexArrays(1, &uiVAO[0]); 
    glGenBuffers(2, &uiVBO[0]); 
    GetError(); 
} 

- (void)drawRect:(NSRect)dirtyRect { 
    [super drawRect:dirtyRect]; 

    glClearColor(0, 0, 0, 0); 
    glClear(GL_COLOR_BUFFER_BIT); 

    glUseProgram(program); 
    GetError(); 

    glBindVertexArray(uiVAO[0]); 
    GetError(); 

    glBindBuffer(GL_ARRAY_BUFFER, uiVBO[0]); 
    glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), fTriangle, GL_STATIC_DRAW); 
    glEnableVertexAttribArray(m_posAttr); 
    GetError(); 
    glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, 0); 
    GetError(); 

    glBindBuffer(GL_ARRAY_BUFFER, uiVBO[1]); 
    glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), fTriangleColor, GL_STATIC_DRAW); 
    glEnableVertexAttribArray(m_colAttr); 
    GetError(); 
    glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, 0); 
    GetError(); 

    glDrawArrays(GL_TRIANGLES, 0, 3); 
    GetError(); 

    glDisableVertexAttribArray(m_posAttr); 
    glDisableVertexAttribArray(m_colAttr); 

    glFlush(); 
    GetError(); 
} 

- (void)dealloc { 
    glDeleteProgram(program); 
    glDeleteBuffers(2, uiVBO); 
    glDeleteVertexArrays(1, uiVAO); 
    GetError(); 
} 

@end 

error.h:

//// Prints OpenGL errors 

#ifndef __ERROR_H__ 
#define __ERROR_H__ 

#include <stdlib.h> 
#include <assert.h> 

#ifdef DEBUG 

#define GetError()\ 
{\ 
for (GLenum Error = glGetError(); (GL_NO_ERROR != Error); Error = glGetError())\ 
{\ 
switch (Error)\ 
{\ 
case GL_INVALID_ENUM:  printf("\n%s\n\n", "GL_INVALID_ENUM"  ); assert(0); break;\ 
case GL_INVALID_VALUE:  printf("\n%s\n\n", "GL_INVALID_VALUE" ); assert(0); break;\ 
case GL_INVALID_OPERATION: printf("\n%s\n\n", "GL_INVALID_OPERATION"); assert(0); break;\ 
case GL_OUT_OF_MEMORY:  printf("\n%s\n\n", "GL_OUT_OF_MEMORY" ); assert(0); break;\ 
default:                    break;\ 
}\ 
}\ 
} 

#else 

#define GetError() 

#endif /* DEBUG  */ 
#endif /* __ERROR_H__ */ 
+0

我看到的第一件事就是你必须在** glClear之前调用glClearColor **。否则它不起作用。下一步:在VAO设置代码之后绑定VAO - >当VAO绑定时没有存储在VAO中的信息 - >所有设置均被重置。下一步:你不应该在每一帧重新创建VAO和VBO。它们应该生成一次,然后在绘图方法中使用。 – BDL

+1

既然有太多不同的东西看起来不对,你应该考虑寻找一个好的教程。 – BDL

+0

@BDL谢谢!我会尽力解决它并更新问题。我搜索了很好的教程,但我只找到了旧教程。我试图按照[这一个](https://github.com/beelsebob/Cocoa-GL-Tutorial) –

回答

0

经过大量努力和代码的修改,我发现:唯一真正的问题是NSOpenGLPixelFormatAttribute阵列中的NSOpenGLPFADoubleBuffer选项。评论这个选项后,我得到了所需的输出。

在我看来,原因是我有2个输出图形缓冲区。但是,代码只执行一次,第一个缓冲区被绘制,然后交换。所以,绘制了第二个空的缓冲区。