为什么我的iOS设备上使用VBO时,这个OpenGL ES 2.0着色器不起作用?

7
如果有人能够揭示这里出了什么问题,也许是gl命令的错序或其他不兼容的命令序列,我将非常感激您的帮助。尽管进行了大量的谷歌研究并查看了《OpenGL ES 2.0 编程指南》中的示例,但整天都在尝试让此代码运行,但没有成功。
我正在尝试在iPhone上使用顶点缓冲对象和自定义着色器在OpenGL ES 2.0中交织一系列自定义结构的顶点数据,其类型如下:
typedef struct {
    float x, y; // Position.
    float radius;
    float colR,colG,colB,colA; // Color rgba components.
} VType;

位置、半径和颜色字节分别用于顶点位置、点大小和颜色。这些的 ID 被初始化:
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屏幕上2D的,正如你可以看到它们在顶点着色器中每个都有'z,w'附加为'0.0,1.0'。
以下是设置VBO并使用glDrawElements进行渲染的核心代码。运行此代码时,很明显glClear已成功,并且NSLog打印确认了这一点,但是DrawFrame代码中列出的没有任何VType顶点在视口中绘制。顶点坐标都在屏幕尺寸内,例如x,y:(92,454)。
请注意,以下代码中的任何未声明变量都是类属性,并具有适当的类型,例如'vao'是GLuint,'vbos'是GLuint [2],'program'是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);
}

绘制框架代码

// 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
您不一定需要为2D顶点创建投影矩阵,但您绝对需要将所有3个坐标转换为[-1,1]范围(通过将z设置为0已经完成了此操作)。然后,这些坐标将通过当前视口变换由GL进行变换(通常应与屏幕尺寸匹配)。因此,如果坐标在屏幕尺寸中,则在着色器中将它们转换为[-1,1],或者在应用程序中使用[-1,1]坐标(这也更具分辨率兼容性)。
编辑:我不知道OpenGL ES如何处理这个问题,但在桌面GL中(至少到2.1),您需要调用glEnable(GL_VERTEX_PROGRAM_POINT_SIZE)才能使顶点着色器能够更改点大小。

非常感谢您的回答,Christian。我已经设置了一个投影矩阵,现在可以在屏幕中央看到一个正方形,而不是GL_POINTS绘图模式下应该有的圆形。在glDrawElements之前,我添加了以下几行代码:glEnable(GL_POINT_SPRITE_OES); glEnable(GL_POINT_SMOOTH); glEnable(GL_BLEND);但仍然没有成功。您有什么想法吗? - KomodoDave
我认为当启用点平滑时,绘制圆点是否取决于实现(当未启用时,应始终为正方形)。点精灵与此无关。但是您可以使用点精灵来模拟它。当启用它们时,您可以在片段着色器中读取一个特殊变量gl_PointCoord,该变量包含点内此片段的纹理坐标。您可以使用这些坐标读取一个只包含圆的纹理(每个其他像素为0),然后丢弃该纹理中alpha(或red)值为0(或低于0.5)的每个片段。 - Christian Rau
嗨@ChristianRau,你的SourceForge电子邮件是联系你的最佳方式吗?我想给你发送一封关于潜在项目的电子邮件。谢谢。 - Crashalot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接