|
| 1 | +--- |
| 2 | +slug: neat_3d_gradient |
| 3 | +title: How we built NEAT, the 3D gradient tool |
| 4 | +author: Francesco Gatti |
| 5 | +image: /img/avatars/francesco_avatar.jpg |
| 6 | +author_url: https://www.linkedin.com/in/fgatti675 |
| 7 | +author_image_url: https://avatars.githubusercontent.com/u/5120271?v=4 |
| 8 | +--- |
| 9 | + |
| 10 | +<video class="demo" loop autoplay muted width="100%"> |
| 11 | + <source src="/img/blog/neat_stripe.webm" type="video/mp4"/> |
| 12 | +</video> |
| 13 | + |
| 14 | +The first time I saw the Stripe shader animation on their website, **I was hooked.** I really wanted to have something |
| 15 | +that cool for the websites I was working on and tried to reverse engineer what Stripe does. I must say, it wasn't easy! |
| 16 | +I had to learn a lot about shaders, WebGL, and three.js to get to the point where I could create something similar. |
| 17 | + |
| 18 | +We are going to be using a lot of **Perlin noise functions** to generate the waves and the gradient. **Perlin noise** is |
| 19 | +a type of gradient noise used in computer graphics to create natural-looking textures. It was invented by Ken Perlin in |
| 20 | +the 1980s. The noise is generated by interpolating between random values. It is locally stable, so it is well-suited for |
| 21 | +generating animations by including a time parameter in the noise function. |
| 22 | + |
| 23 | + |
| 24 | + |
| 25 | +The Stripe animation is really a 3D shape, a plane divided in triangles acting like a flag that has waves passing |
| 26 | +through it. On top of that, there is a gradient that changes color and brightness. That is really the essence of the |
| 27 | +effect. |
| 28 | + |
| 29 | +I tried achieving the same effect with basic three.js, but it was really hard to get it right. I quickly realized that |
| 30 | +**I need to use custom shaders**, one for determining the position of each vertex in the plane and another one for |
| 31 | +assigning the color of each pixel. The first iterations were calculating the position of each vertex in the CPU and |
| 32 | +sending it to the GPU. This was really slow, and I had to find a way to calculate the position of each vertex in the |
| 33 | +GPU. |
| 34 | + |
| 35 | +## Creating the Vertex Shader |
| 36 | + |
| 37 | +<video class="demo" loop autoplay muted width="100%"> |
| 38 | + <source src="/img/blog/neat_vertex_shader.mp4" type="video/mp4"/> |
| 39 | +</video> |
| 40 | + |
| 41 | +The **vertex shader** is in charge of determining the position of each vertex. We have this loop running on the CPU |
| 42 | +using `requestAnimationFrame` that triggers updates. Each vertex is passed through a Perlin noise function. This Perlin |
| 43 | +function receives the coordinates of the shader, as well as the elapsed time and some parameters that we use to tweak |
| 44 | +the waves animation. **We can change the frequency of the waves, the amplitude, the speed, and the horizontal and |
| 45 | +vertical pressure.** |
| 46 | + |
| 47 | +## Creating the Fragment Shader |
| 48 | + |
| 49 | +<video class="demo" loop autoplay muted width="100%"> |
| 50 | + <source src="/img/blog/neat_color_shader.webm" type="video/mp4"/> |
| 51 | +</video> |
| 52 | + |
| 53 | +The **fragment shader** is in charge of determining the color of each pixel. NEAT uses from 1 to 5 colors as input. Each |
| 54 | +of these colors is passed through a Perlin noise function that generates a pattern like the one represented above. **The |
| 55 | +colors are then mixed together based on the noise value.** If we don't apply any blending to the colors, the result will |
| 56 | +be a sharp transition between the colors, as represented in the video above. We can apply a blending factor to the |
| 57 | +colors so that the transition between them is smoother. We can also apply horizontal and vertical pressure to the color |
| 58 | +patterns, so they are more or less pronounced. |
| 59 | + |
| 60 | +## Post Processing |
| 61 | + |
| 62 | +If we put it all together, we get a **3D gradient that morphs and changes.** At this point, we can apply some |
| 63 | +post-processing effects to the final image. We can change the brightness and saturation of the colors. It turns out this |
| 64 | +is pretty easy to do with WebGL shaders once you have calculated the color of each pixel. **We can also add some shadows |
| 65 | +and highlights based on the vertex normals.** This is a simple way to add some depth to the image. In the latest |
| 66 | +versions, we added some grain to the image to make it look more like a film. We can change the scale, intensity, and |
| 67 | +speed of the grain. |
| 68 | + |
| 69 | +## The Editor |
| 70 | + |
| 71 | +Having all this power in a single shader is really cool, but it's not easy to tweak the parameters. **That's why we |
| 72 | +created a simple editor that allows you to change the parameters in real-time.** You can change the speed, the frequency |
| 73 | +of the waves, the amplitude, the colors, the blending, the brightness, the saturation, the grain, and the resolution of |
| 74 | +the image, among other things. All this is performed in real-time. Every change is passed to the shaders as a uniform |
| 75 | +variable, and the image is re-rendered. |
| 76 | + |
| 77 | +**This is really cool because you can see the changes immediately.** Until we had the editor, we were tweaking the |
| 78 | +parameters in the code and reloading the page to see the changes. This was really slow and cumbersome. It was also hard |
| 79 | +to know if we were going in the right direction. It was more a process of trial and error. It was not until we had the |
| 80 | +editor that we could really see the potential of the tool. **We could create a lot of different patterns and see how |
| 81 | +they look in real-time.** We could also save the patterns we liked and keep them as presets. |
| 82 | + |
| 83 | +At this point, we were able to fine-tune a gradient to make it look exactly like the Stripe gradient. It has been quite |
| 84 | +a journey, but we are really happy with the results. Once you have a gradient you like, you can export it as a JSON |
| 85 | +object and use it in your projects. **We have created a lot of patterns with NEAT, and we are really happy with the |
| 86 | +results.** We have used it in many projects, and it has always been a hit. We are really proud of it, and we hope you |
| 87 | +like it too. |
| 88 | + |
| 89 | +Check the [NEAT website](https://neat.firecms.co) to see some examples of what you can do with it. You can also check |
| 90 | +the [NEAT repository](https://github.com/firecmsco/neat) to see the code and the editor in action. |
0 commit comments