Drawing with with blur effect on image using opengl

旧时模样 提交于 2019-12-08 05:26:35

问题


I have the same requirement as this question

I am right now at situation where i set UIImage on my opengl view. Below is the complete code i used to set uiimage. Also it includes the drawing code. Using below code I am able to set image and drawing on it.

when i do not set image in background it allows me to draw blur and smooth drawing

but if i set background image it draws solid drawing

I want smooth drawing on background image.

I have used some of GLPaint code of apple for drawing.

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

//Called on touchedMoved

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

    }
}

Any workaround to accomplish this? I am almost there to my goal but badly stuck here.Any help will be appreciated.


回答1:


You might try setting the shadow color to the same as the stroke color, and the stroke blur radius to however many points out from the edge of the stroke you want the blur to extend. You'll probably want to set the shadow offset to CGSizeZero.




回答2:


You can try openGL code from This Link

or try this

CGSize offset;
float blur;//set this variable as per your requirement
offset.width = 10;
offset.height = -10;

CGContextSetShadow(context, offset, blur);



回答3:


I got the solution...

The thing remaining was I need to set my opengl states after i draw UIImage in opengl view. The same thing i did when i initialized brush texture...

I just added below code in LayoutSubviews method after _updateContent method

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

and now this code is working perfectly..




回答4:


You can use CGContextSetBlendMode(context, kCGBlendModeClear) ike real eraser effect



来源:https://stackoverflow.com/questions/15131213/drawing-with-with-blur-effect-on-image-using-opengl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!