气泡效果中的 iOS 图像

Posted

技术标签:

【中文标题】气泡效果中的 iOS 图像【英文标题】:iOS images in a bubble effect 【发布时间】:2012-07-23 14:06:26 【问题描述】:

我有一些图像想要“放入气泡中”。气泡在屏幕周围漂浮,这些图像被困在其中。

最好的方法是将内部图像与气泡图像结合起来,并以某种方式扭曲内部图像,使其看起来像是在气泡内部的反射。

有谁知道如何在不使用纹理和网格的情况下实现这种效果?也许有人记得一个旧项目或做过类似事情的事情?

这是我的意思的一个例子:

【问题讨论】:

根据CoreImage 引用,过滤器CIGlassLozengeios 上不可用。因此,它不会让您的生活更轻松,因为您必须找到第 3 部分库或代码片段才能达到此效果。 【参考方案1】:

您可以使用我的开源 GPUImage 框架中的 GPUImageSphereRefractionFilter 执行此操作:

我在this answer 中详细描述了它是如何工作的,以回答关于对 android 的类似影响的问题。基本上,我使用片段着色器来折射穿过假想球体的光,然后使用它来查找包含源图像的纹理。使用简单的高斯模糊对背景进行模糊处理。

如果您想获得所显示图像的确切外观,您可能需要调整此片段着色器以向球体添加一些掠角颜色,但这应该会让您相当接近。

为了好玩,我决定尝试更接近地复制上面的玻璃球。我在球体上添加了掠射角光照和镜面光照反射,以及不反转折射纹理坐标,导致了这个结果:

我在这个较新的版本中使用了以下片段着色器:

 varying highp vec2 textureCoordinate;

 uniform sampler2D inputImageTexture;

 uniform highp vec2 center;
 uniform highp float radius;
 uniform highp float aspectRatio;
 uniform highp float refractiveIndex;
// uniform vec3 lightPosition;
 const highp vec3 lightPosition = vec3(-0.5, 0.5, 1.0);
 const highp vec3 ambientLightPosition = vec3(0.0, 0.0, 1.0);

 void main()
 
     highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
     highp float distanceFromCenter = distance(center, textureCoordinateToUse);
     lowp float checkForPresenceWithinSphere = step(distanceFromCenter, radius);

     distanceFromCenter = distanceFromCenter / radius;

     highp float normalizedDepth = radius * sqrt(1.0 - distanceFromCenter * distanceFromCenter);
     highp vec3 sphereNormal = normalize(vec3(textureCoordinateToUse - center, normalizedDepth));

     highp vec3 refractedVector = 2.0 * refract(vec3(0.0, 0.0, -1.0), sphereNormal, refractiveIndex);
     refractedVector.xy = -refractedVector.xy;

     highp vec3 finalSphereColor = texture2D(inputImageTexture, (refractedVector.xy + 1.0) * 0.5).rgb;

     // Grazing angle lighting
     highp float lightingIntensity = 2.5 * (1.0 - pow(clamp(dot(ambientLightPosition, sphereNormal), 0.0, 1.0), 0.25));
     finalSphereColor += lightingIntensity;

     // Specular lighting
     lightingIntensity  = clamp(dot(normalize(lightPosition), sphereNormal), 0.0, 1.0);
     lightingIntensity  = pow(lightingIntensity, 15.0);
     finalSphereColor += vec3(0.8, 0.8, 0.8) * lightingIntensity;

     gl_FragColor = vec4(finalSphereColor, 1.0) * checkForPresenceWithinSphere;
 

并且此滤镜可以使用 GPUImageGlassSphereFilter 运行。

【讨论】:

我只是在看这个过滤器。完美,谢谢布拉德。 有没有办法关闭背景图,所以我只有反射球图? 模糊背景不是默认滤镜的一部分,它只是生成球体。在 FilterShowcase 示例中(我从中提取了上面的内容),我使用了一个高斯模糊滤镜和一个混合来组合两个过滤后的图像。您可以只使用球体折射滤镜来仅获取中心球体图像。 布拉德,无论中心如何,这似乎总是显示中心坐标,无论中心在哪里。例如,如果我移动中心,图像中心的像素会随着玻璃球体移动。那有意义吗?有没有办法使用当前中心周围的像素而不是图像中心来创建玻璃球?【参考方案2】:

