feat(immersive): add GPU blur + noise distortion in shader
- Multi-sample blur: 12 samples in circular pattern - Noise-based UV distortion to break up pixelation - Random sample offsets for organic blur effect - All blur computation is GPU-side (no CPU cost)
This commit is contained in:
1 parent
6fc1156b93
commit
add1cf3cc0
1 file changed
+67
-25
@@ -2,59 +2,101 @@
|
|||||||
/**
|
/**
|
||||||
* Ambient Motion Fragment Shader
|
* Ambient Motion Fragment Shader
|
||||||
*
|
*
|
||||||
* Adds subtle GPU-driven motion to the background:
|
* Adds GPU-driven motion and blur simulation to the background:
|
||||||
|
* - Multi-sample blur (samples multiple nearby points)
|
||||||
* - UV drift (slow wandering)
|
* - UV drift (slow wandering)
|
||||||
* - Zoom oscillation (breathing effect)
|
* - Zoom oscillation (breathing effect)
|
||||||
* - Color breathing (subtle brightness pulsing)
|
* - Color breathing (subtle brightness pulsing)
|
||||||
*
|
* - Noise-based distortion to break up pixelation
|
||||||
* All effects are controlled by u_intensity (0 = static, 1 = full motion).
|
|
||||||
* All computation is GPU-side - no CPU per-frame work.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
|
|
||||||
// Input from vertex shader
|
|
||||||
in vec2 v_texCoord;
|
in vec2 v_texCoord;
|
||||||
|
|
||||||
// Output
|
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
// Uniforms
|
|
||||||
uniform sampler2D u_texture;
|
uniform sampler2D u_texture;
|
||||||
uniform float u_time; // Time in seconds
|
uniform float u_time;
|
||||||
uniform float u_intensity; // Motion intensity (0.0 - 1.0)
|
uniform float u_intensity;
|
||||||
|
|
||||||
// Constants for motion parameters - made MORE visible
|
// Motion parameters
|
||||||
const float DRIFT_SPEED_X = 0.15;
|
const float DRIFT_SPEED_X = 0.12;
|
||||||
const float DRIFT_SPEED_Y = 0.12;
|
const float DRIFT_SPEED_Y = 0.09;
|
||||||
const float DRIFT_AMOUNT = 0.08; // 8% UV drift
|
const float DRIFT_AMOUNT = 0.06;
|
||||||
|
|
||||||
const float ZOOM_SPEED = 0.1;
|
const float ZOOM_SPEED = 0.08;
|
||||||
const float ZOOM_AMOUNT = 0.05; // 5% zoom oscillation
|
const float ZOOM_AMOUNT = 0.04;
|
||||||
|
|
||||||
const float BREATH_SPEED = 0.2;
|
const float BREATH_SPEED = 0.15;
|
||||||
const float BREATH_AMOUNT = 0.12; // 12% brightness pulse
|
const float BREATH_AMOUNT = 0.08;
|
||||||
|
|
||||||
|
// Blur simulation parameters
|
||||||
|
const float BLUR_RADIUS = 0.015; // UV space blur radius
|
||||||
|
const int BLUR_SAMPLES = 12; // Number of samples for blur
|
||||||
|
|
||||||
|
// Simple pseudo-random function
|
||||||
|
float random(vec2 st) {
|
||||||
|
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Smooth noise function
|
||||||
|
float noise(vec2 st) {
|
||||||
|
vec2 i = floor(st);
|
||||||
|
vec2 f = fract(st);
|
||||||
|
|
||||||
|
float a = random(i);
|
||||||
|
float b = random(i + vec2(1.0, 0.0));
|
||||||
|
float c = random(i + vec2(0.0, 1.0));
|
||||||
|
float d = random(i + vec2(1.0, 1.0));
|
||||||
|
|
||||||
|
vec2 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
|
||||||
|
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 uv = v_texCoord;
|
vec2 uv = v_texCoord;
|
||||||
vec2 center = vec2(0.5);
|
vec2 center = vec2(0.5);
|
||||||
|
|
||||||
// UV drift - slow wandering motion
|
// UV drift
|
||||||
float driftX = sin(u_time * DRIFT_SPEED_X) * DRIFT_AMOUNT * u_intensity;
|
float driftX = sin(u_time * DRIFT_SPEED_X) * DRIFT_AMOUNT * u_intensity;
|
||||||
float driftY = cos(u_time * DRIFT_SPEED_Y * 1.3) * DRIFT_AMOUNT * u_intensity;
|
float driftY = cos(u_time * DRIFT_SPEED_Y * 1.3) * DRIFT_AMOUNT * u_intensity;
|
||||||
uv += vec2(driftX, driftY);
|
uv += vec2(driftX, driftY);
|
||||||
|
|
||||||
// Zoom oscillation - subtle breathing
|
// Zoom oscillation
|
||||||
float zoom = 1.0 + sin(u_time * ZOOM_SPEED) * ZOOM_AMOUNT * u_intensity;
|
float zoom = 1.0 + sin(u_time * ZOOM_SPEED) * ZOOM_AMOUNT * u_intensity;
|
||||||
uv = center + (uv - center) / zoom;
|
uv = center + (uv - center) / zoom;
|
||||||
|
|
||||||
// Clamp UV to avoid edge artifacts
|
// Add subtle noise-based distortion to break up pixelation
|
||||||
uv = clamp(uv, 0.0, 1.0);
|
float noiseScale = 8.0;
|
||||||
|
float distortAmount = 0.008;
|
||||||
|
float n1 = noise(uv * noiseScale + u_time * 0.1);
|
||||||
|
float n2 = noise(uv * noiseScale + 100.0 + u_time * 0.1);
|
||||||
|
uv += vec2(n1 - 0.5, n2 - 0.5) * distortAmount;
|
||||||
|
|
||||||
// Sample texture
|
// Multi-sample blur to smooth out the texture
|
||||||
vec4 color = texture(u_texture, uv);
|
vec4 color = vec4(0.0);
|
||||||
|
float totalWeight = 0.0;
|
||||||
|
|
||||||
// Color breathing - subtle brightness pulsing
|
for (int i = 0; i < BLUR_SAMPLES; i++) {
|
||||||
|
float angle = float(i) * 6.28318530718 / float(BLUR_SAMPLES);
|
||||||
|
float r = BLUR_RADIUS * (0.5 + 0.5 * random(uv + float(i)));
|
||||||
|
vec2 offset = vec2(cos(angle), sin(angle)) * r;
|
||||||
|
|
||||||
|
vec2 sampleUV = clamp(uv + offset, 0.0, 1.0);
|
||||||
|
float weight = 1.0 - length(offset) / BLUR_RADIUS;
|
||||||
|
|
||||||
|
color += texture(u_texture, sampleUV) * weight;
|
||||||
|
totalWeight += weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add center sample with higher weight
|
||||||
|
color += texture(u_texture, clamp(uv, 0.0, 1.0)) * 2.0;
|
||||||
|
totalWeight += 2.0;
|
||||||
|
|
||||||
|
color /= totalWeight;
|
||||||
|
|
||||||
|
// Color breathing
|
||||||
float breath = 1.0 + sin(u_time * BREATH_SPEED) * BREATH_AMOUNT * u_intensity;
|
float breath = 1.0 + sin(u_time * BREATH_SPEED) * BREATH_AMOUNT * u_intensity;
|
||||||
color.rgb *= breath;
|
color.rgb *= breath;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user