WebGL执行texImage2D报错 Three.js绑定fabricjs画布纹理模型全黑如何修复
问题修复方案
你遇到的TypeError: Failed to execute 'texImage2D' on 'WebGLRenderingContext': Overload resolution failed报错和模型全黑的问题,由以下几个错误导致,对应修复方式如下:
核心错误点
- 变量名不匹配:fabric代码中创建的Three.js纹理变量名为
texture,但OBJ加载逻辑中引用的纹理变量名是canvasTexture,变量未定义导致纹理传入无效触发WebGL报错 - 异步加载时序错误:SVG、纹理图片都是异步加载资源,你在资源还未完成加载、fabric画布还未完成渲染时就将画布传入Three.js生成纹理,画布内容为空/不完整触发WebGL纹理解析错误
- 材质依赖光照未配置:你使用的
MeshPhongMaterial是高光反光材质,必须配合场景光源才能显示颜色,无光照时材质默认显示纯黑 - 纹理参数配置错误:
needsUpdate配置时机错误,且未针对画布尺寸适配WebGL纹理要求 - 跨域配置位置错误:跨域属性需要配置在资源加载的参数中,而非生成的fabric对象属性中
修复步骤
1. 调整fabric相关代码,统一变量、修正时序和跨域配置
var canvas = new fabric.Canvas("canvas", { // 确保canvas尺寸为2的幂,避免WebGL纹理适配问题,示例为1024*1024,可按需调整 width: 1024, height: 1024 }); canvas.backgroundColor = "#FFBE9F"; // 全局纹理变量,和OBJ加载逻辑共用 var canvasTexture = new THREE.Texture(canvas.getElement()); // 非2的幂尺寸纹理适配配置 canvasTexture.wrapS = THREE.ClampToEdgeWrapping; canvasTexture.wrapT = THREE.ClampToEdgeWrapping; canvasTexture.minFilter = THREE.LinearFilter; canvasTexture.magFilter = THREE.LinearFilter; // 记录资源加载计数,确保所有异步资源加载完成后再更新纹理 var loadCount = 0; var totalLoad = 2; // 两个异步资源:SVG、纹理图 function checkAllLoaded() { loadCount++; if(loadCount === totalLoad) { // 所有资源加载完成,画布渲染完毕后标记纹理需要更新 canvas.renderAll(); canvasTexture.needsUpdate = true; // 此时再调用OBJ模型加载逻辑 loadObj(); } } var text = new fabric.IText('Three.js\n+\nFaBric.js', { fontSize: 100, textAlign: 'center', fontWeight: 'bold', left: 512, top: 512, originX: 'center', originY: 'center', selectable: true }); canvas.add(text); // 加载SVG,跨域配置放在加载参数中 fabric.loadSVGFromURL('assets/men/cat1/prod1/pattern.svg', function (objects, options) { var svgData = fabric.util.groupSVGElements(objects, { selectable: false }); svgData.top = 420; svgData.left = 70; canvas.add(svgData); canvas.sendToBack(svgData); checkAllLoaded(); }, null, { crossOrigin: 'anonymous' }); // 加载纹理图,跨域配置放在加载参数中 fabric.Image.fromURL('assets/men/cat1/texture.png', function (myImg) { var img1 = myImg.set({ left: 0, top: 0, selectable: false }); canvas.add(img1); canvas.sendToBack(img1); checkAllLoaded(); }, { crossOrigin: 'anonymous' });
2. 调整OBJ加载代码,修正变量引用
function loadObj() { canvasTexture.anisotropy = renderer.capabilities.getMaxAnisotropy(); // 材质直接用已经初始化完成的canvasTexture const textureMaterial = new THREE.MeshPhongMaterial({ map: canvasTexture }); var loader = new THREE.OBJLoader2(manager); loader.load('assets/men/cat1/model1.obj', function (data) { if (object != null) { scene.remove(object); } object = data.detail.loaderRootNode; object.traverse(function (child) { if (child.isMesh) { child.material = textureMaterial; // 确保模型有UV坐标,没有UV的模型无法映射纹理 if(!child.geometry.attributes.uv) { console.error('模型缺少UV坐标,无法映射纹理'); } }; }); var scale = height / 5; object.scale.set(scale, scale, scale); object.position.set(0, -scale * 1.25, 0); object.rotation.set(0, Math.PI / 2, 0); object.receiveShadow = true; object.castShadow = true; scene.add(object); render(); }); }
3. 给场景添加光照
在场景初始化逻辑中加入以下代码:
// 环境光,提供基础照明 const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); // 平行光,提供高光效果,适配Phong材质 const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(10, 10, 10); scene.add(directionalLight);
额外注意事项
如果修改后纹理还是显示异常,检查你的OBJ模型是否带有UV坐标,没有UV坐标的3D模型无法正常映射2D纹理,需要在3D建模软件中展开UV后导出使用。
如果后续需要实时更新fabric画布内容到3D纹理,每次修改画布内容后调用canvas.renderAll()再设置canvasTexture.needsUpdate = true即可。
内容的提问来源于stack exchange,提问作者naoval luthfi
相关产品推荐
相关产品推荐

