Почему этот шейдер OpenGL ES 2.0 не работает с моим VBO на iOS? - PullRequest
7 голосов
/ 29 августа 2011

Если кто-то может пролить свет на то, что здесь происходит не так, как, возможно, неправильное указание команд gl или какая-либо другая несовместимая последовательность команд, я был бы чрезвычайно признателен за вашу помощь. Я пытался заставить этот код работать весь день, но безуспешно, несмотря на многочисленные исследования Google и изучение примеров в «Руководстве по программированию OpenGL ES 2.0».

Я пытаюсь использовать объект Vertex Buffer и пользовательские шейдеры в OpenGL ES 2.0 на iPhone. Я пытаюсь чередовать данные вершин из ряда пользовательских структур следующего типа:

typedef struct {
    float x, y; // Position.
    float radius;
    float colR,colG,colB,colA; // Color rgba components.
} VType;

Положение, радиус и цвет байтов должны учитываться для местоположения вершины, размера точки и цвета соответственно. Идентификаторы для них инициализируются:

ID_ATT_Pos = 0;
ID_ATT_Radius = 1;
ID_ATT_Color = 2;
// Note: I have also tried values of 1,2,3 but no difference.

Шаг для них указывается в каждом вызове glVertexAttribPointer.

Предполагается, что каждая вершина будет нарисована в своем положении x, y с указанным цветом и размером точки ее радиуса. С каждым вышеупомянутым атрибутом связан атрибут вершинного шейдера, это «a_position», «a_color» и «a_radius». Вот вершинные и фрагментные шейдеры:

VertexShader.txt

attribute vec2 a_position;      
attribute vec4 a_color;     
attribute float a_radius;       
varying vec4 v_color;
void main()
{
    gl_Position = vec4(a_position,0.0,1.0);
    gl_PointSize = a_radius;
    v_color = a_color;
}

FragmentShader.txt

#ifdef GL_FRAGMENT_PRECISION_HIGH
    precision highp float;
#else
    precision mediump float;
#endif
void main()
{
    gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}

Интересно, требуется ли матрица проекции в вершинном шейдере? Все точки, которые я создаю, являются двумерными по размерам экрана iPhone, и, как вы можете видеть, к каждой из них в вершинном шейдере добавлено 'z, w', как '0.0,1.0'.

Остальной основной код для настройки VBO и рендеринга с использованием glDrawElements приведен ниже. При выполнении этого кода становится очевидным, что glClear был успешным, и печать NSLog действительно подтверждает это, однако вершины VType не отображаются в области просмотра с помощью кода DrawFrame, указанного ниже. Координаты вершины находятся в пределах размеров экрана, например, х, у: (92, 454).

Обратите внимание, что любые необъявленные переменные в следующем коде являются свойствами класса и имеют соответствующий тип, например, «vao» - это GLuint, «vbos» - это GLuint [2], «программа» - дескриптор программы GLuint. Я также пропустил стандартный код установки OpenGL, который был протестирован с различными внутренними кодами и показан для работы.

Код загрузки шейдера

-(GLuint)loadShaderType:(GLenum)type From:(NSString*)shaderFile {
    GLuint shader;
    GLint compiled;

    // Create and compile vertex shader.
    NSString *filepath = [[NSBundle mainBundle] pathForResource:shaderFile ofType:@"txt"];

    const GLchar *shaderSrc = (GLchar *)[[NSString stringWithContentsOfFile:filepath encoding:NSUTF8StringEncoding error:nil] UTF8String];
    if (!shaderSrc) {
        NSLog(@"Failed to load vertex shader");
        return 0;
    }

    // Create shader object.
    shader = glCreateShader(type);
    if (shader == 0) return 0;
    // Load shader source.
    glShaderSource(shader, 1, &shaderSrc, NULL);
    // Compile shader.
    glCompileShader(shader);
    // Check compile status.
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);

    if (!compiled) {
        GLint infoLen = 0;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);

        if (infoLen > 1) {
            char * infoLog = (char*)malloc(sizeof(char)*infoLen);
            glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
            NSLog(@"Error compiling shader:\n%s\n",infoLog);
            free(infoLog);
        }
        glDeleteShader(shader);
        return 0;
    }
    return shader;
}

