title: 'plus' or 'x' shaped wave in threejs
body: <p>I have this scene made with THREE.js. (see code snippet attached in the post)
  or <a href="https://codepen.io/farisk/pen/jOPgKGQ" rel="nofollow noreferrer">https://codepen.io/farisk/pen/jOPgKGQ</a></p>
  
  <p>Currently its a radiating a circular wave based on the formula in the ‘<code>distance()</code>’ function</p>
  
  <p>As such :</p>
  
  <pre><code>return Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2));
  </code></pre>
  
  <p>I’m wondering if its possible to modify the formula so that I can somehow achieve a ‘X’ or ‘Plus sign (+)’ shaped wave instead?</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var once = false;
  
  class App {
    init() {
      this.stats = new Stats();
      this.stats.showPanel(0);
      document.body.querySelector('.stats').appendChild(this.stats.domElement);
  
      this.backgroundColor = 0x000000;
      this.ambientLightColor = 0xffffff;
      this.spotLightColor = 0xff9999;
      // this.boxColor = 0x1a63ed;
      this.boxColor = 0xffffff;
      this.angle = 0;
      this.gridSize = 30;
      this.ratio = 1.3
      this.col = this.gridSize*this.ratio;
      this.row = this.gridSize;
      this.velocity = .05;
      this.boxes = [];
  
      this.amplitude = -7;
      this.frequency = 0;
      this.waveLength = 242;
  
      this.scene = new THREE.Scene();
      this.scene.background = new THREE.Color(this.backgroundColor);
  
      this.camera = new THREE.PerspectiveCamera(2, window.innerWidth / window.innerHeight, 1, 10000);
      this.camera.position.set(0, 800, 0);
  
      this.addRenderer();
  
      document.body.appendChild(this.renderer.domElement);
  
      this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
  
      this.addAmbientLight();
  
      this.addDirectionalLight();
  
      this.addFloor();
  
      this.addBoxes(this.scene);
  
      this.addGUIControls();
  
      this.animate();
  
      window.addEventListener('resize', this.onResize.bind(this));
    }
  
    addDirectionalLight() {
      this.directionalLight = new THREE.DirectionalLight(0xffffff, 1);
      this.directionalLight.castShadow = true;
      this.directionalLight.position.set(0, 1, 0);
  
      this.directionalLight.shadow.camera.far = 10000;
      this.directionalLight.shadow.camera.near = -100;
  
      this.directionalLight.shadow.camera.left = -40;
      this.directionalLight.shadow.camera.right = 40;
      this.directionalLight.shadow.camera.top = 20;
      this.directionalLight.shadow.camera.bottom = -20;
      this.directionalLight.shadow.camera.zoom = 1;
      this.directionalLight.shadow.camera.needsUpdate = true;
  
      const targetObject = new THREE.Object3D();
      targetObject.position.set(-50, -82, 40);
      this.directionalLight.target = targetObject;
  
      this.scene.add(this.directionalLight);
      this.scene.add(this.directionalLight.target);
    }
  
    addGUIControls() {
      this.gui = new dat.GUI();
      this.gui.add(this, 'amplitude', -10, 10);
      this.gui.add(this, 'velocity', 0, .5);
      this.gui.add(this, 'waveLength', 100, 500);
      this.controller = this.gui.add(this, 'gridSize', 24, 150);
  
      this.controller.onFinishChange((value) =&gt; {
        this.gridSize = Math.floor(value);
  
        this.clearScene();
  
        this.col = this.gridSize*this.ratio;
        this.row = this.gridSize;
  
        this.addBoxes(this.scene);
      });
    }
  
    addRenderer() {
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.renderer.shadowMap.enabled = true;
      this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
      this.renderer.setSize(window.innerWidth, window.innerHeight);
    }
  
    addAmbientLight() {
      const light = new THREE.AmbientLight(this.ambientLightColor, .5);
      this.scene.add(light);
    }
  
    addSpotLight() {
      this.spotLight = new THREE.SpotLight(this.spotLightColor);
      this.spotLight.position.set(100, 250, 150);
      this.spotLight.castShadow = true;
      this.scene.add(this.spotLight);
    }
  
    clearScene() {
      this.scene.remove(this.mesh);
  
      this.boxes = [];
    }
  
    addBoxes(scene) {
      const size = 0.05;
      const height = 20;
      const material = new THREE.MeshLambertMaterial({
        color: this.boxColor,
      });
  
      const geometry = new THREE.BoxBufferGeometry(size, height, size);
      geometry.translate( 0, 2.5, 0 );
      this.mesh = this.getBox(geometry, material, this.row * this.col);
      this.scene.add(this.mesh);
  
      let ii = 0;
  
      for (let i = 0; i &lt; this.col; i++) {
        this.boxes[i] = [];
  
        for (let j = 0; j &lt; this.row; j++) {
          const pivot = new THREE.Object3D();
          this.boxes[i][j] = pivot;
  
          pivot.scale.set(1, 0.001, 1);
          // pivot.position.set(i - this.gridSize*this.ratio * .5, height * .5, j - this.gridSize * .5);
          pivot.position.set(i - this.gridSize*this.ratio * .5, height * 0, j - this.gridSize * .5);
  
          pivot.updateMatrix();
          this.mesh.setMatrixAt(ii++, pivot.matrix);
        }
      }
  
      this.mesh.instanceMatrix.needsUpdate = true;
    }
  
    drawWave() {
      let ii= 0;
  
      for (let i = 0; i &lt; this.col; i++) {
        for (let j = 0; j &lt; this.row; j++) {
          const distance = this.distance(j, i, this.row * .5, this.col * .5);
  
          const offset = this.map(distance, 0, this.waveLength, -100, 100);
          const angle = this.angle + offset ;
          if (!once) {
            console.log(this.boxes)
            once = true
          }
          this.boxes[i][j].scale.y = this.map(Math.sin(angle), -1, -this.amplitude, 0.001, 1);
          this.boxes[i][j].rotation.z = this.map(Math.sin(angle), -1, -this.amplitude, 0.001, 1);
  
          this.boxes[i][j].updateMatrix();
          this.mesh.setMatrixAt(ii++, this.boxes[i][j].matrix);
        }
      }
  
      this.mesh.instanceMatrix.needsUpdate = true;
  
      this.angle -= this.velocity;
    }
  
    distance(x1, y1, x2, y2) {
      // return Math.sin(x1 - x2)
      return Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2));
    }
  
    map(value, start1, stop1, start2, stop2) {
      return (value - start1) / (stop1 - start1) * (stop2 - start2) + start2
    }
  
    addFloor() {
      const planeGeometry = new THREE.PlaneBufferGeometry(10, 500);
      const planeMaterial = new THREE.ShadowMaterial({ opacity:1 });
  
      this.floor = new THREE.Mesh(planeGeometry, planeMaterial);
  
      planeGeometry.rotateX(- Math.PI / 2);
  
      this.floor.position.y = 2;
      this.floor.receiveShadow = true;
  
      this.scene.add(this.floor);
    }
  
    getBox(geometry, material, count) {
      const mesh = new THREE.InstancedMesh(geometry, material, count);
      mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
      mesh.castShadow = true;
      mesh.receiveShadow = true;
  
      return mesh;
    }
  
    addGrid() {
      const size = this.col;
      const divisions = size;
      const gridHelper = new THREE.GridHelper(size, divisions);
  
      gridHelper.position.set(0, 0, 0);
      gridHelper.material.opacity = 0;
      gridHelper.material.transparent = true;
  
      this.scene.add(gridHelper);
    }
  
    animate() {
      this.stats.begin();
  
      this.drawWave();
  
      this.controls.update();
  
      this.renderer.render(this.scene, this.camera);
  
      this.stats.end();
  
      requestAnimationFrame(this.animate.bind(this));
    }
  
    onResize() {
      const ww = window.innerWidth;
      const wh = window.innerHeight;
  
      this.camera.aspect = ww / wh;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(ww, wh);
    }
  }
  
  new App().init();</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>html {
    font-family: sans-serif;
  }
  
  * {
    box-sizing: border-box;
  }
  
  body {
    background: black;
    color: #fff;
    font-family: sans-serif;
    overflow: hidden;
    cursor: -webkit-grab;
    cursor: -moz-grab;
    padding: 0;
    margin: 0;
  }
  
  canvas {
    width: 100%;
    height: 100%;
  }
  
  .stats {
    opacity: 1;
    z-index: 10;
    position: absolute;
  }
  
  .dg.ac {
    position: absolute;
    z-index: 10 !important;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>  &lt;main&gt;
       &lt;div class="stats"&gt;&lt;/div&gt;
    &lt;/main&gt;
  
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"&gt;&lt;/script&gt;
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"&gt;&lt;/script&gt;
    &lt;script src="https://threejs.org/examples/js/controls/OrbitControls.js"&gt;&lt;/script&gt;
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.2/dat.gui.js"&gt;&lt;/script&gt;
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"&gt;&lt;/script&gt;</code></pre>
  </div>
  </div>
  </p>