WebGL顶点着色器编译报错:含main()却提示缺失
问题:Three.js着色器加载为空导致"Missing main()"错误
报错信息
three.js:12525 THREE.WebGLProgram: Shader Error 0 - VALIDATE_STATUS false Program Info Log: Vertex shader is not compiled. ERROR: Missing main() ERROR: Missing main()
问题背景
一个1-2年前可正常运行的Three.js着色器测试应用,现在在Chrome、Firefox浏览器及Windows 10设备上均出现上述报错。检查发现,虽然着色器文件中明确包含main()函数,但控制台打印出的着色器内容为空,而本地Python服务器日志显示着色器文件请求已成功返回200:
::1 - - [14/Nov/2022 02:28:41] "GET /shaders/default.vert HTTP/1.1" 200 - ::1 - - [14/Nov/2022 02:28:41] "GET /shaders/default.frag HTTP/1.1" 200 -
最小复现示例
本地服务器启动命令
python -m http.server 8000
index.html
<html> <head> <title>Test tree.js app</title> <style> body { margin: 0; } canvas { width: 100%; height: 100% } </style> </head> <body> <script src="https://threejs.org/build/three.js"></script> <script src="main.js"></script> </body> </html>
main.js
RESOURCES = [ ["vert_shader", "http://localhost:8000/shaders/default.vert"], ["frag_shader", "http://localhost:8000/shaders/default.frag"] ]; function initialise_scene(resources) { var scene = new THREE.Scene(); scene.fog = new THREE.FogExp2(0x7c7c7c, 0.002); var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.z = 30; var renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setClearColor(scene.fog.color, 1); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); function defaultShader(r, g, b) { return new THREE.ShaderMaterial({ uniforms: { color: {value: new THREE.Vector3(r, g, b)} }, vertexShader: resources["vert_shader"], fragmentShader: resources["frag_shader"] }); }; geometry = new THREE.BoxGeometry(4, 4, 4); // material = new THREE.MeshLambertMaterial({ color: 0x000000 }); material = defaultShader(0.0, 0.0, 0.0); cube = new THREE.Mesh(geometry, material); cube.position.set(-10, 5, -5); scene.add(cube); renderer.render(scene, camera); } function load_resources() { var promises = [] for(let r of RESOURCES) { promises.push(fetch(r[1], { mode: 'no-cors' }) .then(res => res.text())) } return Promise.all(promises).then(function(res) { let resources = {} for(let i in RESOURCES) { resources[RESOURCES[i][0]] = res[i] } return resources }) } load_resources().then(res => initialise_scene(res))
shaders/default.vert
void main() { }
shaders/default.frag
uniform vec3 color; void main() { gl_FragColor = vec4(color, 1.0); }
问题根源
- fetch跨域模式错误:使用
mode: 'no-cors'发起请求时,浏览器会将响应标记为opaque response,无法读取响应内容,即使服务器返回200,res.text()也会返回空字符串,导致Three.js拿到空的着色器代码,从而报错"Missing main()"。 - 顶点着色器功能缺失:当前顶点着色器的
main()函数为空,没有输出顶点位置,即使加载成功也无法渲染出物体。
解决方案
1. 修正fetch请求配置
移除mode: 'no-cors',本地页面和服务器同域,无需跨域模式:
function load_resources() { var promises = [] for(let r of RESOURCES) { // 移除no-cors模式 promises.push(fetch(r[1]) .then(res => res.text())) } return Promise.all(promises).then(function(res) { let resources = {} for(let i in RESOURCES) { resources[RESOURCES[i][0]] = res[i] } return resources }) }
2. 完善顶点着色器
补充顶点位置的输出逻辑,确保WebGL能正确处理顶点数据:
void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }
额外优化建议
- 使用相对路径加载资源,避免硬编码
localhost,提高代码灵活性:RESOURCES = [ ["vert_shader", "./shaders/default.vert"], ["frag_shader", "./shaders/default.frag"] ]; - 添加请求错误处理,便于排查资源加载失败问题:
promises.push(fetch(r[1]) .then(res => { if (!res.ok) throw new Error(`资源请求失败,状态码:${res.status}`); return res.text(); }) .catch(err => { console.error('加载着色器出错:', err); throw err; // 继续抛出错误,避免后续逻辑执行 }) )
内容的提问来源于stack exchange,提问作者Talos Asimov
相关产品推荐
相关产品推荐

