Search code examples
three.jsgrafanareact-three-fibergltfgrafana-plugin

Grafana Panel Plugin cannot find .gltf object using ThreeJS


I am trying to use the ThreeJS Library to load a .gltf object and display on to a grafana panel. I have put the .gltf object in my src folder and referenced it in src/components/SimplePanel.tsx.

I've taken a number of routes to try to fix the isse but it just keeps throwing status=404 when given the correct path and utilizing the GET method.

Error: threejs-panel | logger=context userId=0 orgId=1 uname= t=*** level=info msg="Request Completed" method=GET path=/api/live/ws status=-1 remote_addr=172.18.0.1 time_ms=0 duration=693.968µs size=0 referer= handler=/api/live/ws

SimplePanel.tsx

import React, { useEffect, useRef } from 'react';
import { PanelProps } from '@grafana/data';
import { SimpleOptions } from 'types';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

interface Props extends PanelProps<SimpleOptions> {}

export const SimplePanel: React.FC<Props> = ({ options, data, width, height }) => {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!containerRef.current) return;

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
    const renderer = new THREE.WebGLRenderer();
    const loader = new GLTFLoader();

    renderer.setSize(width, height);
    containerRef.current.appendChild(renderer.domElement);

    loader.load('./src/Blackhawk.gltf', (gltf) => {
      const model = gltf.scene;
      model.scale.set(0.1, 0.1, 0.1);
      scene.add(model);

      // Adjust camera position
      const box = new THREE.Box3().setFromObject(model);
      const size = box.getSize(new THREE.Vector3());
      const center = box.getCenter(new THREE.Vector3());

      const maxDim = Math.max(size.x, size.y, size.z);
      const fov = camera.fov * (Math.PI / 180);
      let distance = maxDim / (2 * Math.tan(fov / 2));
      distance += maxDim * 0.25;

      camera.position.copy(center);
      camera.position.z += distance;
      camera.lookAt(center);

      // Optional: Add lighting to the scene
      const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
      scene.add(ambientLight);

      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
      directionalLight.position.set(5, 5, 5);
      scene.add(directionalLight);

      function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
      }

      animate();
    });
  }, []);

  return (
    <div
      ref={containerRef}
      style={{ width: '100%', height: '100%', overflow: 'hidden' }}
    ></div>
  );
};

Webpack.config.ts

        test: /\.(png|jpe?g|gif|svg|gltf)$/,
        type: 'asset/resource',
        generator: {
          // Keep publicPath relative for host.com/grafana/ deployments
          publicPath: `public/plugins/${getPluginId}/img/`,
          outputPath: 'img/',
          filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]',
        },

One thing I notice is that when I run the dev script, the .gltf object is not added to the dist folder. At one point in my configuration, i was able to get it to load into the config folder and it would import two file. One in the dist/img/ folder that was named 2efghij3***.gltf and another in the dist folder named 9dbql***.gltf that called the file in the img folder.

I have correctly added needed dependencies like Three, because I can see the default black screen that Three applies when i load the panel. My problem is, the Docker or Plugin cannot find the .gltf object. Is there a specific folder it needs to be in or way it needs to be referenced?

I've tried extending webpack.config.ts and configuring the handling of .gltf object there but it still failed to load the object.


Solution

  • put the gltf in the public folder