DEV Community

Cover image for Create a background with GLSL Shader [Threejs | Typescript]
NOPR9D ☄️
NOPR9D ☄️

Posted on

5 3

Create a background with GLSL Shader [Threejs | Typescript]

Hi to all!

Lately I had a little fun with 3D in javascript, and that's why I'm doing a first post. We will use Threejs and GLSL Shaders.

We will learn how we can make a background like this :

GLSL Shaders are designed for use with graphics and contain functionality for manipulating vectors and matrices.

The shader syntax that three.js uses is GLSL and this code is compiled and run on the GPU using WebGL, here we apply this to a Plane Geometry but you can also do it for any 3D elements having a ShaderMaterial.


Normally Shaders always begin with a version declaration, followed by a list of input and output variables, uniforms and its main function but with Threejs we just need variales, uniforms and function.

// Default Vertex for threejs
precision mediump float;

varying vec2 vUv;

  void main() {
     vUv = uv;
     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
              }
Enter fullscreen mode Exit fullscreen mode
// Default Fragment for threejs
out vec4 fragColor;

void main() {
    fragColor = vec4(1.0, 0.0, 0.0, 1.0);
            }
Enter fullscreen mode Exit fullscreen mode

And yeah, as you can see we have two files, vertex shader and fragment shader.

  • Vertex Shader : Here you can operate all change to deform an object in a shader, your code will be done on every vertices.

  • Fragment Shader : It will take the output from the vertex shader and associates colors, depth value, ...


So now we're done with the shader presentations, and I guess we don't need to introduce Threejs.

As always with threejs we need to initialize the scene.

  private scene!: THREE.Scene;
  private camera!: THREE.PerspectiveCamera;
  private light!: THREE.SpotLight;
  private renderer!: THREE.WebGLRenderer;
  private clock!: THREE.Clock;

  public init(canvas: HTMLCanvasElement) {
    // Scene
    this.scene = new THREE.Scene();
    this.scene.background = new THREE.Color(0xe3e3e3);

    // Light
    this.light = new THREE.SpotLight(0xffffff, 1);

    // Camera
    const fov = 45;
    const aspect = window.innerWidth / window.innerHeight;
    const near = 1;
    const far = 100;
    this.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);

   // Renderer
   this.renderer = new THREE.WebGLRenderer({
      canvas: canvas
    });
    this.renderer.setClearColor(0xffffff, 1);
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(window.innerWidth, window.innerHeight);

    this.clock = new THREE.Clock();
}
Enter fullscreen mode Exit fullscreen mode

We have our scene, now we need our 3D elements, we will use PlaneBufferGeometry for a flat surface and ShaderMaterial to apply custom shaders.

this.geometry = new THREE.PlaneBufferGeometry(30, 10);

this.material = new THREE.ShaderMaterial({
      vertexShader: "HERE-CUSTOM-VERTEX",
      fragmentShader: "HERE-CUSTOM-FRAGMENT",
      // Here you can pass args to your shaders (material or data).
      // Exemple "uResolution" in .ts >>>> input as "varying vec2 uResolution" in .glsl;
      // uResolution for responsive, uTime will be use by THREE.Clock
      uniforms: {
        uTime: { value: 0.0 },
        uResolution: { value: { x: window.innerWidth, y: window.innerHeight } },
        uColor: { value: new THREE.Color(0xffffff) }
      }
    });
this.mesh = new THREE.Mesh(this.geometry, this.material);

Enter fullscreen mode Exit fullscreen mode

Add all to our scene and look at our plane object.

    this.scene.add(this.camera);
    this.scene.add(this.mesh);
    this.scene.add(this.light);
    this.mesh.position.set(0, 0, 0);
    this.camera.position.set(0, 0, 10);
    this.light.position.set(0, 0, 10);

    this.light.lookAt(this.mesh.position);
    this.camera.lookAt(this.mesh.position);
Enter fullscreen mode Exit fullscreen mode

Now we can finally animate our scene, we will be careful to make everything responsive


 public run() {
    window.requestAnimationFrame(this.run.bind(this));
    // Update Shaders uTime value
    this.material.uniforms.uTime.value = this.clock.getElapsedTime();
    this.renderer.render(this.scene, this.camera);
   }

  private addEvents(): void {
    window.addEventListener("resize", this.onResize.bind(this), false);
  }

  private onResize() {
    // Update Shader uResolution value
    this.material.uniforms.uResolution = {
      value: { x: window.innerWidth, y: window.innerHeight }
    };
    this.camera.aspect = window.innerWidth / window.innerHeight;
    this.camera.updateProjectionMatrix();
    this.renderer.setSize(window.innerWidth, window.innerHeight);
  }
}


const scene = new CustomScene();
scene.init(document.getElementById("canvas") as HTMLCanvasElement);
scene.run();

Enter fullscreen mode Exit fullscreen mode

And Voila !

Image of AssemblyAI tool

Challenge Submission: SpeechCraft - AI-Powered Speech Analysis for Better Communication

SpeechCraft is an advanced real-time speech analytics platform that transforms spoken words into actionable insights. Using cutting-edge AI technology from AssemblyAI, it provides instant transcription while analyzing multiple dimensions of speech performance.

Read full post

Top comments (1)

Collapse
 
artydev profile image
artydev

Great thank you

The best way to debug slow web pages cover image

The best way to debug slow web pages

Tools like Page Speed Insights and Google Lighthouse are great for providing advice for front end performance issues. But what these tools can’t do, is evaluate performance across your entire stack of distributed services and applications.

Watch video

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay