Learn how to make a GLSL Circle

In this tutorial, I show how to make a simple GLSL Circle.

For those who aren’t familiar with GLSL, you can follow a really good set of tutorials here: https://thebookofshaders.com/

If you are familiar but just need a refresher or just gettin started, feel free to watch. I follow a simple set of progressions from controlling the colors in the view to creating a circle shape. From there I show how to inset the colors.

  1. Normalize the UV coordinates of your scene so you are working from 0,0 in the center.
  2. Generate a color
  3. Modify your color on a set of changing variables (in this case iTime)
  4. set fragColor to your new color!

And here’s the code for this:

[pastacode lang=”cpp” manual=”void%20mainImage(%20out%20vec4%20fragColor%2C%20in%20vec2%20fragCoord%20)%0A%7B%0A%20%20%20%20%2F%2F%20Normalized%20pixel%20coordinates%20(from%200%20to%201)%0A%20%20%20%20vec2%20uv%20%3D%20fragCoord.xy%2FiResolution.xy%3B%0A%20%20%20%20vec2%20center%20%3D%20uv%20-%20vec2(0.5%2C0.5)%3B%0A%20%20%20%20center.x%20%3D%20center.x%20*%20(iResolution.x%20%2F%20iResolution.y)%3B%0A%0A%20%20%20%20%0A%20%20%20%20vec3%20col%20%3D%20vec3(0.9%2C%200.3%20%2B%20center.y%2C%200.5%20%2B%20center.x)%3B%0A%20%20%20%20%0A%20%20%20%20float%20r%20%3D%200.2%20%2B%200.5%20*%20cos(iTime)%3B%0A%20%20%20%20%0A%20%20%20%20col%20*%3D%201.0%20-%20smoothstep(r%2C%20r%20%2B%200.01%2C%20length(center))%3B%0A%0A%20%20%20%20%2F%2F%20Output%20to%20screen%0A%20%20%20%20fragColor%20%3D%20vec4(col%2C1.0)%3B%0A%7D” message=”” highlight=”” provider=”manual”/]

To practice this I recommend making a new experiment here: https://www.shadertoy.com/new

GLSL Functions Explained

UPDATE: Actually, you don’t need to read further, instead go here: http://thebookofshaders.com/glossary/

 

Disclaimer: I’m in no way an expert on GLSL, graphics programing, or anything else in the world, really…

However, I’m finding it difficult to find good docs on WebGL functions, that explain in layman’s terms what the hell they do. So I’m starting a list here and updating it as I learn more. Also, if I’m wrong, tell me, I don’t want to give out bad information.

 

float step(float a, float b)

  • returns a float value of either 0.0 or 1.0 depending on if “b” is higher or lower than “a”
  • “a” represents the limit or threshold to cross
  • “b” represents the number to test against the threshold

float smoothstep(float a, float b, float c)

  • returns a float value of anywhere from 0.0 to 1.0. 0.0 for any “c” value below “a” and 1.0 for any “c” value above “b”. The “c” values in between the “a” and “b” range are interpolated
  • “a” represents the start of the range (threshold)
  • “b” represents the end of the range (threshold)
  • “c” represents the value to test against the range

float fract(float a)

  • returns only the fraction portion of a value. So given the value 3.14159265358979, it will return .14159265358979

 

Simple Shader with ThreeJS

Ok folks, it doesn’t get easier than this. If you want to start writing shaders in the browser but can’t figure out how to create your shader program, ThreeJS has you covered.

To write a shader in GLSL (oenGL Shading Language) you first need to let the browser know where you’re going to put your program. Some the shader stuff might look like a combination of javascript and C to you, however, it’s actually GLSL. That’s the language you write shaders in for the web. In order to start writing shaders, you first need to have something to shade. Which means you need to have atleast a simple 3 dimensional object upon which the shader can begin “shading”. The most simple is a plane (two triangles put together into a square) which you will use below to start experimenting with shaders.

Just like drawing with canvas and javascript you need a context. WebGL (the technology threeJS uses) uses the same canvas element that you might be used to drawing with in 2D. Basically instead of get a context of “2D” we are going to get the canvas context of “webgl” instead.

[pastacode lang=”javascript” manual=”const%20gl%20%3D%20canvas.getContext(‘webgl’%2C%20%7B%0A%20%20antialias%3A%20false%2C%0A%20%20depth%3A%20false%0A%7D)%3B” message=”” highlight=”” provider=”manual”/]

