Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Creating a WebGL visualization that renders realistic clouds using fragment shaders and signed distance fields (SDF) involves several steps. Below is a simple example to get you started. This code will create a basic setup where we use noise functions to simulate cloud formations with SDFs.
- First, ensure you have a canvas element in your HTML:
- ```html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>WebGL Clouds</title>
- <style>
- body { margin: 0; overflow: hidden; }
- canvas { display: block; }
- </style>
- </head>
- <body>
- <canvas id="webgl-canvas"></canvas>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
- <script src="clouds.js"></script>
- </body>
- </html>
- ```
- Next, create a JavaScript file named `clouds.js` and add the following code:
- ```javascript
- const canvas = document.getElementById('webgl-canvas');
- const width = window.innerWidth;
- const height = window.innerHeight;
- // Initialize WebGL context
- const gl = canvas.getContext('webgl', { antialias: true });
- if (!gl) {
- console.error("WebGL is not supported in your browser.");
- }
- // Create shaders and program
- function createShader(type, source) {
- const shader = gl.createShader(type);
- gl.shaderSource(shader, source);
- gl.compileShader(shader);
- if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
- console.error(gl.getShaderInfoLog(shader));
- return null;
- }
- return shader;
- }
- const vertexShaderSource = `
- attribute vec4 a_position;
- void main() {
- gl_Position = a_position;
- }
- `;
- const fragmentShaderSource = `
- precision mediump float;
- uniform float u_time;
- uniform vec2 u_resolution;
- float rand(vec2 co){
- return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
- }
- float noise(vec2 p){
- vec2 ip = floor(p);
- vec2 u = fract(p);
- float res = mix(mix(rand(ip), rand(ip + vec2(1.,0.)), smoothstep(0.,1.,u.x)),
- mix(rand(ip + vec2(0.,1.)), rand(ip + vec2(1.,1.)), smoothstep(0.,1.,u.x)),
- smoothstep(0.,1.,u.y));
- return res;
- }
- float fbm(in vec2 p) {
- float value = 0.;
- float amplitude = .5;
- for (int i = 0; i < 6; i++) {
- value += amplitude * noise(p);
- p *= 2.;
- amplitude *= .5;
- }
- return value;
- }
- float cloudSDF(vec3 pos) {
- vec2 uv = pos.xy + fbm(pos.xz + u_time * 0.1) - 0.5;
- float d = length(uv) - 0.3;
- // Adding some variation for more realistic clouds
- d += (fbm(pos.zx + u_time * 0.2) - 0.5) * 0.05;
- return d;
- }
- void main() {
- vec2 uv = gl_FragCoord.xy / u_resolution;
- float cloudiness = smoothstep(0.4, 1., cloudSDF(vec3(uv * 8., 0.)));
- gl_FragColor = vec4(vec3(cloudiness), 1.);
- }
- `;
- const vertexShader = createShader(gl.VERTEX_SHADER, vertexShaderSource);
- const fragmentShader = createShader(gl.FRAGMENT_SHADER, fragmentShaderSource);
- const program = gl.createProgram();
- gl.attachShader(program, vertexShader);
- gl.attachShader(program, fragmentShader);
- gl.linkProgram(program);
- if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
- console.error("Could not initialize shaders");
- }
- // Set up the canvas
- gl.viewport(0, 0, width, height);
- gl.clearColor(1, 1, 1, 1);
- gl.enable(gl.DEPTH_TEST);
- // Create buffers for position
- const positionBuffer = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
- const positions = [
- -1, -1,
- 1, -1,
- -1, 1,
- -1, 1,
- 1, -1,
- 1, 1
- ];
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
- // Attributes and uniforms
- const positionLocation = gl.getAttribLocation(program, "a_position");
- const timeLocation = gl.getUniformLocation(program, "u_time");
- const resolutionLocation = gl.getUniformLocation(program, "u_resolution");
- gl.useProgram(program);
- gl.enableVertexAttribArray(positionLocation);
- gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
- // Render loop
- let then = 0;
- function render(now) {
- now *= 0.001; // convert to seconds
- const deltaTime = now - then;
- then = now;
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
- gl.uniform1f(timeLocation, now);
- gl.uniform2f(resolutionLocation, width, height);
- gl.drawArrays(gl.TRIANGLES, 0, 6);
- requestAnimationFrame(render);
- }
- requestAnimationFrame(render);
- ```
- ### Explanation:
- - **Vertex Shader**: The vertex shader is very simple; it just passes the position of each vertex to the fragment shader. This setup uses a full-screen quad.
- - **Fragment Shader**: The fragment shader does all the heavy lifting:
- - `rand`: A simple random function using trigonometric functions.
- - `noise`: Generates noise using the Perlin noise algorithm.
- - `fbm` (Fractional Brownian Motion): Combines multiple layers of noise at different frequencies to create a more complex and realistic texture.
- - `cloudSDF`: Computes a signed distance field for clouds, where positive values represent cloud space and negative values represent clear sky.
- - **Render Loop**: The render loop updates the time uniform every frame and renders the scene using the quad defined in the vertex buffer.
- This code provides a basic starting point. You can further enhance it by adding more complex noise functions, lighting effects, or even integrating wind animation for dynamic cloud movement.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement