Created
March 19, 2023 02:22
-
-
Save eupston/f237a55cea936bdf819043ba1c651eb3 to your computer and use it in GitHub Desktop.
ChatGPT Portal WebGL Shader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<style> | |
canvas { touch-action-delay: none; touch-action: none; } | |
</style> | |
</head> | |
<body> | |
<canvas id="canvas"></canvas> | |
<script> | |
const canvas = document.getElementById('canvas'); | |
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); | |
if (!gl) { | |
alert('WebGL not supported in your browser'); | |
} | |
// Vertex shader | |
const vertexShaderSource = ` | |
attribute vec4 a_position; | |
attribute vec2 a_texCoord; | |
varying vec2 v_texCoord; | |
void main() { | |
gl_Position = a_position; | |
v_texCoord = a_texCoord; | |
} | |
`; | |
// Fragment shader | |
const fragmentShaderSource = ` | |
precision mediump float; | |
uniform sampler2D u_image; | |
uniform vec2 u_mouse; | |
uniform float u_time; | |
varying vec2 v_texCoord; | |
void main() { | |
vec2 pos = v_texCoord; | |
float dist = distance(pos, u_mouse); | |
float strength = 0.2 * sin(u_time) + 0.3; | |
float radius = 0.2; | |
if (dist < radius) { | |
float factor = smoothstep(radius, radius - strength, dist); | |
pos += (u_mouse - pos) * factor; | |
} | |
vec4 color = texture2D(u_image, pos); | |
gl_FragColor = color; | |
} | |
`; | |
// Compile shaders | |
function compileShader(gl, type, source) { | |
const shader = gl.createShader(type); | |
gl.shaderSource(shader, source); | |
gl.compileShader(shader); | |
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { | |
console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader)); | |
gl.deleteShader(shader); | |
return null; | |
} | |
return shader; | |
} | |
const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vertexShaderSource); | |
const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource); | |
// Create and link the program | |
const program = gl.createProgram(); | |
gl.attachShader(program, vertexShader); | |
gl.attachShader(program, fragmentShader); | |
gl.linkProgram(program); | |
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { | |
console.error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(program)); | |
} | |
gl.useProgram(program); | |
// Create buffer for the vertex positions | |
const positionBuffer = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); | |
const positions = [ | |
-1, -1, | |
1, -1, | |
-1, 1, | |
1, 1, | |
]; | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); | |
// Create buffer for the texture coordinates | |
const texCoordBuffer = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); | |
const texCoords = [ | |
0, 0, | |
1, 0, | |
0, 1, | |
1, 1, | |
]; | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW); | |
// Load the image | |
const image = new Image(); | |
image.src = './surreal_mountains.png' | |
image.onload = () => { | |
// Resize the | |
const aspectRatio = image.width / image.height; | |
const windowAspectRatio = window.innerWidth / window.innerHeight; | |
if (aspectRatio > windowAspectRatio) { | |
canvas.width = window.innerWidth; | |
canvas.height = window.innerWidth / aspectRatio; | |
} else { | |
canvas.width = window.innerHeight * aspectRatio; | |
canvas.height = window.innerHeight; | |
} | |
canvas.style.position = "absolute"; | |
canvas.style.left = (window.innerWidth - canvas.width) / 2 + "px"; | |
canvas.style.top = (window.innerHeight - canvas.height) / 2 + "px"; | |
// Create the texture | |
const texture = gl.createTexture(); | |
gl.bindTexture(gl.TEXTURE_2D, texture); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); | |
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); | |
// Set up the attributes and uniforms | |
const positionAttribute = gl.getAttribLocation(program, 'a_position'); | |
gl.enableVertexAttribArray(positionAttribute); | |
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); | |
gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 0, 0); | |
const texCoordAttribute = gl.getAttribLocation(program, 'a_texCoord'); | |
gl.enableVertexAttribArray(texCoordAttribute); | |
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); | |
gl.vertexAttribPointer(texCoordAttribute, 2, gl.FLOAT, false, 0, 0); | |
const imageUniform = gl.getUniformLocation(program, 'u_image'); | |
gl.uniform1i(imageUniform, 0); | |
const mouseUniformLocation = gl.getUniformLocation(program, 'u_mouse'); | |
const timeUniformLocation = gl.getUniformLocation(program, 'u_time'); | |
// Set up the render loop | |
function render(time) { | |
time *= 0.002; // Convert to seconds | |
gl.uniform1f(timeUniformLocation, time); | |
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); | |
gl.clearColor(0, 0, 0, 0); | |
gl.clear(gl.COLOR_BUFFER_BIT); | |
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); | |
requestAnimationFrame(render); | |
} | |
requestAnimationFrame(render); | |
// Add mouse move listener | |
canvas.addEventListener('mousemove', (event) => { | |
const rect = canvas.getBoundingClientRect(); | |
const x = (event.clientX - rect.left) / canvas.width; | |
const y = 1 - (event.clientY - rect.top) / canvas.height; | |
gl.uniform2f(mouseUniformLocation, x, y); | |
}); | |
}; | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment