javascriptjquerythree.js

how to import THREE.InfiniteGridHelper


When attempting to use THREE.InfiniteGridHelper there doesn't seem to be a way to import the code that doesn't generate an error. Even copying and pasting the code does not work.

Currently I have the code copied and pasted into my main.js page and this gives the error it gives

Uncaught TypeError: "InfiniteGridHelper" is read-only http://127.0.0.1:5000/static/main.js:10

I have also tried pasting the code into its own InfiniteGridHelper.js page to be run locally , importing the code from https://mevedia.com/share/InfiniteGridHelper.js?c, import maps, and using a regular script tag. the results tend to cycle between errors like

Uncaught TypeError: THREE.InfiniteGridHelper is not a constructor http://127.0.0.1:5000/static/main.js:142

"SyntaxError: import declarations may only appear at top level of a module"

Uncaught SyntaxError: The requested module 'http://127.0.0.1:5000/static/InfiniteGridHelper.js' doesn't provide an export named: 'InfiniteGridHelper'

Uncaught ReferenceError: THREE is not defined http://127.0.0.1:5000/static/InfiniteGridHelper.js:3

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://mevedia.com/share/InfiniteGridHelper.js?c. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.

There is a forum on this library that seems to have been abandoned but it looks like other people were able to get it to work and it also seems to work on codepen. I'm just not able to figure out a way to get it to run locally.

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

// Author: Fyrestar https://mevedia.com (https://github.com/Fyrestar/THREE.InfiniteGridHelper)


THREE.InfiniteGridHelper = function InfiniteGridHelper( size1, size2, color, distance, axes = 'xzy' ) {

    color = color || new THREE.Color( 'white' );
    size1 = size1 || 10;
    size2 = size2 || 100;

    distance = distance || 8000;



    const planeAxes = axes.substr( 0, 2 );

    const geometry = new THREE.PlaneBufferGeometry( 2, 2, 1, 1 );

    const material = new THREE.ShaderMaterial( {

        side: THREE.DoubleSide,

        uniforms: {
            uSize1: {
                value: size1
            },
            uSize2: {
                value: size2
            },
            uColor: {
                value: color
            },
            uDistance: {
                value: distance
            }
        },
        transparent: true,
        vertexShader: `
           
           varying vec3 worldPosition;
           
           uniform float uDistance;
           
           void main() {
           
                vec3 pos = position.${axes} * uDistance;
                pos.${planeAxes} += cameraPosition.${planeAxes};
                
                worldPosition = pos;
                
                gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
           
           }
           `,


        fragmentShader: `
           
           varying vec3 worldPosition;
           
           uniform float uSize1;
           uniform float uSize2;
           uniform vec3 uColor;
           uniform float uDistance;
            
            
            
            float getGrid(float size) {
            
                vec2 r = worldPosition.${planeAxes} / size;
                
                
                vec2 grid = abs(fract(r - 0.5) - 0.5) / fwidth(r);
                float line = min(grid.x, grid.y);
                
            
                return 1.0 - min(line, 1.0);
            }
            
           void main() {
           
                
                  float d = 1.0 - min(distance(cameraPosition.${planeAxes}, worldPosition.${planeAxes}) / uDistance, 1.0);
                
                  float g1 = getGrid(uSize1);
                  float g2 = getGrid(uSize2);
                  
                  
                  gl_FragColor = vec4(uColor.rgb, mix(g2, g1, g1) * pow(d, 3.0));
                  gl_FragColor.a = mix(0.5 * gl_FragColor.a, gl_FragColor.a, g2);
                
                  if ( gl_FragColor.a <= 0.0 ) discard;
                
           
           }
           
           `,

        extensions: {
            derivatives: true
        }

    } );


    THREE.Mesh.call( this, geometry, material );

    this.frustumCulled = false;

};

THREE.InfiniteGridHelper.prototype = {
    ...THREE.Mesh.prototype,
    ...THREE.Object3D.prototype,
    ...THREE.EventDispatcher.prototype
};

