如何正确导入THREE.InfiniteGridHelper并解决本地运行报错
解决THREE.InfiniteGridHelper本地运行报错问题
遇到的报错汇总
尝试使用THREE.InfiniteGridHelper时,无论采用复制代码到main.js、单独文件导入、远程链接导入等方式,均出现以下报错:
Uncaught TypeError: "InfiniteGridHelper" is read-only
Uncaught TypeError: THREE.InfiniteGridHelper is not a constructor
SyntaxError: import declarations may only appear at top level of a module
Uncaught SyntaxError: The requested module doesn't provide an export named: 'InfiniteGridHelper'
Uncaught ReferenceError: THREE is not defined
Cross-Origin Request Blocked: Same Origin Policy限制,远程链接无CORS头
核心问题分析
- ES模块中导入的
THREE对象是只读的,原代码直接修改THREE.InfiniteGridHelper导致只读错误 - 单独文件导入时未正确处理模块依赖,导致THREE未定义或导出错误
修复方案
1. 封装独立的InfiniteGridHelper模块
新建InfiniteGridHelper.js文件,内容如下:
import * as THREE from 'three'; export class InfiniteGridHelper extends THREE.Mesh { constructor(size1 = 10, size2 = 100, color = new THREE.Color('white'), distance = 8000, axes = 'xzy') { 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; } }
说明:移除原代码中兼容旧版本THREE的冗余逻辑,直接通过类继承THREE.Mesh并以模块方式导出,避免修改只读的THREE全局对象。
2. 修改main.js导入并使用
import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { InfiniteGridHelper } from './InfiniteGridHelper.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); // 窗口resize处理 window.addEventListener('resize', () => { const width = window.innerWidth; const height = window.innerHeight; renderer.setSize(width, height); camera.aspect = width / height; camera.updateProjectionMatrix(); }); // 轨道控制器 const controls = new OrbitControls(camera, renderer.domElement); controls.update(); // 使用InfiniteGridHelper const gridHelper = new InfiniteGridHelper(10, 100); scene.add(gridHelper); // 创建立方体 const geometry = new THREE.BoxGeometry(); const material = new THREE.MeshNormalMaterial(); 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();
说明:直接导入封装好的InfiniteGridHelper类,避免修改THREE全局对象,解决只读错误。
3. 确保HTML结构正确
保持原HTML的importmap和模块引用,注意文件路径匹配:
<!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>
内容的提问来源于stack exchange,提问作者person
相关产品推荐
相关产品推荐