Код инициализации

    GLfloat screenHeight = [[UIScreen mainScreen] bounds].size.height;
GLfloat screenWidth = [[UIScreen mainScreen] bounds].size.width;

glViewport(0, 0, screenWidth, screenHeight);


glGenVertexArraysOES(1, &vao);
glBindVertexArrayOES(vao);

// Generate buffer, bind to use now, set initial data.
glGenBuffers(2, vbos);

glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);
glBufferData(GL_ARRAY_BUFFER, vxBufSize, squidVxs, GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ixBufSize, squidIxs, GL_STATIC_DRAW);

glEnableVertexAttribArray(ID_ATT_Pos); // Pos   
glVertexAttribPointer(ID_ATT_Pos, 2, GL_FLOAT, GL_FALSE, sizeof(VType), BUFFER_OFFSET(0));
glEnableVertexAttribArray(ID_ATT_Radius);// Radius
glVertexAttribPointer(ID_ATT_Radius, 1, GL_FLOAT, GL_FALSE, sizeof(VType), BUFFER_OFFSET(sizeof(float)*2));
glEnableVertexAttribArray(ID_ATT_Color);// Color
glVertexAttribPointer(ID_ATT_Color, 4, GL_FLOAT, GL_FALSE, sizeof(VType), BUFFER_OFFSET(sizeof(float)*3));

GLuint shaders[2];
shaders[0] = [self loadShaderType:GL_VERTEX_SHADER From:@"VertexShader"];
shaders[1] = [self loadShaderType:GL_FRAGMENT_SHADER From:@"FragmentShader"];

program = glCreateProgram();
glAttachShader(program, shaders[0]);
glAttachShader(program, shaders[1]);

glBindAttribLocation(program, ID_ATT_Pos, "a_position");
glBindAttribLocation(program, ID_ATT_Radius, "a_radius");
glBindAttribLocation(program, ID_ATT_Color, "a_color");

glLinkProgram(program);

GLint linked;
glGetProgramiv(program, GL_LINK_STATUS, &linked);

if (!linked) {
    GLint infoLen = 0;
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
    if (infoLen > 1) {
        char* infoLog = (char*)malloc(sizeof(char)*infoLen);
        glGetProgramInfoLog(program, infoLen, NULL, infoLog);
        NSLog(@"Error linking program:\n%s\n",infoLog);
        free(infoLog);
    }
    glDeleteProgram(program);
}

Код DrawFrame

// Note: Framebuffer swapping is taken care of before/after these
//       lines, and has been shown to work.
glClearColor(0.33f, 0.0f, 0.33f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glDrawElements(GL_POINTS, numPoints, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

Дайте мне знать, если нужна какая-либо другая информация, спасибо за ваше время.

1 Ответ

3 голосов
/ 29 августа 2011

Вам не обязательно нужна матрица проекции для ваших 2d вершин, но вам определенно нужно преобразовать все 3 координаты в диапазон [-1,1] (что вы уже сделали для z, установив его в 0).Эти координаты затем преобразуются GL с текущим преобразованием области просмотра (которое обычно должно соответствовать размерам вашего экрана).Поэтому, если координаты указаны в размерах экрана, преобразуйте их в [-1,1] в шейдере или просто используйте [-1,1] координаты в приложении (что также будет более независимым от разрешения).

РЕДАКТИРОВАТЬ: И я не знаю, как OpenGL ES справляется с этим, но в настольном GL (по крайней мере до 2.1) вам нужно вызвать glEnable(GL_VERTEX_PROGRAM_POINT_SIZE), чтобы вершинный шейдер мог изменить точкуразмер.

...