<script>
        const imgData = `data:image/png;base64,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`;
    </script>
    <div id="info"></div>
    <script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
body{
  overflow: hidden;
  margin: 0;
}

#info {
  position: absolute;
  color: white;
  font-family: Arial;
}
import * as THREE from "https://threejs.org/build/three.module.js";
import { OrbitControls } from "https://threejs.org/examples/jsm/controls/OrbitControls.js";

let fft = [];
let data1;
let data2;
let data3;

const lineMaterial = new THREE.LineBasicMaterial({ color: 0x0000ff });

$.get({
    url: 'https://files.wnology.io/5fd77c0d33491f0006da9de8/ThreeJS/docs/temp/1620291600000-144f8cf0ddf47a2d6676017480e6794f.json',
    async: false
}, function(data) {
    data1 = data
});

$.get({
    url: 'https://files.wnology.io/5fd77c0d33491f0006da9de8/ThreeJS/docs/temp/1620291600000-4b685a1eaa1bb5cd30ff2a2f0627d221.json',
    async: false
}, function(data) {
    data2 = data
});

$.get({
    url: 'https://files.wnology.io/5fd77c0d33491f0006da9de8/ThreeJS/docs/temp/1620291600000-96a43a9c906b2c173bda688c0afb6cd2.json',
    async: false
}, function(data) {
    data3 = data
});

fft.push(data1)
fft.push(data2)
fft.push(data3)
fft.push(data1)
fft.push(data2)
fft.push(data3)
fft.push(data1)
fft.push(data2)
fft.push(data3)
fft.push(data1)

console.log(fft)

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(-100, 100, 150);
let renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2(1, 1);

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

let light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(1);
scene.add(light, new THREE.AmbientLight(0xffffff, 0.75));

createAGrid()

let g = new THREE.BoxGeometry();
g.translate(0, 0.5, 0);
let m = new THREE.MeshLambertMaterial({
    onBeforeCompile: shader => {
        shader.uniforms.lut = {
            value: new THREE.TextureLoader().load(imgData)
        }
        shader.vertexShader = `
      varying float vCurrHeight;
      ${shader.vertexShader}
    `.replace(
            `#include <worldpos_vertex>`,
            `
        #include <worldpos_vertex>
        vCurrHeight = (instanceMatrix * vec4( transformed, 1.0 )).y;
        
      `
        );
        shader.fragmentShader = `
      uniform sampler2D lut;
      varying float vCurrHeight;
      ${shader.fragmentShader}
    `.replace(
            `vec4 diffuseColor = vec4( diffuse, opacity );`,
            `
        float h = clamp(vCurrHeight / 30., 0., 1.);
        vec3 col = texture(lut, vec2(0.3, h)).rgb;
        vec4 diffuseColor = vec4( col, opacity );
      `
        );
        //console.log(shader.fragmentShader)
    }
});
let rows = fft.length;
let cols = 1008;
let factor = 300

let o = new THREE.InstancedMesh(g, m, rows * cols);

let dummy = new THREE.Object3D();
let mat4 = new THREE.Matrix4();
for (let y = 0; y < rows; y++) {
    for (let x = 0; x < cols; x++) {
        dummy.position.set(0, 0, (rows - 1) / 2 - y).multiplyScalar(20);
        dummy.position.set(-(cols - 1) / 2 + x, 0, dummy.position.z)
        dummy.position.set(dummy.position.x, dummy.position.y, dummy.position.z).multiplyScalar(0.243);

        let hData = fft[y][x].a

        dummy.scale.set(0.25, hData * factor, 0.25);
        dummy.updateMatrix();
        o.setMatrixAt(y * cols + x, dummy.matrix);
    }
}

scene.add(o);

window.addEventListener('resize', onWindowResize);
document.addEventListener('mousemove', onMouseMove);

renderer.setAnimationLoop(_ => {

    raycaster.setFromCamera(mouse, camera);

    const intersection = raycaster.intersectObject(o);

    if (intersection.length > 0) {

        info.style.display = "block";
        const instanceId = intersection[0].instanceId;

        o.getMatrixAt(instanceId, mat4);
        mat4.decompose(dummy.position, dummy.quaternion, dummy.scale);

        info.innerText = `data: ${dummy.scale.y/factor}`;

    } else {
        info.style.display = "none";
    }

    renderer.render(scene, camera);
})

function onMouseMove(event) {

    event.preventDefault();

    info.style.transform = `translate(${event.clientX + 15}px, ${event.clientY + 5}px)`;

    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

}

function createAGrid(opts) {
    var gridXZ = new THREE.GridHelper(250, 6)
    gridXZ.scale.set(1, 0.5, 0.25);
    scene.add(gridXZ);

    var gridXY = new THREE.GridHelper(250, 6);
    gridXY.position.z = -31, 25
    gridXY.position.y = 125
    gridXY.rotation.x = Math.PI / 2;
    scene.add(gridXY);

    var gridYZ = new THREE.GridHelper(250, 3);
    gridYZ.position.x = -125
    gridYZ.position.y = 125
    gridYZ.rotation.z = Math.PI / 2;
    gridYZ.scale.set(1, 1, 0.25);
    scene.add(gridYZ);
}

function onWindowResize() {

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);

}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.