纹理上的片段着色器

发布于 2024-08-25 10:58:00 字数 4520 浏览 6 评论 0原文

我正在尝试向程序添加一些后处理功能。渲染是使用 openGL 完成的。我只是想让程序加载一些自制的片段着色器并在视频流上使用它们。

我使用“OpenGL Shader Builder”编写了一小段着色器,它只是将纹理转换为灰度。着色器在着色器生成器中运行良好,但我无法使其在主程序中运行。屏幕保持全黑。

这是设置:

@implementation PluginGLView

- (id) initWithCoder: (NSCoder *) coder
{
const GLubyte * strExt;

if ((self = [super initWithCoder:coder]) == nil)
    return nil;

glLock = [[NSLock alloc] init];
if (nil == glLock) {
    [self release];
    return nil;
}

// Init pixel format attribs
NSOpenGLPixelFormatAttribute attrs[] =
{
    NSOpenGLPFAAccelerated,
    NSOpenGLPFANoRecovery,
    NSOpenGLPFADoubleBuffer,
    0
};

// Get pixel format from OpenGL
NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
if (!pixFmt)
{
    NSLog(@"No Accelerated OpenGL pixel format found\n");
    
    NSOpenGLPixelFormatAttribute attrs2[] =
    {
        NSOpenGLPFANoRecovery,
        0
    };

    // Get pixel format from OpenGL
    pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs2];
    if (!pixFmt) {
        NSLog(@"No OpenGL pixel format found!\n");
        
        [self release];
        return nil;
    }
}

[self setPixelFormat:[pixFmt autorelease]];

/*
long swapInterval = 1 ;
[[self openGLContext]
        setValues:&swapInterval
        forParameter:NSOpenGLCPSwapInterval];
*/
[glLock lock];
[[self openGLContext] makeCurrentContext];

// Init object members
strExt = glGetString (GL_EXTENSIONS);
texture_range  = gluCheckExtension ((const unsigned char *)"GL_APPLE_texture_range", strExt) ? GL_TRUE : GL_FALSE;
texture_hint   = GL_STORAGE_SHARED_APPLE ;
client_storage = gluCheckExtension ((const unsigned char *)"GL_APPLE_client_storage", strExt) ? GL_TRUE : GL_FALSE;
rect_texture   = gluCheckExtension((const unsigned char *)"GL_EXT_texture_rectangle", strExt) ? GL_TRUE : GL_FALSE;

// Setup some basic OpenGL stuff
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

// Loads the shaders
shader=LoadShader(GL_FRAGMENT_SHADER,"/Users/alexandremathieu/fragment.fs");
program=glCreateProgram();
glAttachShader(program, shader);
glLinkProgram(program);
glUseProgram(program);

[NSOpenGLContext clearCurrentContext];
[glLock unlock];

image_width = 1024;
image_height = 512;
image_depth = 16;

image_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
image_base = (GLubyte *) calloc(((IMAGE_COUNT * image_width * image_height) / 3) * 4, image_depth >> 3);
if (image_base == nil) {
    [self release];
    return nil;
}

// Create and load textures for the first time
[self loadTextures:GL_TRUE];

// Init fps timer
//gettimeofday(&cycle_time, NULL);

drawBG = YES;

// Call for a redisplay
noDisplay = YES;
PSXDisplay.Disabled = 1;
[self setNeedsDisplay:true];

return self;
}

这是“渲染屏幕”功能,基本上......渲染屏幕。

- (void)renderScreen
{
    int bufferIndex = whichImage;
    
    glBindTexture(GL_TEXTURE_RECTANGLE_EXT, bufferIndex+1);
                
    glUseProgram(program);
    int loc=glGetUniformLocation(program, "texture");
    glUniform1i(loc,bufferIndex+1);
                
    glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, image_width, image_height, GL_BGRA, image_type, image[bufferIndex]);
                
                
    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f);
        glVertex2f(-1.0f, 1.0f);
                    
        glTexCoord2f(0.0f, image_height);
        glVertex2f(-1.0f, -1.0f);
                    
        glTexCoord2f(image_width, image_height);
        glVertex2f(1.0f, -1.0f);
                    
        glTexCoord2f(image_width, 0.0f);
        glVertex2f(1.0f, 1.0f);
    glEnd();
            
    [[self openGLContext] flushBuffer];
    [NSOpenGLContext clearCurrentContext];
    //[glLock unlock];
    
}

最后是着色器。

uniform sampler2DRect texture;

void main() {
    vec4 color, texel;
    color = gl_Color;
    texel = texture2DRect(texture, gl_TexCoord[0].xy);
    color *= texel;
    // Begin Shader
    float gray=0.0;
    gray+=(color.r + color.g + color.b)/3.0;
    color=vec4(gray,gray,gray,color.a);  
    // End Shader
    gl_FragColor = color;
 }

着色器的加载和使用有效,因为我可以使用此着色器将屏幕全部变成红色

void main(){
    gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}

如果着色器包含语法错误,我会从 LoadShader 函数等收到错误消息。如果我删除着色器的使用,则一切正常。

我认为问题来自于“将纹理作为统一参数传递”的事情。但这是我使用 openGL 的第一步,我不能确定任何事情。

I am trying to add some post-processing capabilities to a program. The rendering is done using openGL. I just want to allow the program to load some home made fragment shader and use them on the video stream.

