Skip to content

Commit

Permalink
add MTIHighlightShadowFilter
Browse files Browse the repository at this point in the history
  • Loading branch information
YuAo committed Aug 9, 2020
1 parent 9b2d8b8 commit 42c3635
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
.DS_Store

## User settings
xcuserdata/
Expand Down
19 changes: 19 additions & 0 deletions MetalPetalHighlightShadow.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Pod::Spec.new do |s|
s.name = 'MetalPetalHighlightShadow'
s.version = '0.1.0'
s.summary = 'Highlight and shadow adjust filter for MetalPetal'
s.description = 'Highlight and shadow adjust filter for MetalPetal'

s.homepage = 'https://github.com/MetalPetal/HighlightShadow'
s.license = { :type => 'GPLv3', :file => 'LICENSE' }
s.author = { 'yuao' => '[email protected]' }
s.source = { :git => 'https://github.com/MetalPetal/HighlightShadow.git', :tag => s.version.to_s }

s.ios.deployment_target = '10.0'
s.macos.deployment_target = '10.13'

s.source_files = 'Sources/**/*'

s.dependency 'MetalPetal'

end
25 changes: 25 additions & 0 deletions Sources/MTIHighlightShadowFilter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// MTIHighlightShadowFilter.h
// MetalPetal
//
// Created by YuAo on 2020/8/9.
//

#import <Foundation/Foundation.h>
#import <MetalPetal/MetalPetal.h>

NS_ASSUME_NONNULL_BEGIN

@interface MTIHighlightShadowFilter : NSObject <MTIUnaryFilter>

@property (nonatomic) float radius;

/// Amount for shadow adjustment, -1.0 to 1.0
@property (nonatomic) float shadow;

/// Amount for highlight adjustment, -1.0 to 1.0
@property (nonatomic) float highlight;

@end

NS_ASSUME_NONNULL_END
48 changes: 48 additions & 0 deletions Sources/MTIHighlightShadowFilter.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// MTIHighlightShadowFilter.m
// MetalPetal
//
// Created by YuAo on 2020/8/9.
//

#import "MTIHighlightShadowFilter.h"

@interface MTIHighlightShadowFilter()

@property (nonatomic, strong) MTIMPSGaussianBlurFilter *blurFilter;

@end

@implementation MTIHighlightShadowFilter
@synthesize inputImage = _inputImage;
@synthesize outputPixelFormat = _outputPixelFormat;

+ (MTIRenderPipelineKernel *)kernel {
return [[MTIRenderPipelineKernel alloc] initWithVertexFunctionDescriptor:[[MTIFunctionDescriptor alloc] initWithName:MTIFilterPassthroughVertexFunctionName]
fragmentFunctionDescriptor:[[MTIFunctionDescriptor alloc] initWithName:@"shadowHighlightAdjust" libraryURL:MTIDefaultLibraryURLForBundle([NSBundle bundleForClass:self])]];
}

- (instancetype)init {
if (self = [super init]) {
_radius = 30;
_blurFilter = [[MTIMPSGaussianBlurFilter alloc] init];
_blurFilter.radius = _radius;
}
return self;
}

- (MTIImage *)outputImage {
if (!self.inputImage) {
return nil;
}
self.blurFilter.radius = self.radius;
self.blurFilter.inputImage = self.inputImage;
MTIImage *blurredImage = self.blurFilter.outputImage;
return [MTIHighlightShadowFilter.kernel applyToInputImages:@[self.inputImage, blurredImage]
parameters:@{@"shadow": @(self.shadow),
@"highlight": @(self.highlight)}
outputTextureDimensions:self.inputImage.dimensions
outputPixelFormat:self.outputPixelFormat];
}

@end
128 changes: 128 additions & 0 deletions Sources/MTIHighlightShadowFilter.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//
// MTIHighlightShadowFilter.metal
// MetalPetal
//
// Created by YuAo on 2020/8/9.
//

#include <metal_stdlib>
using namespace metal;

namespace metalpetalshadowhighlight {

static float4 convertFromRGBToYIQ(float4 src) {
float3 pix2;
float4 pix = src;
pix.xyz = sqrt(fmax(pix.xyz, 0.000000e+00f));
pix2 = ((pix.x* float3(2.990000e-01f, 5.960000e-01f, 2.120000e-01f))+ (pix.y* float3(5.870000e-01f, -2.755000e-01f, -5.230000e-01f)))+ (pix.z* float3(1.140000e-01f, -3.210000e-01f, 3.110000e-01f));
return float4(pix2, pix.w);
}

static float4 convertFromYIQToRGB(float4 src) {
float4 color, pix;
pix = src;
color.xyz = ((pix.x* float3(1.000480e+00f, 9.998640e-01f, 9.994460e-01f))+ (pix.y* float3(9.555580e-01f, -2.715450e-01f, -1.108030e+00f)))+ (pix.z* float3(6.195490e-01f, -6.467860e-01f, 1.705420e+00f));
color.xyz = fmax(color.xyz, float3(0.000000e+00f));
color.xyz = color.xyz* color.xyz;
color.w = pix.w;
return color;
}

typedef struct {
float4 position [[ position ]];
float2 textureCoordinate;
} MTIDefaultVertexOut;

fragment float4 shadowHighlightAdjust(MTIDefaultVertexOut vertexIn [[stage_in]],
texture2d<float, access::sample> sourceTexture [[texture(0)]],
texture2d<float, access::sample> blurTexture [[texture(1)]],
sampler sourceSampler [[sampler(0)]],
sampler blurSampler [[sampler(1)]],
constant float &shadow [[buffer(0)]],
constant float &highlight [[buffer(1)]]) {
float4 source = sourceTexture.sample(sourceSampler, vertexIn.textureCoordinate);
float4 blur = blurTexture.sample(blurSampler, vertexIn.textureCoordinate);
float4 sourceYIQ = convertFromRGBToYIQ(source);
float4 blurYIQ = convertFromRGBToYIQ(blur);
float highlights_sign_negated = copysign(1.0, -highlight);
float shadows_sign = copysign(1.0f, shadow);
//constexpr float whitepoint = 1.0;
constexpr float compress = 0.5;
constexpr float low_approximation = 0.01f;
constexpr float shadowColor = 1.0;
constexpr float highlightColor = 1.0;
float tb0 = 1.0 - blurYIQ.x;
if (tb0 < 1.0 - compress) {
float highlights2 = highlight * highlight;
float highlights_xform = min(1.0f - tb0 / (1.0f - compress), 1.0f);
while (highlights2 > 0.0f) {
float lref, href;
float chunk, optrans;

float la = sourceYIQ.x;
float la_abs;
float la_inverted = 1.0f - la;
float la_inverted_abs;
float lb = (tb0 - 0.5f) * highlights_sign_negated * sign(la_inverted) + 0.5f;

la_abs = abs(la);
lref = copysign(la_abs > low_approximation ? 1.0f / la_abs : 1.0f / low_approximation, la);

la_inverted_abs = abs(la_inverted);
href = copysign(la_inverted_abs > low_approximation ? 1.0f / la_inverted_abs : 1.0f / low_approximation, la_inverted);

chunk = highlights2 > 1.0f ? 1.0f : highlights2;
optrans = chunk * highlights_xform;
highlights2 -= 1.0f;

sourceYIQ.x = la * (1.0 - optrans) + (la > 0.5f ? 1.0f - (1.0f - 2.0f * (la - 0.5f)) * (1.0f - lb) : 2.0f * la * lb) * optrans;

sourceYIQ.y = sourceYIQ.y * (1.0f - optrans)
+ sourceYIQ.y * (sourceYIQ.x * lref * (1.0f - highlightColor)
+ (1.0f - sourceYIQ.x) * href * highlightColor) * optrans;

sourceYIQ.z = sourceYIQ.z * (1.0f - optrans)
+ sourceYIQ.z * (sourceYIQ.x * lref * (1.0f - highlightColor)
+ (1.0f - sourceYIQ.x) * href * highlightColor) * optrans;
}
}
if (tb0 > compress) {
float shadows2 = shadow * shadow;
float shadows_xform = min(tb0 / (1.0f - compress) - compress / (1.0f - compress), 1.0f);

while (shadows2 > 0.0f) {
float lref, href;
float chunk, optrans;

float la = sourceYIQ.x;
float la_abs;
float la_inverted = 1.0f - la;
float la_inverted_abs;
float lb = (tb0 - 0.5f) * shadows_sign * sign(la_inverted) + 0.5f;

la_abs = abs(la);
lref = copysign(la_abs > low_approximation ? 1.0f / la_abs : 1.0f / low_approximation, la);

la_inverted_abs = abs(la_inverted);
href = copysign(la_inverted_abs > low_approximation ? 1.0f / la_inverted_abs : 1.0f / low_approximation,
la_inverted);

chunk = shadows2 > 1.0f ? 1.0f : shadows2;
optrans = chunk * shadows_xform;
shadows2 -= 1.0f;

sourceYIQ.x = la * (1.0 - optrans)
+ (la > 0.5f ? 1.0f - (1.0f - 2.0f * (la - 0.5f)) * (1.0f - lb) : 2.0f * la * lb) * optrans;

sourceYIQ.y = sourceYIQ.y * (1.0f - optrans)
+ sourceYIQ.y * (sourceYIQ.x * lref * shadowColor
+ (1.0f - sourceYIQ.x) * href * (1.0f - shadowColor)) * optrans;

sourceYIQ.z = sourceYIQ.z * (1.0f - optrans)
+ sourceYIQ.z * (sourceYIQ.x * lref * shadowColor
+ (1.0f - sourceYIQ.x) * href * (1.0f - shadowColor)) * optrans;
}
}
return convertFromYIQToRGB(sourceYIQ);
}
}

0 comments on commit 42c3635

Please sign in to comment.