代码之家  ›  专栏  ›  技术社区  ›  Heena

利用opengl绘制具有模糊效果的图像

  •  1
  • Heena  · 技术社区  · 11 年前

    我的要求和 this question

    我现在的处境是在我的opengl视图上设置UIImage。 下面是我用来设置uiimage的完整代码。它还包括图形代码。 使用下面的代码,我可以设置图像并在上面绘制。

    当我不在背景中设置图像时,它允许我绘制模糊和平滑的图形

    但如果我设置背景图像,它会绘制实心图形

    我想要在背景图像上画得平滑。

    我已经使用了苹果公司的一些GLPaint代码进行绘图。

     - (id)initWithCoder:(NSCoder*)coder
    {
        CGImageRef      brushImage;
        CGContextRef    brushContext;
        GLubyte         *brushData;
        size_t          width, height;
    
        if ((self = [super initWithCoder:coder]))
        {
            CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
            eaglLayer.opaque = NO;
            eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                            [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking,
                                            kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
                                            nil];
    
            _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
            if (!_context || ![EAGLContext setCurrentContext:_context])
            {
                return nil;
            }
    
            {
                brushImage = [UIImage imageNamed:@"Brush.png"].CGImage;
    
                width = CGImageGetWidth(brushImage);
                height = CGImageGetHeight(brushImage);
    
                if(brushImage) {
                    brushData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
                    brushContext = CGBitmapContextCreate(brushData, width, width, 8, width * 4, CGImageGetColorSpace(brushImage), kCGImageAlphaPremultipliedLast);
                    CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
                    CGContextDrawImage(brushContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), brushImage);
                    CGContextRelease(brushContext);
                    glGenTextures(1, &brushTexture);
                    glBindTexture(GL_TEXTURE_2D, brushTexture);
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, brushData);
                    free(brushData);
                }
            }
    
            // Setup OpenGL states
            glMatrixMode(GL_PROJECTION);
            CGRect frame = self.bounds;
            glOrthof(0, frame.size.width, 0, frame.size.height, -1, 1);
            glViewport(0, 0, frame.size.width , frame.size.height);
            glMatrixMode(GL_MODELVIEW);
    
            glDisable(GL_DITHER);
            glEnable(GL_TEXTURE_2D);
            glEnableClientState(GL_VERTEX_ARRAY);
    
            glEnable(GL_BLEND);
            glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    
            glEnable(GL_POINT_SPRITE_OES);
            glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
            glPointSize(10);
    
        }
        return self;
    }
    
    
    
      - (void)layoutSubviews
        {
            [EAGLContext setCurrentContext:_context];
            [self destroyFramebuffer];
            [self createFramebuffer];
    
            if (texture)    {
                [self _updateContent];
                glDeleteTextures(1, &texture);
                texture = 0;
            }
        }
    
    
        - (void)_updateContent {
            NSUInteger width = self.frame.size.width;
            NSUInteger height = self.frame.size.height;
    
            CGFloat texWidth = (1.0 * width)/TEX_SIZE;
            CGFloat texHeight = (1.0 * height)/TEX_SIZE;
    
            GLfloat verts[12] = {
                0, height,
                width, height,
                width, 0,
                0, height,
                0, 0,
                width, 0
            };
    
            GLfloat txcoord[12] = {
                0, texHeight,
                texWidth, texHeight,
                texWidth, 0,
                0, texHeight,
                0, 0,
                texWidth, 0
            };
    
            [EAGLContext setCurrentContext:_context];
            glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer);
            glVertexPointer(2, GL_FLOAT, 0, verts);
            glTexCoordPointer(2, GL_FLOAT, 0, txcoord);
            glDrawArrays(GL_TRIANGLES, 0, 6);
    
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    
            glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer);
            [_context presentRenderbuffer:GL_RENDERBUFFER_OES];
    
            glDisable(GL_TEXTURE_2D);
            glDisable(GL_BLEND);
    
        }
    
    
       - (void)setContent:(UIImage*)image
    {
    
        if (image) {
            //        self.isNotEmpty = YES;
            CGImageRef contentImage = image.CGImage;
    
            [EAGLContext setCurrentContext:_context];
    
            CGFloat w = CGImageGetWidth(contentImage);
            CGFloat h = CGImageGetHeight(contentImage);
    
            GLubyte *data = (GLubyte *)calloc(TEX_SIZE * TEX_SIZE * 4, sizeof(GLubyte));
    
            CGContextRef ctx = CGBitmapContextCreate(data, TEX_SIZE, TEX_SIZE, 8, TEX_SIZE * 4, CGImageGetColorSpace(contentImage), kCGImageAlphaPremultipliedLast);
            CGContextScaleCTM(ctx, 1, -1);
            CGContextTranslateCTM(ctx, 0, -TEX_SIZE);
            CGContextDrawImage(ctx, CGRectMake(0, 0, w, h), contentImage);
            CGContextRelease(ctx);
    
            if (!texture) {
                glGenTextures(1, &texture);
            }
            glBindTexture(GL_TEXTURE_2D, texture);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
            free(data);
        } 
        [self setNeedsLayout];        
        glDisable(GL_VERTEX_ARRAY);
    }
    

    //在触摸时调用Moved

    - (void) renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end
    {
        glEnable(GL_BLEND);
        if(1){
            sharedDelegate = [AppDelegate appDelegate];
    
            static GLfloat*     vertexBuffer = NULL;
            static NSUInteger   vertexMax = 64;
            NSUInteger          vertexCount = 0,
            count,
            i;
            GLenum err;
    
            glColor4f(1.0, 0.0, 1.0, 1.0);
    
            // Convert locations from Points to Pixels
            CGFloat scale = self.contentScaleFactor;
            start.x *= scale;
            start.y *= scale;
            end.x *= scale;
            end.y *= scale;
    
            // Allocate vertex array buffer
            if(vertexBuffer == NULL)
                vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat));
    
            // Add points to the buffer so there are drawing points every X pixels
            count = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / kBrushPixelStep), 1);
            for(i = 0; i < count; ++i) {
                if(vertexCount == vertexMax) {
                    vertexMax = 2 * vertexMax;
                    vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat));
                }
    
                vertexBuffer[2 * vertexCount + 0] = start.x + (end.x - start.x) * ((GLfloat)i / (GLfloat)count);
                vertexBuffer[2 * vertexCount + 1] = start.y + (end.y - start.y) * ((GLfloat)i / (GLfloat)count);
                vertexCount += 1;
            }
    
            if(sharedDelegate.boolIsEraser)
            {
                glColor4f(1.0, 1.0, 1.0, 0.5);
                glBlendFunc( GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
            }
            // Render the vertex array
            glVertexPointer(2, GL_FLOAT, 0, vertexBuffer);
            glDrawArrays(GL_POINTS, 0, vertexCount);
    
            if(sharedDelegate.boolIsEraser){
                // at last restore the  mixed-mode
                glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
            }
    
            glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer);
            [_context presentRenderbuffer:GL_RENDERBUFFER_OES];
    
            err = glGetError();
            if (err != GL_NO_ERROR)
                NSLog(@"Error in frame. glError: 0x%04X", err);
    
        }
    }
    

    有什么解决办法可以做到这一点吗? 我几乎要进球了,但我被困在了这里。任何帮助都将不胜感激。

    4 回复  |  直到 11 年前
        1
  •  1
  •   Peter Hosey    11 年前

    您可以尝试将阴影颜色设置为与笔划颜色相同,并将笔划模糊半径设置为希望模糊扩展的笔划边缘的任意点。您可能需要将阴影偏移设置为 CGSizeZero .

        2
  •  1
  •   Nirav Gadhiya    11 年前

    您可以从中尝试openGL代码 This Link

    或者试试这个

    CGSize offset;
    float blur;//set this variable as per your requirement
    offset.width = 10;
    offset.height = -10;
    
    CGContextSetShadow(context, offset, blur);
    
        3
  •  1
  •   Heena    11 年前

    我找到了解决方案。。。

    剩下的就是在opengl视图中绘制UIImage之后,我需要设置我的opengl状态。和我初始化笔刷纹理时做的一样。。。

    我刚刚在中添加了以下代码 LayoutSubviews 之后的方法 _updateContent 方法

            // Setup OpenGL states
            glMatrixMode(GL_PROJECTION);
            CGRect frame = self.bounds;
            glOrthof(0, frame.size.width, 0, frame.size.height, -1, 1);
            glViewport(0, 0, frame.size.width , frame.size.height);
            glMatrixMode(GL_MODELVIEW);
    
            glDisable(GL_DITHER);
            glEnable(GL_TEXTURE_2D);
            glEnableClientState(GL_VERTEX_ARRAY);
    
            glEnable(GL_BLEND);
            glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    
            glEnable(GL_POINT_SPRITE_OES);
            glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE)
    

    现在这个代码运行得很好。。

        4
  •  0
  •   Undertaker    11 年前

    您可以使用 CGContextSetBlendMode(context,kCGBlendModeClear)类似于真正的橡皮擦效果