tilt-shift-camera/app/src/main/res/raw/tiltshift_fragment.glsl

147 lines
4.5 KiB
Text
Raw Normal View History

#extension GL_OES_EGL_image_external : require
// Fragment shader for tilt-shift effect
// Supports both linear and radial blur modes
precision mediump float;
// Camera texture (external texture for camera preview)
uniform samplerExternalOES uTexture;
// Effect parameters
uniform int uMode; // 0 = linear, 1 = radial
uniform float uAngle; // Rotation angle in radians
uniform float uPositionX; // Horizontal center of focus (0-1)
uniform float uPositionY; // Vertical center of focus (0-1)
uniform float uSize; // Size of in-focus region (0-1)
uniform float uBlurAmount; // Maximum blur intensity (0-1)
uniform float uFalloff; // Transition sharpness (0-1, higher = more gradual)
uniform float uAspectRatio; // Ellipse aspect ratio for radial mode
uniform vec2 uResolution; // Texture resolution for proper sampling
varying vec2 vTexCoord;
// Calculate signed distance from the focus region for LINEAR mode
float linearFocusDistance(vec2 uv) {
// Center point of the focus region
vec2 center = vec2(uPositionX, uPositionY);
vec2 offset = uv - center;
// Adjust angle by -90 degrees to compensate for portrait texture rotation
float adjustedAngle = uAngle - 1.5707963;
float cosA = cos(adjustedAngle);
float sinA = sin(adjustedAngle);
// After rotation, measure perpendicular distance from center line
float rotatedY = -offset.x * sinA + offset.y * cosA;
return abs(rotatedY);
}
// Calculate signed distance from the focus region for RADIAL mode
float radialFocusDistance(vec2 uv) {
// Center point of the focus region
vec2 center = vec2(uPositionX, uPositionY);
vec2 offset = uv - center;
// Adjust for aspect ratio to create ellipse
// Correct for screen aspect ratio first
float screenAspect = uResolution.x / uResolution.y;
offset.x *= screenAspect;
// Apply rotation
float adjustedAngle = uAngle - 1.5707963;
float cosA = cos(adjustedAngle);
float sinA = sin(adjustedAngle);
vec2 rotated = vec2(
offset.x * cosA - offset.y * sinA,
offset.x * sinA + offset.y * cosA
);
// Apply ellipse aspect ratio
rotated.x /= uAspectRatio;
// Distance from center (elliptical)
return length(rotated);
}
// Calculate blur factor based on distance from focus
float blurFactor(float dist) {
float halfSize = uSize * 0.5;
// Falloff range scales with the falloff parameter
float transitionSize = halfSize * uFalloff;
if (dist < halfSize) {
return 0.0; // In focus region
}
// Smooth falloff using smoothstep
float normalizedDist = (dist - halfSize) / max(transitionSize, 0.001);
return smoothstep(0.0, 1.0, normalizedDist) * uBlurAmount;
}
// Get Gaussian weight for blur kernel (9-tap, sigma ~= 2.0)
float getWeight(int i) {
if (i == 0) return 0.0162;
if (i == 1) return 0.0540;
if (i == 2) return 0.1216;
if (i == 3) return 0.1933;
if (i == 4) return 0.2258;
if (i == 5) return 0.1933;
if (i == 6) return 0.1216;
if (i == 7) return 0.0540;
return 0.0162; // i == 8
}
// Sample with Gaussian blur
vec4 sampleBlurred(vec2 uv, float blur) {
if (blur < 0.01) {
return texture2D(uTexture, uv);
}
vec4 color = vec4(0.0);
vec2 texelSize = 1.0 / uResolution;
// For radial mode, blur in radial direction from center
// For linear mode, blur perpendicular to focus line
vec2 blurDir;
if (uMode == 1) {
// Radial: blur away from center
vec2 center = vec2(uPositionX, uPositionY);
vec2 toCenter = uv - center;
float len = length(toCenter);
if (len > 0.001) {
blurDir = toCenter / len;
} else {
blurDir = vec2(1.0, 0.0);
}
} else {
// Linear: blur perpendicular to focus line
float blurAngle = uAngle;
blurDir = vec2(cos(blurAngle), sin(blurAngle));
}
// Scale blur radius by blur amount
float radius = blur * 20.0;
// 9-tap Gaussian blur
for (int i = 0; i < 9; i++) {
float offset = float(i) - 4.0;
vec2 samplePos = uv + blurDir * texelSize * offset * radius;
color += texture2D(uTexture, samplePos) * getWeight(i);
}
return color;
}
void main() {
float dist;
if (uMode == 1) {
dist = radialFocusDistance(vTexCoord);
} else {
dist = linearFocusDistance(vTexCoord);
}
float blur = blurFactor(dist);
gl_FragColor = sampleBlurred(vTexCoord, blur);
}