body{
  overflow: hidden;
  margin: 0;
}
import * as THREE from "https://cdn.skypack.dev/[email protected]";
import {OrbitControls} from "https://cdn.skypack.dev/[email protected]/examples/jsm/controls/OrbitControls";

console.clear();

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 1000);
camera.position.set(0, 2, 5);
let renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", event => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
})

let controls = new OrbitControls(camera, renderer.domElement);

let gu = {
  time: {value: 0}
}

scene.add(new THREE.GridHelper());

let r = 0.1, R = 20, halfAngle = THREE.MathUtils.degToRad(45);
let g = new THREE.PlaneGeometry(1, 1, 72, 20);
let pos = g.attributes.position;
let uv = g.attributes.uv;
for(let i = 0; i < pos.count; i++){
  let y = 1. - uv.getY(i);
  let radius = r + (R - r) * y;
  let x = pos.getX(i);
  pos.setXY(i, Math.cos(x * halfAngle) * radius, Math.sin(x * halfAngle) * radius);
}
g.rotateX(-Math.PI * 0.5);
g.rotateY(-Math.PI * 0.5);

let m = new THREE.MeshBasicMaterial({
  color: new THREE.Color(0, 0.75, 1),
  side: THREE.DoubleSide,
  transparent: true,
  onBeforeCompile: shader => {
    shader.uniforms.time = gu.time;
    shader.fragmentShader = `
      uniform float time;
      ${shader.fragmentShader}
    `.replace(
      `#include <color_fragment>`,
      `#include <color_fragment>
      float t = time;
      float mainWave = sin((vUv.x - t * 0.2) * 1.5 * PI2) * 0.5 + 0.5;
      mainWave = mainWave * 0.25 + 0.25;
      mainWave *= (sin(t * PI2 * 5.) * 0.5 + 0.5) * 0.25 + 0.75;
      float sideLines = smoothstep(0.45, 0.5, abs(vUv.x - 0.5));
      float scanLineSin = abs(vUv.x - (sin(t * 2.7) * 0.5 + 0.5));
      float scanLine = smoothstep(0.01, 0., scanLineSin);
      float fadeOut = pow(vUv.y, 2.7);
      
      
      float a = 0.;
      a = max(a, mainWave);
      a = max(a, sideLines);
      a = max(a, scanLine);
      
      diffuseColor.a = a * fadeOut;
      
      `
    );
    console.log(shader.fragmentShader)
  }
});
m.defines = {"USE_UV": ""}

let laser = new THREE.Mesh(g, m);
laser.position.set(0, 1.5, 0);
scene.add(laser);

let clock = new THREE.Clock();

renderer.setAnimationLoop(() => {
  let t = clock.getElapsedTime();
  gu.time.value = t;
  laser.rotation.x = (Math.sin(t) * 0.5 + 0.5) * THREE.MathUtils.degToRad(10);
  renderer.render(scene, camera);
});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.