feat(shader): Add Deep Sea background shader for BlurPipeline
- Add compile_deepsea_shader() with animated underwater-like GLSL shader - Add render_deepsea_to_fbo() to render background to scene FBO - Deep Sea shader features: FBM noise, animated blobs, caustic lines, vignette - Add deepsea_program to cleanup() for proper resource management - Add 2 new tests for Deep Sea shader compilation and FBO rendering Task: Phase 1, Task 2 of frosted_glass_20260313 track
This commit is contained in:
@@ -161,6 +161,7 @@ class BlurPipeline:
|
||||
self.blur_tex_b: int | None = None
|
||||
self.h_blur_program: int | None = None
|
||||
self.v_blur_program: int | None = None
|
||||
self.deepsea_program: int | None = None
|
||||
self._fb_width: int = 0
|
||||
self._fb_height: int = 0
|
||||
|
||||
@@ -273,6 +274,94 @@ void main() {
|
||||
self.h_blur_program = self._compile_shader(vert_src, h_frag_src)
|
||||
self.v_blur_program = self._compile_shader(vert_src, v_frag_src)
|
||||
|
||||
def compile_deepsea_shader(self):
|
||||
vert_src = """
|
||||
#version 330 core
|
||||
void main() {
|
||||
vec2 pos = vec2(-1.0, -1.0);
|
||||
if (gl_VertexID == 1) pos = vec2(1.0, -1.0);
|
||||
else if (gl_VertexID == 2) pos = vec2(-1.0, 1.0);
|
||||
else if (gl_VertexID == 3) pos = vec2(1.0, 1.0);
|
||||
gl_Position = vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
"""
|
||||
frag_src = """
|
||||
#version 330 core
|
||||
uniform float u_time;
|
||||
uniform vec2 u_resolution;
|
||||
out vec4 FragColor;
|
||||
|
||||
float hash(vec2 p) {
|
||||
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
|
||||
}
|
||||
|
||||
float noise(vec2 p) {
|
||||
vec2 i = floor(p);
|
||||
vec2 f = fract(p);
|
||||
f = f * f * (3.0 - 2.0 * f);
|
||||
float a = hash(i);
|
||||
float b = hash(i + vec2(1.0, 0.0));
|
||||
float c = hash(i + vec2(0.0, 1.0));
|
||||
float d = hash(i + vec2(1.0, 1.0));
|
||||
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
||||
}
|
||||
|
||||
float fbm(vec2 p) {
|
||||
float v = 0.0;
|
||||
float a = 0.5;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
v += a * noise(p);
|
||||
p *= 2.0;
|
||||
a *= 0.5;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
|
||||
float t = u_time * 0.3;
|
||||
vec3 col = vec3(0.01, 0.05, 0.12);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float phase = t * (0.1 + float(i) * 0.05);
|
||||
vec2 blob_uv = uv + vec2(sin(phase), cos(phase * 0.8)) * 0.3;
|
||||
float blob = fbm(blob_uv * 3.0 + t * 0.2);
|
||||
col = mix(col, vec3(0.02, 0.20, 0.40), blob * 0.4);
|
||||
}
|
||||
float line_alpha = 0.0;
|
||||
for (int i = 0; i < 12; i++) {
|
||||
float fi = float(i);
|
||||
float offset = mod(t * 15.0 + fi * (u_resolution.x / 12.0), u_resolution.x);
|
||||
float line_x = offset / u_resolution.x;
|
||||
float dist = abs(uv.x - line_x);
|
||||
float alpha = smoothstep(0.02, 0.0, dist) * (0.1 + 0.05 * sin(t + fi));
|
||||
line_alpha += alpha;
|
||||
}
|
||||
col += vec3(0.04, 0.35, 0.55) * line_alpha;
|
||||
float vignette = 1.0 - length(uv - 0.5) * 0.8;
|
||||
col *= vignette;
|
||||
FragColor = vec4(col, 1.0);
|
||||
}
|
||||
"""
|
||||
self.deepsea_program = self._compile_shader(vert_src, frag_src)
|
||||
|
||||
def render_deepsea_to_fbo(self, width: int, height: int, time: float):
|
||||
if not self.deepsea_program or not self.scene_fbo:
|
||||
return
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.scene_fbo)
|
||||
gl.glViewport(0, 0, width, height)
|
||||
gl.glClearColor(0.01, 0.05, 0.12, 1.0)
|
||||
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
|
||||
gl.glUseProgram(self.deepsea_program)
|
||||
u_time = gl.glGetUniformLocation(self.deepsea_program, "u_time")
|
||||
if u_time != -1:
|
||||
gl.glUniform1f(u_time, time)
|
||||
u_res = gl.glGetUniformLocation(self.deepsea_program, "u_resolution")
|
||||
if u_res != -1:
|
||||
gl.glUniform2f(u_res, float(width), float(height))
|
||||
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)
|
||||
gl.glUseProgram(0)
|
||||
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
|
||||
|
||||
def _render_quad(self, program: int, src_tex: int, texel_size: tuple[float, float]):
|
||||
gl.glUseProgram(program)
|
||||
gl.glActiveTexture(gl.GL_TEXTURE0)
|
||||
@@ -313,7 +402,7 @@ void main() {
|
||||
def cleanup(self):
|
||||
fbos = [f for f in [self.scene_fbo, self.blur_fbo_a, self.blur_fbo_b] if f is not None]
|
||||
texs = [t for t in [self.scene_tex, self.blur_tex_a, self.blur_tex_b] if t is not None]
|
||||
progs = [p for p in [self.h_blur_program, self.v_blur_program] if p is not None]
|
||||
progs = [p for p in [self.h_blur_program, self.v_blur_program, self.deepsea_program] if p is not None]
|
||||
if fbos:
|
||||
gl.glDeleteFramebuffers(len(fbos), fbos)
|
||||
if texs:
|
||||
@@ -329,3 +418,4 @@ void main() {
|
||||
self.blur_tex_b = None
|
||||
self.h_blur_program = None
|
||||
self.v_blur_program = None
|
||||
self.deepsea_program = None
|
||||
|
||||
Reference in New Issue
Block a user