<div id="container">
  <div class="box">
    <div id="canvas">
      <canvas id="c">
      </canvas>
    </div>
  </div>
</div>
html,
body
  height 100%

#container
  width 100%
  height 100%
  background #d7d7d7
  /* --- FLEX --- */
  display flex
  justify-content center
  align-items center
  
.box
  width 200px
  height 200px
  background #fffafa
  color #fff
  text-align center
  box-shadow 5px 5px 20px #666
  display inherit
  justify-content inherit
  align-items inherit

#canvas
  width 100%
  height 100%
  
#c
  width 100%
  height 100%

View Compiled
// テーマ:シェーダーで関数を描画する
// お手本
// https://thebookofshaders.com/05/?lan=jp

////////////////////////////////////////////////////////////////////////
// 必要なモジュール類
////////////////////////////////////////////////////////////////////////
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r127/build/three.module.js';
import { OrbitControls } from 'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/controls/OrbitControls.js';

////////////////////////////////////////////////////////////////////////
// 本体
////////////////////////////////////////////////////////////////////////
main();

function main() {
  ////////////////////////////////////////////////////////////////////////
  // キャンバスの設定
  ////////////////////////////////////////////////////////////////////////
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});
  renderer.autoClearColor = false;
  
  ////////////////////////////////////////////////////////////////////////
  // 正射影カメラ正射影を使用するカメラです。
  //この投影モードでは、カメラからの距離にかかわらず、レンダリング画像内のオブジェクトのサイズが一定になります。
  ////////////////////////////////////////////////////////////////////////
  const left = -1;
  const right = 1;
  const top = 1;
  const buttom = -1;
  const near = -1;
  const far = 1;

  const camera = new THREE.OrthographicCamera(
    left,
    right,
    top,
    buttom,
    near,
    far
  );
  ////////////////////////////////////////////////////////////////////////
  // シーンの生成
  ////////////////////////////////////////////////////////////////////////
  const scene = new THREE.Scene();
  ////////////////////////////////////////////////////////////////////////
  // ジオメトリの生成 
  ////////////////////////////////////////////////////////////////////////
  const plane = new THREE.PlaneGeometry(2, 2);
  ////////////////////////////////////////////////////////////////////////
  // シェーダーの生成 
  ////////////////////////////////////////////////////////////////////////
  const fragmentShader = `
      #include <common>

      //iResolution: 解像度
      uniform vec3 iResolution;
      uniform float iTime;
      uniform float lineWidth;
      uniform float numberOfDivisions;
      // マウスの位置
      uniform vec2 u_mouse;
      
      ///////////////////////////////////////////////////////////
      // plot関数 (0.0~1.0の間の値を使って、Y軸に線を引く)
      ////////////////////////////////////////////////////////////
      float plot(vec2 position) {    
          // smoothstep(min, max, between) この関数はその範囲の間で0.0から1.0まで滑らかに変化する数値を返す
          // 入力値がminより小さい場合、smoothstep()は0を返します。
          // 入力値がmaxと等しいか、maxより大きい場合、smoothstep()は1を返します。
          // 入力がminとmaxの間にある場合、smoothstep()は0と1.0の間の値を(比例して)返します。
          // 最初の2つのパラメータは値の変化の起こる範囲の始まりと終わり
          // 3つめのパラメータはチェックの対象になる値
          // 0.02 よりもabs(position.y - position.x)が小さければ0を返す
          // abs(position.y - position.x) が 0か、0よりも大きい場合 1を返す
          // abs(position.y - position.x) が 0.02 ~ 0 の間にある場合、 0と1.0の間の値を(比例して)返す
          return smoothstep(0.02, 0.0, abs(position.y - position.x));
      }
      
      ////////////////////////////////////////////////////////////
      // mainImage関数 (基本はここで操作)
      ////////////////////////////////////////////////////////////
      
      // out 出力用 in 入力用
      void mainImage( out vec4 fragColor, in vec2 fragCoord ){
          
          //正規化(原点を中心におく)
          vec2 position = (fragCoord.xy * 2.0 - iResolution.xy) / min(iResolution.x, iResolution.y);
          
          // 左下が0 右上が1 になるから ひだりしたであればあるほど黒くなるし、右上になればなるほど白くなる
          // 縦で別れているのは、xの値をyにもいれているから
          float y = position.x;
          
          vec3 color = vec3(y);
          
          // ラインの描画 (x=y の直線時は1になる)
          float pct = plot(position);
          // x=y の直線に近づければ近づくほど、pctは1に近づくから 黒と緑の2色を制御できている
          color = (1.0 - pct) * color + pct * vec3(0.0, 1.0, 0.0);

          // 画面への出力
          fragColor = vec4(color, 1.0);
      }

      ////////////////////////////////////////////////////////////
      // main 関数
      /////////////////////////////////////////////////////////////
      void main() {
        mainImage(gl_FragColor, gl_FragCoord.xy);
      }
  `;
 const uniforms = {
    iTime: { value: 0 },
    lineWidth: { value: 0.0030 },
    numberOfDivisions: { value: 10.0 },
    iResolution:  { value: new THREE.Vector3() },
    u_mouse: { value: new THREE.Vector2() }
  };
  ////////////////////////////////////////////////////////////////////////
  // インタラクティブ(マウス)
  ////////////////////////////////////////////////////////////////////////
  document.onmousemove = function(e){
     uniforms.u_mouse.value.x = e.offsetX
     uniforms.u_mouse.value.y = e.offsetY
  }
  
  ////////////////////////////////////////////////////////////////////////
  // マテリアルの生成 
  ////////////////////////////////////////////////////////////////////////
   //ShaderMaterial:カスタムシェーダーでレンダリングされたマテリアルです。
  //シェーダーとは、GPU上で動作するGLSLで書かれた小さなプログラムです。
  const material = new THREE.ShaderMaterial({
    fragmentShader,
    uniforms,
  });
  scene.add(new THREE.Mesh(plane, material));
  
  
  ////////////////////////////////////////////////////////////////////////
  // OrbitControls
  // ref
  // https://www.i-ryo.com/entry/2020/05/02/215245#OrbitControlsjs%E3%82%92%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80
  ////////////////////////////////////////////////////////////////////////
	const controls = new OrbitControls( camera, renderer.domElement );
	controls.minDistance = 0;
	controls.maxDistance = 100;
  
  ////////////////////////////////////////////////////////////////////////
  // GUI
  ////////////////////////////////////////////////////////////////////////
  const gui = new dat.GUI();
  ////////////////////////////
  //   シェーダー系
  ////////////////////////////
    {
    var originalShaderGuiControls = new function (){
      this.uniformsLineWidth = 0.0025;
      this.uniformsNumberOfDivisions = 1.0;
      this.onChange = function () {
        uniforms.lineWidth.value = originalShaderGuiControls.uniformsLineWidth;
        uniforms.numberOfDivisions.value = originalShaderGuiControls.uniformsNumberOfDivisions;
        
      }
    }
    {
      const folder = gui.addFolder('オリジナルシェーダー');
      folder.add(originalShaderGuiControls, 'uniformsLineWidth', 0.0025, 0.01)
        .name('ラインの太さ')
        .onChange(originalShaderGuiControls.onChange);
      
      folder.add(originalShaderGuiControls, 'uniformsNumberOfDivisions', 1, 10.0)
        .name('円を分割する数')
        .onChange(originalShaderGuiControls.onChange);
      folder.open();
    }
  }

  
  ////////////////////////////////////////////////////////////////////////
  // アニメーション
  //////////////////////////////////////////////////////////////////////// 
  function render(time) {
    time *= 0.001;  // convert to seconds
    resizeRendererToDisplaySize(renderer);
    const canvas = renderer.domElement;
    uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
    uniforms.iTime.value = time;

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);
  
  ////////////////////////////////////////////////////////////////////////
  // render関数内 ディスプレイサイズにリサイズ
  ////////////////////////////////////////////////////////////////////////
  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }
}


Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/three.js/93/three.min.js
  2. https://cdn.jsdelivr.net/npm/three@0.101.1/examples/js/controls/OrbitControls.js
  3. https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js
  4. https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/postprocessing/EffectComposer.js