Follow the instructions below to begin creating your own shaders. If you are having trouble getting started and don’t want to create your own contexts, you can easily use shadertoy to do the heavy lifting for you. It allows you to start writing GLSL immediately.

In your JS

[pastacode lang=”javascript” manual=”var%20camera%20%3D%20new%20THREE.Camera()%3B%0A%09camera.position.z%20%3D%201%3B%0A%0A%09var%20scene%20%3D%20new%20THREE.Scene()%3B%0A%0A%09var%20uniforms%20%3D%20%7B%0A%09%09time%3A%20%7B%20type%3A%20%22f%22%2C%20value%3A%201.0%20%7D%2C%0A%09%09resolution%3A%20%7B%20type%3A%20%22v2%22%2C%20value%3A%20new%20THREE.Vector2()%20%7D%0A%09%7D%3B%0A%0A%09var%20material%20%3D%20new%20THREE.ShaderMaterial(%20%7B%0A%09%09uniforms%3A%20uniforms%2C%0A%09%09vertexShader%3A%20document.getElementById(%20’vertexShader’%20).innerText%2C%0A%09%09fragmentShader%3A%20document.getElementById(%20’fragmentShader’%20).innerText%0A%09%7D)%3B%0A%0A%09var%20mesh%20%3D%20new%20THREE.Mesh(%20new%20THREE.PlaneGeometry(%202%2C%202%20)%2C%20material%20)%3B%0A%0A%09scene.add(%20mesh%20)%3B%0A%0A%09var%20canvas%20%3D%20document.querySelector(%22.lense-flare%22)%3B%0A%09var%20parent%20%3D%20canvas.parentElement%3B%0A%09var%20renderer%20%3D%20new%20THREE.WebGLRenderer(%7B%20canvas%3A%20canvas%20%7D)%3B%0A%09renderer.setSize(%20parent.clientWidth%2C%20parent.clientHeight%20)%3B%0A%0A%09uniforms.resolution.value.x%20%3D%20parent.clientWidth%3B%0A%09uniforms.resolution.value.y%20%3D%20parent.clientHeight%3B%0A%09var%20startTime%20%3D%20Date.now()%3B%0A%0A%09animate()%3B%0A%0A%09function%20animate()%20%7B%0A%09%09requestAnimationFrame(%20animate%20)%3B%0A%09%09render()%3B%0A%09%7D%0A%0A%09function%20render()%20%7B%0A%09%09var%20elapsedMilliseconds%20%3D%20Date.now()%20-%20startTime%3B%0A%09%09var%20elapsedSeconds%20%3D%20elapsedMilliseconds%20%2F%201000.%3B%0A%09%09uniforms.time.value%20%3D%2060.%20*%20elapsedSeconds%3B%0A%09%09renderer.render(%20scene%2C%20camera%20)%3B%0A%09%7D” message=”” highlight=”” provider=”manual”/]

 

In your head:

[pastacode lang=”markup” manual=”%3Cscript%20id%3D%22vertexShader%22%20type%3D%22x-shader%2Fx-vertex%22%3E%0A%09%09%09uniform%20float%20time%3B%0A%09%09%09uniform%20vec2%20resolution%3B%0A%09%09%09void%20main()%09%7B%0A%09%09%09%09gl_Position%20%3D%20vec4(%20position%2C%201.0%20)%3B%0A%09%09%09%7D%0A%09%09%3C%2Fscript%3E%0A%09%09%3Cscript%20id%3D%22fragmentShader%22%20type%3D%22x-shader%2Fx-fragment%22%3E%0A%09%09%09uniform%20float%20time%3B%0A%09%09%09uniform%20vec2%20resolution%3B%0A%09%09%09void%20main()%09%7B%0A%09%09%09%09float%20x%20%3D%20mod(time%20%2B%20gl_FragCoord.x%2C%2020.)%20%3C%2010.%20%3F%201.%20%3A%200.%3B%0A%09%09%09%09float%20y%20%3D%20mod(time%20%2B%20gl_FragCoord.y%2C%2020.)%20%3C%2010.%20%3F%201.%20%3A%200.%3B%0A%09%09%09%09gl_FragColor%20%3D%20vec4(vec3(min(x%2C%20y))%2C%201.)%3B%0A%09%09%09%7D%0A%09%09%3C%2Fscript%3E” message=”” highlight=”” provider=”manual”/]