作为记录,我最终使用了@BradLarson 建议的 GPUImage,但我必须编写一个自定义过滤器,如下所示。该滤镜采用“内部”图像和气泡纹理并将两者混合,同时还执行折射计算但不反转图像坐标。效果:

.h

@interface GPUImageBubbleFilter : GPUImageTwoInputFilter

@property (readwrite, nonatomic) CGFloat refractiveIndex;   
@property (readwrite, nonatomic) CGFloat radius;            

@end

.m

#import "GPUImageBubbleFilter.h"

NSString *const kGPUImageBubbleShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;
 varying highp vec2 textureCoordinate2;

 uniform sampler2D inputImageTexture;
 uniform sampler2D inputImageTexture2;

 uniform highp vec2 center;
 uniform highp float radius;
 uniform highp float aspectRatio;
 uniform highp float refractiveIndex;

 void main()
 
     highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
     highp float distanceFromCenter = distance(center, textureCoordinateToUse);
     lowp float checkForPresenceWithinSphere = step(distanceFromCenter, radius);

     distanceFromCenter = distanceFromCenter / radius;

     highp float normalizedDepth = radius * sqrt(1.0 - distanceFromCenter * distanceFromCenter);
     highp vec3 sphereNormal = normalize(vec3(textureCoordinateToUse - center, normalizedDepth));

     highp vec3 refractedVector = refract(vec3(0.0, 0.0, -1.0), sphereNormal, refractiveIndex);

     lowp vec4 textureColor = texture2D(inputImageTexture, (refractedVector.xy + 1.0) * 0.5) * checkForPresenceWithinSphere; 
     lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2) * checkForPresenceWithinSphere;

     gl_FragColor = mix(textureColor, textureColor2, textureColor2.a);    
 

 );


@interface GPUImageBubbleFilter () 
    GLint radiusUniform, centerUniform, aspectRatioUniform, refractiveIndexUniform;


@property (readwrite, nonatomic) CGFloat aspectRatio;

@end

@implementation GPUImageBubbleFilter
@synthesize radius = _radius, refractiveIndex = _refractiveIndex, aspectRatio = _aspectRatio;

- (id) init 
    self = [super initWithFragmentShaderFromString: kGPUImageBubbleShaderString];
    if( self ) 
        radiusUniform = [filterProgram uniformIndex: @"radius"];
        aspectRatioUniform = [filterProgram uniformIndex: @"aspectRatio"];
        centerUniform = [filterProgram uniformIndex: @"center"];
        refractiveIndexUniform = [filterProgram uniformIndex: @"refractiveIndex"];

        self.radius = 0.5;
        self.refractiveIndex = 0.5;
        self.aspectRatio = 1.0;

        GLfloat center[2] = 0.5, 0.5;
        [GPUImageOpenGLESContext useImageProcessingContext];
        [filterProgram use];
        glUniform2fv(centerUniform, 1, center);

        [self setBackgroundColorRed: 0 green: 0 blue: 0 alpha: 0];
    

    return self;


#pragma mark - Accessors
- (void) setRadius:(CGFloat)radius 
    _radius = radius;

    [GPUImageOpenGLESContext useImageProcessingContext];
    [filterProgram use];
    glUniform1f(radiusUniform, _radius);


- (void) setAspectRatio:(CGFloat)aspectRatio 
    _aspectRatio = aspectRatio;

    [GPUImageOpenGLESContext useImageProcessingContext];
    [filterProgram use];
    glUniform1f(aspectRatioUniform, _aspectRatio);


- (void)setRefractiveIndex:(CGFloat)newValue;

    _refractiveIndex = newValue;

    [GPUImageOpenGLESContext useImageProcessingContext];
    [filterProgram use];
    glUniform1f(refractiveIndexUniform, _refractiveIndex);

【讨论】:

我想看看我是否可以单独使用一些照明计算来更接近你的气泡效果和上面的玻璃球,我已经更新了上面的答案。您的气泡纹理可能仍会产生更美观的结果,但您可以尝试 GPUImageGlassSphereFilter 看看它是否可以在您的应用程序中正常工作。 承认吧,这很有趣不是吗:)

以上是关于气泡效果中的 iOS 图像的主要内容,如果未能解决你的问题,请参考以下文章

有啥第三方库可以方便的实现iOS的聊天气泡

iOS绘制聊天气泡

在 UITableviewCell 中的气泡上显示图像

背景图像未与 s-s-rS 中的气泡图对齐

原创 ios绘制 圆形气泡

记录-有意思的气泡 Loading 效果