if ( parseInt( THREE.REVISION ) > 126 ) {

    class InfiniteGridHelper extends THREE.Mesh {

        constructor ( size1, size2, color, distance, axes = 'xzy' ) {


            color = color || new THREE.Color( 'white' );
            size1 = size1 || 10;
            size2 = size2 || 100;

            distance = distance || 8000;



            const planeAxes = axes.substr( 0, 2 );

            const geometry = new THREE.PlaneBufferGeometry( 2, 2, 1, 1 );

            const material = new THREE.ShaderMaterial( {

                side: THREE.DoubleSide,

                uniforms: {
                    uSize1: {
                        value: size1
                    },
                    uSize2: {
                        value: size2
                    },
                    uColor: {
                        value: color
                    },
                    uDistance: {
                        value: distance
                    }
                },
                transparent: true,
                vertexShader: `
           
           varying vec3 worldPosition;
           
           uniform float uDistance;
           
           void main() {
           
                vec3 pos = position.${axes} * uDistance;
                pos.${planeAxes} += cameraPosition.${planeAxes};
                
                worldPosition = pos;
                
                gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
           
           }
           `,


                fragmentShader: `
           
           varying vec3 worldPosition;
           
           uniform float uSize1;
           uniform float uSize2;
           uniform vec3 uColor;
           uniform float uDistance;
            
            
            
            float getGrid(float size) {
            
                vec2 r = worldPosition.${planeAxes} / size;
                
                
                vec2 grid = abs(fract(r - 0.5) - 0.5) / fwidth(r);
                float line = min(grid.x, grid.y);
                
            
                return 1.0 - min(line, 1.0);
            }
            
           void main() {
           
                
                  float d = 1.0 - min(distance(cameraPosition.${planeAxes}, worldPosition.${planeAxes}) / uDistance, 1.0);
                
                  float g1 = getGrid(uSize1);
                  float g2 = getGrid(uSize2);
                  
                  
                  gl_FragColor = vec4(uColor.rgb, mix(g2, g1, g1) * pow(d, 3.0));
                  gl_FragColor.a = mix(0.5 * gl_FragColor.a, gl_FragColor.a, g2);
                
                  if ( gl_FragColor.a <= 0.0 ) discard;
                
           
           }
           
           `,

                extensions: {
                    derivatives: true
                }

            } );

            super( geometry, material );

            this.frustumCulled = false;

        }

    }
    
    Object.assign( InfiniteGridHelper.prototype, THREE.InfiniteGridHelper.prototype );

    THREE.InfiniteGridHelper = InfiniteGridHelper;

}


// creating the scene

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / 
    window.innerHeight, 0.1, 1000);
    camera.position.set(0,0,5);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

window.addEventListener('resize',function(){
    var width = window.innerWidth;
    var height = window.innerHeight;
    renderer.setSize(width, height);
    camera.aspect=window.innerWidth/ window.innerHeight;
    camera.updateProjectionMatrix();
})

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


// Infinite Grid Helper
const gridHelper = new THREE.InfiniteGridHelper(10, 100);
scene.add(gridHelper);
scene.add( gridHelper );

// Create a simple cube
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshNormalMaterial(); // MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

function animate() {
    requestAnimationFrame(animate);

    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;

    renderer.render(scene, camera);
    controls.update()
}

animate();
<!DOCTYPE html>
<html>
<head>
    <title>Three.js Scene</title>
    <style>
        body { margin: 0; }
        canvas { width: 100%; height: 100% }
    </style>
</head>
<body>
        <script type="importmap"> { "imports": 
            { "three": "https://cdn.jsdelivr.net/npm/three@0.169.0/build/three.module.js", 
            "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.169.0/examples/jsm/"}} 
        </script>
        <script type="module" src="static/main.js"></script>

</body>
</html>


