为什么此 OpenGL ES 2.0 着色器不能与 iOS 上的 VBO 配合使用?

发布于 2024-12-01 16:54:07 字数 5332 浏览 2 评论 0原文

如果有人能够阐明这里出了什么问题,也许是 gl 命令的顺序错误或其他一些不兼容的命令序列,我将非常感谢您的帮助。尽管我进行了大量的 Google 研究并仔细研究了“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”。

剩余的核心代码需要设置下面列出了使用 glDrawElements 的 VBO 和渲染。运行此代码时,可以明显看出 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);
}

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));

如果需要任何其他信息,请告诉我,谢谢您的宝贵时间。

If anyone can shed light on what's going wrong here, perhaps a misordering of gl commands or some other incompatible command sequence, I would be tremendously grateful for your assistance. I have been trying to get this code working all day with no success, despite much Google research and poring over examples in "OpenGL ES 2.0 Programming Guide".

I'm trying to use a Vertex Buffer Object and custom shaders in OpenGL ES 2.0 on iPhone. I am attempting to interleave vertex data from a series of custom structures of the following type:

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

The position, radius and color bytes are to be considered for vertex location, pointsize and color respectively. Ids for these are initialised:

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.

The stride for these is specified in each glVertexAttribPointer call.

It is intended that each vertex be drawn at its x,y position with the specified color and a pointsize of its radius. Associated with each aforementioned attribute is a vertex shader attribute, these are "a_position","a_color" and "a_radius". Here are the vertex and fragment shaders:

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);
}

I wonder if a projection matrix is required in the vertex shader? All the points I create are 2D in the dimensions of the iPhone screen, and as you can see they each have 'z,w' appended as '0.0,1.0' in the vertex shader above.

Remaining core code to setup the VBO and render using glDrawElements is listed below. When running this code it is visibly apparent that the glClear has been successful and indeed NSLog print confirms this, however no VType vertices are drawn in the viewport by the DrawFrame code listed below. The vertex coordinates are well within screen dimensions e.g. x,y: (92, 454).

Note that any undeclared variables in the following code are class properties, and of appropriate type so e.g. 'vao' is GLuint, 'vbos' is GLuint[2], 'program' is a GLuint program handle. I have also left out the boilerplate OpenGL setup code, which has been tested with different code internals and shown to work.

Load Shader Code

-(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;
}

Initialisation Code

    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 Code

// 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));

Let me know if any other information is needed, thank you for your time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

与他有关 2024-12-08 16:54:07

您不一定需要 2d 顶点的投影矩阵,但您肯定需要将所有 3 个坐标转换为 [-1,1] 范围(您已经通过将 z 设置为 0 来完成此操作)。然后,GL 使用当前视口变换(通常应与您的屏幕尺寸匹配)对这些坐标进行变换。因此,如果坐标采用屏幕尺寸,则在着色器中将它们转换为 [-1,1],或者仅在应用程序中使用 [-1,1] 坐标(这也与分辨率无关)。

编辑:我不知道OpenGL ES如何处理这个问题,但是在桌面GL(至少2.1以下)中,您需要为顶点着色器调用glEnable(GL_VERTEX_PROGRAM_POINT_SIZE)能够改变点的大小。

You do not necessarily need a projection matrix for your 2d vertices, but you definitely need to transform all 3 coordinates into the [-1,1] range (which you have already done for z by setting it to 0). These coordinates are then transformed by GL with the current viewport transformation (that should usually match your screen dimensions). So if the coordinates are in screen dimensions, then transform them into [-1,1] in the shader, or just use [-1,1] coordinates in the application (which would also be more resolution agnostic).

EDIT: And I don't know how OpenGL ES handles this, but in desktop GL (at least upto 2.1) you need to call glEnable(GL_VERTEX_PROGRAM_POINT_SIZE) for the vertex shader to be able to chnage the point size.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文