I wrote a little piece of shader using "OpenGL Shader Builder" that just turns a texture in grayscale. The shaders works well in the shader builder but I can't make it work in the main program. The screens stays all black.

Here is the setup :

@implementation PluginGLView

- (id) initWithCoder: (NSCoder *) coder
{
const GLubyte * strExt;

if ((self = [super initWithCoder:coder]) == nil)
    return nil;

glLock = [[NSLock alloc] init];
if (nil == glLock) {
    [self release];
    return nil;
}

// Init pixel format attribs
NSOpenGLPixelFormatAttribute attrs[] =
{
    NSOpenGLPFAAccelerated,
    NSOpenGLPFANoRecovery,
    NSOpenGLPFADoubleBuffer,
    0
};

// Get pixel format from OpenGL
NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
if (!pixFmt)
{
    NSLog(@"No Accelerated OpenGL pixel format found\n");
    
    NSOpenGLPixelFormatAttribute attrs2[] =
    {
        NSOpenGLPFANoRecovery,
        0
    };

    // Get pixel format from OpenGL
    pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs2];
    if (!pixFmt) {
        NSLog(@"No OpenGL pixel format found!\n");
        
        [self release];
        return nil;
    }
}

[self setPixelFormat:[pixFmt autorelease]];

/*
long swapInterval = 1 ;
[[self openGLContext]
        setValues:&swapInterval
        forParameter:NSOpenGLCPSwapInterval];
*/
[glLock lock];
[[self openGLContext] makeCurrentContext];

// Init object members
strExt = glGetString (GL_EXTENSIONS);
texture_range  = gluCheckExtension ((const unsigned char *)"GL_APPLE_texture_range", strExt) ? GL_TRUE : GL_FALSE;
texture_hint   = GL_STORAGE_SHARED_APPLE ;
client_storage = gluCheckExtension ((const unsigned char *)"GL_APPLE_client_storage", strExt) ? GL_TRUE : GL_FALSE;
rect_texture   = gluCheckExtension((const unsigned char *)"GL_EXT_texture_rectangle", strExt) ? GL_TRUE : GL_FALSE;

// Setup some basic OpenGL stuff
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

// Loads the shaders
shader=LoadShader(GL_FRAGMENT_SHADER,"/Users/alexandremathieu/fragment.fs");
program=glCreateProgram();
glAttachShader(program, shader);
glLinkProgram(program);
glUseProgram(program);

[NSOpenGLContext clearCurrentContext];
[glLock unlock];

image_width = 1024;
image_height = 512;
image_depth = 16;

image_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
image_base = (GLubyte *) calloc(((IMAGE_COUNT * image_width * image_height) / 3) * 4, image_depth >> 3);
if (image_base == nil) {
    [self release];
    return nil;
}

// Create and load textures for the first time
[self loadTextures:GL_TRUE];

// Init fps timer
//gettimeofday(&cycle_time, NULL);

drawBG = YES;

// Call for a redisplay
noDisplay = YES;
PSXDisplay.Disabled = 1;
[self setNeedsDisplay:true];

return self;
}

And here is the "render screen" function which basically...renders the screen.

- (void)renderScreen
{
    int bufferIndex = whichImage;
    
    glBindTexture(GL_TEXTURE_RECTANGLE_EXT, bufferIndex+1);
                
    glUseProgram(program);
    int loc=glGetUniformLocation(program, "texture");
    glUniform1i(loc,bufferIndex+1);
                
    glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, image_width, image_height, GL_BGRA, image_type, image[bufferIndex]);
                
                
    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f);
        glVertex2f(-1.0f, 1.0f);
                    
        glTexCoord2f(0.0f, image_height);
        glVertex2f(-1.0f, -1.0f);
                    
        glTexCoord2f(image_width, image_height);
        glVertex2f(1.0f, -1.0f);
                    
        glTexCoord2f(image_width, 0.0f);
        glVertex2f(1.0f, 1.0f);
    glEnd();
            
    [[self openGLContext] flushBuffer];
    [NSOpenGLContext clearCurrentContext];
    //[glLock unlock];
    
}

and finally here's the shader.

uniform sampler2DRect texture;

void main() {
    vec4 color, texel;
    color = gl_Color;
    texel = texture2DRect(texture, gl_TexCoord[0].xy);
    color *= texel;
    // Begin Shader
    float gray=0.0;
    gray+=(color.r + color.g + color.b)/3.0;
    color=vec4(gray,gray,gray,color.a);  
    // End Shader
    gl_FragColor = color;
 }

The loading and using of shaders works since I am able to turn the screen all red with this shader

void main(){
    gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}

If the shader contains a syntax error I get an error message from the LoadShader function etc. If I remove the use of the shader, everything works normally.

I think the problem comes from the "passing the texture as a uniform parameter" thing. But these are my very firsts step with openGL and I can't be sure of anything.

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

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

发布评论

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

评论(1

路还长,别太狂 2024-09-01 10:58:00

纹理采样器必须设置为活动纹理单元的数量。例如,对于 glActiveTexture(GL_TEXTURE3),采样器也必须设置为 3。在你的情况下,数字应该是 0。

Texture samplers have to be set to the number of the active texture unit. So for example with glActiveTexture(GL_TEXTURE3) the sampler must be set to 3 as well. In your case the number should be 0.

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