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

ThreeJS Setting the Right Aspect Ratio for the Camera

One quick note for myself and anyone who will ever use this…

If you are working with an abnormal size canvas, you need to do some math to set the size of the renderer to be correct with the aspect ratio:

[pastacode lang=”javascript” manual=”let%20rect%20%3D%20this.renderer.domElement.getBoundingClientRect()%3B%0A%09%09camera.aspect%20%3D%20rect.width%20%2F%20rect.height%3B%0A%09%09camera.updateProjectionMatrix()%3B%0A%09%09renderer.setSize(%20rect.width%2C%20rect.height%20)%3B” message=”” highlight=”” provider=”manual”/]

Basically, you are working out the bounding box in which the scene will exist. To do that, we need to give the camera an aspect ratio and a size for the renderer. Setting the size on the renderer is easy; just send the width and height. The aspect ratio is also pretty easy; just divide the width by the height and you are good to go.

Both the width and height can be found by using “getBoundingClientRect()”.

NOTE: This site is all about helpful hints tricks and tips. The posts lately have been short on purpose. For one, I’m busy AF and don’t have the time to post anything of great detail. Additionally, I believe in simplicity. You can visit, find something helpful and move on with your life.

As always I appreciate your feedback, please leave a comment if you feel I’m leading people down a less than idea path or just comment because you like talking IDC.

Export GLTF Format From Blender to ThreeJS

In the following video I show how to export textures/meshes from blender into the new(ish) gltf format. This is a binary format that contains the mesh and images in a very small file size which works well for exporting to webGL contexts. It’s sort of the new collada exporter and very easy to use with libraries such as threejs. As of now the exporter doesn’t support the more advanced features but will export meshes, textures, cameras and animations.

Follow along below to export your scene in gltf.

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”/]