ChromeOS下修复Windows 3.1飞屏保JS代码:Logo不渲染故障
问题原因分析
- 纹理异步加载未处理:
THREE.TextureLoader.load()是异步方法,原代码直接将其返回值(未加载完成的纹理)赋值给材质的map属性,导致材质初始化时纹理还未就绪,无法渲染出Logo。 - ChromeOS本地文件跨域限制:直接通过
file://协议打开项目时,ChromeOS的浏览器会限制本地资源的跨域加载,导致纹理文件window-filter.png无法被正确读取。 - 颜色设置语法错误:
randomlyPositionFlyingWindow函数中,错误地使用flyingWindow.material[0].color.setHex = color;,setHex是方法,应该调用而不是赋值,这会导致窗口侧面颜色无法正常更新。 - 材质共享状态问题:原代码中所有窗口共享同一个
blackMaterial实例,修改单个窗口的颜色会同步影响所有窗口。
修复后的完整代码
const scene = new THREE.Scene(); const fov = 75; const aspect = window.innerWidth / window.innerHeight; const near = 0.1; const far = 1000; const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); const renderer = new THREE.WebGLRenderer(); const loader = new THREE.TextureLoader(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); camera.position.z = 2; window.addEventListener('resize', onWindowResize, false); // 等待纹理加载完成后再初始化窗口 loader.load('window-filter.png', (texture) => { const flyingWindows = createFlyingWindows(40, texture); flyingWindows.forEach(flyingWindow => scene.add(flyingWindow)); animate(flyingWindows); }, undefined, (error) => { console.error('纹理加载失败:', error); }); function animate(flyingWindows) { requestAnimationFrame(() => animate(flyingWindows)); camera.position.z -= 0.7; flyingWindows.forEach(flyingWindow => { if (camera.position.z < flyingWindow.position.z) { randomlyPositionFlyingWindow(flyingWindow, camera); } }); renderer.render(scene, camera); } function createFlyingWindows(qty, windowTexture) { const width = 1.235; const height = 1; const depth = 0.01; const geometry = new THREE.BoxGeometry(width, height, depth); const flyingWindows = []; const windowImageMaterial = new THREE.MeshBasicMaterial({ map: windowTexture, transparent: true, side: THREE.FrontSide, }); const blackMaterial = new THREE.MeshBasicMaterial({ color: 0x000000, side: THREE.DoubleSide, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: 1, }); for (let i = 0; i < qty; i++) { const color = getRandomColor(); const colorMaterial = new THREE.MeshBasicMaterial({ color, side: THREE.BackSide, }); // 克隆黑色材质,避免共享状态导致颜色同步变化 const materials = [ blackMaterial.clone(), blackMaterial.clone(), blackMaterial.clone(), blackMaterial.clone(), windowImageMaterial, colorMaterial, ]; const flyingWindow = new THREE.Mesh(geometry, materials); randomlyPositionFlyingWindow(flyingWindow, camera); flyingWindows.push(flyingWindow); } return flyingWindows; } function randomlyPositionFlyingWindow(flyingWindow, camera) { flyingWindow.position.z = camera.position.z - Math.floor(Math.random() * 50) - 100; const distance = Math.abs(camera.position.z - flyingWindow.position.z); flyingWindow.position.x = Math.floor(Math.random() * (distance / 3)) + 0.5; flyingWindow.position.y = Math.floor(Math.random() * (distance / 3)) + 0.5; if (Math.random() > 0.5) { flyingWindow.position.x *= -1; } if (Math.random() > 0.5) { flyingWindow.position.y *= -1; } const color = getRandomColor(); // 修复setHex方法的调用方式 flyingWindow.material[0].color.setHex(color); flyingWindow.material[1].color.setHex(color); flyingWindow.material[2].color.setHex(color); flyingWindow.material[3].color.setHex(color); flyingWindow.material[5].color.setHex(color); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } // 补充原代码缺失的getRandomColor函数 function getRandomColor() { const windowsColors = [0x00a4ef, 0xff5c33, 0xffb900, 0x7fba00]; return windowsColors[Math.floor(Math.random() * windowsColors.length)]; }
额外运行建议
ChromeOS下不要直接通过file://协议打开项目,建议使用本地服务器(比如执行npx serve命令启动简易服务器)运行,绕过浏览器的跨域限制,确保纹理文件能正常加载。
内容的提问来源于stack exchange,提问作者Jacek GRZYWNIAK
相关产品推荐
相关产品推荐

