diff --git a/src/psychadelic-graphics/Hatsune-Miku-vocaloids-30622078-935-1023.jpg b/src/psychadelic-graphics/Hatsune-Miku-vocaloids-30622078-935-1023.jpg new file mode 100644 index 0000000..8fa2c1a Binary files /dev/null and b/src/psychadelic-graphics/Hatsune-Miku-vocaloids-30622078-935-1023.jpg differ diff --git a/src/psychadelic-graphics/app.ts b/src/psychadelic-graphics/app.ts index 70ba433..c4484a1 100644 --- a/src/psychadelic-graphics/app.ts +++ b/src/psychadelic-graphics/app.ts @@ -1,14 +1,40 @@ import psychadelicColors from './psychadelicColors.frag.glsl'; - +import mikuImageUrl from './Hatsune-Miku-vocaloids-30622078-935-1023.jpg'; const canvas = document.getElementById('canvas') as HTMLCanvasElement; const gl = canvas.getContext('webgl2')!; -// Basic vertex shader (just passes coordinates) +// Load Miku texture +const mikuTexture = gl.createTexture(); +// Create a single pixel as initial texture to avoid errors before image loads +gl.bindTexture(gl.TEXTURE_2D, mikuTexture); +gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 255, 255])); + +const mikuImage = new Image(); +mikuImage.src = mikuImageUrl; + +mikuImage.onload = () => { + console.log('Miku image loaded successfully'); + gl.bindTexture(gl.TEXTURE_2D, mikuTexture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, mikuImage); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); +}; + +mikuImage.onerror = (err) => { + console.error('Failed to load Miku image:', err); +}; + +// Basic vertex shader (just passes coordinates and texture coordinates) const vertexShaderSource = `#version 300 es in vec4 a_position; +out vec2 v_texCoord; void main() { gl_Position = a_position; + // Convert position from clip space (-1 to +1) to texture coordinates (0 to 1) + v_texCoord = a_position.xy * -0.5 + 0.5; }`; // Compile shader @@ -58,6 +84,7 @@ gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0); const timeUniformLocation = gl.getUniformLocation(program, 'u_time'); const canvasWidthLocation = gl.getUniformLocation(program, 'u_canvasWidth'); const canvasHeightLocation = gl.getUniformLocation(program, 'u_canvasHeight'); +const mikuTextureLocation = gl.getUniformLocation(program, 'u_mikuTexture'); // Set up resize handler function resize() { @@ -72,8 +99,13 @@ resize(); function draw(time: number) { gl.useProgram(program); gl.uniform1f(timeUniformLocation, time * 0.001); // Convert to seconds - gl.uniform1f(canvasWidthLocation, canvas.width); // Convert to seconds - gl.uniform1f(canvasHeightLocation, canvas.height); // Convert to seconds + gl.uniform1f(canvasWidthLocation, canvas.width); + gl.uniform1f(canvasHeightLocation, canvas.height); + + // Bind Miku texture to texture unit 0 + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, mikuTexture); + gl.uniform1i(mikuTextureLocation, 0); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); requestAnimationFrame(draw); diff --git a/src/psychadelic-graphics/psychadelicColors.frag.glsl b/src/psychadelic-graphics/psychadelicColors.frag.glsl index fa9d099..296d855 100644 --- a/src/psychadelic-graphics/psychadelicColors.frag.glsl +++ b/src/psychadelic-graphics/psychadelicColors.frag.glsl @@ -2,11 +2,11 @@ precision highp float; uniform float u_time; - uniform float u_canvasWidth; uniform float u_canvasHeight; +uniform sampler2D u_mikuTexture; - +in vec2 v_texCoord; out vec4 fragColor; // See https://thebookofshaders.com/10/ @@ -34,7 +34,7 @@ vec2 pixellate(vec2 inputVec, float size) { ); } -void pixelatedSinWave() { +vec4 pixelatedSinWave() { vec2 uv = gl_FragCoord.xy/vec2(u_canvasWidth, u_canvasHeight); float amount = 1.0/(u_time * 9.0); @@ -45,17 +45,30 @@ void pixelatedSinWave() { float dist = distance(uv, vec2(0.5, 0.5)); float curve = sin(dist * 60.0); vec4 outputColor = vec4(0.5, 0.1, curve, 1.0); + return outputColor; float size = 0.01; float period = 1.0; fragColor = boxFade(outputColor, size, period); - } +vec4 miku() { + // Get base texture color + vec2 uv = v_texCoord; + + // Sample the texture first without effects + vec4 texColor = texture(u_mikuTexture, uv); + + return texColor; +} void main() { - pixelatedSinWave(); + vec4 texColor = miku(); + // Apply box fade effect + float boxSize = 0.02; + float period = 2.0; + fragColor = boxFade(texColor, boxSize, period); }