Solution

  • I tried running your example and I faced the same read-only TypeError.

    Following the way OrbitControls was implemented, I made a few changes in the implementation of the InfiniteGridHelper. So, the proposed implementation is below:

    1. infinite-grid-helper.js
    import * as THREE from 'three';
    
    class InfiniteGridHelper extends THREE.Mesh {
    
      constructor ( size1, size2, color, distance, axes = 'xzy' ) {
    
    
        color = color || new THREE.Color( 'white' );
        size1 = size1 || 10;
        size2 = size2 || 100;
    
        distance = distance || 8000;
    
    
    
        const planeAxes = axes.substr( 0, 2 );
    
        const geometry = new THREE.PlaneGeometry( 2, 2, 1, 1 );
    
        const material = new THREE.ShaderMaterial( {
    
          side: THREE.DoubleSide,
    
          uniforms: {
            uSize1: {
              value: size1
            },
            uSize2: {
              value: size2
            },
            uColor: {
              value: color
            },
            uDistance: {
              value: distance
            }
          },
          transparent: true,
          vertexShader: `
             
             varying vec3 worldPosition;
         
             uniform float uDistance;
             
             void main() {
             
                  vec3 pos = position.${axes} * uDistance;
                  pos.${planeAxes} += cameraPosition.${planeAxes};
                  
                  worldPosition = pos;
                  
                  gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
             
             }
             `,
    
    
          fragmentShader: `
             
             varying vec3 worldPosition;
             
             uniform float uSize1;
             uniform float uSize2;
             uniform vec3 uColor;
             uniform float uDistance;
              
              
              
              float getGrid(float size) {
              
                  vec2 r = worldPosition.${planeAxes} / size;
                  
                  
                  vec2 grid = abs(fract(r - 0.5) - 0.5) / fwidth(r);
                  float line = min(grid.x, grid.y);
                  
              
                  return 1.0 - min(line, 1.0);
              }
              
             void main() {
             
                  
                    float d = 1.0 - min(distance(cameraPosition.${planeAxes}, worldPosition.${planeAxes}) / uDistance, 1.0);
                  
                    float g1 = getGrid(uSize1);
                    float g2 = getGrid(uSize2);
                    
                    
                    gl_FragColor = vec4(uColor.rgb, mix(g2, g1, g1) * pow(d, 3.0));
                    gl_FragColor.a = mix(0.5 * gl_FragColor.a, gl_FragColor.a, g2);
                  
                    if ( gl_FragColor.a <= 0.0 ) discard;
                  
             
             }
             
             `,
    
          extensions: {
            derivatives: true
          }
    
        } );
    
        super( geometry, material );
    
        this.frustumCulled = false;
    
      }
    
    }
    
    export { InfiniteGridHelper };
    

    An export of the InfiniteGridHelper class was created and taking into account that PlaneBufferGeometry has been deprecated since r145, it was replaced with PlaneGeometry.

    Then, we have to import it to our script:

    1. script.js
    import * as THREE from 'three';
    import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
    import { InfiniteGridHelper } from './infinite-grid-helper.js';
    
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / 
        window.innerHeight, 0.1, 1000);
        camera.position.set(0,0,5);
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    
    window.addEventListener('resize',function(){
        var width = window.innerWidth;
        var height = window.innerHeight;
        renderer.setSize(width, height);
        camera.aspect=window.innerWidth/ window.innerHeight;
        camera.updateProjectionMatrix();
    })
    
    const controls = new OrbitControls( camera, renderer.domElement );
    controls.update()
    
    
    // Infinite Grid Helper
    const gridHelper = new InfiniteGridHelper(10, 100);
    scene.add(gridHelper);
    scene.add( gridHelper );
    
    // Create a simple cube
    const geometry = new THREE.BoxGeometry();
    const material = new THREE.MeshNormalMaterial(); // MeshBasicMaterial({ color: 0x00ff00 });
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    
    function animate() {
        requestAnimationFrame(animate);
    
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;
    
        renderer.render(scene, camera);
        controls.update()
    }
    
    animate();
    

    Finally, we have to include it in the HTML file:

    1. index.html
    <!DOCTYPE html>
    <html>
    <head>
        <title>Three.js Scene</title>
        <style>
            body { margin: 0; }
            canvas { width: 100%; height: 100% }
        </style>
    </head>
    <body>
            <script type="importmap"> { "imports": 
                { "three": "https://cdn.jsdelivr.net/npm/three@0.169.0/build/three.module.js", 
                "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.169.0/examples/jsm/"}} 
            </script>
            <script type="module" src="infinite-grid-helper.js"></script>
            <script type="module" src="script.js"></script>
    
    </body>
    </html>
    

    Running it from a local server, will produce the following result:

    enter image description here